From e3cada51aca4a6c85e21aa9288ff7761326ec960 Mon Sep 17 00:00:00 2001 From: Marian Date: Mon, 20 Jul 2026 12:44:01 +0000 Subject: [PATCH 01/25] feat(oidc): add is_env_managed column to oidc_providers Marks the single provider that BAMBUDDY_OIDC_* environment variables define, so a later change can upsert it on startup and refuse UI/API writes to it. The row is never delete-recreated: user_oidc_links.provider_id is FK ON DELETE CASCADE, so dropping the provider would take every account link with it. The migration carries its own test rather than relying on the model test. A table created from metadata already has the column, so that path never exercises the ALTER; an installed instance gets it only through run_migrations, and that is the path an upgrade actually takes. Covered: the column appears on a pre-existing table, rows created before the upgrade read as not env-managed, and re-running is a no-op because every boot replays the whole migration set. Refs #2593 --- backend/app/core/database.py | 8 ++ backend/app/models/oidc_provider.py | 4 + .../unit/test_oidc_env_managed_migration.py | 126 ++++++++++++++++++ backend/tests/unit/test_oidc_env_provider.py | 12 ++ 4 files changed, 150 insertions(+) create mode 100644 backend/tests/unit/test_oidc_env_managed_migration.py create mode 100644 backend/tests/unit/test_oidc_env_provider.py diff --git a/backend/app/core/database.py b/backend/app/core/database.py index 95b0872c9..bb271b1ea 100644 --- a/backend/app/core/database.py +++ b/backend/app/core/database.py @@ -3689,6 +3689,14 @@ async def run_migrations(conn): else: await _safe_execute(conn, "ALTER TABLE oidc_providers ADD COLUMN is_autologin BOOLEAN DEFAULT false") + # Migration: Add is_env_managed column to oidc_providers (#2593). Marks the + # provider upserted from BAMBUDDY_OIDC_* env vars on startup. Postgres + # rejects ``DEFAULT 0`` for BOOLEAN columns. + if is_sqlite(): + await _safe_execute(conn, "ALTER TABLE oidc_providers ADD COLUMN is_env_managed BOOLEAN DEFAULT 0") + else: + await _safe_execute(conn, "ALTER TABLE oidc_providers ADD COLUMN is_env_managed BOOLEAN DEFAULT false") + # Migration: Add dispatch_attempts to print_queue (#2555). Counts the times # the start-watchdog reverted the row from 'printing' back to 'pending' so a # printer that never actually starts stops being retried forever. INTEGER diff --git a/backend/app/models/oidc_provider.py b/backend/app/models/oidc_provider.py index c5e989545..31f770b5d 100644 --- a/backend/app/models/oidc_provider.py +++ b/backend/app/models/oidc_provider.py @@ -128,6 +128,10 @@ class OIDCProvider(Base): # authorize-URL fetch fails or times out, and ``/login?fallback=local`` # plus ``BAMBUDDY_LOCAL_LOGIN=true`` provide a documented recovery path. is_autologin: Mapped[bool] = mapped_column(Boolean, default=False, server_default="0") + # Marks the single provider defined by BAMBUDDY_OIDC_* env vars. Upserted on + # startup; UI/API writes to it are rejected. Never delete-recreated (user_oidc_links + # FK is ON DELETE CASCADE). + is_env_managed: Mapped[bool] = mapped_column(Boolean, default=False, server_default="0") @property def has_icon(self) -> bool: diff --git a/backend/tests/unit/test_oidc_env_managed_migration.py b/backend/tests/unit/test_oidc_env_managed_migration.py new file mode 100644 index 000000000..bec82b1b9 --- /dev/null +++ b/backend/tests/unit/test_oidc_env_managed_migration.py @@ -0,0 +1,126 @@ +"""The is_env_managed column has to reach databases that already exist (#2593). + +The model test covers a table freshly created from metadata, which is not how +an upgrade arrives: an installed instance has an oidc_providers table without +the column, and only run_migrations adds it there. Every boot re-runs the whole +migration set, so adding it twice must be a no-op rather than an error. +""" + +from __future__ import annotations + +import pytest +from sqlalchemy import text +from sqlalchemy.ext.asyncio import create_async_engine + +from backend.app.core.database import Base, run_migrations + + +def _register_all_models(): + from backend.app.models import ( # noqa: F401 + ams_history, + ams_label, + api_key, + archive, + color_catalog, + external_link, + filament, + group, + kprofile_note, + library, + maintenance, + notification, + notification_template, + print_log, + print_queue, + printer, + project, + project_bom, + settings, + slot_preset, + smart_plug, + smart_plug_energy_snapshot, + spool, + spool_assignment, + spool_catalog, + spool_k_profile, + spool_usage_history, + spoolbuddy_device, + user, + user_email_pref, + virtual_printer, + ) + + +@pytest.fixture(autouse=True) +def force_sqlite_dialect(monkeypatch): + """Force the SQLite branch regardless of test env settings.""" + from backend.app.core import database as database_module, db_dialect + + monkeypatch.setattr(db_dialect, "is_sqlite", lambda: True) + monkeypatch.setattr(db_dialect, "is_postgres", lambda: False) + monkeypatch.setattr(database_module, "is_sqlite", lambda: True) + + +@pytest.fixture +async def engine(): + """A database as it stands before this change: every table created from the + models, then the new column dropped again -- the model already declares it, + so only removing it reproduces what an installed instance actually has.""" + _register_all_models() + + eng = create_async_engine("sqlite+aiosqlite:///:memory:", echo=False) + async with eng.begin() as conn: + await conn.run_sync(Base.metadata.create_all) + await conn.execute(text("ALTER TABLE oidc_providers DROP COLUMN is_env_managed")) + yield eng + await eng.dispose() + + +async def _columns(conn) -> set[str]: + rows = await conn.execute(text("PRAGMA table_info(oidc_providers)")) + return {r[1] for r in rows} + + +@pytest.mark.asyncio +async def test_migration_adds_the_column_to_an_existing_table(engine): + async with engine.connect() as conn: + assert "is_env_managed" not in await _columns(conn) + + async with engine.begin() as conn: + await run_migrations(conn) + + async with engine.connect() as conn: + assert "is_env_managed" in await _columns(conn) + + +@pytest.mark.asyncio +async def test_existing_rows_default_to_not_env_managed(engine): + """A provider created through the UI before the upgrade must not come back + locked -- is_env_managed decides whether the API refuses to edit it.""" + async with engine.begin() as conn: + await conn.execute( + text( + "INSERT INTO oidc_providers" + " (id, name, issuer_url, client_id, client_secret, scopes, is_enabled," + " auto_create_users, auto_link_existing_accounts, email_claim," + " require_email_verified)" + " VALUES (1, 'UI provider', 'https://sso.example', 'app', 'enc'," + " 'openid email profile', 1, 0, 0, 'email', 1)" + ) + ) + await run_migrations(conn) + + async with engine.connect() as conn: + row = await conn.execute(text("SELECT is_env_managed FROM oidc_providers WHERE id = 1")) + assert not row.scalar() + + +@pytest.mark.asyncio +async def test_it_is_idempotent(engine): + """Every boot re-runs the migration set.""" + for _ in range(2): + async with engine.begin() as conn: + await run_migrations(conn) + + async with engine.connect() as conn: + assert "is_env_managed" in await _columns(conn) diff --git a/backend/tests/unit/test_oidc_env_provider.py b/backend/tests/unit/test_oidc_env_provider.py new file mode 100644 index 000000000..df193fb36 --- /dev/null +++ b/backend/tests/unit/test_oidc_env_provider.py @@ -0,0 +1,12 @@ +import pytest + +from backend.app.models.oidc_provider import OIDCProvider + + +@pytest.mark.asyncio +async def test_is_env_managed_defaults_false(db_session): + p = OIDCProvider(name="x", issuer_url="https://i", client_id="c", client_secret="s") + db_session.add(p) + await db_session.commit() + await db_session.refresh(p) + assert p.is_env_managed is False From d6ecd9248086f1c9222b248c2eb38fbd975d0f5c Mon Sep 17 00:00:00 2001 From: Marian Date: Mon, 20 Jul 2026 13:28:59 +0000 Subject: [PATCH 02/25] feat(oidc): read BAMBUDDY_OIDC_* env config A declarative deployment has no way to click through the settings UI, so one provider can be configured entirely from the environment. This reads and defaults only -- validity is decided later by the same OIDCProviderCreate schema the API uses, so env config cannot bypass a check the UI enforces. All four required vars or nothing, and an empty one counts as unset: a provider missing its secret would otherwise be written to the database and fail at authorize time, far from the typo in the compose file that caused it. Booleans follow the project's existing spelling convention (true/1/yes), so an unrecognised value leaves the documented default rather than guessing. Refs #2593 --- backend/app/core/oidc_env.py | 54 ++++++++++ backend/tests/unit/test_oidc_env_reader.py | 118 +++++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 backend/app/core/oidc_env.py create mode 100644 backend/tests/unit/test_oidc_env_reader.py diff --git a/backend/app/core/oidc_env.py b/backend/app/core/oidc_env.py new file mode 100644 index 000000000..60f557a98 --- /dev/null +++ b/backend/app/core/oidc_env.py @@ -0,0 +1,54 @@ +"""Read the single OIDC provider defined by BAMBUDDY_OIDC_* env vars (#2593). + +A declarative deployment (compose, Helm, GitOps) has no way to click through +the settings UI, so one provider can be configured entirely from the +environment. This module only reads and defaults; validity is decided by the +same OIDCProviderCreate schema the API uses, so env config cannot bypass a +check the UI enforces. +""" + +from __future__ import annotations + +import os + +# All four or nothing: a provider missing its secret would be written to the +# database and then fail at authorize time, long after the operator could +# connect the failure to a typo in their compose file. +_REQUIRED = ( + "BAMBUDDY_OIDC_NAME", + "BAMBUDDY_OIDC_ISSUER_URL", + "BAMBUDDY_OIDC_CLIENT_ID", + "BAMBUDDY_OIDC_CLIENT_SECRET", +) + +_TRUTHY = {"true", "1", "yes"} + + +def _env_bool(key: str, default: bool) -> bool: + value = os.environ.get(key) + return default if value is None else value.strip().lower() in _TRUTHY + + +def read_env_oidc_config() -> dict | None: + """The provider's fields from the environment, or None if it isn't configured. + + An empty required var counts as unset -- `BAMBUDDY_OIDC_CLIENT_SECRET=` in + a compose file is a forgotten value, not an intentional empty secret. + """ + if not all(os.environ.get(key) for key in _REQUIRED): + return None + + return { + "name": os.environ["BAMBUDDY_OIDC_NAME"], + "issuer_url": os.environ["BAMBUDDY_OIDC_ISSUER_URL"], + "client_id": os.environ["BAMBUDDY_OIDC_CLIENT_ID"], + "client_secret": os.environ["BAMBUDDY_OIDC_CLIENT_SECRET"], + "scopes": os.environ.get("BAMBUDDY_OIDC_SCOPES", "openid email profile"), + "is_enabled": _env_bool("BAMBUDDY_OIDC_ENABLED", True), + "auto_create_users": _env_bool("BAMBUDDY_OIDC_AUTO_CREATE_USERS", False), + "auto_link_existing_accounts": _env_bool("BAMBUDDY_OIDC_AUTO_LINK_EXISTING", False), + "email_claim": os.environ.get("BAMBUDDY_OIDC_EMAIL_CLAIM", "email"), + "require_email_verified": _env_bool("BAMBUDDY_OIDC_REQUIRE_EMAIL_VERIFIED", True), + "icon_url": os.environ.get("BAMBUDDY_OIDC_ICON_URL"), + "is_autologin": _env_bool("BAMBUDDY_OIDC_AUTOLOGIN", False), + } diff --git a/backend/tests/unit/test_oidc_env_reader.py b/backend/tests/unit/test_oidc_env_reader.py new file mode 100644 index 000000000..7e8c7b875 --- /dev/null +++ b/backend/tests/unit/test_oidc_env_reader.py @@ -0,0 +1,118 @@ +"""BAMBUDDY_OIDC_* reader (#2593). + +The reader is deliberately dumb: it maps env vars to field names and applies +defaults. Whether the resulting provider is *valid* is decided later, by the +same OIDCProviderCreate schema the API uses, so env config cannot bypass a +check the UI enforces. +""" + +from __future__ import annotations + +import pytest + +from backend.app.core.oidc_env import read_env_oidc_config + +REQUIRED = { + "BAMBUDDY_OIDC_NAME": "Keycloak", + "BAMBUDDY_OIDC_ISSUER_URL": "https://sso.example.com/realms/main", + "BAMBUDDY_OIDC_CLIENT_ID": "bambuddy", + "BAMBUDDY_OIDC_CLIENT_SECRET": "s3cr3t", +} + +OPTIONAL = ( + "BAMBUDDY_OIDC_SCOPES", + "BAMBUDDY_OIDC_ENABLED", + "BAMBUDDY_OIDC_AUTO_CREATE_USERS", + "BAMBUDDY_OIDC_AUTO_LINK_EXISTING", + "BAMBUDDY_OIDC_EMAIL_CLAIM", + "BAMBUDDY_OIDC_REQUIRE_EMAIL_VERIFIED", + "BAMBUDDY_OIDC_ICON_URL", + "BAMBUDDY_OIDC_AUTOLOGIN", +) + + +@pytest.fixture(autouse=True) +def clean_env(monkeypatch): + for key in (*REQUIRED, *OPTIONAL): + monkeypatch.delenv(key, raising=False) + + +def _set_required(monkeypatch): + for key, value in REQUIRED.items(): + monkeypatch.setenv(key, value) + + +def test_returns_none_when_nothing_is_configured(): + assert read_env_oidc_config() is None + + +@pytest.mark.parametrize("missing", sorted(REQUIRED)) +def test_returns_none_when_any_single_required_var_is_missing(monkeypatch, missing): + """All four or nothing -- a half-configured provider must not reach the + database, where it would fail at authorize time instead of at startup.""" + _set_required(monkeypatch) + monkeypatch.delenv(missing) + assert read_env_oidc_config() is None + + +def test_an_empty_required_var_counts_as_unset(monkeypatch): + """`BAMBUDDY_OIDC_CLIENT_SECRET=` in a compose file is a forgotten value, + not an intentional empty secret.""" + _set_required(monkeypatch) + monkeypatch.setenv("BAMBUDDY_OIDC_CLIENT_SECRET", "") + assert read_env_oidc_config() is None + + +def test_reads_the_required_vars(monkeypatch): + _set_required(monkeypatch) + cfg = read_env_oidc_config() + assert cfg["name"] == "Keycloak" + assert cfg["issuer_url"] == "https://sso.example.com/realms/main" + assert cfg["client_id"] == "bambuddy" + assert cfg["client_secret"] == "s3cr3t" + + +def test_applies_the_documented_defaults(monkeypatch): + _set_required(monkeypatch) + cfg = read_env_oidc_config() + assert cfg["scopes"] == "openid email profile" + assert cfg["is_enabled"] is True + assert cfg["auto_create_users"] is False + assert cfg["auto_link_existing_accounts"] is False + assert cfg["email_claim"] == "email" + assert cfg["require_email_verified"] is True + assert cfg["icon_url"] is None + assert cfg["is_autologin"] is False + + +@pytest.mark.parametrize("raw", ["true", "TRUE", "True", "1", "yes", "YES", " yes "]) +def test_booleans_accept_the_project_truthy_spellings(monkeypatch, raw): + _set_required(monkeypatch) + monkeypatch.setenv("BAMBUDDY_OIDC_AUTO_CREATE_USERS", raw) + assert read_env_oidc_config()["auto_create_users"] is True + + +@pytest.mark.parametrize("raw", ["false", "0", "no", "", "off", "nonsense"]) +def test_anything_else_is_false(monkeypatch, raw): + """Only the three documented spellings enable a flag; an unrecognised value + must not silently turn on auto-create-users.""" + _set_required(monkeypatch) + monkeypatch.setenv("BAMBUDDY_OIDC_AUTO_CREATE_USERS", raw) + assert read_env_oidc_config()["auto_create_users"] is False + + +def test_a_boolean_default_of_true_can_be_turned_off(monkeypatch): + _set_required(monkeypatch) + monkeypatch.setenv("BAMBUDDY_OIDC_REQUIRE_EMAIL_VERIFIED", "false") + assert read_env_oidc_config()["require_email_verified"] is False + + +def test_optional_strings_override_their_defaults(monkeypatch): + _set_required(monkeypatch) + monkeypatch.setenv("BAMBUDDY_OIDC_SCOPES", "openid profile groups") + monkeypatch.setenv("BAMBUDDY_OIDC_EMAIL_CLAIM", "mail") + monkeypatch.setenv("BAMBUDDY_OIDC_ICON_URL", "https://sso.example.com/logo.png") + cfg = read_env_oidc_config() + assert cfg["scopes"] == "openid profile groups" + assert cfg["email_claim"] == "mail" + assert cfg["icon_url"] == "https://sso.example.com/logo.png" From 58602a3f1b58df4c4dfff8a863a8ed7d3501037f Mon Sep 17 00:00:00 2001 From: Marian Date: Mon, 20 Jul 2026 13:32:12 +0000 Subject: [PATCH 03/25] feat(oidc): upsert the env-managed provider The row is updated in place, never delete-recreated: user_oidc_links references it with ON DELETE CASCADE, so recreating the provider would silently unlink every account bound to it. For the same reason, removing the variables disables the provider rather than deleting it -- the links would not come back when the config does. Config goes through OIDCProviderCreate, the schema the API already uses, so the environment cannot reach a state the UI would have refused. That covers the SEC-1 auto-link check: auto-link plus unverified email is an account takeover, and it is rejected here exactly as it is in the UI. Nothing raises. This runs during startup, so a typo in one variable must not stop the app from booting -- a rejected config is logged and skipped, leaving the previous provider untouched. Refs #2593 --- backend/app/core/oidc_env.py | 76 +++++++++ .../tests/integration/test_oidc_env_apply.py | 160 ++++++++++++++++++ 2 files changed, 236 insertions(+) create mode 100644 backend/tests/integration/test_oidc_env_apply.py diff --git a/backend/app/core/oidc_env.py b/backend/app/core/oidc_env.py index 60f557a98..5d02bdd7b 100644 --- a/backend/app/core/oidc_env.py +++ b/backend/app/core/oidc_env.py @@ -9,8 +9,14 @@ check the UI enforces. from __future__ import annotations +import logging import os +from sqlalchemy import select, update +from sqlalchemy.ext.asyncio import AsyncSession + +logger = logging.getLogger(__name__) + # All four or nothing: a provider missing its secret would be written to the # database and then fail at authorize time, long after the operator could # connect the failure to a typo in their compose file. @@ -52,3 +58,73 @@ def read_env_oidc_config() -> dict | None: "icon_url": os.environ.get("BAMBUDDY_OIDC_ICON_URL"), "is_autologin": _env_bool("BAMBUDDY_OIDC_AUTOLOGIN", False), } + + +# Everything the schema validates and the model stores, except client_secret -- +# that one goes through the property so it is encrypted at rest. +_APPLIED_FIELDS = ( + "name", + "issuer_url", + "client_id", + "scopes", + "is_enabled", + "auto_create_users", + "auto_link_existing_accounts", + "email_claim", + "require_email_verified", + "icon_url", + "is_autologin", +) + + +async def apply_env_oidc_provider(db: AsyncSession) -> None: + """Upsert the env-managed provider, or disable it when the config is gone. + + Never raises: this runs during startup, and a typo in one variable must not + stop the app from booting. A rejected config is logged and skipped. + """ + # Imported here rather than at module scope: app.core is imported by the + # models themselves, so a top-level import would be a cycle. + from backend.app.models.oidc_provider import OIDCProvider + from backend.app.schemas.auth import OIDCProviderCreate + + config = read_env_oidc_config() + existing = ( + await db.execute(select(OIDCProvider).where(OIDCProvider.is_env_managed.is_(True))) + ).scalar_one_or_none() + + if config is None: + # Disabled, never deleted: user_oidc_links.provider_id is FK ON DELETE + # CASCADE, so removing the row would unlink every bound account and the + # links would not come back when the variables do. + if existing is not None and existing.is_enabled: + existing.is_enabled = False + await db.commit() + logger.info("BAMBUDDY_OIDC_* is unset -- env-managed provider disabled.") + return + + try: + # The same schema the API uses, so env config cannot reach a state the + # UI would have refused (notably the SEC-1 auto-link check). + validated = OIDCProviderCreate(**config) + except Exception as exc: # noqa: BLE001 -- any rejection must be survivable + logger.error("BAMBUDDY_OIDC_* config rejected, provider not applied: %s", exc) + return + + if existing is None: + existing = OIDCProvider(is_env_managed=True) + db.add(existing) + for field in _APPLIED_FIELDS: + setattr(existing, field, getattr(validated, field)) + existing.client_secret = validated.client_secret + existing.is_env_managed = True + await db.flush() # the id is needed by the autologin sweep below + + if existing.is_autologin: + await db.execute( + update(OIDCProvider) + .where(OIDCProvider.id != existing.id, OIDCProvider.is_autologin.is_(True)) + .values(is_autologin=False) + ) + await db.commit() + logger.info("Env-managed OIDC provider %r applied.", existing.name) diff --git a/backend/tests/integration/test_oidc_env_apply.py b/backend/tests/integration/test_oidc_env_apply.py new file mode 100644 index 000000000..e83aeeba9 --- /dev/null +++ b/backend/tests/integration/test_oidc_env_apply.py @@ -0,0 +1,160 @@ +"""Upserting the env-managed OIDC provider (#2593). + +Startup applies BAMBUDDY_OIDC_* to the database. The row is updated in place, +never delete-recreated: user_oidc_links.provider_id is FK ON DELETE CASCADE, so +recreating the provider would silently unlink every account bound to it. +""" + +from __future__ import annotations + +import pytest +from sqlalchemy import select + +from backend.app.core.oidc_env import apply_env_oidc_provider +from backend.app.models.oidc_provider import OIDCProvider + +REQUIRED = { + "BAMBUDDY_OIDC_NAME": "Keycloak", + "BAMBUDDY_OIDC_ISSUER_URL": "https://sso.example.com/realms/main", + "BAMBUDDY_OIDC_CLIENT_ID": "bambuddy", + "BAMBUDDY_OIDC_CLIENT_SECRET": "s3cr3t", +} + +ALL_VARS = ( + *REQUIRED, + "BAMBUDDY_OIDC_SCOPES", + "BAMBUDDY_OIDC_ENABLED", + "BAMBUDDY_OIDC_AUTO_CREATE_USERS", + "BAMBUDDY_OIDC_AUTO_LINK_EXISTING", + "BAMBUDDY_OIDC_EMAIL_CLAIM", + "BAMBUDDY_OIDC_REQUIRE_EMAIL_VERIFIED", + "BAMBUDDY_OIDC_ICON_URL", + "BAMBUDDY_OIDC_AUTOLOGIN", +) + + +@pytest.fixture(autouse=True) +def clean_env(monkeypatch): + for key in ALL_VARS: + monkeypatch.delenv(key, raising=False) + + +def _configure(monkeypatch, **overrides): + for key, value in REQUIRED.items(): + monkeypatch.setenv(key, value) + for key, value in overrides.items(): + monkeypatch.setenv(key, value) + + +async def _env_provider(db_session) -> OIDCProvider | None: + result = await db_session.execute(select(OIDCProvider).where(OIDCProvider.is_env_managed.is_(True))) + return result.scalar_one_or_none() + + +@pytest.mark.asyncio +async def test_creates_the_provider_from_env(db_session, monkeypatch): + _configure(monkeypatch) + await apply_env_oidc_provider(db_session) + + provider = await _env_provider(db_session) + assert provider is not None + assert provider.name == "Keycloak" + assert provider.client_id == "bambuddy" + assert provider.is_env_managed is True + assert provider.client_secret == "s3cr3t" # property decrypts + + +@pytest.mark.asyncio +async def test_a_changed_var_updates_the_same_row(db_session, monkeypatch): + """The id must survive: user_oidc_links references it with ON DELETE + CASCADE, so a delete-recreate would unlink every bound account.""" + _configure(monkeypatch) + await apply_env_oidc_provider(db_session) + original_id = (await _env_provider(db_session)).id + + monkeypatch.setenv("BAMBUDDY_OIDC_CLIENT_ID", "rotated") + await apply_env_oidc_provider(db_session) + + provider = await _env_provider(db_session) + assert provider.id == original_id + assert provider.client_id == "rotated" + + +@pytest.mark.asyncio +async def test_removing_the_env_config_disables_but_keeps_the_row(db_session, monkeypatch): + _configure(monkeypatch) + await apply_env_oidc_provider(db_session) + original_id = (await _env_provider(db_session)).id + + for key in ALL_VARS: + monkeypatch.delenv(key, raising=False) + await apply_env_oidc_provider(db_session) + + provider = await _env_provider(db_session) + assert provider is not None, "deleting would cascade away every account link" + assert provider.id == original_id + assert provider.is_enabled is False + + +@pytest.mark.asyncio +async def test_env_autologin_clears_it_on_other_providers(db_session, monkeypatch): + """Only one provider may be the autologin target; the env one wins.""" + ui_provider = OIDCProvider( + name="UI provider", + issuer_url="https://other.example.com", + client_id="ui", + is_autologin=True, + ) + ui_provider.client_secret = "ui-secret" + db_session.add(ui_provider) + await db_session.commit() + + _configure(monkeypatch, BAMBUDDY_OIDC_AUTOLOGIN="true") + await apply_env_oidc_provider(db_session) + + await db_session.refresh(ui_provider) + assert (await _env_provider(db_session)).is_autologin is True + assert ui_provider.is_autologin is False + + +@pytest.mark.asyncio +async def test_a_ui_provider_is_otherwise_left_alone(db_session, monkeypatch): + ui_provider = OIDCProvider(name="UI provider", issuer_url="https://other.example.com", client_id="ui") + ui_provider.client_secret = "ui-secret" + db_session.add(ui_provider) + await db_session.commit() + + _configure(monkeypatch) + await apply_env_oidc_provider(db_session) + + await db_session.refresh(ui_provider) + assert ui_provider.is_env_managed is False + assert ui_provider.is_enabled is True + assert ui_provider.client_id == "ui" + + +@pytest.mark.asyncio +async def test_an_unsafe_auto_link_config_is_skipped_not_raised(db_session, monkeypatch): + """auto-link + unverified email is the SEC-1 account-takeover shape. The + schema rejects it for the UI, and env config must not be a way around that + -- but a bad variable must not stop the app from booting either.""" + _configure( + monkeypatch, + BAMBUDDY_OIDC_AUTO_LINK_EXISTING="true", + BAMBUDDY_OIDC_REQUIRE_EMAIL_VERIFIED="false", + ) + + await apply_env_oidc_provider(db_session) + + assert await _env_provider(db_session) is None + + +@pytest.mark.asyncio +async def test_applying_twice_without_changes_is_a_no_op(db_session, monkeypatch): + """Every boot re-applies; the second run must not create a second row.""" + _configure(monkeypatch) + await apply_env_oidc_provider(db_session) + await apply_env_oidc_provider(db_session) + + result = await db_session.execute(select(OIDCProvider).where(OIDCProvider.is_env_managed.is_(True))) + assert len(result.scalars().all()) == 1 From e7a413e745ae73bce545771b184d309bb2ea958a Mon Sep 17 00:00:00 2001 From: Marian Date: Mon, 20 Jul 2026 13:40:30 +0000 Subject: [PATCH 04/25] feat(oidc): apply the env provider during startup Placed after init_db(): is_env_managed only exists once run_migrations has added it, so an upsert before that would fail on every existing installation. The wiring gets its own tests because the apply tests cannot cover it -- they call apply_env_oidc_provider() directly, so deleting this call would leave the feature dead with a fully green suite. Verified: removing the call fails the three startup tests while all seven apply tests still pass. They assert against the lifespan's source rather than running it. The function is ~460 lines and starts printer connections, MQTT and schedulers; executing it would exercise everything except the line in question. The docstring says plainly that this proves the call exists and runs after migrations, and proves nothing about its behaviour. Refs #2593 --- backend/app/main.py | 8 ++++ .../integration/test_oidc_env_startup.py | 43 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 backend/tests/integration/test_oidc_env_startup.py diff --git a/backend/app/main.py b/backend/app/main.py index 378feb178..c39358880 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -6194,6 +6194,14 @@ async def lifespan(app: FastAPI): await init_db() + # After migrations, so the is_env_managed column exists. Never raises -- + # a bad BAMBUDDY_OIDC_* value is logged and skipped rather than blocking + # startup (see apply_env_oidc_provider). + from backend.app.core.oidc_env import apply_env_oidc_provider + + async with async_session() as oidc_db: + await apply_env_oidc_provider(oidc_db) + # Register an app-scoped httpx client for Bambu Cloud services so # per-request BambuCloudService instances reuse the same connection pool # (important for routes like /cloud/filament-info that chain many diff --git a/backend/tests/integration/test_oidc_env_startup.py b/backend/tests/integration/test_oidc_env_startup.py new file mode 100644 index 000000000..d75c61c00 --- /dev/null +++ b/backend/tests/integration/test_oidc_env_startup.py @@ -0,0 +1,43 @@ +"""The env provider is applied on startup, not merely appliable (#2593). + +test_oidc_env_apply.py calls apply_env_oidc_provider() directly, so it stays +green even if nothing ever calls it -- deleting the lifespan call would leave +the feature dead with a fully passing suite. These tests pin the call site. + +They read the lifespan's source rather than running it: the function is ~460 +lines and starts printer connections, MQTT and schedulers, so executing it +here would test everything except the one line in question. That makes this a +wiring check, not a behavioural one -- it proves the call exists and runs +after migrations, and deliberately proves nothing about what it does. The +behaviour is covered by test_oidc_env_apply.py. +""" + +from __future__ import annotations + +import inspect + +from backend.app.main import lifespan + + +def _lifespan_source() -> str: + return inspect.getsource(lifespan) + + +def test_lifespan_applies_the_env_oidc_provider(): + assert "apply_env_oidc_provider(" in _lifespan_source() + + +def test_it_runs_after_the_migrations(): + """is_env_managed does not exist until run_migrations has added it, so an + upsert before init_db() would fail on every existing installation.""" + source = _lifespan_source() + assert source.index("await init_db()") < source.index("apply_env_oidc_provider(") + + +def test_the_apply_call_is_awaited(): + """apply_env_oidc_provider is a coroutine; calling it without await would + return an un-awaited coroutine and silently apply nothing.""" + source = _lifespan_source() + call = source.index("apply_env_oidc_provider(") + line_start = source.rindex("\n", 0, call) + 1 + assert source[line_start:call].strip().endswith("await") From c9ee2598078f18d7fd8f16593959cfcba4059954 Mon Sep 17 00:00:00 2001 From: Marian Date: Mon, 20 Jul 2026 14:38:28 +0000 Subject: [PATCH 05/25] feat(oidc): refuse API writes to the env-managed provider Startup rewrites this row from BAMBUDDY_OIDC_* on every boot, so an edit through the UI would be accepted and then silently reverted at the next restart -- the operator would watch their change vanish with nothing explaining why. A 409 says so instead. Covers all four mutating routes, including the two icon ones: the icon comes from BAMBUDDY_OIDC_ICON_URL and would be restored the same way. Extracted as one helper rather than four copies of the same check, so a fifth route cannot be added with the guard silently missing. Locking it is safe because BAMBUDDY_LOCAL_LOGIN (#1589) remains the documented recovery path if the provider itself becomes unusable. A test pins that UI-created providers stay editable -- the lock must not leak onto them. Refs #2593 --- backend/app/api/routes/mfa.py | 16 ++ .../tests/integration/test_oidc_env_lock.py | 137 ++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 backend/tests/integration/test_oidc_env_lock.py diff --git a/backend/app/api/routes/mfa.py b/backend/app/api/routes/mfa.py index b7238fcb6..e653c6813 100644 --- a/backend/app/api/routes/mfa.py +++ b/backend/app/api/routes/mfa.py @@ -1404,6 +1404,18 @@ async def create_oidc_provider( return _build_provider_response(provider) +def _refuse_if_env_managed(provider: OIDCProvider) -> None: + """Startup rewrites this provider from BAMBUDDY_OIDC_* on every boot, so an + edit here would be accepted and then silently reverted at the next restart. + BAMBUDDY_LOCAL_LOGIN (#1589) remains the recovery path if it becomes + unusable, so refusing outright cannot lock anyone out.""" + if provider.is_env_managed: + raise HTTPException( + status_code=status.HTTP_409_CONFLICT, + detail="This OIDC provider is managed by environment variables and cannot be modified.", + ) + + @router.put("/oidc/providers/{provider_id}", response_model=OIDCProviderResponse) async def update_oidc_provider( provider_id: int, @@ -1426,6 +1438,7 @@ async def update_oidc_provider( provider = result2.scalar_one_or_none() if not provider: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Provider not found") + _refuse_if_env_managed(provider) if body.default_group_id is not None: grp_chk = await db.execute(select(Group).where(Group.id == body.default_group_id)) @@ -1503,6 +1516,7 @@ async def delete_oidc_provider( provider = result2.scalar_one_or_none() if not provider: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Provider not found") + _refuse_if_env_managed(provider) await db.delete(provider) await db.commit() @@ -1571,6 +1585,7 @@ async def delete_oidc_provider_icon( provider = result.scalar_one_or_none() if provider is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Provider not found") + _refuse_if_env_managed(provider) # Setting deferred columns is safe — no read happens, just a write. provider.icon_url = None @@ -1603,6 +1618,7 @@ async def refresh_oidc_provider_icon( provider = result.scalar_one_or_none() if provider is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Provider not found") + _refuse_if_env_managed(provider) if not provider.icon_url: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, diff --git a/backend/tests/integration/test_oidc_env_lock.py b/backend/tests/integration/test_oidc_env_lock.py new file mode 100644 index 000000000..6c8c99358 --- /dev/null +++ b/backend/tests/integration/test_oidc_env_lock.py @@ -0,0 +1,137 @@ +"""The env-managed provider is read-only through the API (#2593). + +Startup rewrites this row from BAMBUDDY_OIDC_* on every boot, so a UI edit +would silently disappear at the next restart -- the operator would see their +change accepted and then reverted, with nothing explaining why. Refusing the +write is the honest answer. + +Locking it out is safe because BAMBUDDY_LOCAL_LOGIN (#1589) is the documented +recovery path if the provider itself becomes unusable. +""" + +from __future__ import annotations + +import pytest +from httpx import AsyncClient + +from backend.app.models.oidc_provider import OIDCProvider +from backend.tests.integration.test_mfa_api import _auth_header, _setup_and_login + + +async def _env_managed_provider(db_session) -> int: + provider = OIDCProvider( + name="Env Keycloak", + issuer_url="https://sso.example.com/realms/main", + client_id="bambuddy", + icon_url="https://sso.example.com/logo.png", + is_env_managed=True, + ) + provider.client_secret = "s3cr3t" + db_session.add(provider) + await db_session.commit() + await db_session.refresh(provider) + return provider.id + + +@pytest.mark.asyncio +@pytest.mark.integration +async def test_put_is_refused(async_client: AsyncClient, db_session): + provider_id = await _env_managed_provider(db_session) + token = await _setup_and_login(async_client, "envlockput", "envlockput123") + + response = await async_client.put( + f"/api/v1/auth/oidc/providers/{provider_id}", + json={"name": "hijacked"}, + headers=_auth_header(token), + ) + + assert response.status_code == 409 + + +@pytest.mark.asyncio +@pytest.mark.integration +async def test_delete_is_refused(async_client: AsyncClient, db_session): + provider_id = await _env_managed_provider(db_session) + token = await _setup_and_login(async_client, "envlockdel", "envlockdel123") + + response = await async_client.delete( + f"/api/v1/auth/oidc/providers/{provider_id}", + headers=_auth_header(token), + ) + + assert response.status_code == 409 + + +@pytest.mark.asyncio +@pytest.mark.integration +async def test_icon_delete_is_refused(async_client: AsyncClient, db_session): + """The icon is part of the env config too -- BAMBUDDY_OIDC_ICON_URL.""" + provider_id = await _env_managed_provider(db_session) + token = await _setup_and_login(async_client, "envlockicondel", "envlockicondel123") + + response = await async_client.delete( + f"/api/v1/auth/oidc/providers/{provider_id}/icon", + headers=_auth_header(token), + ) + + assert response.status_code == 409 + + +@pytest.mark.asyncio +@pytest.mark.integration +async def test_icon_refresh_is_refused(async_client: AsyncClient, db_session): + provider_id = await _env_managed_provider(db_session) + token = await _setup_and_login(async_client, "envlockiconref", "envlockiconref123") + + response = await async_client.post( + f"/api/v1/auth/oidc/providers/{provider_id}/icon/refresh", + headers=_auth_header(token), + ) + + assert response.status_code == 409 + + +@pytest.mark.asyncio +@pytest.mark.integration +async def test_a_ui_provider_is_still_editable(async_client: AsyncClient): + """The lock must not leak onto providers the operator created themselves -- + they coexist with the env one and stay fully editable.""" + token = await _setup_and_login(async_client, "envlockui", "envlockui123") + created = await async_client.post( + "/api/v1/auth/oidc/providers", + json={ + "name": "UI provider", + "issuer_url": "https://other.example.com", + "client_id": "ui", + "client_secret": "ui-secret", + "scopes": "openid", + "is_enabled": True, + "auto_create_users": False, + }, + headers=_auth_header(token), + ) + provider_id = created.json()["id"] + + response = await async_client.put( + f"/api/v1/auth/oidc/providers/{provider_id}", + json={"name": "Renamed"}, + headers=_auth_header(token), + ) + + assert response.status_code == 200 + assert response.json()["name"] == "Renamed" + + +@pytest.mark.asyncio +@pytest.mark.integration +async def test_the_response_says_which_provider_is_env_managed(async_client: AsyncClient, db_session): + """The frontend needs this to render the lock; without it the UI would show + editable fields whose writes the API then refuses.""" + await _env_managed_provider(db_session) + token = await _setup_and_login(async_client, "envlockflag", "envlockflag123") + + response = await async_client.get("/api/v1/auth/oidc/providers/all", headers=_auth_header(token)) + + assert response.status_code == 200 + providers = response.json() + assert any(p["is_env_managed"] for p in providers) From ccc90ff34c2c92c166e0731e4df946b2ec6efed5 Mon Sep 17 00:00:00 2001 From: Marian Date: Mon, 20 Jul 2026 14:38:28 +0000 Subject: [PATCH 06/25] feat(oidc): expose is_env_managed in the provider response The frontend needs it to render the provider read-only. Without the flag the UI would offer editable fields whose writes the API then refuses with 409 -- the change would look accepted right up until it wasn't. Refs #2593 --- backend/app/schemas/auth.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/app/schemas/auth.py b/backend/app/schemas/auth.py index 597e03a1f..af604b1a1 100644 --- a/backend/app/schemas/auth.py +++ b/backend/app/schemas/auth.py @@ -518,6 +518,9 @@ class OIDCProviderResponse(BaseModel): icon_url: str | None = None default_group_id: int | None = None is_autologin: bool = False # #1589 + # #2593 — the UI renders this provider read-only; without the flag it would + # offer editable fields whose writes the API then refuses with 409. + is_env_managed: bool = False # Set explicitly in the route handler from `icon_content_type is not None` # rather than `@computed_field` (project policy) or `icon_data is not None` # (would trigger an async lazy-load on the deferred BLOB column). From 8d1b2b90273ca7ac4c030f7ada26b261f05a7273 Mon Sep 17 00:00:00 2001 From: Marian Date: Mon, 20 Jul 2026 14:38:28 +0000 Subject: [PATCH 07/25] chore(config): register BAMBUDDY_OIDC_* in the typo-guard Unknown BAMBUDDY_* vars log "possible typo" on every boot, so a correct OIDC config would have told its operator it was wrong, once per restart. The test asserts against the reader's own variable list rather than a copied one, so a thirteenth variable added later fails here instead of surfacing in somebody's logs. Refs #2593 --- backend/app/core/config.py | 14 ++++++++++++++ backend/tests/unit/test_oidc_env_reader.py | 11 +++++++++++ 2 files changed, 25 insertions(+) diff --git a/backend/app/core/config.py b/backend/app/core/config.py index a5a99b3e3..72bbca2e5 100644 --- a/backend/app/core/config.py +++ b/backend/app/core/config.py @@ -135,6 +135,20 @@ _INTENTIONAL_UNSETTINGS = { "LOG_DIR", # config.py (above) "LOG_LEVEL", # main.py logging setup "BUG_REPORT_RELAY_URL", # config.py (above) + # #2593 — core/oidc_env.py reads these directly; they are not Settings + # fields because they map to an OIDCProvider row, not to app config. + "BAMBUDDY_OIDC_NAME", + "BAMBUDDY_OIDC_ISSUER_URL", + "BAMBUDDY_OIDC_CLIENT_ID", + "BAMBUDDY_OIDC_CLIENT_SECRET", + "BAMBUDDY_OIDC_SCOPES", + "BAMBUDDY_OIDC_ENABLED", + "BAMBUDDY_OIDC_AUTO_CREATE_USERS", + "BAMBUDDY_OIDC_AUTO_LINK_EXISTING", + "BAMBUDDY_OIDC_EMAIL_CLAIM", + "BAMBUDDY_OIDC_REQUIRE_EMAIL_VERIFIED", + "BAMBUDDY_OIDC_ICON_URL", + "BAMBUDDY_OIDC_AUTOLOGIN", } _known_settings_fields = {f.upper() for f in settings.model_fields} diff --git a/backend/tests/unit/test_oidc_env_reader.py b/backend/tests/unit/test_oidc_env_reader.py index 7e8c7b875..307bf3dba 100644 --- a/backend/tests/unit/test_oidc_env_reader.py +++ b/backend/tests/unit/test_oidc_env_reader.py @@ -116,3 +116,14 @@ def test_optional_strings_override_their_defaults(monkeypatch): assert cfg["scopes"] == "openid profile groups" assert cfg["email_claim"] == "mail" assert cfg["icon_url"] == "https://sso.example.com/logo.png" + + +def test_every_var_the_reader_knows_is_registered_in_the_typo_guard(): + """An unregistered BAMBUDDY_* var logs "possible typo" at every boot, which + would tell operators their correct config is wrong. Asserted against the + reader's own vars rather than a copied list, so a var added later is caught + here instead of in someone's logs.""" + from backend.app.core.config import _INTENTIONAL_UNSETTINGS + + unregistered = {v for v in (*REQUIRED, *OPTIONAL) if v not in _INTENTIONAL_UNSETTINGS} + assert not unregistered From 05aebac67b8a8d0a0ba3ccb1c3463b38855933bd Mon Sep 17 00:00:00 2001 From: Marian Date: Mon, 20 Jul 2026 16:33:16 +0000 Subject: [PATCH 08/25] feat(oidc): show the env-managed provider as locked in settings The API answers 409 to any write against this provider, so offering edit, delete and the enable toggle would promise a change that cannot land -- the operator would click, see nothing happen, and have no way to tell why. The controls are hidden and a lock badge names the reason instead. Reuses settings.environmentManagedLabel, the string the Home Assistant env-managed fields already use: same situation, same wording, and no new key to keep in parity across eleven locales. is_env_managed is optional on the client type so a response from an older backend still type-checks. Refs #2593 --- .../components/OIDCProviderSettings.test.tsx | 51 +++++++++++++++++++ frontend/src/api/client.ts | 5 ++ .../src/components/OIDCProviderSettings.tsx | 50 ++++++++++++------ 3 files changed, 90 insertions(+), 16 deletions(-) diff --git a/frontend/src/__tests__/components/OIDCProviderSettings.test.tsx b/frontend/src/__tests__/components/OIDCProviderSettings.test.tsx index 1f40953b9..1436b7e20 100644 --- a/frontend/src/__tests__/components/OIDCProviderSettings.test.tsx +++ b/frontend/src/__tests__/components/OIDCProviderSettings.test.tsx @@ -325,3 +325,54 @@ describe('OIDCProviderSettings', () => { }); }); }); + +describe('env-managed provider (#2593)', () => { + const envManagedProvider = { + ...mockProviders[0], + id: 2, + name: 'EnvIdP', + is_env_managed: true, + }; + + it('marks the provider as environment managed', async () => { + server.use( + http.get('/api/v1/auth/oidc/providers/all', () => HttpResponse.json([envManagedProvider])) + ); + render(); + + await waitFor(() => { + expect(screen.getByText('EnvIdP')).toBeInTheDocument(); + }); + expect(screen.getByText(/Environment Managed/i)).toBeInTheDocument(); + }); + + it('offers no edit or delete control for it', async () => { + server.use( + http.get('/api/v1/auth/oidc/providers/all', () => HttpResponse.json([envManagedProvider])) + ); + render(); + + await waitFor(() => { + expect(screen.getByText('EnvIdP')).toBeInTheDocument(); + }); + // Startup rewrites this row from the environment on every boot, and the API + // answers 409 — offering the controls would promise an edit that cannot land. + expect(screen.queryByTestId('edit-provider-2')).not.toBeInTheDocument(); + expect(screen.queryByTestId('delete-provider-2')).not.toBeInTheDocument(); + }); + + it('still offers them for a UI-created provider', async () => { + server.use( + http.get('/api/v1/auth/oidc/providers/all', () => + HttpResponse.json([{ ...mockProviders[0], is_env_managed: false }]) + ) + ); + render(); + + await waitFor(() => { + expect(screen.getByText('TestIdP')).toBeInTheDocument(); + }); + expect(screen.getByTestId('edit-provider-1')).toBeInTheDocument(); + expect(screen.getByTestId('delete-provider-1')).toBeInTheDocument(); + }); +}); diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index f9cbbb212..a0da7257d 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -3518,6 +3518,11 @@ export interface OIDCProvider { // #1589: when true, the LoginPage redirects unauthenticated visitors // straight to this provider on mount. At most one provider may carry this. is_autologin: boolean; + // #2593: defined by BAMBUDDY_OIDC_* and rewritten from the environment on + // every boot. The API answers 409 to any write, so the settings UI must not + // offer edit/delete controls that cannot succeed. Optional so a response + // from an older backend still type-checks. + is_env_managed?: boolean; } export interface OIDCProviderCreate { diff --git a/frontend/src/components/OIDCProviderSettings.tsx b/frontend/src/components/OIDCProviderSettings.tsx index cacc0d952..6ec27aca9 100644 --- a/frontend/src/components/OIDCProviderSettings.tsx +++ b/frontend/src/components/OIDCProviderSettings.tsx @@ -1,6 +1,6 @@ import { useState, type ReactNode } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; -import { Plus, Edit2, Trash2, Globe, Check, X, RefreshCw, ExternalLink, ImageOff } from 'lucide-react'; +import { Plus, Edit2, Trash2, Globe, Check, X, RefreshCw, ExternalLink, ImageOff, Lock } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { api } from '../api/client'; import type { Group, OIDCProvider, OIDCProviderCreate } from '../api/client'; @@ -386,6 +386,11 @@ export function OIDCProviderSettings() { {t('common.disabled')} )} + {provider.is_env_managed && ( + + {t('settings.environmentManagedLabel')} + + )}
@@ -417,21 +422,34 @@ export function OIDCProviderSettings() { )} - toggleEnabled(provider)} - disabled={updateMutation.isPending} - /> - - + {/* #2593: startup rewrites the env-managed row from BAMBUDDY_OIDC_* + and the API answers 409, so offering these would promise a + change that cannot land. */} + {!provider.is_env_managed && ( + <> + toggleEnabled(provider)} + disabled={updateMutation.isPending} + /> + + + + )}
From f7c5efc7b275c974b7ee936b2cbb5fc878316dbf Mon Sep 17 00:00:00 2001 From: Marian Date: Mon, 20 Jul 2026 16:46:16 +0000 Subject: [PATCH 09/25] docs: document the BAMBUDDY_OIDC_* variables in .env.example Follows the BAMBUDDY_LOCAL_LOGIN block's style: what it is for, when it activates, and the two things an operator cannot guess from the variable names -- that removing the config disables rather than deletes the provider, because deleting would permanently drop every account link, and that the UI shows it read-only because startup would overwrite an edit anyway. Also states why auto-link is refused without verified emails, since that is the one setting that will be silently skipped if someone gets it wrong. Refs #2593 --- .env.example | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/.env.example b/.env.example index 572ab248d..7a2227b2e 100644 --- a/.env.example +++ b/.env.example @@ -66,3 +66,43 @@ LOG_TO_FILE=true # LDAP is governed by its own ldap_enabled toggle and is not affected. # Leave unset for normal operation. # BAMBUDDY_LOCAL_LOGIN=true + +# --- OIDC provider from the environment (#2593) ------------------------------ +# Defines ONE OIDC provider declaratively, for deployments that are managed by +# compose files or GitOps and never touch the settings UI. Providers created in +# the UI are unaffected and keep working alongside this one. +# +# Activates only when all four required vars below are set; an empty value +# counts as unset. The provider is written on startup and re-applied on every +# boot, so the UI shows it as read-only and the API refuses to change it -- an +# edit there would be reverted at the next restart anyway. +# +# Removing the vars DISABLES the provider rather than deleting it: accounts +# linked to it would otherwise lose their link permanently. Re-adding the vars +# enables it again with those links intact. +# +# If you lock yourself out, BAMBUDDY_LOCAL_LOGIN=true above is the way back in. +# +# Required: +# BAMBUDDY_OIDC_NAME=Keycloak +# BAMBUDDY_OIDC_ISSUER_URL=https://sso.example.com/realms/main +# BAMBUDDY_OIDC_CLIENT_ID=bambuddy +# BAMBUDDY_OIDC_CLIENT_SECRET=your-client-secret +# +# Optional, shown with their defaults: +# BAMBUDDY_OIDC_SCOPES=openid email profile +# BAMBUDDY_OIDC_ENABLED=true +# BAMBUDDY_OIDC_AUTO_CREATE_USERS=false +# BAMBUDDY_OIDC_AUTO_LINK_EXISTING=false +# BAMBUDDY_OIDC_EMAIL_CLAIM=email +# BAMBUDDY_OIDC_REQUIRE_EMAIL_VERIFIED=true +# BAMBUDDY_OIDC_ICON_URL= +# BAMBUDDY_OIDC_AUTOLOGIN=false +# +# Booleans accept true/1/yes; anything else keeps the default. +# +# AUTO_LINK_EXISTING binds an OIDC identity to an existing local account with +# the same email address. With EMAIL_CLAIM=email it is refused unless +# REQUIRE_EMAIL_VERIFIED=true, because an identity provider that does not +# verify addresses would let anyone claim someone else's account. The whole +# config is then skipped and logged; the app still starts. From c163b3524afd3d4b8511d48886642ecd39458de0 Mon Sep 17 00:00:00 2001 From: Marian Date: Tue, 21 Jul 2026 06:13:14 +0000 Subject: [PATCH 10/25] fix(oidc): identify the env provider by name, and release it when unconfigured Two problems, both from using is_env_managed as the provider's identity. An operator who names the env provider after one that already exists hit the unique constraint on `name` during the insert. That happens inside the lifespan, so the app did not boot -- from a function whose docstring promises it never raises. The lookup now matches on the name, which is unique, so an existing provider is adopted and updated instead of duplicated. And removing the config left the row disabled but still flagged, so the API went on refusing every edit and delete while nothing managed it any more: a dead end reachable only through the database. The flag is now cleared as well, handing the provider back to the UI. Re-adding the config finds the same row by name, so the account links it carries survive the round trip. Falls out of the same change: the issuer URL and client id can be rotated under an unchanged name without orphaning those links. Found by Marian asking what happens when you want to change the provider -- the answer was "you cannot, ever again". Refs #2593 --- backend/app/core/oidc_env.py | 35 +++++--- .../tests/integration/test_oidc_env_apply.py | 87 ++++++++++++++++++- 2 files changed, 111 insertions(+), 11 deletions(-) diff --git a/backend/app/core/oidc_env.py b/backend/app/core/oidc_env.py index 5d02bdd7b..39f9d6078 100644 --- a/backend/app/core/oidc_env.py +++ b/backend/app/core/oidc_env.py @@ -78,7 +78,7 @@ _APPLIED_FIELDS = ( async def apply_env_oidc_provider(db: AsyncSession) -> None: - """Upsert the env-managed provider, or disable it when the config is gone. + """Upsert the env-managed provider, or release it when the config is gone. Never raises: this runs during startup, and a typo in one variable must not stop the app from booting. A rejected config is logged and skipped. @@ -89,20 +89,35 @@ async def apply_env_oidc_provider(db: AsyncSession) -> None: from backend.app.schemas.auth import OIDCProviderCreate config = read_env_oidc_config() - existing = ( - await db.execute(select(OIDCProvider).where(OIDCProvider.is_env_managed.is_(True))) - ).scalar_one_or_none() if config is None: - # Disabled, never deleted: user_oidc_links.provider_id is FK ON DELETE - # CASCADE, so removing the row would unlink every bound account and the - # links would not come back when the variables do. - if existing is not None and existing.is_enabled: - existing.is_enabled = False + # Nothing to look up by name any more, so the previously managed row is + # found by the flag -- and then released. + released = ( + await db.execute(select(OIDCProvider).where(OIDCProvider.is_env_managed.is_(True))) + ).scalar_one_or_none() + if released is not None: + # Disabled, never deleted: user_oidc_links.provider_id is FK ON + # DELETE CASCADE, so removing the row would unlink every bound + # account and the links would not come back when the variables do. + # The flag is cleared as well: with no config behind it, a provider + # the API still refuses to edit or delete would be a dead end + # reachable only through the database. + released.is_enabled = False + released.is_env_managed = False await db.commit() - logger.info("BAMBUDDY_OIDC_* is unset -- env-managed provider disabled.") + logger.info( + "BAMBUDDY_OIDC_* is unset -- provider %r disabled and released to the UI.", + released.name, + ) return + # Identity is the name, which is unique on the table. Matching on the flag + # instead meant an operator who named the env provider after one that + # already existed hit that unique constraint during startup -- and this + # function runs in the lifespan, so the app would not boot. + existing = (await db.execute(select(OIDCProvider).where(OIDCProvider.name == config["name"]))).scalar_one_or_none() + try: # The same schema the API uses, so env config cannot reach a state the # UI would have refused (notably the SEC-1 auto-link check). diff --git a/backend/tests/integration/test_oidc_env_apply.py b/backend/tests/integration/test_oidc_env_apply.py index e83aeeba9..ac222431d 100644 --- a/backend/tests/integration/test_oidc_env_apply.py +++ b/backend/tests/integration/test_oidc_env_apply.py @@ -90,7 +90,10 @@ async def test_removing_the_env_config_disables_but_keeps_the_row(db_session, mo monkeypatch.delenv(key, raising=False) await apply_env_oidc_provider(db_session) - provider = await _env_provider(db_session) + # Looked up by name, not by the flag: releasing the provider clears the flag, + # and the point of this test is that the ROW survives either way. + result = await db_session.execute(select(OIDCProvider).where(OIDCProvider.name == "Keycloak")) + provider = result.scalar_one_or_none() assert provider is not None, "deleting would cascade away every account link" assert provider.id == original_id assert provider.is_enabled is False @@ -158,3 +161,85 @@ async def test_applying_twice_without_changes_is_a_no_op(db_session, monkeypatch result = await db_session.execute(select(OIDCProvider).where(OIDCProvider.is_env_managed.is_(True))) assert len(result.scalars().all()) == 1 + + +# --- identity is the name, not the flag --------------------------------------- +# The provider is looked up by BAMBUDDY_OIDC_NAME, which is unique on the table. +# Matching on is_env_managed instead made three things impossible: adopting a +# provider that already carries the name (the insert hit the unique constraint +# and took startup down with it), releasing the provider when the config goes +# away, and finding it again afterwards. + + +@pytest.mark.asyncio +async def test_a_name_collision_adopts_the_existing_provider(db_session, monkeypatch): + """An operator who names the env provider after one they created in the UI + must not end up with an app that refuses to boot.""" + ui_provider = OIDCProvider(name="Keycloak", issuer_url="https://old.example.com", client_id="ui-client") + ui_provider.client_secret = "ui-secret" + db_session.add(ui_provider) + await db_session.commit() + original_id = ui_provider.id + + _configure(monkeypatch) + await apply_env_oidc_provider(db_session) + + provider = await _env_provider(db_session) + assert provider is not None + assert provider.id == original_id, "adopted, not duplicated" + assert provider.client_id == "bambuddy" + + result = await db_session.execute(select(OIDCProvider).where(OIDCProvider.name == "Keycloak")) + assert len(result.scalars().all()) == 1 + + +@pytest.mark.asyncio +async def test_removing_the_config_releases_the_provider_to_the_ui(db_session, monkeypatch): + """Nothing manages it any more, so the API must stop refusing edits and + deletes -- otherwise the row is a dead end only reachable via the database.""" + _configure(monkeypatch) + await apply_env_oidc_provider(db_session) + + for key in ALL_VARS: + monkeypatch.delenv(key, raising=False) + await apply_env_oidc_provider(db_session) + + result = await db_session.execute(select(OIDCProvider).where(OIDCProvider.name == "Keycloak")) + provider = result.scalar_one() + assert provider.is_enabled is False + assert provider.is_env_managed is False + + +@pytest.mark.asyncio +async def test_restoring_the_config_finds_the_same_row_again(db_session, monkeypatch): + """The account links hang off this row; a second provider would orphan them.""" + _configure(monkeypatch) + await apply_env_oidc_provider(db_session) + original_id = (await _env_provider(db_session)).id + + for key in ALL_VARS: + monkeypatch.delenv(key, raising=False) + await apply_env_oidc_provider(db_session) + + _configure(monkeypatch) + await apply_env_oidc_provider(db_session) + + provider = await _env_provider(db_session) + assert provider.id == original_id + assert provider.is_enabled is True + + +@pytest.mark.asyncio +async def test_the_issuer_and_client_can_change_under_the_same_name(db_session, monkeypatch): + _configure(monkeypatch) + await apply_env_oidc_provider(db_session) + original_id = (await _env_provider(db_session)).id + + monkeypatch.setenv("BAMBUDDY_OIDC_ISSUER_URL", "https://sso.example.com/realms/other") + monkeypatch.setenv("BAMBUDDY_OIDC_CLIENT_ID", "rotated") + await apply_env_oidc_provider(db_session) + + provider = await _env_provider(db_session) + assert provider.id == original_id + assert provider.issuer_url == "https://sso.example.com/realms/other" + assert provider.client_id == "rotated" From 1116b43fbdd656f63776d7b1b18d63e5f1f30337 Mon Sep 17 00:00:00 2001 From: Marian Date: Tue, 28 Jul 2026 18:49:58 +0000 Subject: [PATCH 11/25] fix(oidc): never log the client_secret when env config is rejected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit apply_env_oidc_provider logged the raw Pydantic exception on rejection. client_secret has max_length=512, so a longer value raises string_too_long and str(exc) embeds input_value=..., leaking BAMBUDDY_OIDC_CLIENT_SECRET into the logs (maziggy review, PR #2625). Split the catch: ValidationError logs errors(include_input=False), which strips submitted values; any other exception logs only its class name, never str(exc). Rejection stays survivable — a bad config is still skipped and the app still boots. Adds two regression tests: an over-long secret is rejected without the value reaching the log, and a non-ValidationError is survived without leaking its message. Co-Authored-By: Claude Opus 4.8 (1M context) --- backend/app/core/oidc_env.py | 14 +++++- .../tests/integration/test_oidc_env_apply.py | 44 +++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/backend/app/core/oidc_env.py b/backend/app/core/oidc_env.py index 39f9d6078..c8e769dd1 100644 --- a/backend/app/core/oidc_env.py +++ b/backend/app/core/oidc_env.py @@ -12,6 +12,7 @@ from __future__ import annotations import logging import os +from pydantic import ValidationError from sqlalchemy import select, update from sqlalchemy.ext.asyncio import AsyncSession @@ -122,8 +123,19 @@ async def apply_env_oidc_provider(db: AsyncSession) -> None: # The same schema the API uses, so env config cannot reach a state the # UI would have refused (notably the SEC-1 auto-link check). validated = OIDCProviderCreate(**config) + except ValidationError as exc: + # errors(include_input=False) strips the submitted values -- str(exc) + # embeds input_value=... and would leak BAMBUDDY_OIDC_CLIENT_SECRET. + logger.error( + "BAMBUDDY_OIDC_* config rejected, provider not applied: %s", + exc.errors(include_input=False), + ) + return except Exception as exc: # noqa: BLE001 -- any rejection must be survivable - logger.error("BAMBUDDY_OIDC_* config rejected, provider not applied: %s", exc) + # Log only the exception class, never str(exc): an unexpected error here + # could carry a configured value in its message. Structural guarantee, + # not one contingent on which exceptions the schema validators raise. + logger.error("BAMBUDDY_OIDC_* config could not be applied: %s", type(exc).__name__) return if existing is None: diff --git a/backend/tests/integration/test_oidc_env_apply.py b/backend/tests/integration/test_oidc_env_apply.py index ac222431d..8f97842fd 100644 --- a/backend/tests/integration/test_oidc_env_apply.py +++ b/backend/tests/integration/test_oidc_env_apply.py @@ -7,6 +7,8 @@ recreating the provider would silently unlink every account bound to it. from __future__ import annotations +import logging + import pytest from sqlalchemy import select @@ -152,6 +154,48 @@ async def test_an_unsafe_auto_link_config_is_skipped_not_raised(db_session, monk assert await _env_provider(db_session) is None +@pytest.mark.asyncio +async def test_a_rejected_config_never_logs_the_client_secret(db_session, monkeypatch, caplog): + """client_secret has max_length=512, so an over-long value raises + string_too_long. The rejection must be logged without the value: str(exc) + embeds input_value=..., which would leak the secret (no-secrets-in-logs).""" + secret = "S3CR3T" * 100 # > 512 chars -> ValidationError on client_secret + _configure(monkeypatch, BAMBUDDY_OIDC_CLIENT_SECRET=secret) + + with caplog.at_level(logging.ERROR): + await apply_env_oidc_provider(db_session) + + assert await _env_provider(db_session) is None # rejected, not booted-through + assert "rejected" in caplog.text # the rejection was actually logged + assert secret not in caplog.text + assert "S3CR3T" not in caplog.text # not even a fragment of the value + + +@pytest.mark.asyncio +async def test_a_non_validation_error_is_survivable_and_leaks_nothing(db_session, monkeypatch, caplog): + """The generic except branch handles anything that isn't a ValidationError + (e.g. a library call raising mid-construction). It must not stop boot and, + since such a message could carry a configured value, must log only the + exception class -- never str(exc).""" + # oidc_env imports OIDCProviderCreate inside the function (to avoid an + # import cycle), so patch it at its source module, not on oidc_env. + import backend.app.schemas.auth as auth_schemas + + def _raise(**_kwargs): + raise RuntimeError("boom leaked-secret") + + monkeypatch.setattr(auth_schemas, "OIDCProviderCreate", _raise) + _configure(monkeypatch, BAMBUDDY_OIDC_CLIENT_SECRET="leaked-secret") + + with caplog.at_level(logging.ERROR): + await apply_env_oidc_provider(db_session) # must not raise + + assert await _env_provider(db_session) is None + assert "could not be applied" in caplog.text + assert "RuntimeError" in caplog.text # class is logged... + assert "leaked-secret" not in caplog.text # ...but nothing from the message + + @pytest.mark.asyncio async def test_applying_twice_without_changes_is_a_no_op(db_session, monkeypatch): """Every boot re-applies; the second run must not create a second row.""" From d64f5d96510dc132139bed17c634c783b4b93d56 Mon Sep 17 00:00:00 2001 From: Marian Date: Thu, 30 Jul 2026 14:43:23 +0000 Subject: [PATCH 12/25] fix(oidc): release the row the env config managed before a rename apply_env_oidc_provider matches the provider by BAMBUDDY_OIDC_NAME but never cleared is_env_managed from the row it managed previously. Renaming the variable therefore left two flagged rows, and both consequences are reachable by ordinary config edits: the old row stayed enabled with a stale issuer and secret on the login page while _refuse_if_env_managed answered 409 to every attempt to edit, disable or delete it -- the dead end reachable only through the database that the release path exists to prevent -- and unsetting the variables later hit scalar_one_or_none() on two rows, so MultipleResultsFound propagated out of the lifespan and the app stopped booting. The upsert now sweeps the flag off every other row, the same shape the autologin sweep one block down already uses: disable and release rather than delete, for the same cascade reason as everywhere else in this branch. The release path releases every flagged row it finds instead of exactly one -- the sweep should keep that at one, but a release path that dies with MultipleResultsFound the moment that invariant breaks is a second way to lose the boot, and the query costs the same either way. Releasing now clears is_autologin as well. Without it a released row keeps a latent autologin claim: update_oidc_provider only re-runs the exclusivity sweep when a request sets is_autologin=True, so merely re-enabling the row in the UI would silently make it the autologin target again. Reported by maziggy in review of #2625, with the rename reproduction. --- backend/app/core/oidc_env.py | 38 ++- .../tests/integration/test_oidc_env_apply.py | 229 ++++++++++++++++++ 2 files changed, 259 insertions(+), 8 deletions(-) diff --git a/backend/app/core/oidc_env.py b/backend/app/core/oidc_env.py index c8e769dd1..2e90b7053 100644 --- a/backend/app/core/oidc_env.py +++ b/backend/app/core/oidc_env.py @@ -92,12 +92,15 @@ async def apply_env_oidc_provider(db: AsyncSession) -> None: config = read_env_oidc_config() if config is None: - # Nothing to look up by name any more, so the previously managed row is - # found by the flag -- and then released. - released = ( - await db.execute(select(OIDCProvider).where(OIDCProvider.is_env_managed.is_(True))) - ).scalar_one_or_none() - if released is not None: + # Nothing to look up by name any more, so the previously managed rows are + # found by the flag -- and then released. All of them: an install + # upgraded from a version that did not sweep the flag on rename carries + # two, and scalar_one_or_none() would raise MultipleResultsFound out of + # the lifespan instead of booting. + released_rows = ( + (await db.execute(select(OIDCProvider).where(OIDCProvider.is_env_managed.is_(True)))).scalars().all() + ) + for released in released_rows: # Disabled, never deleted: user_oidc_links.provider_id is FK ON # DELETE CASCADE, so removing the row would unlink every bound # account and the links would not come back when the variables do. @@ -106,11 +109,17 @@ async def apply_env_oidc_provider(db: AsyncSession) -> None: # reachable only through the database. released.is_enabled = False released.is_env_managed = False - await db.commit() + # Cleared too, or the released row keeps a latent autologin claim: + # update_oidc_provider only re-runs the exclusivity sweep when a + # request sets is_autologin=True, so re-enabling this row in the UI + # would silently make it the autologin target again. + released.is_autologin = False logger.info( "BAMBUDDY_OIDC_* is unset -- provider %r disabled and released to the UI.", released.name, ) + if released_rows: + await db.commit() return # Identity is the name, which is unique on the table. Matching on the flag @@ -145,7 +154,20 @@ async def apply_env_oidc_provider(db: AsyncSession) -> None: setattr(existing, field, getattr(validated, field)) existing.client_secret = validated.client_secret existing.is_env_managed = True - await db.flush() # the id is needed by the autologin sweep below + await db.flush() # the id is needed by the sweeps below + + # Renaming BAMBUDDY_OIDC_NAME matches nothing, so the row managed until now + # stays behind. Left flagged it would keep a stale issuer and secret on the + # login page while the API refuses every edit, disable and delete on it + # (409) -- the dead end reachable only through the database that the release + # path exists to prevent -- and the next release would find two rows and + # take the boot down with MultipleResultsFound. Released, not deleted, for + # the same cascade reason as everywhere else. + await db.execute( + update(OIDCProvider) + .where(OIDCProvider.id != existing.id, OIDCProvider.is_env_managed.is_(True)) + .values(is_env_managed=False, is_enabled=False, is_autologin=False) + ) if existing.is_autologin: await db.execute( diff --git a/backend/tests/integration/test_oidc_env_apply.py b/backend/tests/integration/test_oidc_env_apply.py index 8f97842fd..3c9a7eb38 100644 --- a/backend/tests/integration/test_oidc_env_apply.py +++ b/backend/tests/integration/test_oidc_env_apply.py @@ -287,3 +287,232 @@ async def test_the_issuer_and_client_can_change_under_the_same_name(db_session, assert provider.id == original_id assert provider.issuer_url == "https://sso.example.com/realms/other" assert provider.client_id == "rotated" + + +# --- a rename must not leave the old row managed ------------------------------- +# Identity is the name, so renaming BAMBUDDY_OIDC_NAME matches nothing and +# creates a second row. Leaving the flag on the first one is what makes that +# fatal: it stays enabled with a stale issuer and secret on the login page, the +# API refuses every edit/disable/delete on it (409), and the release path's +# scalar_one_or_none() then raises MultipleResultsFound out of the lifespan -- +# the app stops booting. Both states are reachable by ordinary config edits. + + +async def _env_managed(db_session) -> list[OIDCProvider]: + result = await db_session.execute(select(OIDCProvider).where(OIDCProvider.is_env_managed.is_(True))) + return list(result.scalars().all()) + + +@pytest.mark.asyncio +async def test_renaming_the_provider_releases_the_row_it_managed_before(db_session, monkeypatch): + _configure(monkeypatch, BAMBUDDY_OIDC_AUTOLOGIN="true") + await apply_env_oidc_provider(db_session) + old_id = (await _env_provider(db_session)).id + + monkeypatch.setenv("BAMBUDDY_OIDC_NAME", "Authentik") + await apply_env_oidc_provider(db_session) + + managed = await _env_managed(db_session) + assert [p.name for p in managed] == ["Authentik"], "exactly one row may carry the flag" + + old = (await db_session.execute(select(OIDCProvider).where(OIDCProvider.id == old_id))).scalar_one() + # Released, not deleted -- user_oidc_links.provider_id cascades. + assert old.is_env_managed is False + assert old.is_enabled is False, "a stale issuer must not stay on the login page" + assert old.is_autologin is False + + +@pytest.mark.asyncio +async def test_boot_survives_removing_the_config_after_a_rename(db_session, monkeypatch): + """The MultipleResultsFound path: rename, then unset. Must not raise.""" + _configure(monkeypatch) + await apply_env_oidc_provider(db_session) + monkeypatch.setenv("BAMBUDDY_OIDC_NAME", "Authentik") + await apply_env_oidc_provider(db_session) + + for key in ALL_VARS: + monkeypatch.delenv(key, raising=False) + await apply_env_oidc_provider(db_session) # must not raise + + assert await _env_managed(db_session) == [] + names = (await db_session.execute(select(OIDCProvider.name))).scalars().all() + assert sorted(names) == ["Authentik", "Keycloak"], "both rows survive, both released" + + +@pytest.mark.asyncio +async def test_a_database_left_with_two_managed_rows_is_repaired(db_session, monkeypatch): + """An install upgraded from the version that never swept the flag already + has two managed rows. Releasing only one of them would leave the same dead + end behind, so the release path releases every row it finds.""" + for name in ("Keycloak", "Authentik"): + stale = OIDCProvider( + name=name, + issuer_url="https://sso.example.com/realms/main", + client_id="bambuddy", + is_env_managed=True, + ) + stale.client_secret = "s3cr3t" + db_session.add(stale) + await db_session.commit() + + await apply_env_oidc_provider(db_session) # no vars set -> release path + + assert await _env_managed(db_session) == [] + + +@pytest.mark.asyncio +async def test_releasing_the_provider_clears_autologin(db_session, monkeypatch): + """is_enabled and is_env_managed alone leave a UI-editable row carrying a + latent autologin claim: update_oidc_provider only runs the exclusivity + sweep when a request sets is_autologin=True, so merely re-enabling this row + makes it the autologin target again.""" + _configure(monkeypatch, BAMBUDDY_OIDC_AUTOLOGIN="true") + await apply_env_oidc_provider(db_session) + assert (await _env_provider(db_session)).is_autologin is True + + for key in ALL_VARS: + monkeypatch.delenv(key, raising=False) + await apply_env_oidc_provider(db_session) + + released = (await db_session.execute(select(OIDCProvider).where(OIDCProvider.name == "Keycloak"))).scalar_one() + assert released.is_autologin is False + + +# --- account links and collision behavior ------------------------------------ + + +@pytest.mark.asyncio +async def test_renaming_to_match_a_ui_provider_adopts_it_and_releases_the_old_row(db_session, monkeypatch): + """New name collides with existing UI provider: env config adopts that row, + old env-managed row is released. Identity is the name, so the collision is + resolved by matching the new name against the table.""" + # Start with env-managed "Keycloak" + _configure(monkeypatch) + await apply_env_oidc_provider(db_session) + old_id = (await _env_provider(db_session)).id + + # Add a UI provider named "Authentik" + ui_provider = OIDCProvider(name="Authentik", issuer_url="https://auth.example.com", client_id="ui-client") + ui_provider.client_secret = "ui-secret" + db_session.add(ui_provider) + await db_session.commit() + ui_id = ui_provider.id + + # Rename env provider to "Authentik" — matches the UI provider + monkeypatch.setenv("BAMBUDDY_OIDC_NAME", "Authentik") + await apply_env_oidc_provider(db_session) + + # The UI provider is adopted and becomes env-managed + provider = await _env_provider(db_session) + assert provider.id == ui_id, "adopted the UI provider" + assert provider.name == "Authentik" + assert provider.client_id == "bambuddy" # updated from env + assert provider.is_env_managed is True + + # The old Keycloak row is released + old = (await db_session.execute(select(OIDCProvider).where(OIDCProvider.id == old_id))).scalar_one() + assert old.name == "Keycloak" + assert old.is_env_managed is False + assert old.is_enabled is False + + +@pytest.mark.asyncio +async def test_account_links_survive_a_provider_rename(db_session, monkeypatch): + """The provider row is never deleted, only updated: user_oidc_links FK + ON DELETE CASCADE must not be triggered by a rename.""" + from backend.app.models.oidc_provider import UserOIDCLink + from backend.app.models.user import User + + # Create a user and link it to the env-managed provider + _configure(monkeypatch) + await apply_env_oidc_provider(db_session) + provider_id = (await _env_provider(db_session)).id + + user = User(username="testuser", email="test@example.com") + db_session.add(user) + await db_session.flush() + + link = UserOIDCLink( + user_id=user.id, + provider_id=provider_id, + provider_user_id="oidc-sub-12345", + provider_email="test@idp.example.com", + ) + db_session.add(link) + await db_session.commit() + + # Rename the env provider + monkeypatch.setenv("BAMBUDDY_OIDC_NAME", "Authentik") + await apply_env_oidc_provider(db_session) + + # The link still exists, pointing to the old row (which is now released) + result = await db_session.execute(select(UserOIDCLink).where(UserOIDCLink.provider_id == provider_id)) + links = result.scalars().all() + assert len(links) == 1 + assert links[0].provider_user_id == "oidc-sub-12345" + + +@pytest.mark.asyncio +async def test_renaming_with_autologin_updates_the_exclusivity_sweep(db_session, monkeypatch): + """When renamed env config has autologin=true, the sweep clears autologin + from other rows. The old row is released (autologin cleared there too).""" + # Setup: env provider "Keycloak" with autologin + _configure(monkeypatch, BAMBUDDY_OIDC_AUTOLOGIN="true") + await apply_env_oidc_provider(db_session) + old_id = (await _env_provider(db_session)).id + assert (await _env_provider(db_session)).is_autologin is True + + # Another UI provider also has autologin + ui_provider = OIDCProvider(name="UI", issuer_url="https://ui.example.com", client_id="ui") + ui_provider.client_secret = "secret" + ui_provider.is_autologin = True + db_session.add(ui_provider) + await db_session.commit() + + # Rename env provider to "Authentik" with autologin=true + monkeypatch.setenv("BAMBUDDY_OIDC_NAME", "Authentik") + await apply_env_oidc_provider(db_session) + + # New row is the autologin target + new_provider = await _env_provider(db_session) + assert new_provider.name == "Authentik" + assert new_provider.is_autologin is True + + # Old row is released and autologin cleared + old = (await db_session.execute(select(OIDCProvider).where(OIDCProvider.id == old_id))).scalar_one() + assert old.is_env_managed is False + assert old.is_autologin is False + + # UI provider autologin is cleared (only env-managed can be autologin now) + await db_session.refresh(ui_provider) + assert ui_provider.is_autologin is False + + +@pytest.mark.asyncio +async def test_restoring_env_config_after_rename_then_unset_finds_the_original_row(db_session, monkeypatch): + """Rename Keycloak → Authentik, unset everything, restore Keycloak. + Must re-enable the original row, not create a new one.""" + _configure(monkeypatch) + await apply_env_oidc_provider(db_session) + original_id = (await _env_provider(db_session)).id + + # Rename to Authentik + monkeypatch.setenv("BAMBUDDY_OIDC_NAME", "Authentik") + await apply_env_oidc_provider(db_session) + assert (await _env_provider(db_session)).name == "Authentik" + + # Unset everything + for key in ALL_VARS: + monkeypatch.delenv(key, raising=False) + await apply_env_oidc_provider(db_session) + + # Restore the original Keycloak config + _configure(monkeypatch) + await apply_env_oidc_provider(db_session) + + # Same row, re-enabled + provider = await _env_provider(db_session) + assert provider.id == original_id + assert provider.name == "Keycloak" + assert provider.is_enabled is True + assert provider.is_env_managed is True From ac2f4d058e36a2aecf8eaab0df21feb23ca15151 Mon Sep 17 00:00:00 2001 From: Marian Date: Thu, 30 Jul 2026 14:25:23 +0000 Subject: [PATCH 13/25] fix(oidc): hide the icon buttons on the env-managed provider too refresh-icon and remove-icon rendered outside the !provider.is_env_managed block, and both routes answer 409 for that provider -- so a click could only ever produce an error toast, which is the reason the comment right below them gives for hiding everything else. Its icon comes from BAMBUDDY_OIDC_ICON_URL and is re-applied on every boot. Reported by maziggy in review of #2625. --- .../components/OIDCProviderSettings.test.tsx | 40 ++++++++++++++ .../src/components/OIDCProviderSettings.tsx | 53 ++++++++++--------- 2 files changed, 67 insertions(+), 26 deletions(-) diff --git a/frontend/src/__tests__/components/OIDCProviderSettings.test.tsx b/frontend/src/__tests__/components/OIDCProviderSettings.test.tsx index 1436b7e20..91d35eaa4 100644 --- a/frontend/src/__tests__/components/OIDCProviderSettings.test.tsx +++ b/frontend/src/__tests__/components/OIDCProviderSettings.test.tsx @@ -361,6 +361,25 @@ describe('env-managed provider (#2593)', () => { expect(screen.queryByTestId('delete-provider-2')).not.toBeInTheDocument(); }); + it('offers no icon controls for it either', async () => { + server.use( + http.get('/api/v1/auth/oidc/providers/all', () => + HttpResponse.json([ + { ...envManagedProvider, icon_url: 'https://idp.example.com/i.png', has_icon: true }, + ]) + ) + ); + render(); + + await waitFor(() => { + expect(screen.getByText('EnvIdP')).toBeInTheDocument(); + }); + // Both icon routes answer 409 for an env-managed provider, so a click could + // only ever produce an error toast — the same reason the rest are hidden. + expect(screen.queryByTestId('refresh-icon-2')).not.toBeInTheDocument(); + expect(screen.queryByTestId('remove-icon-2')).not.toBeInTheDocument(); + }); + it('still offers them for a UI-created provider', async () => { server.use( http.get('/api/v1/auth/oidc/providers/all', () => @@ -375,4 +394,25 @@ describe('env-managed provider (#2593)', () => { expect(screen.getByTestId('edit-provider-1')).toBeInTheDocument(); expect(screen.getByTestId('delete-provider-1')).toBeInTheDocument(); }); + + it('hides the enable/disable toggle for env-managed providers', async () => { + server.use( + http.get('/api/v1/auth/oidc/providers/all', () => + HttpResponse.json([ + { ...mockProviders[0], id: 2, name: 'EnvIdP', is_enabled: true, is_env_managed: true }, + { ...mockProviders[0], id: 3, name: 'UiIdP', is_enabled: true, is_env_managed: false }, + ]) + ) + ); + render(); + + await waitFor(() => { + expect(screen.getByText('EnvIdP')).toBeInTheDocument(); + expect(screen.getByText('UiIdP')).toBeInTheDocument(); + }); + // The toggle carries no testid, so it is counted: two cards are rendered and + // exactly one switch may exist — the UI provider's. Enabling the env-managed + // one would be reverted by the next boot, and the API answers 409. + expect(screen.getAllByRole('switch')).toHaveLength(1); + }); }); diff --git a/frontend/src/components/OIDCProviderSettings.tsx b/frontend/src/components/OIDCProviderSettings.tsx index 6ec27aca9..a9ade30c5 100644 --- a/frontend/src/components/OIDCProviderSettings.tsx +++ b/frontend/src/components/OIDCProviderSettings.tsx @@ -398,35 +398,36 @@ export function OIDCProviderSettings() {
- {provider.icon_url && ( - - )} - {provider.has_icon && ( - - )} {/* #2593: startup rewrites the env-managed row from BAMBUDDY_OIDC_* - and the API answers 409, so offering these would promise a - change that cannot land. */} + and the API answers 409, so offering any of these would promise + a change that cannot land -- the icon routes included, where the + click only ever produced an error toast. */} {!provider.is_env_managed && ( <> + {provider.icon_url && ( + + )} + {provider.has_icon && ( + + )} toggleEnabled(provider)} From 3c679459e1cbc3097db6234ee4adcd09b21de829 Mon Sep 17 00:00:00 2001 From: Marian Date: Thu, 30 Jul 2026 14:26:04 +0000 Subject: [PATCH 14/25] feat(oidc): set the default group from the environment, by name Without it every account auto-created through the env provider fell back to Viewers (routes/mfa.py), and because the provider is locked the UI could not correct it either -- a real limitation for a declarative deployment running BAMBUDDY_OIDC_AUTO_CREATE_USERS=true. BAMBUDDY_OIDC_DEFAULT_GROUP names a group rather than an id: ids are handed out per installation, so the same compose file would point at a different group on the next deployment. The name is matched exactly, resolved against the database before anything is written, and default_group_id joins _APPLIED_FIELDS so dropping the variable clears the group again -- the environment is the whole truth for this row. A name that matches no group is refused rather than defaulted: silently landing users in Viewers is the failure this variable exists to remove, and the API already answers 422 for a default_group_id that does not exist. The refusal is logged and survivable, and it says which of the two cases happened, because they differ sharply -- an existing provider keeps running on its last good config, while on a first boot nothing is created and no SSO button appears. Raised by maziggy in review of #2625 as a scope decision; documented in .env.example and in the companion wiki PR. --- .env.example | 10 ++ backend/app/core/config.py | 1 + backend/app/core/oidc_env.py | 31 +++++ .../tests/integration/test_oidc_env_apply.py | 122 ++++++++++++++++++ backend/tests/unit/test_oidc_env_reader.py | 18 +++ 5 files changed, 182 insertions(+) diff --git a/.env.example b/.env.example index 7a2227b2e..40503b36b 100644 --- a/.env.example +++ b/.env.example @@ -98,9 +98,19 @@ LOG_TO_FILE=true # BAMBUDDY_OIDC_REQUIRE_EMAIL_VERIFIED=true # BAMBUDDY_OIDC_ICON_URL= # BAMBUDDY_OIDC_AUTOLOGIN=false +# BAMBUDDY_OIDC_DEFAULT_GROUP= # # Booleans accept true/1/yes; anything else keeps the default. # +# DEFAULT_GROUP is the group new users land in when AUTO_CREATE_USERS is on; +# without it they get Viewers. It matches a group NAME exactly (case-sensitive) +# -- group ids are assigned per install, so the same compose file would point at +# a different group on every deployment. A name that matches no group is +# refused: the provider is left as it was and the reason is logged, rather than +# quietly creating under-privileged users the locked UI could not correct. On a +# FIRST boot that means no provider is created at all and no SSO button appears +# -- create the group first. Removing the variable clears the group again. +# # AUTO_LINK_EXISTING binds an OIDC identity to an existing local account with # the same email address. With EMAIL_CLAIM=email it is refused unless # REQUIRE_EMAIL_VERIFIED=true, because an identity provider that does not diff --git a/backend/app/core/config.py b/backend/app/core/config.py index 72bbca2e5..d704b0a22 100644 --- a/backend/app/core/config.py +++ b/backend/app/core/config.py @@ -149,6 +149,7 @@ _INTENTIONAL_UNSETTINGS = { "BAMBUDDY_OIDC_REQUIRE_EMAIL_VERIFIED", "BAMBUDDY_OIDC_ICON_URL", "BAMBUDDY_OIDC_AUTOLOGIN", + "BAMBUDDY_OIDC_DEFAULT_GROUP", } _known_settings_fields = {f.upper() for f in settings.model_fields} diff --git a/backend/app/core/oidc_env.py b/backend/app/core/oidc_env.py index 2e90b7053..cda941442 100644 --- a/backend/app/core/oidc_env.py +++ b/backend/app/core/oidc_env.py @@ -58,6 +58,11 @@ def read_env_oidc_config() -> dict | None: "require_email_verified": _env_bool("BAMBUDDY_OIDC_REQUIRE_EMAIL_VERIFIED", True), "icon_url": os.environ.get("BAMBUDDY_OIDC_ICON_URL"), "is_autologin": _env_bool("BAMBUDDY_OIDC_AUTOLOGIN", False), + # A name, not an id: ids are assigned per install, so the same compose + # file would point at a different group on every deployment. Resolved + # against the database in apply_env_oidc_provider -- the reader has no + # session and stays dumb. + "default_group": (os.environ.get("BAMBUDDY_OIDC_DEFAULT_GROUP") or "").strip() or None, } @@ -75,6 +80,10 @@ _APPLIED_FIELDS = ( "require_email_verified", "icon_url", "is_autologin", + # Written on every boot, so a group that is no longer declared is cleared: + # the environment is the whole truth for this row, and the API lock means + # a lingering value could not be removed in the UI either. + "default_group_id", ) @@ -86,6 +95,7 @@ async def apply_env_oidc_provider(db: AsyncSession) -> None: """ # Imported here rather than at module scope: app.core is imported by the # models themselves, so a top-level import would be a cycle. + from backend.app.models.group import Group from backend.app.models.oidc_provider import OIDCProvider from backend.app.schemas.auth import OIDCProviderCreate @@ -128,6 +138,27 @@ async def apply_env_oidc_provider(db: AsyncSession) -> None: # function runs in the lifespan, so the app would not boot. existing = (await db.execute(select(OIDCProvider).where(OIDCProvider.name == config["name"]))).scalar_one_or_none() + # Resolved before anything is written, so a name that matches no group + # leaves the running provider untouched. Refused rather than defaulted: + # falling back would put every auto-created user in Viewers (routes/mfa.py) + # for as long as the typo lives, and the API answers 422 for a + # default_group_id that does not exist -- env config gets the same answer. + group_name = config.pop("default_group", None) + if group_name is not None: + group = (await db.execute(select(Group).where(Group.name == group_name))).scalar_one_or_none() + if group is None: + # Spelled out because the two cases differ sharply: an existing + # provider keeps running on its last good config, while on a first + # boot nothing is created at all and the login page has no SSO + # button until the name matches. + logger.error( + "BAMBUDDY_OIDC_DEFAULT_GROUP=%r matches no group, provider not applied (%s).", + group_name, + "previous config left running" if existing is not None else "no provider created", + ) + return + config["default_group_id"] = group.id + try: # The same schema the API uses, so env config cannot reach a state the # UI would have refused (notably the SEC-1 auto-link check). diff --git a/backend/tests/integration/test_oidc_env_apply.py b/backend/tests/integration/test_oidc_env_apply.py index 3c9a7eb38..19a40aac2 100644 --- a/backend/tests/integration/test_oidc_env_apply.py +++ b/backend/tests/integration/test_oidc_env_apply.py @@ -8,6 +8,7 @@ recreating the provider would silently unlink every account bound to it. from __future__ import annotations import logging +import os import pytest from sqlalchemy import select @@ -32,6 +33,7 @@ ALL_VARS = ( "BAMBUDDY_OIDC_REQUIRE_EMAIL_VERIFIED", "BAMBUDDY_OIDC_ICON_URL", "BAMBUDDY_OIDC_AUTOLOGIN", + "BAMBUDDY_OIDC_DEFAULT_GROUP", ) @@ -378,6 +380,96 @@ async def test_releasing_the_provider_clears_autologin(db_session, monkeypatch): assert released.is_autologin is False +# --- default group by name ----------------------------------------------------- +# Group ids are not stable across installs, so a declarative deployment cannot +# name one by id. Without this, every auto-created user falls back to Viewers +# (routes/mfa.py) and the env lock means the UI cannot correct the provider. + + +async def _group(db_session, name: str): + from backend.app.models.group import Group + + group = Group(name=name, description=f"Test group {name}") + db_session.add(group) + await db_session.commit() + return group + + +@pytest.mark.asyncio +async def test_the_default_group_is_resolved_by_name(db_session, monkeypatch): + group = await _group(db_session, "Operators") + _configure(monkeypatch, BAMBUDDY_OIDC_DEFAULT_GROUP="Operators") + + await apply_env_oidc_provider(db_session) + + assert (await _env_provider(db_session)).default_group_id == group.id + + +@pytest.mark.asyncio +async def test_an_unknown_group_name_is_rejected_rather_than_defaulted(db_session, monkeypatch, caplog): + """Silently falling back to Viewers is how a typo mints under-privileged + users for weeks. The API answers 400 for a default_group_id that does not + exist; env config gets the same answer, logged and survivable.""" + _configure(monkeypatch, BAMBUDDY_OIDC_DEFAULT_GROUP="Nope") + + with caplog.at_level(logging.ERROR): + await apply_env_oidc_provider(db_session) + + assert await _env_provider(db_session) is None + assert "BAMBUDDY_OIDC_DEFAULT_GROUP" in caplog.text + assert "Nope" in caplog.text + + +@pytest.mark.asyncio +async def test_an_unknown_group_name_leaves_the_previous_provider_intact(db_session, monkeypatch): + """Rejection happens before the upsert, so the running config survives a + bad edit -- the provider keeps working until the operator fixes the name.""" + group = await _group(db_session, "Operators") + _configure(monkeypatch, BAMBUDDY_OIDC_DEFAULT_GROUP="Operators") + await apply_env_oidc_provider(db_session) + + monkeypatch.setenv("BAMBUDDY_OIDC_DEFAULT_GROUP", "Typo") + await apply_env_oidc_provider(db_session) + + provider = await _env_provider(db_session) + assert provider is not None + assert provider.default_group_id == group.id + + +@pytest.mark.asyncio +async def test_no_group_variable_leaves_the_default_group_unset(db_session, monkeypatch): + _configure(monkeypatch) + await apply_env_oidc_provider(db_session) + + assert (await _env_provider(db_session)).default_group_id is None + + +@pytest.mark.asyncio +async def test_removing_the_group_variable_clears_the_default_group(db_session, monkeypatch): + """The environment is the whole truth for this row; a group that is no + longer declared must not linger, since the lock blocks removing it in the UI.""" + await _group(db_session, "Operators") + _configure(monkeypatch, BAMBUDDY_OIDC_DEFAULT_GROUP="Operators") + await apply_env_oidc_provider(db_session) + + monkeypatch.delenv("BAMBUDDY_OIDC_DEFAULT_GROUP") + await apply_env_oidc_provider(db_session) + + assert (await _env_provider(db_session)).default_group_id is None + + +@pytest.mark.asyncio +async def test_an_empty_group_variable_counts_as_unset(db_session, monkeypatch): + """Same rule the required vars follow: an empty value in a compose file is + a forgotten value, not a request to reject the config.""" + _configure(monkeypatch, BAMBUDDY_OIDC_DEFAULT_GROUP="") + await apply_env_oidc_provider(db_session) + + provider = await _env_provider(db_session) + assert provider is not None + assert provider.default_group_id is None + + # --- account links and collision behavior ------------------------------------ @@ -488,6 +580,36 @@ async def test_renaming_with_autologin_updates_the_exclusivity_sweep(db_session, assert ui_provider.is_autologin is False +@pytest.mark.asyncio +async def test_group_name_matching_is_case_sensitive(db_session, monkeypatch, caplog): + """Group name is resolved by exact match; 'operators' != 'Operators'.""" + await _group(db_session, "Operators") # capital O + _configure(monkeypatch, BAMBUDDY_OIDC_DEFAULT_GROUP="operators") # lowercase + + with caplog.at_level(logging.ERROR): + await apply_env_oidc_provider(db_session) + + # Config is rejected + assert await _env_provider(db_session) is None + assert "operators" in caplog.text + assert "BAMBUDDY_OIDC_DEFAULT_GROUP" in caplog.text + + +@pytest.mark.asyncio +async def test_group_name_rejection_does_not_log_the_secret(db_session, monkeypatch, caplog): + """Group resolution happens before schema validation, so the secret is + not yet in scope, but verify it's not leaked by the error path.""" + _configure(monkeypatch, BAMBUDDY_OIDC_DEFAULT_GROUP="NonExistent") + secret = os.environ["BAMBUDDY_OIDC_CLIENT_SECRET"] + + with caplog.at_level(logging.ERROR): + await apply_env_oidc_provider(db_session) + + # Config is rejected but secret is safe + assert await _env_provider(db_session) is None + assert secret not in caplog.text + + @pytest.mark.asyncio async def test_restoring_env_config_after_rename_then_unset_finds_the_original_row(db_session, monkeypatch): """Rename Keycloak → Authentik, unset everything, restore Keycloak. diff --git a/backend/tests/unit/test_oidc_env_reader.py b/backend/tests/unit/test_oidc_env_reader.py index 307bf3dba..7a9c4ed96 100644 --- a/backend/tests/unit/test_oidc_env_reader.py +++ b/backend/tests/unit/test_oidc_env_reader.py @@ -28,6 +28,7 @@ OPTIONAL = ( "BAMBUDDY_OIDC_REQUIRE_EMAIL_VERIFIED", "BAMBUDDY_OIDC_ICON_URL", "BAMBUDDY_OIDC_AUTOLOGIN", + "BAMBUDDY_OIDC_DEFAULT_GROUP", ) @@ -118,6 +119,23 @@ def test_optional_strings_override_their_defaults(monkeypatch): assert cfg["icon_url"] == "https://sso.example.com/logo.png" +def test_the_default_group_is_read_as_a_name(monkeypatch): + """A name, not an id: group ids differ per install, so an id in a compose + file would point at whatever group happened to be created third.""" + _set_required(monkeypatch) + monkeypatch.setenv("BAMBUDDY_OIDC_DEFAULT_GROUP", "Operators") + cfg = read_env_oidc_config() + assert cfg["default_group"] == "Operators" + assert "default_group_id" not in cfg, "resolution needs the database, not the reader" + + +@pytest.mark.parametrize("raw", ["", " "]) +def test_a_blank_default_group_is_unset(monkeypatch, raw): + _set_required(monkeypatch) + monkeypatch.setenv("BAMBUDDY_OIDC_DEFAULT_GROUP", raw) + assert read_env_oidc_config()["default_group"] is None + + def test_every_var_the_reader_knows_is_registered_in_the_typo_guard(): """An unregistered BAMBUDDY_* var logs "possible typo" at every boot, which would tell operators their correct config is wrong. Asserted against the From ed29319cf977fe520a84b3702e0166c89fd0dc61 Mon Sep 17 00:00:00 2001 From: Marian Date: Thu, 30 Jul 2026 14:44:49 +0000 Subject: [PATCH 15/25] docs(oidc): drop the upgrade-path claim from the release-path rationale The two-flagged-row state was never released, so no installation can carry it in -- the reason to release every flagged row is not repair, it is that the sweep's invariant is not enforced anywhere and scalar_one_or_none() turns a broken one into a failed boot. Comment, test docstring and test name say that instead. --- backend/app/core/oidc_env.py | 8 ++++---- backend/tests/integration/test_oidc_env_apply.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/backend/app/core/oidc_env.py b/backend/app/core/oidc_env.py index cda941442..07cfc54ce 100644 --- a/backend/app/core/oidc_env.py +++ b/backend/app/core/oidc_env.py @@ -103,10 +103,10 @@ async def apply_env_oidc_provider(db: AsyncSession) -> None: if config is None: # Nothing to look up by name any more, so the previously managed rows are - # found by the flag -- and then released. All of them: an install - # upgraded from a version that did not sweep the flag on rename carries - # two, and scalar_one_or_none() would raise MultipleResultsFound out of - # the lifespan instead of booting. + # found by the flag -- and then released. All of them: the upsert's sweep + # should keep that at one, but scalar_one_or_none() would raise + # MultipleResultsFound out of the lifespan the moment it isn't, and + # losing the boot is too steep a price for an invariant check. released_rows = ( (await db.execute(select(OIDCProvider).where(OIDCProvider.is_env_managed.is_(True)))).scalars().all() ) diff --git a/backend/tests/integration/test_oidc_env_apply.py b/backend/tests/integration/test_oidc_env_apply.py index 19a40aac2..1d9066fd8 100644 --- a/backend/tests/integration/test_oidc_env_apply.py +++ b/backend/tests/integration/test_oidc_env_apply.py @@ -342,10 +342,10 @@ async def test_boot_survives_removing_the_config_after_a_rename(db_session, monk @pytest.mark.asyncio -async def test_a_database_left_with_two_managed_rows_is_repaired(db_session, monkeypatch): - """An install upgraded from the version that never swept the flag already - has two managed rows. Releasing only one of them would leave the same dead - end behind, so the release path releases every row it finds.""" +async def test_every_managed_row_is_released_not_just_one(db_session, monkeypatch): + """The upsert's sweep should keep this at one row. Should is not enforced by + the schema, and the cost of being wrong is the whole release path raising + MultipleResultsFound out of the lifespan -- so it releases what it finds.""" for name in ("Keycloak", "Authentik"): stale = OIDCProvider( name=name, From 6dff1e964471ab3de6e0d72b998b7cb69830f3f3 Mon Sep 17 00:00:00 2001 From: Marian Date: Fri, 31 Jul 2026 13:10:14 +0000 Subject: [PATCH 16/25] fix(oidc): make apply_env_oidc_provider never raise on DB errors The db.execute/db.commit calls in the upsert and release paths sat outside the try/except that only wrapped OIDCProviderCreate, so a commit failure at startup (connection blip, WAL lock) propagated out of the lifespan and took the instance down -- the exact outcome this module exists to avoid. The body now runs inside a private _apply_env_oidc_provider(), with the public entry point catching, logging and rolling back on any exception. --- backend/app/core/oidc_env.py | 16 ++++++++++++-- .../tests/integration/test_oidc_env_apply.py | 22 +++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/backend/app/core/oidc_env.py b/backend/app/core/oidc_env.py index 07cfc54ce..16a3f3d71 100644 --- a/backend/app/core/oidc_env.py +++ b/backend/app/core/oidc_env.py @@ -90,9 +90,21 @@ _APPLIED_FIELDS = ( async def apply_env_oidc_provider(db: AsyncSession) -> None: """Upsert the env-managed provider, or release it when the config is gone. - Never raises: this runs during startup, and a typo in one variable must not - stop the app from booting. A rejected config is logged and skipped. + Never raises: this runs during startup, and a typo in one variable -- or a + DB error on commit -- must not stop the app from booting. A rejected + config is logged and skipped. """ + try: + await _apply_env_oidc_provider(db) + except Exception as exc: # noqa: BLE001 -- startup must survive any failure here + # Never str(exc): a DB error message can echo a configured value. Class only. + logger.error("BAMBUDDY_OIDC_* could not be applied: %s", type(exc).__name__) + # A commit may have half-applied; roll back so the shared session is + # left clean for the rest of startup. + await db.rollback() + + +async def _apply_env_oidc_provider(db: AsyncSession) -> None: # Imported here rather than at module scope: app.core is imported by the # models themselves, so a top-level import would be a cycle. from backend.app.models.group import Group diff --git a/backend/tests/integration/test_oidc_env_apply.py b/backend/tests/integration/test_oidc_env_apply.py index 1d9066fd8..965ee1c78 100644 --- a/backend/tests/integration/test_oidc_env_apply.py +++ b/backend/tests/integration/test_oidc_env_apply.py @@ -198,6 +198,28 @@ async def test_a_non_validation_error_is_survivable_and_leaks_nothing(db_session assert "leaked-secret" not in caplog.text # ...but nothing from the message +@pytest.mark.asyncio +async def test_a_commit_failure_is_survivable_and_leaks_nothing(db_session, monkeypatch, caplog): + """The upsert's db.execute/db.commit calls sit outside the inner + ValidationError guard -- a Postgres blip or a SQLite WAL lock at startup + must not propagate out of the lifespan either. Only the exception class + may be logged, never str(exc), since a DB error message can echo a + configured value.""" + + async def _raise_on_commit(): + raise RuntimeError("database is locked") + + monkeypatch.setattr(db_session, "commit", _raise_on_commit) + _configure(monkeypatch, BAMBUDDY_OIDC_CLIENT_SECRET="leaked-secret") + + with caplog.at_level(logging.ERROR): + await apply_env_oidc_provider(db_session) # must not raise + + assert "could not be applied" in caplog.text + assert "RuntimeError" in caplog.text # class is logged... + assert "leaked-secret" not in caplog.text # ...but nothing from the message + + @pytest.mark.asyncio async def test_applying_twice_without_changes_is_a_no_op(db_session, monkeypatch): """Every boot re-applies; the second run must not create a second row.""" From c4b5d42f48886a866c1350b82c64e23a2bcd7749 Mon Sep 17 00:00:00 2001 From: Marian Date: Fri, 31 Jul 2026 13:11:15 +0000 Subject: [PATCH 17/25] fix(oidc): log distinctly when env config adopts a UI-created provider A name collision with a provider that was NOT already env-managed overwrites its issuer, client id and secret in place and locks it behind the env-managed 409 -- but it logged the same routine "applied" line as an ordinary re-apply, giving no signal a UI provider was just taken over. Adoption is now a WARNING with its own wording; a routine re-apply of an already env-managed provider keeps the INFO line. --- backend/app/core/oidc_env.py | 14 +++++++- .../tests/integration/test_oidc_env_apply.py | 32 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/backend/app/core/oidc_env.py b/backend/app/core/oidc_env.py index 16a3f3d71..123399f75 100644 --- a/backend/app/core/oidc_env.py +++ b/backend/app/core/oidc_env.py @@ -190,6 +190,11 @@ async def _apply_env_oidc_provider(db: AsyncSession) -> None: logger.error("BAMBUDDY_OIDC_* config could not be applied: %s", type(exc).__name__) return + # Computed before `existing` is reassigned below: a freshly-created row is + # not an adoption, and a found row that was already env-managed is a + # routine re-apply -- only a found row that the UI created is an adoption. + adopted_ui_provider = existing is not None and not existing.is_env_managed + if existing is None: existing = OIDCProvider(is_env_managed=True) db.add(existing) @@ -219,4 +224,11 @@ async def _apply_env_oidc_provider(db: AsyncSession) -> None: .values(is_autologin=False) ) await db.commit() - logger.info("Env-managed OIDC provider %r applied.", existing.name) + if adopted_ui_provider: + logger.warning( + "Env-managed OIDC provider %r adopted an existing UI-created provider of the " + "same name; its issuer, client and secret are now managed by BAMBUDDY_OIDC_*.", + existing.name, + ) + else: + logger.info("Env-managed OIDC provider %r applied.", existing.name) diff --git a/backend/tests/integration/test_oidc_env_apply.py b/backend/tests/integration/test_oidc_env_apply.py index 965ee1c78..5fce40c48 100644 --- a/backend/tests/integration/test_oidc_env_apply.py +++ b/backend/tests/integration/test_oidc_env_apply.py @@ -261,6 +261,38 @@ async def test_a_name_collision_adopts_the_existing_provider(db_session, monkeyp assert len(result.scalars().all()) == 1 +@pytest.mark.asyncio +async def test_adopting_a_ui_provider_logs_a_distinct_warning(db_session, monkeypatch, caplog): + """Overwriting a UI-created provider in place is a bigger deal than a + routine re-apply -- it must not be silent at the same INFO level.""" + ui_provider = OIDCProvider(name="Keycloak", issuer_url="https://old.example.com", client_id="ui-client") + ui_provider.client_secret = "ui-secret" + db_session.add(ui_provider) + await db_session.commit() + + _configure(monkeypatch) + with caplog.at_level(logging.INFO): + await apply_env_oidc_provider(db_session) + + warnings = [r for r in caplog.records if r.levelname == "WARNING"] + assert any("adopted" in r.message for r in warnings) + + +@pytest.mark.asyncio +async def test_a_routine_reapply_does_not_log_an_adoption_warning(db_session, monkeypatch, caplog): + """The same provider re-applying on the next boot is not an adoption -- + it was already env-managed.""" + _configure(monkeypatch) + await apply_env_oidc_provider(db_session) + caplog.clear() + + with caplog.at_level(logging.INFO): + await apply_env_oidc_provider(db_session) + + warnings = [r for r in caplog.records if r.levelname == "WARNING"] + assert not any("adopted" in r.message for r in warnings) + + @pytest.mark.asyncio async def test_removing_the_config_releases_the_provider_to_the_ui(db_session, monkeypatch): """Nothing manages it any more, so the API must stop refusing edits and From f6e0d767317daa1d0ab71b4d07a20b1f8804ea07 Mon Sep 17 00:00:00 2001 From: Marian Date: Fri, 31 Jul 2026 13:11:41 +0000 Subject: [PATCH 18/25] docs(oidc): document issuer URL policy and name-collision adoption .env.example described what the required vars do but not two sharp edges: the issuer must be a public HTTPS URL (an in-cluster http://keycloak:8080 is silently refused), and BAMBUDDY_OIDC_NAME matches an existing UI-created provider by name and takes it over. --- .env.example | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.env.example b/.env.example index 40503b36b..12e4e3d1c 100644 --- a/.env.example +++ b/.env.example @@ -116,3 +116,13 @@ LOG_TO_FILE=true # REQUIRE_EMAIL_VERIFIED=true, because an identity provider that does not # verify addresses would let anyone claim someone else's account. The whole # config is then skipped and logged; the app still starts. +# +# ISSUER_URL must be https:// and publicly reachable -- private, loopback, +# link-local, numeric-encoded and IPv4-mapped hosts are rejected. An in-cluster +# URL like http://keycloak:8080 is refused with a single log line and no SSO +# button; use the externally-reachable HTTPS issuer URL instead. +# +# NAME is matched against the existing providers on every boot: setting it to +# the name of one you already created in the UI ADOPTS and OVERWRITES it (its +# issuer, client id and secret are replaced and it becomes read-only). Pick a +# name that doesn't collide unless that takeover is intended. From be19461470e2f12a98c6f1f470fdd01c34bbe6c1 Mon Sep 17 00:00:00 2001 From: Marian Date: Fri, 31 Jul 2026 13:12:44 +0000 Subject: [PATCH 19/25] refactor(auth): reuse oidc_env's truthy-bool helper for BAMBUDDY_LOCAL_LOGIN _local_login_env_bypass() re-inlined the same {"true", "1", "yes"} set oidc_env._env_bool already enforces, so the typo-guard existed in two places. oidc_env has no module-scope import of models (its model imports are lazy inside apply_env_oidc_provider), so importing _env_bool at module scope here is not a cycle -- confirmed by importing backend.app.main and this module directly. --- backend/app/api/routes/auth.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/app/api/routes/auth.py b/backend/app/api/routes/auth.py index d72ecc384..9e4e0fa43 100644 --- a/backend/app/api/routes/auth.py +++ b/backend/app/api/routes/auth.py @@ -35,6 +35,7 @@ from backend.app.core.auth import ( security, ) from backend.app.core.database import async_session, get_db +from backend.app.core.oidc_env import _env_bool from backend.app.core.permissions import ALL_PERMISSIONS from backend.app.models.auth_ephemeral import AuthEphemeralToken, AuthRateLimitEvent, EventType, TokenType from backend.app.models.group import Group @@ -122,7 +123,7 @@ def _local_login_env_bypass() -> bool: an install whose SSO provider is unreachable. Accepted truthy values: ``true``, ``1``, ``yes`` (case-insensitive). """ - return os.environ.get("BAMBUDDY_LOCAL_LOGIN", "").strip().lower() in {"true", "1", "yes"} + return _env_bool("BAMBUDDY_LOCAL_LOGIN", False) def _get_client_ip(request: Request) -> str: From 6eea61dc789a0441eebdf6895ff03ed2583f1ffc Mon Sep 17 00:00:00 2001 From: Marian Date: Fri, 31 Jul 2026 13:18:21 +0000 Subject: [PATCH 20/25] fix(oidc): survive a failing rollback in the never-raise handler too The recovery rollback after a failed commit was itself unguarded, so a rollback that raises on a wedged connection would still take the boot down -- the exact failure the never-raise contract exists to prevent. Suppressed; the caller's `async with` discards the session regardless. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_016q8EAf9Rj7ZHL92sPnXYxy --- backend/app/core/oidc_env.py | 9 ++++++-- .../tests/integration/test_oidc_env_apply.py | 23 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/backend/app/core/oidc_env.py b/backend/app/core/oidc_env.py index 123399f75..a82b81dff 100644 --- a/backend/app/core/oidc_env.py +++ b/backend/app/core/oidc_env.py @@ -9,6 +9,7 @@ check the UI enforces. from __future__ import annotations +import contextlib import logging import os @@ -100,8 +101,12 @@ async def apply_env_oidc_provider(db: AsyncSession) -> None: # Never str(exc): a DB error message can echo a configured value. Class only. logger.error("BAMBUDDY_OIDC_* could not be applied: %s", type(exc).__name__) # A commit may have half-applied; roll back so the shared session is - # left clean for the rest of startup. - await db.rollback() + # left clean for the rest of startup. Suppressed because rollback on a + # wedged connection can itself raise -- and the whole point here is that + # nothing in this path takes the boot down. The session is discarded by + # the caller's `async with` regardless. + with contextlib.suppress(Exception): + await db.rollback() async def _apply_env_oidc_provider(db: AsyncSession) -> None: diff --git a/backend/tests/integration/test_oidc_env_apply.py b/backend/tests/integration/test_oidc_env_apply.py index 5fce40c48..60f9b913c 100644 --- a/backend/tests/integration/test_oidc_env_apply.py +++ b/backend/tests/integration/test_oidc_env_apply.py @@ -220,6 +220,29 @@ async def test_a_commit_failure_is_survivable_and_leaks_nothing(db_session, monk assert "leaked-secret" not in caplog.text # ...but nothing from the message +@pytest.mark.asyncio +async def test_a_failing_rollback_is_also_survivable(db_session, monkeypatch, caplog): + """The handler rolls back after a failed commit -- but rollback on a wedged + connection can raise too, and 'never raises' has to hold for that as well + or the boot dies on the recovery path. The rollback is suppressed.""" + + async def _raise_on_commit(): + raise RuntimeError("database is locked") + + async def _raise_on_rollback(): + raise RuntimeError("connection is closed") + + monkeypatch.setattr(db_session, "commit", _raise_on_commit) + monkeypatch.setattr(db_session, "rollback", _raise_on_rollback) + _configure(monkeypatch, BAMBUDDY_OIDC_CLIENT_SECRET="leaked-secret") + + with caplog.at_level(logging.ERROR): + await apply_env_oidc_provider(db_session) # must not raise, even here + + assert "could not be applied" in caplog.text + assert "leaked-secret" not in caplog.text + + @pytest.mark.asyncio async def test_applying_twice_without_changes_is_a_no_op(db_session, monkeypatch): """Every boot re-applies; the second run must not create a second row.""" From c547505c641b45bed265c8aaa6dbed8ab73da87c Mon Sep 17 00:00:00 2001 From: Marian Date: Sat, 1 Aug 2026 08:36:56 +0000 Subject: [PATCH 21/25] fix(oidc): treat a blank optional env var as unset, not a refusal BAMBUDDY_OIDC_SCOPES, _EMAIL_CLAIM and _ICON_URL fell back to their default only when the key was absent, so `BAMBUDDY_OIDC_ICON_URL=` in a compose file (as .env.example ships it, commented) reached the schema validator as an empty string and got the whole provider refused. default_group already treated blank as unset; these three now follow the same rule. --- backend/app/core/oidc_env.py | 6 ++-- .../tests/integration/test_oidc_env_apply.py | 35 +++++++++++++++++++ backend/tests/unit/test_oidc_env_reader.py | 27 ++++++++++++++ 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/backend/app/core/oidc_env.py b/backend/app/core/oidc_env.py index a82b81dff..62269cb22 100644 --- a/backend/app/core/oidc_env.py +++ b/backend/app/core/oidc_env.py @@ -51,13 +51,13 @@ def read_env_oidc_config() -> dict | None: "issuer_url": os.environ["BAMBUDDY_OIDC_ISSUER_URL"], "client_id": os.environ["BAMBUDDY_OIDC_CLIENT_ID"], "client_secret": os.environ["BAMBUDDY_OIDC_CLIENT_SECRET"], - "scopes": os.environ.get("BAMBUDDY_OIDC_SCOPES", "openid email profile"), + "scopes": (os.environ.get("BAMBUDDY_OIDC_SCOPES") or "").strip() or "openid email profile", "is_enabled": _env_bool("BAMBUDDY_OIDC_ENABLED", True), "auto_create_users": _env_bool("BAMBUDDY_OIDC_AUTO_CREATE_USERS", False), "auto_link_existing_accounts": _env_bool("BAMBUDDY_OIDC_AUTO_LINK_EXISTING", False), - "email_claim": os.environ.get("BAMBUDDY_OIDC_EMAIL_CLAIM", "email"), + "email_claim": (os.environ.get("BAMBUDDY_OIDC_EMAIL_CLAIM") or "").strip() or "email", "require_email_verified": _env_bool("BAMBUDDY_OIDC_REQUIRE_EMAIL_VERIFIED", True), - "icon_url": os.environ.get("BAMBUDDY_OIDC_ICON_URL"), + "icon_url": (os.environ.get("BAMBUDDY_OIDC_ICON_URL") or "").strip() or None, "is_autologin": _env_bool("BAMBUDDY_OIDC_AUTOLOGIN", False), # A name, not an id: ids are assigned per install, so the same compose # file would point at a different group on every deployment. Resolved diff --git a/backend/tests/integration/test_oidc_env_apply.py b/backend/tests/integration/test_oidc_env_apply.py index 60f9b913c..76c224e85 100644 --- a/backend/tests/integration/test_oidc_env_apply.py +++ b/backend/tests/integration/test_oidc_env_apply.py @@ -547,6 +547,41 @@ async def test_an_empty_group_variable_counts_as_unset(db_session, monkeypatch): assert provider.default_group_id is None +# --- blank optional strings count as unset, not a refusal --------------------- +# `.env.example` ships `# BAMBUDDY_OIDC_ICON_URL=` commented out, so uncommenting +# it must not take the provider down -- same rule default_group already follows. + + +@pytest.mark.asyncio +async def test_a_blank_scopes_still_creates_the_provider(db_session, monkeypatch): + _configure(monkeypatch, BAMBUDDY_OIDC_SCOPES="") + await apply_env_oidc_provider(db_session) + + provider = await _env_provider(db_session) + assert provider is not None, "a blank optional var must not refuse the whole provider" + assert provider.scopes == "openid email profile" + + +@pytest.mark.asyncio +async def test_a_blank_email_claim_still_creates_the_provider(db_session, monkeypatch): + _configure(monkeypatch, BAMBUDDY_OIDC_EMAIL_CLAIM="") + await apply_env_oidc_provider(db_session) + + provider = await _env_provider(db_session) + assert provider is not None, "a blank optional var must not refuse the whole provider" + assert provider.email_claim == "email" + + +@pytest.mark.asyncio +async def test_a_blank_icon_url_still_creates_the_provider(db_session, monkeypatch): + _configure(monkeypatch, BAMBUDDY_OIDC_ICON_URL="") + await apply_env_oidc_provider(db_session) + + provider = await _env_provider(db_session) + assert provider is not None, "a blank optional var must not refuse the whole provider" + assert provider.icon_url is None + + # --- account links and collision behavior ------------------------------------ diff --git a/backend/tests/unit/test_oidc_env_reader.py b/backend/tests/unit/test_oidc_env_reader.py index 7a9c4ed96..80cc5cb17 100644 --- a/backend/tests/unit/test_oidc_env_reader.py +++ b/backend/tests/unit/test_oidc_env_reader.py @@ -119,6 +119,33 @@ def test_optional_strings_override_their_defaults(monkeypatch): assert cfg["icon_url"] == "https://sso.example.com/logo.png" +@pytest.mark.parametrize("raw", ["", " "]) +def test_a_blank_scopes_is_unset(monkeypatch, raw): + """`BAMBUDDY_OIDC_SCOPES=` in a compose file is a forgotten value, not a + request for a provider with no scopes -- same rule as default_group.""" + _set_required(monkeypatch) + monkeypatch.setenv("BAMBUDDY_OIDC_SCOPES", raw) + assert read_env_oidc_config()["scopes"] == "openid email profile" + + +@pytest.mark.parametrize("raw", ["", " "]) +def test_a_blank_email_claim_is_unset(monkeypatch, raw): + _set_required(monkeypatch) + monkeypatch.setenv("BAMBUDDY_OIDC_EMAIL_CLAIM", raw) + assert read_env_oidc_config()["email_claim"] == "email" + + +@pytest.mark.parametrize("raw", ["", " "]) +def test_a_blank_icon_url_is_unset(monkeypatch, raw): + """Uncommenting `# BAMBUDDY_OIDC_ICON_URL=` in .env.example must not take + the provider down -- the reader must still return a config, not refuse it.""" + _set_required(monkeypatch) + monkeypatch.setenv("BAMBUDDY_OIDC_ICON_URL", raw) + cfg = read_env_oidc_config() + assert cfg is not None, "a blank optional var must not refuse the whole provider" + assert cfg["icon_url"] is None + + def test_the_default_group_is_read_as_a_name(monkeypatch): """A name, not an id: group ids differ per install, so an id in a compose file would point at whatever group happened to be created third.""" From 77c9bdd694d43e2fdd4ac895b9ecad8beb2f84c5 Mon Sep 17 00:00:00 2001 From: Marian Date: Sat, 1 Aug 2026 08:38:07 +0000 Subject: [PATCH 22/25] fix(oidc): reject an unrecognized boolean instead of guessing _env_bool returned the default for anything outside {true,1,yes}, so BAMBUDDY_OIDC_REQUIRE_EMAIL_VERIFIED=on silently read as OFF and BAMBUDDY_OIDC_ENABLED=on silently disabled the provider -- the exact opposite of what .env.example claimed. Unrecognized values now raise EnvOIDCConfigError, caught in _apply_env_oidc_provider the same way a bad DEFAULT_GROUP or a ValidationError already is: logged and left running, never released on a typo. Also promotes _env_bool to env_bool now that it has a call site in auth.py, and corrects the boolean-parsing sentence in .env.example. --- .env.example | 3 +- backend/app/api/routes/auth.py | 4 +- backend/app/core/oidc_env.py | 37 +++++++++++--- .../tests/integration/test_oidc_env_apply.py | 49 ++++++++++++++++++ backend/tests/unit/test_oidc_env_reader.py | 51 +++++++++++++++++-- 5 files changed, 128 insertions(+), 16 deletions(-) diff --git a/.env.example b/.env.example index 12e4e3d1c..911f8ce96 100644 --- a/.env.example +++ b/.env.example @@ -100,7 +100,8 @@ LOG_TO_FILE=true # BAMBUDDY_OIDC_AUTOLOGIN=false # BAMBUDDY_OIDC_DEFAULT_GROUP= # -# Booleans accept true/1/yes; anything else keeps the default. +# Booleans accept true/1/yes or false/0/no (case-insensitive). Blank or unset +# uses the default; any other value is rejected and the provider is skipped. # # DEFAULT_GROUP is the group new users land in when AUTO_CREATE_USERS is on; # without it they get Viewers. It matches a group NAME exactly (case-sensitive) diff --git a/backend/app/api/routes/auth.py b/backend/app/api/routes/auth.py index 9e4e0fa43..8f279d948 100644 --- a/backend/app/api/routes/auth.py +++ b/backend/app/api/routes/auth.py @@ -35,7 +35,7 @@ from backend.app.core.auth import ( security, ) from backend.app.core.database import async_session, get_db -from backend.app.core.oidc_env import _env_bool +from backend.app.core.oidc_env import env_bool from backend.app.core.permissions import ALL_PERMISSIONS from backend.app.models.auth_ephemeral import AuthEphemeralToken, AuthRateLimitEvent, EventType, TokenType from backend.app.models.group import Group @@ -123,7 +123,7 @@ def _local_login_env_bypass() -> bool: an install whose SSO provider is unreachable. Accepted truthy values: ``true``, ``1``, ``yes`` (case-insensitive). """ - return _env_bool("BAMBUDDY_LOCAL_LOGIN", False) + return env_bool("BAMBUDDY_LOCAL_LOGIN", False) def _get_client_ip(request: Request) -> str: diff --git a/backend/app/core/oidc_env.py b/backend/app/core/oidc_env.py index 62269cb22..d5900a6e7 100644 --- a/backend/app/core/oidc_env.py +++ b/backend/app/core/oidc_env.py @@ -30,11 +30,25 @@ _REQUIRED = ( ) _TRUTHY = {"true", "1", "yes"} +_FALSY = {"false", "0", "no"} -def _env_bool(key: str, default: bool) -> bool: +class EnvOIDCConfigError(Exception): + """A BAMBUDDY_OIDC_* value the reader cannot interpret. Only ever carries a + boolean variable's name and value -- booleans are not secret, so the message + is safe to log in full (unlike client_secret, which never reaches here).""" + + +def env_bool(key: str, default: bool) -> bool: value = os.environ.get(key) - return default if value is None else value.strip().lower() in _TRUTHY + if value is None or value.strip() == "": + return default # absent or blank == unset -> default, per the module's promise + norm = value.strip().lower() + if norm in _TRUTHY: + return True + if norm in _FALSY: + return False + raise EnvOIDCConfigError(f"{key}={value!r} is not a recognized boolean (use true/1/yes or false/0/no)") def read_env_oidc_config() -> dict | None: @@ -52,13 +66,13 @@ def read_env_oidc_config() -> dict | None: "client_id": os.environ["BAMBUDDY_OIDC_CLIENT_ID"], "client_secret": os.environ["BAMBUDDY_OIDC_CLIENT_SECRET"], "scopes": (os.environ.get("BAMBUDDY_OIDC_SCOPES") or "").strip() or "openid email profile", - "is_enabled": _env_bool("BAMBUDDY_OIDC_ENABLED", True), - "auto_create_users": _env_bool("BAMBUDDY_OIDC_AUTO_CREATE_USERS", False), - "auto_link_existing_accounts": _env_bool("BAMBUDDY_OIDC_AUTO_LINK_EXISTING", False), + "is_enabled": env_bool("BAMBUDDY_OIDC_ENABLED", True), + "auto_create_users": env_bool("BAMBUDDY_OIDC_AUTO_CREATE_USERS", False), + "auto_link_existing_accounts": env_bool("BAMBUDDY_OIDC_AUTO_LINK_EXISTING", False), "email_claim": (os.environ.get("BAMBUDDY_OIDC_EMAIL_CLAIM") or "").strip() or "email", - "require_email_verified": _env_bool("BAMBUDDY_OIDC_REQUIRE_EMAIL_VERIFIED", True), + "require_email_verified": env_bool("BAMBUDDY_OIDC_REQUIRE_EMAIL_VERIFIED", True), "icon_url": (os.environ.get("BAMBUDDY_OIDC_ICON_URL") or "").strip() or None, - "is_autologin": _env_bool("BAMBUDDY_OIDC_AUTOLOGIN", False), + "is_autologin": env_bool("BAMBUDDY_OIDC_AUTOLOGIN", False), # A name, not an id: ids are assigned per install, so the same compose # file would point at a different group on every deployment. Resolved # against the database in apply_env_oidc_provider -- the reader has no @@ -116,7 +130,14 @@ async def _apply_env_oidc_provider(db: AsyncSession) -> None: from backend.app.models.oidc_provider import OIDCProvider from backend.app.schemas.auth import OIDCProviderCreate - config = read_env_oidc_config() + try: + config = read_env_oidc_config() + except EnvOIDCConfigError as exc: + # Same disposition as a ValidationError or an unmatched DEFAULT_GROUP: + # log clearly and leave any running provider as it was. Safe to log the + # full message -- EnvOIDCConfigError only ever carries a boolean var. + logger.error("BAMBUDDY_OIDC_* config rejected, provider not applied: %s", exc) + return if config is None: # Nothing to look up by name any more, so the previously managed rows are diff --git a/backend/tests/integration/test_oidc_env_apply.py b/backend/tests/integration/test_oidc_env_apply.py index 76c224e85..df5445f89 100644 --- a/backend/tests/integration/test_oidc_env_apply.py +++ b/backend/tests/integration/test_oidc_env_apply.py @@ -173,6 +173,55 @@ async def test_a_rejected_config_never_logs_the_client_secret(db_session, monkey assert "S3CR3T" not in caplog.text # not even a fragment of the value +# --- an unrecognized boolean is rejected, not guessed -------------------------- +# `_env_bool` used to return the default for anything outside {true,1,yes}, so +# BAMBUDDY_OIDC_REQUIRE_EMAIL_VERIFIED=on silently read as OFF and +# BAMBUDDY_OIDC_ENABLED=on silently disabled the provider. Strict parsing +# refuses the config instead -- through the same clean path a bad +# DEFAULT_GROUP or a ValidationError already uses, so a typo never releases a +# provider that was running fine. + + +@pytest.mark.asyncio +async def test_an_unrecognized_require_email_verified_leaves_a_running_provider_intact(db_session, monkeypatch, caplog): + _configure(monkeypatch) + await apply_env_oidc_provider(db_session) + original = await _env_provider(db_session) + original_id, original_enabled = original.id, original.is_enabled + + monkeypatch.setenv("BAMBUDDY_OIDC_REQUIRE_EMAIL_VERIFIED", "on") + with caplog.at_level(logging.ERROR): + await apply_env_oidc_provider(db_session) + + provider = await _env_provider(db_session) + assert provider is not None, "a typo must not release the provider" + assert provider.id == original_id + assert provider.is_enabled == original_enabled + assert provider.is_env_managed is True + assert "rejected" in caplog.text + assert "BAMBUDDY_OIDC_REQUIRE_EMAIL_VERIFIED" in caplog.text + + +@pytest.mark.asyncio +async def test_an_unrecognized_enabled_leaves_a_running_provider_intact(db_session, monkeypatch, caplog): + _configure(monkeypatch) + await apply_env_oidc_provider(db_session) + original = await _env_provider(db_session) + original_id, original_enabled = original.id, original.is_enabled + + monkeypatch.setenv("BAMBUDDY_OIDC_ENABLED", "on") + with caplog.at_level(logging.ERROR): + await apply_env_oidc_provider(db_session) + + provider = await _env_provider(db_session) + assert provider is not None, "a typo must not release the provider" + assert provider.id == original_id + assert provider.is_enabled == original_enabled + assert provider.is_env_managed is True + assert "rejected" in caplog.text + assert "BAMBUDDY_OIDC_ENABLED" in caplog.text + + @pytest.mark.asyncio async def test_a_non_validation_error_is_survivable_and_leaks_nothing(db_session, monkeypatch, caplog): """The generic except branch handles anything that isn't a ValidationError diff --git a/backend/tests/unit/test_oidc_env_reader.py b/backend/tests/unit/test_oidc_env_reader.py index 80cc5cb17..a9342f722 100644 --- a/backend/tests/unit/test_oidc_env_reader.py +++ b/backend/tests/unit/test_oidc_env_reader.py @@ -10,7 +10,7 @@ from __future__ import annotations import pytest -from backend.app.core.oidc_env import read_env_oidc_config +from backend.app.core.oidc_env import EnvOIDCConfigError, env_bool, read_env_oidc_config REQUIRED = { "BAMBUDDY_OIDC_NAME": "Keycloak", @@ -93,21 +93,62 @@ def test_booleans_accept_the_project_truthy_spellings(monkeypatch, raw): assert read_env_oidc_config()["auto_create_users"] is True -@pytest.mark.parametrize("raw", ["false", "0", "no", "", "off", "nonsense"]) -def test_anything_else_is_false(monkeypatch, raw): - """Only the three documented spellings enable a flag; an unrecognised value - must not silently turn on auto-create-users.""" +@pytest.mark.parametrize("raw", ["false", "FALSE", "False", "0", "no", "NO"]) +def test_falsy_values_are_false(monkeypatch, raw): _set_required(monkeypatch) monkeypatch.setenv("BAMBUDDY_OIDC_AUTO_CREATE_USERS", raw) assert read_env_oidc_config()["auto_create_users"] is False +@pytest.mark.parametrize("raw", ["on", "enabled", "y", "nonsense"]) +def test_an_unrecognized_boolean_is_rejected(monkeypatch, raw): + """Only the documented spellings are accepted; an unrecognised value must + not silently turn a flag on or off -- it must refuse the whole config + instead of guessing (M-R4 strict boolean parsing).""" + _set_required(monkeypatch) + monkeypatch.setenv("BAMBUDDY_OIDC_AUTO_CREATE_USERS", raw) + with pytest.raises(EnvOIDCConfigError, match="BAMBUDDY_OIDC_AUTO_CREATE_USERS"): + read_env_oidc_config() + + def test_a_boolean_default_of_true_can_be_turned_off(monkeypatch): _set_required(monkeypatch) monkeypatch.setenv("BAMBUDDY_OIDC_REQUIRE_EMAIL_VERIFIED", "false") assert read_env_oidc_config()["require_email_verified"] is False +# --- env_bool, tested directly ------------------------------------------------ +# The reader-level tests above pin the contract through read_env_oidc_config; +# these exercise the helper itself so its default/blank/reject behavior is +# proven independently of any particular BAMBUDDY_OIDC_* field. + + +@pytest.mark.parametrize("raw", ["false", "FALSE", "0", "no", "NO"]) +def test_env_bool_falsy_values_are_false(monkeypatch, raw): + monkeypatch.setenv("SOME_FLAG", raw) + assert env_bool("SOME_FLAG", True) is False + + +@pytest.mark.parametrize("default", [True, False]) +def test_env_bool_absent_is_the_given_default(monkeypatch, default): + monkeypatch.delenv("SOME_FLAG", raising=False) + assert env_bool("SOME_FLAG", default) is default + + +@pytest.mark.parametrize("raw", ["", " "]) +@pytest.mark.parametrize("default", [True, False]) +def test_env_bool_blank_is_the_given_default(monkeypatch, raw, default): + monkeypatch.setenv("SOME_FLAG", raw) + assert env_bool("SOME_FLAG", default) is default + + +@pytest.mark.parametrize("raw", ["on", "enabled", "y", "nonsense"]) +def test_env_bool_rejects_an_unrecognized_value(monkeypatch, raw): + monkeypatch.setenv("SOME_FLAG", raw) + with pytest.raises(EnvOIDCConfigError, match="SOME_FLAG"): + env_bool("SOME_FLAG", True) + + def test_optional_strings_override_their_defaults(monkeypatch): _set_required(monkeypatch) monkeypatch.setenv("BAMBUDDY_OIDC_SCOPES", "openid profile groups") From 9e783fbad6c28b74840e662a4ec531fc8deafb4a Mon Sep 17 00:00:00 2001 From: Marian Date: Sat, 1 Aug 2026 08:44:04 +0000 Subject: [PATCH 23/25] fix(oidc): keep the local-login bypass lenient under strict env_bool Promoting env_bool to strict rejection made BAMBUDDY_LOCAL_LOGIN=on raise EnvOIDCConfigError uncaught on the login/forgot-password path -- a 500 on the exact recovery endpoint the bypass exists to keep open. env_bool gains a strict flag (default True for the startup OIDC reader); the local-login caller opts out so an unrecognized value falls back to "off" instead. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_016q8EAf9Rj7ZHL92sPnXYxy --- backend/app/api/routes/auth.py | 6 +++++- backend/app/core/oidc_env.py | 14 +++++++++++-- .../integration/test_local_login_gate.py | 20 +++++++++++++++++++ backend/tests/unit/test_oidc_env_reader.py | 10 ++++++++++ 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/backend/app/api/routes/auth.py b/backend/app/api/routes/auth.py index 8f279d948..e8302cf35 100644 --- a/backend/app/api/routes/auth.py +++ b/backend/app/api/routes/auth.py @@ -123,7 +123,11 @@ def _local_login_env_bypass() -> bool: an install whose SSO provider is unreachable. Accepted truthy values: ``true``, ``1``, ``yes`` (case-insensitive). """ - return env_bool("BAMBUDDY_LOCAL_LOGIN", False) + # strict=False: this runs on the login/forgot-password request path, not at + # startup. An unrecognized value must fall back to "off" (the safe default), + # never raise -- a 500 on the recovery endpoint is the opposite of what this + # bypass is for. + return env_bool("BAMBUDDY_LOCAL_LOGIN", False, strict=False) def _get_client_ip(request: Request) -> str: diff --git a/backend/app/core/oidc_env.py b/backend/app/core/oidc_env.py index d5900a6e7..fdf234e1d 100644 --- a/backend/app/core/oidc_env.py +++ b/backend/app/core/oidc_env.py @@ -39,7 +39,15 @@ class EnvOIDCConfigError(Exception): is safe to log in full (unlike client_secret, which never reaches here).""" -def env_bool(key: str, default: bool) -> bool: +def env_bool(key: str, default: bool, *, strict: bool = True) -> bool: + """Parse a boolean env var. Absent or blank -> default (empty == unset). + + strict (the default): an unrecognized non-empty value raises + EnvOIDCConfigError, so a typo is refused loudly rather than silently read as + the wrong thing. strict=False: an unrecognized value falls back to the + default instead -- for a caller on a request path where a raise would be a + 500, not a skipped startup config (see _local_login_env_bypass). + """ value = os.environ.get(key) if value is None or value.strip() == "": return default # absent or blank == unset -> default, per the module's promise @@ -48,7 +56,9 @@ def env_bool(key: str, default: bool) -> bool: return True if norm in _FALSY: return False - raise EnvOIDCConfigError(f"{key}={value!r} is not a recognized boolean (use true/1/yes or false/0/no)") + if strict: + raise EnvOIDCConfigError(f"{key}={value!r} is not a recognized boolean (use true/1/yes or false/0/no)") + return default def read_env_oidc_config() -> dict | None: diff --git a/backend/tests/integration/test_local_login_gate.py b/backend/tests/integration/test_local_login_gate.py index 0ea3bfb79..d5d09fe2c 100644 --- a/backend/tests/integration/test_local_login_gate.py +++ b/backend/tests/integration/test_local_login_gate.py @@ -96,6 +96,26 @@ class TestLocalLoginGate: ) assert response.status_code == 200, response.text + @pytest.mark.asyncio + @pytest.mark.integration + async def test_unrecognized_env_value_does_not_500_the_login_path( + self, async_client: AsyncClient, db_session: AsyncSession, monkeypatch: pytest.MonkeyPatch + ): + """The recovery bypass reads BAMBUDDY_LOCAL_LOGIN on the request path, so + an unrecognized value (BAMBUDDY_LOCAL_LOGIN=on) must fall back to "off", + never raise -- env_bool is strict for the startup OIDC reader but lenient + here. A raise would 500 the very endpoint the bypass exists to keep open.""" + await _enable_auth(async_client, "gateonval") + await _set_setting(db_session, "local_login_enabled", "false") + monkeypatch.setenv("BAMBUDDY_LOCAL_LOGIN", "on") + + response = await async_client.post( + "/api/v1/auth/login", + json={"username": "gateonval", "password": "GatePass1!"}, + ) + # Bypass stays off (same 401 as no env var), and crucially not a 500. + assert response.status_code == 401, response.text + @pytest.mark.asyncio @pytest.mark.integration async def test_forgot_password_rejected_when_local_disabled( diff --git a/backend/tests/unit/test_oidc_env_reader.py b/backend/tests/unit/test_oidc_env_reader.py index a9342f722..2fae0df2d 100644 --- a/backend/tests/unit/test_oidc_env_reader.py +++ b/backend/tests/unit/test_oidc_env_reader.py @@ -149,6 +149,16 @@ def test_env_bool_rejects_an_unrecognized_value(monkeypatch, raw): env_bool("SOME_FLAG", True) +@pytest.mark.parametrize("raw", ["on", "enabled", "y", "nonsense"]) +@pytest.mark.parametrize("default", [True, False]) +def test_env_bool_lenient_falls_back_to_default_on_unrecognized(monkeypatch, raw, default): + """strict=False (the request-path callers like BAMBUDDY_LOCAL_LOGIN): an + unrecognized value must return the default, never raise -- a raise there + would 500 a live endpoint rather than skip a startup config.""" + monkeypatch.setenv("SOME_FLAG", raw) + assert env_bool("SOME_FLAG", default, strict=False) is default + + def test_optional_strings_override_their_defaults(monkeypatch): _set_required(monkeypatch) monkeypatch.setenv("BAMBUDDY_OIDC_SCOPES", "openid profile groups") From aef4f3a3e938b651304df7f21490fdb333c89864 Mon Sep 17 00:00:00 2001 From: maziggy Date: Sat, 1 Aug 2026 11:37:01 +0200 Subject: [PATCH 24/25] fix(oidc): strip the required BAMBUDDY_OIDC_* values and register the local-login bypass A Kubernetes Secret written as a block scalar carries a trailing newline, and the schema bounds the four required variables by max_length only, so an unstripped issuer_url was stored and enabled and then raised httpx.InvalidURL on the first click of the SSO button -- the authorize-time failure the all-or-nothing rule exists to prevent. Whitespace-only values got through the same way, contradicting the reader's own "an empty required var counts as unset". The optional variables have always treated blank as unset; the required ones now do too. Also registers BAMBUDDY_LOCAL_LOGIN (#1589) in the typo guard, which logged "possible typo" for it on every boot while listing every BAMBUDDY_OIDC_* variable as legitimate. --- CHANGELOG.md | 1 + backend/app/core/config.py | 4 +++ backend/app/core/oidc_env.py | 20 +++++++++---- .../integration/test_local_login_gate.py | 9 ++++++ backend/tests/unit/test_oidc_env_reader.py | 29 +++++++++++++++++-- .../{index-CbDmTKuP.js => index-CCCWDEkl.js} | 2 +- static/index.html | 2 +- 7 files changed, 56 insertions(+), 11 deletions(-) rename static/assets/{index-CbDmTKuP.js => index-CCCWDEkl.js} (96%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 521e1eeb3..535488888 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ All notable changes to Bambuddy will be documented in this file. - **Git backup now actually writes cloud profiles (#2717, reporter @jmoore-skild)** — Enabling **Cloud Profiles** for a Git backup produced nothing. The collector looked for a `setting` list in the Bambu Cloud response, which is keyed by preset type instead, so the loop never ran once — and it asked for the credential store used when authentication is *disabled*, so on any install with authentication on it found no account to collect from in the first place. Neither failure was visible: `backup_metadata.json` still recorded `cloud_profiles: true`, and the log line read `Collected cloud profiles: 0 filament, 0 printer, 0 process`, which looks like a successful backup of an empty account. Cloud profiles are now collected from **every connected account across both Bambu Cloud and Orca Cloud**, one directory per cloud per account, keyed by user ID so no email address is written into a backup repository. Bambu presets are stored with the payload needed to recreate them rather than just their names, and Bambu's bundled public catalogue is skipped — it is identical for everyone, re-downloadable, and would rewrite the repository on every run. The metadata now records what was actually collected, per cloud and per account, and a run that collects nothing while the category is enabled says so as a warning instead of an INFO line that reads like success. The Cloud Profiles checkbox no longer keys off your own Bambu sign-in — it enables when *any* account is connected and shows how many are in scope, which matters on a multi-user install where the presets being backed up are other people's. A backup also no longer disconnects an Orca Cloud account whose session it can't refresh: Orca reports every rejection with one composite reason, so a genuine revocation is indistinguishable from a lost token-rotation race, and an unattended job should not be the thing that guesses. The account is skipped with a warning, and the dead credentials are cleared the next time you open Orca Cloud Profiles — where you can pair again on the spot. Translated in all locales; wiki updated. Covered by backend tests. ### Added +- **Configure an OIDC provider from environment variables (#2593, contributor @munin92)** — Single Sign-On could only be set up by clicking through Settings → Authentication, which does not exist as a step in a deployment driven by a compose file, a Helm chart or a GitOps repository: every fresh install of the same stack needed someone to log in and re-enter the same issuer, client ID and secret by hand. One provider can now be defined entirely from `BAMBUDDY_OIDC_*` variables. It is written on startup and re-applied on every boot, so the file in your repository is the source of truth, and providers created in the UI keep working alongside it, untouched. Only the four required variables — name, issuer URL, client ID and client secret — activate it, and all four or none: a half-configured provider is refused at boot with a log line naming what was wrong, rather than appearing on the login page and failing when somebody clicks it. Values are validated by exactly the same rules the settings UI enforces, including the one that refuses account auto-linking on an unverified email address, so the environment cannot reach a configuration the UI would have rejected. A typo never stops the app from booting and never takes a working provider down: the previous configuration keeps running and the reason is logged. In the UI the provider is shown with a lock badge and no edit, delete or enable controls, because startup would overwrite any change at the next restart. Removing the variables disables the provider instead of deleting it — deleting would permanently unlink every account bound to it — and re-adding them brings it back with those links intact. `BAMBUDDY_LOCAL_LOGIN=true` remains the way back in if a misconfigured provider ever locks you out. All thirteen variables are documented in `.env.example`; wiki updated. Covered by backend and frontend tests. - **Keep the AMS slots the slicer picked (#2700, contributor @Striker72rus)** — Bambu Studio and OrcaSlicer resolve which physical AMS tray feeds each filament themselves, right before sending. Bambuddy threw that away: a queue-mode virtual printer worked the mapping out again at dispatch time, from the filament type and colour baked into the 3MF. That is usually the better answer — it is computed against the printer's live trays and it respects **Prefer lowest filament** and the AMS-backup gate that goes with it — but it has nothing to go on when the match isn't unique. Two spools of the same red PLA, and the slot you deliberately chose in the slicer is a coin toss. A new per-virtual-printer **Save AMS mapping** toggle keeps the slicer's pick instead: the print dispatches to exactly those trays, and the mapping is stored on the archive so a reprint can reuse the same physical spools — a **Mapping** button in the print modal selects every slot from it in one click, and the archive card and queue row say so. Because a tray number only means something on the AMS it was resolved against, the mapping records its printer and is only ever offered on that same printer; a model-based ("Any [model]") virtual printer has no fixed printer and is unaffected. Off by default, so nothing changes for existing virtual printers until you turn it on, and **Force color match** still wins for the print being dispatched when both are on. Translated in all locales; wiki updated. Covered by backend and frontend tests. - **P2S/X2D accessory fans: left auxiliary cooling and chamber exhaust (#2691, contributor @gzimbric, requested in #2660)** — The P2S and X2D have two fans Bambuddy could not show or drive. The **left auxiliary part cooling fan** had no tile and no control at all, because the printer only reports it inside its air-duct data and never in the ordinary fan fields Bambuddy was reading. The **chamber exhaust fan** had the opposite problem: its tile appeared on every P2S whether or not the fan was fitted, so owners of a base machine had a control that did nothing. Both are add-on kits on the P2S and fitted at the factory on the X2D. Both tiles now appear only when the printer itself reports the hardware, so a base P2S looks exactly as it does today and a kitted one gains the fans it actually has. The left auxiliary fan is set from the same speed popover as the others, and the enclosure fan is labelled **Exhaust** on the P2S and X2D — matching the printer's own screen and Bambu Studio — while every other enclosed model keeps **Chamber Fan**. The confirmation message after changing a speed uses the same name as the tile that was clicked. The four tiles are ordered part cooling, left auxiliary, auxiliary, exhaust, so they read left to right in the same order as the physical fans. Both fields are also published through the status endpoint, the WebSocket feed and the MQTT relay, so external automations can read them. Translated in all locales; wiki updated. Covered by backend and frontend tests, including the case where the printer sends a partial fan report — a tile must not disappear mid-print just because one update didn't mention it. - **Live print progress in the browser tab (#2693, contributor @Chachigo, requested in #1041)** — Watching a print meant keeping the Bambuddy tab in view, or switching back to it every few minutes. Enable **Print progress in tab** under Settings → Appearance and the tab title becomes `42% · Bambuddy` while the favicon turns into a progress ring in your theme accent colour, both updating live over the WebSocket the rest of the UI already uses. With several printers running, the tab follows the one finishing soonest, tie-broken by highest progress; title and favicon return to their defaults as soon as nothing is printing or the toggle goes off. Off by default, and stored per browser (like the light/dark toggle) so a wall-mounted dashboard and a laptop can each have their own setting. Translated in all locales; wiki updated. Covered by frontend tests. diff --git a/backend/app/core/config.py b/backend/app/core/config.py index d704b0a22..01d7350c3 100644 --- a/backend/app/core/config.py +++ b/backend/app/core/config.py @@ -135,6 +135,10 @@ _INTENTIONAL_UNSETTINGS = { "LOG_DIR", # config.py (above) "LOG_LEVEL", # main.py logging setup "BUG_REPORT_RELAY_URL", # config.py (above) + # #1589 — api/routes/auth.py reads this on the login path. Unregistered it + # logged "possible typo" at every boot, telling an operator who is locked + # out and following the documented recovery that the variable is not real. + "BAMBUDDY_LOCAL_LOGIN", # #2593 — core/oidc_env.py reads these directly; they are not Settings # fields because they map to an OIDCProvider row, not to app config. "BAMBUDDY_OIDC_NAME", diff --git a/backend/app/core/oidc_env.py b/backend/app/core/oidc_env.py index fdf234e1d..19b413d80 100644 --- a/backend/app/core/oidc_env.py +++ b/backend/app/core/oidc_env.py @@ -65,16 +65,24 @@ def read_env_oidc_config() -> dict | None: """The provider's fields from the environment, or None if it isn't configured. An empty required var counts as unset -- `BAMBUDDY_OIDC_CLIENT_SECRET=` in - a compose file is a forgotten value, not an intentional empty secret. + a compose file is a forgotten value, not an intentional empty secret. Blank + means blank *after* stripping, and the surviving value is stripped too: a + Kubernetes Secret written as a block scalar (``stringData: secret: |``) or + created from a file carries a trailing newline that nothing downstream + rejects -- max_length is the only bound the schema puts on these four. An + issuer_url with a trailing newline is stored and enabled, and then fails + with httpx.InvalidURL on the first click of the SSO button, which is the + authorize-time failure the all-or-nothing rule above exists to prevent. """ - if not all(os.environ.get(key) for key in _REQUIRED): + required = {key: (os.environ.get(key) or "").strip() for key in _REQUIRED} + if not all(required.values()): return None return { - "name": os.environ["BAMBUDDY_OIDC_NAME"], - "issuer_url": os.environ["BAMBUDDY_OIDC_ISSUER_URL"], - "client_id": os.environ["BAMBUDDY_OIDC_CLIENT_ID"], - "client_secret": os.environ["BAMBUDDY_OIDC_CLIENT_SECRET"], + "name": required["BAMBUDDY_OIDC_NAME"], + "issuer_url": required["BAMBUDDY_OIDC_ISSUER_URL"], + "client_id": required["BAMBUDDY_OIDC_CLIENT_ID"], + "client_secret": required["BAMBUDDY_OIDC_CLIENT_SECRET"], "scopes": (os.environ.get("BAMBUDDY_OIDC_SCOPES") or "").strip() or "openid email profile", "is_enabled": env_bool("BAMBUDDY_OIDC_ENABLED", True), "auto_create_users": env_bool("BAMBUDDY_OIDC_AUTO_CREATE_USERS", False), diff --git a/backend/tests/integration/test_local_login_gate.py b/backend/tests/integration/test_local_login_gate.py index d5d09fe2c..3c78391e6 100644 --- a/backend/tests/integration/test_local_login_gate.py +++ b/backend/tests/integration/test_local_login_gate.py @@ -116,6 +116,15 @@ class TestLocalLoginGate: # Bypass stays off (same 401 as no env var), and crucially not a 500. assert response.status_code == 401, response.text + def test_the_bypass_var_is_registered_in_the_typo_guard(self): + """config.py logs "possible typo" for any unregistered BAMBUDDY_* var. + Unregistered, this one tells an operator who is locked out and following + the documented recovery that the variable they just set is not real -- + while the same line lists every BAMBUDDY_OIDC_* var as legitimate.""" + from backend.app.core.config import _INTENTIONAL_UNSETTINGS + + assert "BAMBUDDY_LOCAL_LOGIN" in _INTENTIONAL_UNSETTINGS + @pytest.mark.asyncio @pytest.mark.integration async def test_forgot_password_rejected_when_local_disabled( diff --git a/backend/tests/unit/test_oidc_env_reader.py b/backend/tests/unit/test_oidc_env_reader.py index 2fae0df2d..f5aa650ea 100644 --- a/backend/tests/unit/test_oidc_env_reader.py +++ b/backend/tests/unit/test_oidc_env_reader.py @@ -56,14 +56,37 @@ def test_returns_none_when_any_single_required_var_is_missing(monkeypatch, missi assert read_env_oidc_config() is None -def test_an_empty_required_var_counts_as_unset(monkeypatch): +@pytest.mark.parametrize("raw", ["", " ", "\n", " \t\n "]) +@pytest.mark.parametrize("key", sorted(REQUIRED)) +def test_an_empty_required_var_counts_as_unset(monkeypatch, key, raw): """`BAMBUDDY_OIDC_CLIENT_SECRET=` in a compose file is a forgotten value, - not an intentional empty secret.""" + not an intentional empty secret -- and neither is one holding only + whitespace, which the optional vars have always treated as unset.""" _set_required(monkeypatch) - monkeypatch.setenv("BAMBUDDY_OIDC_CLIENT_SECRET", "") + monkeypatch.setenv(key, raw) assert read_env_oidc_config() is None +@pytest.mark.parametrize("key", sorted(REQUIRED)) +def test_a_required_var_is_stripped(monkeypatch, key): + """A Kubernetes Secret written as a block scalar carries a trailing + newline, and the schema bounds these four by max_length only -- so an + unstripped issuer_url reaches the database, enables the SSO button and + then raises httpx.InvalidURL on the first click, long after startup could + have refused it.""" + _set_required(monkeypatch) + monkeypatch.setenv(key, f" {REQUIRED[key]}\n") + + cfg = read_env_oidc_config() + field = { + "BAMBUDDY_OIDC_NAME": "name", + "BAMBUDDY_OIDC_ISSUER_URL": "issuer_url", + "BAMBUDDY_OIDC_CLIENT_ID": "client_id", + "BAMBUDDY_OIDC_CLIENT_SECRET": "client_secret", + }[key] + assert cfg[field] == REQUIRED[key] + + def test_reads_the_required_vars(monkeypatch): _set_required(monkeypatch) cfg = read_env_oidc_config() diff --git a/static/assets/index-CbDmTKuP.js b/static/assets/index-CCCWDEkl.js similarity index 96% rename from static/assets/index-CbDmTKuP.js rename to static/assets/index-CCCWDEkl.js index 011264931..d9a3ffae5 100644 --- a/static/assets/index-CbDmTKuP.js +++ b/static/assets/index-CCCWDEkl.js @@ -8706,7 +8706,7 @@ ${t.slice(l+2)}`,d+=1;else break}t.push({indent:l,number:parseInt(s,10),content: "CN=PrintFarm_Admins,OU=Groups,DC=example,DC=com": "Administrators", "CN=PrintFarm_Users,OU=Groups,DC=example,DC=com": "Operators" }`,value:i.ldap_group_mapping,onChange:e=>a({...i,ldap_group_mapping:e.target.value})}),(0,K.jsxs)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:[e(`settings.ldap.groupMappingHint`)||`Map LDAP group DNs to BamBuddy groups. Available groups: `,l.map(e=>e.name).join(`, `)]})]})]})}),(0,K.jsxs)(`div`,{className:`flex gap-3 pt-2`,children:[(0,K.jsxs)($,{onClick:p,disabled:u.isPending,children:[u.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(_s,{className:`w-4 h-4`}),e(`common.save`)||`Save`]}),(0,K.jsxs)($,{variant:`secondary`,onClick:()=>f.mutate(),disabled:f.isPending,children:[f.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(ql,{className:`w-4 h-4`}),e(`settings.ldap.testConnection`)||`Test Connection`]})]})]})})]})]})}function b6({value:e,onChange:t,placeholder:n,maxLength:r=6}){return(0,K.jsx)(`input`,{type:`text`,value:e,onChange:e=>t(e.target.value.toUpperCase().replace(/\s/g,``)),maxLength:r,className:`w-full px-4 py-3 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors font-mono tracking-widest text-center`,placeholder:n,autoComplete:`one-time-code`})}function x6({codes:e,onDone:t}){let{t:n}=W(),[r,i]=(0,y.useState)(!1);return(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(`div`,{className:`bg-amber-50 dark:bg-amber-500/10 border border-amber-300 dark:border-amber-500/30 rounded-lg p-4`,children:(0,K.jsx)(`p`,{className:`text-amber-700 dark:text-amber-400 text-sm font-medium`,children:n(`settings.twoFa.backupCodesWarning`)})}),(0,K.jsx)(`div`,{className:`grid grid-cols-2 gap-2`,children:e.map((e,t)=>(0,K.jsx)(`code`,{className:`bg-bambu-dark-secondary rounded px-3 py-2 text-center font-mono text-sm text-white tracking-widest`,children:e},t))}),(0,K.jsxs)(`div`,{className:`flex gap-3`,children:[(0,K.jsxs)($,{variant:`secondary`,size:`sm`,onClick:()=>{navigator.clipboard.writeText(e.join(` -`)),i(!0),setTimeout(()=>i(!1),2e3)},className:`flex items-center gap-2`,children:[(0,K.jsx)(Ls,{className:`w-4 h-4`}),n(r?`common.copied`:`common.copy`)]}),(0,K.jsx)($,{variant:`primary`,size:`sm`,onClick:t,className:`flex-1`,children:n(`settings.twoFa.savedCodes`)})]})]})}function KUe({onDone:e}){let{t}=W(),n=oo(),{showToast:r}=Id(),[i,a]=(0,y.useState)(`qr`),[o,s]=(0,y.useState)(``),[c,l]=(0,y.useState)([]),[u,d]=(0,y.useState)(!1),{data:f,isLoading:p}=q({queryKey:[`totp-setup`],queryFn:()=>Q.setupTOTP(),staleTime:1/0}),m=J({mutationFn:e=>Q.enableTOTP(e),onSuccess:e=>{l(e.backup_codes),a(`backup`),n.invalidateQueries({queryKey:[`2fa-status`]})},onError:()=>r(t(`settings.twoFa.invalidCode`),`error`)});return p||!f?(0,K.jsx)(`div`,{className:`flex items-center justify-center py-8`,children:(0,K.jsx)(Il,{className:`w-6 h-6 animate-spin text-bambu-green`})}):i===`qr`?(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(`p`,{className:`text-bambu-gray-light text-sm`,children:t(`settings.twoFa.setupInstructions`)}),(0,K.jsx)(`div`,{className:`flex justify-center`,children:(0,K.jsx)(`img`,{src:`data:image/png;base64,${f.qr_code_b64}`,alt:`TOTP QR Code`,className:`w-48 h-48 rounded-lg`})}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mb-1`,children:t(`settings.twoFa.manualEntry`)}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 bg-bambu-dark-secondary rounded-lg px-3 py-2`,children:[(0,K.jsx)(`code`,{className:`text-white text-xs font-mono flex-1 break-all`,children:u?f.secret:`••••••••••••••••`}),(0,K.jsx)(`button`,{onClick:()=>d(!u),className:`text-bambu-gray hover:text-white`,children:u?(0,K.jsx)(ec,{className:`w-4 h-4`}):(0,K.jsx)(tc,{className:`w-4 h-4`})}),(0,K.jsx)(`button`,{onClick:()=>{navigator.clipboard.writeText(f.secret)},className:`text-bambu-gray hover:text-white`,children:(0,K.jsx)(Ls,{className:`w-4 h-4`})})]})]}),(0,K.jsx)($,{variant:`primary`,className:`w-full`,onClick:()=>a(`confirm`),children:t(`settings.twoFa.scannedContinue`)})]}):i===`confirm`?(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(`p`,{className:`text-bambu-gray-light text-sm`,children:t(`settings.twoFa.enterCodeToConfirm`)}),(0,K.jsx)(b6,{value:o,onChange:s,placeholder:`000000`}),(0,K.jsxs)(`div`,{className:`flex gap-3`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:()=>a(`qr`),className:`flex-1`,children:t(`common.back`)}),(0,K.jsx)($,{variant:`primary`,className:`flex-1`,disabled:o.length!==6||m.isPending,onClick:()=>m.mutate(o),children:m.isPending?t(`common.saving`):t(`settings.twoFa.activate`)})]})]}):(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(`h3`,{className:`text-white font-medium`,children:t(`settings.twoFa.backupCodesTitle`)}),(0,K.jsx)(x6,{codes:c,onDone:e})]})}function qUe(){let{t:e}=W(),t=oo(),{showToast:n}=Id(),{user:r}=Sd(),[i,a]=(0,y.useState)(!1),[o,s]=(0,y.useState)(!1),[c,l]=(0,y.useState)(!1),[u,d]=(0,y.useState)(``),[f,p]=(0,y.useState)(``),[m,h]=(0,y.useState)(null),[g,_]=(0,y.useState)(null),[v,b]=(0,y.useState)(``),[x,S]=(0,y.useState)(!1),[C,w]=(0,y.useState)(``),[T,E]=(0,y.useState)(!1),{data:D,isLoading:O}=q({queryKey:[`2fa-status`],queryFn:()=>Q.get2FAStatus()}),{data:k}=q({queryKey:[`oidc-links`],queryFn:()=>Q.getOIDCLinks()}),A=J({mutationFn:()=>Q.enableEmailOTP(),onSuccess:e=>{_(e.setup_token),n(e.message,`success`)},onError:t=>{let r=t.message??``;r.toLowerCase().includes(`smtp`)?n(e(`settings.twoFa.smtpRequired`),`error`):n(r,`error`)}}),j=J({mutationFn:()=>Q.confirmEnableEmailOTP(g,v),onSuccess:()=>{t.invalidateQueries({queryKey:[`2fa-status`]}),_(null),b(``),n(e(`settings.twoFa.emailOtpEnabled`),`success`)},onError:e=>n(e.message,`error`)}),M=J({mutationFn:e=>Q.disableEmailOTP(e),onSuccess:()=>{t.invalidateQueries({queryKey:[`2fa-status`]}),S(!1),w(``),n(e(`settings.twoFa.emailOtpDisabled`),`success`)},onError:e=>n(e.message,`error`)}),N=J({mutationFn:e=>Q.disableTOTP(e),onSuccess:()=>{t.invalidateQueries({queryKey:[`2fa-status`]}),s(!1),d(``),n(e(`settings.twoFa.totpDisabled`),`success`)},onError:()=>n(e(`settings.twoFa.invalidCode`),`error`)}),P=J({mutationFn:e=>Q.regenerateBackupCodes(e),onSuccess:e=>{t.invalidateQueries({queryKey:[`2fa-status`]}),l(!1),p(``),h(e.backup_codes)},onError:()=>n(e(`settings.twoFa.invalidCode`),`error`)}),F=J({mutationFn:e=>Q.deleteOIDCLink(e),onSuccess:()=>{t.invalidateQueries({queryKey:[`oidc-links`]}),n(e(`settings.twoFa.oidcUnlinked`),`success`)},onError:e=>n(e.message,`error`)});if(O)return(0,K.jsx)(`div`,{className:`flex items-center justify-center py-12`,children:(0,K.jsx)(Il,{className:`w-6 h-6 animate-spin text-bambu-green`})});let I=!!r?.email;return(0,K.jsxs)(`div`,{className:`space-y-6`,children:[(0,K.jsxs)(Od,{id:`card-2fa-totp`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,K.jsx)(`div`,{className:`w-10 h-10 rounded-full flex items-center justify-center ${D?.totp_enabled?`bg-green-100 dark:bg-green-500/20`:`bg-gray-500/20`}`,children:(0,K.jsx)(cu,{className:`w-5 h-5 ${D?.totp_enabled?`text-green-600 dark:text-green-400`:`text-gray-400`}`})}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`text-white font-semibold`,children:e(`settings.twoFa.totpTitle`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-sm`,children:e(`settings.twoFa.totpDesc`)})]}),(0,K.jsx)(`div`,{className:`ml-auto`,children:D?.totp_enabled?(0,K.jsxs)(`span`,{className:`flex items-center gap-1 text-green-700 dark:text-green-400 text-sm font-medium`,children:[(0,K.jsx)($l,{className:`w-4 h-4`}),` `,e(`common.enabled`)]}):(0,K.jsxs)(`span`,{className:`flex items-center gap-1 text-bambu-gray text-sm`,children:[(0,K.jsx)(eu,{className:`w-4 h-4`}),` `,e(`common.disabled`)]})})]})}),(0,K.jsx)(Ad,{children:i?(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between mb-2`,children:[(0,K.jsx)(`h4`,{className:`text-white font-medium`,children:e(`settings.twoFa.setupAuthApp`)}),(0,K.jsx)(`button`,{onClick:()=>{a(!1),t.removeQueries({queryKey:[`totp-setup`]})},className:`text-bambu-gray hover:text-white`,children:(0,K.jsx)(Yu,{className:`w-5 h-5`})})]}),(0,K.jsx)(KUe,{onDone:()=>{a(!1),t.removeQueries({queryKey:[`totp-setup`]})}})]}):o?(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(`p`,{className:`text-bambu-gray-light text-sm`,children:e(`settings.twoFa.disableConfirmHint`)}),(0,K.jsx)(b6,{value:u,onChange:d,placeholder:`000000 or XXXXXXXX`,maxLength:8}),(0,K.jsxs)(`div`,{className:`flex gap-3`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:()=>{s(!1),d(``)},className:`flex-1`,children:e(`common.cancel`)}),(0,K.jsx)($,{variant:`danger`,className:`flex-1`,disabled:u.length<6||N.isPending,onClick:()=>N.mutate(u),children:N.isPending?e(`common.saving`):e(`settings.twoFa.disableTotp`)})]})]}):c?(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(`p`,{className:`text-bambu-gray-light text-sm`,children:e(`settings.twoFa.regenBackupHint`)}),(0,K.jsx)(b6,{value:f,onChange:p,placeholder:`000000 or XXXXXXXX`,maxLength:8}),(0,K.jsxs)(`div`,{className:`flex gap-3`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:()=>{l(!1),p(``)},className:`flex-1`,children:e(`common.cancel`)}),(0,K.jsx)($,{variant:`primary`,className:`flex-1`,disabled:f.length<6||P.isPending,onClick:()=>P.mutate(f),children:P.isPending?e(`common.saving`):e(`settings.twoFa.regenBackup`)})]})]}):m?(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(`h4`,{className:`text-white font-medium`,children:e(`settings.twoFa.newBackupCodes`)}),(0,K.jsx)(x6,{codes:m,onDone:()=>h(null)})]}):(0,K.jsx)(`div`,{className:`space-y-3`,children:D?.totp_enabled?(0,K.jsxs)(`div`,{className:`flex flex-wrap gap-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-sm text-bambu-gray-light`,children:[(0,K.jsx)(Vc,{className:`w-4 h-4`}),e(`settings.twoFa.backupCodesRemaining`,{count:D.backup_codes_remaining})]}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,onClick:()=>l(!0),className:`flex items-center gap-2`,children:[(0,K.jsx)(Il,{className:`w-4 h-4`}),e(`settings.twoFa.regenBackup`)]}),(0,K.jsxs)($,{variant:`danger`,size:`sm`,onClick:()=>s(!0),className:`flex items-center gap-2`,children:[(0,K.jsx)(Ou,{className:`w-4 h-4`}),e(`settings.twoFa.disableTotp`)]})]}):(0,K.jsxs)($,{variant:`primary`,onClick:()=>a(!0),className:`flex items-center gap-2`,children:[(0,K.jsx)(cu,{className:`w-4 h-4`}),e(`settings.twoFa.setupTotp`)]})})})]}),(0,K.jsxs)(Od,{id:`card-2fa-emailotp`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,K.jsx)(`div`,{className:`w-10 h-10 rounded-full flex items-center justify-center ${D?.email_otp_enabled?`bg-green-100 dark:bg-green-500/20`:`bg-gray-500/20`}`,children:(0,K.jsx)(tl,{className:`w-5 h-5 ${D?.email_otp_enabled?`text-green-600 dark:text-green-400`:`text-gray-400`}`})}),(0,K.jsxs)(`div`,{className:`flex-1`,children:[(0,K.jsx)(`h3`,{className:`text-white font-semibold`,children:e(`settings.twoFa.emailOtpTitle`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-sm`,children:I?e(`settings.twoFa.emailOtpDesc`,{email:r?.email}):e(`settings.twoFa.emailOtpNoEmail`)})]}),(0,K.jsx)(`div`,{className:`ml-auto`,children:D?.email_otp_enabled?(0,K.jsxs)(`span`,{className:`flex items-center gap-1 text-green-700 dark:text-green-400 text-sm font-medium`,children:[(0,K.jsx)($l,{className:`w-4 h-4`}),` `,e(`common.enabled`)]}):(0,K.jsxs)(`span`,{className:`flex items-center gap-1 text-bambu-gray text-sm`,children:[(0,K.jsx)(eu,{className:`w-4 h-4`}),` `,e(`common.disabled`)]})})]})}),(0,K.jsx)(Ad,{children:I?g?(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(`p`,{className:`text-bambu-gray-light text-sm`,children:e(`settings.twoFa.emailSetupEnterCode`)}),(0,K.jsx)(b6,{value:v,onChange:b,placeholder:`000000`}),(0,K.jsxs)(`div`,{className:`flex gap-3`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:()=>{_(null),b(``)},className:`flex-1`,children:e(`common.cancel`)}),(0,K.jsx)($,{variant:`primary`,className:`flex-1`,disabled:v.length!==6||j.isPending,onClick:()=>j.mutate(),children:j.isPending?e(`common.saving`):e(`settings.twoFa.verifyAndEnable`)})]})]}):x?(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(`p`,{className:`text-bambu-gray-light text-sm`,children:e(`settings.twoFa.emailDisablePasswordHint`)}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`input`,{type:T?`text`:`password`,value:C,onChange:e=>w(e.target.value),placeholder:e(`settings.twoFa.passwordPlaceholder`),className:`w-full px-4 py-3 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors`}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>E(!T),className:`absolute right-3 top-1/2 -translate-y-1/2 text-bambu-gray hover:text-white`,children:T?(0,K.jsx)(ec,{className:`w-5 h-5`}):(0,K.jsx)(tc,{className:`w-5 h-5`})})]}),(0,K.jsxs)(`div`,{className:`flex gap-3`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:()=>{S(!1),w(``)},className:`flex-1`,children:e(`common.cancel`)}),(0,K.jsx)($,{variant:`danger`,className:`flex-1`,disabled:!C||M.isPending,onClick:()=>M.mutate(C),children:M.isPending?e(`common.saving`):e(`settings.twoFa.disableEmailOtp`)})]})]}):(0,K.jsx)(`div`,{className:`flex gap-3`,children:D?.email_otp_enabled?(0,K.jsxs)($,{variant:`danger`,size:`sm`,onClick:()=>S(!0),className:`flex items-center gap-2`,children:[(0,K.jsx)(Ou,{className:`w-4 h-4`}),e(`settings.twoFa.disableEmailOtp`)]}):(0,K.jsxs)($,{variant:`primary`,disabled:!I||A.isPending,onClick:()=>A.mutate(),className:`flex items-center gap-2`,children:[(0,K.jsx)(tl,{className:`w-4 h-4`}),A.isPending?e(`common.saving`):e(`settings.twoFa.enableEmailOtp`)]})}):(0,K.jsx)(`p`,{className:`text-amber-700 dark:text-amber-400 text-sm`,children:e(`settings.twoFa.addEmailFirst`)})})]}),k&&k.length>0&&(0,K.jsxs)(Od,{id:`card-2fa-linked`,children:[(0,K.jsxs)(kd,{children:[(0,K.jsx)(`h3`,{className:`text-white font-semibold`,children:e(`settings.twoFa.linkedAccounts`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-sm`,children:e(`settings.twoFa.linkedAccountsDesc`)})]}),(0,K.jsx)(Ad,{children:(0,K.jsx)(`div`,{className:`space-y-3`,children:k.map(e=>(0,K.jsxs)(`div`,{className:`flex items-center justify-between py-2 border-b border-bambu-dark-tertiary last:border-0`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white text-sm font-medium`,children:e.provider_name}),e.provider_email&&(0,K.jsx)(`p`,{className:`text-bambu-gray text-xs`,children:e.provider_email})]}),(0,K.jsx)($,{variant:`danger`,size:`sm`,onClick:()=>F.mutate(e.provider_id),disabled:F.isPending,children:(0,K.jsx)(Ou,{className:`w-4 h-4`})})]},e.id))})})]})]})}var JUe={name:``,issuer_url:``,client_id:``,client_secret:``,scopes:`openid email profile`,is_enabled:!0,auto_create_users:!1,auto_link_existing_accounts:!1,email_claim:`email`,require_email_verified:!0,icon_url:void 0,default_group_id:null,is_autologin:!1};function S6({initial:e,isEdit:t=!1,groups:n=[],onSave:r,onCancel:i,isPending:a}){let{t:o}=W(),[s,c]=(0,y.useState)(e),[l,u]=(0,y.useState)(!1),d=(e,t)=>c(n=>({...n,[e]:t})),f=`w-full px-4 py-3 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors text-sm`,p=`block text-sm font-medium text-white mb-1`,m=()=>{let e={...s};t&&!l&&delete e.client_secret,r(e)},h=s.auto_link_existing_accounts===!0,g=s.require_email_verified??!0,_;return _=h?o(`settings.oidc.form.requireEmailVerifiedAutoLink`):g?o(`settings.oidc.form.requireEmailVerifiedDesc`):(0,K.jsx)(`span`,{className:`text-red-700 dark:text-red-400`,children:o(`settings.oidc.form.requireEmailVerifiedWarning`)}),(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 gap-4`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:p,children:[o(`settings.oidc.form.name`),` `,(0,K.jsx)(`span`,{className:`text-red-700 dark:text-red-400`,children:`*`})]}),(0,K.jsx)(`input`,{className:f,value:s.name,onChange:e=>d(`name`,e.target.value),placeholder:`Google`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:p,children:[o(`settings.oidc.form.issuerUrl`),` `,(0,K.jsx)(`span`,{className:`text-red-700 dark:text-red-400`,children:`*`})]}),(0,K.jsx)(`input`,{className:f,value:s.issuer_url,onChange:e=>d(`issuer_url`,e.target.value),placeholder:`https://accounts.google.com`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:p,children:[o(`settings.oidc.form.clientId`),` `,(0,K.jsx)(`span`,{className:`text-red-700 dark:text-red-400`,children:`*`})]}),(0,K.jsx)(`input`,{className:f,value:s.client_id,onChange:e=>d(`client_id`,e.target.value),placeholder:`your-client-id`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:p,children:[o(`settings.oidc.form.clientSecret`),!t&&(0,K.jsx)(`span`,{className:`text-red-700 dark:text-red-400`,children:` *`}),t&&(0,K.jsxs)(`span`,{className:`text-bambu-gray text-xs ml-1`,children:[`(`,o(`settings.oidc.form.secretHint`),`)`]})]}),(0,K.jsx)(`input`,{className:f,type:`password`,value:l?s.client_secret:``,placeholder:t&&!l?`••••••••`:o(`settings.oidc.form.secretPlaceholder`),onChange:e=>{u(!0),d(`client_secret`,e.target.value)}})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:p,children:o(`settings.oidc.form.scopes`)}),(0,K.jsx)(`input`,{className:f,value:s.scopes,onChange:e=>d(`scopes`,e.target.value),placeholder:`openid email profile`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:p,children:o(`settings.oidc.form.iconUrl`)}),(0,K.jsx)(`input`,{className:f,value:s.icon_url??``,onChange:e=>d(`icon_url`,e.target.value===``?null:e.target.value),placeholder:`https://...`})]})]}),(0,K.jsxs)(`div`,{className:`flex flex-wrap gap-6 pt-2`,children:[(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer`,children:[(0,K.jsx)(oU,{checked:s.is_enabled??!0,onChange:e=>d(`is_enabled`,e)}),(0,K.jsx)(`span`,{className:`text-white text-sm`,children:o(`settings.oidc.form.enabled`)})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer`,children:[(0,K.jsx)(oU,{checked:s.auto_create_users??!1,onChange:e=>d(`auto_create_users`,e)}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white text-sm`,children:o(`settings.oidc.form.autoCreate`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-xs`,children:o(`settings.oidc.form.autoCreateDesc`)})]})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer w-full`,children:[(0,K.jsx)(oU,{checked:s.auto_link_existing_accounts??!1,onChange:e=>d(`auto_link_existing_accounts`,e)}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white text-sm`,children:o(`settings.oidc.form.autoLink`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-xs`,children:o(`settings.oidc.form.autoLinkDesc`)})]})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer w-full`,children:[(0,K.jsx)(oU,{checked:g,onChange:e=>d(`require_email_verified`,e),disabled:h}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white text-sm`,children:o(`settings.oidc.form.requireEmailVerified`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-xs`,children:_})]})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer w-full`,children:[(0,K.jsx)(oU,{checked:s.is_autologin??!1,onChange:e=>d(`is_autologin`,e)}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white text-sm`,children:o(`settings.oidc.form.autologin`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-xs`,children:o(`settings.oidc.form.autologinDesc`)})]})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:p,children:o(`settings.oidc.form.emailClaim`)}),(0,K.jsx)(`input`,{className:f,value:s.email_claim,onChange:e=>d(`email_claim`,e.target.value||`email`),placeholder:o(`settings.oidc.form.emailClaimPlaceholder`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-xs mt-1`,children:o(`settings.oidc.form.emailClaimDesc`)}),h&&s.email_claim!==`email`&&(0,K.jsx)(`p`,{className:`text-yellow-700 dark:text-yellow-400 text-xs mt-1`,children:o(`settings.oidc.form.emailClaimCustomClaimAutoLinkWarning`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:p,children:o(`settings.oidc.form.defaultGroup`)}),(0,K.jsxs)(`select`,{className:f,value:s.default_group_id??``,onChange:e=>d(`default_group_id`,e.target.value?Number(e.target.value):null),children:[(0,K.jsx)(`option`,{value:``,children:o(`settings.oidc.form.defaultGroupViewersFallback`)}),n.map(e=>(0,K.jsx)(`option`,{value:e.id,children:e.name},e.id))]}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-xs mt-1`,children:o(`settings.oidc.form.defaultGroupDesc`)})]}),(0,K.jsxs)(`div`,{className:`flex gap-3 pt-2`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:i,className:`flex-1`,children:o(`common.cancel`)}),(0,K.jsx)($,{variant:`primary`,className:`flex-1`,disabled:!s.name||!s.issuer_url||!s.client_id||!t&&!s.client_secret||t&&l&&!s.client_secret||a,onClick:m,children:o(a?`common.saving`:`common.save`)})]})]})}function YUe({provider:e}){let[t,n]=(0,y.useState)(!1);return e.has_icon&&!t?(0,K.jsx)(`img`,{src:Q.oidcProviderIconUrl(e.id),alt:e.name,className:`w-8 h-8 rounded object-contain`,onError:()=>n(!0)}):(0,K.jsx)(`div`,{className:`w-8 h-8 rounded-full bg-bambu-dark-tertiary flex items-center justify-center`,children:(0,K.jsx)(Tc,{className:`w-4 h-4 text-bambu-gray`})})}function XUe(){let{t:e}=W(),t=oo(),{showToast:n}=Id(),[r,i]=(0,y.useState)(!1),[a,o]=(0,y.useState)(null),[s,c]=(0,y.useState)(null),{data:l,isLoading:u}=q({queryKey:[`oidc-providers-all`],queryFn:()=>Q.getOIDCProvidersAll()}),{data:d=[]}=q({queryKey:[`groups`],queryFn:()=>Q.getGroups()}),f=J({mutationFn:e=>Q.createOIDCProvider(e),onSuccess:()=>{t.invalidateQueries({queryKey:[`oidc-providers-all`]}),i(!1),n(e(`settings.oidc.created`),`success`)},onError:e=>n(e.message,`error`)}),p=J({mutationFn:({id:e,data:t})=>Q.updateOIDCProvider(e,t),onSuccess:()=>{t.invalidateQueries({queryKey:[`oidc-providers-all`]}),o(null),n(e(`settings.oidc.updated`),`success`)},onError:e=>n(e.message,`error`)}),m=J({mutationFn:e=>Q.deleteOIDCProvider(e),onSuccess:()=>{t.invalidateQueries({queryKey:[`oidc-providers-all`]}),c(null),n(e(`settings.oidc.deleted`),`success`)},onError:e=>n(e.message,`error`)}),h=J({mutationFn:e=>Q.refreshOIDCProviderIcon(e),onSuccess:()=>{t.invalidateQueries({queryKey:[`oidc-providers-all`]}),t.invalidateQueries({queryKey:[`oidc-providers`]}),n(e(`settings.oidc.iconRefreshed`),`success`)},onError:t=>n(t.message||e(`settings.oidc.iconFetchFailed`),`error`)}),g=J({mutationFn:e=>Q.deleteOIDCProviderIcon(e),onSuccess:()=>{t.invalidateQueries({queryKey:[`oidc-providers-all`]}),t.invalidateQueries({queryKey:[`oidc-providers`]}),n(e(`settings.oidc.iconRemoved`),`success`)},onError:e=>n(e.message,`error`)}),_=e=>p.mutate({id:e.id,data:{is_enabled:!e.is_enabled}});return u?(0,K.jsx)(`div`,{className:`flex items-center justify-center py-12`,children:(0,K.jsx)(Il,{className:`w-6 h-6 animate-spin text-bambu-green`})}):(0,K.jsxs)(`div`,{className:`space-y-6`,children:[(0,K.jsxs)(Od,{id:`card-oidc`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`text-white font-semibold`,children:e(`settings.oidc.title`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-sm`,children:e(`settings.oidc.desc`)})]}),!r&&(0,K.jsxs)($,{variant:`primary`,size:`sm`,onClick:()=>i(!0),className:`flex items-center gap-2`,children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),e(`settings.oidc.addProvider`)]})]})}),r&&(0,K.jsx)(Ad,{children:(0,K.jsxs)(`div`,{className:`border-t border-bambu-dark-tertiary pt-4`,children:[(0,K.jsx)(`h4`,{className:`text-white font-medium mb-4`,children:e(`settings.oidc.newProvider`)}),(0,K.jsx)(S6,{initial:JUe,groups:d,onSave:e=>f.mutate(e),onCancel:()=>i(!1),isPending:f.isPending})]})})]}),l&&l.length===0&&!r&&(0,K.jsx)(Od,{id:`card-oidc-empty`,children:(0,K.jsx)(Ad,{children:(0,K.jsxs)(`div`,{className:`text-center py-8 space-y-3`,children:[(0,K.jsx)(Tc,{className:`w-12 h-12 text-bambu-gray mx-auto`}),(0,K.jsx)(`p`,{className:`text-bambu-gray`,children:e(`settings.oidc.empty`)}),(0,K.jsxs)($,{variant:`primary`,size:`sm`,onClick:()=>i(!0),className:`inline-flex items-center gap-2`,children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),e(`settings.oidc.addProvider`)]})]})})}),l?.map(t=>(0,K.jsxs)(Od,{children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,K.jsx)(YUe,{provider:t}),(0,K.jsxs)(`div`,{className:`flex-1`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`h4`,{className:`text-white font-medium`,children:t.name}),t.is_enabled?(0,K.jsxs)(`span`,{className:`flex items-center gap-1 text-xs text-green-700 dark:text-green-400 bg-green-50 dark:bg-green-400/10 px-2 py-0.5 rounded-full`,children:[(0,K.jsx)(cs,{className:`w-3 h-3`}),` `,e(`common.enabled`)]}):(0,K.jsxs)(`span`,{className:`flex items-center gap-1 text-xs text-bambu-gray bg-bambu-dark-tertiary px-2 py-0.5 rounded-full`,children:[(0,K.jsx)(Yu,{className:`w-3 h-3`}),` `,e(`common.disabled`)]})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-1 text-bambu-gray text-xs mt-0.5`,children:[(0,K.jsx)($s,{className:`w-3 h-3`}),(0,K.jsx)(`span`,{children:t.issuer_url})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[t.icon_url&&(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>h.mutate(t.id),disabled:h.isPending,title:e(`settings.oidc.refreshIcon`),"data-testid":`refresh-icon-${t.id}`,children:(0,K.jsx)(Il,{className:`w-4 h-4 ${h.isPending?`animate-spin`:``}`})}),t.has_icon&&(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>g.mutate(t.id),disabled:g.isPending,title:e(`settings.oidc.removeIcon`),"data-testid":`remove-icon-${t.id}`,children:(0,K.jsx)(Ic,{className:`w-4 h-4`})}),(0,K.jsx)(oU,{checked:t.is_enabled,onChange:()=>_(t),disabled:p.isPending}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>o(a===t.id?null:t.id),children:(0,K.jsx)(Tl,{className:`w-4 h-4`})}),(0,K.jsx)($,{variant:`danger`,size:`sm`,onClick:()=>c(t),children:(0,K.jsx)(Ou,{className:`w-4 h-4`})})]})]})}),a===t.id&&(0,K.jsx)(Ad,{children:(0,K.jsx)(`div`,{className:`border-t border-bambu-dark-tertiary pt-4`,children:(0,K.jsx)(S6,{isEdit:!0,groups:d,initial:{name:t.name,issuer_url:t.issuer_url,client_id:t.client_id,client_secret:``,scopes:t.scopes,is_enabled:t.is_enabled,auto_create_users:t.auto_create_users,auto_link_existing_accounts:t.auto_link_existing_accounts,email_claim:t.email_claim,require_email_verified:t.require_email_verified,icon_url:t.icon_url??void 0,default_group_id:t.default_group_id??null,is_autologin:t.is_autologin},onSave:e=>p.mutate({id:t.id,data:e}),onCancel:()=>o(null),isPending:p.isPending})})}),a!==t.id&&(0,K.jsx)(Ad,{children:(0,K.jsxs)(`dl`,{className:`grid grid-cols-2 sm:grid-cols-3 gap-x-6 gap-y-2 text-sm`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`dt`,{className:`text-bambu-gray`,children:e(`settings.oidc.form.clientId`)}),(0,K.jsx)(`dd`,{className:`text-white font-mono truncate`,children:t.client_id})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`dt`,{className:`text-bambu-gray`,children:e(`settings.oidc.form.scopes`)}),(0,K.jsx)(`dd`,{className:`text-white`,children:t.scopes})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`dt`,{className:`text-bambu-gray`,children:e(`settings.oidc.form.autoCreate`)}),(0,K.jsx)(`dd`,{className:t.auto_create_users?`text-green-700 dark:text-green-400`:`text-bambu-gray`,children:t.auto_create_users?e(`common.yes`):e(`common.no`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`dt`,{className:`text-bambu-gray`,children:e(`settings.oidc.form.autoLink`)}),(0,K.jsx)(`dd`,{className:t.auto_link_existing_accounts?`text-green-700 dark:text-green-400`:`text-bambu-gray`,children:t.auto_link_existing_accounts?e(`common.yes`):e(`common.no`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`dt`,{className:`text-bambu-gray`,children:e(`settings.oidc.form.emailClaim`)}),(0,K.jsx)(`dd`,{className:`text-white font-mono`,children:t.email_claim})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`dt`,{className:`text-bambu-gray`,children:e(`settings.oidc.form.requireEmailVerified`)}),(0,K.jsx)(`dd`,{className:t.require_email_verified?`text-green-700 dark:text-green-400`:`text-red-700 dark:text-red-400`,children:t.require_email_verified?e(`common.yes`):e(`common.no`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`dt`,{className:`text-bambu-gray`,children:e(`settings.oidc.form.defaultGroup`)}),(0,K.jsx)(`dd`,{className:`text-white`,children:t.default_group_id?d.find(e=>e.id===t.default_group_id)?.name??e(`settings.oidc.form.defaultGroupViewersFallback`):e(`settings.oidc.form.defaultGroupViewersFallback`)})]})]})})]},t.id)),s&&(0,K.jsx)(Gd,{title:e(`settings.oidc.deleteTitle`),message:e(`settings.oidc.deleteMessage`,{name:s.name}),confirmText:e(`common.delete`),variant:`danger`,onConfirm:()=>m.mutate(s.id),onCancel:()=>c(null)})]})}var C6=new Map;function w6(e){C6.set(e.anchor,e)}function ZUe(){return Array.from(C6.values())}w6({labelKey:`settings.encryption.title`,labelFallback:`MFA Encryption Status`,tab:`users`,subTab:`security`,keywords:`mfa encryption status security backup totp oidc fernet`,anchor:`card-mfa-encryption`});function QUe(){let{t:e}=W(),{data:t,isLoading:n,isError:r,refetch:i}=q({queryKey:[`encryptionStatus`],queryFn:()=>Q.getEncryptionStatus(),refetchInterval:e=>{if(!e.state.error)return 3e4;let t=e.state.fetchFailureCount??0;return t<=3?Math.min(5e3*Math.max(1,t),3e4):!1}});if(n)return(0,K.jsxs)(Od,{id:`card-mfa-encryption`,"data-testid":`encryption-status-card`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(tu,{className:`text-bambu-gray`,size:20}),(0,K.jsx)(`h2`,{className:`text-lg font-semibold`,children:e(`settings.encryption.title`)})]})}),(0,K.jsx)(Ad,{children:(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-bambu-gray`,"data-testid":`encryption-loading`,children:[(0,K.jsx)(X,{className:`animate-spin`,size:16}),(0,K.jsx)(`span`,{children:e(`common.loading`)})]})})]});if(r||!t)return(0,K.jsxs)(Od,{id:`card-mfa-encryption`,"data-testid":`encryption-status-card`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(tu,{className:`text-bambu-gray`,size:20}),(0,K.jsx)(`h2`,{className:`text-lg font-semibold`,children:e(`settings.encryption.title`)})]})}),(0,K.jsxs)(Ad,{children:[(0,K.jsx)(`div`,{className:`text-red-700 dark:text-red-400`,"data-testid":`encryption-error`,children:e(`common.errorLoading`)}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>i(),className:`mt-2 text-sm text-blue-700 dark:text-blue-400 underline hover:text-blue-800 dark:hover:text-blue-300`,"data-testid":`encryption-retry-button`,children:e(`common.retry`)})]})]});let a=t.legacy_plaintext_rows.oidc_providers+t.legacy_plaintext_rows.user_totp,o=t.encrypted_rows.oidc_providers+t.encrypted_rows.user_totp,s,c,l,u;t.decryption_broken?(s=`bg-red-100 dark:bg-red-500/20 border-red-400 dark:border-red-500/50 text-red-700 dark:text-red-400`,c=(0,K.jsx)(Cs,{className:`text-red-600 dark:text-red-400`,size:20}),l=e(`settings.encryption.decryptionBrokenTitle`),u=e(`settings.encryption.decryptionBrokenError`,{count:o})):t.key_source===`generated`?(s=`bg-amber-50 dark:bg-amber-500/10 border-amber-300 dark:border-amber-500/30 text-amber-700 dark:text-amber-400`,c=(0,K.jsx)($l,{className:`text-amber-600 dark:text-amber-400`,size:20}),l=e(`settings.encryption.enabledGenerated`),u=e(`settings.encryption.backupHint`)):a>0?(s=`bg-amber-50 dark:bg-amber-500/10 border-amber-300 dark:border-amber-500/30 text-amber-700 dark:text-amber-400`,c=(0,K.jsx)(ju,{className:`text-amber-600 dark:text-amber-400`,size:20}),l=t.key_source===`env`?e(`settings.encryption.enabledFromEnv`):e(`settings.encryption.enabledFromFile`),u=e(`settings.encryption.legacyRowsWarning`,{count:a})):t.key_configured?(s=`bg-green-100 dark:bg-green-500/20 border-green-300 dark:border-green-500/30 text-green-700 dark:text-green-400`,c=(0,K.jsx)($l,{className:`text-green-600 dark:text-green-400`,size:20}),l=t.key_source===`env`?e(`settings.encryption.enabledFromEnv`):e(`settings.encryption.enabledFromFile`),u=e(`settings.encryption.allEncrypted`)):(s=`bg-gray-500/20 border-gray-500/30 text-gray-400`,c=(0,K.jsx)(eu,{className:`text-gray-400`,size:20}),l=e(`settings.encryption.notConfigured`),u=e(`settings.encryption.notConfiguredDesc`));let d=t.key_source===`generated`&&a>0;return(0,K.jsxs)(Od,{id:`card-mfa-encryption`,"data-testid":`encryption-status-card`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[c,(0,K.jsx)(`h2`,{className:`text-lg font-semibold`,children:e(`settings.encryption.title`)})]})}),(0,K.jsxs)(Ad,{children:[(0,K.jsxs)(`div`,{className:`p-3 border rounded-lg ${s}`,"data-testid":`encryption-status`,children:[(0,K.jsx)(`p`,{className:`font-medium mb-1`,children:l}),(0,K.jsx)(`p`,{className:`text-sm`,children:u})]}),d&&(0,K.jsx)(`div`,{className:`mt-2 p-3 border rounded-lg bg-amber-50 dark:bg-amber-500/10 border-amber-300 dark:border-amber-500/30 text-amber-700 dark:text-amber-400`,"data-testid":`encryption-legacy-warning`,children:(0,K.jsx)(`p`,{className:`text-sm`,children:e(`settings.encryption.legacyRowsWarning`,{count:a})})}),t.migration_error_count>0&&(0,K.jsx)(`div`,{className:`mt-2 p-3 border rounded-lg bg-amber-50 dark:bg-amber-500/10 border-amber-300 dark:border-amber-500/30 text-amber-700 dark:text-amber-400`,"data-testid":`encryption-migration-warning`,children:(0,K.jsx)(`p`,{className:`text-sm`,children:e(`settings.encryption.migrationErrorWarning`,{count:t.migration_error_count})})}),(0,K.jsxs)(`div`,{className:`mt-4 grid grid-cols-2 gap-4 text-sm`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-bambu-gray`,children:e(`settings.encryption.encryptedRowsLabel`)}),(0,K.jsxs)(`p`,{className:`font-medium`,children:[`OIDC: `,t.encrypted_rows.oidc_providers,` · TOTP: `,t.encrypted_rows.user_totp]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-bambu-gray`,children:e(`settings.encryption.legacyRowsLabel`)}),(0,K.jsxs)(`p`,{className:`font-medium`,children:[`OIDC: `,t.legacy_plaintext_rows.oidc_providers,` · TOTP: `,t.legacy_plaintext_rows.user_totp]})]})]})]})]})}var $Ue={get:`bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400 border-blue-300 dark:border-blue-500/30`,post:`bg-green-100 dark:bg-green-500/20 text-green-700 dark:text-green-400 border-green-300 dark:border-green-500/30`,put:`bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400 border-yellow-300 dark:border-yellow-500/30`,patch:`bg-orange-100 dark:bg-orange-500/20 text-orange-700 dark:text-orange-400 border-orange-300 dark:border-orange-500/30`,delete:`bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-400 border-red-300 dark:border-red-500/30`};function eWe(e,t){let n=t.replace(`#/`,``).split(`/`),r=e;for(let e of n)r=r[e];return r}function T6(e,t,n=0){if(n>5)return`...`;if(t.$ref)return T6(e,eWe(e,t.$ref),n+1);if(t.allOf){let r={};for(let i of t.allOf){let t=T6(e,i,n+1);typeof t==`object`&&t&&Object.assign(r,t)}return r}if(t.example!==void 0)return t.example;if(t.default!==void 0)return t.default;switch(t.type){case`string`:return t.enum?t.enum[0]:`string`;case`integer`:case`number`:return 0;case`boolean`:return!1;case`array`:return t.items?[T6(e,t.items,n+1)]:[];case`object`:if(t.properties){let r={};for(let[i,a]of Object.entries(t.properties))r[i]=T6(e,a,n+1);return r}return{};default:return null}}function tWe({path:e,method:t,spec:n,schema:r,apiKey:i}){let[a,o]=(0,y.useState)(!1),[s,c]=(0,y.useState)({}),[l,u]=(0,y.useState)(``),[d,f]=(0,y.useState)(null),[p,m]=(0,y.useState)(!1),[h,g]=(0,y.useState)(!1);(0,y.useEffect)(()=>{if(a&&n.parameters){let e={};for(let t of n.parameters)t.schema?.default!==void 0&&(e[t.name]=String(t.schema.default));c(t=>({...e,...t}))}},[a,n.parameters]),(0,y.useEffect)(()=>{if(a&&n.requestBody?.content?.[`application/json`]?.schema&&!l){let e=n.requestBody.content[`application/json`].schema,t=T6(r,e);u(JSON.stringify(t,null,2))}},[a,n.requestBody,r,l]);let _=(()=>{let e=[];for(let t of n.parameters||[])if(t.in===`path`||t.required){let n=s[t.name];(n===void 0||n===``)&&e.push(t.name)}return e})(),v=async()=>{if(_.length>0){f({status:0,statusText:`Validation Error`,headers:{},body:`Missing required parameters: ${_.join(`, `)}`,duration:0});return}m(!0),f(null);try{let r=e,a=new URLSearchParams;for(let e of n.parameters||[]){let t=s[e.name];t!==void 0&&t!==``&&(e.in===`path`?r=r.replace(`{${e.name}}`,encodeURIComponent(t)):e.in===`query`&&a.append(e.name,t))}let o=a.toString(),c=`${r}${o?`?${o}`:``}`,u={"Content-Type":`application/json`};i&&(u[`X-API-Key`]=i);let d={method:t.toUpperCase(),headers:u};[`post`,`put`,`patch`].includes(t)&&l&&(d.body=l);let p=performance.now(),m=await fetch(c,d),h=Math.round(performance.now()-p),g={};m.headers.forEach((e,t)=>{g[t]=e});let _;_=m.headers.get(`content-type`)?.includes(`application/json`)?await m.json():await m.text(),f({status:m.status,statusText:m.statusText,headers:g,body:_,duration:h})}catch(e){f({status:0,statusText:`Network Error`,headers:{},body:e instanceof Error?e.message:`Unknown error`,duration:0})}finally{m(!1)}},b=async()=>{if(d){let e=typeof d.body==`string`?d.body:JSON.stringify(d.body,null,2);try{await navigator.clipboard.writeText(e),g(!0),setTimeout(()=>g(!1),2e3)}catch{let t=document.createElement(`textarea`);t.value=e,t.style.position=`fixed`,t.style.left=`-999999px`,document.body.appendChild(t),t.select(),document.execCommand(`copy`),document.body.removeChild(t),g(!0),setTimeout(()=>g(!1),2e3)}}},x=(n.parameters||[]).filter(e=>e.in===`path`),S=(n.parameters||[]).filter(e=>e.in===`query`),C=[`post`,`put`,`patch`].includes(t)&&n.requestBody;return(0,K.jsxs)(`div`,{className:`border border-bambu-dark-tertiary rounded-lg overflow-hidden`,children:[(0,K.jsxs)(`button`,{onClick:()=>o(!a),className:`w-full flex items-center gap-3 p-3 hover:bg-bambu-dark-tertiary/50 transition-colors text-left`,children:[a?(0,K.jsx)(ls,{className:`w-4 h-4 text-bambu-gray flex-shrink-0`}):(0,K.jsx)(us,{className:`w-4 h-4 text-bambu-gray flex-shrink-0`}),(0,K.jsx)(`span`,{className:`px-2 py-0.5 text-xs font-mono font-semibold uppercase rounded border ${$Ue[t]||`bg-gray-500/20 text-gray-400`}`,children:t}),(0,K.jsx)(`code`,{className:`text-sm text-white font-mono flex-1 truncate`,children:e}),n.summary&&(0,K.jsx)(`span`,{className:`text-sm text-bambu-gray truncate max-w-[40%]`,children:n.summary})]}),a&&(0,K.jsxs)(`div`,{className:`border-t border-bambu-dark-tertiary p-4 space-y-4 bg-bambu-dark/50`,children:[n.description&&(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:n.description}),x.length>0&&(0,K.jsxs)(`div`,{className:`space-y-2`,children:[(0,K.jsx)(`h4`,{className:`text-sm font-medium text-white`,children:`Path Parameters`}),(0,K.jsx)(`div`,{className:`space-y-2`,children:x.map(e=>(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsxs)(`label`,{className:`text-sm text-bambu-gray w-32 flex-shrink-0`,children:[e.name,e.required&&(0,K.jsx)(`span`,{className:`text-red-700 dark:text-red-400 ml-1`,children:`*`})]}),(0,K.jsx)(`input`,{type:`text`,value:s[e.name]||``,onChange:t=>c(n=>({...n,[e.name]:t.target.value})),placeholder:e.description||e.schema?.type||`value`,className:`flex-1 px-2 py-1 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-sm font-mono focus:border-bambu-green focus:outline-none`})]},e.name))})]}),S.length>0&&(0,K.jsxs)(`div`,{className:`space-y-2`,children:[(0,K.jsx)(`h4`,{className:`text-sm font-medium text-white`,children:`Query Parameters`}),(0,K.jsx)(`div`,{className:`space-y-2`,children:S.map(e=>(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsxs)(`label`,{className:`text-sm text-bambu-gray w-32 flex-shrink-0`,children:[e.name,e.required&&(0,K.jsx)(`span`,{className:`text-red-700 dark:text-red-400 ml-1`,children:`*`})]}),e.schema?.enum?(0,K.jsxs)(`select`,{value:s[e.name]||``,onChange:t=>c(n=>({...n,[e.name]:t.target.value})),className:`flex-1 px-2 py-1 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-sm focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:``,children:`-- Select --`}),e.schema.enum.map(e=>(0,K.jsx)(`option`,{value:e,children:e},e))]}):(0,K.jsx)(`input`,{type:`text`,value:s[e.name]||``,onChange:t=>c(n=>({...n,[e.name]:t.target.value})),placeholder:e.description||e.schema?.type||`value`,className:`flex-1 px-2 py-1 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-sm font-mono focus:border-bambu-green focus:outline-none`})]},e.name))})]}),C&&(0,K.jsxs)(`div`,{className:`space-y-2`,children:[(0,K.jsx)(`h4`,{className:`text-sm font-medium text-white`,children:`Request Body`}),(0,K.jsx)(`textarea`,{value:l,onChange:e=>u(e.target.value),rows:8,className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-sm font-mono focus:border-bambu-green focus:outline-none resize-y`,placeholder:`JSON request body...`})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsxs)($,{onClick:v,disabled:p,children:[p?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(Ol,{className:`w-4 h-4`}),`Execute`]}),_.length>0&&(0,K.jsxs)(`span`,{className:`text-xs text-yellow-700 dark:text-yellow-400 flex items-center gap-1`,children:[(0,K.jsx)(hs,{className:`w-3 h-3`}),`Fill in: `,_.join(`, `)]})]}),d&&(0,K.jsxs)(`div`,{className:`space-y-2`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`h4`,{className:`text-sm font-medium text-white flex items-center gap-2`,children:[`Response`,(0,K.jsxs)(`span`,{className:`px-2 py-0.5 text-xs rounded ${d.status>=200&&d.status<300?`bg-green-100 dark:bg-green-500/20 text-green-700 dark:text-green-400`:d.status>=400?`bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-400`:`bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400`}`,children:[d.status,` `,d.statusText]}),(0,K.jsxs)(`span`,{className:`text-xs text-bambu-gray`,children:[d.duration,`ms`]})]}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:b,children:h?(0,K.jsx)(_s,{className:`w-3 h-3 text-green-600 dark:text-green-400`}):(0,K.jsx)(Ls,{className:`w-3 h-3`})})]}),(0,K.jsx)(`pre`,{className:`p-3 bg-bambu-dark rounded-lg text-sm font-mono text-white overflow-auto max-h-96 border border-bambu-dark-tertiary`,children:typeof d.body==`string`?d.body:JSON.stringify(d.body,null,2)})]})]})]})}function nWe({apiKey:e=``}){let[t,n]=(0,y.useState)(null),[r,i]=(0,y.useState)(!0),[a,o]=(0,y.useState)(null),[s,c]=(0,y.useState)(new Set),[l,u]=(0,y.useState)(``);if((0,y.useEffect)(()=>{async function e(){try{let e=await fetch(`/openapi.json`);if(!e.ok)throw Error(`Failed to fetch OpenAPI schema`);n(await e.json())}catch(e){o(e instanceof Error?e.message:`Unknown error`)}finally{i(!1)}}e()},[]),r)return(0,K.jsx)(`div`,{className:`flex justify-center py-12`,children:(0,K.jsx)(X,{className:`w-8 h-8 text-bambu-green animate-spin`})});if(a||!t)return(0,K.jsx)(Od,{children:(0,K.jsx)(Ad,{className:`py-8`,children:(0,K.jsxs)(`div`,{className:`text-center text-red-700 dark:text-red-400`,children:[(0,K.jsx)(hs,{className:`w-12 h-12 mx-auto mb-3 opacity-50`}),(0,K.jsx)(`p`,{children:`Failed to load API schema`}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mt-1`,children:a})]})})});let d={};for(let[e,n]of Object.entries(t.paths))for(let[t,r]of Object.entries(n)){if(t===`parameters`)continue;let n=r.tags||[`Other`];for(let i of n)d[i]||(d[i]=[]),d[i].push({path:e,method:t,spec:r})}let f=Object.entries(d).map(([e,t])=>l?{tag:e,endpoints:t.filter(({path:e,method:t,spec:n})=>{let r=l.toLowerCase();return e.toLowerCase().includes(r)||t.toLowerCase().includes(r)||(n.summary?.toLowerCase()||``).includes(r)||(n.description?.toLowerCase()||``).includes(r)})}:{tag:e,endpoints:t}).filter(({endpoints:e})=>e.length>0).sort((e,t)=>e.tag.localeCompare(t.tag)),p=e=>{c(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})};return(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between gap-4`,children:[(0,K.jsx)(`div`,{className:`flex-1`,children:(0,K.jsx)(`input`,{type:`text`,value:l,onChange:e=>u(e.target.value),placeholder:`Search endpoints...`,className:`w-full max-w-md px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`})}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>{c(new Set(f.map(e=>e.tag)))},children:`Expand All`}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>{c(new Set)},children:`Collapse All`}),(0,K.jsxs)(`a`,{href:`/docs`,target:`_blank`,rel:`noopener noreferrer`,className:`flex items-center gap-1 text-sm text-bambu-green hover:underline`,children:[(0,K.jsx)($s,{className:`w-4 h-4`}),`Swagger UI`]})]})]}),(0,K.jsxs)(`p`,{className:`text-sm text-bambu-gray`,children:[f.reduce((e,t)=>e+t.endpoints.length,0),` endpoints in `,f.length,` categories`]}),(0,K.jsx)(`div`,{className:`space-y-3`,children:f.map(({tag:n,endpoints:r})=>(0,K.jsxs)(Od,{children:[(0,K.jsx)(`button`,{onClick:()=>p(n),className:`w-full flex items-center justify-between p-4 hover:bg-bambu-dark-tertiary/30 transition-colors text-left`,children:(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[s.has(n)?(0,K.jsx)(ls,{className:`w-5 h-5 text-bambu-gray`}):(0,K.jsx)(us,{className:`w-5 h-5 text-bambu-gray`}),(0,K.jsx)(`h3`,{className:`text-base font-semibold text-white capitalize`,children:n.replace(/-/g,` `)}),(0,K.jsx)(`span`,{className:`text-xs bg-bambu-dark-tertiary px-2 py-0.5 rounded-full text-bambu-gray`,children:r.length})]})}),s.has(n)&&(0,K.jsx)(Ad,{className:`pt-0 space-y-2`,children:r.map(({path:n,method:r,spec:i})=>(0,K.jsx)(tWe,{path:n,method:r,spec:i,schema:t,apiKey:e},`${r}-${n}`))})]},n))})]})}var rWe=[`general`,`plugs`,`notifications`,`queue`,`filament`,`network`,`apikeys`,`virtual-printer`,`spoolbuddy`,`failure-detection`,`users`,`backup`];w6({labelKey:`settings.general`,tab:`general`,keywords:`language date time format printer model printers cards`,anchor:`card-general`}),w6({labelKey:`settings.appearance`,tab:`general`,keywords:`theme dark light mode colors`,anchor:`card-appearance`}),w6({labelKey:`settings.archiveSettings`,tab:`general`,keywords:`archive auto save thumbnails captures`,anchor:`card-archive`}),w6({labelKey:`settings.camera`,tab:`general`,keywords:`camera external video stream`,anchor:`card-camera`}),w6({labelKey:`settings.costTracking`,tab:`general`,keywords:`currency filament cost energy kwh price`,anchor:`card-cost`}),w6({labelKey:`settings.fileManager`,tab:`general`,keywords:`file manager archive mode disk warning storage`,anchor:`card-filemanager`}),w6({labelKey:`settings.updates`,tab:`general`,keywords:`updates version firmware beta check`,anchor:`card-updates`}),w6({labelKey:`settings.dataManagement`,tab:`general`,keywords:`data reset clear logs notifications preferences`,anchor:`card-data`}),w6({labelKey:`settings.smartPlugs`,tab:`plugs`,keywords:`smart plug energy power automation tapo kasa tplink shelly`,anchor:`card-plugs`}),w6({labelKey:`settings.providers`,tab:`notifications`,keywords:`telegram discord email notification providers webhook`,anchor:`card-providers`}),w6({labelKey:`settings.messageTemplates`,tab:`notifications`,keywords:`message templates notification text edit`,anchor:`card-templates`}),w6({labelKey:`settings.defaultPrintOptions`,labelFallback:`Default Print Options`,tab:`queue`,keywords:`print bed leveling flow calibration vibration first layer timelapse`,anchor:`card-print-options`}),w6({labelKey:`settings.tempFanPresetsTitle`,labelFallback:`Temperature & Fan Presets`,tab:`queue`,keywords:`temperature fan presets nozzle bed chamber quick buttons popover`,anchor:`card-temp-fan-presets`}),w6({labelKey:`settings.staggeredStart`,labelFallback:`Staggered Start`,tab:`queue`,keywords:`staggered batch delay start queue group`,anchor:`card-staggered`}),w6({labelKey:`settings.plateClear`,labelFallback:`Plate-Clear Confirmation`,tab:`queue`,keywords:`plate clear confirm auto queue`,anchor:`card-plate`}),w6({labelKey:`settings.concurrentUploadsTitle`,labelFallback:`Concurrent Uploads`,tab:`queue`,keywords:`concurrent parallel upload transfer ftp queue slow farm simultaneous`,anchor:`card-concurrent-uploads`}),w6({labelKey:`settings.gcodeInjection`,labelFallback:`G-code Injection`,tab:`queue`,keywords:`gcode injection start end autoprint farmloop swapmod autoclear printflow`,anchor:`card-gcode`}),w6({labelKey:`settings.slicerCard`,labelFallback:`Slicer`,tab:`queue`,keywords:`slicer orcaslicer bambustudio orca bambu api sidecar url docker preferred`,anchor:`card-slicer`}),w6({labelKey:`settings.queueDrying`,tab:`queue`,keywords:`drying presets temperature time humidity ams`,anchor:`card-drying`}),w6({labelKey:`settings.filamentChecks`,tab:`filament`,keywords:`filament check warning runout remaining`,anchor:`card-filamentchecks`}),w6({labelKey:`settings.printModal`,tab:`filament`,keywords:`print modal custom mapping`,anchor:`card-printmodal`}),w6({labelKey:`settings.amsDisplayThresholds`,tab:`filament`,keywords:`ams humidity temperature threshold history retention`,anchor:`card-amsthresholds`}),w6({labelKey:`settings.externalUrl`,tab:`network`,keywords:`external url reverse proxy public notification link`,anchor:`card-externalurl`}),w6({labelKey:`settings.ftpRetry`,tab:`network`,keywords:`ftp retry upload retries backoff`,anchor:`card-ftpretry`}),w6({labelKey:`settings.homeAssistant`,tab:`network`,keywords:`home assistant ha hass mqtt integration`,anchor:`card-ha`}),w6({labelKey:`settings.mqttPublishing`,tab:`network`,keywords:`mqtt publish broker topic`,anchor:`card-mqtt`}),w6({labelKey:`settings.prometheusMetrics`,tab:`network`,keywords:`prometheus metrics grafana monitoring bearer token`,anchor:`card-prometheus`}),w6({labelKey:`settings.createNewApiKey`,tab:`apikeys`,keywords:`api key create permission scope`,anchor:`card-createapi`}),w6({labelKey:`settings.webhookEndpoints`,tab:`apikeys`,keywords:`webhook endpoint post http`,anchor:`card-webhooks`}),w6({labelKey:`settings.apiBrowser`,tab:`apikeys`,keywords:`api browser endpoint documentation test`,anchor:`card-apibrowser`}),w6({labelKey:`cameraTokens.title`,tab:`apikeys`,keywords:`camera token long-lived home assistant frigate kiosk stream`,anchor:`card-camera-tokens`}),w6({labelKey:`settings.tabs.virtualPrinter`,tab:`virtual-printer`,keywords:`virtual printer proxy archive slicer bambustudio orcaslicer ip bind`,anchor:`card-vp`}),w6({labelKey:`settings.tabs.spoolbuddy`,tab:`spoolbuddy`,keywords:`spoolbuddy device scale nfc rfid kiosk unregister`,anchor:`card-spoolbuddy`}),w6({labelKey:`settings.currentUser`,tab:`users`,subTab:`users`,keywords:`current user profile password change`,anchor:`card-currentuser`}),w6({labelKey:`settings.users`,tab:`users`,subTab:`users`,keywords:`users accounts list`,anchor:`card-users`}),w6({labelKey:`settings.groups`,tab:`users`,subTab:`users`,keywords:`groups roles permissions administrators operators viewers`,anchor:`card-groups`}),w6({labelKey:`settings.sessionPolicy.title`,labelFallback:`Session Policy`,tab:`users`,subTab:`users`,keywords:`session timeout expiry logout remember me jwt token lifetime`,anchor:`card-session-policy`}),w6({labelKey:`settings.email.smtpSettings`,labelFallback:`SMTP Configuration`,tab:`users`,subTab:`email`,keywords:`smtp email send server port password auth starttls ssl`,anchor:`card-smtp`}),w6({labelKey:`settings.ldap.title`,labelFallback:`LDAP Authentication`,tab:`users`,subTab:`ldap`,keywords:`ldap active directory ad authentication bind dn search base group mapping`,anchor:`card-ldap`}),w6({labelKey:`settings.tabs.backup`,tab:`backup`,keywords:`backup github restore download cloud sync profiles archives`,anchor:`card-backup`}),w6({labelKey:`externalLinks.sidebarLayout`,labelFallback:`Sidebar`,tab:`general`,keywords:`sidebar layout links pages hide show external custom navigation url add`,anchor:`card-sidebar-links`}),w6({labelKey:`settings.filamentTracking`,tab:`filament`,keywords:`spoolman filament tracking inventory sync remote integration`,anchor:`card-spoolman`}),w6({labelKey:`settings.catalog.spoolCatalog`,labelFallback:`Spool Catalog`,tab:`filament`,keywords:`spool catalog entries brand material reset import export`,anchor:`card-spool-catalog`}),w6({labelKey:`settings.colorCatalog.title`,labelFallback:`Color Catalog`,tab:`filament`,keywords:`color catalog hex swatch palette sync reset`,anchor:`card-color-catalog`}),w6({labelKey:`settings.tabs.failureDetection`,labelFallback:`Failure Detection`,tab:`failure-detection`,keywords:`failure detection ai ml obico spaghetti detect monitoring`,anchor:`card-fd-ml`}),w6({labelKey:`failureDetection.perPrinterTitle`,labelFallback:`Per-Printer Settings`,tab:`failure-detection`,keywords:`failure detection per printer enable per-printer sensitivity`,anchor:`card-fd-perprinter`}),w6({labelKey:`failureDetection.statusTitle`,labelFallback:`Detection Status`,tab:`failure-detection`,keywords:`failure detection status running connection`,anchor:`card-fd-status`}),w6({labelKey:`failureDetection.historyTitle`,labelFallback:`Detection History`,tab:`failure-detection`,keywords:`failure detection history log events`,anchor:`card-fd-history`}),w6({labelKey:`settings.email.advancedAuth`,labelFallback:`Advanced Email Authentication`,tab:`users`,subTab:`email`,keywords:`email authentication advanced password reset self-service forgot`,anchor:`card-email-advanced-auth`}),w6({labelKey:`settings.email.testConnection`,labelFallback:`Test SMTP Connection`,tab:`users`,subTab:`email`,keywords:`email smtp test connection send check`,anchor:`card-email-test`}),w6({labelKey:`settings.twoFa.totpTitle`,labelFallback:`Authenticator App (TOTP)`,tab:`users`,subTab:`twofa`,keywords:`two factor 2fa totp authenticator app google authy otp`,anchor:`card-2fa-totp`}),w6({labelKey:`settings.twoFa.emailOtpTitle`,labelFallback:`Email One-Time Codes`,tab:`users`,subTab:`twofa`,keywords:`two factor 2fa email otp one time code`,anchor:`card-2fa-emailotp`}),w6({labelKey:`settings.twoFa.linkedAccounts`,labelFallback:`Linked Accounts`,tab:`users`,subTab:`twofa`,keywords:`two factor 2fa linked accounts sso oidc provider google github`,anchor:`card-2fa-linked`}),w6({labelKey:`settings.oidc.title`,labelFallback:`Single Sign-On (OIDC)`,tab:`users`,subTab:`oidc`,keywords:`sso oidc openid single sign-on pocketid authentik keycloak google okta azure provider`,anchor:`card-oidc`}),w6({labelKey:`settings.ldap.serverConfig`,labelFallback:`LDAP Server Configuration`,tab:`users`,subTab:`ldap`,keywords:`ldap server url bind dn user search base group filter tls`,anchor:`card-ldap-server`}),w6({labelKey:`backup.githubBackup`,labelFallback:`GitHub Backup`,tab:`backup`,keywords:`github backup cloud remote sync profiles token`,anchor:`card-backup-github`}),w6({labelKey:`backup.history`,labelFallback:`Backup History`,tab:`backup`,keywords:`backup history log runs github commits`,anchor:`card-backup-history`}),w6({labelKey:`backup.localBackup`,labelFallback:`Local Backup`,tab:`backup`,keywords:`local backup download zip manual export`,anchor:`card-backup-local`}),w6({labelKey:`backup.scheduledBackup`,labelFallback:`Scheduled Backups`,tab:`backup`,keywords:`scheduled backup automatic hourly daily weekly retention local path`,anchor:`card-backup-scheduled`});var iWe={database:`bg-blue-600`,library_files:`bg-green-500`,library_thumbnails:`bg-teal-500`,library_other:`bg-emerald-700`,archive_timelapses:`bg-red-500`,archive_thumbnails:`bg-amber-500`,archive_files:`bg-sky-500`,virtual_printer_uploads:`bg-purple-500`,virtual_printer_upload_cache:`bg-fuchsia-500`,virtual_printer_certs:`bg-violet-500`,virtual_printer_other:`bg-purple-700`,downloads:`bg-cyan-500`,plate_calibration:`bg-lime-500`,logs:`bg-orange-500`,other_data:`bg-yellow-500`},E6=[`bg-blue-500`,`bg-green-500`,`bg-yellow-500`,`bg-red-500`,`bg-orange-500`,`bg-teal-500`,`bg-cyan-500`,`bg-purple-500`],D6=(e,t)=>iWe[e]||E6[t%E6.length];function aWe(){let e=oo(),t=ir(),[n,r]=Ii(),{t:i,i18n:a}=W(),{showToast:o}=Id(),{authEnabled:s,user:c,isAdmin:l,refreshAuth:u,hasPermission:d}=Sd(),{mode:f,resolvedMode:p,darkStyle:m,darkBackground:h,darkAccent:g,lightStyle:_,lightBackground:v,lightAccent:b,setMode:x,setDarkStyle:S,setDarkBackground:C,setDarkAccent:w,setLightStyle:T,setLightBackground:E,setLightAccent:D,progressInTitle:O,setProgressInTitle:k}=Td(),[A,j]=(0,y.useState)(null),[M,N]=(0,y.useState)({}),[P,F]=(0,y.useState)(!1),[I,L]=(0,y.useState)(null),[R,z]=(0,y.useState)(!1),[B,V]=(0,y.useState)(null),[ee,te]=(0,y.useState)(null),[ne,re]=(0,y.useState)(``),[ie,H]=(0,y.useState)(``),[ae,oe]=(0,y.useState)(!1),[U,se]=(0,y.useState)(Wp()),ce=n.get(`tab`),le=ce===`email`,[ue,de]=(0,y.useState)(le?`users`:ce&&rWe.includes(ce)?ce:`general`),[fe,pe]=(0,y.useState)(le?`email`:`users`),[me,he]=(0,y.useState)(ce===`queue`&&n.get(`sub`)===`pipelines`?`pipelines`:`dispatch`),ge=e=>{de(e),e===`users`&&pe(`users`),e===`queue`&&(he(`dispatch`),n.delete(`sub`)),e===`general`?n.delete(`tab`):n.set(`tab`,e),r(n,{replace:!0})},_e=e=>{he(e),e===`pipelines`?n.set(`sub`,`pipelines`):n.delete(`sub`),r(n,{replace:!0})},[ve,ye]=(0,y.useState)(!1),[be,xe]=(0,y.useState)(``),[Se,Ce]=(0,y.useState)({can_queue:!0,can_control_printer:!1,can_read_status:!0,can_manage_library:!0,can_manage_inventory:!0,can_manage_maintenance:!0,can_manage_archives:!0,can_manage_projects:!0,can_access_cloud:!1,can_update_energy_cost:!1}),[we,Te]=(0,y.useState)(null),[Ee,De]=(0,y.useState)(!1),[Oe,ke]=(0,y.useState)(null),[Ae,je]=(0,y.useState)(``),[Me,Ne]=(0,y.useState)(!1),[Pe,Fe]=(0,y.useState)(!1),[Ie,Le]=(0,y.useState)(null),[Re,ze]=(0,y.useState)(!1),[Be,Ve]=(0,y.useState)(!1),[He,Ue]=(0,y.useState)(!1),[We,Ge]=(0,y.useState)({currentPassword:``,newPassword:``,confirmPassword:``}),[Ke,qe]=(0,y.useState)(!1),[Je,Ye]=(0,y.useState)(!1),[Xe,Ze]=(0,y.useState)(!1),[Qe,$e]=(0,y.useState)(`local`),[et,tt]=(0,y.useState)(!1),[nt,rt]=(0,y.useState)(null),[it,at]=(0,y.useState)(null),[ot,st]=(0,y.useState)(null),[ct,lt]=(0,y.useState)(!1),[ut,dt]=(0,y.useState)({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]}),[ft,pt]=(0,y.useState)(null),[mt,ht]=(0,y.useState)(null),[gt,_t]=(0,y.useState)(!1),[vt,yt]=(0,y.useState)({}),[bt,xt]=(0,y.useState)({}),St=e=>{se(e),nee(e),o(i(`settings.toast.settingsSaved`),`success`)},{data:Ct,isLoading:wt}=q({queryKey:[`settings`],queryFn:Q.getSettings}),{data:Tt,isLoading:Et,isFetching:Dt}=q({queryKey:[`storage-usage`],queryFn:()=>Q.getStorageUsage(),enabled:ue===`general`,staleTime:1/0,refetchInterval:!1,refetchOnWindowFocus:!1,refetchOnReconnect:!1}),kt=async()=>{Ye(!0);try{let t=await Q.getStorageUsage({refresh:!0});e.setQueryData([`storage-usage`],t)}catch(e){o(e instanceof Error?e.message:`Failed to refresh storage usage`,`error`)}finally{Ye(!1)}},{data:At,isLoading:jt}=q({queryKey:[`smart-plugs`],queryFn:Q.getSmartPlugs}),{data:Mt,isLoading:Nt}=q({queryKey:[`smart-plugs-energy`,At?.map(e=>e.id)],queryFn:async()=>{if(!At||At.length===0)return null;let e=await Promise.all(At.filter(e=>e.enabled).map(async e=>{try{return{plug:e,status:await Q.getSmartPlugStatus(e.id)}}catch{return{plug:e,status:null}}})),t=0,n=0,r=0,i=0,a=0;for(let{plug:o,status:s}of e){let e=o.plug_type===`mqtt`&&s?.energy?.power!=null;(s?.reachable||e)&&s?.energy&&(a++,s.energy?.power!=null&&(t+=s.energy.power),s.energy?.today!=null&&(n+=s.energy.today),s.energy?.yesterday!=null&&(r+=s.energy.yesterday),s.energy?.total!=null&&(i+=s.energy.total))}return{totalPower:t,totalToday:n,totalYesterday:r,totalLifetime:i,reachableCount:a,totalPlugs:At.filter(e=>e.enabled).length}},enabled:ue===`plugs`&&!!At&&At.length>0,refetchInterval:ue===`plugs`?1e4:!1}),{data:Pt,isLoading:Ft}=q({queryKey:[`notification-providers`],queryFn:Q.getNotificationProviders}),{data:It,isLoading:Lt}=q({queryKey:[`api-keys`],queryFn:Q.getAPIKeys}),G=J({mutationFn:e=>Q.createAPIKey(e),onSuccess:t=>{Te(t.key||null),ye(!1),xe(``),e.invalidateQueries({queryKey:[`api-keys`]}),o(i(`settings.toast.apiKeyCreated`))},onError:e=>{o(`Failed to create API key: ${e.message}`,`error`)}}),Rt=J({mutationFn:e=>Q.deleteAPIKey(e),onSuccess:(t,n)=>{e.setQueryData([`api-keys`],e=>(e??[]).filter(e=>e.id!==n)),o(i(`settings.toast.apiKeyDeleted`))},onError:e=>{o(`Failed to delete API key: ${e.message}`,`error`)}}),{data:zt}=q({queryKey:[`printers`],queryFn:Q.getPrinters}),Bt=gf(zt?.length??0),{data:Vt,isLoading:Ht}=q({queryKey:[`notification-templates`],queryFn:Q.getNotificationTemplates}),{data:Ut}=q({queryKey:[`virtual-printer-settings`],queryFn:fd.getSettings,refetchInterval:1e4}),Wt=Ut?.status?.running??!1,{data:Gt}=q({queryKey:[`spoolbuddy-devices`],queryFn:()=>_d.getDevices(),refetchInterval:15e3}),Kt=Gt?.length??0,qt=Gt?.some(e=>e.online)??!1,{data:Jt}=q({queryKey:[`obico-status`],queryFn:Q.getObicoStatus,refetchInterval:15e3}),Yt=!!(Jt?.is_running&&Jt?.enabled),{data:Xt}=q({queryKey:[`ffmpeg-status`],queryFn:Q.checkFfmpeg}),{data:Zt}=q({queryKey:[`version`],queryFn:Q.getVersion}),Qt=!s||d(`library:purge`),{data:$t}=q({queryKey:[`library-trash-settings`],queryFn:()=>Q.getLibraryTrashSettings(),enabled:Qt}),en=J({mutationFn:e=>Q.updateLibraryTrashSettings(e),onSuccess:()=>{e.invalidateQueries({queryKey:[`library-trash-settings`]}),o(i(`settings.toast.settingsSaved`),`success`)},onError:e=>o(e.message||i(`libraryAutoPurge.saveFailed`),`error`)}),tn=e=>{$t&&en.mutate({retention_days:$t.retention_days,auto_purge_enabled:$t.auto_purge_enabled,auto_purge_days:$t.auto_purge_days,auto_purge_include_never_printed:$t.auto_purge_include_never_printed,...e})},nn=!s||d(`archives:purge`),{data:rn}=q({queryKey:[`archive-purge-settings`],queryFn:()=>Q.getArchivePurgeSettings(),enabled:nn}),an=J({mutationFn:e=>Q.updateArchivePurgeSettings(e),onSuccess:()=>{e.invalidateQueries({queryKey:[`archive-purge-settings`]}),o(i(`settings.toast.settingsSaved`),`success`)},onError:e=>o(e.message||i(`archiveAutoPurge.saveFailed`),`error`)}),on=e=>{rn&&an.mutate({enabled:rn.enabled,days:rn.days,purge_stats:rn.purge_stats,...e})},{data:sn,refetch:cn,isRefetching:ln}=q({queryKey:[`updateCheck`],queryFn:Q.checkForUpdates,enabled:Ct?.check_updates!==!1,staleTime:300*1e3}),{data:un,refetch:dn}=q({queryKey:[`updateStatus`],queryFn:Q.getUpdateStatus,refetchInterval:e=>{let t=e.state.data;return t?.status===`downloading`||t?.status===`installing`?1e3:!1}}),{data:fn}=q({queryKey:[`mqtt-status`],queryFn:Q.getMQTTStatus,refetchInterval:ue===`network`?5e3:!1}),{data:pn}=q({queryKey:[`github-backup-status`],queryFn:Q.getGitHubBackupStatus}),{data:mn}=q({queryKey:[`cloud-status`],queryFn:Q.getCloudStatus}),{data:hn={advanced_auth_enabled:!1,smtp_configured:!1,local_login_enabled:!0,autologin_provider_id:null}}=q({queryKey:[`advancedAuthStatus`],queryFn:()=>Q.getAdvancedAuthStatus()}),{data:gn}=q({queryKey:[`ldapStatus`],queryFn:()=>Q.getLDAPStatus()}),{data:_n}=q({queryKey:[`twoFAStatus`],queryFn:()=>Q.get2FAStatus()}),{data:vn=[]}=q({queryKey:[`oidcProvidersAll`],queryFn:()=>Q.getOIDCProvidersAll(),enabled:l}),{data:yn=[],isLoading:bn}=q({queryKey:[`users`],queryFn:()=>Q.getUsers(),enabled:s&&d(`users:read`)}),{data:xn=[],isLoading:Sn}=q({queryKey:[`groups`],queryFn:()=>Q.getGroups(),enabled:s&&d(`groups:read`)}),Cn=J({mutationFn:e=>Q.createUser(e),onSuccess:()=>{e.invalidateQueries({queryKey:[`users`]}),e.invalidateQueries({queryKey:[`groups`]}),Ze(!1),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]}),o(i(`settings.toast.userCreated`))},onError:e=>{o(e.message,`error`)}}),wn=J({mutationFn:({id:e,data:t})=>Q.updateUser(e,t),onSuccess:()=>{e.invalidateQueries({queryKey:[`users`]}),e.invalidateQueries({queryKey:[`groups`]}),tt(!1),rt(null),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]}),o(i(`settings.toast.userUpdated`))},onError:e=>{o(e.message,`error`)}}),Tn=J({mutationFn:({id:e,deleteItems:t})=>Q.deleteUser(e,t),onSuccess:()=>{e.invalidateQueries({queryKey:[`users`]}),o(i(`settings.toast.userDeleted`)),at(null),st(null)},onError:e=>{o(e.message,`error`)}}),En=J({mutationFn:e=>Q.resetUserPassword({user_id:e}),onSuccess:e=>{o(e.message,`success`)},onError:e=>{o(e.message,`error`)}}),Dn=async e=>{at(e),lt(!0);try{st(await Q.getUserItemsCount(e))}catch{st({archives:0,queue_items:0,library_files:0})}finally{lt(!1)}},On=J({mutationFn:e=>Q.deleteGroup(e),onSuccess:()=>{e.invalidateQueries({queryKey:[`groups`]}),o(i(`settings.toast.groupDeleted`))},onError:e=>{o(e.message,`error`)}}),kn=()=>{let e=hn?.advanced_auth_enabled||!1;if(!ut.username){o(i(`settings.toast.fillRequiredFields`),`error`);return}if(e&&!ut.email){o(`Email is required when advanced authentication is enabled`,`error`);return}if(!e){if(!ut.password){o(i(`settings.toast.fillRequiredFields`),`error`);return}if(ut.password!==ut.confirmPassword){o(i(`settings.toast.passwordsDoNotMatch`),`error`);return}let e=k3(ut.password);if(e){o(i({tooShort:`settings.toast.passwordTooShort`,needsUppercase:`settings.toast.passwordNeedsUppercase`,needsLowercase:`settings.toast.passwordNeedsLowercase`,needsDigit:`settings.toast.passwordNeedsDigit`,needsSpecial:`settings.toast.passwordNeedsSpecial`}[e]),`error`);return}}Cn.mutate({username:ut.username,password:e?void 0:ut.password,email:ut.email||void 0,role:ut.role,group_ids:ut.group_ids.length>0?ut.group_ids:void 0})},An=e=>{if(ut.password){if(ut.password!==ut.confirmPassword){o(i(`settings.toast.passwordsDoNotMatch`),`error`);return}let e=k3(ut.password);if(e){o(i({tooShort:`settings.toast.passwordTooShort`,needsUppercase:`settings.toast.passwordNeedsUppercase`,needsLowercase:`settings.toast.passwordNeedsLowercase`,needsDigit:`settings.toast.passwordNeedsDigit`,needsSpecial:`settings.toast.passwordNeedsSpecial`}[e]),`error`);return}}let t={username:ut.username||void 0,password:ut.password||void 0,email:ut.email||void 0,role:ut.role,group_ids:ut.group_ids};t.password||delete t.password,wn.mutate({id:e,data:t})},jn=e=>{rt(e.id),dt({username:e.username,password:``,email:e.email||``,confirmPassword:``,role:e.role,group_ids:e.groups?.map(e=>e.id)||[]}),tt(!0)},Mn=e=>{dt(t=>({...t,group_ids:t.group_ids.includes(e)?t.group_ids.filter(t=>t!==e):[...t.group_ids,e]}))},Nn=J({mutationFn:Q.applyUpdate,onSuccess:e=>{e.is_ha_addon||e.is_docker||e.is_windows_installer?o(e.message,`error`):dn()}}),[Pn,Fn]=(0,y.useState)(null),In=J({mutationFn:Q.testAllNotificationProviders,onSuccess:t=>{Fn(t),e.invalidateQueries({queryKey:[`notification-providers`]}),t.failed===0?o(`All ${t.tested} providers tested successfully!`,`success`):o(`${t.success}/${t.tested} providers succeeded`,t.failed>0?`error`:`success`)},onError:e=>{o(`Failed to test providers: ${e.message}`,`error`)}}),Ln=J({mutationFn:async e=>{if(!At)return{success:0,failed:0};let t=At.filter(e=>e.enabled),n=await Promise.all(t.map(async t=>{try{return await Q.controlSmartPlug(t.id,e),{success:!0}}catch{return{success:!1}}}));return{success:n.filter(e=>e.success).length,failed:n.filter(e=>!e.success).length}},onSuccess:(t,n)=>{e.invalidateQueries({queryKey:[`smart-plugs`]}),e.invalidateQueries({queryKey:[`smart-plugs-energy`]}),t.failed===0?o(`All ${t.success} plugs turned ${n}`,`success`):o(`${t.success} plugs turned ${n}, ${t.failed} failed`,`error`)},onError:e=>{o(`Failed: ${e.message}`,`error`)}}),Rn=(0,y.useRef)(null),zn=(0,y.useRef)(null),Bn=(0,y.useRef)(!1),Vn=(0,y.useRef)(!0),Hn=(0,y.useRef)(null);(0,y.useEffect)(()=>{if(Ct&&!A){let e={...Ct,external_url:Ct.external_url||window.location.origin};Hn.current=Ct,j(e),setTimeout(()=>{Vn.current=!1},100)}},[Ct,A]),(0,y.useEffect)(()=>{let e=Hn.current;if(!Ct||!A||!e||Ct===e)return;let t={};for(let n of Object.keys(Ct))Ct[n]!==e[n]&&A[n]===e[n]&&(t[n]=Ct[n]);Hn.current=Ct,Object.keys(t).length>0&&j(e=>e&&{...e,...t})},[Ct,A]);let Un=J({mutationFn:Q.updateSettings,onSuccess:t=>{Hn.current=t,e.setQueryData([`settings`],t),e.invalidateQueries({queryKey:[`archiveStats`]}),o(i(`settings.toast.settingsSaved`),`success`)},onError:e=>{o(`Failed to save: ${e.message}`,`error`)},onSettled:()=>{Bn.current=!1}}),Wn=J({mutationFn:({id:e,data:t})=>Q.updatePrinter(e,t),onSuccess:()=>{e.invalidateQueries({queryKey:[`printers`]}),o(i(`settings.toast.cameraSettingsSaved`),`success`)},onError:e=>{o(`Failed to update printer: ${e.message}`,`error`)}});(0,y.useEffect)(()=>{let e=Hn.current;if(!(Vn.current||!A||!Ct||!e)&&!(s&&!d(`settings:update`))&&(e.auto_archive!==A.auto_archive||e.save_thumbnails!==A.save_thumbnails||e.capture_finish_photo!==A.capture_finish_photo||(e.finish_photo_restore_plate??!0)!==(A.finish_photo_restore_plate??!0)||e.default_filament_cost!==A.default_filament_cost||e.currency!==A.currency||e.energy_cost_per_kwh!==A.energy_cost_per_kwh||e.energy_tracking_mode!==A.energy_tracking_mode||e.check_updates!==A.check_updates||(e.check_printer_firmware??!0)!==(A.check_printer_firmware??!0)||(e.include_beta_updates??!1)!==(A.include_beta_updates??!1)||(e.local_login_enabled??!0)!==(A.local_login_enabled??!0)||e.notification_language!==A.notification_language||(e.bed_cooled_threshold??35)!==(A.bed_cooled_threshold??35)||e.ams_humidity_good!==A.ams_humidity_good||e.ams_humidity_fair!==A.ams_humidity_fair||e.ams_temp_good!==A.ams_temp_good||e.ams_temp_fair!==A.ams_temp_fair||e.ams_history_retention_days!==A.ams_history_retention_days||e.disable_filament_warnings!==A.disable_filament_warnings||e.prefer_lowest_filament!==A.prefer_lowest_filament||(e.queue_drying_enabled??!1)!==(A.queue_drying_enabled??!1)||(e.queue_drying_block??!1)!==(A.queue_drying_block??!1)||(e.ambient_drying_enabled??!1)!==(A.ambient_drying_enabled??!1)||(e.print_drying_enabled??!1)!==(A.print_drying_enabled??!1)||(e.drying_presets??``)!==(A.drying_presets??``)||(e.ams_humidity_thresholds??``)!==(A.ams_humidity_thresholds??``)||e.per_printer_mapping_expanded!==A.per_printer_mapping_expanded||e.date_format!==A.date_format||e.time_format!==A.time_format||e.default_printer_id!==A.default_printer_id||e.ftp_retry_enabled!==A.ftp_retry_enabled||e.ftp_retry_count!==A.ftp_retry_count||e.ftp_retry_delay!==A.ftp_retry_delay||e.ftp_timeout!==A.ftp_timeout||e.mqtt_enabled!==A.mqtt_enabled||e.mqtt_broker!==A.mqtt_broker||e.mqtt_port!==A.mqtt_port||e.mqtt_username!==A.mqtt_username||e.mqtt_password!==A.mqtt_password||e.mqtt_topic_prefix!==A.mqtt_topic_prefix||e.mqtt_use_tls!==A.mqtt_use_tls||e.external_url!==A.external_url||e.ha_enabled!==A.ha_enabled||e.ha_url!==A.ha_url||e.ha_token!==A.ha_token||(e.library_archive_mode??`ask`)!==(A.library_archive_mode??`ask`)||Number(e.library_disk_warning_gb??5)!==Number(A.library_disk_warning_gb??5)||(e.camera_view_mode??`window`)!==(A.camera_view_mode??`window`)||(e.preferred_slicer??`bambu_studio`)!==(A.preferred_slicer??`bambu_studio`)||(e.open_in_slicer??null)!==(A.open_in_slicer??null)||(e.use_slicer_api??!1)!==(A.use_slicer_api??!1)||(e.orcaslicer_api_url??``)!==(A.orcaslicer_api_url??``)||(e.slicer_stall_timeout_minutes??15)!==(A.slicer_stall_timeout_minutes??15)||(e.bambu_studio_api_url??``)!==(A.bambu_studio_api_url??``)||e.prometheus_enabled!==A.prometheus_enabled||e.prometheus_token!==A.prometheus_token||(e.user_notifications_enabled??!0)!==(A.user_notifications_enabled??!0)||(e.default_bed_levelling??`auto`)!==(A.default_bed_levelling??`auto`)||(e.default_flow_cali??`auto`)!==(A.default_flow_cali??`auto`)||(e.default_vibration_cali??!0)!==(A.default_vibration_cali??!0)||(e.default_layer_inspect??!1)!==(A.default_layer_inspect??!1)||(e.default_timelapse??!1)!==(A.default_timelapse??!1)||(e.default_nozzle_offset_cali??`auto`)!==(A.default_nozzle_offset_cali??`auto`)||(e.stagger_group_size??2)!==(A.stagger_group_size??2)||(e.stagger_interval_minutes??5)!==(A.stagger_interval_minutes??5)||(e.require_plate_clear??!1)!==(A.require_plate_clear??!1)||(e.queue_max_concurrent_uploads??4)!==(A.queue_max_concurrent_uploads??4)||(e.preheat_enabled??!1)!==(A.preheat_enabled??!1)||(e.preheat_filament_targets??``)!==(A.preheat_filament_targets??``)||(e.preheat_max_wait_seconds??900)!==(A.preheat_max_wait_seconds??900)||(e.preheat_soak_seconds??300)!==(A.preheat_soak_seconds??300)||(e.nozzle_temp_presets??``)!==(A.nozzle_temp_presets??``)||(e.bed_temp_presets??``)!==(A.bed_temp_presets??``)||(e.chamber_temp_presets??``)!==(A.chamber_temp_presets??``)||(e.fan_speed_presets??``)!==(A.fan_speed_presets??``)||(e.session_max_hours??24)!==(A.session_max_hours??24))&&!Bn.current)return Rn.current&&clearTimeout(Rn.current),Rn.current=setTimeout(()=>{if(Bn.current)return;Bn.current=!0;let e={auto_archive:A.auto_archive,save_thumbnails:A.save_thumbnails,capture_finish_photo:A.capture_finish_photo,finish_photo_restore_plate:A.finish_photo_restore_plate??!0,default_filament_cost:A.default_filament_cost,currency:A.currency,energy_cost_per_kwh:A.energy_cost_per_kwh,energy_tracking_mode:A.energy_tracking_mode,check_updates:A.check_updates,check_printer_firmware:A.check_printer_firmware,include_beta_updates:A.include_beta_updates,local_login_enabled:A.local_login_enabled,notification_language:A.notification_language,bed_cooled_threshold:A.bed_cooled_threshold,ams_humidity_good:A.ams_humidity_good,ams_humidity_fair:A.ams_humidity_fair,ams_temp_good:A.ams_temp_good,ams_temp_fair:A.ams_temp_fair,ams_history_retention_days:A.ams_history_retention_days,disable_filament_warnings:A.disable_filament_warnings,prefer_lowest_filament:A.prefer_lowest_filament,queue_drying_enabled:A.queue_drying_enabled,queue_drying_block:A.queue_drying_block,ambient_drying_enabled:A.ambient_drying_enabled,print_drying_enabled:A.print_drying_enabled,drying_presets:A.drying_presets,ams_humidity_thresholds:A.ams_humidity_thresholds,per_printer_mapping_expanded:A.per_printer_mapping_expanded,date_format:A.date_format,time_format:A.time_format,default_printer_id:A.default_printer_id,ftp_retry_enabled:A.ftp_retry_enabled,ftp_retry_count:A.ftp_retry_count,ftp_retry_delay:A.ftp_retry_delay,ftp_timeout:A.ftp_timeout,mqtt_enabled:A.mqtt_enabled,mqtt_broker:A.mqtt_broker,mqtt_port:A.mqtt_port,mqtt_username:A.mqtt_username,mqtt_password:A.mqtt_password,mqtt_topic_prefix:A.mqtt_topic_prefix,mqtt_use_tls:A.mqtt_use_tls,external_url:A.external_url,ha_enabled:A.ha_enabled,ha_url:A.ha_url,ha_token:A.ha_token,library_archive_mode:A.library_archive_mode,library_disk_warning_gb:A.library_disk_warning_gb,camera_view_mode:A.camera_view_mode,preferred_slicer:A.preferred_slicer,open_in_slicer:A.open_in_slicer,use_slicer_api:A.use_slicer_api,orcaslicer_api_url:A.orcaslicer_api_url,slicer_stall_timeout_minutes:A.slicer_stall_timeout_minutes,bambu_studio_api_url:A.bambu_studio_api_url,prometheus_enabled:A.prometheus_enabled,prometheus_token:A.prometheus_token,user_notifications_enabled:A.user_notifications_enabled,default_bed_levelling:A.default_bed_levelling,default_flow_cali:A.default_flow_cali,default_vibration_cali:A.default_vibration_cali,default_layer_inspect:A.default_layer_inspect,default_timelapse:A.default_timelapse,default_nozzle_offset_cali:A.default_nozzle_offset_cali,stagger_group_size:A.stagger_group_size,stagger_interval_minutes:A.stagger_interval_minutes,require_plate_clear:A.require_plate_clear,queue_max_concurrent_uploads:A.queue_max_concurrent_uploads,preheat_enabled:A.preheat_enabled,preheat_filament_targets:A.preheat_filament_targets,preheat_max_wait_seconds:A.preheat_max_wait_seconds,preheat_soak_seconds:A.preheat_soak_seconds,nozzle_temp_presets:A.nozzle_temp_presets,bed_temp_presets:A.bed_temp_presets,chamber_temp_presets:A.chamber_temp_presets,fan_speed_presets:A.fan_speed_presets,session_max_hours:A.session_max_hours};Un.mutate(e)},500),()=>{Rn.current&&clearTimeout(Rn.current)}},[A,Ct,Un,s,d,o,i]);let Gn=(0,y.useCallback)((e,t)=>{if(s&&!d(`settings:update`)){o(i(`settings.toast.noPermissionUpdate`),`error`);return}j(n=>n?{...n,[e]:t}:null)},[s,d,o,i]),Kn=async(e,t,n)=>{if(!t){o(i(`settings.toast.enterCameraUrl`),`error`);return}xt(t=>({...t,[e]:!0})),yt(t=>({...t,[e]:null}));try{let r=await Q.testExternalCamera(e,t,n);yt(t=>({...t,[e]:r})),r.success?o(r.coalesced?i(`settings.toast.cameraConnectedCoalesced`,{resolution:r.resolution||``}):i(`settings.toast.cameraConnected`,{resolution:r.resolution||``}),`success`):o(r.error||i(`settings.toast.connectionFailed`),`error`)}catch(t){let n=t instanceof Error?t.message:i(`settings.toast.testFailed`);yt(t=>({...t,[e]:{success:!1,error:n}})),o(n,`error`)}finally{xt(t=>({...t,[e]:!1}))}},[qn,Jn]=(0,y.useState)({}),Yn=(0,y.useRef)({}),Xn=(0,y.useRef)(new Set),[Zn,Qn]=(0,y.useState)({}),$n=(0,y.useRef)({}),er=(0,y.useRef)(new Set);(0,y.useEffect)(()=>{if(zt){let e={},t={};zt.forEach(n=>{n.external_camera_url&&!Xn.current.has(n.id)&&(e[n.id]=n.external_camera_url,Xn.current.add(n.id)),n.external_camera_snapshot_url&&!er.current.has(n.id)&&(t[n.id]=n.external_camera_snapshot_url,er.current.add(n.id))}),Object.keys(e).length>0&&Jn(t=>({...t,...e})),Object.keys(t).length>0&&Qn(e=>({...e,...t}))}},[zt]);let tr=(e,t)=>{Jn(n=>({...n,[e]:t})),Yn.current[e]&&clearTimeout(Yn.current[e]),Yn.current[e]=setTimeout(()=>{Wn.mutate({id:e,data:{external_camera_url:t||null}})},800)},nr=(e,t)=>{Qn(n=>({...n,[e]:t})),$n.current[e]&&clearTimeout($n.current[e]),$n.current[e]=setTimeout(()=>{Wn.mutate({id:e,data:{external_camera_snapshot_url:t||null}})},800)},rr=(e,t)=>{let n={};t.type!==void 0&&(n.external_camera_type=t.type||null),t.enabled!==void 0&&(n.external_camera_enabled=t.enabled),t.rotation!==void 0&&(n.camera_rotation=t.rotation),Wn.mutate({id:e,data:n})};if(wt||!A)return(0,K.jsx)(`div`,{className:`p-4 md:p-8 flex justify-center`,children:(0,K.jsx)(X,{className:`w-8 h-8 text-bambu-green animate-spin`})});let ar=ZUe().map(e=>({...e,label:i(e.labelKey,e.labelFallback??e.labelKey)})),or=ie.trim().toLowerCase(),sr=or?ar.filter(e=>e.label.toLowerCase().includes(or)||e.keywords.toLowerCase().includes(or)).slice(0,8):[],cr=e=>{ge(e.tab),e.subTab&&pe(e.subTab),H(``),setTimeout(()=>{let t=document.getElementById(e.anchor);t&&(t.scrollIntoView({behavior:`smooth`,block:`start`}),t.classList.add(`ring-2`,`ring-bambu-green`),setTimeout(()=>t.classList.remove(`ring-2`,`ring-bambu-green`),1500))},50)};return(0,K.jsx)(Dd,{density:`dense`,children:(0,K.jsxs)(`div`,{className:`p-4 md:p-8`,children:[(0,K.jsxs)(`div`,{className:`mb-4 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`h1`,{className:`text-2xl font-bold text-white flex items-center gap-3`,children:[(0,K.jsx)(Zl,{className:`w-7 h-7 text-bambu-green`}),i(`settings.title`)]}),(0,K.jsx)(`p`,{className:`text-bambu-gray mt-1`,children:i(`settings.configureBambuddy`)})]}),(0,K.jsxs)(`div`,{className:`relative sm:w-72`,children:[(0,K.jsx)(Kl,{className:`w-4 h-4 text-bambu-gray absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none`}),(0,K.jsx)(`input`,{type:`text`,value:ie,onChange:e=>H(e.target.value),placeholder:i(`settings.searchPlaceholder`,`Search settings…`),className:`w-full pl-9 pr-8 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-sm focus:outline-none focus:border-bambu-green`}),ie&&(0,K.jsx)(`button`,{onClick:()=>H(``),className:`absolute right-2 top-1/2 -translate-y-1/2 p-1 text-bambu-gray hover:text-white`,"aria-label":`Clear`,children:(0,K.jsx)(Yu,{className:`w-3.5 h-3.5`})}),sr.length>0&&(0,K.jsx)(`div`,{className:`absolute top-full left-0 right-0 mt-1 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg shadow-xl z-30 overflow-hidden`,children:sr.map(e=>(0,K.jsxs)(`button`,{onClick:()=>cr(e),className:`w-full px-3 py-2 text-left hover:bg-bambu-dark-tertiary transition-colors border-b border-bambu-dark-tertiary last:border-b-0`,children:[(0,K.jsx)(`p`,{className:`text-sm text-white`,children:e.label}),(0,K.jsxs)(`p`,{className:`text-xs text-bambu-gray`,children:[i(`settings.tabs.${e.tab===`virtual-printer`?`virtualPrinter`:e.tab===`failure-detection`?`failureDetection`:e.tab}`),e.subTab?` › ${i(`settings.tabs.${e.subTab}`,e.subTab)}`:``]})]},e.anchor))}),or&&sr.length===0&&(0,K.jsx)(`div`,{className:`absolute top-full left-0 right-0 mt-1 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg shadow-xl z-30 p-3`,children:(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray italic`,children:i(`settings.noSearchResults`,`No matching settings.`)})})]})]}),(0,K.jsxs)(`div`,{className:`flex flex-col lg:flex-row gap-4 lg:gap-6`,children:[(0,K.jsxs)(`nav`,{className:`flex flex-wrap gap-1 border-b border-bambu-dark-tertiary lg:flex-col lg:flex-nowrap lg:gap-0 lg:border-b-0 lg:border-r lg:w-48 lg:flex-shrink-0 lg:self-start lg:sticky lg:top-4`,children:[(0,K.jsxs)(`button`,{onClick:()=>ge(`general`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${ue===`general`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Zl,{className:`w-4 h-4`}),i(`settings.tabs.general`)]}),(0,K.jsxs)(`button`,{onClick:()=>ge(`plugs`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${ue===`plugs`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(kl,{className:`w-4 h-4`}),i(`settings.tabs.smartPlugs`),At&&At.length>0&&(0,K.jsx)(`span`,{className:`text-xs bg-bambu-dark-tertiary px-1.5 py-0.5 rounded-full`,children:At.length})]}),(0,K.jsxs)(`button`,{onClick:()=>ge(`notifications`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${ue===`notifications`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Wo,{className:`w-4 h-4`}),i(`settings.tabs.notifications`),Pt&&Pt.length>0&&(0,K.jsx)(`span`,{className:`text-xs bg-bambu-dark-tertiary px-1.5 py-0.5 rounded-full`,children:Pt.length})]}),(0,K.jsxs)(`button`,{onClick:()=>ge(`queue`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${ue===`queue`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Jc,{className:`w-4 h-4`}),i(`settings.tabs.queue`,`Workflow`)]}),(0,K.jsxs)(`button`,{onClick:()=>ge(`filament`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${ue===`filament`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Bs,{className:`w-4 h-4`}),i(`settings.tabs.filament`)]}),(0,K.jsxs)(`button`,{onClick:()=>ge(`network`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${ue===`network`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Gu,{className:`w-4 h-4`}),i(`settings.tabs.network`),(0,K.jsx)(`span`,{className:`w-2 h-2 rounded-full ${fn?.enabled?`bg-green-400`:`bg-gray-500`}`})]}),(0,K.jsxs)(`button`,{onClick:()=>ge(`apikeys`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${ue===`apikeys`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Vc,{className:`w-4 h-4`}),i(`settings.tabs.apiKeys`),It&&It.length>0&&(0,K.jsx)(`span`,{className:`text-xs bg-bambu-dark-tertiary px-1.5 py-0.5 rounded-full`,children:It.length})]}),(0,K.jsxs)(`button`,{onClick:()=>ge(`virtual-printer`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${ue===`virtual-printer`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Nl,{className:`w-4 h-4`}),i(`settings.tabs.virtualPrinter`),(0,K.jsx)(`span`,{className:`w-2 h-2 rounded-full ${Wt?`bg-green-400`:`bg-gray-500`}`})]}),(0,K.jsxs)(`button`,{onClick:()=>ge(`spoolbuddy`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${ue===`spoolbuddy`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Hl,{className:`w-4 h-4`}),i(`settings.tabs.spoolbuddy`),Kt>0&&(0,K.jsx)(`span`,{className:`text-xs bg-bambu-dark-tertiary px-1.5 py-0.5 rounded-full`,children:Kt}),(0,K.jsx)(`span`,{className:`w-2 h-2 rounded-full ${qt?`bg-green-400`:`bg-gray-500`}`})]}),(0,K.jsxs)(`button`,{onClick:()=>ge(`failure-detection`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${ue===`failure-detection`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Ul,{className:`w-4 h-4`}),i(`settings.tabs.failureDetection`),(0,K.jsx)(`span`,{className:`w-2 h-2 rounded-full ${Yt?`bg-green-400`:`bg-gray-500`}`})]}),(0,K.jsxs)(`button`,{onClick:()=>ge(`users`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${ue===`users`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Lu,{className:`w-4 h-4`}),i(`settings.tabs.users`),s&&(0,K.jsx)(`span`,{className:`w-2 h-2 rounded-full bg-green-400`})]}),(0,K.jsxs)(`button`,{onClick:()=>ge(`backup`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${ue===`backup`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Vs,{className:`w-4 h-4`}),i(`settings.tabs.backup`),(0,K.jsx)(`span`,{className:`w-2 h-2 rounded-full ${mn?.is_authenticated&&pn?.configured&&pn?.enabled||Ct?.local_backup_enabled?`bg-green-400`:`bg-gray-500`}`})]})]}),(0,K.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[ue===`general`&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`a`,{href:_f(Bt,`app-settings`),target:`_blank`,rel:`noopener noreferrer`,className:`group block mb-4 lg:mb-6 rounded-xl border border-bambu-green/30 bg-gradient-to-br from-bambu-green/15 via-bambu-green/5 to-transparent hover:border-bambu-green/50 hover:from-bambu-green/20 transition-colors`,children:(0,K.jsxs)(`div`,{className:`flex flex-col md:flex-row items-start md:items-center gap-4 p-4 md:p-5`,children:[(0,K.jsx)(`div`,{className:`p-3 rounded-lg bg-bambu-green/20 text-bambu-green flex-shrink-0`,children:Bt===`business`?(0,K.jsx)(Yo,{className:`w-6 h-6`}):(0,K.jsx)(Nc,{className:`w-6 h-6`})}),(0,K.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,K.jsx)(`p`,{className:`text-base font-semibold text-white`,children:Bt===`business`?i(`sponsors.businessTitle`,`Bambuddy for business`):i(`sponsors.sectionTitle`,`Independent & community-funded`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mt-0.5`,children:Bt===`business`?i(`sponsors.businessTagline`,`You're running {{count}} printers. Priority support, commercial licensing and invoicing are available for teams and print farms.`,{count:zt?.length??0}):i(`sponsors.tagline`,`Bambuddy is free and stays that way because people choose to support it. No VC, no cloud lock-in.`)})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 px-4 py-2 rounded-lg bg-bambu-green/20 text-bambu-green group-hover:bg-bambu-green/30 text-sm font-medium whitespace-nowrap self-start md:self-auto`,children:[Bt===`business`?i(`sponsors.businessCta`,`Bambuddy for business`):i(`sponsors.viewSupporters`,`View supporters`),(0,K.jsx)($s,{className:`w-4 h-4`})]})]})}),(0,K.jsxs)(`div`,{className:`flex flex-col lg:flex-row gap-4 lg:gap-6`,children:[(0,K.jsxs)(`div`,{className:`space-y-3 flex-1 lg:max-w-xl`,children:[(0,K.jsxs)(Od,{id:`card-general`,children:[(0,K.jsx)(kd,{children:(0,K.jsx)(`h2`,{className:`text-lg font-semibold text-white`,children:i(`settings.general`)})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:[(0,K.jsx)(Tc,{className:`w-4 h-4 inline mr-1`}),i(`settings.language`)]}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`select`,{value:a.language,onChange:e=>{let t=e.target.value;if(s&&!d(`settings:update`)){o(i(`settings.toast.noPermissionUpdate`),`error`);return}a.changeLanguage(t),Un.mutate({language:t})},className:`w-full px-3 py-2 pr-10 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none appearance-none cursor-pointer`,children:Ot.map(e=>(0,K.jsxs)(`option`,{value:e.code,children:[e.nativeName,` (`,e.name,`)`]},e.code))}),(0,K.jsx)(ls,{className:`absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray pointer-events-none`})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.languageDescription`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.defaultView`)}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`select`,{value:U,onChange:e=>St(e.target.value),className:`w-full px-3 py-2 pr-10 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none appearance-none cursor-pointer`,children:Up.map(e=>(0,K.jsx)(`option`,{value:e.to,children:i(e.labelKey)},e.id))}),(0,K.jsx)(ls,{className:`absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray pointer-events-none`})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.defaultViewDescription`)})]}),(0,K.jsxs)(`div`,{className:`grid grid-cols-2 gap-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.dateFormat`)}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsxs)(`select`,{value:A.date_format||`system`,onChange:e=>Gn(`date_format`,e.target.value),className:`w-full px-3 py-2 pr-10 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none appearance-none cursor-pointer`,children:[(0,K.jsx)(`option`,{value:`system`,children:i(`settings.systemDefault`)}),(0,K.jsx)(`option`,{value:`us`,children:i(`settings.dateFormatUs`)}),(0,K.jsx)(`option`,{value:`eu`,children:i(`settings.dateFormatEu`)}),(0,K.jsx)(`option`,{value:`iso`,children:i(`settings.dateFormatIso`)})]}),(0,K.jsx)(ls,{className:`absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray pointer-events-none`})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.timeFormat`)}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsxs)(`select`,{value:A.time_format||`system`,onChange:e=>Gn(`time_format`,e.target.value),className:`w-full px-3 py-2 pr-10 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none appearance-none cursor-pointer`,children:[(0,K.jsx)(`option`,{value:`system`,children:i(`settings.systemDefault`)}),(0,K.jsx)(`option`,{value:`12h`,children:i(`settings.timeFormat12`)}),(0,K.jsx)(`option`,{value:`24h`,children:i(`settings.timeFormat24`)})]}),(0,K.jsx)(ls,{className:`absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray pointer-events-none`})]})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.defaultPrinter`)}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsxs)(`select`,{value:A.default_printer_id??``,onChange:e=>Gn(`default_printer_id`,e.target.value?Number(e.target.value):null),className:`w-full px-3 py-2 pr-10 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none appearance-none cursor-pointer`,children:[(0,K.jsx)(`option`,{value:``,children:i(`settings.noDefaultPrinter`)}),zt?.map(e=>(0,K.jsx)(`option`,{value:e.id,children:e.name},e.id))]}),(0,K.jsx)(ls,{className:`absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray pointer-events-none`})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.defaultPrinterDescription`)})]})]})]}),(0,K.jsxs)(Od,{id:`card-appearance`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(bl,{className:`w-5 h-5`}),i(`settings.appearance`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 mb-2`,children:[(0,K.jsxs)(`label`,{className:`text-sm text-bambu-gray`,children:[i(`settings.theme`),`:`]}),(0,K.jsx)(`div`,{className:`flex gap-1`,children:[{id:`dark`,label:i(`settings.themeDark`)},{id:`light`,label:i(`settings.themeLight`)},{id:`system`,label:i(`settings.themeSystem`)}].map(({id:e,label:t})=>(0,K.jsx)(`button`,{onClick:()=>{x(e),o(i(`settings.toast.settingsSaved`),`success`)},className:`px-3 py-1 text-xs rounded-lg border transition-colors ${f===e?`border-bambu-green bg-bambu-green/10 text-bambu-green`:`border-gray-300 dark:border-bambu-dark-tertiary text-gray-500 dark:text-bambu-gray hover:text-gray-900 dark:hover:text-white cursor-pointer`}`,children:t},e))})]}),(0,K.jsxs)(`div`,{className:`space-y-3 p-4 rounded-lg border ${p===`dark`?`border-bambu-green bg-bambu-green/5`:`border-bambu-dark-tertiary`}`,children:[(0,K.jsxs)(`h3`,{className:`text-sm font-medium text-white flex items-center gap-2`,children:[i(`settings.darkMode`),p===`dark`&&(0,K.jsx)(`span`,{className:`text-xs text-bambu-green`,children:i(`settings.active`)})]}),(0,K.jsxs)(`div`,{className:`grid grid-cols-3 gap-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.background`)}),(0,K.jsxs)(`select`,{value:h,onChange:e=>{C(e.target.value),o(i(`settings.toast.settingsSaved`),`success`)},className:`w-full px-2 py-1.5 text-sm bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`neutral`,children:i(`settings.bgNeutral`)}),(0,K.jsx)(`option`,{value:`warm`,children:i(`settings.bgWarm`)}),(0,K.jsx)(`option`,{value:`cool`,children:i(`settings.bgCool`)}),(0,K.jsx)(`option`,{value:`oled`,children:i(`settings.bgOled`)}),(0,K.jsx)(`option`,{value:`slate`,children:i(`settings.bgSlate`)}),(0,K.jsx)(`option`,{value:`forest`,children:i(`settings.bgForest`)})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.accent`)}),(0,K.jsxs)(`select`,{value:g,onChange:e=>{w(e.target.value),o(i(`settings.toast.settingsSaved`),`success`)},className:`w-full px-2 py-1.5 text-sm bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`green`,children:i(`settings.accentGreen`)}),(0,K.jsx)(`option`,{value:`teal`,children:i(`settings.accentTeal`)}),(0,K.jsx)(`option`,{value:`blue`,children:i(`settings.accentBlue`)}),(0,K.jsx)(`option`,{value:`orange`,children:i(`settings.accentOrange`)}),(0,K.jsx)(`option`,{value:`purple`,children:i(`settings.accentPurple`)}),(0,K.jsx)(`option`,{value:`red`,children:i(`settings.accentRed`)})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.style`)}),(0,K.jsxs)(`select`,{value:m,onChange:e=>{S(e.target.value),o(i(`settings.toast.settingsSaved`),`success`)},className:`w-full px-2 py-1.5 text-sm bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`classic`,children:i(`settings.styleClassic`)}),(0,K.jsx)(`option`,{value:`glow`,children:i(`settings.styleGlow`)}),(0,K.jsx)(`option`,{value:`vibrant`,children:i(`settings.styleVibrant`)})]})]})]})]}),(0,K.jsxs)(`div`,{className:`space-y-3 p-4 rounded-lg border ${p===`light`?`border-bambu-green bg-bambu-green/5`:`border-bambu-dark-tertiary`}`,children:[(0,K.jsxs)(`h3`,{className:`text-sm font-medium text-white flex items-center gap-2`,children:[i(`settings.lightMode`),p===`light`&&(0,K.jsx)(`span`,{className:`text-xs text-bambu-green`,children:i(`settings.active`)})]}),(0,K.jsxs)(`div`,{className:`grid grid-cols-3 gap-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.background`)}),(0,K.jsxs)(`select`,{value:v,onChange:e=>{E(e.target.value),o(i(`settings.toast.settingsSaved`),`success`)},className:`w-full px-2 py-1.5 text-sm bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`neutral`,children:i(`settings.bgNeutral`)}),(0,K.jsx)(`option`,{value:`warm`,children:i(`settings.bgWarm`)}),(0,K.jsx)(`option`,{value:`cool`,children:i(`settings.bgCool`)})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.accent`)}),(0,K.jsxs)(`select`,{value:b,onChange:e=>{D(e.target.value),o(i(`settings.toast.settingsSaved`),`success`)},className:`w-full px-2 py-1.5 text-sm bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`green`,children:i(`settings.accentGreen`)}),(0,K.jsx)(`option`,{value:`teal`,children:i(`settings.accentTeal`)}),(0,K.jsx)(`option`,{value:`blue`,children:i(`settings.accentBlue`)}),(0,K.jsx)(`option`,{value:`orange`,children:i(`settings.accentOrange`)}),(0,K.jsx)(`option`,{value:`purple`,children:i(`settings.accentPurple`)}),(0,K.jsx)(`option`,{value:`red`,children:i(`settings.accentRed`)})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.style`)}),(0,K.jsxs)(`select`,{value:_,onChange:e=>{T(e.target.value),o(i(`settings.toast.settingsSaved`),`success`)},className:`w-full px-2 py-1.5 text-sm bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`classic`,children:i(`settings.styleClassic`)}),(0,K.jsx)(`option`,{value:`glow`,children:i(`settings.styleGlow`)}),(0,K.jsx)(`option`,{value:`vibrant`,children:i(`settings.styleVibrant`)})]})]})]})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.themeToggleHint`)}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between pt-2 border-t border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.progressInTitle`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.progressInTitleDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:O,onChange:e=>{k(e.target.checked),o(i(`settings.toast.settingsSaved`),`success`)},className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]})]})]}),(0,K.jsxs)(Od,{id:`card-archive`,children:[(0,K.jsx)(kd,{children:(0,K.jsx)(`h2`,{className:`text-lg font-semibold text-white`,children:i(`settings.archiveSettings`)})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.autoArchivePrints`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.autoArchiveDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.auto_archive,onChange:e=>Gn(`auto_archive`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.saveThumbnails`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.saveThumbnailsDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.save_thumbnails,onChange:e=>Gn(`save_thumbnails`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.captureFinishPhoto`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.captureFinishPhotoDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.capture_finish_photo,onChange:e=>Gn(`capture_finish_photo`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),A.capture_finish_photo&&(0,K.jsxs)(`div`,{className:`flex items-center justify-between pl-4 border-l-2 border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.finishPhotoRestorePlate`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.finishPhotoRestorePlateDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.finish_photo_restore_plate??!0,onChange:e=>Gn(`finish_photo_restore_plate`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),A.capture_finish_photo&&Xt&&!Xt.installed&&(0,K.jsxs)(`div`,{className:`flex items-start gap-2 p-3 bg-yellow-500/10 border border-yellow-500/30 rounded-lg`,children:[(0,K.jsx)(ju,{className:`w-5 h-5 text-yellow-500 flex-shrink-0 mt-0.5`}),(0,K.jsxs)(`div`,{className:`text-sm`,children:[(0,K.jsx)(`p`,{className:`text-yellow-500 font-medium`,children:i(`settings.ffmpegNotInstalled`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray mt-1`,children:i(`settings.ffmpegRequired`)})]})]}),nn&&rn&&(0,K.jsxs)(`div`,{className:`border-t border-bambu-dark-tertiary pt-3 mt-3 space-y-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`archiveAutoPurge.enableLabel`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`archiveAutoPurge.enableDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:rn.enabled,onChange:e=>on({enabled:e.target.checked}),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`archiveAutoPurge.ageLabel`)}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`input`,{type:`number`,min:7,max:3650,disabled:!rn.enabled,value:rn.days,onChange:e=>on({days:Math.max(7,Math.min(3650,parseInt(e.target.value||`0`,10)||0))}),className:`w-24 px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none disabled:opacity-50`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:i(`archiveAutoPurge.days`)})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`archiveAutoPurge.ageDescription`)})]}),(0,K.jsxs)(`label`,{className:`flex items-start gap-2 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,disabled:!rn.enabled,checked:rn.purge_stats,onChange:e=>on({purge_stats:e.target.checked}),className:`mt-0.5 shrink-0 disabled:opacity-50`}),(0,K.jsxs)(`span`,{className:`text-sm`,children:[(0,K.jsx)(`span`,{className:`text-white block`,children:i(`archiveAutoPurge.purgeStatsLabel`)}),(0,K.jsx)(`span`,{className:`text-xs text-bambu-gray block mt-0.5`,children:i(`archiveAutoPurge.purgeStatsDescription`)})]})]})]})]})]})]}),(0,K.jsxs)(`div`,{className:`space-y-3 flex-1 lg:max-w-md`,children:[(0,K.jsxs)(Od,{id:`card-camera`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(zu,{className:`w-5 h-5 text-bambu-green`}),i(`settings.camera`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.cameraViewMode`)}),(0,K.jsxs)(`select`,{value:A.camera_view_mode??`window`,onChange:e=>Gn(`camera_view_mode`,e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`window`,children:i(`settings.newWindow`)}),(0,K.jsx)(`option`,{value:`embedded`,children:i(`settings.embeddedOverlay`)})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:A.camera_view_mode===`embedded`?i(`settings.cameraOverlayDescription`):i(`settings.cameraWindowDescription`)})]}),(0,K.jsxs)(`div`,{className:`border-t border-bambu-dark-tertiary pt-4 mt-4`,children:[(0,K.jsx)(`h3`,{className:`text-sm font-medium text-white mb-2`,children:i(`settings.externalCameras`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mb-3`,children:i(`settings.externalCamerasDescription`)}),zt&&zt.length>0?(0,K.jsx)(`div`,{className:`space-y-3`,children:zt.map(e=>(0,K.jsxs)(`div`,{className:`p-3 bg-bambu-dark rounded-lg`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between mb-2`,children:[(0,K.jsx)(`span`,{className:`text-white font-medium text-sm`,children:e.name}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:e.external_camera_enabled,onChange:t=>rr(e.id,{enabled:t.target.checked}),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-9 h-5 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-bambu-green`})]})]}),e.external_camera_enabled&&(0,K.jsxs)(`div`,{className:`space-y-2 mt-2`,children:[(0,K.jsx)(`input`,{type:`text`,placeholder:e.external_camera_type===`usb`?i(`settings.cameraPlaceholderUsb`):i(`settings.cameraPlaceholderUrl`),value:qn[e.id]??e.external_camera_url??``,onChange:t=>tr(e.id,t.target.value),className:`w-full px-3 py-2 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded text-white text-sm focus:border-bambu-green focus:outline-none`}),(0,K.jsxs)(`div`,{className:`flex gap-2`,children:[(0,K.jsxs)(`select`,{value:e.external_camera_type||`mjpeg`,onChange:t=>rr(e.id,{type:t.target.value}),className:`flex-1 px-3 py-2 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded text-white text-sm focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`mjpeg`,children:i(`settings.cameraTypeMjpeg`)}),(0,K.jsx)(`option`,{value:`rtsp`,children:i(`settings.cameraTypeRtsp`)}),(0,K.jsx)(`option`,{value:`snapshot`,children:i(`settings.cameraTypeSnapshot`)}),(0,K.jsx)(`option`,{value:`usb`,children:i(`settings.cameraTypeUsb`)})]}),(0,K.jsx)($,{size:`sm`,variant:`secondary`,onClick:()=>Kn(e.id,qn[e.id]??e.external_camera_url??``,e.external_camera_type||`mjpeg`),disabled:bt[e.id]||!(qn[e.id]??e.external_camera_url),children:bt[e.id]?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):i(`settings.test`)})]}),vt[e.id]&&(0,K.jsx)(`div`,{className:`text-xs flex items-center gap-1 ${vt[e.id]?.success?`text-green-500`:`text-red-500`}`,children:vt[e.id]?.success?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(_s,{className:`w-3 h-3`}),i(`settings.connected`),vt[e.id]?.resolution&&` (${vt[e.id]?.resolution})`]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(Cs,{className:`w-3 h-3`}),vt[e.id]?.error||i(`settings.toast.connectionFailed`)]})}),(e.external_camera_type===`mjpeg`||e.external_camera_type===`rtsp`||e.external_camera_type===`usb`)&&(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsx)(`label`,{className:`text-xs text-bambu-gray`,children:i(`settings.cameraSnapshotUrl`,`Snapshot URL (optional)`)}),(0,K.jsxs)(`div`,{className:`flex gap-2`,children:[(0,K.jsx)(`input`,{type:`text`,placeholder:i(`settings.cameraSnapshotUrlPlaceholder`,`http://192.168.1.61:1984/api/frame.jpeg?src=printer`),value:Zn[e.id]??e.external_camera_snapshot_url??``,onChange:t=>nr(e.id,t.target.value),className:`flex-1 px-3 py-2 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded text-white text-sm focus:border-bambu-green focus:outline-none`}),(0,K.jsx)($,{size:`sm`,variant:`secondary`,onClick:()=>Kn(e.id,Zn[e.id]??e.external_camera_snapshot_url??``,`snapshot`),disabled:bt[e.id]||!(Zn[e.id]??e.external_camera_snapshot_url),children:bt[e.id]?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):i(`settings.test`)})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray opacity-75`,children:i(`settings.cameraSnapshotUrlHelp`,`Single-frame URL used for notification thumbnails, finish photos, timelapse and plate detection. Leave blank to capture from the live stream above. Useful for go2rtc (/api/frame.jpeg) and IP cameras with a dedicated snapshot endpoint.`)})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`label`,{className:`text-xs text-bambu-gray`,children:i(`settings.cameraRotation`)}),(0,K.jsxs)(`select`,{value:e.camera_rotation||0,onChange:t=>rr(e.id,{rotation:parseInt(t.target.value)}),className:`px-2 py-1 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded text-white text-xs focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:0,children:`0°`}),(0,K.jsx)(`option`,{value:90,children:`90°`}),(0,K.jsx)(`option`,{value:180,children:`180°`}),(0,K.jsx)(`option`,{value:270,children:`270°`})]})]})]})]},e.id))}):(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray italic`,children:i(`settings.noPrintersConfigured`)})]})]})]}),(0,K.jsxs)(Od,{id:`card-cost`,children:[(0,K.jsx)(kd,{children:(0,K.jsx)(`h2`,{className:`text-lg font-semibold text-white`,children:i(`settings.costTracking`)})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.currency`)}),(0,K.jsx)(`select`,{value:A.currency,onChange:e=>Gn(`currency`,e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:hf.map(e=>(0,K.jsx)(`option`,{value:e.code,children:e.label},e.code))})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.defaultFilamentCost`)}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`span`,{className:`absolute left-3 top-1/2 -translate-y-1/2 text-bambu-gray text-sm pointer-events-none`,children:mf(A.currency)}),(0,K.jsx)(`input`,{type:`number`,step:`0.01`,min:`0`,value:A.default_filament_cost,onChange:e=>Gn(`default_filament_cost`,parseFloat(e.target.value)||0),style:{paddingLeft:`${Math.max(2,mf(A.currency).length*.6+1)}rem`},className:`w-full pr-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.electricityCost`)}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`span`,{className:`absolute left-3 top-1/2 -translate-y-1/2 text-bambu-gray text-sm pointer-events-none`,children:mf(A.currency)}),(0,K.jsx)(`input`,{type:`number`,step:`0.001`,min:`0`,value:A.energy_cost_per_kwh,onChange:e=>Gn(`energy_cost_per_kwh`,parseFloat(e.target.value)||0),style:{paddingLeft:`${Math.max(2,mf(A.currency).length*.6+1)}rem`},className:`w-full pr-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.energyDisplayMode`)}),(0,K.jsxs)(`select`,{value:A.energy_tracking_mode||`total`,onChange:e=>Gn(`energy_tracking_mode`,e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`print`,children:i(`settings.printsOnly`)}),(0,K.jsx)(`option`,{value:`total`,children:i(`settings.totalConsumption`)})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:A.energy_tracking_mode===`print`?i(`settings.energyModePrintDescription`):i(`settings.energyModeTotalDescription`)})]})]})]}),(0,K.jsxs)(Od,{id:`card-filemanager`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(sc,{className:`w-5 h-5 text-bambu-green`}),i(`settings.fileManager`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.createArchiveEntry`)}),(0,K.jsxs)(`select`,{value:A.library_archive_mode??`ask`,onChange:e=>Gn(`library_archive_mode`,e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`always`,children:i(`settings.archiveMode.always`)}),(0,K.jsx)(`option`,{value:`never`,children:i(`settings.archiveMode.never`)}),(0,K.jsx)(`option`,{value:`ask`,children:i(`settings.archiveMode.ask`)})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.createArchiveEntryDescription`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.lowDiskSpaceWarning`)}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`input`,{type:`number`,min:`0.5`,max:`100`,step:`0.5`,value:A.library_disk_warning_gb??5,onChange:e=>Gn(`library_disk_warning_gb`,parseFloat(e.target.value)||5),className:`w-24 px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:`GB`})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.lowDiskSpaceDescription`)})]}),Qt&&$t&&(0,K.jsxs)(`div`,{className:`border-t border-bambu-dark-tertiary pt-3 mt-3 space-y-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`libraryAutoPurge.enableLabel`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`libraryAutoPurge.enableDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:$t.auto_purge_enabled,onChange:e=>tn({auto_purge_enabled:e.target.checked}),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`libraryAutoPurge.ageLabel`)}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`input`,{type:`number`,min:7,max:3650,disabled:!$t.auto_purge_enabled,value:$t.auto_purge_days,onChange:e=>tn({auto_purge_days:Math.max(7,Math.min(3650,parseInt(e.target.value||`0`,10)||0))}),className:`w-24 px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none disabled:opacity-50`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:i(`libraryAutoPurge.days`)})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`libraryAutoPurge.ageDescription`)})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-2 text-sm text-white cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,disabled:!$t.auto_purge_enabled,checked:$t.auto_purge_include_never_printed,onChange:e=>tn({auto_purge_include_never_printed:e.target.checked}),className:`rounded border-gray-300 disabled:opacity-50`}),i(`libraryAutoPurge.includeNeverPrinted`)]})]})]})]}),(0,K.jsxs)(Od,{id:`card-data`,children:[(0,K.jsx)(kd,{children:(0,K.jsx)(`h2`,{className:`text-lg font-semibold text-white`,children:i(`settings.dataManagement`)})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.clearNotificationLogs`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.clearNotificationLogsDescription`)})]}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,onClick:()=>Ne(!0),children:[(0,K.jsx)(Ou,{className:`w-4 h-4`}),i(`common.clear`)]})]}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.resetUiPreferences`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.resetUiPreferencesDescription`)})]}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,onClick:()=>Fe(!0),children:[(0,K.jsx)(Ou,{className:`w-4 h-4`}),i(`settings.reset`)]})]}),(0,K.jsxs)(`div`,{className:`pt-4 border-t border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.storageUsage`,`Storage Usage`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.storageUsageDescription`,`Breakdown of data usage by category`)})]}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,onClick:kt,disabled:Dt||Je,children:[(0,K.jsx)(Il,{className:`w-4 h-4 ${Dt||Je?`animate-spin`:``}`}),i(`common.refresh`,`Refresh`)]})]}),(0,K.jsx)(`div`,{className:`mt-3`,children:Et?(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-sm text-bambu-gray`,children:[(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}),i(`common.loading`,`Loading`)]}):Tt?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`div`,{className:`w-full h-3 bg-bambu-dark rounded-full overflow-hidden flex`,children:Tt.categories.filter(e=>e.bytes>0).map((e,t)=>(0,K.jsx)(`div`,{className:`${D6(e.key,t)} h-full`,style:{width:`${e.percent_of_total}%`},title:`${e.label}: ${e.formatted}`},e.key))}),(0,K.jsx)(`div`,{className:`mt-3 flex flex-wrap gap-3`,children:Tt.categories.filter(e=>e.bytes>0).map((e,t)=>(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-xs`,children:[(0,K.jsx)(`span`,{className:`w-3 h-3 rounded-full ${D6(e.key,t)}`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:e.label}),(0,K.jsx)(`span`,{className:`text-white`,children:e.formatted}),(0,K.jsxs)(`span`,{className:`text-bambu-gray`,children:[`(`,e.percent_of_total.toFixed(1),`%)`]})]},e.key))}),(0,K.jsxs)(`div`,{className:`mt-2 text-xs text-bambu-gray`,children:[i(`settings.storageUsageTotal`,`Total`),`: `,(0,K.jsx)(`span`,{className:`text-white`,children:Tt.total_formatted}),Tt.scan_errors>0&&(0,K.jsxs)(`span`,{className:`ml-2 text-amber-700 dark:text-amber-400`,children:[i(`settings.storageUsageErrors`,`Scan errors`),`: `,Tt.scan_errors]})]}),Tt.other_breakdown?.length>0&&(0,K.jsxs)(`div`,{className:`mt-4`,children:[(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mb-2`,children:i(`settings.storageUsageOtherBreakdown`,`Other breakdown`)}),(0,K.jsx)(`div`,{className:`space-y-2`,children:Tt.other_breakdown.map(e=>(0,K.jsxs)(`div`,{className:`flex items-center justify-between text-xs`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`span`,{className:`text-white`,children:e.label}),(0,K.jsx)(`span`,{className:`px-2 py-0.5 rounded-full border ${e.kind===`system`?`border-slate-500 text-slate-300`:`border-bambu-green text-bambu-green`}`,children:e.kind===`system`?i(`settings.storageUsageSystem`,`System`):i(`settings.storageUsageData`,`Data`)})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-bambu-gray`,children:[(0,K.jsx)(`span`,{className:`text-white`,children:e.formatted}),(0,K.jsxs)(`span`,{children:[`(`,e.percent_of_total.toFixed(1),`%)`]})]})]},`${e.bucket}-${e.kind}`))})]})]}):(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.storageUsageUnavailable`,`Storage usage data is unavailable`)})})]}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between pt-4 border-t border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.backupRestore`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.backupRestoreDescription`)})]}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,onClick:()=>ge(`backup`),children:[(0,K.jsx)(Vs,{className:`w-4 h-4`}),i(`settings.goToBackup`)]})]})]})]})]}),(0,K.jsxs)(`div`,{className:`space-y-3 flex-1 lg:max-w-sm`,children:[(0,K.jsxs)(Od,{id:`card-updates`,children:[(0,K.jsx)(kd,{children:(0,K.jsx)(`h2`,{className:`text-lg font-semibold text-white`,children:i(`settings.updates`)})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-xs font-medium text-bambu-gray uppercase tracking-wider`,children:i(`settings.printerFirmware`)}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.checkPrinterFirmware`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.checkFirmwareDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.check_printer_firmware??!0,onChange:e=>Gn(`check_printer_firmware`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),(0,K.jsx)(`div`,{className:`border-t border-bambu-dark-tertiary pt-4`,children:(0,K.jsx)(`p`,{className:`text-xs font-medium text-bambu-gray uppercase tracking-wider mb-4`,children:i(`settings.bambuddySoftware`)})}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.checkForUpdatesLabel`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.autoCheckDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.check_updates,onChange:e=>Gn(`check_updates`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between ${A.check_updates?``:`opacity-50`}`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.includeBetaUpdates`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.includeBetaUpdatesDesc`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.include_beta_updates??!1,onChange:e=>Gn(`include_beta_updates`,e.target.checked),disabled:!A.check_updates,className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between mb-2`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.currentVersion`)}),(0,K.jsxs)(`p`,{className:`text-sm text-bambu-gray`,children:[`v`,Zt?.version||`...`]})]}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,onClick:()=>cn(),disabled:ln,children:[ln?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(Il,{className:`w-4 h-4`}),i(`settings.checkNow`)]})]}),sn?.update_available?(0,K.jsxs)(`div`,{className:`mt-4 p-3 bg-bambu-green/10 border border-bambu-green/30 rounded-lg`,children:[(0,K.jsxs)(`div`,{className:`flex items-start justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`p`,{className:`text-bambu-green font-medium`,children:[`Update available: v`,sn.latest_version]}),sn.release_name&&sn.release_name!==sn.latest_version&&(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mt-1`,children:sn.release_name})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[sn.release_notes&&(0,K.jsx)(`button`,{onClick:()=>ze(!0),className:`text-bambu-gray hover:text-white transition-colors text-sm underline`,children:i(`settings.releaseNotes`)}),sn.release_url&&(0,K.jsx)(`a`,{href:sn.release_url,target:`_blank`,rel:`noopener noreferrer`,className:`text-bambu-gray hover:text-white transition-colors`,title:i(`settings.viewReleaseOnGitHub`),children:(0,K.jsx)($s,{className:`w-4 h-4`})})]})]}),un?.status===`downloading`||un?.status===`installing`?(0,K.jsxs)(`div`,{className:`mt-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-sm text-bambu-gray`,children:[(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}),(0,K.jsx)(`span`,{children:un.message})]}),(0,K.jsx)(`div`,{className:`mt-2 w-full bg-bambu-dark-tertiary rounded-full h-2`,children:(0,K.jsx)(`div`,{className:`bg-bambu-green h-2 rounded-full transition-all duration-300`,style:{width:`${un.progress}%`}})})]}):un?.status===`complete`?(0,K.jsx)(`div`,{className:`mt-3 p-2 bg-bambu-green/20 rounded text-sm text-bambu-green`,children:un.message}):un?.status===`error`?(0,K.jsx)(`div`,{className:`mt-3 p-2 bg-red-100 dark:bg-red-500/20 rounded text-sm text-red-700 dark:text-red-400`,children:un.error||un.message}):sn?.is_ha_addon?(0,K.jsx)(`div`,{className:`mt-3 p-3 bg-bambu-dark-tertiary rounded-lg`,children:(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.updateViaHomeAssistant`)})}):sn?.is_docker?(0,K.jsxs)(`div`,{className:`mt-3 p-3 bg-bambu-dark-tertiary rounded-lg`,children:[(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mb-2`,children:i(`settings.updateViaDocker`)}),(0,K.jsx)(`code`,{className:`block text-xs bg-bambu-dark p-2 rounded text-bambu-green font-mono`,children:`docker compose pull && docker compose up -d`})]}):sn?.update_method===`windows_installer`?(0,K.jsxs)(`div`,{className:`mt-3 p-3 bg-bambu-dark-tertiary rounded-lg`,children:[(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mb-3`,children:i(`settings.updateViaWindowsInstaller`)}),(0,K.jsxs)(`a`,{href:sn.installer_download_url||sn.release_url||`https://github.com/maziggy/bambuddy/releases/tag/v${sn.latest_version}`,target:`_blank`,rel:`noopener noreferrer`,className:`inline-flex items-center justify-center font-medium rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-bambu-dark disabled:opacity-50 bg-bambu-green hover:bg-bambu-green-light text-white focus:ring-bambu-green px-4 py-2 text-sm gap-2 min-h-[44px] md:min-h-0`,children:[(0,K.jsx)(Ks,{className:`w-4 h-4`}),i(`settings.downloadWindowsInstaller`,{version:sn.latest_version})]})]}):(0,K.jsxs)($,{className:`mt-3`,onClick:()=>Nn.mutate(),disabled:Nn.isPending,children:[Nn.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(Ks,{className:`w-4 h-4`}),i(`settings.installUpdate`)]})]}):sn?.error?(0,K.jsx)(`div`,{className:`mt-2 p-2 bg-red-50 dark:bg-red-500/10 border border-red-300 dark:border-red-500/30 rounded text-sm text-red-700 dark:text-red-400`,children:i(`settings.failedToCheckUpdates`,{error:sn.error})}):sn&&!sn.update_available?(0,K.jsx)(`p`,{className:`mt-2 text-sm text-bambu-gray`,children:i(`settings.latestVersionRunning`)}):null]})]})]}),(0,K.jsx)(DUe,{})]})]})]}),ue===`network`&&A&&(0,K.jsxs)(`div`,{className:`flex flex-col lg:flex-row gap-6`,children:[(0,K.jsxs)(`div`,{className:`flex-1 lg:max-w-xl space-y-3`,children:[(0,K.jsxs)(Od,{id:`card-externalurl`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(Tc,{className:`w-5 h-5 text-blue-600 dark:text-blue-400`}),i(`settings.externalUrl`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.externalUrlDescription`)}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.bambuddyUrl`)}),(0,K.jsx)(`input`,{type:`text`,value:A.external_url??``,onChange:e=>Gn(`external_url`,e.target.value),placeholder:`http://192.168.1.100:8000`,className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.externalUrlHint`)})]})]})]}),(0,K.jsxs)(Od,{id:`card-ftpretry`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(Il,{className:`w-5 h-5 text-blue-600 dark:text-blue-400`}),i(`settings.ftpRetry`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.ftpRetryDescription`)}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.enableRetry`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.autoRetryDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.ftp_retry_enabled??!0,onChange:e=>Gn(`ftp_retry_enabled`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),A.ftp_retry_enabled&&(0,K.jsxs)(`div`,{className:`space-y-3 pt-2 border-t border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.retryAttempts`)}),(0,K.jsxs)(`div`,{className:`relative w-44`,children:[(0,K.jsx)(`select`,{value:A.ftp_retry_count??3,onChange:e=>Gn(`ftp_retry_count`,parseInt(e.target.value)),className:`w-full px-3 py-2 pr-10 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none appearance-none cursor-pointer`,children:[1,2,3,4,5,6,7,8,9,10].map(e=>(0,K.jsx)(`option`,{value:e,children:i(`settings.time`,{count:e})},e))}),(0,K.jsx)(ls,{className:`absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray pointer-events-none`})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.retryDelay`)}),(0,K.jsxs)(`div`,{className:`relative w-44`,children:[(0,K.jsx)(`select`,{value:A.ftp_retry_delay??2,onChange:e=>Gn(`ftp_retry_delay`,parseInt(e.target.value)),className:`w-full px-3 py-2 pr-10 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none appearance-none cursor-pointer`,children:[1,2,3,5,10,15,20,30].map(e=>(0,K.jsx)(`option`,{value:e,children:i(`settings.second`,{count:e})},e))}),(0,K.jsx)(ls,{className:`absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray pointer-events-none`})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.connectionTimeout`)}),(0,K.jsxs)(`div`,{className:`relative w-44`,children:[(0,K.jsx)(`select`,{value:A.ftp_timeout??30,onChange:e=>Gn(`ftp_timeout`,parseInt(e.target.value)),className:`w-full px-3 py-2 pr-10 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none appearance-none cursor-pointer`,children:[10,15,20,30,45,60,90,120,180,300].map(e=>(0,K.jsx)(`option`,{value:e,children:i(`settings.nSeconds`,{count:e})},e))}),(0,K.jsx)(ls,{className:`absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray pointer-events-none`})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.increaseForWeakWifi`)})]})]})]})]})]}),(0,K.jsxs)(`div`,{className:`flex-1 lg:max-w-xl space-y-3`,children:[(0,K.jsxs)(Od,{id:`card-ha`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(Fc,{className:`w-5 h-5 text-bambu-green`}),i(`settings.homeAssistant`)]}),A.ha_enabled&&mt&&(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`span`,{className:`w-2.5 h-2.5 rounded-full ${mt.success?`bg-green-400`:`bg-red-400`}`}),(0,K.jsx)(`span`,{className:`text-sm ${mt.success?`text-green-700 dark:text-green-400`:`text-red-700 dark:text-red-400`}`,children:mt.success?i(`settings.connected`):i(`settings.disconnected`)})]})]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.homeAssistantFullDescription`)}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex-1`,children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.enableHomeAssistant`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.homeAssistantDescription`)}),A.ha_env_managed&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1 mt-1`,children:[(0,K.jsx)(Qc,{className:`w-3 h-3 text-bambu-green`}),(0,K.jsx)(`span`,{className:`text-xs text-bambu-green`,children:i(`settings.autoEnabledViaEnv`)})]})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.ha_enabled??!1,onChange:e=>Gn(`ha_enabled`,e.target.checked),disabled:A.ha_env_managed,className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green ${A.ha_env_managed?`opacity-60 cursor-not-allowed`:``}`})]})]}),A.ha_enabled&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:[i(`settings.homeAssistantUrl`),A.ha_url_from_env&&(0,K.jsx)(`span`,{className:`ml-2 text-xs text-bambu-green`,children:i(`settings.environmentManagedLabel`)})]}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`input`,{type:`text`,value:A.ha_url??``,onChange:e=>Gn(`ha_url`,e.target.value),placeholder:`http://192.168.1.100:8123`,disabled:A.ha_url_from_env,className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none ${A.ha_url_from_env?`opacity-60 cursor-not-allowed`:``}`}),A.ha_url_from_env&&(0,K.jsx)(Qc,{className:`absolute right-3 top-2.5 w-4 h-4 text-bambu-gray`})]}),A.ha_url_from_env&&(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.urlFromEnvReadOnly`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:[i(`settings.longLivedAccessToken`),A.ha_token_from_env&&(0,K.jsx)(`span`,{className:`ml-2 text-xs text-bambu-green`,children:i(`settings.environmentManagedLabel`)})]}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`input`,{type:`password`,value:A.ha_token??``,onChange:e=>Gn(`ha_token`,e.target.value),placeholder:`eyJ0eXAiOiJKV1QiLC...`,disabled:A.ha_token_from_env,className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none ${A.ha_token_from_env?`opacity-60 cursor-not-allowed`:``}`}),A.ha_token_from_env&&(0,K.jsx)(Qc,{className:`absolute right-3 top-2.5 w-4 h-4 text-bambu-gray`})]}),A.ha_token_from_env?(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.tokenFromEnvReadOnly`)}):(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.haTokenHint`)})]}),A.ha_url&&A.ha_token&&(0,K.jsx)(`div`,{className:`pt-2 border-t border-bambu-dark-tertiary`,children:(0,K.jsxs)($,{variant:`secondary`,size:`sm`,disabled:gt,onClick:async()=>{_t(!0),ht(null);try{ht(await Q.testHAConnection(A.ha_url,A.ha_token))}catch(e){ht({success:!1,message:null,error:e instanceof Error?e.message:i(`common.unknownError`)})}finally{_t(!1)}},children:[gt?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(Gu,{className:`w-4 h-4`}),i(`settings.testConnection`)]})})]})]})]}),(0,K.jsxs)(Od,{id:`card-mqtt`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(Gu,{className:`w-5 h-5 text-blue-600 dark:text-blue-400`}),i(`settings.mqttPublishing`)]}),fn?.enabled&&(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`span`,{className:`w-2.5 h-2.5 rounded-full ${fn.connected?`bg-green-400`:`bg-red-400`}`}),(0,K.jsx)(`span`,{className:`text-sm ${fn.connected?`text-green-700 dark:text-green-400`:`text-red-700 dark:text-red-400`}`,children:fn.connected?i(`settings.connected`):i(`settings.disconnected`)})]})]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.mqttDescription`)}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.enableMqtt`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.mqttEnableDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.mqtt_enabled??!1,onChange:e=>Gn(`mqtt_enabled`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),A.mqtt_enabled&&(0,K.jsxs)(`div`,{className:`space-y-3 pt-2 border-t border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.brokerHostname`)}),(0,K.jsx)(`input`,{type:`text`,value:A.mqtt_broker??``,onChange:e=>Gn(`mqtt_broker`,e.target.value),placeholder:`mqtt.example.com or 192.168.1.100`,className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`})]}),(0,K.jsxs)(`div`,{className:`flex items-end gap-4`,children:[(0,K.jsxs)(`div`,{className:`flex-1`,children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.port`)}),(0,K.jsx)(`input`,{type:`number`,min:`1`,max:`65535`,value:A.mqtt_port??1883,onChange:e=>Gn(`mqtt_port`,Math.min(65535,Math.max(1,parseInt(e.target.value)||1883))),className:`w-24 px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-3 pb-2`,children:[(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.mqtt_use_tls??!1,onChange:e=>{let t=e.target.checked;Gn(`mqtt_use_tls`,t);let n=A.mqtt_port??1883;t&&n===1883?Gn(`mqtt_port`,8883):!t&&n===8883&&Gn(`mqtt_port`,1883)},className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]}),(0,K.jsx)(`span`,{className:`text-white text-sm`,children:i(`settings.useTls`)})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.usernameOptional`)}),(0,K.jsx)(`input`,{type:`text`,value:A.mqtt_username??``,onChange:e=>Gn(`mqtt_username`,e.target.value),placeholder:i(`settings.leaveEmptyForAnonymous`),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.passwordOptional`)}),(0,K.jsx)(`input`,{type:`password`,value:A.mqtt_password??``,onChange:e=>Gn(`mqtt_password`,e.target.value),placeholder:i(`settings.leaveEmptyForAnonymous`),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.topicPrefix`)}),(0,K.jsx)(`input`,{type:`text`,value:A.mqtt_topic_prefix??`bambuddy`,onChange:e=>Gn(`mqtt_topic_prefix`,e.target.value),placeholder:`bambuddy`,className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.topicPrefixHint`,{prefix:A.mqtt_topic_prefix||`bambuddy`})})]}),fn&&(0,K.jsx)(`div`,{className:`pt-3 mt-3 border-t border-bambu-dark-tertiary`,children:(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-sm`,children:[(0,K.jsx)(`span`,{className:`w-2 h-2 rounded-full ${fn.connected?`bg-green-400`:`bg-red-400`}`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:fn.connected?(0,K.jsxs)(K.Fragment,{children:[i(`settings.mqttConnectedTo`),` `,(0,K.jsxs)(`span`,{className:`text-white`,children:[fn.broker,`:`,fn.port]})]}):i(`settings.spoolmanDisconnected`)})]})})]})]})]})]}),(0,K.jsx)(`div`,{className:`flex-1 lg:max-w-md space-y-3`,children:(0,K.jsxs)(Od,{id:`card-prometheus`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(Au,{className:`w-5 h-5 text-orange-600 dark:text-orange-400`}),i(`settings.prometheusMetrics`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.prometheusEndpointDescription`)}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.enableMetricsEndpoint`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.prometheusDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.prometheus_enabled??!1,onChange:e=>Gn(`prometheus_enabled`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),A.prometheus_enabled&&(0,K.jsxs)(`div`,{className:`space-y-3 pt-2 border-t border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.bearerTokenOptional`)}),(0,K.jsx)(`input`,{type:`password`,value:A.prometheus_token??``,onChange:e=>Gn(`prometheus_token`,e.target.value),placeholder:i(`settings.leaveEmptyForNoAuth`),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.bearerTokenHint`)})]}),(0,K.jsxs)(`div`,{className:`pt-2 border-t border-bambu-dark-tertiary`,children:[(0,K.jsx)(`p`,{className:`text-sm text-white mb-2`,children:i(`settings.availableMetrics`)}),(0,K.jsxs)(`div`,{className:`text-xs text-bambu-gray space-y-1`,children:[(0,K.jsxs)(`p`,{children:[(0,K.jsx)(`code`,{className:`text-orange-700 dark:text-orange-400`,children:`bambuddy_printer_connected`}),` - `,i(`settings.metricsConnectionStatus`)]}),(0,K.jsxs)(`p`,{children:[(0,K.jsx)(`code`,{className:`text-orange-700 dark:text-orange-400`,children:`bambuddy_printer_state`}),` - `,i(`settings.metricsPrinterState`)]}),(0,K.jsxs)(`p`,{children:[(0,K.jsx)(`code`,{className:`text-orange-700 dark:text-orange-400`,children:`bambuddy_print_progress`}),` - `,i(`settings.metricsPrintProgress`)]}),(0,K.jsxs)(`p`,{children:[(0,K.jsx)(`code`,{className:`text-orange-700 dark:text-orange-400`,children:`bambuddy_bed_temp_celsius`}),` - `,i(`settings.metricsBedTemp`)]}),(0,K.jsxs)(`p`,{children:[(0,K.jsx)(`code`,{className:`text-orange-700 dark:text-orange-400`,children:`bambuddy_nozzle_temp_celsius`}),` - `,i(`settings.metricsNozzleTemp`)]}),(0,K.jsxs)(`p`,{children:[(0,K.jsx)(`code`,{className:`text-orange-700 dark:text-orange-400`,children:`bambuddy_prints_total`}),` - `,i(`settings.metricsPrintsTotal`)]}),(0,K.jsx)(`p`,{className:`text-bambu-gray/70 italic`,children:i(`settings.metricsMore`)})]})]})]})]})]})})]}),mt&&(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/50 flex items-center justify-center z-50`,children:(0,K.jsxs)(`div`,{className:`bg-bambu-dark-secondary rounded-lg p-6 max-w-md w-full mx-4`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-3 mb-4`,children:[mt.success?(0,K.jsx)(_s,{className:`w-8 h-8 text-green-600 dark:text-green-400`}):(0,K.jsx)(Cs,{className:`w-8 h-8 text-red-600 dark:text-red-400`}),(0,K.jsx)(`h3`,{className:`text-lg font-medium text-white`,children:mt.success?i(`settings.connectionSuccessful`):i(`settings.connectionFailed`)})]}),(0,K.jsx)(`p`,{className:`text-bambu-gray mb-6`,children:mt.success?mt.message||i(`settings.haConnectionSuccess`):mt.error||i(`settings.haConnectionFailed`)}),(0,K.jsx)(`div`,{className:`flex justify-end`,children:(0,K.jsx)($,{variant:`primary`,onClick:()=>ht(null),children:i(`settings.ok`)})})]})}),ue===`plugs`&&(0,K.jsxs)(`div`,{id:`card-plugs`,children:[(0,K.jsxs)(`div`,{className:`flex items-start justify-between mb-6`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(kl,{className:`w-5 h-5 text-bambu-green`}),i(`settings.smartPlugs`)]}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mt-1`,children:i(`settings.smartPlugsDescription`)})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 pt-1 shrink-0`,children:[At&&At.filter(e=>e.enabled).length>1&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)($,{variant:`secondary`,size:`sm`,className:`whitespace-nowrap`,onClick:()=>Le(`on`),disabled:Ln.isPending,title:i(`settings.turnAllPlugsOn`),children:[Ln.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(Ml,{className:`w-4 h-4 text-bambu-green`}),i(`settings.allOn`)]}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,className:`whitespace-nowrap`,onClick:()=>Le(`off`),disabled:Ln.isPending,title:i(`settings.turnAllPlugsOff`),children:[Ln.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(jl,{className:`w-4 h-4 text-red-600 dark:text-red-400`}),i(`settings.allOff`)]})]}),(0,K.jsxs)($,{className:`whitespace-nowrap`,onClick:()=>{L(null),F(!0)},children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),i(`settings.addSmartPlug`)]})]})]}),At&&At.length>0&&(0,K.jsxs)(Od,{className:`mb-6`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-base font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(Zu,{className:`w-4 h-4 text-yellow-600 dark:text-yellow-400`}),i(`settings.energySummary`),Nt&&(0,K.jsx)(X,{className:`w-4 h-4 animate-spin text-bambu-gray ml-2`})]})}),(0,K.jsx)(Ad,{children:Mt?(0,K.jsxs)(`div`,{className:`grid grid-cols-2 md:grid-cols-4 gap-4`,children:[(0,K.jsxs)(`div`,{className:`bg-bambu-dark rounded-lg p-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-bambu-gray text-xs mb-1`,children:[(0,K.jsx)(Zu,{className:`w-3 h-3`}),i(`settings.currentPower`)]}),(0,K.jsxs)(`div`,{className:`text-xl font-bold text-white`,children:[Mt.totalPower.toFixed(1),(0,K.jsx)(`span`,{className:`text-sm font-normal text-bambu-gray ml-1`,children:`W`})]}),(0,K.jsx)(`div`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.plugsOnline`,{reachable:Mt.reachableCount,total:Mt.totalPlugs})})]}),(0,K.jsxs)(`div`,{className:`bg-bambu-dark rounded-lg p-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-bambu-gray text-xs mb-1`,children:[(0,K.jsx)(ts,{className:`w-3 h-3`}),i(`settings.today`)]}),(0,K.jsxs)(`div`,{className:`text-xl font-bold text-white`,children:[Mt.totalToday.toFixed(3),(0,K.jsx)(`span`,{className:`text-sm font-normal text-bambu-gray ml-1`,children:`kWh`})]}),(A?.energy_cost_per_kwh??0)>0&&(0,K.jsxs)(`div`,{className:`text-xs text-bambu-gray mt-1`,children:[`~`,(Mt.totalToday*(A?.energy_cost_per_kwh??0)).toFixed(2),` `,mf(A?.currency||`USD`)]})]}),(0,K.jsxs)(`div`,{className:`bg-bambu-dark rounded-lg p-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-bambu-gray text-xs mb-1`,children:[(0,K.jsx)(Au,{className:`w-3 h-3`}),i(`settings.yesterday`)]}),(0,K.jsxs)(`div`,{className:`text-xl font-bold text-white`,children:[Mt.totalYesterday.toFixed(3),(0,K.jsx)(`span`,{className:`text-sm font-normal text-bambu-gray ml-1`,children:`kWh`})]}),(A?.energy_cost_per_kwh??0)>0&&(0,K.jsxs)(`div`,{className:`text-xs text-bambu-gray mt-1`,children:[`~`,(Mt.totalYesterday*(A?.energy_cost_per_kwh??0)).toFixed(2),` `,mf(A?.currency||`USD`)]})]}),(0,K.jsxs)(`div`,{className:`bg-bambu-dark rounded-lg p-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-bambu-gray text-xs mb-1`,children:[(0,K.jsx)(Us,{className:`w-3 h-3`}),i(`settings.total`)]}),(0,K.jsxs)(`div`,{className:`text-xl font-bold text-white`,children:[Mt.totalLifetime.toFixed(1),(0,K.jsx)(`span`,{className:`text-sm font-normal text-bambu-gray ml-1`,children:`kWh`})]}),(A?.energy_cost_per_kwh??0)>0&&(0,K.jsxs)(`div`,{className:`text-xs text-bambu-gray mt-1`,children:[`~`,(Mt.totalLifetime*(A?.energy_cost_per_kwh??0)).toFixed(2),` `,mf(A?.currency||`USD`)]})]})]}):Nt?null:(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.enablePlugsForSummary`)})})]}),jt?(0,K.jsx)(`div`,{className:`flex justify-center py-12`,children:(0,K.jsx)(X,{className:`w-8 h-8 text-bambu-green animate-spin`})}):At&&At.length>0?(0,K.jsx)(`div`,{className:`grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4`,children:At.map(e=>(0,K.jsx)(GHe,{plug:e,onEdit:e=>{L(e),F(!0)}},e.id))}):(0,K.jsx)(Od,{children:(0,K.jsx)(Ad,{className:`py-12`,children:(0,K.jsxs)(`div`,{className:`text-center text-bambu-gray`,children:[(0,K.jsx)(kl,{className:`w-16 h-16 mx-auto mb-4 opacity-30`}),(0,K.jsx)(`p`,{className:`text-lg font-medium text-white mb-2`,children:i(`settings.noSmartPlugsTitle`)}),(0,K.jsx)(`p`,{className:`text-sm mb-4`,children:i(`settings.noSmartPlugsDescription`)}),(0,K.jsxs)($,{onClick:()=>{L(null),F(!0)},children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),i(`settings.addFirstSmartPlug`)]})]})})})]}),ue===`notifications`&&(0,K.jsxs)(`div`,{className:`grid grid-cols-1 lg:grid-cols-2 gap-4`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between mb-4`,children:[(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2`,id:`card-providers`,children:[(0,K.jsx)(Wo,{className:`w-5 h-5 text-bambu-green`}),i(`settings.providers`)]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsxs)($,{size:`sm`,variant:`secondary`,onClick:()=>oe(!0),children:[(0,K.jsx)(Pc,{className:`w-4 h-4`}),i(`settings.log`)]}),Pt&&Pt.length>0&&(0,K.jsxs)($,{size:`sm`,variant:`secondary`,onClick:()=>{Fn(null),In.mutate()},disabled:In.isPending,children:[In.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(ql,{className:`w-4 h-4`}),i(`settings.testAll`)]}),(0,K.jsxs)($,{size:`sm`,onClick:()=>{V(null),z(!0)},children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),i(`settings.addNotificationProvider`)]})]})]}),(0,K.jsx)(Od,{className:`mb-4`,children:(0,K.jsx)(Ad,{className:`py-3`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white text-sm font-medium`,children:i(`settings.notificationLanguage`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.notificationLanguageDescription`)})]}),(0,K.jsx)(`select`,{value:A.notification_language||`en`,onChange:e=>Gn(`notification_language`,e.target.value),className:`px-2 py-1.5 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-sm focus:outline-none focus:ring-1 focus:ring-bambu-green`,children:Ot.map(e=>(0,K.jsx)(`option`,{value:e.code,children:e.nativeName},e.code))})]})})}),(0,K.jsx)(Od,{className:`mb-4`,children:(0,K.jsx)(Ad,{className:`py-3`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white text-sm font-medium`,children:i(`settings.bedCooledThreshold`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.bedCooledThresholdDescription`)})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,K.jsx)(`input`,{type:`number`,min:20,max:80,step:1,value:A.bed_cooled_threshold??35,onChange:e=>Gn(`bed_cooled_threshold`,Number(e.target.value)),className:`w-16 px-2 py-1.5 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-sm text-center focus:outline-none focus:ring-1 focus:ring-bambu-green`}),(0,K.jsx)(`span`,{className:`text-sm text-bambu-gray`,children:`°C`})]})]})})}),(0,K.jsx)(Od,{className:`mb-4`,children:(0,K.jsx)(Ad,{className:`py-3`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between ${hn?.advanced_auth_enabled?``:`opacity-50`}`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white text-sm font-medium`,children:i(`settings.userNotificationsEnabled`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:hn?.advanced_auth_enabled?i(`settings.userNotificationsEnabledDescription`):i(`settings.userNotificationsDisabledHint`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,className:`sr-only peer`,checked:A.user_notifications_enabled??!0,disabled:!hn?.advanced_auth_enabled,onChange:e=>Gn(`user_notifications_enabled`,e.target.checked)}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green peer-disabled:cursor-not-allowed`})]})]})})}),Pn&&(0,K.jsx)(Od,{className:`mb-4`,children:(0,K.jsxs)(Ad,{className:`py-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between mb-2`,children:[(0,K.jsx)(`span`,{className:`text-sm font-medium text-white`,children:i(`settings.testResults`)}),(0,K.jsx)(`button`,{onClick:()=>Fn(null),className:`text-bambu-gray hover:text-white text-xs`,children:i(`common.dismiss`)})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-4 text-sm mb-2`,children:[(0,K.jsxs)(`span`,{className:`flex items-center gap-1 text-bambu-green`,children:[(0,K.jsx)(_s,{className:`w-4 h-4`}),i(`settings.testPassedCount`,{count:Pn.success})]}),Pn.failed>0&&(0,K.jsxs)(`span`,{className:`flex items-center gap-1 text-red-700 dark:text-red-400`,children:[(0,K.jsx)(Cs,{className:`w-4 h-4`}),i(`settings.testFailedCount`,{count:Pn.failed})]})]}),Pn.results.filter(e=>!e.success).length>0&&(0,K.jsx)(`div`,{className:`space-y-1 mt-2 pt-2 border-t border-bambu-dark-tertiary`,children:Pn.results.filter(e=>!e.success).map(e=>(0,K.jsxs)(`div`,{className:`text-xs text-red-700 dark:text-red-400`,children:[(0,K.jsxs)(`span`,{className:`font-medium`,children:[e.provider_name,`:`]}),` `,e.message]},e.provider_id))})]})}),Ft?(0,K.jsx)(`div`,{className:`flex justify-center py-12`,children:(0,K.jsx)(X,{className:`w-6 h-6 text-bambu-green animate-spin`})}):Pt&&Pt.length>0?(0,K.jsx)(`div`,{className:`space-y-3`,children:Pt.map(e=>(0,K.jsx)(qHe,{provider:e,onEdit:e=>{V(e),z(!0)}},e.id))}):(0,K.jsx)(Od,{children:(0,K.jsx)(Ad,{className:`py-8`,children:(0,K.jsxs)(`div`,{className:`text-center text-bambu-gray`,children:[(0,K.jsx)(Wo,{className:`w-12 h-12 mx-auto mb-3 opacity-30`}),(0,K.jsx)(`p`,{className:`text-sm font-medium text-white mb-2`,children:i(`settings.noProvidersTitle`)}),(0,K.jsx)(`p`,{className:`text-xs mb-3`,children:i(`settings.noProvidersDescription`)}),(0,K.jsxs)($,{size:`sm`,onClick:()=>{V(null),z(!0)},children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),i(`settings.addProvider`)]})]})})})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2 mb-2`,id:`card-templates`,children:[(0,K.jsx)(sc,{className:`w-5 h-5 text-bambu-green`}),i(`settings.messageTemplates`)]}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mb-3`,children:i(`settings.messageTemplatesDescription`)}),(0,K.jsxs)(`div`,{className:`relative mb-3`,children:[(0,K.jsx)(Kl,{className:`w-4 h-4 text-bambu-gray absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none`}),(0,K.jsx)(`input`,{type:`text`,value:ne,onChange:e=>re(e.target.value),placeholder:i(`settings.filterTemplates`,`Filter templates…`),className:`w-full pl-9 pr-8 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-sm focus:outline-none focus:border-bambu-green`}),ne&&(0,K.jsx)(`button`,{onClick:()=>re(``),className:`absolute right-2 top-1/2 -translate-y-1/2 p-1 text-bambu-gray hover:text-white`,"aria-label":`Clear filter`,children:(0,K.jsx)(Yu,{className:`w-3.5 h-3.5`})})]}),Ht?(0,K.jsx)(`div`,{className:`flex justify-center py-8`,children:(0,K.jsx)(X,{className:`w-6 h-6 text-bambu-green animate-spin`})}):Vt&&Vt.length>0?(()=>{let e=ne.trim().toLowerCase(),t=[...Vt].sort((e,t)=>e.name.localeCompare(t.name)).filter(t=>!e||t.name.toLowerCase().includes(e)||(t.title_template||``).toLowerCase().includes(e));return t.length===0?(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray italic text-center py-6`,children:i(`settings.noTemplatesMatch`,`No templates match your filter.`)}):(0,K.jsx)(`div`,{className:`space-y-2`,children:t.map(e=>(0,K.jsx)(Od,{className:`cursor-pointer hover:border-bambu-green/50 transition-colors`,onClick:()=>te(e),children:(0,K.jsx)(Ad,{className:`py-2.5 px-3`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsx)(`p`,{className:`text-white font-medium text-sm truncate`,children:e.name}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-xs truncate mt-0.5`,children:e.title_template})]}),(0,K.jsx)(`button`,{className:`p-1.5 hover:bg-bambu-dark-tertiary rounded transition-colors shrink-0 ml-2`,onClick:t=>{t.stopPropagation(),te(e)},children:(0,K.jsx)(Tl,{className:`w-4 h-4 text-bambu-gray`})})]})})},e.id))})})():(0,K.jsx)(Od,{children:(0,K.jsx)(Ad,{className:`py-8`,children:(0,K.jsxs)(`div`,{className:`text-center text-bambu-gray`,children:[(0,K.jsx)(sc,{className:`w-12 h-12 mx-auto mb-3 opacity-30`}),(0,K.jsx)(`p`,{className:`text-sm`,children:i(`settings.noTemplatesAvailable`)})]})})})]})]}),ue===`apikeys`&&(0,K.jsxs)(`div`,{className:d(`api_keys:read`)?`grid grid-cols-1 xl:grid-cols-2 gap-4`:`grid grid-cols-1 gap-4`,children:[(0,K.jsxs)(`div`,{children:[d(`api_keys:read`)&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{className:`flex items-start justify-between gap-4 mb-6`,children:[(0,K.jsxs)(`div`,{className:`flex-1`,children:[(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2`,id:`card-createapi`,children:[(0,K.jsx)(Vc,{className:`w-5 h-5 text-bambu-green`}),i(`settings.apiKeys`)]}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mt-1`,children:i(`settings.apiKeysDescription`)})]}),(0,K.jsxs)($,{size:`sm`,onClick:()=>ye(!0),className:`flex-shrink-0`,children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),i(`settings.createKey`)]})]}),we&&(0,K.jsx)(Od,{className:`mb-6 border-bambu-green`,children:(0,K.jsx)(Ad,{className:`py-4`,children:(0,K.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,K.jsx)(_s,{className:`w-5 h-5 text-bambu-green flex-shrink-0 mt-0.5`}),(0,K.jsxs)(`div`,{className:`flex-1`,children:[(0,K.jsx)(`p`,{className:`text-white font-medium mb-1`,children:i(`settings.apiKeyCreated`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mb-2`,children:i(`settings.apiKeyCopyWarning`)}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 bg-bambu-dark rounded-lg p-2`,children:[(0,K.jsx)(`code`,{className:`flex-1 text-sm text-bambu-green font-mono break-all`,children:we}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:async()=>{try{if(navigator.clipboard&&navigator.clipboard.writeText)await navigator.clipboard.writeText(we);else{let e=document.createElement(`textarea`);e.value=we,e.style.position=`fixed`,e.style.left=`-999999px`,document.body.appendChild(e),e.select(),document.execCommand(`copy`),document.body.removeChild(e)}o(i(`settings.toast.keyCopied`))}catch{o(i(`settings.toast.copyFailed`),`error`)}},children:(0,K.jsx)(Ls,{className:`w-4 h-4`})})]}),(0,K.jsxs)(`div`,{className:`flex gap-2 mt-3`,children:[(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>{je(we),o(i(`settings.toast.keyAddedToBrowser`))},children:i(`settings.useInApiBrowser`)}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,onClick:()=>De(!0),children:[(0,K.jsx)(Pl,{className:`w-4 h-4`}),i(`settings.apiKeyQrButton`)]}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>{De(!1),Te(null)},children:i(`common.dismiss`)})]})]})]})})}),Ee&&we&&(0,K.jsx)(uUe,{apiKey:we,baseUrl:A?.external_url||void 0,onClose:()=>De(!1)}),ve&&(0,K.jsxs)(Od,{className:`mb-6`,children:[(0,K.jsx)(kd,{children:(0,K.jsx)(`h3`,{className:`text-base font-semibold text-white`,children:i(`settings.createNewApiKey`)})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.keyName`)}),(0,K.jsx)(`input`,{type:`text`,value:be,onChange:e=>xe(e.target.value),placeholder:i(`settings.keyNamePlaceholder`),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-2`,children:i(`common.permissions`)}),(0,K.jsxs)(`div`,{className:`space-y-2`,children:[(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:Se.can_read_status,onChange:e=>Ce(t=>({...t,can_read_status:e.target.checked})),className:`w-4 h-4 text-bambu-green rounded border-bambu-dark-tertiary bg-bambu-dark focus:ring-bambu-green`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`span`,{className:`text-white`,children:i(`settings.readStatus`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.readStatusDescription`)})]})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:Se.can_queue,onChange:e=>Ce(t=>({...t,can_queue:e.target.checked})),className:`w-4 h-4 text-bambu-green rounded border-bambu-dark-tertiary bg-bambu-dark focus:ring-bambu-green`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`span`,{className:`text-white`,children:i(`settings.manageQueue`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.manageQueueDescription`)})]})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:Se.can_control_printer,onChange:e=>Ce(t=>({...t,can_control_printer:e.target.checked})),className:`w-4 h-4 text-bambu-green rounded border-bambu-dark-tertiary bg-bambu-dark focus:ring-bambu-green`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`span`,{className:`text-white`,children:i(`settings.controlPrinter`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.controlPrinterDescription`)})]})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:Se.can_manage_library,onChange:e=>Ce(t=>({...t,can_manage_library:e.target.checked})),className:`w-4 h-4 text-bambu-green rounded border-bambu-dark-tertiary bg-bambu-dark focus:ring-bambu-green`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`span`,{className:`text-white`,children:i(`settings.manageLibrary`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.manageLibraryDescription`)})]})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:Se.can_manage_inventory,onChange:e=>Ce(t=>({...t,can_manage_inventory:e.target.checked})),className:`w-4 h-4 text-bambu-green rounded border-bambu-dark-tertiary bg-bambu-dark focus:ring-bambu-green`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`span`,{className:`text-white`,children:i(`settings.manageInventory`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.manageInventoryDescription`)})]})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:Se.can_manage_maintenance,onChange:e=>Ce(t=>({...t,can_manage_maintenance:e.target.checked})),className:`w-4 h-4 text-bambu-green rounded border-bambu-dark-tertiary bg-bambu-dark focus:ring-bambu-green`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`span`,{className:`text-white`,children:i(`settings.manageMaintenance`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.manageMaintenanceDescription`)})]})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:Se.can_manage_archives,onChange:e=>Ce(t=>({...t,can_manage_archives:e.target.checked})),className:`w-4 h-4 text-bambu-green rounded border-bambu-dark-tertiary bg-bambu-dark focus:ring-bambu-green`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`span`,{className:`text-white`,children:i(`settings.manageArchives`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.manageArchivesDescription`)})]})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:Se.can_manage_projects,onChange:e=>Ce(t=>({...t,can_manage_projects:e.target.checked})),className:`w-4 h-4 text-bambu-green rounded border-bambu-dark-tertiary bg-bambu-dark focus:ring-bambu-green`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`span`,{className:`text-white`,children:i(`settings.manageProjects`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.manageProjectsDescription`)})]})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:Se.can_access_cloud,onChange:e=>Ce(t=>({...t,can_access_cloud:e.target.checked})),className:`w-4 h-4 text-bambu-green rounded border-bambu-dark-tertiary bg-bambu-dark focus:ring-bambu-green`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`span`,{className:`text-white`,children:i(`settings.cloudAccess`,`Allow cloud access`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.cloudAccessDescription`,`Read Bambu Cloud presets and filaments on your behalf. Requires you to be signed into Bambu Cloud.`)})]})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:Se.can_update_energy_cost,onChange:e=>Ce(t=>({...t,can_update_energy_cost:e.target.checked})),className:`w-4 h-4 text-bambu-green rounded border-bambu-dark-tertiary bg-bambu-dark focus:ring-bambu-green`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`span`,{className:`text-white`,children:i(`settings.updateEnergyCost`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.updateEnergyCostDescription`)})]})]})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 pt-2`,children:[(0,K.jsxs)($,{onClick:()=>G.mutate({name:be||i(`settings.unnamedKey`),...Se}),disabled:G.isPending,children:[G.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(Al,{className:`w-4 h-4`}),i(`settings.createKey`)]}),(0,K.jsx)($,{variant:`secondary`,onClick:()=>ye(!1),children:i(`common.cancel`)})]})]})]}),Lt?(0,K.jsx)(`div`,{className:`flex justify-center py-12`,children:(0,K.jsx)(X,{className:`w-8 h-8 text-bambu-green animate-spin`})}):It&&It.length>0?(0,K.jsx)(`div`,{className:`space-y-3`,children:It.map(e=>(0,K.jsx)(Od,{children:(0,K.jsx)(Ad,{className:`py-3`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,K.jsx)(Vc,{className:`w-5 h-5 ${e.enabled?`text-bambu-green`:`text-bambu-gray`}`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white font-medium`,children:e.name}),(0,K.jsxs)(`p`,{className:`text-xs text-bambu-gray`,children:[e.key_prefix,`••••••••`,e.last_used&&` · ${i(`settings.lastUsed`)}: ${Ff(e.last_used)}`]})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsxs)(`div`,{className:`flex gap-1 text-xs flex-wrap justify-end`,children:[e.can_read_status&&(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400 rounded`,children:i(`settings.read`)}),e.can_queue&&(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 bg-green-100 dark:bg-green-500/20 text-green-700 dark:text-green-400 rounded`,children:i(`queue.title`)}),e.can_control_printer&&(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 bg-orange-100 dark:bg-orange-500/20 text-orange-700 dark:text-orange-400 rounded`,children:i(`settings.control`)}),e.can_manage_library&&(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 bg-cyan-100 dark:bg-cyan-500/20 text-cyan-700 dark:text-cyan-400 rounded`,children:i(`settings.libraryBadge`)}),e.can_manage_inventory&&(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 bg-pink-100 dark:bg-pink-500/20 text-pink-700 dark:text-pink-400 rounded`,children:i(`settings.inventoryBadge`)}),e.can_manage_maintenance&&(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 bg-teal-100 dark:bg-teal-500/20 text-teal-700 dark:text-teal-400 rounded`,children:i(`settings.maintenanceBadge`)}),e.can_manage_archives&&(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 bg-indigo-100 dark:bg-indigo-500/20 text-indigo-700 dark:text-indigo-400 rounded`,children:i(`settings.archivesBadge`)}),e.can_manage_projects&&(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 bg-lime-100 dark:bg-lime-500/20 text-lime-700 dark:text-lime-400 rounded`,children:i(`settings.projectsBadge`)}),e.can_access_cloud&&(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-400 rounded`,children:i(`settings.cloudBadge`,`Cloud`)}),e.can_update_energy_cost&&(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 bg-amber-100 dark:bg-amber-500/20 text-amber-700 dark:text-amber-400 rounded`,children:i(`settings.energyCostBadge`)}),e.user_id===null&&(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400 rounded`,title:i(`settings.legacyKeyTooltip`,`Created before per-user ownership; recreate to use cloud access`),children:i(`settings.legacyKey`,`Legacy`)})]}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>ke(e.id),children:(0,K.jsx)(Ou,{className:`w-4 h-4 text-red-600 dark:text-red-400`})})]})]})})},e.id))}):(0,K.jsx)(Od,{children:(0,K.jsx)(Ad,{className:`py-12`,children:(0,K.jsxs)(`div`,{className:`text-center text-bambu-gray`,children:[(0,K.jsx)(Vc,{className:`w-16 h-16 mx-auto mb-4 opacity-30`}),(0,K.jsx)(`p`,{className:`text-lg font-medium text-white mb-2`,children:i(`settings.apiKeysEmptyTitle`)}),(0,K.jsx)(`p`,{className:`text-sm mb-4`,children:i(`settings.apiKeysEmptyDescription`)}),(0,K.jsxs)($,{onClick:()=>ye(!0),children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),i(`settings.createFirstKey`)]})]})})}),(0,K.jsxs)(Od,{className:`mt-6`,children:[(0,K.jsx)(kd,{children:(0,K.jsx)(`h3`,{className:`text-base font-semibold text-white`,id:`card-webhooks`,children:i(`settings.webhookEndpoints`)})}),(0,K.jsxs)(Ad,{className:`space-y-3 text-sm`,children:[(0,K.jsx)(`p`,{className:`text-bambu-gray`,children:i(`settings.webhookApiKeyHint`)}),(0,K.jsxs)(`div`,{className:`space-y-2 font-mono text-xs`,children:[(0,K.jsxs)(`div`,{className:`p-2 bg-bambu-dark rounded`,children:[(0,K.jsx)(`span`,{className:`text-blue-700 dark:text-blue-400`,children:`GET`}),` `,(0,K.jsx)(`span`,{className:`text-white`,children:`/api/v1/webhook/status`}),(0,K.jsxs)(`span`,{className:`text-bambu-gray`,children:[` - `,i(`settings.webhook.getAllStatus`)]})]}),(0,K.jsxs)(`div`,{className:`p-2 bg-bambu-dark rounded`,children:[(0,K.jsx)(`span`,{className:`text-blue-700 dark:text-blue-400`,children:`GET`}),` `,(0,K.jsx)(`span`,{className:`text-white`,children:`/api/v1/webhook/status/:id`}),(0,K.jsxs)(`span`,{className:`text-bambu-gray`,children:[` - `,i(`settings.webhook.getSpecificStatus`)]})]}),(0,K.jsxs)(`div`,{className:`p-2 bg-bambu-dark rounded`,children:[(0,K.jsx)(`span`,{className:`text-green-700 dark:text-green-400`,children:`POST`}),` `,(0,K.jsx)(`span`,{className:`text-white`,children:`/api/v1/webhook/queue`}),(0,K.jsxs)(`span`,{className:`text-bambu-gray`,children:[` - `,i(`settings.webhook.addToQueue`)]})]}),(0,K.jsxs)(`div`,{className:`p-2 bg-bambu-dark rounded`,children:[(0,K.jsx)(`span`,{className:`text-orange-700 dark:text-orange-400`,children:`POST`}),` `,(0,K.jsx)(`span`,{className:`text-white`,children:`/api/v1/webhook/printer/:id/pause`}),(0,K.jsxs)(`span`,{className:`text-bambu-gray`,children:[` - `,i(`settings.webhook.pausePrint`)]})]}),(0,K.jsxs)(`div`,{className:`p-2 bg-bambu-dark rounded`,children:[(0,K.jsx)(`span`,{className:`text-orange-700 dark:text-orange-400`,children:`POST`}),` `,(0,K.jsx)(`span`,{className:`text-white`,children:`/api/v1/webhook/printer/:id/resume`}),(0,K.jsxs)(`span`,{className:`text-bambu-gray`,children:[` - `,i(`settings.webhook.resumePrint`)]})]}),(0,K.jsxs)(`div`,{className:`p-2 bg-bambu-dark rounded`,children:[(0,K.jsx)(`span`,{className:`text-red-700 dark:text-red-400`,children:`POST`}),` `,(0,K.jsx)(`span`,{className:`text-white`,children:`/api/v1/webhook/printer/:id/stop`}),(0,K.jsxs)(`span`,{className:`text-bambu-gray`,children:[` - `,i(`settings.webhook.stopPrint`)]})]})]})]})]})]}),(0,K.jsxs)(Od,{className:`mt-6`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-base font-semibold text-white flex items-center gap-2`,id:`card-camera-tokens`,children:[(0,K.jsx)(zu,{className:`w-4 h-4 text-bambu-green`}),i(`cameraTokens.title`,`Camera API Tokens`)]})}),(0,K.jsx)(Ad,{children:(0,K.jsx)(WHe,{})})]})]}),d(`api_keys:read`)&&(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`div`,{className:`mb-6`,children:[(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2`,id:`card-apibrowser`,children:[(0,K.jsx)(Tc,{className:`w-5 h-5 text-bambu-green`}),i(`settings.apiBrowser`)]}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mt-1`,children:i(`settings.apiBrowserDescription`)})]}),(0,K.jsx)(Od,{className:`mb-4`,children:(0,K.jsxs)(Ad,{className:`py-3`,children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-2`,children:i(`settings.apiKeyForTesting`)}),(0,K.jsx)(`input`,{type:`text`,value:Ae,onChange:e=>je(e.target.value),placeholder:i(`settings.apiKeyPlaceholder`),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white font-mono text-sm focus:border-bambu-green focus:outline-none`}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-2`,children:i(`settings.apiKeyHint`)})]})}),(0,K.jsx)(nWe,{apiKey:Ae})]})]}),ue===`virtual-printer`&&(0,K.jsx)(`div`,{id:`card-vp`,children:(0,K.jsx)(NUe,{})}),ue===`spoolbuddy`&&(0,K.jsx)(`div`,{id:`card-spoolbuddy`,children:(0,K.jsx)(FUe,{})}),ue===`queue`&&(0,K.jsxs)(`div`,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{className:`flex gap-1 border-b border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`button`,{onClick:()=>_e(`dispatch`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px flex items-center gap-2 ${me===`dispatch`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Jc,{className:`w-4 h-4`}),i(`settings.tabs.queueDispatch`,`Queue & Dispatch`)]}),(0,K.jsxs)(`button`,{onClick:()=>_e(`pipelines`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px flex items-center gap-2 ${me===`pipelines`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(qu,{className:`w-4 h-4`}),i(`settings.tabs.queuePipelines`,`Pipelines`)]})]}),me===`pipelines`&&(0,K.jsx)(IHe,{}),me===`dispatch`&&A&&(0,K.jsxs)(`div`,{className:`flex flex-col lg:flex-row gap-4 lg:gap-6`,children:[(0,K.jsxs)(`div`,{className:`lg:w-1/2 space-y-3`,children:[(0,K.jsxs)(Od,{id:`card-print-options`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-base font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(Jc,{className:`w-4 h-4 text-bambu-green`}),i(`settings.defaultPrintOptions`,`Default Print Options`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.defaultPrintOptionsDescription`,`Set default values for print options when starting new prints. These can be overridden per print in the print dialog.`)}),[{key:`default_bed_levelling`,label:i(`settings.defaultBedLevelling`,`Bed Levelling`),desc:i(`settings.defaultBedLevellingDesc`,`Auto-level bed before print`),fallback:!0,dualNozzleOnly:!1,tristate:!0},{key:`default_flow_cali`,label:i(`settings.defaultFlowCali`,`Flow Calibration`),desc:i(`settings.defaultFlowCaliDesc`,`Calibrate extrusion flow`),fallback:!1,dualNozzleOnly:!1,tristate:!0},{key:`default_vibration_cali`,label:i(`settings.defaultVibrationCali`,`Vibration Calibration`),desc:i(`settings.defaultVibrationCaliDesc`,`Reduce ringing artifacts`),fallback:!0,dualNozzleOnly:!1,tristate:!1},{key:`default_layer_inspect`,label:i(`settings.defaultLayerInspect`,`First Layer Inspection`),desc:i(`settings.defaultLayerInspectDesc`,`AI inspection of first layer`),fallback:!1,dualNozzleOnly:!1,tristate:!1},{key:`default_timelapse`,label:i(`settings.defaultTimelapse`,`Timelapse`),desc:i(`settings.defaultTimelapseDesc`,`Record timelapse video`),fallback:!1,dualNozzleOnly:!1,tristate:!1},{key:`default_nozzle_offset_cali`,label:i(`settings.defaultNozzleOffsetCali`,`Nozzle Offset Calibration`),desc:i(`settings.defaultNozzleOffsetCaliDesc`,`Calibrate nozzle offsets between extruders`),fallback:!0,dualNozzleOnly:!0,tristate:!0}].filter(({dualNozzleOnly:e})=>!e||(zt||[]).some(e=>e.nozzle_count===2)).map(({key:e,label:t,desc:n,fallback:r,tristate:a})=>(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex-1 mr-4`,children:[(0,K.jsx)(`p`,{className:`text-sm text-white`,children:t}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-0.5`,children:n})]}),a?(0,K.jsx)(`div`,{className:`flex gap-1 shrink-0`,children:uW.map(t=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>Gn(e,t),className:`px-2.5 py-1 text-xs rounded transition-colors ${(A[e]??`auto`)===t?dW[t]:`bg-bambu-dark-tertiary text-bambu-gray hover:text-white`}`,children:i(`settings.calibrationMode_${t}`)},t))}):(0,K.jsx)(`div`,{className:`flex gap-1 shrink-0`,children:[`off`,`on`].map(t=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>Gn(e,t===`on`),className:`px-2.5 py-1 text-xs rounded transition-colors ${(A[e]??r?`on`:`off`)===t?dW[t]:`bg-bambu-dark-tertiary text-bambu-gray hover:text-white`}`,children:i(`settings.calibrationMode_${t}`)},t))})]},e))]})]}),(0,K.jsxs)(Od,{id:`card-plate`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-base font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(tu,{className:`w-4 h-4 text-bambu-green`}),i(`settings.plateClear`,`Plate-Clear Confirmation`)]})}),(0,K.jsx)(Ad,{className:`space-y-3`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex-1 mr-4`,children:[(0,K.jsx)(`p`,{className:`text-sm text-white`,children:i(`settings.requirePlateClear`,`Require plate-clear confirmation`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.requirePlateClearDescription`,`When enabled, the scheduler waits for per-printer plate-clear confirmation before starting queued prints on printers with finished jobs. Disabling this also hides the plate status badge and the "Mark plate as cleared" button on printer cards.`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.require_plate_clear??!1,onChange:e=>Gn(`require_plate_clear`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]})})]}),(0,K.jsxs)(Od,{id:`card-temp-fan-presets`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-base font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(Eu,{className:`w-4 h-4 text-bambu-green`}),i(`settings.tempFanPresetsTitle`,`Temperature & Fan Presets`)]})}),(0,K.jsxs)(Ad,{className:`space-y-4`,children:[(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.tempFanPresetsDescription`,`Customize the quick-select values shown in printer-card temperature and fan-speed popovers. The Off button is always shown.`)}),oee.map(e=>{let t=Zp(A?.[e.key]??``,e.defaults,e.lo,e.hi),n=e.unit===`C`?`°C`:`%`;return(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between mb-1`,children:[(0,K.jsxs)(`label`,{className:`text-sm text-white`,children:[i(`settings.${{nozzle_temp_presets:`tempFanPresetsNozzle`,bed_temp_presets:`tempFanPresetsBed`,chamber_temp_presets:`tempFanPresetsChamber`,fan_speed_presets:`tempFanPresetsFan`}[e.key]}`,{nozzle_temp_presets:`Nozzle temperature`,bed_temp_presets:`Bed temperature`,chamber_temp_presets:`Chamber temperature`,fan_speed_presets:`Fan speed`}[e.key]),` `,(0,K.jsxs)(`span`,{className:`text-bambu-gray text-xs`,children:[`(`,n,` · `,e.lo,`–`,e.hi,`)`]})]}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>Gn(e.key,``),title:i(`settings.tempFanPresetsReset`,`Reset to defaults`),className:`text-bambu-gray hover:text-white transition-colors p-1 rounded hover:bg-bambu-dark-tertiary`,children:(0,K.jsx)(Rl,{className:`w-3.5 h-3.5`})})]}),(0,K.jsx)(`div`,{className:`flex gap-2`,children:[0,1,2].map(n=>(0,K.jsx)(`input`,{type:`number`,min:e.lo,max:e.hi,value:t[n],onChange:r=>{let i=[t[0],t[1],t[2]],a=parseInt(r.target.value,10);i[n]=Math.max(e.lo,Math.min(e.hi,Number.isFinite(a)?a:e.lo)),Gn(e.key,JSON.stringify(i))},className:`flex-1 px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-sm focus:outline-none focus:border-bambu-green`},n))})]},e.key)})]})]}),(0,K.jsxs)(Od,{id:`card-staggered`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-base font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(Uc,{className:`w-4 h-4 text-bambu-green`}),i(`settings.staggeredStart`,`Staggered Start`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.staggeredStartDescription`,`Default group size and interval when staggering multi-printer batch starts. Can be overridden per batch in the print modal.`)}),(0,K.jsxs)(`div`,{className:`flex gap-4`,children:[(0,K.jsxs)(`div`,{className:`flex-1`,children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.staggerGroupSize`,`Group size`)}),(0,K.jsx)(`input`,{type:`number`,min:1,max:50,value:A.stagger_group_size??2,onChange:e=>Gn(`stagger_group_size`,Math.max(1,Math.min(50,parseInt(e.target.value)||1))),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-sm focus:outline-none focus:border-bambu-green`}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.staggerGroupSizeHelp`,`Printers to start simultaneously per group`)})]}),(0,K.jsxs)(`div`,{className:`flex-1`,children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.staggerInterval`,`Interval (minutes)`)}),(0,K.jsx)(`input`,{type:`number`,min:1,max:60,value:A.stagger_interval_minutes??5,onChange:e=>Gn(`stagger_interval_minutes`,Math.max(1,Math.min(60,parseInt(e.target.value)||1))),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-sm focus:outline-none focus:border-bambu-green`}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.staggerIntervalHelp`,`Delay between each group starting`)})]})]})]})]}),(0,K.jsxs)(Od,{id:`card-concurrent-uploads`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-base font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(Os,{className:`w-4 h-4 text-bambu-green`}),i(`settings.concurrentUploadsTitle`,`Concurrent Uploads`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.concurrentUploadsDescription`,`How many printers the queue may send files to at the same time. Printers receive files slowly (a large print can take several minutes), and each one waits its turn — so on a bigger fleet, raising this is what stops the last printer in a batch from waiting out every transfer before it. Lower it if your network or Bambuddy host struggles with parallel transfers.`)}),(0,K.jsxs)(`div`,{className:`w-full sm:w-1/2`,children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.concurrentUploadsLabel`,`Printers uploaded to at once`)}),(0,K.jsx)(`input`,{type:`number`,min:1,max:16,value:A.queue_max_concurrent_uploads??4,onChange:e=>Gn(`queue_max_concurrent_uploads`,Math.max(1,Math.min(16,parseInt(e.target.value)||1))),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-sm focus:outline-none focus:border-bambu-green`}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.concurrentUploadsHelp`,`1 sends to one printer at a time (the old behaviour). Default is 4.`)})]})]})]}),(0,K.jsxs)(Od,{id:`card-preheat`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-base font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(uc,{className:`w-4 h-4 text-amber-600 dark:text-amber-400`}),i(`settings.preheatTitle`,`Preheat & Heat Soak`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.preheatDescription`,`Heat the bed (and chamber, if supported) and hold at temperature before each queued print starts. Helpful for engineering filaments (PA, ABS) on printers without an active chamber heater — the bed warms the chamber by radiation while the soak timer runs. The bed target is read from the print file; chamber behaviour depends on printer model.`)}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex-1 mr-4`,children:[(0,K.jsx)(`p`,{className:`text-sm text-white`,children:i(`settings.preheatEnabled`,`Enable preheat & soak`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-0.5`,children:i(`settings.preheatEnabledDesc`,`When off, queued prints dispatch immediately.`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.preheat_enabled??!1,onChange:e=>Gn(`preheat_enabled`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),(0,K.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 gap-3 pt-1`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.preheatMaxWait`,`Max wait (seconds)`)}),(0,K.jsx)(`input`,{type:`number`,min:60,max:3600,value:A.preheat_max_wait_seconds??900,onChange:e=>Gn(`preheat_max_wait_seconds`,Math.max(60,Math.min(3600,parseInt(e.target.value)||900))),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-sm focus:outline-none focus:border-bambu-green disabled:opacity-50`,disabled:!(A.preheat_enabled??!1)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.preheatMaxWaitHelp`,`Cap on the chamber warm-up phase before falling through.`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.preheatSoak`,`Soak (seconds)`)}),(0,K.jsx)(`input`,{type:`number`,min:0,max:1800,value:A.preheat_soak_seconds??300,onChange:e=>Gn(`preheat_soak_seconds`,Math.max(0,Math.min(1800,parseInt(e.target.value)||0))),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-sm focus:outline-none focus:border-bambu-green disabled:opacity-50`,disabled:!(A.preheat_enabled??!1)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.preheatSoakHelp`,`Hold time after target reached or max-wait elapsed.`)})]})]}),(0,K.jsxs)(`div`,{className:`pt-2 border-t border-bambu-dark-tertiary/50`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between mb-1`,children:[(0,K.jsx)(`label`,{className:`text-sm text-white`,children:i(`settings.preheatFilamentTargetsLabel`,`Per-filament chamber target (°C)`)}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>Gn(`preheat_filament_targets`,``),title:i(`settings.preheatFilamentTargetsReset`,`Reset to defaults`),className:`text-bambu-gray hover:text-white transition-colors p-1 rounded hover:bg-bambu-dark-tertiary`,children:(0,K.jsx)(Rl,{className:`w-3.5 h-3.5`})})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mb-2`,children:i(`settings.preheatFilamentTargetsHint`,`Bambuddy picks the highest target across the loaded AMS slots; PLA-only prints derive 0 and skip the chamber phase automatically.`)}),(0,K.jsx)(NHe,{value:A.preheat_filament_targets??``,onChange:e=>Gn(`preheat_filament_targets`,e),disabled:!(A.preheat_enabled??!1)})]}),(0,K.jsxs)(`p`,{className:`text-xs text-bambu-gray pt-1 border-t border-bambu-dark-tertiary/50`,children:[(0,K.jsx)(`span`,{className:`font-medium text-bambu-gray/90`,children:i(`settings.preheatHardwareTitle`,`Per-printer behaviour:`)}),` `,i(`settings.preheatHardwareDetail`,`H2C/H2D/H2D Pro/H2S/X2D/X1E actively heat the chamber via M141. X1C/P2S read chamber temp but rely on bed-radiation heating. P1S/P1P/A1/A1 Mini have no chamber sensor — only the soak timer applies.`)]})]})]}),(0,K.jsxs)(Od,{id:`card-gcode`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-base font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(js,{className:`w-4 h-4 text-bambu-green`}),i(`settings.gcodeInjection`,`G-code Injection`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`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.`)}),(()=>{let e=(()=>{try{return A.gcode_snippets?JSON.parse(A.gcode_snippets):{}}catch{return{}}})(),t=[...new Set((zt||[]).filter(e=>e.model).map(e=>e.model))].sort(),n=(t,n,r)=>{let i={...e};i[t]||(i[t]={start_gcode:``,end_gcode:``}),i[t][n]=r,!i[t].start_gcode&&!i[t].end_gcode&&delete i[t];let a=Object.keys(i).length>0?JSON.stringify(i):``;j(e=>e?{...e,gcode_snippets:a}:null),zn.current=a},r=()=>{zn.current!==null&&(Un.mutate({gcode_snippets:zn.current}),zn.current=null)};return t.length===0?(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray italic`,children:i(`settings.gcodeInjectionNoPrinters`,`No printers found. Add printers to configure G-code snippets.`)}):t.map(t=>{let a=e[t]||{start_gcode:``,end_gcode:``},o=!!(a.start_gcode||a.end_gcode);return(0,K.jsx)(Op,{defaultOpen:o,className:`border border-bambu-dark-tertiary rounded-lg px-3 py-2`,summary:(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`h4`,{className:`text-sm font-medium text-white`,children:t}),o&&(0,K.jsx)(`span`,{className:`text-xs px-1.5 py-0.5 rounded bg-bambu-green/20 text-bambu-green`,children:i(`settings.gcodeConfigured`,`Configured`)})]}),children:(0,K.jsxs)(`div`,{className:`space-y-2`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.gcodeStartLabel`,`Start G-code`)}),(0,K.jsx)(`textarea`,{value:a.start_gcode,onChange:e=>n(t,`start_gcode`,e.target.value),onBlur:r,placeholder:i(`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`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.gcodeEndLabel`,`End G-code`)}),(0,K.jsx)(`textarea`,{value:a.end_gcode,onChange:e=>n(t,`end_gcode`,e.target.value),onBlur:r,placeholder:i(`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`})]})]})},t)})})()]})]})]}),(0,K.jsxs)(`div`,{className:`lg:w-1/2 space-y-3`,children:[(0,K.jsxs)(Od,{id:`card-pipelines`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-base font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(qu,{className:`w-4 h-4 text-bambu-green`}),i(`settings.pipelineLimits.title`,`Slicer Pipeline limits`)]})}),(0,K.jsx)(Ad,{className:`space-y-2`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,K.jsxs)(`div`,{className:`flex-1`,children:[(0,K.jsx)(`p`,{className:`text-sm text-white`,children:i(`settings.pipelineLimits.maxCopiesLabel`,`Max copies per run`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-0.5`,children:i(`settings.pipelineLimits.maxCopiesDesc`,`Upper bound on the copies operators can request when running a pipeline. Server-side hard cap is 1000.`)})]}),(0,K.jsx)(`input`,{type:`number`,min:1,max:1e3,value:A.pipeline_max_copies??50,onChange:e=>{let t=parseInt(e.target.value,10);Number.isNaN(t)||Gn(`pipeline_max_copies`,Math.max(1,Math.min(1e3,t)))},"aria-label":i(`settings.pipelineLimits.maxCopiesLabel`,`Max copies per run`),className:`w-24 px-2 py-1 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-sm`})]})})]}),(0,K.jsxs)(Od,{id:`card-slicer`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-base font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(Ps,{className:`w-4 h-4 text-bambu-green`}),i(`settings.slicerCard`,`Slicer`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.preferredSlicer`)}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsxs)(`select`,{value:A.preferred_slicer??`bambu_studio`,onChange:e=>Gn(`preferred_slicer`,e.target.value),className:`w-full px-3 py-2 pr-10 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none appearance-none cursor-pointer`,children:[(0,K.jsx)(`option`,{value:`bambu_studio`,children:i(`settings.slicerBambuStudio`)}),(0,K.jsx)(`option`,{value:`orcaslicer`,children:i(`settings.slicerOrcaSlicer`)})]}),(0,K.jsx)(ls,{className:`absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray pointer-events-none`})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.preferredSlicerDescription`)}),(A.preferred_slicer??`bambu_studio`)===`orcaslicer`&&(0,K.jsx)(`div`,{role:`alert`,className:`text-xs text-amber-800 dark:text-amber-200 bg-amber-50 dark:bg-amber-900/20 border border-amber-300 dark:border-amber-700/40 rounded p-2 mt-2`,children:i(`settings.orcaslicerKnownIssuesWarning`,`OrcaSlicer 2.3.2 / 2.4.0-dev have known CLI bugs that block slicing many Bambu-authored 3MFs — see upstream issues #12426 (segfault on painted multi-extruder files) and #13386 (parameter-range strict-validation reject). Bambu Studio is recommended until the upstream fixes land.`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.openInSlicerLabel`,`Open in Slicer`)}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsxs)(`select`,{value:A.open_in_slicer??``,onChange:e=>Gn(`open_in_slicer`,e.target.value===``?null:e.target.value),className:`w-full px-3 py-2 pr-10 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none appearance-none cursor-pointer`,children:[(0,K.jsx)(`option`,{value:``,children:i(`settings.openInSlicerInherit`,`Same as API slicer`)}),(0,K.jsx)(`option`,{value:`bambu_studio`,children:i(`settings.slicerBambuStudio`)}),(0,K.jsx)(`option`,{value:`orcaslicer`,children:i(`settings.slicerOrcaSlicer`)})]}),(0,K.jsx)(ls,{className:`absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray pointer-events-none`})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.openInSlicerDescription`,`Desktop slicer used by the 'Open in Slicer' button. Leave on 'Same as API slicer' to inherit, or pick a different slicer to use locally.`)})]}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,K.jsxs)(`div`,{className:`min-w-0`,children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.useSlicerApi`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.useSlicerApiDescription`)})]}),(0,K.jsxs)(`label`,{className:`flex items-center cursor-pointer shrink-0`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.use_slicer_api??!1,onChange:e=>Gn(`use_slicer_api`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`relative w-11 h-6 bg-bambu-dark-tertiary rounded-full peer peer-checked:bg-bambu-green peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-bambu-green/50 transition-colors after:content-[''] after:absolute after:top-0.5 after:left-0.5 after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-transform peer-checked:after:translate-x-5`})]})]}),(A.use_slicer_api??!1)&&(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:(A.preferred_slicer??`bambu_studio`)===`orcaslicer`?i(`settings.orcaslicerApiUrl`,`OrcaSlicer sidecar URL`):i(`settings.bambuStudioApiUrl`,`Bambu Studio sidecar URL`)}),(0,K.jsx)(`input`,{type:`text`,value:((A.preferred_slicer??`bambu_studio`)===`orcaslicer`?A.orcaslicer_api_url:A.bambu_studio_api_url)??``,onChange:e=>Gn((A.preferred_slicer??`bambu_studio`)===`orcaslicer`?`orcaslicer_api_url`:`bambu_studio_api_url`,e.target.value),placeholder:(A.preferred_slicer??`bambu_studio`)===`orcaslicer`?`http://localhost:3003`:`http://localhost:3001`,className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none placeholder:text-bambu-gray/40`}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.slicerApiUrlDescription`,`URL of the slicer-API sidecar container. Leave blank to use the SLICER_API_URL / BAMBU_STUDIO_API_URL env var defaults.`)})]}),(A.use_slicer_api??!1)&&(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.slicerStallTimeout`)}),(0,K.jsx)(`input`,{type:`number`,min:1,max:240,value:A.slicer_stall_timeout_minutes??15,onChange:e=>Gn(`slicer_stall_timeout_minutes`,Number(e.target.value)),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.slicerStallTimeoutDescription`)})]})]})]}),(A.use_slicer_api??!1)&&(0,K.jsx)(PHe,{}),(0,K.jsxs)(Od,{children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-base font-semibold text-white flex items-center gap-2`,id:`card-drying`,children:[(0,K.jsx)(uc,{className:`w-4 h-4 text-amber-600 dark:text-amber-400`}),i(`settings.queueDrying`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.queueDryingDescription`)}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-white`,children:i(`settings.queueDryingEnabled`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-0.5`,children:i(`settings.queueDryingEnabledDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.queue_drying_enabled??!1,onChange:e=>Gn(`queue_drying_enabled`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),A.queue_drying_enabled&&(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-white`,children:i(`settings.queueDryingBlock`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-0.5`,children:i(`settings.queueDryingBlockDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.queue_drying_block??!1,onChange:e=>Gn(`queue_drying_block`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-amber-500`})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-white`,children:i(`settings.ambientDryingEnabled`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-0.5`,children:i(`settings.ambientDryingEnabledDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.ambient_drying_enabled??!1,onChange:e=>Gn(`ambient_drying_enabled`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-white`,children:i(`settings.printDryingEnabled`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-0.5`,children:i(`settings.printDryingEnabledDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.print_drying_enabled??!1,onChange:e=>Gn(`print_drying_enabled`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),(0,K.jsxs)(`div`,{className:`space-y-2`,children:[(0,K.jsx)(`p`,{className:`text-sm text-white font-medium`,children:i(`settings.dryingPresets`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.dryingPresetsDescription`)}),(0,K.jsx)(`div`,{className:`overflow-x-auto`,children:(0,K.jsxs)(`table`,{className:`w-full text-xs`,children:[(0,K.jsx)(`thead`,{children:(0,K.jsxs)(`tr`,{className:`text-bambu-gray border-b border-bambu-dark-tertiary`,children:[(0,K.jsx)(`th`,{className:`text-left py-1.5`,children:i(`settings.dryingFilament`)}),(0,K.jsx)(`th`,{className:`text-center py-1.5`,colSpan:2,children:`AMS 2 Pro`}),(0,K.jsx)(`th`,{className:`text-center py-1.5`,colSpan:2,children:`AMS-HT`})]})}),(0,K.jsx)(`tbody`,{children:(()=>{let e={PLA:{n3f:45,n3s:45,n3f_hours:12,n3s_hours:12},PETG:{n3f:65,n3s:65,n3f_hours:12,n3s_hours:12},TPU:{n3f:65,n3s:75,n3f_hours:12,n3s_hours:18},ABS:{n3f:65,n3s:80,n3f_hours:12,n3s_hours:8},ASA:{n3f:65,n3s:80,n3f_hours:12,n3s_hours:8},PA:{n3f:65,n3s:85,n3f_hours:12,n3s_hours:12},PC:{n3f:65,n3s:80,n3f_hours:12,n3s_hours:8},PVA:{n3f:65,n3s:85,n3f_hours:12,n3s_hours:18}},t={...e};try{if(A.drying_presets){let n=JSON.parse(A.drying_presets);typeof n==`object`&&n&&(t={...e,...n})}}catch{}let n=(e,n,r)=>{let i={...t,[e]:{...t[e],[n]:r}};Gn(`drying_presets`,JSON.stringify(i))};return Object.entries(t).map(([e,t])=>(0,K.jsxs)(`tr`,{className:`border-b border-bambu-dark-tertiary/50`,children:[(0,K.jsx)(`td`,{className:`py-1.5 pr-2 text-white font-medium`,children:e}),(0,K.jsx)(`td`,{className:`py-1 px-1`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-end gap-1`,children:[(0,K.jsx)(`input`,{type:`number`,min:30,max:65,value:t.n3f,onChange:t=>n(e,`n3f`,Math.max(1,parseInt(t.target.value)||0)),className:`w-14 px-1.5 py-1 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-center text-xs focus:border-amber-500/50 focus:outline-none [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:`°C`})]})}),(0,K.jsx)(`td`,{className:`py-1 px-1`,children:(0,K.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,K.jsx)(`input`,{type:`number`,min:1,max:24,value:t.n3f_hours,onChange:t=>n(e,`n3f_hours`,Math.max(1,parseInt(t.target.value)||0)),className:`w-14 px-1.5 py-1 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-center text-xs focus:border-amber-500/50 focus:outline-none [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:`h`})]})}),(0,K.jsx)(`td`,{className:`py-1 px-1`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-end gap-1`,children:[(0,K.jsx)(`input`,{type:`number`,min:30,max:85,value:t.n3s,onChange:t=>n(e,`n3s`,Math.max(1,parseInt(t.target.value)||0)),className:`w-14 px-1.5 py-1 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-center text-xs focus:border-amber-500/50 focus:outline-none [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:`°C`})]})}),(0,K.jsx)(`td`,{className:`py-1 px-1`,children:(0,K.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,K.jsx)(`input`,{type:`number`,min:1,max:24,value:t.n3s_hours,onChange:t=>n(e,`n3s_hours`,Math.max(1,parseInt(t.target.value)||0)),className:`w-14 px-1.5 py-1 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-center text-xs focus:border-amber-500/50 focus:outline-none [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:`h`})]})})]},e))})()})]})})]}),(0,K.jsxs)(`div`,{className:`space-y-2`,children:[(0,K.jsx)(`p`,{className:`text-sm text-white font-medium`,children:i(`settings.humidityThresholds`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.humidityThresholdsDescription`)}),(0,K.jsx)(`div`,{className:`overflow-x-auto`,children:(0,K.jsxs)(`table`,{className:`w-full text-xs`,children:[(0,K.jsx)(`thead`,{children:(0,K.jsxs)(`tr`,{className:`text-bambu-gray border-b border-bambu-dark-tertiary`,children:[(0,K.jsx)(`th`,{className:`text-left py-1.5`,children:i(`settings.dryingFilament`)}),(0,K.jsx)(`th`,{className:`text-right py-1.5 pr-2`,children:i(`settings.humidityThresholdCol`)})]})}),(0,K.jsx)(`tbody`,{children:(()=>{let e=A.ams_humidity_fair??60,t=[`PLA`,`PETG`,`TPU`,`ABS`,`ASA`,`PA`,`PC`,`PVA`],n={};try{if(A.ams_humidity_thresholds){let e=JSON.parse(A.ams_humidity_thresholds);typeof e==`object`&&e&&(n=e)}}catch{}let r=[{key:`default`,label:i(`settings.humidityThresholdDefault`),value:Number(n.default??e),isDefault:!0},...t.map(t=>({key:t,label:t,value:Number(n[t]??n.default??e),isDefault:!1}))],a=(e,t)=>{if(t.trim()===``){let t={...n};delete t[e],Gn(`ams_humidity_thresholds`,JSON.stringify(t));return}let r=parseInt(t,10);if(Number.isNaN(r))return;let i=Math.max(5,Math.min(95,r)),a={...n,[e]:i};Gn(`ams_humidity_thresholds`,JSON.stringify(a))};return r.map(e=>{let t=M[e.key],n=t===void 0?String(e.value):t;return(0,K.jsxs)(`tr`,{className:`border-b border-bambu-dark-tertiary/50`,children:[(0,K.jsx)(`td`,{className:`py-1.5 pr-2 font-medium ${e.isDefault?`text-bambu-gray italic`:`text-white`}`,children:e.label}),(0,K.jsx)(`td`,{className:`py-1 pr-2`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-end gap-1`,children:[(0,K.jsx)(`input`,{type:`number`,min:5,max:95,value:n,onChange:t=>N(n=>({...n,[e.key]:t.target.value})),onBlur:t=>{a(e.key,t.target.value),N(t=>{let n={...t};return delete n[e.key],n})},onKeyDown:e=>{e.key===`Enter`&&e.currentTarget.blur()},className:`w-14 px-1.5 py-1 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-center text-xs focus:border-amber-500/50 focus:outline-none [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:`%`})]})})]},e.key)})})()})]})})]})]})]})]})]})]}),ue===`filament`&&A&&(0,K.jsx)(K.Fragment,{children:(0,K.jsxs)(`div`,{className:`flex flex-col lg:flex-row gap-4 lg:gap-6`,children:[(0,K.jsxs)(`div`,{className:`lg:w-1/3 space-y-3`,children:[(0,K.jsx)(mUe,{}),(0,K.jsxs)(Od,{id:`card-filamentchecks`,children:[(0,K.jsx)(kd,{children:(0,K.jsx)(`h2`,{className:`text-lg font-semibold text-white`,children:i(`settings.filamentChecks`)})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.disableFilamentWarnings`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.disableFilamentWarningsDesc`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.disable_filament_warnings,onChange:e=>Gn(`disable_filament_warnings`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.preferLowestFilament`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.preferLowestFilamentDesc`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray/70 mt-1`,children:i(`settings.preferLowestFilamentBackupNote`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.prefer_lowest_filament,onChange:e=>Gn(`prefer_lowest_filament`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]})]})]}),(0,K.jsxs)(Od,{id:`card-printmodal`,children:[(0,K.jsx)(kd,{children:(0,K.jsx)(`h2`,{className:`text-lg font-semibold text-white`,children:i(`settings.printModal`)})}),(0,K.jsx)(Ad,{className:`space-y-3`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.expandCustomMapping`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.expandCustomMappingDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.per_printer_mapping_expanded??!1,onChange:e=>Gn(`per_printer_mapping_expanded`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]})})]}),(0,K.jsxs)(Od,{id:`card-amsthresholds`,children:[(0,K.jsx)(kd,{children:(0,K.jsx)(`h2`,{className:`text-lg font-semibold text-white`,children:i(`settings.amsDisplayThresholds`)})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.amsThresholdsDescription`)}),(0,K.jsxs)(`div`,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-white`,children:[(0,K.jsx)(Js,{className:`w-4 h-4 text-blue-600 dark:text-blue-400`}),(0,K.jsx)(`span`,{className:`font-medium`,children:i(`settings.humidity`)})]}),(0,K.jsxs)(`div`,{className:`grid grid-cols-2 gap-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:[i(`settings.goodGreen`),` ≤`]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`input`,{type:`number`,min:`0`,max:`100`,value:A.ams_humidity_good??40,onChange:e=>Gn(`ams_humidity_good`,parseInt(e.target.value)||40),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:`%`})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:[i(`settings.fairOrange`),` ≤`]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`input`,{type:`number`,min:`0`,max:`100`,value:A.ams_humidity_fair??60,onChange:e=>Gn(`ams_humidity_fair`,parseInt(e.target.value)||60),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:`%`})]})]})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.aboveFairBad`)}),(0,K.jsx)(`p`,{className:`text-xs text-amber-700/80 dark:text-amber-400/70`,children:i(`settings.fairAlsoDryingThreshold`)})]}),(0,K.jsxs)(`div`,{className:`space-y-3 pt-2 border-t border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-white`,children:[(0,K.jsx)(Eu,{className:`w-4 h-4 text-orange-600 dark:text-orange-400`}),(0,K.jsx)(`span`,{className:`font-medium`,children:i(`settings.temperature`)})]}),(0,K.jsxs)(`div`,{className:`grid grid-cols-2 gap-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:[i(`settings.goodBlue`),` ≤`]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`input`,{type:`number`,step:`0.5`,min:`0`,max:`60`,value:A.ams_temp_good??28,onChange:e=>Gn(`ams_temp_good`,parseFloat(e.target.value)||28),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:`°C`})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:[i(`settings.fairOrange`),` ≤`]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`input`,{type:`number`,step:`0.5`,min:`0`,max:`60`,value:A.ams_temp_fair??35,onChange:e=>Gn(`ams_temp_fair`,parseFloat(e.target.value)||35),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:`°C`})]})]})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.aboveFairHot`)})]}),(0,K.jsxs)(`div`,{className:`space-y-3 pt-4 border-t border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-white`,children:[(0,K.jsx)(Vs,{className:`w-4 h-4 text-purple-600 dark:text-purple-400`}),(0,K.jsx)(`span`,{className:`font-medium`,children:i(`settings.historyRetention`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.keepSensorHistory`)}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`input`,{type:`number`,min:`1`,max:`365`,value:A.ams_history_retention_days??30,onChange:e=>Gn(`ams_history_retention_days`,parseInt(e.target.value)||30),className:`w-24 px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:i(`common.days`)})]})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.historyRetentionDescription`)})]})]})]})]}),(0,K.jsxs)(`div`,{className:`lg:w-2/3 space-y-3`,children:[(0,K.jsx)(hUe,{}),(0,K.jsx)(TUe,{})]})]})}),Oe!==null&&(0,K.jsx)(Gd,{title:i(`settings.deleteApiKeyTitle`),message:i(`settings.deleteApiKeyMessage`),confirmText:i(`settings.deleteKey`),variant:`danger`,onConfirm:()=>{Rt.mutate(Oe),ke(null)},onCancel:()=>ke(null)}),P&&(0,K.jsx)(KHe,{plug:I,onClose:()=>{F(!1),L(null)}}),R&&(0,K.jsx)(YHe,{provider:B,onClose:()=>{z(!1),V(null)}}),ee&&(0,K.jsx)(XHe,{template:ee,onClose:()=>te(null)}),ae&&(0,K.jsx)(QHe,{onClose:()=>oe(!1)}),Me&&(0,K.jsx)(Gd,{title:i(`settings.clearNotificationLogs`),message:i(`settings.clearLogsMessage`),confirmText:i(`settings.clearLogs`),variant:`warning`,onConfirm:async()=>{Ne(!1);try{o((await Q.clearNotificationLogs(30)).message,`success`)}catch{o(i(`settings.toast.clearLogsFailed`),`error`)}},onCancel:()=>Ne(!1)}),Pe&&(0,K.jsx)(Gd,{title:i(`settings.resetUiPreferences`),message:i(`settings.resetUiPreferencesMessage`),confirmText:i(`settings.resetPreferences`),variant:`default`,onConfirm:()=>{Fe(!1),localStorage.clear(),o(i(`settings.toast.uiPreferencesReset`),`success`),setTimeout(()=>window.location.reload(),1e3)},onCancel:()=>Fe(!1)}),Ie&&(0,K.jsx)(Gd,{title:`Turn All Plugs ${Ie===`on`?`On`:`Off`}`,message:`This will turn ${Ie===`on`?`ON`:`OFF`} all ${At?.filter(e=>e.enabled).length||0} enabled smart plugs. ${Ie===`off`?`Any running printers may be affected!`:``}`,confirmText:`Turn All ${Ie===`on`?`On`:`Off`}`,variant:Ie===`off`?`danger`:`warning`,onConfirm:()=>{let e=Ie;Le(null),Ln.mutate(e)},onCancel:()=>Le(null)}),Re&&sn?.release_notes&&(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4`,onClick:()=>ze(!1),children:(0,K.jsxs)(Od,{className:`w-full max-w-2xl max-h-[80vh] flex flex-col`,onClick:e=>e.stopPropagation(),children:[(0,K.jsxs)(kd,{className:`flex flex-row items-center justify-between shrink-0`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white`,children:[`Release Notes - v`,sn.latest_version]}),sn.release_name&&sn.release_name!==sn.latest_version&&(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:sn.release_name})]}),(0,K.jsx)(`button`,{onClick:()=>ze(!1),className:`p-1 rounded hover:bg-bambu-dark-tertiary text-bambu-gray hover:text-white`,children:(0,K.jsx)(Yu,{className:`w-5 h-5`})})]}),(0,K.jsx)(Ad,{className:`overflow-y-auto flex-1`,children:(0,K.jsx)(`pre`,{className:`text-sm text-bambu-gray whitespace-pre-wrap font-sans`,children:sn.release_notes})}),(0,K.jsxs)(`div`,{className:`p-4 border-t border-bambu-dark-tertiary shrink-0 flex gap-2`,children:[sn.release_url&&(0,K.jsx)(`a`,{href:sn.release_url,target:`_blank`,rel:`noopener noreferrer`,className:`flex-1`,children:(0,K.jsxs)($,{variant:`secondary`,className:`w-full`,children:[(0,K.jsx)($s,{className:`w-4 h-4`}),`View on GitHub`]})}),(0,K.jsx)($,{onClick:()=>ze(!1),className:`flex-1`,children:`Close`})]})]})}),ue===`users`&&(0,K.jsxs)(`div`,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{className:`flex gap-1 border-b border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`button`,{onClick:()=>pe(`users`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${fe===`users`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Lu,{className:`w-4 h-4`}),i(`settings.tabs.users`)]}),(0,K.jsxs)(`button`,{onClick:()=>pe(`email`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${fe===`email`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(tl,{className:`w-4 h-4`}),i(`settings.tabs.emailAuth`)||`Email Authentication`,hn?.advanced_auth_enabled&&(0,K.jsx)(`span`,{className:`w-2 h-2 rounded-full bg-green-400`})]}),(0,K.jsxs)(`button`,{onClick:()=>pe(`ldap`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${fe===`ldap`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(tu,{className:`w-4 h-4`}),i(`settings.tabs.ldap`)||`LDAP`,gn?.ldap_enabled&&(0,K.jsx)(`span`,{className:`w-2 h-2 rounded-full bg-green-400`})]}),(0,K.jsxs)(`button`,{onClick:()=>pe(`twofa`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px flex items-center gap-2 ${fe===`twofa`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(tu,{className:`w-4 h-4`}),i(`settings.tabs.twoFa`),(0,K.jsx)(`span`,{className:`w-2 h-2 rounded-full ${_n?.totp_enabled||_n?.email_otp_enabled?`bg-green-400`:`bg-bambu-gray/40`}`})]}),l&&(0,K.jsxs)(`button`,{onClick:()=>pe(`oidc`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px flex items-center gap-2 ${fe===`oidc`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Tc,{className:`w-4 h-4`}),i(`settings.tabs.oidc`),(0,K.jsx)(`span`,{className:`w-2 h-2 rounded-full ${vn.some(e=>e.is_enabled)?`bg-green-400`:`bg-bambu-gray/40`}`})]}),l&&(0,K.jsxs)(`button`,{onClick:()=>pe(`security`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px flex items-center gap-2 ${fe===`security`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(tu,{className:`w-4 h-4`}),i(`settings.tabs.security`)]})]}),fe===`users`&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(Od,{children:(0,K.jsx)(Ad,{className:`py-4`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,K.jsx)(`div`,{className:`w-10 h-10 rounded-full flex items-center justify-center ${s?`bg-green-500/20`:`bg-gray-500/20`}`,children:s?(0,K.jsx)(Qc,{className:`w-5 h-5 text-green-600 dark:text-green-400`}):(0,K.jsx)(Zc,{className:`w-5 h-5 text-gray-400`})}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`text-white font-medium`,children:i(`settings.authentication`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(s?`settings.authEnabledDescription`:`settings.authDisabledDescription`)})]})]}),s?c?.is_admin&&(0,K.jsxs)($,{variant:`secondary`,onClick:()=>Ve(!0),children:[(0,K.jsx)(Zc,{className:`w-4 h-4`}),i(`common.disable`)]}):(0,K.jsxs)($,{onClick:()=>t(`/setup`),children:[(0,K.jsx)(Qc,{className:`w-4 h-4`}),i(`common.enable`)]})]})})}),hn?.advanced_auth_enabled&&(0,K.jsx)(Od,{className:`border-blue-500/30 bg-blue-500/5`,children:(0,K.jsx)(Ad,{className:`py-4`,children:(0,K.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,K.jsx)(`div`,{className:`w-10 h-10 rounded-full flex items-center justify-center bg-blue-500/20 flex-shrink-0`,children:(0,K.jsx)(tl,{className:`w-5 h-5 text-blue-600 dark:text-blue-400`})}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`text-white font-medium`,children:i(`settings.email.advancedAuthEnabled`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mt-1`,children:i(`settings.email.advancedAuthEnabledDesc`)})]})]})})}),s&&(0,K.jsxs)(`div`,{className:`grid grid-cols-1 xl:grid-cols-2 gap-6`,children:[(0,K.jsxs)(`div`,{className:`space-y-3`,children:[(0,K.jsxs)(Od,{id:`card-session-policy`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-lg font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(Qc,{className:`w-5 h-5 text-bambu-green`}),i(`settings.sessionPolicy.title`)]})}),(0,K.jsxs)(Ad,{children:[(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mb-4`,children:i(`settings.sessionPolicy.description`)}),(0,K.jsxs)(`div`,{className:`grid grid-cols-2 sm:grid-cols-4 gap-2 mb-4`,children:[[{hours:24,labelKey:`settings.sessionPolicy.preset24h`},{hours:168,labelKey:`settings.sessionPolicy.preset7d`},{hours:720,labelKey:`settings.sessionPolicy.preset30d`}].map(e=>{let t=(A?.session_max_hours??24)===e.hours;return(0,K.jsx)(`button`,{type:`button`,onClick:()=>Gn(`session_max_hours`,e.hours),disabled:s&&!d(`settings:update`),className:`px-3 py-2 rounded-lg text-sm font-medium transition-colors ${t?`bg-bambu-green text-white`:`bg-bambu-dark-tertiary text-bambu-gray hover:text-white hover:bg-bambu-dark`} disabled:opacity-50 disabled:cursor-not-allowed`,children:i(e.labelKey)},e.hours)}),(0,K.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,K.jsx)(`input`,{type:`number`,min:1,max:720,value:A?.session_max_hours??24,onChange:e=>{let t=parseInt(e.target.value,10);Number.isNaN(t)||Gn(`session_max_hours`,Math.max(1,Math.min(720,t)))},disabled:s&&!d(`settings:update`),"aria-label":i(`settings.sessionPolicy.customHoursLabel`),className:`w-20 px-2 py-2 bg-bambu-dark-tertiary text-white text-sm rounded-lg border border-bambu-dark-tertiary focus:border-bambu-green focus:outline-none disabled:opacity-50`}),(0,K.jsx)(`span`,{className:`text-sm text-bambu-gray`,children:i(`settings.sessionPolicy.hoursSuffix`)})]})]}),(A?.session_max_hours??24)>24&&(0,K.jsxs)(`div`,{className:`flex items-start gap-2 p-3 rounded-lg bg-yellow-50 dark:bg-yellow-500/10 border border-yellow-300 dark:border-yellow-500/30`,children:[(0,K.jsx)(ju,{className:`w-4 h-4 text-yellow-600 dark:text-yellow-400 flex-shrink-0 mt-0.5`}),(0,K.jsx)(`p`,{className:`text-xs text-yellow-800 dark:text-yellow-200`,children:i(`settings.sessionPolicy.warning`)})]})]})]}),c&&(0,K.jsxs)(Od,{children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`h3`,{className:`text-lg font-semibold text-white flex items-center gap-2`,id:`card-currentuser`,children:[(0,K.jsx)(Lu,{className:`w-5 h-5 text-bambu-green`}),i(`settings.currentUser`)]}),c.auth_source!==`ldap`&&(0,K.jsxs)($,{size:`sm`,variant:`ghost`,onClick:()=>Ue(!0),children:[(0,K.jsx)(Vc,{className:`w-4 h-4`}),i(`settings.changePassword`)]})]})}),(0,K.jsx)(Ad,{children:(0,K.jsx)(`div`,{className:`flex items-center justify-between`,children:(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white font-medium text-lg`,children:c.username}),(0,K.jsxs)(`div`,{className:`flex flex-wrap gap-1 mt-2`,children:[c.is_admin&&(0,K.jsx)(`span`,{className:`px-2 py-0.5 rounded-full text-xs font-medium bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-300`,children:i(`settings.admin`)}),c.groups?.map(e=>(0,K.jsx)(`span`,{className:`px-2 py-0.5 rounded-full text-xs font-medium ${e.name===`Administrators`?`bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-300`:e.name===`Operators`?`bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-300`:e.name===`Viewers`?`bg-green-100 dark:bg-green-500/20 text-green-700 dark:text-green-300`:`bg-gray-500/20 text-gray-300`}`,children:e.name},e.id))]})]})})})]}),(0,K.jsxs)(Od,{children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`h3`,{className:`text-lg font-semibold text-white flex items-center gap-2`,id:`card-users`,children:[(0,K.jsx)(Lu,{className:`w-5 h-5 text-bambu-green`}),i(`settings.users`)]}),d(`users:create`)&&(0,K.jsxs)($,{size:`sm`,onClick:()=>{Ze(!0),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]})},children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),i(`settings.addUser`)]})]})}),(0,K.jsx)(Ad,{children:bn?(0,K.jsx)(`div`,{className:`flex items-center justify-center py-8`,children:(0,K.jsx)(X,{className:`w-6 h-6 text-bambu-green animate-spin`})}):yn.length===0?(0,K.jsx)(`p`,{className:`text-center text-bambu-gray py-8`,children:i(`settings.noUsersFound`)}):(0,K.jsx)(`div`,{className:`divide-y divide-bambu-dark-tertiary`,children:yn.map(e=>(0,K.jsxs)(`div`,{className:`py-3 flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,K.jsx)(`p`,{className:`text-white font-medium truncate`,children:e.username}),(0,K.jsxs)(`div`,{className:`flex flex-wrap gap-1 mt-1`,children:[e.auth_source===`ldap`&&(0,K.jsx)(`span`,{className:`px-2 py-0.5 rounded-full text-xs font-medium bg-cyan-100 dark:bg-cyan-500/20 text-cyan-700 dark:text-cyan-300`,children:`LDAP`}),e.is_admin&&(0,K.jsx)(`span`,{className:`px-2 py-0.5 rounded-full text-xs font-medium bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-300`,children:i(`settings.admin`)}),e.groups?.map(e=>(0,K.jsx)(`span`,{className:`px-2 py-0.5 rounded-full text-xs font-medium ${e.name===`Administrators`?`bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-300`:e.name===`Operators`?`bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-300`:e.name===`Viewers`?`bg-green-100 dark:bg-green-500/20 text-green-700 dark:text-green-300`:`bg-gray-500/20 text-gray-300`}`,children:e.name},e.id))]})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-1 ml-4`,children:[d(`users:update`)&&(0,K.jsx)($,{size:`sm`,variant:`ghost`,onClick:()=>jn(e),children:(0,K.jsx)(Tl,{className:`w-4 h-4`})}),d(`users:delete`)&&e.id!==c?.id&&(0,K.jsx)($,{size:`sm`,variant:`ghost`,onClick:()=>Dn(e.id),children:(0,K.jsx)(Ou,{className:`w-4 h-4`})})]})]},e.id))})})]})]}),(0,K.jsx)(`div`,{children:(0,K.jsxs)(Od,{children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`h3`,{className:`text-lg font-semibold text-white flex items-center gap-2`,id:`card-groups`,children:[(0,K.jsx)(tu,{className:`w-5 h-5 text-bambu-green`}),i(`settings.groups`)]}),d(`groups:create`)&&(0,K.jsxs)($,{size:`sm`,onClick:()=>t(`/groups/new`),children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),i(`settings.addGroup`)]})]})}),(0,K.jsx)(Ad,{children:Sn?(0,K.jsx)(`div`,{className:`flex items-center justify-center py-8`,children:(0,K.jsx)(X,{className:`w-6 h-6 text-bambu-green animate-spin`})}):xn.length===0?(0,K.jsx)(`p`,{className:`text-center text-bambu-gray py-8`,children:i(`settings.noGroupsFound`)}):(0,K.jsx)(`div`,{className:`divide-y divide-bambu-dark-tertiary`,children:xn.map(e=>(0,K.jsxs)(`div`,{className:`py-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(tu,{className:`w-4 h-4 ${e.name===`Administrators`?`text-purple-600 dark:text-purple-400`:e.name===`Operators`?`text-blue-600 dark:text-blue-400`:e.name===`Viewers`?`text-green-600 dark:text-green-400`:`text-bambu-gray`}`}),(0,K.jsx)(`span`,{className:`text-white font-medium`,children:e.name}),e.is_system&&(0,K.jsx)(`span`,{className:`px-2 py-0.5 rounded text-xs bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400`,children:i(`settings.system`)})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-1`,children:[d(`groups:update`)&&(0,K.jsx)($,{size:`sm`,variant:`ghost`,onClick:()=>t(`/groups/${e.id}/edit`),children:(0,K.jsx)(Tl,{className:`w-4 h-4`})}),d(`groups:delete`)&&!e.is_system&&(0,K.jsx)($,{size:`sm`,variant:`ghost`,onClick:()=>pt(e.id),children:(0,K.jsx)(Ou,{className:`w-4 h-4`})})]})]}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mt-1 ml-6`,children:e.description||i(`settings.noDescription`)}),(0,K.jsxs)(`div`,{className:`flex items-center gap-4 mt-2 ml-6 text-xs text-bambu-gray`,children:[(0,K.jsx)(`span`,{children:i(`settings.userCount`,{count:e.user_count})}),(0,K.jsx)(`span`,{children:i(`settings.permissionCount`,{count:e.permissions.length})})]})]},e.id))})})]})})]}),!s&&(0,K.jsx)(Od,{children:(0,K.jsx)(Ad,{className:`py-6`,children:(0,K.jsxs)(`div`,{className:`text-center`,children:[(0,K.jsx)(Zc,{className:`w-12 h-12 text-bambu-gray mx-auto mb-4`}),(0,K.jsx)(`h3`,{className:`text-lg font-medium text-white mb-2`,children:i(`settings.authDisabledTitle`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mb-4 max-w-md mx-auto`,children:i(`settings.authDisabledMessage`)}),(0,K.jsxs)(`ul`,{className:`space-y-2 text-sm text-bambu-gray mb-6 text-left max-w-xs mx-auto`,children:[(0,K.jsxs)(`li`,{className:`flex items-start gap-2`,children:[(0,K.jsx)(_s,{className:`w-4 h-4 text-bambu-green mt-0.5 flex-shrink-0`}),(0,K.jsx)(`span`,{children:i(`settings.authDisabledFeature1`)})]}),(0,K.jsxs)(`li`,{className:`flex items-start gap-2`,children:[(0,K.jsx)(_s,{className:`w-4 h-4 text-bambu-green mt-0.5 flex-shrink-0`}),(0,K.jsx)(`span`,{children:i(`settings.authDisabledFeature2`)})]}),(0,K.jsxs)(`li`,{className:`flex items-start gap-2`,children:[(0,K.jsx)(_s,{className:`w-4 h-4 text-bambu-green mt-0.5 flex-shrink-0`}),(0,K.jsx)(`span`,{children:i(`settings.authDisabledFeature3`)})]})]}),(0,K.jsxs)($,{onClick:()=>t(`/setup`),children:[(0,K.jsx)(Qc,{className:`w-4 h-4`}),i(`settings.enableAuthentication`)]})]})})})]}),fe===`email`&&(0,K.jsx)(`div`,{className:`max-w-5xl`,id:`card-smtp`,children:(0,K.jsx)(UUe,{})}),fe===`ldap`&&(0,K.jsx)(`div`,{className:`max-w-5xl`,id:`card-ldap`,children:(0,K.jsx)(GUe,{})}),fe===`twofa`&&(0,K.jsx)(`div`,{className:`max-w-2xl`,children:(0,K.jsx)(qUe,{})}),fe===`oidc`&&l&&(0,K.jsxs)(`div`,{className:`max-w-3xl space-y-4`,children:[(0,K.jsx)(Od,{children:(0,K.jsx)(Ad,{className:`space-y-3 p-4`,children:(0,K.jsxs)(`label`,{className:`flex items-start gap-3 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.local_login_enabled===!1,onChange:e=>Gn(`local_login_enabled`,!e.target.checked),className:`mt-1 h-4 w-4 rounded border-bambu-dark-tertiary bg-bambu-dark-secondary text-bambu-green focus:ring-bambu-green/50 cursor-pointer`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-sm font-medium text-white`,children:i(`settings.localLogin.disable`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-0.5`,children:i(`settings.localLogin.disableHint`)})]})]})})}),(0,K.jsx)(XUe,{})]}),fe===`security`&&l&&(0,K.jsx)(`div`,{className:`max-w-3xl`,children:(0,K.jsx)(QUe,{})})]}),Xe&&!hn?.advanced_auth_enabled&&(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black flex items-center justify-center z-50 p-4`,onClick:()=>{Ze(!1),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]})},children:(0,K.jsxs)(Od,{className:`w-full max-w-md`,onClick:e=>e.stopPropagation(),children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(Lu,{className:`w-5 h-5 text-bambu-green`}),(0,K.jsx)(`h2`,{className:`text-lg font-semibold text-white`,children:i(`settings.createUser`)})]}),(0,K.jsx)($,{variant:`ghost`,size:`sm`,onClick:()=>{Ze(!1),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]})},children:(0,K.jsx)(Yu,{className:`w-5 h-5`})})]})}),(0,K.jsxs)(Ad,{children:[gn?.ldap_enabled&&(0,K.jsxs)(`div`,{className:`mb-4 flex items-center gap-1 p-1 bg-bambu-dark-secondary rounded-lg`,role:`tablist`,"aria-label":i(`users.modal.tabsAriaLabel`),children:[(0,K.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":Qe===`local`,onClick:()=>$e(`local`),className:`flex-1 px-3 py-2 text-sm rounded-md transition-colors ${Qe===`local`?`bg-bambu-green/15 text-bambu-green`:`text-bambu-gray hover:text-white`}`,children:i(`users.modal.localTab`)}),(0,K.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":Qe===`ldap`,onClick:()=>$e(`ldap`),className:`flex-1 px-3 py-2 text-sm rounded-md transition-colors ${Qe===`ldap`?`bg-bambu-green/15 text-bambu-green`:`text-bambu-gray hover:text-white`}`,children:i(`users.modal.ldapTab`)})]}),Qe===`ldap`&&gn?.ldap_enabled?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(r6,{onSuccess:e=>{Ze(!1),$e(`local`),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]}),o(i(`users.toast.ldapProvisioned`,{username:e.username}))}}),(0,K.jsx)(`div`,{className:`mt-6 flex justify-end`,children:(0,K.jsx)($,{variant:`secondary`,onClick:()=>{Ze(!1),$e(`local`),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]})},children:i(`common.cancel`)})})]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm font-medium text-white mb-2`,children:i(`settings.username`)}),(0,K.jsx)(`input`,{type:`text`,value:ut.username,onChange:e=>dt({...ut,username:e.target.value}),className:`w-full px-4 py-3 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors`,placeholder:i(`settings.enterUsername`),autoComplete:`username`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm font-medium text-white mb-2`,children:i(`settings.password`)}),(0,K.jsx)(`input`,{type:`password`,value:ut.password,onChange:e=>dt({...ut,password:e.target.value}),className:`w-full px-4 py-3 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors`,placeholder:i(`settings.enterPassword`),autoComplete:`new-password`,minLength:8}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-xs mt-1`,children:i(`settings.passwordRequirements`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm font-medium text-white mb-2`,children:i(`settings.confirmPassword`)}),(0,K.jsx)(`input`,{type:`password`,value:ut.confirmPassword,onChange:e=>dt({...ut,confirmPassword:e.target.value}),className:`w-full px-4 py-3 bg-bambu-dark-secondary border rounded-lg text-white placeholder-bambu-gray focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors ${ut.confirmPassword&&ut.password!==ut.confirmPassword?`border-red-500`:`border-bambu-dark-tertiary`}`,placeholder:i(`settings.confirmPasswordPlaceholder`),autoComplete:`new-password`,minLength:6}),ut.confirmPassword&&ut.password!==ut.confirmPassword&&(0,K.jsx)(`p`,{className:`text-red-700 dark:text-red-400 text-xs mt-1`,children:i(`settings.passwordsDoNotMatch`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm font-medium text-white mb-2`,children:i(`settings.groups`)}),(0,K.jsxs)(`div`,{className:`space-y-2 max-h-40 overflow-y-auto p-2 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg`,children:[xn.map(e=>(0,K.jsxs)(`label`,{className:`flex items-center gap-3 px-2 py-1.5 rounded hover:bg-bambu-dark-tertiary cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:ut.group_ids.includes(e.id),onChange:()=>Mn(e.id),className:`w-4 h-4 rounded border-bambu-gray text-bambu-green focus:ring-bambu-green focus:ring-offset-0 bg-bambu-dark`}),(0,K.jsx)(`span`,{className:`text-sm text-white`,children:e.name}),e.is_system&&(0,K.jsx)(`span`,{className:`text-xs text-yellow-700 dark:text-yellow-400`,children:i(`settings.systemBadge`)})]},e.id)),xn.length===0&&(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.noGroupsAvailable`)})]})]})]}),(0,K.jsxs)(`div`,{className:`mt-6 flex justify-end gap-3`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:()=>{Ze(!1),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]})},children:i(`common.cancel`)}),(0,K.jsx)($,{onClick:kn,disabled:Cn.isPending||!ut.username||!ut.password||ut.password!==ut.confirmPassword||k3(ut.password)!==null,children:Cn.isPending?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}),i(`settings.creating`)]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),i(`settings.createUser`)]})})]})]})]})]})}),Xe&&hn?.advanced_auth_enabled&&(0,K.jsx)(pUe,{formData:ut,setFormData:dt,groups:xn,onClose:()=>{Ze(!1),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]})},onCreate:kn,isCreating:Cn.isPending,isCreateButtonDisabled:Cn.isPending||!ut.username||!ut.email,ldapEnabled:gn?.ldap_enabled,onLdapProvisioned:e=>{Ze(!1),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]}),o(i(`users.toast.ldapProvisioned`,{username:e.username}))}}),et&&nt!==null&&(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black flex items-center justify-center z-50 p-4`,onClick:()=>{tt(!1),rt(null),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]})},children:(0,K.jsxs)(Od,{className:`w-full max-w-md`,onClick:e=>e.stopPropagation(),children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(Tl,{className:`w-5 h-5 text-bambu-green`}),(0,K.jsx)(`h2`,{className:`text-lg font-semibold text-white`,children:i(`settings.editUser`)})]}),(0,K.jsx)($,{variant:`ghost`,size:`sm`,onClick:()=>{tt(!1),rt(null),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]})},children:(0,K.jsx)(Yu,{className:`w-5 h-5`})})]})}),(0,K.jsxs)(Ad,{children:[(0,K.jsxs)(`div`,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:`block text-sm font-medium text-white mb-2`,children:[i(`settings.username`),` `,hn?.advanced_auth_enabled&&(0,K.jsx)(`span`,{className:`text-red-700 dark:text-red-400`,children:`*`})]}),(0,K.jsx)(`input`,{type:`text`,value:ut.username,onChange:e=>dt({...ut,username:e.target.value}),className:`w-full px-4 py-3 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors`,placeholder:i(`settings.enterUsername`),autoComplete:`username`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:`block text-sm font-medium text-white mb-2`,children:[i(`users.form.email`)||`Email`,` `,hn?.advanced_auth_enabled?(0,K.jsx)(`span`,{className:`text-red-700 dark:text-red-400`,children:`*`}):(0,K.jsxs)(`span`,{className:`text-bambu-gray font-normal`,children:[`(`,i(`users.form.optional`)||`optional`,`)`]})]}),(0,K.jsx)(`input`,{type:`email`,value:ut.email,onChange:e=>dt({...ut,email:e.target.value}),className:`w-full px-4 py-3 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors`,placeholder:i(`users.form.emailPlaceholder`)||`user@example.com`,required:hn?.advanced_auth_enabled})]}),!hn?.advanced_auth_enabled&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:`block text-sm font-medium text-white mb-2`,children:[i(`users.form.password`)||`Password`,` `,(0,K.jsxs)(`span`,{className:`text-bambu-gray font-normal`,children:[`(`,i(`users.form.leaveBlankToKeep`)||`leave blank to keep current`,`)`]})]}),(0,K.jsx)(`input`,{type:`password`,value:ut.password,onChange:e=>dt({...ut,password:e.target.value,confirmPassword:``}),className:`w-full px-4 py-3 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors`,placeholder:i(`settings.enterNewPassword`),autoComplete:`new-password`,minLength:8}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-xs mt-1`,children:i(`settings.passwordRequirements`)})]}),ut.password&&(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm font-medium text-white mb-2`,children:i(`settings.confirmPassword`)}),(0,K.jsx)(`input`,{type:`password`,value:ut.confirmPassword,onChange:e=>dt({...ut,confirmPassword:e.target.value}),className:`w-full px-4 py-3 bg-bambu-dark-secondary border rounded-lg text-white placeholder-bambu-gray focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors ${ut.confirmPassword&&ut.password!==ut.confirmPassword?`border-red-500`:`border-bambu-dark-tertiary`}`,placeholder:i(`settings.confirmNewPassword`),autoComplete:`new-password`,minLength:6}),ut.confirmPassword&&ut.password!==ut.confirmPassword&&(0,K.jsx)(`p`,{className:`text-red-700 dark:text-red-400 text-xs mt-1`,children:i(`settings.passwordsDoNotMatch`)})]})]}),hn?.advanced_auth_enabled&&(0,K.jsxs)(`div`,{className:`bg-bambu-dark-secondary/50 border border-bambu-green/20 rounded-lg p-3 space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`users.form.passwordManagedByAdvancedAuth`)||`Password is managed by Advanced Authentication. Use "Reset Password" to send a new password to the user via email.`}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>nt&&En.mutate(nt),disabled:En.isPending||!ut.email,className:`w-full`,children:En.isPending?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}),i(`users.form.resettingPassword`)||`Resetting Password...`]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(Rl,{className:`w-4 h-4`}),i(`users.form.resetPassword`)||`Reset Password`]})})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm font-medium text-white mb-2`,children:i(`users.form.groups`)||`Groups`}),(0,K.jsx)(`div`,{className:`space-y-2 max-h-40 overflow-y-auto p-2 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg`,children:xn.map(e=>(0,K.jsxs)(`label`,{className:`flex items-center gap-3 px-2 py-1.5 rounded hover:bg-bambu-dark-tertiary cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:ut.group_ids.includes(e.id),onChange:()=>Mn(e.id),className:`w-4 h-4 rounded border-bambu-gray text-bambu-green focus:ring-bambu-green focus:ring-offset-0 bg-bambu-dark`}),(0,K.jsx)(`span`,{className:`text-sm text-white`,children:e.name}),e.is_system&&(0,K.jsxs)(`span`,{className:`text-xs text-yellow-700 dark:text-yellow-400`,children:[`(`,i(`users.system`)||`System`,`)`]})]},e.id))})]})]}),(0,K.jsxs)(`div`,{className:`mt-6 flex justify-end gap-3`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:()=>{tt(!1),rt(null),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]})},children:i(`users.modal.cancel`)||`Cancel`}),(0,K.jsx)($,{onClick:()=>An(nt),disabled:wn.isPending||!ut.username||hn?.advanced_auth_enabled&&!ut.email||!!(!hn?.advanced_auth_enabled&&ut.password&&(ut.password!==ut.confirmPassword||k3(ut.password)!==null)),children:wn.isPending?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}),i(`users.modal.saving`)||`Saving...`]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(Vl,{className:`w-4 h-4`}),i(`users.modal.saveChanges`)||`Save Changes`]})})]})]})]})}),it!==null&&(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/80 flex items-center justify-center z-50 p-4`,onClick:()=>{at(null),st(null)},children:(0,K.jsxs)(Od,{className:`w-full max-w-md`,onClick:e=>e.stopPropagation(),children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-red-700 dark:text-red-400`,children:[(0,K.jsx)(Ou,{className:`w-5 h-5`}),(0,K.jsx)(`h3`,{className:`text-lg font-semibold`,children:i(`settings.deleteUserTitle`)})]})}),(0,K.jsx)(Ad,{className:`space-y-3`,children:ct?(0,K.jsx)(`div`,{className:`flex items-center justify-center py-4`,children:(0,K.jsx)(`div`,{className:`animate-spin rounded-full h-6 w-6 border-2 border-bambu-green border-t-transparent`})}):ot&&ot.archives+ot.queue_items+ot.library_files>0?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.userHasCreated`)}),(0,K.jsxs)(`ul`,{className:`list-disc list-inside text-bambu-gray space-y-1`,children:[ot.archives>0&&(0,K.jsxs)(`li`,{children:[ot.archives,` archive`,ot.archives===1?``:`s`]}),ot.queue_items>0&&(0,K.jsxs)(`li`,{children:[ot.queue_items,` queue item`,ot.queue_items===1?``:`s`]}),ot.library_files>0&&(0,K.jsxs)(`li`,{children:[ot.library_files,` library file`,ot.library_files===1?``:`s`]})]}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-sm`,children:i(`settings.userItemsQuestion`)}),(0,K.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[(0,K.jsx)($,{variant:`danger`,onClick:()=>Tn.mutate({id:it,deleteItems:!0}),disabled:Tn.isPending,className:`justify-center`,children:i(`settings.deleteUserAndItems`)}),(0,K.jsx)($,{variant:`secondary`,onClick:()=>Tn.mutate({id:it,deleteItems:!1}),disabled:Tn.isPending,className:`justify-center`,children:i(`settings.deleteUserKeepItems`)}),(0,K.jsx)($,{variant:`ghost`,onClick:()=>{at(null),st(null)},disabled:Tn.isPending,className:`justify-center`,children:i(`common.cancel`)})]})]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.deleteUserConfirm`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-sm`,children:i(`settings.actionCannotBeUndone`)}),(0,K.jsxs)(`div`,{className:`flex gap-2 justify-end`,children:[(0,K.jsx)($,{variant:`ghost`,onClick:()=>{at(null),st(null)},disabled:Tn.isPending,children:i(`common.cancel`)}),(0,K.jsx)($,{variant:`danger`,onClick:()=>Tn.mutate({id:it,deleteItems:!1}),disabled:Tn.isPending,children:i(`settings.deleteUserTitle`)})]})]})})]})}),ft!==null&&(0,K.jsx)(Gd,{title:i(`settings.deleteGroupTitle`),message:i(`settings.deleteGroupMessage`),confirmText:i(`settings.deleteGroup`),variant:`danger`,onConfirm:()=>{On.mutate(ft),pt(null)},onCancel:()=>pt(null)}),ue===`failure-detection`&&(0,K.jsx)(`div`,{id:`card-failure-detection`,children:(0,K.jsx)(BUe,{})}),ue===`backup`&&(0,K.jsxs)(`div`,{id:`card-backup`,children:[(0,K.jsxs)(`div`,{className:`mb-4 p-3 bg-amber-50 dark:bg-amber-500/10 border border-amber-300 dark:border-amber-500/30 rounded-lg flex items-start gap-2`,children:[(0,K.jsx)(tu,{className:`text-amber-600 dark:text-amber-400 flex-shrink-0 mt-0.5`,size:16}),(0,K.jsx)(`p`,{className:`text-sm text-amber-700 dark:text-amber-400`,children:i(`backup.includesEncryptionKey`)})]}),(0,K.jsx)(zUe,{})]}),Be&&(0,K.jsx)(Gd,{title:i(`settings.disableAuthenticationTitle`),message:i(`settings.disableAuthenticationMessage`),confirmText:i(`settings.disableAuthentication`),variant:`danger`,onConfirm:async()=>{try{await Q.disableAuth(),o(i(`settings.toast.authDisabled`),`success`),await u(),Ve(!1),window.location.href=`/`}catch(e){o(e instanceof Error?e.message:i(`settings.toast.authDisableFailed`),`error`)}},onCancel:()=>Ve(!1)}),He&&(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/70 flex items-center justify-center z-50 p-4`,onClick:()=>{Ue(!1),Ge({currentPassword:``,newPassword:``,confirmPassword:``})},children:(0,K.jsxs)(Od,{className:`w-full max-w-md`,onClick:e=>e.stopPropagation(),children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(Vc,{className:`w-5 h-5 text-bambu-green`}),(0,K.jsx)(`h2`,{className:`text-lg font-semibold text-white`,children:i(`settings.changePassword`)})]}),(0,K.jsx)($,{variant:`ghost`,size:`sm`,onClick:()=>{Ue(!1),Ge({currentPassword:``,newPassword:``,confirmPassword:``})},children:(0,K.jsx)(Yu,{className:`w-5 h-5`})})]})}),(0,K.jsxs)(Ad,{children:[(0,K.jsxs)(`div`,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm font-medium text-white mb-2`,children:`Current Password`}),(0,K.jsx)(`input`,{type:`password`,value:We.currentPassword,onChange:e=>Ge({...We,currentPassword:e.target.value}),className:`w-full px-4 py-3 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors`,placeholder:i(`settings.enterCurrentPassword`),autoComplete:`current-password`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm font-medium text-white mb-2`,children:`New Password`}),(0,K.jsx)(`input`,{type:`password`,value:We.newPassword,onChange:e=>Ge({...We,newPassword:e.target.value}),className:`w-full px-4 py-3 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors`,placeholder:i(`settings.enterNewPasswordMin6`),autoComplete:`new-password`,minLength:6})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm font-medium text-white mb-2`,children:`Confirm New Password`}),(0,K.jsx)(`input`,{type:`password`,value:We.confirmPassword,onChange:e=>Ge({...We,confirmPassword:e.target.value}),className:`w-full px-4 py-3 bg-bambu-dark-secondary border rounded-lg text-white placeholder-bambu-gray focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors ${We.confirmPassword&&We.newPassword!==We.confirmPassword?`border-red-500`:`border-bambu-dark-tertiary`}`,placeholder:i(`settings.confirmNewPassword`),autoComplete:`new-password`,minLength:6}),We.confirmPassword&&We.newPassword!==We.confirmPassword&&(0,K.jsx)(`p`,{className:`text-red-700 dark:text-red-400 text-xs mt-1`,children:i(`settings.passwordsDoNotMatch`)})]})]}),(0,K.jsxs)(`div`,{className:`mt-6 flex justify-end gap-3`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:()=>{Ue(!1),Ge({currentPassword:``,newPassword:``,confirmPassword:``})},children:i(`common.cancel`)}),(0,K.jsx)($,{onClick:async()=>{if(We.newPassword!==We.confirmPassword){o(i(`settings.toast.passwordsDoNotMatch`),`error`);return}if(We.newPassword.length<6){o(i(`settings.toast.passwordTooShort`),`error`);return}qe(!0);try{await Q.changePassword(We.currentPassword,We.newPassword),o(i(`settings.toast.passwordChanged`),`success`),Ue(!1),Ge({currentPassword:``,newPassword:``,confirmPassword:``})}catch(e){o(e instanceof Error?e.message:`Failed to change password`,`error`)}finally{qe(!1)}},disabled:Ke||!We.currentPassword||!We.newPassword||We.newPassword!==We.confirmPassword||We.newPassword.length<6,children:Ke?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}),i(`settings.changing`)]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(Vc,{className:`w-4 h-4`}),i(`settings.changePassword`)]})})]})]})]})})]})]})]})})}var O6={PLA:`GFL99`,"PLA-CF":`GFL98`,"PLA SILK":`GFL96`,"PLA HIGH SPEED":`GFL95`,PETG:`GFG99`,"PETG HF":`GFG96`,"PETG-CF":`GFG98`,PCTG:`GFG97`,ABS:`GFB99`,ASA:`GFB98`,PC:`GFC99`,PA:`GFN99`,"PA-CF":`GFN98`,NYLON:`GFN99`,TPU:`GFU99`,PVA:`GFS99`,HIPS:`GFS98`,PE:`GFP99`,PP:`GFP97`};function k6(e){let t=(e||``).toUpperCase().trim();return t&&(O6[t]||O6[t.replace(/[-\s]?CF$/,``)]||O6[t.replace(/\+$/,``)]||O6[t.split(/[-\s]/)[0]])||``}function A6(e){let t=e.replace(/@.+$/,``).trim();return t.startsWith(`# `)?t.slice(2).trim():t}var j6={local:0,orca_cloud:1,cloud:2,builtin:3};function oWe(e){let{localPresets:t,orcaProfiles:n,cloudSettings:r,builtinFilaments:i}=e,a=[],o=e=>e.trim().toLowerCase(),s=new Set,c=new Set,l=new Set,u=(e,t,...n)=>{let r=n.filter(e=>!!e);if(r.some(e=>s.has(e)))return!1;let i=`${e}|${o(t)}`;return c.has(i)?!1:(r.forEach(e=>s.add(e)),c.add(i),l.add(o(t)),!0)};for(let e of t??[]){let t=A6(e.name),n=e.filament_type||kU(t).material;u(`local`,t)&&a.push({id:`local_${e.id}`,name:t,source:`local`,filamentId:k6(n),filamentType:n||``})}for(let e of n??[]){let t=A6(e.name),n=kU(t).material;u(`orca_cloud`,t,e.setting_id)&&a.push({id:`orca_${e.setting_id}`,name:t,source:`orca_cloud`,filamentId:k6(n),filamentType:n})}for(let e of r??[]){let t=A6(e.name),n=e.setting_id.startsWith(`GFS`)?LU(e.setting_id):``;u(`cloud`,t,e.setting_id,n||void 0)&&a.push({id:e.setting_id,name:t,source:`cloud`,filamentId:n,filamentType:kU(t).material})}for(let e of i??[]){let t=e.filament_id.startsWith(`GF`)?`GFS${e.filament_id.slice(2)}`:e.filament_id;l.has(o(e.name))||u(`builtin`,e.name,e.filament_id,t)&&a.push({id:`builtin_${e.filament_id}`,name:e.name,source:`builtin`,filamentId:e.filament_id,filamentType:kU(e.name).material})}return a.sort((e,t)=>e.source===t.source?e.name.localeCompare(t.name):j6[e.source]-j6[t.source])}async function sWe(e,t){if(e.filamentId)return e.filamentId;if(e.source!==`cloud`||!t)return``;try{return(await t(e.id)).filament_id||``}catch{return``}}var M6=e=>(Math.trunc(parseFloat(e)*1e3)/1e3).toFixed(3),N6=`HS00`,P6=`HH00`,F6=e=>{let t=e.match(/^([A-Z]{2}\d{2})/);return t?t[1]:N6},cWe=e=>F6(e)===P6?`HF`:`S`,I6=e=>{for(let t of[`High Flow_`,`High Flow `,`Standard_`,`Standard `,`HF_`,`HF `,`S_`,`S `])if(e.startsWith(t))return e.slice(t.length);let t=e.indexOf(`_`);return t>0?e.slice(t+1):e};function L6({profile:e,onEdit:t,onCopy:n,selectionMode:r,isSelected:i,onToggleSelect:a,note:o}){let s=cWe(e.nozzle_id),c=e.nozzle_diameter;return(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[r&&(0,K.jsx)(`button`,{onClick:a,className:`text-bambu-gray hover:text-white transition-colors p-1`,children:i?(0,K.jsx)(fu,{className:`w-4 h-4 text-bambu-green`}):(0,K.jsx)(mu,{className:`w-4 h-4`})}),(0,K.jsxs)(`button`,{onClick:()=>{r&&a?a():t()},className:`flex-1 text-left px-3 py-2 bg-bambu-dark rounded hover:bg-bambu-dark-tertiary transition-colors ${i?`ring-1 ring-bambu-green`:``}`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`span`,{className:`text-bambu-green font-mono text-sm font-bold whitespace-nowrap`,children:M6(e.k_value)}),(0,K.jsx)(`span`,{className:`text-white text-sm truncate flex-1`,title:e.name,children:e.name||`Unnamed`}),o&&(0,K.jsx)(`span`,{title:`Has note`,children:(0,K.jsx)(_u,{className:`w-3 h-3 text-yellow-500`})}),(0,K.jsxs)(`span`,{className:`text-xs text-bambu-gray whitespace-nowrap`,children:[s,` `,c]})]}),o&&(0,K.jsxs)(`div`,{className:`text-xs mt-0.5 truncate text-yellow-500/70`,title:o,children:[`Note: `,o.length>50?o.substring(0,50)+`...`:o]})]}),!r&&n&&(0,K.jsx)(`button`,{onClick:e=>{e.stopPropagation(),n()},className:`text-bambu-gray hover:text-white transition-colors p-1`,title:`Copy profile`,children:(0,K.jsx)(Ls,{className:`w-4 h-4`})})]})}function R6({profile:e,printerId:t,nozzleDiameter:n,existingProfiles:r=[],builtinFilaments:i=[],filamentPresets:a=[],isDualNozzle:o=!1,supportsFlowType:s=!0,initialNote:c=``,initialNoteKey:l=null,onClose:u,onSave:d,onSaveNote:f,hasPermission:p}){let{t:m}=W(),{showToast:h}=Id(),[g,_]=(0,y.useState)(e?.name||``),[v,b]=(0,y.useState)(e?.k_value?M6(e.k_value):`0.020`),[x,S]=(0,y.useState)(e?.filament_id||``),[C,w]=(0,y.useState)(e?F6(e.nozzle_id):N6),[T,E]=(0,y.useState)(e?.nozzle_diameter||n),[D,O]=(0,y.useState)(e?[e.extruder_id]:o?[0,1]:[0]),[k,A]=(0,y.useState)(!1),[j,M]=(0,y.useState)({current:0,total:0}),[N,P]=(0,y.useState)(c),[F,I]=(0,y.useState)(``),{schedule:L}=BU(),R=y.useMemo(()=>e?.filament_id?i.find(t=>t.filament_id===e.filament_id)?.name||I6(r.find(t=>t.filament_id===e.filament_id)?.name||e.name||``)||e.filament_id:``,[e,r,i]),z=y.useMemo(()=>{let e=[[`local`,m(`kProfiles.modal.source.local`)],[`orca_cloud`,m(`kProfiles.modal.source.orcaCloud`)],[`cloud`,m(`kProfiles.modal.source.bambuCloud`)],[`builtin`,m(`kProfiles.modal.source.builtin`)]],t=F.trim().toLowerCase(),n=t?a.filter(e=>e.name.toLowerCase().includes(t)):a;return e.map(([e,t])=>({source:e,label:t,items:n.filter(t=>t.source===e)})).filter(e=>e.items.length>0)},[a,F,m]),B=J({mutationFn:e=>(console.log(`[KProfile] Calling API...`),Q.setKProfile(t,e)),onSuccess:(t,n)=>{if(console.log(`[KProfile] Save success:`,t),h(m(`kProfiles.toast.profileSaved`)),f&&N!==c){let t;t=N===``&&l?l:e&&e.slot_id>0?e.setting_id||`slot_${e.slot_id}_${e.filament_id}_${e.extruder_id}`:`name_${g}_${n.filament_id}`,f(t,N)}A(!0),L(()=>{A(!1),d()},2500)},onError:e=>{console.error(`[KProfile] Save error:`,e),h(e.message,`error`),A(!1)}}),V=J({mutationFn:e=>(console.log(`[KProfile] Deleting profile...`),Q.deleteKProfile(t,e)),onSuccess:e=>{console.log(`[KProfile] Delete success:`,e),h(m(`kProfiles.toast.profileDeleted`)),A(!0),L(()=>{A(!1),u()},4e3)},onError:e=>{console.error(`[KProfile] Delete error:`,e),h(e.message,`error`),A(!1)}}),[ee,te]=(0,y.useState)(!1),ne=()=>{e&&V.mutate({slot_id:e.slot_id,extruder_id:e.extruder_id,nozzle_id:e.nozzle_id,nozzle_diameter:e.nozzle_diameter,filament_id:e.filament_id,setting_id:e.setting_id})};return(0,K.jsxs)(`div`,{className:`fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4`,children:[(0,K.jsxs)(Od,{className:`w-full max-w-md relative`,children:[k&&(0,K.jsxs)(`div`,{className:`absolute inset-0 bg-bambu-dark-secondary/90 flex flex-col items-center justify-center z-10 rounded-lg`,children:[(0,K.jsx)(X,{className:`w-8 h-8 text-bambu-green animate-spin mb-3`}),(0,K.jsx)(`p`,{className:`text-white font-medium`,children:j.total>1?m(`kProfiles.modal.savingExtruder`,{current:j.current,total:j.total}):m(`kProfiles.modal.syncing`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-sm mt-1`,children:m(`kProfiles.modal.pleaseWait`)})]}),(0,K.jsxs)(Ad,{className:`p-0`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between p-4 border-b border-bambu-dark-tertiary`,children:[(0,K.jsx)(`h2`,{className:`text-xl font-semibold text-white`,children:m(e?`kProfiles.modal.editTitle`:`kProfiles.modal.addTitle`)}),(0,K.jsx)(`button`,{onClick:u,className:`text-bambu-gray hover:text-white transition-colors`,disabled:k,children:(0,K.jsx)(Yu,{className:`w-5 h-5`})})]}),(0,K.jsxs)(`form`,{onSubmit:async n=>{if(n.preventDefault(),o&&!e&&D.length===0){h(m(`kProfiles.toast.selectAtLeastOneExtruder`),`error`);return}let r=parseFloat(v).toFixed(6),i=`${C}-${T}`,s=e&&e.nozzle_id||i,c=e?e.nozzle_diameter:T,l=e?.filament_id||``;if(!e){let e=a.find(e=>e.id===x);if(!e){h(m(`kProfiles.toast.selectFilament`),`error`);return}if(l=await sWe(e,Q.getCloudSettingDetail),!l){h(m(`kProfiles.toast.filamentNotResolvable`,{name:e.name}),`error`);return}}if(e||D.length===1){let t={name:g,k_value:r,filament_id:l,nozzle_id:s,nozzle_diameter:c,extruder_id:e?e.extruder_id:D[0],setting_id:e?.setting_id,slot_id:e?.slot_id??0};console.log(`[KProfile] Saving profile:`,t),B.mutate(t);return}A(!0),M({current:1,total:D.length});let u=D.map(e=>({name:g,k_value:r,filament_id:l,nozzle_id:i,nozzle_diameter:T,extruder_id:e,setting_id:void 0,slot_id:0}));console.log(`[KProfile] Saving ${u.length} profiles in batch:`,u);try{await Q.setKProfilesBatch(t,u),h(m(`kProfiles.toast.profilesSaved`,{count:D.length})),f&&N&&f(`name_${g}_${l}`,N)}catch(e){console.error(`[KProfile] Failed to save batch:`,e),h(m(`kProfiles.toast.failedToSaveBatch`),`error`),A(!1),M({current:0,total:0});return}M({current:D.length,total:D.length}),L(()=>{A(!1),M({current:0,total:0}),d()},3e3)},className:`p-4 space-y-4`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:m(`kProfiles.modal.profileName`)}),(0,K.jsx)(`input`,{type:`text`,value:g,onChange:e=>_(e.target.value),disabled:!!e,className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none ${e?`opacity-60 cursor-not-allowed`:``}`,placeholder:m(`kProfiles.modal.profileNamePlaceholder`),required:!e})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:m(`kProfiles.modal.kValue`)}),(0,K.jsx)(`input`,{type:`text`,inputMode:`decimal`,value:v,onChange:e=>{let t=e.target.value;(t===``||/^\d*\.?\d*$/.test(t))&&b(t)},onBlur:e=>{let t=parseFloat(e.target.value);isNaN(t)||b((Math.trunc(t*1e3)/1e3).toFixed(3))},className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none font-mono`,placeholder:m(`kProfiles.modal.kValuePlaceholder`),required:!0}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:m(`kProfiles.modal.kValueHelp`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:m(`kProfiles.modal.filament`)}),e?(0,K.jsx)(`div`,{className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white opacity-60`,children:R||e.filament_id}):(0,K.jsxs)(`div`,{className:`border border-bambu-dark-tertiary rounded-lg overflow-hidden`,children:[(0,K.jsxs)(`div`,{className:`relative border-b border-bambu-dark-tertiary`,children:[(0,K.jsx)(Kl,{className:`absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray`}),(0,K.jsx)(`input`,{type:`text`,value:F,onChange:e=>I(e.target.value),placeholder:m(`kProfiles.modal.searchFilaments`),className:`w-full pl-10 pr-3 py-2 bg-bambu-dark text-white placeholder-bambu-gray focus:outline-none`})]}),(0,K.jsx)(`div`,{className:`max-h-56 overflow-y-auto bg-bambu-dark`,children:z.length===0?(0,K.jsx)(`p`,{className:`px-3 py-3 text-xs text-bambu-gray`,children:a.length===0?m(`kProfiles.modal.noFilamentsHelp`):m(`kProfiles.modal.noFilamentMatches`)}):z.map(e=>(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`div`,{className:`sticky top-0 z-10 flex items-center gap-2 px-3 py-1.5 bg-bambu-dark-secondary border-y border-bambu-dark-tertiary`,children:[(0,K.jsx)(`span`,{className:`text-xs font-bold uppercase tracking-wider text-bambu-green`,children:e.label}),(0,K.jsx)(`span`,{className:`text-[10px] text-bambu-gray`,children:e.items.length})]}),e.items.map(e=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>{S(e.id),g||_(`${C===P6?`HF`:`S`} ${e.name}`)},className:`w-full text-left px-3 py-1.5 text-sm transition-colors ${x===e.id?`bg-bambu-green/20 text-white`:`text-white hover:bg-bambu-dark-tertiary`}`,children:e.name},e.id))]},e.source))})]})]}),(0,K.jsxs)(`div`,{className:s?`grid grid-cols-2 gap-4`:``,children:[(0,K.jsxs)(`div`,{className:s?``:`hidden`,children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:m(`kProfiles.modal.flowType`)}),(0,K.jsxs)(`select`,{value:C,onChange:t=>{let n=t.target.value;if(w(n),!e&&x&&!g){let e=a.find(e=>e.id===x);e&&_(`${n===P6?`HF`:`S`} ${e.name}`)}},disabled:!!e,className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none ${e?`opacity-60 cursor-not-allowed`:``}`,children:[(0,K.jsx)(`option`,{value:P6,children:m(`kProfiles.modal.highFlow`)}),(0,K.jsx)(`option`,{value:N6,children:m(`kProfiles.modal.standard`)})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:m(`kProfiles.modal.nozzleSize`)}),(0,K.jsxs)(`select`,{value:T,onChange:e=>E(e.target.value),disabled:!!e,className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none ${e?`opacity-60 cursor-not-allowed`:``}`,children:[(0,K.jsx)(`option`,{value:`0.2`,children:`0.2mm`}),(0,K.jsx)(`option`,{value:`0.4`,children:`0.4mm`}),(0,K.jsx)(`option`,{value:`0.6`,children:`0.6mm`}),(0,K.jsx)(`option`,{value:`0.8`,children:`0.8mm`})]})]})]}),o&&(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:m(e?`kProfiles.modal.extruder`:`kProfiles.modal.extruders`)}),e?(0,K.jsx)(`div`,{className:`px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white opacity-60`,children:e.extruder_id===1?m(`kProfiles.modal.left`):m(`kProfiles.modal.right`)}):(0,K.jsxs)(`div`,{className:`flex gap-4`,children:[(0,K.jsxs)(`label`,{className:`flex items-center gap-2 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:D.includes(1),onChange:e=>{e.target.checked?O([...D,1]):O(D.filter(e=>e!==1))},className:`w-4 h-4 rounded border-bambu-dark-tertiary bg-bambu-dark text-bambu-green focus:ring-bambu-green focus:ring-offset-0 accent-bambu-green`}),(0,K.jsx)(`span`,{className:`text-white`,children:m(`kProfiles.modal.left`)})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-2 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:D.includes(0),onChange:e=>{e.target.checked?O([...D,0]):O(D.filter(e=>e!==0))},className:`w-4 h-4 rounded border-bambu-dark-tertiary bg-bambu-dark text-bambu-green focus:ring-bambu-green focus:ring-offset-0 accent-bambu-green`}),(0,K.jsx)(`span`,{className:`text-white`,children:m(`kProfiles.modal.right`)})]})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:m(`kProfiles.modal.notes`)}),(0,K.jsx)(`textarea`,{value:N,onChange:e=>P(e.target.value),placeholder:m(`kProfiles.modal.notesPlaceholder`),rows:2,className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none resize-none`}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:m(`kProfiles.modal.notesHelp`)})]}),(0,K.jsxs)(`div`,{className:`flex gap-2 pt-4`,children:[e&&(0,K.jsx)($,{type:`button`,variant:`secondary`,onClick:()=>te(!0),disabled:V.isPending||k||!p(`kprofiles:delete`),title:p(`kprofiles:delete`)?void 0:m(`kProfiles.permission.noDelete`),className:`text-red-500 hover:bg-red-500/10`,children:V.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(Ou,{className:`w-4 h-4`})}),(0,K.jsx)($,{type:`button`,variant:`secondary`,onClick:u,disabled:k,className:`flex-1`,children:m(`common.cancel`)}),(0,K.jsxs)($,{type:`submit`,disabled:B.isPending||k||!p(e?`kprofiles:update`:`kprofiles:create`),title:p(e?`kprofiles:update`:`kprofiles:create`)?void 0:m(e?`kProfiles.permission.noUpdate`:`kProfiles.permission.noCreate`),className:`flex-1`,children:[B.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(bc,{className:`w-4 h-4`}),m(`common.save`)]})]})]})]})]}),ee&&(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/70 flex items-center justify-center z-[60]`,children:(0,K.jsx)(Od,{className:`w-full max-w-sm`,children:(0,K.jsxs)(Ad,{className:`p-6`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-3 mb-4`,children:[(0,K.jsx)(`div`,{className:`w-10 h-10 rounded-full bg-red-500/20 flex items-center justify-center`,children:(0,K.jsx)(Ou,{className:`w-5 h-5 text-red-500`})}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`text-lg font-semibold text-white`,children:m(`kProfiles.deleteConfirm.title`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:m(`kProfiles.deleteConfirm.cannotUndo`)})]})]}),(0,K.jsx)(`p`,{className:`text-bambu-gray mb-6`,children:m(`kProfiles.deleteConfirm.message`,{name:e?.name})}),(0,K.jsxs)(`div`,{className:`flex gap-3`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:()=>te(!1),className:`flex-1`,children:m(`common.cancel`)}),(0,K.jsxs)($,{onClick:()=>{te(!1),ne()},disabled:V.isPending,className:`flex-1 bg-red-500 hover:bg-red-600 text-white`,children:[V.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(Ou,{className:`w-4 h-4`}),m(`common.delete`)]})]})]})})})]})}var z6={NOZZLE_DIAMETER:`bambusy_kprofiles_nozzle`,SORT_OPTION:`bambusy_kprofiles_sort`};function lWe(){let{t:e}=W(),{showToast:t}=Id(),{hasPermission:n}=Sd(),[r,i]=(0,y.useState)(null),[a,o]=(0,y.useState)(()=>localStorage.getItem(z6.NOZZLE_DIAMETER)||`0.4`),[s,c]=(0,y.useState)(null),[l,u]=(0,y.useState)(!1),[d,f]=(0,y.useState)(null),[p,m]=(0,y.useState)(``),[h,g]=(0,y.useState)(`all`),[_,v]=(0,y.useState)(`all`),[b,x]=(0,y.useState)(()=>localStorage.getItem(z6.SORT_OPTION)||`name`),[S,C]=(0,y.useState)(!1),[w,T]=(0,y.useState)(new Set),[E,D]=(0,y.useState)(!1),[O,k]=(0,y.useState)(!1),A=(0,y.useCallback)(e=>`${e.slot_id}_${e.extruder_id}`,[]);(0,y.useEffect)(()=>{localStorage.setItem(z6.NOZZLE_DIAMETER,a)},[a]),(0,y.useEffect)(()=>{localStorage.setItem(z6.SORT_OPTION,b)},[b]);let{data:j,isLoading:M}=q({queryKey:[`printers`],queryFn:Q.getPrinters}),{data:N,isLoading:P,isFetching:F,error:I,refetch:L}=q({queryKey:[`kprofiles`,r,a],queryFn:async()=>{console.log(`[KProfiles] Fetching profiles for printer`,r,`nozzle`,a);let e=await Q.getKProfiles(r,a);return console.log(`[KProfiles] Received profiles:`,e?.profiles?.length||0,`profiles`),e},enabled:!!r,retry:!1,staleTime:0,gcTime:0,refetchOnMount:`always`}),{data:R}=q({queryKey:[`builtinFilaments`],queryFn:()=>Q.getBuiltinFilaments(),staleTime:3e5}),{data:z}=q({queryKey:[`filamentIdMap`],queryFn:()=>Q.getFilamentIdMap(),staleTime:3e5}),{data:B}=q({queryKey:[`localPresets`],queryFn:()=>Q.getLocalPresets(),retry:!1}),{data:V}=q({queryKey:[`orcaCloudProfilesForKProfiles`],queryFn:()=>Q.orcaCloudListProfiles(),retry:!1}),{data:ee}=q({queryKey:[`cloudSettings`],queryFn:()=>Q.getCloudSettings(),retry:!1}),{data:te,refetch:ne}=q({queryKey:[`kprofile-notes`,r],queryFn:()=>Q.getKProfileNotes(r),enabled:!!r,staleTime:3e4}),re=I?.message?.includes(`not connected`);(0,y.useEffect)(()=>{if(!r&&j&&j.length>0){let e=j.find(e=>e.is_active);e&&i(e.id)}},[r,j]),(0,y.useEffect)(()=>{if(r){let e=setTimeout(()=>{L()},150);return()=>clearTimeout(e)}},[r,a]);let ie=j?.filter(e=>e.is_active)||[],H=y.useMemo(()=>{let e=new Map;if(R)for(let t of R)e.set(t.filament_id,t.name);if(z)for(let[t,n]of Object.entries(z))e.has(t)||e.set(t,n);return e},[R,z]),ae=y.useMemo(()=>Array.from(H.entries()).map(([e,t])=>({filament_id:e,name:t})),[H]),oe=y.useMemo(()=>oWe({localPresets:B?.filament,orcaProfiles:V?.filament,cloudSettings:ee?.filament,builtinFilaments:R}),[B?.filament,V?.filament,ee?.filament,R]),U=y.useCallback(e=>H.get(e.filament_id)||I6(e.name),[H]),se=y.useMemo(()=>N?.profiles?N.profiles.filter(e=>{let t=p.toLowerCase(),n=!t||e.name.toLowerCase().includes(t)||e.filament_id.toLowerCase().includes(t),r=h===`all`||h===`left`&&e.extruder_id===1||h===`right`&&e.extruder_id===0,i=_===`all`||_===`hf`&&e.nozzle_id.startsWith(`HH`)||_===`s`&&e.nozzle_id.startsWith(`HS`);return n&&r&&i}).sort((e,t)=>{switch(b){case`k_value`:return parseFloat(e.k_value)-parseFloat(t.k_value);case`filament`:return U(e).localeCompare(U(t));default:return e.name.localeCompare(t.name)}}):[],[N?.profiles,p,h,_,b,U]),ce=j?.find(e=>e.id===r),le=ce?.nozzle_count===2,ue=ce?.supports_nozzle_flow_type??!0;(0,y.useEffect)(()=>{ue||v(`all`)},[ue]),(0,y.useEffect)(()=>{let e=e=>{e.target instanceof HTMLInputElement||e.target instanceof HTMLTextAreaElement||e.target instanceof HTMLSelectElement||s||l||d||(e.key===`r`||e.key===`R`?(e.preventDefault(),L()):e.key===`n`||e.key===`N`?(e.preventDefault(),u(!0)):e.key===`Escape`&&S&&(e.preventDefault(),C(!1),T(new Set)))};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[s,l,d,S,L]);let de=(0,y.useCallback)(()=>{if(!N?.profiles||N.profiles.length===0){t(e(`kProfiles.toast.noProfilesToExport`),`error`);return}let n={version:1,exported_at:new Date().toISOString(),printer:ce?.name||`Unknown`,nozzle_diameter:a,profiles:N.profiles.map(e=>({name:e.name,k_value:e.k_value,filament_id:e.filament_id,nozzle_id:e.nozzle_id,nozzle_diameter:e.nozzle_diameter,extruder_id:e.extruder_id}))},r=new Blob([JSON.stringify(n,null,2)],{type:`application/json`}),i=URL.createObjectURL(r),o=document.createElement(`a`);o.href=i,o.download=`kprofiles_${ce?.name||`printer`}_${a}mm_${new Date().toISOString().split(`T`)[0]}.json`,document.body.appendChild(o),o.click(),document.body.removeChild(o),URL.revokeObjectURL(i),t(e(`kProfiles.toast.exportedProfiles`,{count:N.profiles.length}))},[N?.profiles,ce,a,t,e]),fe=(0,y.useCallback)(()=>{let n=document.createElement(`input`);n.type=`file`,n.accept=`.json`,n.onchange=async n=>{let i=n.target.files?.[0];if(i)try{let n=await i.text(),o=JSON.parse(n);if(!o.profiles||!Array.isArray(o.profiles)){t(e(`kProfiles.toast.invalidFileFormat`),`error`);return}let s=0;for(let e of o.profiles)if(!(!e.name||!e.k_value||!e.filament_id))try{await Q.setKProfile(r,{name:e.name,k_value:parseFloat(e.k_value).toFixed(6),filament_id:e.filament_id,nozzle_id:e.nozzle_id||`${N6}-${a}`,nozzle_diameter:e.nozzle_diameter||a,extruder_id:e.extruder_id??0,slot_id:0}),s++,await new Promise(e=>setTimeout(e,500))}catch(t){console.error(`Failed to import profile:`,e.name,t)}t(e(`kProfiles.toast.importedProfiles`,{count:s,total:o.profiles.length})),L()}catch(n){console.error(`Import error:`,n),t(e(`kProfiles.toast.failedToParseImport`),`error`)}},n.click()},[r,a,t,L,e]),pe=(0,y.useCallback)(e=>{T(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},[]),me=(0,y.useCallback)(()=>{T(new Set(se.map(e=>A(e))))},[se,A]),he=(0,y.useCallback)(()=>{w.size!==0&&D(!0)},[w.size]),ge=(0,y.useCallback)(async()=>{let n=se.filter(e=>w.has(A(e)));k(!0);let i=0;for(let e of n)try{await Q.deleteKProfile(r,{slot_id:e.slot_id,extruder_id:e.extruder_id,nozzle_id:e.nozzle_id,nozzle_diameter:e.nozzle_diameter,filament_id:e.filament_id,setting_id:e.setting_id}),i++,await new Promise(e=>setTimeout(e,300))}catch(t){console.error(`Failed to delete profile:`,e.name,t)}t(e(`kProfiles.toast.profilesDeleted`,{count:i})),k(!1),D(!1),C(!1),T(new Set),L()},[r,w,se,t,L,A,e]),_e=(0,y.useCallback)(e=>{let t=[];return e.setting_id&&t.push(e.setting_id),t.push(`slot_${e.slot_id}_${e.filament_id}_${e.extruder_id}`),t.push(`name_${e.name}_${e.filament_id}`),t},[]),ve=(0,y.useCallback)(async(n,i)=>{if(r)try{await Q.setKProfileNote(r,n,i),ne()}catch(n){console.error(`Failed to save note:`,n),t(e(`kProfiles.toast.failedToSaveNote`),`error`)}},[r,ne,t,e]),ye=(0,y.useCallback)(e=>{if(!te?.notes)return{note:``,key:null};let t=_e(e);for(let e of t)if(te.notes[e])return{note:te.notes[e],key:e};return{note:``,key:null}},[te,_e]),be=(0,y.useCallback)(e=>ye(e).note,[ye]);return M?(0,K.jsx)(`div`,{className:`flex justify-center py-12`,children:(0,K.jsx)(X,{className:`w-8 h-8 text-bambu-green animate-spin`})}):!j||j.length===0?(0,K.jsx)(Od,{children:(0,K.jsxs)(Ad,{className:`py-12 text-center`,children:[(0,K.jsx)(hs,{className:`w-12 h-12 text-bambu-gray mx-auto mb-4`}),(0,K.jsx)(`h3`,{className:`text-lg font-semibold text-white mb-2`,children:e(`kProfiles.noPrintersConfigured`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray`,children:e(`kProfiles.addPrinterInSettings`)})]})}):ie.length===0?(0,K.jsx)(Od,{children:(0,K.jsxs)(Ad,{className:`py-12 text-center`,children:[(0,K.jsx)(Nl,{className:`w-12 h-12 text-bambu-gray mx-auto mb-4`}),(0,K.jsx)(`h3`,{className:`text-lg font-semibold text-white mb-2`,children:e(`kProfiles.noActivePrinters`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray`,children:e(`kProfiles.enablePrinterConnection`)})]})}):(0,K.jsxs)(K.Fragment,{children:[F&&!P&&(0,K.jsxs)(`div`,{className:`fixed inset-0 bg-black/50 flex flex-col items-center justify-center z-40`,children:[(0,K.jsx)(X,{className:`w-10 h-10 text-bambu-green animate-spin mb-3`}),(0,K.jsx)(`p`,{className:`text-white font-medium`,children:e(`kProfiles.loadingProfiles`)})]}),(0,K.jsxs)(`div`,{className:`flex flex-wrap gap-4 mb-6`,children:[(0,K.jsxs)(`div`,{className:`flex-1 min-w-48`,children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:e(`kProfiles.printer`)}),(0,K.jsx)(`select`,{value:r||``,onChange:e=>i(parseInt(e.target.value)),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:ie.map(e=>(0,K.jsx)(`option`,{value:e.id,children:e.name},e.id))})]}),(0,K.jsxs)(`div`,{className:`w-32`,children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:e(`kProfiles.nozzle`)}),(0,K.jsxs)(`select`,{value:a,onChange:e=>o(e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`0.2`,children:`0.2mm`}),(0,K.jsx)(`option`,{value:`0.4`,children:`0.4mm`}),(0,K.jsx)(`option`,{value:`0.6`,children:`0.6mm`}),(0,K.jsx)(`option`,{value:`0.8`,children:`0.8mm`})]})]}),(0,K.jsxs)(`div`,{className:`flex items-end gap-2`,children:[(0,K.jsxs)($,{variant:`secondary`,onClick:()=>L(),disabled:F||!n(`kprofiles:read`),title:n(`kprofiles:read`)?void 0:e(`kProfiles.permission.noRead`),children:[(0,K.jsx)(Il,{className:`w-4 h-4 ${F?`animate-spin`:``}`}),e(`kProfiles.refresh`)]}),(0,K.jsxs)($,{onClick:()=>u(!0),disabled:!n(`kprofiles:create`),title:n(`kprofiles:create`)?void 0:e(`kProfiles.permission.noCreate`),children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),e(`kProfiles.addProfile`)]})]})]}),(0,K.jsxs)(`div`,{className:`flex flex-wrap gap-4 mb-4`,children:[(0,K.jsxs)(`div`,{className:`flex-1 min-w-48 relative`,children:[(0,K.jsx)(Kl,{className:`absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray`}),(0,K.jsx)(`input`,{type:`text`,value:p,onChange:e=>m(e.target.value),placeholder:e(`kProfiles.searchPlaceholder`),className:`w-full pl-10 pr-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none`})]}),le&&(0,K.jsx)(`div`,{className:`w-36`,children:(0,K.jsxs)(`select`,{value:h,onChange:e=>g(e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`all`,children:e(`kProfiles.allExtruders`)}),(0,K.jsx)(`option`,{value:`left`,children:e(`kProfiles.leftOnly`)}),(0,K.jsx)(`option`,{value:`right`,children:e(`kProfiles.rightOnly`)})]})}),ue&&(0,K.jsx)(`div`,{className:`w-32`,children:(0,K.jsxs)(`select`,{value:_,onChange:e=>v(e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`all`,children:e(`kProfiles.allFlow`)}),(0,K.jsx)(`option`,{value:`hf`,children:e(`kProfiles.hfOnly`)}),(0,K.jsx)(`option`,{value:`s`,children:e(`kProfiles.sOnly`)})]})}),(0,K.jsx)(`div`,{className:`w-32`,children:(0,K.jsxs)(`select`,{value:b,onChange:e=>x(e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`name`,children:e(`kProfiles.sortName`)}),(0,K.jsx)(`option`,{value:`k_value`,children:e(`kProfiles.sortKValue`)}),(0,K.jsx)(`option`,{value:`filament`,children:e(`kProfiles.sortFilament`)})]})})]}),(0,K.jsxs)(`div`,{className:`flex flex-wrap gap-2 mb-6`,children:[(0,K.jsxs)($,{variant:`secondary`,onClick:de,disabled:!N?.profiles?.length||!n(`kprofiles:read`),title:n(`kprofiles:read`)?void 0:e(`kProfiles.permission.noExport`),children:[(0,K.jsx)(Ks,{className:`w-4 h-4`}),e(`kProfiles.export`)]}),(0,K.jsxs)($,{variant:`secondary`,onClick:fe,disabled:!n(`kprofiles:create`),title:n(`kprofiles:create`)?void 0:e(`kProfiles.permission.noImport`),children:[(0,K.jsx)(Fu,{className:`w-4 h-4`}),e(`kProfiles.import`)]}),(0,K.jsx)(`div`,{className:`flex-1`}),S?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)($,{variant:`secondary`,onClick:me,children:[(0,K.jsx)(fu,{className:`w-4 h-4`}),e(`kProfiles.selectAll`)]}),(0,K.jsxs)($,{variant:`secondary`,onClick:he,disabled:w.size===0||!n(`kprofiles:delete`),className:`text-red-500 hover:bg-red-500/10`,title:n(`kprofiles:delete`)?void 0:e(`kProfiles.permission.noDelete`),children:[(0,K.jsx)(Ou,{className:`w-4 h-4`}),e(`kProfiles.delete`),` (`,w.size,`)`]}),(0,K.jsxs)($,{variant:`secondary`,onClick:()=>{C(!1),T(new Set)},children:[(0,K.jsx)(Yu,{className:`w-4 h-4`}),e(`common.cancel`)]})]}):(0,K.jsxs)($,{variant:`secondary`,onClick:()=>C(!0),disabled:!se.length||!n(`kprofiles:delete`),title:n(`kprofiles:delete`)?void 0:e(`kProfiles.permission.noDelete`),children:[(0,K.jsx)(fu,{className:`w-4 h-4`}),e(`kProfiles.select`)]})]}),P?(0,K.jsx)(`div`,{className:`flex justify-center py-12`,children:(0,K.jsx)(X,{className:`w-8 h-8 text-bambu-green animate-spin`})}):re?(0,K.jsx)(Od,{children:(0,K.jsxs)(Ad,{className:`py-12 text-center`,children:[(0,K.jsx)(Wu,{className:`w-12 h-12 text-bambu-gray mx-auto mb-4`}),(0,K.jsx)(`h3`,{className:`text-lg font-semibold text-white mb-2`,children:e(`kProfiles.printerOffline`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray mb-4`,children:e(`kProfiles.printerOfflineDesc`)}),(0,K.jsxs)($,{variant:`secondary`,onClick:()=>L(),children:[(0,K.jsx)(Il,{className:`w-4 h-4`}),e(`common.refresh`)]})]})}):se.length>0?le?(0,K.jsxs)(`div`,{className:`grid grid-cols-2 gap-4`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`text-sm font-medium text-bambu-gray mb-2 px-1`,children:e(`kProfiles.leftExtruder`)}),(0,K.jsx)(`div`,{className:`space-y-1`,children:se.filter(e=>e.extruder_id===1).map(e=>(0,K.jsx)(L6,{profile:e,onEdit:()=>c(e),onCopy:()=>f(e),selectionMode:S,isSelected:w.has(A(e)),onToggleSelect:()=>pe(A(e)),note:be(e)},A(e)))})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`text-sm font-medium text-bambu-gray mb-2 px-1`,children:e(`kProfiles.rightExtruder`)}),(0,K.jsx)(`div`,{className:`space-y-1`,children:se.filter(e=>e.extruder_id===0).map(e=>(0,K.jsx)(L6,{profile:e,onEdit:()=>c(e),onCopy:()=>f(e),selectionMode:S,isSelected:w.has(A(e)),onToggleSelect:()=>pe(A(e)),note:be(e)},A(e)))})]})]}):(0,K.jsx)(`div`,{className:`space-y-1`,children:se.map(e=>(0,K.jsx)(L6,{profile:e,onEdit:()=>c(e),onCopy:()=>f(e),selectionMode:S,isSelected:w.has(A(e)),onToggleSelect:()=>pe(A(e)),note:be(e)},A(e)))}):p||h!==`all`||_!==`all`?(0,K.jsx)(Od,{children:(0,K.jsxs)(Ad,{className:`py-12 text-center`,children:[(0,K.jsx)(Kl,{className:`w-12 h-12 text-bambu-gray mx-auto mb-4`}),(0,K.jsx)(`h3`,{className:`text-lg font-semibold text-white mb-2`,children:e(`kProfiles.noMatchingProfiles`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray`,children:e(`kProfiles.noMatchingProfilesDesc`)})]})}):(0,K.jsx)(Od,{children:(0,K.jsxs)(Ad,{className:`py-12 text-center`,children:[(0,K.jsx)(bc,{className:`w-12 h-12 text-bambu-gray mx-auto mb-4`}),(0,K.jsx)(`h3`,{className:`text-lg font-semibold text-white mb-2`,children:e(`kProfiles.noKProfiles`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray mb-4`,children:e(`kProfiles.noKProfilesDesc`,{diameter:a})}),(0,K.jsxs)($,{onClick:()=>u(!0),children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),e(`kProfiles.createFirstProfile`)]})]})}),s&&r&&(()=>{let{note:e,key:t}=ye(s);return(0,K.jsx)(R6,{profile:s,printerId:r,nozzleDiameter:a,existingProfiles:N?.profiles,builtinFilaments:ae,filamentPresets:oe,isDualNozzle:le,supportsFlowType:ue,initialNote:e,initialNoteKey:t,onSaveNote:ve,hasPermission:n,onClose:()=>{console.log(`[KProfiles] Edit modal onClose - refetching profiles...`),c(null),L()},onSave:()=>{c(null),L()}})})(),l&&r&&(0,K.jsx)(R6,{printerId:r,nozzleDiameter:a,existingProfiles:N?.profiles,builtinFilaments:ae,filamentPresets:oe,isDualNozzle:le,supportsFlowType:ue,onSaveNote:ve,hasPermission:n,onClose:()=>{u(!1),L()},onSave:()=>{u(!1),L()}}),d&&r&&(0,K.jsx)(R6,{printerId:r,nozzleDiameter:a,existingProfiles:N?.profiles,builtinFilaments:ae,filamentPresets:oe,isDualNozzle:le,supportsFlowType:ue,onSaveNote:ve,hasPermission:n,profile:{...d,slot_id:0,name:`${d.name} (Copy)`},onClose:()=>{f(null),L()},onSave:()=>{f(null),L()}}),E&&(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4`,children:(0,K.jsx)(Od,{className:`w-full max-w-sm`,children:(0,K.jsxs)(Ad,{className:`p-6`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-3 mb-4`,children:[(0,K.jsx)(`div`,{className:`w-10 h-10 rounded-full bg-red-500/20 flex items-center justify-center`,children:(0,K.jsx)(Ou,{className:`w-5 h-5 text-red-500`})}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`text-lg font-semibold text-white`,children:e(`kProfiles.bulkDelete.title`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:e(`kProfiles.bulkDelete.cannotUndo`)})]})]}),(0,K.jsx)(`p`,{className:`text-bambu-gray mb-6`,children:e(`kProfiles.bulkDelete.message`,{count:w.size})}),(0,K.jsxs)(`div`,{className:`flex gap-3`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:()=>D(!1),disabled:O,className:`flex-1`,children:e(`common.cancel`)}),(0,K.jsxs)($,{onClick:ge,disabled:O,className:`flex-1 bg-red-500 hover:bg-red-600 text-white`,children:[O?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(Ou,{className:`w-4 h-4`}),e(`common.delete`)]})]})]})})})]})}var B6=[`PLA`,`PETG`,`PCTG`,`ABS`,`ASA`,`TPU`,`PC`,`PA`,`PVA`,`HIPS`,`PP`,`PET`,`NYLON`],uWe={PLA:`E8E8E8`,PETG:`4A90D9`,ABS:`E67E22`,ASA:`D35400`,TPU:`9B59B6`,PC:`BDC3C7`,PA:`2ECC71`,NYLON:`2ECC71`,PVA:`F1C40F`,HIPS:`95A5A6`,PP:`ECF0F1`,PET:`3498DB`};function dWe(e){let t=e.toUpperCase();for(let e of B6)if(RegExp(`\\b${e}\\b`).test(t))return e;return null}function fWe(e){let t=e.replace(/@.+$/,``).trim(),n=t.toUpperCase();for(let e of B6){let r=n.indexOf(e);if(r>0){let e=t.slice(0,r).trim();if(e&&e.length>1)return e}}return null}function V6({preset:e,onDelete:t,onExpand:n,isExpanded:r}){let{t:i}=W(),{hasPermission:a}=Sd(),o=e.filament_type||dWe(e.name),s=e.filament_vendor||fWe(e.name),c=null,l=!1;if(e.default_filament_colour)try{let t=JSON.parse(e.default_filament_colour),n=Array.isArray(t)?t[0]:t;typeof n==`string`&&/^#?[0-9a-fA-F]{6,8}$/.test(n.replace(`#`,``))&&(c=n.replace(`#`,``).slice(0,6),l=!0)}catch{let t=e.default_filament_colour;/^#?[0-9a-fA-F]{6,8}$/.test(t.replace(`#`,``))&&(c=t.replace(`#`,``).slice(0,6),l=!0)}return!c&&o&&(c=uWe[o.toUpperCase()]||null),(0,K.jsx)(Od,{className:`bg-bambu-dark border-bambu-dark-tertiary hover:border-bambu-dark-tertiary/80 transition-colors`,children:(0,K.jsxs)(Ad,{className:`p-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-start justify-between gap-2`,children:[(0,K.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 mb-1`,children:[e.preset_type===`filament`&&(0,K.jsx)(`div`,{className:`w-4 h-4 rounded-full border border-black/20 flex-shrink-0 ${!l&&!c?`opacity-25`:l?``:`opacity-50`}`,style:{backgroundColor:c?`#${c}`:`#666`}}),(0,K.jsx)(`span`,{className:`text-sm font-medium text-white truncate`,children:e.name})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 flex-wrap`,children:[o&&(0,K.jsx)(`span`,{className:`text-xs px-1.5 py-0.5 rounded bg-bambu-green/20 text-bambu-green`,children:o}),s&&(0,K.jsx)(`span`,{className:`text-xs text-bambu-gray`,children:s}),(0,K.jsx)(`span`,{className:`text-xs px-1.5 py-0.5 rounded bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400`,children:i(`profiles.localProfiles.badge`)})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-1 flex-shrink-0`,children:[a(`settings:update`)&&(0,K.jsx)(`button`,{onClick:()=>t(e.id),className:`p-1 text-bambu-gray hover:text-red-600 dark:hover:text-red-400 transition-colors`,title:i(`profiles.localProfiles.delete`),children:(0,K.jsx)(Ou,{className:`w-3.5 h-3.5`})}),(0,K.jsx)(`button`,{onClick:()=>n(r?null:e.id),className:`p-1 text-bambu-gray hover:text-white transition-colors`,children:r?(0,K.jsx)(fs,{className:`w-3.5 h-3.5`}):(0,K.jsx)(ls,{className:`w-3.5 h-3.5`})})]})]}),r&&(0,K.jsxs)(`div`,{className:`mt-3 pt-3 border-t border-bambu-dark-tertiary text-xs space-y-1.5`,children:[o&&(0,K.jsxs)(`div`,{className:`flex justify-between`,children:[(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:i(`profiles.localProfiles.filamentType`)}),(0,K.jsx)(`span`,{className:`text-white`,children:o})]}),s&&(0,K.jsxs)(`div`,{className:`flex justify-between`,children:[(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:i(`profiles.localProfiles.vendor`)}),(0,K.jsx)(`span`,{className:`text-white`,children:s})]}),e.nozzle_temp_min!=null&&e.nozzle_temp_max!=null&&(0,K.jsxs)(`div`,{className:`flex justify-between`,children:[(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:i(`profiles.localProfiles.nozzleTemp`)}),(0,K.jsxs)(`span`,{className:`text-white`,children:[e.nozzle_temp_min,`–`,e.nozzle_temp_max,`°C`]})]}),e.filament_cost&&(0,K.jsxs)(`div`,{className:`flex justify-between`,children:[(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:i(`profiles.localProfiles.cost`)}),(0,K.jsx)(`span`,{className:`text-white`,children:e.filament_cost})]}),e.filament_density&&(0,K.jsxs)(`div`,{className:`flex justify-between`,children:[(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:i(`profiles.localProfiles.density`)}),(0,K.jsxs)(`span`,{className:`text-white`,children:[e.filament_density,` g/cm³`]})]}),e.pressure_advance&&(0,K.jsxs)(`div`,{className:`flex justify-between`,children:[(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:i(`profiles.localProfiles.pressureAdvance`)}),(0,K.jsx)(`span`,{className:`text-white`,children:e.pressure_advance})]}),e.compatible_printers&&(0,K.jsxs)(`div`,{className:`flex justify-between`,children:[(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:i(`profiles.localProfiles.compatiblePrinters`)}),(0,K.jsx)(`span`,{className:`text-white truncate ml-2`,children:(()=>{try{return JSON.parse(e.compatible_printers).join(`, `)}catch{return e.compatible_printers}})()})]}),e.inherits&&e.inherits!==e.name&&(0,K.jsxs)(`div`,{className:`flex justify-between`,children:[(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:i(`profiles.localProfiles.inheritsFrom`)}),(0,K.jsx)(`span`,{className:`text-white truncate ml-2`,children:e.inherits})]}),(0,K.jsxs)(`div`,{className:`flex justify-between`,children:[(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:i(`profiles.localProfiles.source`)}),(0,K.jsx)(`span`,{className:`text-white capitalize`,children:e.source})]})]})]})})}function pWe(){let{t:e}=W(),{hasPermission:t}=Sd(),n=oo(),{showToast:r}=Id(),[i,a]=(0,y.useState)(``),[o,s]=(0,y.useState)(null),[c,l]=(0,y.useState)(!1),[u,d]=(0,y.useState)(null),{data:f,isLoading:p}=q({queryKey:[`localPresets`],queryFn:()=>Q.getLocalPresets()}),m=J({mutationFn:async e=>{let t=[];for(let n of Array.from(e)){let e=new FormData;e.append(`file`,n),t.push(await Q.importLocalPresets(e))}return t},onSuccess:t=>{n.invalidateQueries({queryKey:[`localPresets`]}),n.invalidateQueries({queryKey:[`slicerPresets`]});let i=0,a=0,o=0;for(let e of t)i+=e.imported,a+=e.skipped,o+=e.errors.length;i>0&&r(e(`profiles.localProfiles.toast.importSuccess`,{count:i})),a>0&&r(e(`profiles.localProfiles.toast.importSkipped`,{count:a}),`warning`),o>0&&r(e(`profiles.localProfiles.toast.importError`,{count:o}),`error`)},onError:e=>{r(e.message,`error`)}}),h=J({mutationFn:e=>Q.deleteLocalPreset(e),onSuccess:(t,i)=>{n.setQueryData([`localPresets`],e=>e&&{filament:e.filament.filter(e=>e.id!==i),printer:e.printer.filter(e=>e.id!==i),process:e.process.filter(e=>e.id!==i)}),n.invalidateQueries({queryKey:[`localPresets`]}),n.invalidateQueries({queryKey:[`slicerPresets`]}),d(null),r(e(`profiles.localProfiles.toast.deleted`))}}),g=(0,y.useCallback)(e=>{!e||e.length===0||m.mutate(e)},[m]),_=(0,y.useCallback)(e=>{e.preventDefault(),l(!1),g(e.dataTransfer.files)},[g]),v=(0,y.useCallback)(e=>{if(!i)return e;let t=i.toLowerCase();return e.filter(e=>e.name.toLowerCase().includes(t)||e.filament_type?.toLowerCase().includes(t)||e.filament_vendor?.toLowerCase().includes(t))},[i]),b=(0,y.useMemo)(()=>v(f?.filament||[]),[f?.filament,v]),x=(0,y.useMemo)(()=>v(f?.printer||[]),[f?.printer,v]),S=(0,y.useMemo)(()=>v(f?.process||[]),[f?.process,v]),C=b.length+x.length+S.length,w=(f?.filament?.length??0)+(f?.printer?.length??0)+(f?.process?.length??0)>0;return p?(0,K.jsx)(`div`,{className:`flex items-center justify-center py-16`,children:(0,K.jsx)(X,{className:`w-8 h-8 text-bambu-green animate-spin`})}):(0,K.jsxs)(`div`,{className:`space-y-6`,children:[t(`settings:update`)&&(0,K.jsxs)(`div`,{onDragOver:e=>{e.preventDefault(),l(!0)},onDragLeave:()=>l(!1),onDrop:_,className:`relative border-2 border-dashed rounded-lg p-6 text-center transition-colors ${c?`border-bambu-green bg-bambu-green/10`:`border-bambu-dark-tertiary hover:border-bambu-gray`}`,children:[(0,K.jsx)(`input`,{type:`file`,accept:`.json,.zip,.orca_filament,.bbscfg,.bbsflmt`,multiple:!0,className:`absolute inset-0 w-full h-full opacity-0 cursor-pointer`,onChange:e=>g(e.target.files)}),m.isPending?(0,K.jsxs)(`div`,{className:`flex items-center justify-center gap-2`,children:[(0,K.jsx)(X,{className:`w-5 h-5 text-bambu-green animate-spin`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:e(`profiles.localProfiles.importing`)})]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(Fu,{className:`w-8 h-8 text-bambu-gray mx-auto mb-2`}),(0,K.jsx)(`p`,{className:`text-sm text-white font-medium`,children:e(`profiles.localProfiles.import`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:e(`profiles.localProfiles.importDesc`)})]})]}),w&&(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(Kl,{className:`absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray`}),(0,K.jsx)(`input`,{type:`text`,value:i,onChange:e=>a(e.target.value),placeholder:e(`profiles.localProfiles.search`),className:`w-full pl-9 pr-4 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-sm text-white placeholder-bambu-gray focus:outline-none focus:border-bambu-green`})]}),!w&&!p&&(0,K.jsxs)(`div`,{className:`text-center py-12`,children:[(0,K.jsx)(kc,{className:`w-12 h-12 text-bambu-gray mx-auto mb-3 opacity-50`}),(0,K.jsx)(`p`,{className:`text-bambu-gray`,children:e(`profiles.localProfiles.noPresets`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray/60 mt-1`,children:e(`profiles.localProfiles.importDesc`)})]}),w&&C===0&&!p&&(0,K.jsxs)(`div`,{className:`text-center py-12`,children:[(0,K.jsx)(Kl,{className:`w-12 h-12 text-bambu-gray mx-auto mb-3 opacity-50`}),(0,K.jsx)(`p`,{className:`text-bambu-gray`,children:e(`profiles.localProfiles.noSearchResults`)})]}),C>0&&(0,K.jsxs)(`div`,{className:`grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6`,children:[b.length>0&&(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 mb-3`,children:[(0,K.jsx)(qs,{className:`w-4 h-4 text-bambu-green`}),(0,K.jsx)(`h3`,{className:`text-sm font-medium text-white`,children:e(`profiles.localProfiles.filament`)}),(0,K.jsxs)(`span`,{className:`text-xs text-bambu-gray`,children:[`(`,b.length,`)`]})]}),(0,K.jsx)(`div`,{className:`space-y-2`,children:b.map(e=>(0,K.jsx)(V6,{preset:e,onDelete:e=>d(e),onExpand:s,isExpanded:o===e.id},e.id))})]}),S.length>0&&(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 mb-3`,children:[(0,K.jsx)(Uc,{className:`w-4 h-4 text-blue-600 dark:text-blue-400`}),(0,K.jsx)(`h3`,{className:`text-sm font-medium text-white`,children:e(`profiles.localProfiles.process`)}),(0,K.jsxs)(`span`,{className:`text-xs text-bambu-gray`,children:[`(`,S.length,`)`]})]}),(0,K.jsx)(`div`,{className:`space-y-2`,children:S.map(e=>(0,K.jsx)(V6,{preset:e,onDelete:e=>d(e),onExpand:s,isExpanded:o===e.id},e.id))})]}),x.length>0&&(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 mb-3`,children:[(0,K.jsx)(Xl,{className:`w-4 h-4 text-orange-600 dark:text-orange-400`}),(0,K.jsx)(`h3`,{className:`text-sm font-medium text-white`,children:e(`profiles.localProfiles.printer`)}),(0,K.jsxs)(`span`,{className:`text-xs text-bambu-gray`,children:[`(`,x.length,`)`]})]}),(0,K.jsx)(`div`,{className:`space-y-2`,children:x.map(e=>(0,K.jsx)(V6,{preset:e,onDelete:e=>d(e),onExpand:s,isExpanded:o===e.id},e.id))})]})]}),u!==null&&(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/50 flex items-center justify-center z-50`,children:(0,K.jsxs)(`div`,{className:`bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg p-6 max-w-sm mx-4`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 mb-3`,children:[(0,K.jsx)(hs,{className:`w-5 h-5 text-red-600 dark:text-red-400`}),(0,K.jsx)(`h3`,{className:`text-white font-medium`,children:e(`profiles.localProfiles.deleteConfirmTitle`)})]}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mb-4`,children:e(`profiles.localProfiles.deleteConfirm`)}),(0,K.jsxs)(`div`,{className:`flex justify-end gap-2`,children:[(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>d(null),children:e(`profiles.localProfiles.cancel`)}),(0,K.jsxs)($,{variant:`danger`,size:`sm`,onClick:()=>h.mutate(u),disabled:h.isPending,children:[h.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(Ou,{className:`w-4 h-4`}),e(`profiles.localProfiles.delete`)]})]})]})})]})}function mWe(e){let t=e.match(/@?\s*(?:BBL\s+)?(?:Bambu\s+Lab\s+)?([XPAH][1-9][A-Z]?(?:\s*(?:Carbon|mini))?|H2D)/i),n=e.match(/(\d+\.?\d*)\s*(?:mm\s*)?nozzle|nozzle\s*(\d+\.?\d*)/i),r=e.match(/(\d+\.?\d*)mm\s*(?:Standard|Fine|Extra Fine|Draft|Quality)?/i),i=e.match(/\b(PLA|PETG|ABS|ASA|TPU|PC|PA|PVA|HIPS|PP|PET(?:-?CF)?|PA(?:-?CF)?|PLA(?:-?CF)?)\b/i);return{printer:t?t[1].trim():null,nozzle:n?(n[1]||n[2])+`mm`:null,layerHeight:r?r[1]+`mm`:null,filamentType:i?i[1].toUpperCase():null}}function hWe({settings:e,lastSyncTime:t,onRefresh:n,isRefreshing:r,printers:i,t:a}){let[o,s]=(0,y.useState)(``),[c,l]=(0,y.useState)(`all`),[u,d]=(0,y.useState)(`all`),[f,p]=(0,y.useState)(`all`),[m,h]=(0,y.useState)(`all`),[g,_]=(0,y.useState)(`all`),[v,b]=(0,y.useState)(null),x=(0,y.useMemo)(()=>[...e.filament.map(e=>({...e,type:`filament`})),...e.printer.map(e=>({...e,type:`printer`})),...e.process.map(e=>({...e,type:`process`}))].map(e=>({...e,meta:mWe(e.name)})),[e]),S=(0,y.useMemo)(()=>{let e=new Set,t=new Set,n=new Set;return x.forEach(r=>{r.meta.nozzle&&e.add(r.meta.nozzle),r.meta.filamentType&&t.add(r.meta.filamentType),r.meta.layerHeight&&n.add(r.meta.layerHeight)}),{printers:i.map(e=>({id:e.id.toString(),name:e.name})),nozzles:Array.from(e).sort((e,t)=>parseFloat(e)-parseFloat(t)),filaments:Array.from(t).sort(),layerHeights:Array.from(n).sort((e,t)=>parseFloat(e)-parseFloat(t))}},[x,i]),C=(0,y.useMemo)(()=>u===`all`?null:i.find(e=>e.id.toString()===u)?.model||null,[u,i]),w=(0,y.useMemo)(()=>x.filter(e=>c===`all`||e.type===c).filter(e=>{if(u===`all`||!C)return!0;let t=e.meta.printer?.toLowerCase()||``,n=C.toLowerCase();return t.includes(n)||n.includes(t)}).filter(e=>f===`all`||e.meta.nozzle===f).filter(e=>m===`all`||e.meta.filamentType===m).filter(e=>g===`all`||e.meta.layerHeight===g).filter(e=>o===``||e.name.toLowerCase().includes(o.toLowerCase())).sort((e,t)=>e.name.localeCompare(t.name)),[x,c,u,C,f,m,g,o]),T=()=>{l(`all`),d(`all`),p(`all`),h(`all`),_(`all`),s(``)},E=c!==`all`||u!==`all`||f!==`all`||m!==`all`||g!==`all`||o!==``,D=e.filament.length+e.printer.length+e.process.length,O=e=>w.filter(t=>t.type===e);return(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{className:`space-y-4 mb-6`,children:[(0,K.jsxs)(`div`,{className:`flex flex-col sm:flex-row gap-3`,children:[(0,K.jsxs)(`div`,{className:`relative flex-1`,children:[(0,K.jsx)(Kl,{className:`absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray`}),(0,K.jsx)(`input`,{type:`text`,value:o,onChange:e=>s(e.target.value),placeholder:a(`profiles.cloudView.searchPlaceholder`),className:`w-full pl-10 pr-4 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray-dark focus:border-bambu-green focus:outline-none`})]}),(0,K.jsx)(`div`,{className:`flex gap-2`,children:(0,K.jsxs)($,{variant:`secondary`,onClick:n,disabled:r,children:[(0,K.jsx)(Il,{className:`w-4 h-4 ${r?`animate-spin`:``}`}),a(`profiles.cloudView.refresh`)]})})]}),(0,K.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,K.jsx)(yc,{className:`w-4 h-4 text-bambu-gray`}),(0,K.jsx)(G6,{label:a(`profiles.cloudView.filters.type`),value:c,options:[{value:`all`,label:a(`profiles.cloudView.filters.all`),count:D},{value:`filament`,label:a(`profiles.cloudView.filters.filament`),count:e.filament.length},{value:`printer`,label:a(`profiles.cloudView.filters.printer`),count:e.printer.length},{value:`process`,label:a(`profiles.cloudView.filters.process`),count:e.process.length}],onChange:e=>l(e)}),S.printers.length>0&&(0,K.jsx)(G6,{label:a(`profiles.cloudView.filters.printer`),value:u,options:[{value:`all`,label:a(`profiles.cloudView.filters.all`)},...S.printers.map(e=>({value:e.id,label:e.name}))],onChange:d}),S.nozzles.length>0&&(0,K.jsx)(G6,{label:a(`profiles.cloudView.filters.nozzle`),value:f,options:[{value:`all`,label:a(`profiles.cloudView.filters.all`)},...S.nozzles.map(e=>({value:e,label:e}))],onChange:p}),S.filaments.length>0&&(c===`all`||c===`filament`)&&(0,K.jsx)(G6,{label:a(`profiles.cloudView.filters.filament`),value:m,options:[{value:`all`,label:a(`profiles.cloudView.filters.all`)},...S.filaments.map(e=>({value:e,label:e}))],onChange:h}),S.layerHeights.length>0&&(c===`all`||c===`process`)&&(0,K.jsx)(G6,{label:a(`profiles.cloudView.filters.layer`),value:g,options:[{value:`all`,label:a(`profiles.cloudView.filters.all`)},...S.layerHeights.map(e=>({value:e,label:e}))],onChange:_}),E&&(0,K.jsx)(`button`,{onClick:T,className:`px-3 py-2 text-sm text-bambu-gray hover:text-white transition-colors`,children:a(`profiles.cloudView.clearFilters`)})]})]}),(0,K.jsxs)(`div`,{className:`flex flex-wrap items-center gap-4 mb-4 text-sm text-bambu-gray`,children:[t&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,K.jsx)(Es,{className:`w-3 h-3`}),a(`profiles.cloudView.lastSynced`),` `,Bf(t.toISOString(),`system`,a)]}),(0,K.jsx)(`span`,{children:a(`profiles.cloudView.showingCount`,{showing:w.length,total:D})})]}),w.length===0?(0,K.jsxs)(`div`,{className:`text-center py-16`,children:[(0,K.jsx)(Uc,{className:`w-12 h-12 text-bambu-gray-dark mx-auto mb-4`}),(0,K.jsx)(`p`,{className:`text-bambu-gray`,children:a(`profiles.cloudView.noPresetsFound`)}),E&&(0,K.jsx)(`button`,{onClick:T,className:`mt-2 text-sm text-bambu-green hover:text-bambu-green-light`,children:a(`profiles.cloudView.clearFilters`)})]}):(0,K.jsxs)(`div`,{className:`grid grid-cols-1 md:grid-cols-3 gap-6`,children:[(0,K.jsx)(H6,{icon:(0,K.jsx)(qs,{className:`w-4 h-4 text-amber-600 dark:text-amber-400`}),title:a(`profiles.cloudView.columns.filament`),presets:O(`filament`),emptyText:a(`profiles.cloudView.noFilamentPresets`),onSelect:b}),(0,K.jsx)(H6,{icon:(0,K.jsx)(Xl,{className:`w-4 h-4 text-blue-600 dark:text-blue-400`}),title:a(`profiles.cloudView.columns.process`),presets:O(`process`),emptyText:a(`profiles.cloudView.noProcessPresets`),onSelect:b}),(0,K.jsx)(H6,{icon:(0,K.jsx)(Nl,{className:`w-4 h-4 text-purple-600 dark:text-purple-400`}),title:a(`profiles.cloudView.columns.printer`),presets:O(`printer`),emptyText:a(`profiles.cloudView.noPrinterPresets`),onSelect:b})]}),v&&(0,K.jsx)(_We,{setting:v,onClose:()=>b(null),t:a})]})}function H6({icon:e,title:t,presets:n,emptyText:r,onSelect:i}){return(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 mb-3 px-1`,children:[e,(0,K.jsx)(`h3`,{className:`text-sm font-medium text-bambu-gray`,children:t}),(0,K.jsxs)(`span`,{className:`text-xs text-bambu-gray-dark`,children:[`(`,n.length,`)`]})]}),(0,K.jsx)(`div`,{className:`space-y-1 max-h-[calc(100vh-320px)] overflow-y-auto pr-1`,children:n.length===0?(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray-dark px-3 py-2`,children:r}):n.map(e=>(0,K.jsx)(gWe,{preset:e,onClick:()=>i(e)},e.setting_id))})]})}function gWe({preset:e,onClick:t}){return(0,K.jsx)(`button`,{onClick:t,className:`w-full text-left px-3 py-2 rounded bg-bambu-dark hover:bg-bambu-dark-tertiary transition-colors`,children:(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`span`,{className:`text-white text-sm truncate flex-1`,title:e.name,children:e.name}),e.meta.filamentType&&e.type===`filament`&&(0,K.jsx)(`span`,{className:`text-xs text-bambu-gray whitespace-nowrap`,children:e.meta.filamentType}),e.meta.layerHeight&&e.type===`process`&&(0,K.jsx)(`span`,{className:`text-xs text-bambu-gray whitespace-nowrap`,children:e.meta.layerHeight}),e.meta.printer&&(0,K.jsx)(`span`,{className:`text-xs text-bambu-gray whitespace-nowrap`,children:e.meta.printer})]})})}function _We({setting:e,onClose:t,t:n}){let{data:r,isLoading:i,error:a}=q({queryKey:[`orcaCloudProfileDetail`,e.setting_id],queryFn:()=>Q.orcaCloudGetProfile(e.setting_id),retry:!1});return(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/60 z-50 flex items-center justify-center p-4`,onClick:t,children:(0,K.jsxs)(`div`,{className:`bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg shadow-2xl max-w-4xl w-full max-h-[90vh] flex flex-col`,onClick:e=>e.stopPropagation(),children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between p-4 border-b border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h2`,{className:`text-lg font-bold text-white`,children:e.name}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-0.5`,children:e.type})]}),(0,K.jsx)(`button`,{onClick:t,className:`text-bambu-gray hover:text-white p-1`,children:(0,K.jsx)(Yu,{className:`w-5 h-5`})})]}),(0,K.jsx)(`div`,{className:`flex-1 overflow-y-auto p-4`,children:i?(0,K.jsx)(`div`,{className:`flex items-center justify-center py-16`,children:(0,K.jsx)(X,{className:`w-8 h-8 text-bambu-green animate-spin`})}):a?(0,K.jsx)(`p`,{className:`text-center text-bambu-gray py-16`,children:a.message}):r?(0,K.jsx)(`pre`,{className:`text-xs font-mono text-bambu-gray bg-bambu-dark p-3 rounded overflow-x-auto whitespace-pre`,children:JSON.stringify(r.setting,null,2)}):(0,K.jsx)(`p`,{className:`text-center text-bambu-gray py-16`,children:n(`profiles.cloudView.noPresetsFound`)})})]})})}function vWe(){let{t:e}=W(),t=oo(),{showToast:n}=Id(),{hasPermission:r}=Sd(),i=r(`orca_cloud:auth`),[a,o]=(0,y.useState)(null),[s,c]=(0,y.useState)(5e3),[l,u]=(0,y.useState)(null),{data:d,isLoading:f}=q({queryKey:[`orcaCloudStatus`],queryFn:Q.orcaCloudStatus}),p=!!d?.connected,{data:m,isLoading:h,refetch:g,isRefetching:_,error:v,dataUpdatedAt:b}=q({queryKey:[`orcaCloudProfiles`],queryFn:Q.orcaCloudListProfiles,enabled:p,retry:!1,staleTime:1e3*60*5}),{data:x=[]}=q({queryKey:[`printers`],queryFn:Q.getPrinters,enabled:p}),[S,C]=(0,y.useState)();(0,y.useEffect)(()=>{b&&C(new Date(b))},[b]);let w=()=>{o(null),c(5e3)},T=t=>{t===`access_denied`?u(e(`profiles.orcaCloud.errors.denied`)):t===`expired_token`&&u(e(`profiles.orcaCloud.errors.expired`)),w()},E=J({mutationFn:Q.orcaCloudDeviceStart,onSuccess:e=>{u(null),c(Math.max(1,e.interval)*1e3),o(e)},onError:t=>{u(t.message||e(`profiles.orcaCloud.errors.startFailed`))}}),D=J({mutationFn:Q.orcaCloudLogout,onSuccess:()=>{t.invalidateQueries({queryKey:[`orcaCloudStatus`]}),t.removeQueries({queryKey:[`orcaCloudProfiles`]}),n(e(`profiles.orcaCloud.toast.disconnected`))}}),{data:O,error:k}=q({queryKey:[`orcaCloudDevicePoll`,a?.user_code??`none`],queryFn:Q.orcaCloudDevicePoll,enabled:a!==null,gcTime:0,retry:!1,refetchOnWindowFocus:!1,refetchInterval:a===null?!1:s}),A=(0,y.useRef)(null);return(0,y.useEffect)(()=>{if(!a||!O)return;let r=O.status;if(r===`slow_down`){c(e=>e+5e3);return}r!==`authorization_pending`&&A.current!==r&&(A.current=r,r===`complete`?(w(),t.invalidateQueries({queryKey:[`orcaCloudStatus`]}),t.invalidateQueries({queryKey:[`orcaCloudProfiles`]}),n(e(`profiles.orcaCloud.connectedShort`))):T(r))},[O,a]),(0,y.useEffect)(()=>{a&&k&&(u(e(`profiles.orcaCloud.errors.pollFailed`)),w())},[k,a]),(0,y.useEffect)(()=>{a&&(A.current=null)},[a]),f?(0,K.jsx)(`div`,{className:`flex items-center justify-center py-16`,children:(0,K.jsx)(X,{className:`w-8 h-8 text-bambu-green animate-spin`})}):(0,K.jsxs)(`div`,{children:[p&&(0,K.jsxs)(`div`,{className:`flex items-center justify-between p-3 mb-6 bg-bambu-dark rounded-lg border border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,K.jsx)(`div`,{className:`w-2 h-2 rounded-full bg-bambu-green animate-pulse`}),(0,K.jsx)(`span`,{className:`text-sm text-bambu-gray`,children:d?.email?(0,K.jsxs)(K.Fragment,{children:[e(`profiles.orcaCloud.connectedAs`),` `,(0,K.jsx)(`span`,{className:`text-white`,children:d.email})]}):(0,K.jsx)(`span`,{className:`text-white`,children:e(`profiles.orcaCloud.connectedShort`)})})]}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,onClick:()=>D.mutate(),disabled:D.isPending||!i,title:i?void 0:e(`profiles.orcaCloud.noLogoutPermission`),children:[(0,K.jsx)(el,{className:`w-4 h-4`}),e(`profiles.orcaCloud.logout`)]})]}),p?h?(0,K.jsx)(`div`,{className:`flex items-center justify-center py-16`,children:(0,K.jsx)(X,{className:`w-8 h-8 text-bambu-green animate-spin`})}):v?(0,K.jsxs)(`div`,{className:`text-center py-16`,children:[(0,K.jsx)(`p`,{className:`text-bambu-gray mb-4`,children:v.message}),(0,K.jsx)($,{onClick:()=>g(),children:e(`profiles.orcaCloud.retry`)})]}):m?(0,K.jsx)(hWe,{settings:m,lastSyncTime:S,onRefresh:()=>g(),isRefreshing:_,printers:x,t:e}):null:(0,K.jsx)(yWe,{pairing:a,connectError:l,onConnect:()=>E.mutate(),onCancel:w,isStarting:E.isPending,canManage:i,t:e})]})}function yWe({pairing:e,connectError:t,onConnect:n,onCancel:r,isStarting:i,canManage:a,t:o}){return e?(0,K.jsx)(Od,{children:(0,K.jsxs)(Ad,{className:`p-8 text-center max-w-md mx-auto`,children:[(0,K.jsx)(ks,{className:`w-12 h-12 text-bambu-green mx-auto mb-4`}),(0,K.jsx)(`h2`,{className:`text-xl font-bold text-white mb-2`,children:o(`profiles.orcaCloud.device.title`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray mb-6`,children:o(`profiles.orcaCloud.device.instruction`)}),(0,K.jsx)(`p`,{className:`text-xs uppercase tracking-wide text-bambu-gray mb-2`,children:o(`profiles.orcaCloud.device.codeLabel`)}),(0,K.jsx)(`div`,{className:`mb-6 py-3 px-4 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg`,children:(0,K.jsx)(`span`,{className:`text-2xl font-mono font-bold tracking-[0.3em] text-white select-all`,children:e.user_code})}),(0,K.jsx)(`a`,{href:e.verification_uri_complete,target:`_blank`,rel:`noopener noreferrer`,children:(0,K.jsxs)($,{className:`w-full mb-3`,children:[(0,K.jsx)($s,{className:`w-4 h-4`}),o(`profiles.orcaCloud.device.openButton`)]})}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray break-all mb-6`,children:o(`profiles.orcaCloud.device.manualHint`,{url:e.verification_uri})}),(0,K.jsxs)(`div`,{className:`flex items-center justify-center gap-2 text-sm text-bambu-gray mb-4`,children:[(0,K.jsx)(X,{className:`w-4 h-4 animate-spin text-bambu-green`}),o(`profiles.orcaCloud.device.waiting`)]}),(0,K.jsx)(`button`,{type:`button`,onClick:r,className:`text-bambu-gray hover:text-white text-sm`,children:o(`profiles.orcaCloud.device.cancel`)})]})}):(0,K.jsx)(Od,{children:(0,K.jsxs)(Ad,{className:`p-8 text-center`,children:[(0,K.jsx)(ks,{className:`w-12 h-12 text-bambu-green mx-auto mb-4`}),(0,K.jsx)(`h2`,{className:`text-xl font-bold text-white mb-2`,children:o(`profiles.orcaCloud.connect.title`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray mb-6 max-w-xl mx-auto`,children:o(`profiles.orcaCloud.connect.description`)}),(0,K.jsxs)(`div`,{className:`max-w-sm mx-auto`,children:[(0,K.jsxs)($,{onClick:n,disabled:i||!a,title:a?void 0:o(`profiles.orcaCloud.noConnectPermission`),className:`w-full`,children:[i?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(cs,{className:`w-4 h-4`}),o(`profiles.orcaCloud.connectButton`)]}),t&&(0,K.jsxs)(`p`,{className:`mt-3 text-sm text-red-700 dark:text-red-400 flex items-center justify-center gap-2`,children:[(0,K.jsx)(hs,{className:`w-4 h-4 flex-shrink-0`}),t]})]})]})})}function U6(e,t){let n=`${e} ${t||``}`,r=n.match(/@?\s*(?:BBL\s+)?(?:Bambu\s+Lab\s+)?([XPAH][1-9][A-Z]?(?:\s*(?:Carbon|mini))?|H2D)/i),i=r?r[1].trim():null,a=n.match(/(\d+\.?\d*)\s*(?:mm\s*)?nozzle|nozzle\s*(\d+\.?\d*)/i),o=a?(a[1]||a[2])+`mm`:null,s=n.match(/(\d+\.?\d*)mm\s*(?:Standard|Fine|Extra Fine|Draft|Quality)?/i),c=s?s[1]+`mm`:null,l=n.match(/\b(PLA|PETG|ABS|ASA|TPU|PC|PA|PVA|HIPS|PP|PET(?:-?CF)?|PA(?:-?CF)?|PLA(?:-?CF)?)\b/i);return{printer:i,nozzle:o,layerHeight:c,filamentType:l?l[1].toUpperCase():null}}function W6(e){return/^(P[FPM]US|PF\d|PP\d)/.test(e)}function bWe({onSuccess:e,t}){let{showToast:n}=Id(),[r,i]=(0,y.useState)(`email`),[a,o]=(0,y.useState)(``),[s,c]=(0,y.useState)(``),[l,u]=(0,y.useState)(``),[d,f]=(0,y.useState)(``),[p,m]=(0,y.useState)(`global`),[h,g]=(0,y.useState)(null),[_,v]=(0,y.useState)(null),b=J({mutationFn:()=>Q.cloudLogin(a,s,p),onSuccess:r=>{r.success?(n(t(`profiles.login.toast.loggedIn`)),e()):r.needs_verification?(g(r.verification_type||`email`),v(r.tfa_key||null),r.verification_type===`totp`?n(t(`profiles.login.toast.enterTotp`)):n(t(`profiles.login.toast.codeSent`)),i(`code`)):n(r.message,`error`)},onError:e=>n(e.message,`error`)}),x=J({mutationFn:()=>Q.cloudVerify(a,l,_||void 0,p),onSuccess:r=>{r.success?(n(t(`profiles.login.toast.loggedIn`)),e()):n(r.message,`error`)},onError:e=>n(e.message,`error`)}),S=J({mutationFn:()=>Q.cloudSetToken(d,p),onSuccess:()=>{n(t(`profiles.login.toast.tokenSet`)),e()},onError:e=>n(e.message,`error`)}),C=e=>{e.preventDefault(),r===`email`?b.mutate():r===`code`?x.mutate():r===`token`&&S.mutate()},w=b.isPending||x.isPending||S.isPending;return(0,K.jsx)(Od,{className:`max-w-md mx-auto`,children:(0,K.jsxs)(Ad,{children:[(0,K.jsxs)(`div`,{className:`text-center mb-6`,children:[(0,K.jsx)(`div`,{className:`inline-flex items-center justify-center w-12 h-12 rounded-xl bg-bambu-green/20 mb-3`,children:(0,K.jsx)(ks,{className:`w-6 h-6 text-bambu-green`})}),(0,K.jsx)(`h2`,{className:`text-xl font-semibold text-white`,children:t(`profiles.login.title`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mt-1`,children:t(`profiles.login.subtitle`)})]}),(0,K.jsxs)(`form`,{onSubmit:C,className:`space-y-4`,children:[r===`email`&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:t(`profiles.login.email`)}),(0,K.jsx)(`input`,{type:`email`,value:a,onChange:e=>o(e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray-dark focus:border-bambu-green focus:outline-none`,placeholder:`your@email.com`,required:!0})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:t(`profiles.login.password`)}),(0,K.jsx)(`input`,{type:`password`,value:s,onChange:e=>c(e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray-dark focus:border-bambu-green focus:outline-none`,placeholder:`••••••••`,required:!0})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:t(`profiles.login.region`)}),(0,K.jsxs)(`select`,{value:p,onChange:e=>m(e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`global`,children:t(`profiles.login.regionGlobal`)}),(0,K.jsx)(`option`,{value:`china`,children:t(`profiles.login.regionChina`)})]})]})]}),r===`code`&&(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:t(h===`totp`?`profiles.login.totpCode`:`profiles.login.verificationCode`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mb-2`,children:h===`totp`?t(`profiles.login.enterTotpHint`):t(`profiles.login.checkEmail`,{email:a})}),(0,K.jsx)(`input`,{type:`text`,value:l,onChange:e=>u(e.target.value.replace(/\D/g,``).slice(0,6)),className:`w-full px-3 py-3 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-center text-2xl tracking-widest font-mono focus:border-bambu-green focus:outline-none`,placeholder:`000000`,maxLength:6,required:!0})]}),r===`token`&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:t(`profiles.login.accessToken`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mb-2`,children:t(`profiles.login.accessTokenHint`)}),(0,K.jsx)(`textarea`,{value:d,onChange:e=>f(e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-xs font-mono placeholder-bambu-gray-dark focus:border-bambu-green focus:outline-none resize-none`,placeholder:`eyJ...`,rows:4,required:!0})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:t(`profiles.login.region`)}),(0,K.jsxs)(`select`,{value:p,onChange:e=>m(e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`global`,children:t(`profiles.login.regionGlobal`)}),(0,K.jsx)(`option`,{value:`china`,children:t(`profiles.login.regionChina`)})]})]})]}),(0,K.jsxs)(`div`,{className:`flex gap-2 max-[550px]:flex-wrap max-[550px]:items-center`,children:[r===`code`&&(0,K.jsx)($,{type:`button`,variant:`secondary`,onClick:()=>i(`email`),className:`flex-1`,children:t(`profiles.login.back`)}),(0,K.jsxs)($,{type:`submit`,disabled:w,className:`flex-1`,children:[w?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)($c,{className:`w-4 h-4`}),t(r===`email`?`profiles.login.loginButton`:r===`code`?`profiles.login.verifyButton`:`profiles.login.setTokenButton`)]})]}),r===`email`&&(0,K.jsx)(`div`,{className:`pt-4 border-t border-bambu-dark-tertiary`,children:(0,K.jsxs)(`button`,{type:`button`,onClick:()=>i(`token`),className:`text-sm text-bambu-gray hover:text-white flex items-center gap-2 transition-colors`,children:[(0,K.jsx)(Vc,{className:`w-4 h-4`}),t(`profiles.login.useToken`)]})}),r===`token`&&(0,K.jsx)(`div`,{className:`pt-4 border-t border-bambu-dark-tertiary`,children:(0,K.jsxs)(`button`,{type:`button`,onClick:()=>i(`email`),className:`text-sm text-bambu-gray hover:text-white flex items-center gap-2 transition-colors`,children:[(0,K.jsx)($c,{className:`w-4 h-4`}),t(`profiles.login.useEmail`)]})})]})]})})}function G6({label:e,value:t,options:n,onChange:r}){let[i,a]=(0,y.useState)(!1),o=n.find(e=>e.value===t);return(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsxs)(`button`,{onClick:()=>a(!i),className:`flex items-center gap-2 px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-sm text-white hover:border-bambu-gray-dark transition-colors`,children:[(0,K.jsxs)(`span`,{className:`text-bambu-gray`,children:[e,`:`]}),(0,K.jsx)(`span`,{children:o?.label||`All`}),(0,K.jsx)(ls,{className:`w-4 h-4 text-bambu-gray transition-transform ${i?`rotate-180`:``}`})]}),i&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`div`,{className:`fixed inset-0 z-10`,onClick:()=>a(!1)}),(0,K.jsx)(`div`,{className:`absolute top-full left-0 mt-1 min-w-[160px] bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg shadow-xl z-20 py-1 max-h-60 overflow-y-auto`,children:n.map(e=>(0,K.jsxs)(`button`,{onClick:()=>{r(e.value),a(!1)},className:`w-full px-3 py-2 text-left text-sm flex items-center justify-between hover:bg-bambu-dark-tertiary transition-colors ${t===e.value?`text-bambu-green`:`text-white`}`,children:[(0,K.jsx)(`span`,{children:e.label}),e.count!==void 0&&(0,K.jsx)(`span`,{className:`text-bambu-gray text-xs`,children:e.count})]},e.value))})]})]})}function xWe(){let[e,t]=(0,y.useState)(!1);return(0,y.useEffect)(()=>{let e=()=>{t(window.scrollY>300)};return window.addEventListener(`scroll`,e),()=>window.removeEventListener(`scroll`,e)},[]),e?(0,K.jsx)(`button`,{onClick:()=>{window.scrollTo({top:0,behavior:`smooth`})},className:`fixed bottom-6 right-6 p-3 bg-bambu-green hover:bg-bambu-green-light text-white rounded-full shadow-lg shadow-bambu-green/25 transition-all z-40`,"aria-label":`Scroll to top`,children:(0,K.jsx)(Bo,{className:`w-5 h-5`})}):null}function K6({setting:e,onClick:t,onDuplicate:n,compareMode:r,isCompareSelected:i,compareIndex:a,compareDisabled:o,t:s}){let c=U6(e.name),l=W6(e.setting_id);return(0,K.jsxs)(`div`,{className:`flex items-center gap-2 group`,children:[(0,K.jsx)(`button`,{onClick:t,disabled:o,className:`flex-1 text-left px-3 py-2 rounded transition-colors ${i?`bg-blue-500/20 border border-blue-500/50`:o?`bg-bambu-dark/50 opacity-40 cursor-not-allowed`:`bg-bambu-dark hover:bg-bambu-dark-tertiary`} ${r&&!o?`cursor-pointer`:``}`,children:(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[i&&a!==void 0&&(0,K.jsx)(`span`,{className:`flex-shrink-0 w-5 h-5 rounded-full bg-blue-500 text-white text-xs flex items-center justify-center font-medium`,children:a+1}),!i&&l&&(0,K.jsx)(`span`,{className:`flex-shrink-0 w-1.5 h-1.5 rounded-full bg-bambu-green`,title:s(`profiles.presets.myPreset`)}),(0,K.jsx)(`span`,{className:`text-white text-sm truncate flex-1`,title:e.name,children:e.name}),c.filamentType&&e.type===`filament`&&(0,K.jsx)(`span`,{className:`text-xs text-bambu-gray whitespace-nowrap`,children:c.filamentType}),c.layerHeight&&e.type===`process`&&(0,K.jsx)(`span`,{className:`text-xs text-bambu-gray whitespace-nowrap`,children:c.layerHeight}),c.printer&&(0,K.jsx)(`span`,{className:`text-xs text-bambu-gray whitespace-nowrap`,children:c.printer})]})}),(0,K.jsx)(`button`,{onClick:e=>{e.stopPropagation(),n()},className:`opacity-0 group-hover:opacity-100 text-bambu-gray hover:text-white transition-all p-1`,title:s(`profiles.presets.duplicate`),children:(0,K.jsx)(Ls,{className:`w-4 h-4`})})]})}function q6(e,t=0){let n=` `.repeat(t);if(e===null)return`null`;if(e===void 0)return`undefined`;if(typeof e==`string`){if(e.includes(`\\n`)||e.includes(` +`)),i(!0),setTimeout(()=>i(!1),2e3)},className:`flex items-center gap-2`,children:[(0,K.jsx)(Ls,{className:`w-4 h-4`}),n(r?`common.copied`:`common.copy`)]}),(0,K.jsx)($,{variant:`primary`,size:`sm`,onClick:t,className:`flex-1`,children:n(`settings.twoFa.savedCodes`)})]})]})}function KUe({onDone:e}){let{t}=W(),n=oo(),{showToast:r}=Id(),[i,a]=(0,y.useState)(`qr`),[o,s]=(0,y.useState)(``),[c,l]=(0,y.useState)([]),[u,d]=(0,y.useState)(!1),{data:f,isLoading:p}=q({queryKey:[`totp-setup`],queryFn:()=>Q.setupTOTP(),staleTime:1/0}),m=J({mutationFn:e=>Q.enableTOTP(e),onSuccess:e=>{l(e.backup_codes),a(`backup`),n.invalidateQueries({queryKey:[`2fa-status`]})},onError:()=>r(t(`settings.twoFa.invalidCode`),`error`)});return p||!f?(0,K.jsx)(`div`,{className:`flex items-center justify-center py-8`,children:(0,K.jsx)(Il,{className:`w-6 h-6 animate-spin text-bambu-green`})}):i===`qr`?(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(`p`,{className:`text-bambu-gray-light text-sm`,children:t(`settings.twoFa.setupInstructions`)}),(0,K.jsx)(`div`,{className:`flex justify-center`,children:(0,K.jsx)(`img`,{src:`data:image/png;base64,${f.qr_code_b64}`,alt:`TOTP QR Code`,className:`w-48 h-48 rounded-lg`})}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mb-1`,children:t(`settings.twoFa.manualEntry`)}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 bg-bambu-dark-secondary rounded-lg px-3 py-2`,children:[(0,K.jsx)(`code`,{className:`text-white text-xs font-mono flex-1 break-all`,children:u?f.secret:`••••••••••••••••`}),(0,K.jsx)(`button`,{onClick:()=>d(!u),className:`text-bambu-gray hover:text-white`,children:u?(0,K.jsx)(ec,{className:`w-4 h-4`}):(0,K.jsx)(tc,{className:`w-4 h-4`})}),(0,K.jsx)(`button`,{onClick:()=>{navigator.clipboard.writeText(f.secret)},className:`text-bambu-gray hover:text-white`,children:(0,K.jsx)(Ls,{className:`w-4 h-4`})})]})]}),(0,K.jsx)($,{variant:`primary`,className:`w-full`,onClick:()=>a(`confirm`),children:t(`settings.twoFa.scannedContinue`)})]}):i===`confirm`?(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(`p`,{className:`text-bambu-gray-light text-sm`,children:t(`settings.twoFa.enterCodeToConfirm`)}),(0,K.jsx)(b6,{value:o,onChange:s,placeholder:`000000`}),(0,K.jsxs)(`div`,{className:`flex gap-3`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:()=>a(`qr`),className:`flex-1`,children:t(`common.back`)}),(0,K.jsx)($,{variant:`primary`,className:`flex-1`,disabled:o.length!==6||m.isPending,onClick:()=>m.mutate(o),children:m.isPending?t(`common.saving`):t(`settings.twoFa.activate`)})]})]}):(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(`h3`,{className:`text-white font-medium`,children:t(`settings.twoFa.backupCodesTitle`)}),(0,K.jsx)(x6,{codes:c,onDone:e})]})}function qUe(){let{t:e}=W(),t=oo(),{showToast:n}=Id(),{user:r}=Sd(),[i,a]=(0,y.useState)(!1),[o,s]=(0,y.useState)(!1),[c,l]=(0,y.useState)(!1),[u,d]=(0,y.useState)(``),[f,p]=(0,y.useState)(``),[m,h]=(0,y.useState)(null),[g,_]=(0,y.useState)(null),[v,b]=(0,y.useState)(``),[x,S]=(0,y.useState)(!1),[C,w]=(0,y.useState)(``),[T,E]=(0,y.useState)(!1),{data:D,isLoading:O}=q({queryKey:[`2fa-status`],queryFn:()=>Q.get2FAStatus()}),{data:k}=q({queryKey:[`oidc-links`],queryFn:()=>Q.getOIDCLinks()}),A=J({mutationFn:()=>Q.enableEmailOTP(),onSuccess:e=>{_(e.setup_token),n(e.message,`success`)},onError:t=>{let r=t.message??``;r.toLowerCase().includes(`smtp`)?n(e(`settings.twoFa.smtpRequired`),`error`):n(r,`error`)}}),j=J({mutationFn:()=>Q.confirmEnableEmailOTP(g,v),onSuccess:()=>{t.invalidateQueries({queryKey:[`2fa-status`]}),_(null),b(``),n(e(`settings.twoFa.emailOtpEnabled`),`success`)},onError:e=>n(e.message,`error`)}),M=J({mutationFn:e=>Q.disableEmailOTP(e),onSuccess:()=>{t.invalidateQueries({queryKey:[`2fa-status`]}),S(!1),w(``),n(e(`settings.twoFa.emailOtpDisabled`),`success`)},onError:e=>n(e.message,`error`)}),N=J({mutationFn:e=>Q.disableTOTP(e),onSuccess:()=>{t.invalidateQueries({queryKey:[`2fa-status`]}),s(!1),d(``),n(e(`settings.twoFa.totpDisabled`),`success`)},onError:()=>n(e(`settings.twoFa.invalidCode`),`error`)}),P=J({mutationFn:e=>Q.regenerateBackupCodes(e),onSuccess:e=>{t.invalidateQueries({queryKey:[`2fa-status`]}),l(!1),p(``),h(e.backup_codes)},onError:()=>n(e(`settings.twoFa.invalidCode`),`error`)}),F=J({mutationFn:e=>Q.deleteOIDCLink(e),onSuccess:()=>{t.invalidateQueries({queryKey:[`oidc-links`]}),n(e(`settings.twoFa.oidcUnlinked`),`success`)},onError:e=>n(e.message,`error`)});if(O)return(0,K.jsx)(`div`,{className:`flex items-center justify-center py-12`,children:(0,K.jsx)(Il,{className:`w-6 h-6 animate-spin text-bambu-green`})});let I=!!r?.email;return(0,K.jsxs)(`div`,{className:`space-y-6`,children:[(0,K.jsxs)(Od,{id:`card-2fa-totp`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,K.jsx)(`div`,{className:`w-10 h-10 rounded-full flex items-center justify-center ${D?.totp_enabled?`bg-green-100 dark:bg-green-500/20`:`bg-gray-500/20`}`,children:(0,K.jsx)(cu,{className:`w-5 h-5 ${D?.totp_enabled?`text-green-600 dark:text-green-400`:`text-gray-400`}`})}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`text-white font-semibold`,children:e(`settings.twoFa.totpTitle`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-sm`,children:e(`settings.twoFa.totpDesc`)})]}),(0,K.jsx)(`div`,{className:`ml-auto`,children:D?.totp_enabled?(0,K.jsxs)(`span`,{className:`flex items-center gap-1 text-green-700 dark:text-green-400 text-sm font-medium`,children:[(0,K.jsx)($l,{className:`w-4 h-4`}),` `,e(`common.enabled`)]}):(0,K.jsxs)(`span`,{className:`flex items-center gap-1 text-bambu-gray text-sm`,children:[(0,K.jsx)(eu,{className:`w-4 h-4`}),` `,e(`common.disabled`)]})})]})}),(0,K.jsx)(Ad,{children:i?(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between mb-2`,children:[(0,K.jsx)(`h4`,{className:`text-white font-medium`,children:e(`settings.twoFa.setupAuthApp`)}),(0,K.jsx)(`button`,{onClick:()=>{a(!1),t.removeQueries({queryKey:[`totp-setup`]})},className:`text-bambu-gray hover:text-white`,children:(0,K.jsx)(Yu,{className:`w-5 h-5`})})]}),(0,K.jsx)(KUe,{onDone:()=>{a(!1),t.removeQueries({queryKey:[`totp-setup`]})}})]}):o?(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(`p`,{className:`text-bambu-gray-light text-sm`,children:e(`settings.twoFa.disableConfirmHint`)}),(0,K.jsx)(b6,{value:u,onChange:d,placeholder:`000000 or XXXXXXXX`,maxLength:8}),(0,K.jsxs)(`div`,{className:`flex gap-3`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:()=>{s(!1),d(``)},className:`flex-1`,children:e(`common.cancel`)}),(0,K.jsx)($,{variant:`danger`,className:`flex-1`,disabled:u.length<6||N.isPending,onClick:()=>N.mutate(u),children:N.isPending?e(`common.saving`):e(`settings.twoFa.disableTotp`)})]})]}):c?(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(`p`,{className:`text-bambu-gray-light text-sm`,children:e(`settings.twoFa.regenBackupHint`)}),(0,K.jsx)(b6,{value:f,onChange:p,placeholder:`000000 or XXXXXXXX`,maxLength:8}),(0,K.jsxs)(`div`,{className:`flex gap-3`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:()=>{l(!1),p(``)},className:`flex-1`,children:e(`common.cancel`)}),(0,K.jsx)($,{variant:`primary`,className:`flex-1`,disabled:f.length<6||P.isPending,onClick:()=>P.mutate(f),children:P.isPending?e(`common.saving`):e(`settings.twoFa.regenBackup`)})]})]}):m?(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(`h4`,{className:`text-white font-medium`,children:e(`settings.twoFa.newBackupCodes`)}),(0,K.jsx)(x6,{codes:m,onDone:()=>h(null)})]}):(0,K.jsx)(`div`,{className:`space-y-3`,children:D?.totp_enabled?(0,K.jsxs)(`div`,{className:`flex flex-wrap gap-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-sm text-bambu-gray-light`,children:[(0,K.jsx)(Vc,{className:`w-4 h-4`}),e(`settings.twoFa.backupCodesRemaining`,{count:D.backup_codes_remaining})]}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,onClick:()=>l(!0),className:`flex items-center gap-2`,children:[(0,K.jsx)(Il,{className:`w-4 h-4`}),e(`settings.twoFa.regenBackup`)]}),(0,K.jsxs)($,{variant:`danger`,size:`sm`,onClick:()=>s(!0),className:`flex items-center gap-2`,children:[(0,K.jsx)(Ou,{className:`w-4 h-4`}),e(`settings.twoFa.disableTotp`)]})]}):(0,K.jsxs)($,{variant:`primary`,onClick:()=>a(!0),className:`flex items-center gap-2`,children:[(0,K.jsx)(cu,{className:`w-4 h-4`}),e(`settings.twoFa.setupTotp`)]})})})]}),(0,K.jsxs)(Od,{id:`card-2fa-emailotp`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,K.jsx)(`div`,{className:`w-10 h-10 rounded-full flex items-center justify-center ${D?.email_otp_enabled?`bg-green-100 dark:bg-green-500/20`:`bg-gray-500/20`}`,children:(0,K.jsx)(tl,{className:`w-5 h-5 ${D?.email_otp_enabled?`text-green-600 dark:text-green-400`:`text-gray-400`}`})}),(0,K.jsxs)(`div`,{className:`flex-1`,children:[(0,K.jsx)(`h3`,{className:`text-white font-semibold`,children:e(`settings.twoFa.emailOtpTitle`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-sm`,children:I?e(`settings.twoFa.emailOtpDesc`,{email:r?.email}):e(`settings.twoFa.emailOtpNoEmail`)})]}),(0,K.jsx)(`div`,{className:`ml-auto`,children:D?.email_otp_enabled?(0,K.jsxs)(`span`,{className:`flex items-center gap-1 text-green-700 dark:text-green-400 text-sm font-medium`,children:[(0,K.jsx)($l,{className:`w-4 h-4`}),` `,e(`common.enabled`)]}):(0,K.jsxs)(`span`,{className:`flex items-center gap-1 text-bambu-gray text-sm`,children:[(0,K.jsx)(eu,{className:`w-4 h-4`}),` `,e(`common.disabled`)]})})]})}),(0,K.jsx)(Ad,{children:I?g?(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(`p`,{className:`text-bambu-gray-light text-sm`,children:e(`settings.twoFa.emailSetupEnterCode`)}),(0,K.jsx)(b6,{value:v,onChange:b,placeholder:`000000`}),(0,K.jsxs)(`div`,{className:`flex gap-3`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:()=>{_(null),b(``)},className:`flex-1`,children:e(`common.cancel`)}),(0,K.jsx)($,{variant:`primary`,className:`flex-1`,disabled:v.length!==6||j.isPending,onClick:()=>j.mutate(),children:j.isPending?e(`common.saving`):e(`settings.twoFa.verifyAndEnable`)})]})]}):x?(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(`p`,{className:`text-bambu-gray-light text-sm`,children:e(`settings.twoFa.emailDisablePasswordHint`)}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`input`,{type:T?`text`:`password`,value:C,onChange:e=>w(e.target.value),placeholder:e(`settings.twoFa.passwordPlaceholder`),className:`w-full px-4 py-3 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors`}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>E(!T),className:`absolute right-3 top-1/2 -translate-y-1/2 text-bambu-gray hover:text-white`,children:T?(0,K.jsx)(ec,{className:`w-5 h-5`}):(0,K.jsx)(tc,{className:`w-5 h-5`})})]}),(0,K.jsxs)(`div`,{className:`flex gap-3`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:()=>{S(!1),w(``)},className:`flex-1`,children:e(`common.cancel`)}),(0,K.jsx)($,{variant:`danger`,className:`flex-1`,disabled:!C||M.isPending,onClick:()=>M.mutate(C),children:M.isPending?e(`common.saving`):e(`settings.twoFa.disableEmailOtp`)})]})]}):(0,K.jsx)(`div`,{className:`flex gap-3`,children:D?.email_otp_enabled?(0,K.jsxs)($,{variant:`danger`,size:`sm`,onClick:()=>S(!0),className:`flex items-center gap-2`,children:[(0,K.jsx)(Ou,{className:`w-4 h-4`}),e(`settings.twoFa.disableEmailOtp`)]}):(0,K.jsxs)($,{variant:`primary`,disabled:!I||A.isPending,onClick:()=>A.mutate(),className:`flex items-center gap-2`,children:[(0,K.jsx)(tl,{className:`w-4 h-4`}),A.isPending?e(`common.saving`):e(`settings.twoFa.enableEmailOtp`)]})}):(0,K.jsx)(`p`,{className:`text-amber-700 dark:text-amber-400 text-sm`,children:e(`settings.twoFa.addEmailFirst`)})})]}),k&&k.length>0&&(0,K.jsxs)(Od,{id:`card-2fa-linked`,children:[(0,K.jsxs)(kd,{children:[(0,K.jsx)(`h3`,{className:`text-white font-semibold`,children:e(`settings.twoFa.linkedAccounts`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-sm`,children:e(`settings.twoFa.linkedAccountsDesc`)})]}),(0,K.jsx)(Ad,{children:(0,K.jsx)(`div`,{className:`space-y-3`,children:k.map(e=>(0,K.jsxs)(`div`,{className:`flex items-center justify-between py-2 border-b border-bambu-dark-tertiary last:border-0`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white text-sm font-medium`,children:e.provider_name}),e.provider_email&&(0,K.jsx)(`p`,{className:`text-bambu-gray text-xs`,children:e.provider_email})]}),(0,K.jsx)($,{variant:`danger`,size:`sm`,onClick:()=>F.mutate(e.provider_id),disabled:F.isPending,children:(0,K.jsx)(Ou,{className:`w-4 h-4`})})]},e.id))})})]})]})}var JUe={name:``,issuer_url:``,client_id:``,client_secret:``,scopes:`openid email profile`,is_enabled:!0,auto_create_users:!1,auto_link_existing_accounts:!1,email_claim:`email`,require_email_verified:!0,icon_url:void 0,default_group_id:null,is_autologin:!1};function S6({initial:e,isEdit:t=!1,groups:n=[],onSave:r,onCancel:i,isPending:a}){let{t:o}=W(),[s,c]=(0,y.useState)(e),[l,u]=(0,y.useState)(!1),d=(e,t)=>c(n=>({...n,[e]:t})),f=`w-full px-4 py-3 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors text-sm`,p=`block text-sm font-medium text-white mb-1`,m=()=>{let e={...s};t&&!l&&delete e.client_secret,r(e)},h=s.auto_link_existing_accounts===!0,g=s.require_email_verified??!0,_;return _=h?o(`settings.oidc.form.requireEmailVerifiedAutoLink`):g?o(`settings.oidc.form.requireEmailVerifiedDesc`):(0,K.jsx)(`span`,{className:`text-red-700 dark:text-red-400`,children:o(`settings.oidc.form.requireEmailVerifiedWarning`)}),(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 gap-4`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:p,children:[o(`settings.oidc.form.name`),` `,(0,K.jsx)(`span`,{className:`text-red-700 dark:text-red-400`,children:`*`})]}),(0,K.jsx)(`input`,{className:f,value:s.name,onChange:e=>d(`name`,e.target.value),placeholder:`Google`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:p,children:[o(`settings.oidc.form.issuerUrl`),` `,(0,K.jsx)(`span`,{className:`text-red-700 dark:text-red-400`,children:`*`})]}),(0,K.jsx)(`input`,{className:f,value:s.issuer_url,onChange:e=>d(`issuer_url`,e.target.value),placeholder:`https://accounts.google.com`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:p,children:[o(`settings.oidc.form.clientId`),` `,(0,K.jsx)(`span`,{className:`text-red-700 dark:text-red-400`,children:`*`})]}),(0,K.jsx)(`input`,{className:f,value:s.client_id,onChange:e=>d(`client_id`,e.target.value),placeholder:`your-client-id`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:p,children:[o(`settings.oidc.form.clientSecret`),!t&&(0,K.jsx)(`span`,{className:`text-red-700 dark:text-red-400`,children:` *`}),t&&(0,K.jsxs)(`span`,{className:`text-bambu-gray text-xs ml-1`,children:[`(`,o(`settings.oidc.form.secretHint`),`)`]})]}),(0,K.jsx)(`input`,{className:f,type:`password`,value:l?s.client_secret:``,placeholder:t&&!l?`••••••••`:o(`settings.oidc.form.secretPlaceholder`),onChange:e=>{u(!0),d(`client_secret`,e.target.value)}})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:p,children:o(`settings.oidc.form.scopes`)}),(0,K.jsx)(`input`,{className:f,value:s.scopes,onChange:e=>d(`scopes`,e.target.value),placeholder:`openid email profile`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:p,children:o(`settings.oidc.form.iconUrl`)}),(0,K.jsx)(`input`,{className:f,value:s.icon_url??``,onChange:e=>d(`icon_url`,e.target.value===``?null:e.target.value),placeholder:`https://...`})]})]}),(0,K.jsxs)(`div`,{className:`flex flex-wrap gap-6 pt-2`,children:[(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer`,children:[(0,K.jsx)(oU,{checked:s.is_enabled??!0,onChange:e=>d(`is_enabled`,e)}),(0,K.jsx)(`span`,{className:`text-white text-sm`,children:o(`settings.oidc.form.enabled`)})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer`,children:[(0,K.jsx)(oU,{checked:s.auto_create_users??!1,onChange:e=>d(`auto_create_users`,e)}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white text-sm`,children:o(`settings.oidc.form.autoCreate`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-xs`,children:o(`settings.oidc.form.autoCreateDesc`)})]})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer w-full`,children:[(0,K.jsx)(oU,{checked:s.auto_link_existing_accounts??!1,onChange:e=>d(`auto_link_existing_accounts`,e)}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white text-sm`,children:o(`settings.oidc.form.autoLink`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-xs`,children:o(`settings.oidc.form.autoLinkDesc`)})]})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer w-full`,children:[(0,K.jsx)(oU,{checked:g,onChange:e=>d(`require_email_verified`,e),disabled:h}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white text-sm`,children:o(`settings.oidc.form.requireEmailVerified`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-xs`,children:_})]})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer w-full`,children:[(0,K.jsx)(oU,{checked:s.is_autologin??!1,onChange:e=>d(`is_autologin`,e)}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white text-sm`,children:o(`settings.oidc.form.autologin`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-xs`,children:o(`settings.oidc.form.autologinDesc`)})]})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:p,children:o(`settings.oidc.form.emailClaim`)}),(0,K.jsx)(`input`,{className:f,value:s.email_claim,onChange:e=>d(`email_claim`,e.target.value||`email`),placeholder:o(`settings.oidc.form.emailClaimPlaceholder`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-xs mt-1`,children:o(`settings.oidc.form.emailClaimDesc`)}),h&&s.email_claim!==`email`&&(0,K.jsx)(`p`,{className:`text-yellow-700 dark:text-yellow-400 text-xs mt-1`,children:o(`settings.oidc.form.emailClaimCustomClaimAutoLinkWarning`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:p,children:o(`settings.oidc.form.defaultGroup`)}),(0,K.jsxs)(`select`,{className:f,value:s.default_group_id??``,onChange:e=>d(`default_group_id`,e.target.value?Number(e.target.value):null),children:[(0,K.jsx)(`option`,{value:``,children:o(`settings.oidc.form.defaultGroupViewersFallback`)}),n.map(e=>(0,K.jsx)(`option`,{value:e.id,children:e.name},e.id))]}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-xs mt-1`,children:o(`settings.oidc.form.defaultGroupDesc`)})]}),(0,K.jsxs)(`div`,{className:`flex gap-3 pt-2`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:i,className:`flex-1`,children:o(`common.cancel`)}),(0,K.jsx)($,{variant:`primary`,className:`flex-1`,disabled:!s.name||!s.issuer_url||!s.client_id||!t&&!s.client_secret||t&&l&&!s.client_secret||a,onClick:m,children:o(a?`common.saving`:`common.save`)})]})]})}function YUe({provider:e}){let[t,n]=(0,y.useState)(!1);return e.has_icon&&!t?(0,K.jsx)(`img`,{src:Q.oidcProviderIconUrl(e.id),alt:e.name,className:`w-8 h-8 rounded object-contain`,onError:()=>n(!0)}):(0,K.jsx)(`div`,{className:`w-8 h-8 rounded-full bg-bambu-dark-tertiary flex items-center justify-center`,children:(0,K.jsx)(Tc,{className:`w-4 h-4 text-bambu-gray`})})}function XUe(){let{t:e}=W(),t=oo(),{showToast:n}=Id(),[r,i]=(0,y.useState)(!1),[a,o]=(0,y.useState)(null),[s,c]=(0,y.useState)(null),{data:l,isLoading:u}=q({queryKey:[`oidc-providers-all`],queryFn:()=>Q.getOIDCProvidersAll()}),{data:d=[]}=q({queryKey:[`groups`],queryFn:()=>Q.getGroups()}),f=J({mutationFn:e=>Q.createOIDCProvider(e),onSuccess:()=>{t.invalidateQueries({queryKey:[`oidc-providers-all`]}),i(!1),n(e(`settings.oidc.created`),`success`)},onError:e=>n(e.message,`error`)}),p=J({mutationFn:({id:e,data:t})=>Q.updateOIDCProvider(e,t),onSuccess:()=>{t.invalidateQueries({queryKey:[`oidc-providers-all`]}),o(null),n(e(`settings.oidc.updated`),`success`)},onError:e=>n(e.message,`error`)}),m=J({mutationFn:e=>Q.deleteOIDCProvider(e),onSuccess:()=>{t.invalidateQueries({queryKey:[`oidc-providers-all`]}),c(null),n(e(`settings.oidc.deleted`),`success`)},onError:e=>n(e.message,`error`)}),h=J({mutationFn:e=>Q.refreshOIDCProviderIcon(e),onSuccess:()=>{t.invalidateQueries({queryKey:[`oidc-providers-all`]}),t.invalidateQueries({queryKey:[`oidc-providers`]}),n(e(`settings.oidc.iconRefreshed`),`success`)},onError:t=>n(t.message||e(`settings.oidc.iconFetchFailed`),`error`)}),g=J({mutationFn:e=>Q.deleteOIDCProviderIcon(e),onSuccess:()=>{t.invalidateQueries({queryKey:[`oidc-providers-all`]}),t.invalidateQueries({queryKey:[`oidc-providers`]}),n(e(`settings.oidc.iconRemoved`),`success`)},onError:e=>n(e.message,`error`)}),_=e=>p.mutate({id:e.id,data:{is_enabled:!e.is_enabled}});return u?(0,K.jsx)(`div`,{className:`flex items-center justify-center py-12`,children:(0,K.jsx)(Il,{className:`w-6 h-6 animate-spin text-bambu-green`})}):(0,K.jsxs)(`div`,{className:`space-y-6`,children:[(0,K.jsxs)(Od,{id:`card-oidc`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`text-white font-semibold`,children:e(`settings.oidc.title`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-sm`,children:e(`settings.oidc.desc`)})]}),!r&&(0,K.jsxs)($,{variant:`primary`,size:`sm`,onClick:()=>i(!0),className:`flex items-center gap-2`,children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),e(`settings.oidc.addProvider`)]})]})}),r&&(0,K.jsx)(Ad,{children:(0,K.jsxs)(`div`,{className:`border-t border-bambu-dark-tertiary pt-4`,children:[(0,K.jsx)(`h4`,{className:`text-white font-medium mb-4`,children:e(`settings.oidc.newProvider`)}),(0,K.jsx)(S6,{initial:JUe,groups:d,onSave:e=>f.mutate(e),onCancel:()=>i(!1),isPending:f.isPending})]})})]}),l&&l.length===0&&!r&&(0,K.jsx)(Od,{id:`card-oidc-empty`,children:(0,K.jsx)(Ad,{children:(0,K.jsxs)(`div`,{className:`text-center py-8 space-y-3`,children:[(0,K.jsx)(Tc,{className:`w-12 h-12 text-bambu-gray mx-auto`}),(0,K.jsx)(`p`,{className:`text-bambu-gray`,children:e(`settings.oidc.empty`)}),(0,K.jsxs)($,{variant:`primary`,size:`sm`,onClick:()=>i(!0),className:`inline-flex items-center gap-2`,children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),e(`settings.oidc.addProvider`)]})]})})}),l?.map(t=>(0,K.jsxs)(Od,{children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,K.jsx)(YUe,{provider:t}),(0,K.jsxs)(`div`,{className:`flex-1`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`h4`,{className:`text-white font-medium`,children:t.name}),t.is_enabled?(0,K.jsxs)(`span`,{className:`flex items-center gap-1 text-xs text-green-700 dark:text-green-400 bg-green-50 dark:bg-green-400/10 px-2 py-0.5 rounded-full`,children:[(0,K.jsx)(cs,{className:`w-3 h-3`}),` `,e(`common.enabled`)]}):(0,K.jsxs)(`span`,{className:`flex items-center gap-1 text-xs text-bambu-gray bg-bambu-dark-tertiary px-2 py-0.5 rounded-full`,children:[(0,K.jsx)(Yu,{className:`w-3 h-3`}),` `,e(`common.disabled`)]}),t.is_env_managed&&(0,K.jsxs)(`span`,{className:`flex items-center gap-1 text-xs text-bambu-green`,children:[(0,K.jsx)(Qc,{className:`w-3 h-3`}),` `,e(`settings.environmentManagedLabel`)]})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-1 text-bambu-gray text-xs mt-0.5`,children:[(0,K.jsx)($s,{className:`w-3 h-3`}),(0,K.jsx)(`span`,{children:t.issuer_url})]})]}),(0,K.jsx)(`div`,{className:`flex items-center gap-2`,children:!t.is_env_managed&&(0,K.jsxs)(K.Fragment,{children:[t.icon_url&&(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>h.mutate(t.id),disabled:h.isPending,title:e(`settings.oidc.refreshIcon`),"data-testid":`refresh-icon-${t.id}`,children:(0,K.jsx)(Il,{className:`w-4 h-4 ${h.isPending?`animate-spin`:``}`})}),t.has_icon&&(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>g.mutate(t.id),disabled:g.isPending,title:e(`settings.oidc.removeIcon`),"data-testid":`remove-icon-${t.id}`,children:(0,K.jsx)(Ic,{className:`w-4 h-4`})}),(0,K.jsx)(oU,{checked:t.is_enabled,onChange:()=>_(t),disabled:p.isPending}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>o(a===t.id?null:t.id),"data-testid":`edit-provider-${t.id}`,children:(0,K.jsx)(Tl,{className:`w-4 h-4`})}),(0,K.jsx)($,{variant:`danger`,size:`sm`,onClick:()=>c(t),"data-testid":`delete-provider-${t.id}`,children:(0,K.jsx)(Ou,{className:`w-4 h-4`})})]})})]})}),a===t.id&&(0,K.jsx)(Ad,{children:(0,K.jsx)(`div`,{className:`border-t border-bambu-dark-tertiary pt-4`,children:(0,K.jsx)(S6,{isEdit:!0,groups:d,initial:{name:t.name,issuer_url:t.issuer_url,client_id:t.client_id,client_secret:``,scopes:t.scopes,is_enabled:t.is_enabled,auto_create_users:t.auto_create_users,auto_link_existing_accounts:t.auto_link_existing_accounts,email_claim:t.email_claim,require_email_verified:t.require_email_verified,icon_url:t.icon_url??void 0,default_group_id:t.default_group_id??null,is_autologin:t.is_autologin},onSave:e=>p.mutate({id:t.id,data:e}),onCancel:()=>o(null),isPending:p.isPending})})}),a!==t.id&&(0,K.jsx)(Ad,{children:(0,K.jsxs)(`dl`,{className:`grid grid-cols-2 sm:grid-cols-3 gap-x-6 gap-y-2 text-sm`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`dt`,{className:`text-bambu-gray`,children:e(`settings.oidc.form.clientId`)}),(0,K.jsx)(`dd`,{className:`text-white font-mono truncate`,children:t.client_id})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`dt`,{className:`text-bambu-gray`,children:e(`settings.oidc.form.scopes`)}),(0,K.jsx)(`dd`,{className:`text-white`,children:t.scopes})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`dt`,{className:`text-bambu-gray`,children:e(`settings.oidc.form.autoCreate`)}),(0,K.jsx)(`dd`,{className:t.auto_create_users?`text-green-700 dark:text-green-400`:`text-bambu-gray`,children:t.auto_create_users?e(`common.yes`):e(`common.no`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`dt`,{className:`text-bambu-gray`,children:e(`settings.oidc.form.autoLink`)}),(0,K.jsx)(`dd`,{className:t.auto_link_existing_accounts?`text-green-700 dark:text-green-400`:`text-bambu-gray`,children:t.auto_link_existing_accounts?e(`common.yes`):e(`common.no`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`dt`,{className:`text-bambu-gray`,children:e(`settings.oidc.form.emailClaim`)}),(0,K.jsx)(`dd`,{className:`text-white font-mono`,children:t.email_claim})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`dt`,{className:`text-bambu-gray`,children:e(`settings.oidc.form.requireEmailVerified`)}),(0,K.jsx)(`dd`,{className:t.require_email_verified?`text-green-700 dark:text-green-400`:`text-red-700 dark:text-red-400`,children:t.require_email_verified?e(`common.yes`):e(`common.no`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`dt`,{className:`text-bambu-gray`,children:e(`settings.oidc.form.defaultGroup`)}),(0,K.jsx)(`dd`,{className:`text-white`,children:t.default_group_id?d.find(e=>e.id===t.default_group_id)?.name??e(`settings.oidc.form.defaultGroupViewersFallback`):e(`settings.oidc.form.defaultGroupViewersFallback`)})]})]})})]},t.id)),s&&(0,K.jsx)(Gd,{title:e(`settings.oidc.deleteTitle`),message:e(`settings.oidc.deleteMessage`,{name:s.name}),confirmText:e(`common.delete`),variant:`danger`,onConfirm:()=>m.mutate(s.id),onCancel:()=>c(null)})]})}var C6=new Map;function w6(e){C6.set(e.anchor,e)}function ZUe(){return Array.from(C6.values())}w6({labelKey:`settings.encryption.title`,labelFallback:`MFA Encryption Status`,tab:`users`,subTab:`security`,keywords:`mfa encryption status security backup totp oidc fernet`,anchor:`card-mfa-encryption`});function QUe(){let{t:e}=W(),{data:t,isLoading:n,isError:r,refetch:i}=q({queryKey:[`encryptionStatus`],queryFn:()=>Q.getEncryptionStatus(),refetchInterval:e=>{if(!e.state.error)return 3e4;let t=e.state.fetchFailureCount??0;return t<=3?Math.min(5e3*Math.max(1,t),3e4):!1}});if(n)return(0,K.jsxs)(Od,{id:`card-mfa-encryption`,"data-testid":`encryption-status-card`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(tu,{className:`text-bambu-gray`,size:20}),(0,K.jsx)(`h2`,{className:`text-lg font-semibold`,children:e(`settings.encryption.title`)})]})}),(0,K.jsx)(Ad,{children:(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-bambu-gray`,"data-testid":`encryption-loading`,children:[(0,K.jsx)(X,{className:`animate-spin`,size:16}),(0,K.jsx)(`span`,{children:e(`common.loading`)})]})})]});if(r||!t)return(0,K.jsxs)(Od,{id:`card-mfa-encryption`,"data-testid":`encryption-status-card`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(tu,{className:`text-bambu-gray`,size:20}),(0,K.jsx)(`h2`,{className:`text-lg font-semibold`,children:e(`settings.encryption.title`)})]})}),(0,K.jsxs)(Ad,{children:[(0,K.jsx)(`div`,{className:`text-red-700 dark:text-red-400`,"data-testid":`encryption-error`,children:e(`common.errorLoading`)}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>i(),className:`mt-2 text-sm text-blue-700 dark:text-blue-400 underline hover:text-blue-800 dark:hover:text-blue-300`,"data-testid":`encryption-retry-button`,children:e(`common.retry`)})]})]});let a=t.legacy_plaintext_rows.oidc_providers+t.legacy_plaintext_rows.user_totp,o=t.encrypted_rows.oidc_providers+t.encrypted_rows.user_totp,s,c,l,u;t.decryption_broken?(s=`bg-red-100 dark:bg-red-500/20 border-red-400 dark:border-red-500/50 text-red-700 dark:text-red-400`,c=(0,K.jsx)(Cs,{className:`text-red-600 dark:text-red-400`,size:20}),l=e(`settings.encryption.decryptionBrokenTitle`),u=e(`settings.encryption.decryptionBrokenError`,{count:o})):t.key_source===`generated`?(s=`bg-amber-50 dark:bg-amber-500/10 border-amber-300 dark:border-amber-500/30 text-amber-700 dark:text-amber-400`,c=(0,K.jsx)($l,{className:`text-amber-600 dark:text-amber-400`,size:20}),l=e(`settings.encryption.enabledGenerated`),u=e(`settings.encryption.backupHint`)):a>0?(s=`bg-amber-50 dark:bg-amber-500/10 border-amber-300 dark:border-amber-500/30 text-amber-700 dark:text-amber-400`,c=(0,K.jsx)(ju,{className:`text-amber-600 dark:text-amber-400`,size:20}),l=t.key_source===`env`?e(`settings.encryption.enabledFromEnv`):e(`settings.encryption.enabledFromFile`),u=e(`settings.encryption.legacyRowsWarning`,{count:a})):t.key_configured?(s=`bg-green-100 dark:bg-green-500/20 border-green-300 dark:border-green-500/30 text-green-700 dark:text-green-400`,c=(0,K.jsx)($l,{className:`text-green-600 dark:text-green-400`,size:20}),l=t.key_source===`env`?e(`settings.encryption.enabledFromEnv`):e(`settings.encryption.enabledFromFile`),u=e(`settings.encryption.allEncrypted`)):(s=`bg-gray-500/20 border-gray-500/30 text-gray-400`,c=(0,K.jsx)(eu,{className:`text-gray-400`,size:20}),l=e(`settings.encryption.notConfigured`),u=e(`settings.encryption.notConfiguredDesc`));let d=t.key_source===`generated`&&a>0;return(0,K.jsxs)(Od,{id:`card-mfa-encryption`,"data-testid":`encryption-status-card`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[c,(0,K.jsx)(`h2`,{className:`text-lg font-semibold`,children:e(`settings.encryption.title`)})]})}),(0,K.jsxs)(Ad,{children:[(0,K.jsxs)(`div`,{className:`p-3 border rounded-lg ${s}`,"data-testid":`encryption-status`,children:[(0,K.jsx)(`p`,{className:`font-medium mb-1`,children:l}),(0,K.jsx)(`p`,{className:`text-sm`,children:u})]}),d&&(0,K.jsx)(`div`,{className:`mt-2 p-3 border rounded-lg bg-amber-50 dark:bg-amber-500/10 border-amber-300 dark:border-amber-500/30 text-amber-700 dark:text-amber-400`,"data-testid":`encryption-legacy-warning`,children:(0,K.jsx)(`p`,{className:`text-sm`,children:e(`settings.encryption.legacyRowsWarning`,{count:a})})}),t.migration_error_count>0&&(0,K.jsx)(`div`,{className:`mt-2 p-3 border rounded-lg bg-amber-50 dark:bg-amber-500/10 border-amber-300 dark:border-amber-500/30 text-amber-700 dark:text-amber-400`,"data-testid":`encryption-migration-warning`,children:(0,K.jsx)(`p`,{className:`text-sm`,children:e(`settings.encryption.migrationErrorWarning`,{count:t.migration_error_count})})}),(0,K.jsxs)(`div`,{className:`mt-4 grid grid-cols-2 gap-4 text-sm`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-bambu-gray`,children:e(`settings.encryption.encryptedRowsLabel`)}),(0,K.jsxs)(`p`,{className:`font-medium`,children:[`OIDC: `,t.encrypted_rows.oidc_providers,` · TOTP: `,t.encrypted_rows.user_totp]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-bambu-gray`,children:e(`settings.encryption.legacyRowsLabel`)}),(0,K.jsxs)(`p`,{className:`font-medium`,children:[`OIDC: `,t.legacy_plaintext_rows.oidc_providers,` · TOTP: `,t.legacy_plaintext_rows.user_totp]})]})]})]})]})}var $Ue={get:`bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400 border-blue-300 dark:border-blue-500/30`,post:`bg-green-100 dark:bg-green-500/20 text-green-700 dark:text-green-400 border-green-300 dark:border-green-500/30`,put:`bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400 border-yellow-300 dark:border-yellow-500/30`,patch:`bg-orange-100 dark:bg-orange-500/20 text-orange-700 dark:text-orange-400 border-orange-300 dark:border-orange-500/30`,delete:`bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-400 border-red-300 dark:border-red-500/30`};function eWe(e,t){let n=t.replace(`#/`,``).split(`/`),r=e;for(let e of n)r=r[e];return r}function T6(e,t,n=0){if(n>5)return`...`;if(t.$ref)return T6(e,eWe(e,t.$ref),n+1);if(t.allOf){let r={};for(let i of t.allOf){let t=T6(e,i,n+1);typeof t==`object`&&t&&Object.assign(r,t)}return r}if(t.example!==void 0)return t.example;if(t.default!==void 0)return t.default;switch(t.type){case`string`:return t.enum?t.enum[0]:`string`;case`integer`:case`number`:return 0;case`boolean`:return!1;case`array`:return t.items?[T6(e,t.items,n+1)]:[];case`object`:if(t.properties){let r={};for(let[i,a]of Object.entries(t.properties))r[i]=T6(e,a,n+1);return r}return{};default:return null}}function tWe({path:e,method:t,spec:n,schema:r,apiKey:i}){let[a,o]=(0,y.useState)(!1),[s,c]=(0,y.useState)({}),[l,u]=(0,y.useState)(``),[d,f]=(0,y.useState)(null),[p,m]=(0,y.useState)(!1),[h,g]=(0,y.useState)(!1);(0,y.useEffect)(()=>{if(a&&n.parameters){let e={};for(let t of n.parameters)t.schema?.default!==void 0&&(e[t.name]=String(t.schema.default));c(t=>({...e,...t}))}},[a,n.parameters]),(0,y.useEffect)(()=>{if(a&&n.requestBody?.content?.[`application/json`]?.schema&&!l){let e=n.requestBody.content[`application/json`].schema,t=T6(r,e);u(JSON.stringify(t,null,2))}},[a,n.requestBody,r,l]);let _=(()=>{let e=[];for(let t of n.parameters||[])if(t.in===`path`||t.required){let n=s[t.name];(n===void 0||n===``)&&e.push(t.name)}return e})(),v=async()=>{if(_.length>0){f({status:0,statusText:`Validation Error`,headers:{},body:`Missing required parameters: ${_.join(`, `)}`,duration:0});return}m(!0),f(null);try{let r=e,a=new URLSearchParams;for(let e of n.parameters||[]){let t=s[e.name];t!==void 0&&t!==``&&(e.in===`path`?r=r.replace(`{${e.name}}`,encodeURIComponent(t)):e.in===`query`&&a.append(e.name,t))}let o=a.toString(),c=`${r}${o?`?${o}`:``}`,u={"Content-Type":`application/json`};i&&(u[`X-API-Key`]=i);let d={method:t.toUpperCase(),headers:u};[`post`,`put`,`patch`].includes(t)&&l&&(d.body=l);let p=performance.now(),m=await fetch(c,d),h=Math.round(performance.now()-p),g={};m.headers.forEach((e,t)=>{g[t]=e});let _;_=m.headers.get(`content-type`)?.includes(`application/json`)?await m.json():await m.text(),f({status:m.status,statusText:m.statusText,headers:g,body:_,duration:h})}catch(e){f({status:0,statusText:`Network Error`,headers:{},body:e instanceof Error?e.message:`Unknown error`,duration:0})}finally{m(!1)}},b=async()=>{if(d){let e=typeof d.body==`string`?d.body:JSON.stringify(d.body,null,2);try{await navigator.clipboard.writeText(e),g(!0),setTimeout(()=>g(!1),2e3)}catch{let t=document.createElement(`textarea`);t.value=e,t.style.position=`fixed`,t.style.left=`-999999px`,document.body.appendChild(t),t.select(),document.execCommand(`copy`),document.body.removeChild(t),g(!0),setTimeout(()=>g(!1),2e3)}}},x=(n.parameters||[]).filter(e=>e.in===`path`),S=(n.parameters||[]).filter(e=>e.in===`query`),C=[`post`,`put`,`patch`].includes(t)&&n.requestBody;return(0,K.jsxs)(`div`,{className:`border border-bambu-dark-tertiary rounded-lg overflow-hidden`,children:[(0,K.jsxs)(`button`,{onClick:()=>o(!a),className:`w-full flex items-center gap-3 p-3 hover:bg-bambu-dark-tertiary/50 transition-colors text-left`,children:[a?(0,K.jsx)(ls,{className:`w-4 h-4 text-bambu-gray flex-shrink-0`}):(0,K.jsx)(us,{className:`w-4 h-4 text-bambu-gray flex-shrink-0`}),(0,K.jsx)(`span`,{className:`px-2 py-0.5 text-xs font-mono font-semibold uppercase rounded border ${$Ue[t]||`bg-gray-500/20 text-gray-400`}`,children:t}),(0,K.jsx)(`code`,{className:`text-sm text-white font-mono flex-1 truncate`,children:e}),n.summary&&(0,K.jsx)(`span`,{className:`text-sm text-bambu-gray truncate max-w-[40%]`,children:n.summary})]}),a&&(0,K.jsxs)(`div`,{className:`border-t border-bambu-dark-tertiary p-4 space-y-4 bg-bambu-dark/50`,children:[n.description&&(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:n.description}),x.length>0&&(0,K.jsxs)(`div`,{className:`space-y-2`,children:[(0,K.jsx)(`h4`,{className:`text-sm font-medium text-white`,children:`Path Parameters`}),(0,K.jsx)(`div`,{className:`space-y-2`,children:x.map(e=>(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsxs)(`label`,{className:`text-sm text-bambu-gray w-32 flex-shrink-0`,children:[e.name,e.required&&(0,K.jsx)(`span`,{className:`text-red-700 dark:text-red-400 ml-1`,children:`*`})]}),(0,K.jsx)(`input`,{type:`text`,value:s[e.name]||``,onChange:t=>c(n=>({...n,[e.name]:t.target.value})),placeholder:e.description||e.schema?.type||`value`,className:`flex-1 px-2 py-1 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-sm font-mono focus:border-bambu-green focus:outline-none`})]},e.name))})]}),S.length>0&&(0,K.jsxs)(`div`,{className:`space-y-2`,children:[(0,K.jsx)(`h4`,{className:`text-sm font-medium text-white`,children:`Query Parameters`}),(0,K.jsx)(`div`,{className:`space-y-2`,children:S.map(e=>(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsxs)(`label`,{className:`text-sm text-bambu-gray w-32 flex-shrink-0`,children:[e.name,e.required&&(0,K.jsx)(`span`,{className:`text-red-700 dark:text-red-400 ml-1`,children:`*`})]}),e.schema?.enum?(0,K.jsxs)(`select`,{value:s[e.name]||``,onChange:t=>c(n=>({...n,[e.name]:t.target.value})),className:`flex-1 px-2 py-1 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-sm focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:``,children:`-- Select --`}),e.schema.enum.map(e=>(0,K.jsx)(`option`,{value:e,children:e},e))]}):(0,K.jsx)(`input`,{type:`text`,value:s[e.name]||``,onChange:t=>c(n=>({...n,[e.name]:t.target.value})),placeholder:e.description||e.schema?.type||`value`,className:`flex-1 px-2 py-1 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-sm font-mono focus:border-bambu-green focus:outline-none`})]},e.name))})]}),C&&(0,K.jsxs)(`div`,{className:`space-y-2`,children:[(0,K.jsx)(`h4`,{className:`text-sm font-medium text-white`,children:`Request Body`}),(0,K.jsx)(`textarea`,{value:l,onChange:e=>u(e.target.value),rows:8,className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-sm font-mono focus:border-bambu-green focus:outline-none resize-y`,placeholder:`JSON request body...`})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsxs)($,{onClick:v,disabled:p,children:[p?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(Ol,{className:`w-4 h-4`}),`Execute`]}),_.length>0&&(0,K.jsxs)(`span`,{className:`text-xs text-yellow-700 dark:text-yellow-400 flex items-center gap-1`,children:[(0,K.jsx)(hs,{className:`w-3 h-3`}),`Fill in: `,_.join(`, `)]})]}),d&&(0,K.jsxs)(`div`,{className:`space-y-2`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`h4`,{className:`text-sm font-medium text-white flex items-center gap-2`,children:[`Response`,(0,K.jsxs)(`span`,{className:`px-2 py-0.5 text-xs rounded ${d.status>=200&&d.status<300?`bg-green-100 dark:bg-green-500/20 text-green-700 dark:text-green-400`:d.status>=400?`bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-400`:`bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400`}`,children:[d.status,` `,d.statusText]}),(0,K.jsxs)(`span`,{className:`text-xs text-bambu-gray`,children:[d.duration,`ms`]})]}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:b,children:h?(0,K.jsx)(_s,{className:`w-3 h-3 text-green-600 dark:text-green-400`}):(0,K.jsx)(Ls,{className:`w-3 h-3`})})]}),(0,K.jsx)(`pre`,{className:`p-3 bg-bambu-dark rounded-lg text-sm font-mono text-white overflow-auto max-h-96 border border-bambu-dark-tertiary`,children:typeof d.body==`string`?d.body:JSON.stringify(d.body,null,2)})]})]})]})}function nWe({apiKey:e=``}){let[t,n]=(0,y.useState)(null),[r,i]=(0,y.useState)(!0),[a,o]=(0,y.useState)(null),[s,c]=(0,y.useState)(new Set),[l,u]=(0,y.useState)(``);if((0,y.useEffect)(()=>{async function e(){try{let e=await fetch(`/openapi.json`);if(!e.ok)throw Error(`Failed to fetch OpenAPI schema`);n(await e.json())}catch(e){o(e instanceof Error?e.message:`Unknown error`)}finally{i(!1)}}e()},[]),r)return(0,K.jsx)(`div`,{className:`flex justify-center py-12`,children:(0,K.jsx)(X,{className:`w-8 h-8 text-bambu-green animate-spin`})});if(a||!t)return(0,K.jsx)(Od,{children:(0,K.jsx)(Ad,{className:`py-8`,children:(0,K.jsxs)(`div`,{className:`text-center text-red-700 dark:text-red-400`,children:[(0,K.jsx)(hs,{className:`w-12 h-12 mx-auto mb-3 opacity-50`}),(0,K.jsx)(`p`,{children:`Failed to load API schema`}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mt-1`,children:a})]})})});let d={};for(let[e,n]of Object.entries(t.paths))for(let[t,r]of Object.entries(n)){if(t===`parameters`)continue;let n=r.tags||[`Other`];for(let i of n)d[i]||(d[i]=[]),d[i].push({path:e,method:t,spec:r})}let f=Object.entries(d).map(([e,t])=>l?{tag:e,endpoints:t.filter(({path:e,method:t,spec:n})=>{let r=l.toLowerCase();return e.toLowerCase().includes(r)||t.toLowerCase().includes(r)||(n.summary?.toLowerCase()||``).includes(r)||(n.description?.toLowerCase()||``).includes(r)})}:{tag:e,endpoints:t}).filter(({endpoints:e})=>e.length>0).sort((e,t)=>e.tag.localeCompare(t.tag)),p=e=>{c(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})};return(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between gap-4`,children:[(0,K.jsx)(`div`,{className:`flex-1`,children:(0,K.jsx)(`input`,{type:`text`,value:l,onChange:e=>u(e.target.value),placeholder:`Search endpoints...`,className:`w-full max-w-md px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`})}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>{c(new Set(f.map(e=>e.tag)))},children:`Expand All`}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>{c(new Set)},children:`Collapse All`}),(0,K.jsxs)(`a`,{href:`/docs`,target:`_blank`,rel:`noopener noreferrer`,className:`flex items-center gap-1 text-sm text-bambu-green hover:underline`,children:[(0,K.jsx)($s,{className:`w-4 h-4`}),`Swagger UI`]})]})]}),(0,K.jsxs)(`p`,{className:`text-sm text-bambu-gray`,children:[f.reduce((e,t)=>e+t.endpoints.length,0),` endpoints in `,f.length,` categories`]}),(0,K.jsx)(`div`,{className:`space-y-3`,children:f.map(({tag:n,endpoints:r})=>(0,K.jsxs)(Od,{children:[(0,K.jsx)(`button`,{onClick:()=>p(n),className:`w-full flex items-center justify-between p-4 hover:bg-bambu-dark-tertiary/30 transition-colors text-left`,children:(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[s.has(n)?(0,K.jsx)(ls,{className:`w-5 h-5 text-bambu-gray`}):(0,K.jsx)(us,{className:`w-5 h-5 text-bambu-gray`}),(0,K.jsx)(`h3`,{className:`text-base font-semibold text-white capitalize`,children:n.replace(/-/g,` `)}),(0,K.jsx)(`span`,{className:`text-xs bg-bambu-dark-tertiary px-2 py-0.5 rounded-full text-bambu-gray`,children:r.length})]})}),s.has(n)&&(0,K.jsx)(Ad,{className:`pt-0 space-y-2`,children:r.map(({path:n,method:r,spec:i})=>(0,K.jsx)(tWe,{path:n,method:r,spec:i,schema:t,apiKey:e},`${r}-${n}`))})]},n))})]})}var rWe=[`general`,`plugs`,`notifications`,`queue`,`filament`,`network`,`apikeys`,`virtual-printer`,`spoolbuddy`,`failure-detection`,`users`,`backup`];w6({labelKey:`settings.general`,tab:`general`,keywords:`language date time format printer model printers cards`,anchor:`card-general`}),w6({labelKey:`settings.appearance`,tab:`general`,keywords:`theme dark light mode colors`,anchor:`card-appearance`}),w6({labelKey:`settings.archiveSettings`,tab:`general`,keywords:`archive auto save thumbnails captures`,anchor:`card-archive`}),w6({labelKey:`settings.camera`,tab:`general`,keywords:`camera external video stream`,anchor:`card-camera`}),w6({labelKey:`settings.costTracking`,tab:`general`,keywords:`currency filament cost energy kwh price`,anchor:`card-cost`}),w6({labelKey:`settings.fileManager`,tab:`general`,keywords:`file manager archive mode disk warning storage`,anchor:`card-filemanager`}),w6({labelKey:`settings.updates`,tab:`general`,keywords:`updates version firmware beta check`,anchor:`card-updates`}),w6({labelKey:`settings.dataManagement`,tab:`general`,keywords:`data reset clear logs notifications preferences`,anchor:`card-data`}),w6({labelKey:`settings.smartPlugs`,tab:`plugs`,keywords:`smart plug energy power automation tapo kasa tplink shelly`,anchor:`card-plugs`}),w6({labelKey:`settings.providers`,tab:`notifications`,keywords:`telegram discord email notification providers webhook`,anchor:`card-providers`}),w6({labelKey:`settings.messageTemplates`,tab:`notifications`,keywords:`message templates notification text edit`,anchor:`card-templates`}),w6({labelKey:`settings.defaultPrintOptions`,labelFallback:`Default Print Options`,tab:`queue`,keywords:`print bed leveling flow calibration vibration first layer timelapse`,anchor:`card-print-options`}),w6({labelKey:`settings.tempFanPresetsTitle`,labelFallback:`Temperature & Fan Presets`,tab:`queue`,keywords:`temperature fan presets nozzle bed chamber quick buttons popover`,anchor:`card-temp-fan-presets`}),w6({labelKey:`settings.staggeredStart`,labelFallback:`Staggered Start`,tab:`queue`,keywords:`staggered batch delay start queue group`,anchor:`card-staggered`}),w6({labelKey:`settings.plateClear`,labelFallback:`Plate-Clear Confirmation`,tab:`queue`,keywords:`plate clear confirm auto queue`,anchor:`card-plate`}),w6({labelKey:`settings.concurrentUploadsTitle`,labelFallback:`Concurrent Uploads`,tab:`queue`,keywords:`concurrent parallel upload transfer ftp queue slow farm simultaneous`,anchor:`card-concurrent-uploads`}),w6({labelKey:`settings.gcodeInjection`,labelFallback:`G-code Injection`,tab:`queue`,keywords:`gcode injection start end autoprint farmloop swapmod autoclear printflow`,anchor:`card-gcode`}),w6({labelKey:`settings.slicerCard`,labelFallback:`Slicer`,tab:`queue`,keywords:`slicer orcaslicer bambustudio orca bambu api sidecar url docker preferred`,anchor:`card-slicer`}),w6({labelKey:`settings.queueDrying`,tab:`queue`,keywords:`drying presets temperature time humidity ams`,anchor:`card-drying`}),w6({labelKey:`settings.filamentChecks`,tab:`filament`,keywords:`filament check warning runout remaining`,anchor:`card-filamentchecks`}),w6({labelKey:`settings.printModal`,tab:`filament`,keywords:`print modal custom mapping`,anchor:`card-printmodal`}),w6({labelKey:`settings.amsDisplayThresholds`,tab:`filament`,keywords:`ams humidity temperature threshold history retention`,anchor:`card-amsthresholds`}),w6({labelKey:`settings.externalUrl`,tab:`network`,keywords:`external url reverse proxy public notification link`,anchor:`card-externalurl`}),w6({labelKey:`settings.ftpRetry`,tab:`network`,keywords:`ftp retry upload retries backoff`,anchor:`card-ftpretry`}),w6({labelKey:`settings.homeAssistant`,tab:`network`,keywords:`home assistant ha hass mqtt integration`,anchor:`card-ha`}),w6({labelKey:`settings.mqttPublishing`,tab:`network`,keywords:`mqtt publish broker topic`,anchor:`card-mqtt`}),w6({labelKey:`settings.prometheusMetrics`,tab:`network`,keywords:`prometheus metrics grafana monitoring bearer token`,anchor:`card-prometheus`}),w6({labelKey:`settings.createNewApiKey`,tab:`apikeys`,keywords:`api key create permission scope`,anchor:`card-createapi`}),w6({labelKey:`settings.webhookEndpoints`,tab:`apikeys`,keywords:`webhook endpoint post http`,anchor:`card-webhooks`}),w6({labelKey:`settings.apiBrowser`,tab:`apikeys`,keywords:`api browser endpoint documentation test`,anchor:`card-apibrowser`}),w6({labelKey:`cameraTokens.title`,tab:`apikeys`,keywords:`camera token long-lived home assistant frigate kiosk stream`,anchor:`card-camera-tokens`}),w6({labelKey:`settings.tabs.virtualPrinter`,tab:`virtual-printer`,keywords:`virtual printer proxy archive slicer bambustudio orcaslicer ip bind`,anchor:`card-vp`}),w6({labelKey:`settings.tabs.spoolbuddy`,tab:`spoolbuddy`,keywords:`spoolbuddy device scale nfc rfid kiosk unregister`,anchor:`card-spoolbuddy`}),w6({labelKey:`settings.currentUser`,tab:`users`,subTab:`users`,keywords:`current user profile password change`,anchor:`card-currentuser`}),w6({labelKey:`settings.users`,tab:`users`,subTab:`users`,keywords:`users accounts list`,anchor:`card-users`}),w6({labelKey:`settings.groups`,tab:`users`,subTab:`users`,keywords:`groups roles permissions administrators operators viewers`,anchor:`card-groups`}),w6({labelKey:`settings.sessionPolicy.title`,labelFallback:`Session Policy`,tab:`users`,subTab:`users`,keywords:`session timeout expiry logout remember me jwt token lifetime`,anchor:`card-session-policy`}),w6({labelKey:`settings.email.smtpSettings`,labelFallback:`SMTP Configuration`,tab:`users`,subTab:`email`,keywords:`smtp email send server port password auth starttls ssl`,anchor:`card-smtp`}),w6({labelKey:`settings.ldap.title`,labelFallback:`LDAP Authentication`,tab:`users`,subTab:`ldap`,keywords:`ldap active directory ad authentication bind dn search base group mapping`,anchor:`card-ldap`}),w6({labelKey:`settings.tabs.backup`,tab:`backup`,keywords:`backup github restore download cloud sync profiles archives`,anchor:`card-backup`}),w6({labelKey:`externalLinks.sidebarLayout`,labelFallback:`Sidebar`,tab:`general`,keywords:`sidebar layout links pages hide show external custom navigation url add`,anchor:`card-sidebar-links`}),w6({labelKey:`settings.filamentTracking`,tab:`filament`,keywords:`spoolman filament tracking inventory sync remote integration`,anchor:`card-spoolman`}),w6({labelKey:`settings.catalog.spoolCatalog`,labelFallback:`Spool Catalog`,tab:`filament`,keywords:`spool catalog entries brand material reset import export`,anchor:`card-spool-catalog`}),w6({labelKey:`settings.colorCatalog.title`,labelFallback:`Color Catalog`,tab:`filament`,keywords:`color catalog hex swatch palette sync reset`,anchor:`card-color-catalog`}),w6({labelKey:`settings.tabs.failureDetection`,labelFallback:`Failure Detection`,tab:`failure-detection`,keywords:`failure detection ai ml obico spaghetti detect monitoring`,anchor:`card-fd-ml`}),w6({labelKey:`failureDetection.perPrinterTitle`,labelFallback:`Per-Printer Settings`,tab:`failure-detection`,keywords:`failure detection per printer enable per-printer sensitivity`,anchor:`card-fd-perprinter`}),w6({labelKey:`failureDetection.statusTitle`,labelFallback:`Detection Status`,tab:`failure-detection`,keywords:`failure detection status running connection`,anchor:`card-fd-status`}),w6({labelKey:`failureDetection.historyTitle`,labelFallback:`Detection History`,tab:`failure-detection`,keywords:`failure detection history log events`,anchor:`card-fd-history`}),w6({labelKey:`settings.email.advancedAuth`,labelFallback:`Advanced Email Authentication`,tab:`users`,subTab:`email`,keywords:`email authentication advanced password reset self-service forgot`,anchor:`card-email-advanced-auth`}),w6({labelKey:`settings.email.testConnection`,labelFallback:`Test SMTP Connection`,tab:`users`,subTab:`email`,keywords:`email smtp test connection send check`,anchor:`card-email-test`}),w6({labelKey:`settings.twoFa.totpTitle`,labelFallback:`Authenticator App (TOTP)`,tab:`users`,subTab:`twofa`,keywords:`two factor 2fa totp authenticator app google authy otp`,anchor:`card-2fa-totp`}),w6({labelKey:`settings.twoFa.emailOtpTitle`,labelFallback:`Email One-Time Codes`,tab:`users`,subTab:`twofa`,keywords:`two factor 2fa email otp one time code`,anchor:`card-2fa-emailotp`}),w6({labelKey:`settings.twoFa.linkedAccounts`,labelFallback:`Linked Accounts`,tab:`users`,subTab:`twofa`,keywords:`two factor 2fa linked accounts sso oidc provider google github`,anchor:`card-2fa-linked`}),w6({labelKey:`settings.oidc.title`,labelFallback:`Single Sign-On (OIDC)`,tab:`users`,subTab:`oidc`,keywords:`sso oidc openid single sign-on pocketid authentik keycloak google okta azure provider`,anchor:`card-oidc`}),w6({labelKey:`settings.ldap.serverConfig`,labelFallback:`LDAP Server Configuration`,tab:`users`,subTab:`ldap`,keywords:`ldap server url bind dn user search base group filter tls`,anchor:`card-ldap-server`}),w6({labelKey:`backup.githubBackup`,labelFallback:`GitHub Backup`,tab:`backup`,keywords:`github backup cloud remote sync profiles token`,anchor:`card-backup-github`}),w6({labelKey:`backup.history`,labelFallback:`Backup History`,tab:`backup`,keywords:`backup history log runs github commits`,anchor:`card-backup-history`}),w6({labelKey:`backup.localBackup`,labelFallback:`Local Backup`,tab:`backup`,keywords:`local backup download zip manual export`,anchor:`card-backup-local`}),w6({labelKey:`backup.scheduledBackup`,labelFallback:`Scheduled Backups`,tab:`backup`,keywords:`scheduled backup automatic hourly daily weekly retention local path`,anchor:`card-backup-scheduled`});var iWe={database:`bg-blue-600`,library_files:`bg-green-500`,library_thumbnails:`bg-teal-500`,library_other:`bg-emerald-700`,archive_timelapses:`bg-red-500`,archive_thumbnails:`bg-amber-500`,archive_files:`bg-sky-500`,virtual_printer_uploads:`bg-purple-500`,virtual_printer_upload_cache:`bg-fuchsia-500`,virtual_printer_certs:`bg-violet-500`,virtual_printer_other:`bg-purple-700`,downloads:`bg-cyan-500`,plate_calibration:`bg-lime-500`,logs:`bg-orange-500`,other_data:`bg-yellow-500`},E6=[`bg-blue-500`,`bg-green-500`,`bg-yellow-500`,`bg-red-500`,`bg-orange-500`,`bg-teal-500`,`bg-cyan-500`,`bg-purple-500`],D6=(e,t)=>iWe[e]||E6[t%E6.length];function aWe(){let e=oo(),t=ir(),[n,r]=Ii(),{t:i,i18n:a}=W(),{showToast:o}=Id(),{authEnabled:s,user:c,isAdmin:l,refreshAuth:u,hasPermission:d}=Sd(),{mode:f,resolvedMode:p,darkStyle:m,darkBackground:h,darkAccent:g,lightStyle:_,lightBackground:v,lightAccent:b,setMode:x,setDarkStyle:S,setDarkBackground:C,setDarkAccent:w,setLightStyle:T,setLightBackground:E,setLightAccent:D,progressInTitle:O,setProgressInTitle:k}=Td(),[A,j]=(0,y.useState)(null),[M,N]=(0,y.useState)({}),[P,F]=(0,y.useState)(!1),[I,L]=(0,y.useState)(null),[R,z]=(0,y.useState)(!1),[B,V]=(0,y.useState)(null),[ee,te]=(0,y.useState)(null),[ne,re]=(0,y.useState)(``),[ie,H]=(0,y.useState)(``),[ae,oe]=(0,y.useState)(!1),[U,se]=(0,y.useState)(Wp()),ce=n.get(`tab`),le=ce===`email`,[ue,de]=(0,y.useState)(le?`users`:ce&&rWe.includes(ce)?ce:`general`),[fe,pe]=(0,y.useState)(le?`email`:`users`),[me,he]=(0,y.useState)(ce===`queue`&&n.get(`sub`)===`pipelines`?`pipelines`:`dispatch`),ge=e=>{de(e),e===`users`&&pe(`users`),e===`queue`&&(he(`dispatch`),n.delete(`sub`)),e===`general`?n.delete(`tab`):n.set(`tab`,e),r(n,{replace:!0})},_e=e=>{he(e),e===`pipelines`?n.set(`sub`,`pipelines`):n.delete(`sub`),r(n,{replace:!0})},[ve,ye]=(0,y.useState)(!1),[be,xe]=(0,y.useState)(``),[Se,Ce]=(0,y.useState)({can_queue:!0,can_control_printer:!1,can_read_status:!0,can_manage_library:!0,can_manage_inventory:!0,can_manage_maintenance:!0,can_manage_archives:!0,can_manage_projects:!0,can_access_cloud:!1,can_update_energy_cost:!1}),[we,Te]=(0,y.useState)(null),[Ee,De]=(0,y.useState)(!1),[Oe,ke]=(0,y.useState)(null),[Ae,je]=(0,y.useState)(``),[Me,Ne]=(0,y.useState)(!1),[Pe,Fe]=(0,y.useState)(!1),[Ie,Le]=(0,y.useState)(null),[Re,ze]=(0,y.useState)(!1),[Be,Ve]=(0,y.useState)(!1),[He,Ue]=(0,y.useState)(!1),[We,Ge]=(0,y.useState)({currentPassword:``,newPassword:``,confirmPassword:``}),[Ke,qe]=(0,y.useState)(!1),[Je,Ye]=(0,y.useState)(!1),[Xe,Ze]=(0,y.useState)(!1),[Qe,$e]=(0,y.useState)(`local`),[et,tt]=(0,y.useState)(!1),[nt,rt]=(0,y.useState)(null),[it,at]=(0,y.useState)(null),[ot,st]=(0,y.useState)(null),[ct,lt]=(0,y.useState)(!1),[ut,dt]=(0,y.useState)({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]}),[ft,pt]=(0,y.useState)(null),[mt,ht]=(0,y.useState)(null),[gt,_t]=(0,y.useState)(!1),[vt,yt]=(0,y.useState)({}),[bt,xt]=(0,y.useState)({}),St=e=>{se(e),nee(e),o(i(`settings.toast.settingsSaved`),`success`)},{data:Ct,isLoading:wt}=q({queryKey:[`settings`],queryFn:Q.getSettings}),{data:Tt,isLoading:Et,isFetching:Dt}=q({queryKey:[`storage-usage`],queryFn:()=>Q.getStorageUsage(),enabled:ue===`general`,staleTime:1/0,refetchInterval:!1,refetchOnWindowFocus:!1,refetchOnReconnect:!1}),kt=async()=>{Ye(!0);try{let t=await Q.getStorageUsage({refresh:!0});e.setQueryData([`storage-usage`],t)}catch(e){o(e instanceof Error?e.message:`Failed to refresh storage usage`,`error`)}finally{Ye(!1)}},{data:At,isLoading:jt}=q({queryKey:[`smart-plugs`],queryFn:Q.getSmartPlugs}),{data:Mt,isLoading:Nt}=q({queryKey:[`smart-plugs-energy`,At?.map(e=>e.id)],queryFn:async()=>{if(!At||At.length===0)return null;let e=await Promise.all(At.filter(e=>e.enabled).map(async e=>{try{return{plug:e,status:await Q.getSmartPlugStatus(e.id)}}catch{return{plug:e,status:null}}})),t=0,n=0,r=0,i=0,a=0;for(let{plug:o,status:s}of e){let e=o.plug_type===`mqtt`&&s?.energy?.power!=null;(s?.reachable||e)&&s?.energy&&(a++,s.energy?.power!=null&&(t+=s.energy.power),s.energy?.today!=null&&(n+=s.energy.today),s.energy?.yesterday!=null&&(r+=s.energy.yesterday),s.energy?.total!=null&&(i+=s.energy.total))}return{totalPower:t,totalToday:n,totalYesterday:r,totalLifetime:i,reachableCount:a,totalPlugs:At.filter(e=>e.enabled).length}},enabled:ue===`plugs`&&!!At&&At.length>0,refetchInterval:ue===`plugs`?1e4:!1}),{data:Pt,isLoading:Ft}=q({queryKey:[`notification-providers`],queryFn:Q.getNotificationProviders}),{data:It,isLoading:Lt}=q({queryKey:[`api-keys`],queryFn:Q.getAPIKeys}),G=J({mutationFn:e=>Q.createAPIKey(e),onSuccess:t=>{Te(t.key||null),ye(!1),xe(``),e.invalidateQueries({queryKey:[`api-keys`]}),o(i(`settings.toast.apiKeyCreated`))},onError:e=>{o(`Failed to create API key: ${e.message}`,`error`)}}),Rt=J({mutationFn:e=>Q.deleteAPIKey(e),onSuccess:(t,n)=>{e.setQueryData([`api-keys`],e=>(e??[]).filter(e=>e.id!==n)),o(i(`settings.toast.apiKeyDeleted`))},onError:e=>{o(`Failed to delete API key: ${e.message}`,`error`)}}),{data:zt}=q({queryKey:[`printers`],queryFn:Q.getPrinters}),Bt=gf(zt?.length??0),{data:Vt,isLoading:Ht}=q({queryKey:[`notification-templates`],queryFn:Q.getNotificationTemplates}),{data:Ut}=q({queryKey:[`virtual-printer-settings`],queryFn:fd.getSettings,refetchInterval:1e4}),Wt=Ut?.status?.running??!1,{data:Gt}=q({queryKey:[`spoolbuddy-devices`],queryFn:()=>_d.getDevices(),refetchInterval:15e3}),Kt=Gt?.length??0,qt=Gt?.some(e=>e.online)??!1,{data:Jt}=q({queryKey:[`obico-status`],queryFn:Q.getObicoStatus,refetchInterval:15e3}),Yt=!!(Jt?.is_running&&Jt?.enabled),{data:Xt}=q({queryKey:[`ffmpeg-status`],queryFn:Q.checkFfmpeg}),{data:Zt}=q({queryKey:[`version`],queryFn:Q.getVersion}),Qt=!s||d(`library:purge`),{data:$t}=q({queryKey:[`library-trash-settings`],queryFn:()=>Q.getLibraryTrashSettings(),enabled:Qt}),en=J({mutationFn:e=>Q.updateLibraryTrashSettings(e),onSuccess:()=>{e.invalidateQueries({queryKey:[`library-trash-settings`]}),o(i(`settings.toast.settingsSaved`),`success`)},onError:e=>o(e.message||i(`libraryAutoPurge.saveFailed`),`error`)}),tn=e=>{$t&&en.mutate({retention_days:$t.retention_days,auto_purge_enabled:$t.auto_purge_enabled,auto_purge_days:$t.auto_purge_days,auto_purge_include_never_printed:$t.auto_purge_include_never_printed,...e})},nn=!s||d(`archives:purge`),{data:rn}=q({queryKey:[`archive-purge-settings`],queryFn:()=>Q.getArchivePurgeSettings(),enabled:nn}),an=J({mutationFn:e=>Q.updateArchivePurgeSettings(e),onSuccess:()=>{e.invalidateQueries({queryKey:[`archive-purge-settings`]}),o(i(`settings.toast.settingsSaved`),`success`)},onError:e=>o(e.message||i(`archiveAutoPurge.saveFailed`),`error`)}),on=e=>{rn&&an.mutate({enabled:rn.enabled,days:rn.days,purge_stats:rn.purge_stats,...e})},{data:sn,refetch:cn,isRefetching:ln}=q({queryKey:[`updateCheck`],queryFn:Q.checkForUpdates,enabled:Ct?.check_updates!==!1,staleTime:300*1e3}),{data:un,refetch:dn}=q({queryKey:[`updateStatus`],queryFn:Q.getUpdateStatus,refetchInterval:e=>{let t=e.state.data;return t?.status===`downloading`||t?.status===`installing`?1e3:!1}}),{data:fn}=q({queryKey:[`mqtt-status`],queryFn:Q.getMQTTStatus,refetchInterval:ue===`network`?5e3:!1}),{data:pn}=q({queryKey:[`github-backup-status`],queryFn:Q.getGitHubBackupStatus}),{data:mn}=q({queryKey:[`cloud-status`],queryFn:Q.getCloudStatus}),{data:hn={advanced_auth_enabled:!1,smtp_configured:!1,local_login_enabled:!0,autologin_provider_id:null}}=q({queryKey:[`advancedAuthStatus`],queryFn:()=>Q.getAdvancedAuthStatus()}),{data:gn}=q({queryKey:[`ldapStatus`],queryFn:()=>Q.getLDAPStatus()}),{data:_n}=q({queryKey:[`twoFAStatus`],queryFn:()=>Q.get2FAStatus()}),{data:vn=[]}=q({queryKey:[`oidcProvidersAll`],queryFn:()=>Q.getOIDCProvidersAll(),enabled:l}),{data:yn=[],isLoading:bn}=q({queryKey:[`users`],queryFn:()=>Q.getUsers(),enabled:s&&d(`users:read`)}),{data:xn=[],isLoading:Sn}=q({queryKey:[`groups`],queryFn:()=>Q.getGroups(),enabled:s&&d(`groups:read`)}),Cn=J({mutationFn:e=>Q.createUser(e),onSuccess:()=>{e.invalidateQueries({queryKey:[`users`]}),e.invalidateQueries({queryKey:[`groups`]}),Ze(!1),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]}),o(i(`settings.toast.userCreated`))},onError:e=>{o(e.message,`error`)}}),wn=J({mutationFn:({id:e,data:t})=>Q.updateUser(e,t),onSuccess:()=>{e.invalidateQueries({queryKey:[`users`]}),e.invalidateQueries({queryKey:[`groups`]}),tt(!1),rt(null),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]}),o(i(`settings.toast.userUpdated`))},onError:e=>{o(e.message,`error`)}}),Tn=J({mutationFn:({id:e,deleteItems:t})=>Q.deleteUser(e,t),onSuccess:()=>{e.invalidateQueries({queryKey:[`users`]}),o(i(`settings.toast.userDeleted`)),at(null),st(null)},onError:e=>{o(e.message,`error`)}}),En=J({mutationFn:e=>Q.resetUserPassword({user_id:e}),onSuccess:e=>{o(e.message,`success`)},onError:e=>{o(e.message,`error`)}}),Dn=async e=>{at(e),lt(!0);try{st(await Q.getUserItemsCount(e))}catch{st({archives:0,queue_items:0,library_files:0})}finally{lt(!1)}},On=J({mutationFn:e=>Q.deleteGroup(e),onSuccess:()=>{e.invalidateQueries({queryKey:[`groups`]}),o(i(`settings.toast.groupDeleted`))},onError:e=>{o(e.message,`error`)}}),kn=()=>{let e=hn?.advanced_auth_enabled||!1;if(!ut.username){o(i(`settings.toast.fillRequiredFields`),`error`);return}if(e&&!ut.email){o(`Email is required when advanced authentication is enabled`,`error`);return}if(!e){if(!ut.password){o(i(`settings.toast.fillRequiredFields`),`error`);return}if(ut.password!==ut.confirmPassword){o(i(`settings.toast.passwordsDoNotMatch`),`error`);return}let e=k3(ut.password);if(e){o(i({tooShort:`settings.toast.passwordTooShort`,needsUppercase:`settings.toast.passwordNeedsUppercase`,needsLowercase:`settings.toast.passwordNeedsLowercase`,needsDigit:`settings.toast.passwordNeedsDigit`,needsSpecial:`settings.toast.passwordNeedsSpecial`}[e]),`error`);return}}Cn.mutate({username:ut.username,password:e?void 0:ut.password,email:ut.email||void 0,role:ut.role,group_ids:ut.group_ids.length>0?ut.group_ids:void 0})},An=e=>{if(ut.password){if(ut.password!==ut.confirmPassword){o(i(`settings.toast.passwordsDoNotMatch`),`error`);return}let e=k3(ut.password);if(e){o(i({tooShort:`settings.toast.passwordTooShort`,needsUppercase:`settings.toast.passwordNeedsUppercase`,needsLowercase:`settings.toast.passwordNeedsLowercase`,needsDigit:`settings.toast.passwordNeedsDigit`,needsSpecial:`settings.toast.passwordNeedsSpecial`}[e]),`error`);return}}let t={username:ut.username||void 0,password:ut.password||void 0,email:ut.email||void 0,role:ut.role,group_ids:ut.group_ids};t.password||delete t.password,wn.mutate({id:e,data:t})},jn=e=>{rt(e.id),dt({username:e.username,password:``,email:e.email||``,confirmPassword:``,role:e.role,group_ids:e.groups?.map(e=>e.id)||[]}),tt(!0)},Mn=e=>{dt(t=>({...t,group_ids:t.group_ids.includes(e)?t.group_ids.filter(t=>t!==e):[...t.group_ids,e]}))},Nn=J({mutationFn:Q.applyUpdate,onSuccess:e=>{e.is_ha_addon||e.is_docker||e.is_windows_installer?o(e.message,`error`):dn()}}),[Pn,Fn]=(0,y.useState)(null),In=J({mutationFn:Q.testAllNotificationProviders,onSuccess:t=>{Fn(t),e.invalidateQueries({queryKey:[`notification-providers`]}),t.failed===0?o(`All ${t.tested} providers tested successfully!`,`success`):o(`${t.success}/${t.tested} providers succeeded`,t.failed>0?`error`:`success`)},onError:e=>{o(`Failed to test providers: ${e.message}`,`error`)}}),Ln=J({mutationFn:async e=>{if(!At)return{success:0,failed:0};let t=At.filter(e=>e.enabled),n=await Promise.all(t.map(async t=>{try{return await Q.controlSmartPlug(t.id,e),{success:!0}}catch{return{success:!1}}}));return{success:n.filter(e=>e.success).length,failed:n.filter(e=>!e.success).length}},onSuccess:(t,n)=>{e.invalidateQueries({queryKey:[`smart-plugs`]}),e.invalidateQueries({queryKey:[`smart-plugs-energy`]}),t.failed===0?o(`All ${t.success} plugs turned ${n}`,`success`):o(`${t.success} plugs turned ${n}, ${t.failed} failed`,`error`)},onError:e=>{o(`Failed: ${e.message}`,`error`)}}),Rn=(0,y.useRef)(null),zn=(0,y.useRef)(null),Bn=(0,y.useRef)(!1),Vn=(0,y.useRef)(!0),Hn=(0,y.useRef)(null);(0,y.useEffect)(()=>{if(Ct&&!A){let e={...Ct,external_url:Ct.external_url||window.location.origin};Hn.current=Ct,j(e),setTimeout(()=>{Vn.current=!1},100)}},[Ct,A]),(0,y.useEffect)(()=>{let e=Hn.current;if(!Ct||!A||!e||Ct===e)return;let t={};for(let n of Object.keys(Ct))Ct[n]!==e[n]&&A[n]===e[n]&&(t[n]=Ct[n]);Hn.current=Ct,Object.keys(t).length>0&&j(e=>e&&{...e,...t})},[Ct,A]);let Un=J({mutationFn:Q.updateSettings,onSuccess:t=>{Hn.current=t,e.setQueryData([`settings`],t),e.invalidateQueries({queryKey:[`archiveStats`]}),o(i(`settings.toast.settingsSaved`),`success`)},onError:e=>{o(`Failed to save: ${e.message}`,`error`)},onSettled:()=>{Bn.current=!1}}),Wn=J({mutationFn:({id:e,data:t})=>Q.updatePrinter(e,t),onSuccess:()=>{e.invalidateQueries({queryKey:[`printers`]}),o(i(`settings.toast.cameraSettingsSaved`),`success`)},onError:e=>{o(`Failed to update printer: ${e.message}`,`error`)}});(0,y.useEffect)(()=>{let e=Hn.current;if(!(Vn.current||!A||!Ct||!e)&&!(s&&!d(`settings:update`))&&(e.auto_archive!==A.auto_archive||e.save_thumbnails!==A.save_thumbnails||e.capture_finish_photo!==A.capture_finish_photo||(e.finish_photo_restore_plate??!0)!==(A.finish_photo_restore_plate??!0)||e.default_filament_cost!==A.default_filament_cost||e.currency!==A.currency||e.energy_cost_per_kwh!==A.energy_cost_per_kwh||e.energy_tracking_mode!==A.energy_tracking_mode||e.check_updates!==A.check_updates||(e.check_printer_firmware??!0)!==(A.check_printer_firmware??!0)||(e.include_beta_updates??!1)!==(A.include_beta_updates??!1)||(e.local_login_enabled??!0)!==(A.local_login_enabled??!0)||e.notification_language!==A.notification_language||(e.bed_cooled_threshold??35)!==(A.bed_cooled_threshold??35)||e.ams_humidity_good!==A.ams_humidity_good||e.ams_humidity_fair!==A.ams_humidity_fair||e.ams_temp_good!==A.ams_temp_good||e.ams_temp_fair!==A.ams_temp_fair||e.ams_history_retention_days!==A.ams_history_retention_days||e.disable_filament_warnings!==A.disable_filament_warnings||e.prefer_lowest_filament!==A.prefer_lowest_filament||(e.queue_drying_enabled??!1)!==(A.queue_drying_enabled??!1)||(e.queue_drying_block??!1)!==(A.queue_drying_block??!1)||(e.ambient_drying_enabled??!1)!==(A.ambient_drying_enabled??!1)||(e.print_drying_enabled??!1)!==(A.print_drying_enabled??!1)||(e.drying_presets??``)!==(A.drying_presets??``)||(e.ams_humidity_thresholds??``)!==(A.ams_humidity_thresholds??``)||e.per_printer_mapping_expanded!==A.per_printer_mapping_expanded||e.date_format!==A.date_format||e.time_format!==A.time_format||e.default_printer_id!==A.default_printer_id||e.ftp_retry_enabled!==A.ftp_retry_enabled||e.ftp_retry_count!==A.ftp_retry_count||e.ftp_retry_delay!==A.ftp_retry_delay||e.ftp_timeout!==A.ftp_timeout||e.mqtt_enabled!==A.mqtt_enabled||e.mqtt_broker!==A.mqtt_broker||e.mqtt_port!==A.mqtt_port||e.mqtt_username!==A.mqtt_username||e.mqtt_password!==A.mqtt_password||e.mqtt_topic_prefix!==A.mqtt_topic_prefix||e.mqtt_use_tls!==A.mqtt_use_tls||e.external_url!==A.external_url||e.ha_enabled!==A.ha_enabled||e.ha_url!==A.ha_url||e.ha_token!==A.ha_token||(e.library_archive_mode??`ask`)!==(A.library_archive_mode??`ask`)||Number(e.library_disk_warning_gb??5)!==Number(A.library_disk_warning_gb??5)||(e.camera_view_mode??`window`)!==(A.camera_view_mode??`window`)||(e.preferred_slicer??`bambu_studio`)!==(A.preferred_slicer??`bambu_studio`)||(e.open_in_slicer??null)!==(A.open_in_slicer??null)||(e.use_slicer_api??!1)!==(A.use_slicer_api??!1)||(e.orcaslicer_api_url??``)!==(A.orcaslicer_api_url??``)||(e.slicer_stall_timeout_minutes??15)!==(A.slicer_stall_timeout_minutes??15)||(e.bambu_studio_api_url??``)!==(A.bambu_studio_api_url??``)||e.prometheus_enabled!==A.prometheus_enabled||e.prometheus_token!==A.prometheus_token||(e.user_notifications_enabled??!0)!==(A.user_notifications_enabled??!0)||(e.default_bed_levelling??`auto`)!==(A.default_bed_levelling??`auto`)||(e.default_flow_cali??`auto`)!==(A.default_flow_cali??`auto`)||(e.default_vibration_cali??!0)!==(A.default_vibration_cali??!0)||(e.default_layer_inspect??!1)!==(A.default_layer_inspect??!1)||(e.default_timelapse??!1)!==(A.default_timelapse??!1)||(e.default_nozzle_offset_cali??`auto`)!==(A.default_nozzle_offset_cali??`auto`)||(e.stagger_group_size??2)!==(A.stagger_group_size??2)||(e.stagger_interval_minutes??5)!==(A.stagger_interval_minutes??5)||(e.require_plate_clear??!1)!==(A.require_plate_clear??!1)||(e.queue_max_concurrent_uploads??4)!==(A.queue_max_concurrent_uploads??4)||(e.preheat_enabled??!1)!==(A.preheat_enabled??!1)||(e.preheat_filament_targets??``)!==(A.preheat_filament_targets??``)||(e.preheat_max_wait_seconds??900)!==(A.preheat_max_wait_seconds??900)||(e.preheat_soak_seconds??300)!==(A.preheat_soak_seconds??300)||(e.nozzle_temp_presets??``)!==(A.nozzle_temp_presets??``)||(e.bed_temp_presets??``)!==(A.bed_temp_presets??``)||(e.chamber_temp_presets??``)!==(A.chamber_temp_presets??``)||(e.fan_speed_presets??``)!==(A.fan_speed_presets??``)||(e.session_max_hours??24)!==(A.session_max_hours??24))&&!Bn.current)return Rn.current&&clearTimeout(Rn.current),Rn.current=setTimeout(()=>{if(Bn.current)return;Bn.current=!0;let e={auto_archive:A.auto_archive,save_thumbnails:A.save_thumbnails,capture_finish_photo:A.capture_finish_photo,finish_photo_restore_plate:A.finish_photo_restore_plate??!0,default_filament_cost:A.default_filament_cost,currency:A.currency,energy_cost_per_kwh:A.energy_cost_per_kwh,energy_tracking_mode:A.energy_tracking_mode,check_updates:A.check_updates,check_printer_firmware:A.check_printer_firmware,include_beta_updates:A.include_beta_updates,local_login_enabled:A.local_login_enabled,notification_language:A.notification_language,bed_cooled_threshold:A.bed_cooled_threshold,ams_humidity_good:A.ams_humidity_good,ams_humidity_fair:A.ams_humidity_fair,ams_temp_good:A.ams_temp_good,ams_temp_fair:A.ams_temp_fair,ams_history_retention_days:A.ams_history_retention_days,disable_filament_warnings:A.disable_filament_warnings,prefer_lowest_filament:A.prefer_lowest_filament,queue_drying_enabled:A.queue_drying_enabled,queue_drying_block:A.queue_drying_block,ambient_drying_enabled:A.ambient_drying_enabled,print_drying_enabled:A.print_drying_enabled,drying_presets:A.drying_presets,ams_humidity_thresholds:A.ams_humidity_thresholds,per_printer_mapping_expanded:A.per_printer_mapping_expanded,date_format:A.date_format,time_format:A.time_format,default_printer_id:A.default_printer_id,ftp_retry_enabled:A.ftp_retry_enabled,ftp_retry_count:A.ftp_retry_count,ftp_retry_delay:A.ftp_retry_delay,ftp_timeout:A.ftp_timeout,mqtt_enabled:A.mqtt_enabled,mqtt_broker:A.mqtt_broker,mqtt_port:A.mqtt_port,mqtt_username:A.mqtt_username,mqtt_password:A.mqtt_password,mqtt_topic_prefix:A.mqtt_topic_prefix,mqtt_use_tls:A.mqtt_use_tls,external_url:A.external_url,ha_enabled:A.ha_enabled,ha_url:A.ha_url,ha_token:A.ha_token,library_archive_mode:A.library_archive_mode,library_disk_warning_gb:A.library_disk_warning_gb,camera_view_mode:A.camera_view_mode,preferred_slicer:A.preferred_slicer,open_in_slicer:A.open_in_slicer,use_slicer_api:A.use_slicer_api,orcaslicer_api_url:A.orcaslicer_api_url,slicer_stall_timeout_minutes:A.slicer_stall_timeout_minutes,bambu_studio_api_url:A.bambu_studio_api_url,prometheus_enabled:A.prometheus_enabled,prometheus_token:A.prometheus_token,user_notifications_enabled:A.user_notifications_enabled,default_bed_levelling:A.default_bed_levelling,default_flow_cali:A.default_flow_cali,default_vibration_cali:A.default_vibration_cali,default_layer_inspect:A.default_layer_inspect,default_timelapse:A.default_timelapse,default_nozzle_offset_cali:A.default_nozzle_offset_cali,stagger_group_size:A.stagger_group_size,stagger_interval_minutes:A.stagger_interval_minutes,require_plate_clear:A.require_plate_clear,queue_max_concurrent_uploads:A.queue_max_concurrent_uploads,preheat_enabled:A.preheat_enabled,preheat_filament_targets:A.preheat_filament_targets,preheat_max_wait_seconds:A.preheat_max_wait_seconds,preheat_soak_seconds:A.preheat_soak_seconds,nozzle_temp_presets:A.nozzle_temp_presets,bed_temp_presets:A.bed_temp_presets,chamber_temp_presets:A.chamber_temp_presets,fan_speed_presets:A.fan_speed_presets,session_max_hours:A.session_max_hours};Un.mutate(e)},500),()=>{Rn.current&&clearTimeout(Rn.current)}},[A,Ct,Un,s,d,o,i]);let Gn=(0,y.useCallback)((e,t)=>{if(s&&!d(`settings:update`)){o(i(`settings.toast.noPermissionUpdate`),`error`);return}j(n=>n?{...n,[e]:t}:null)},[s,d,o,i]),Kn=async(e,t,n)=>{if(!t){o(i(`settings.toast.enterCameraUrl`),`error`);return}xt(t=>({...t,[e]:!0})),yt(t=>({...t,[e]:null}));try{let r=await Q.testExternalCamera(e,t,n);yt(t=>({...t,[e]:r})),r.success?o(r.coalesced?i(`settings.toast.cameraConnectedCoalesced`,{resolution:r.resolution||``}):i(`settings.toast.cameraConnected`,{resolution:r.resolution||``}),`success`):o(r.error||i(`settings.toast.connectionFailed`),`error`)}catch(t){let n=t instanceof Error?t.message:i(`settings.toast.testFailed`);yt(t=>({...t,[e]:{success:!1,error:n}})),o(n,`error`)}finally{xt(t=>({...t,[e]:!1}))}},[qn,Jn]=(0,y.useState)({}),Yn=(0,y.useRef)({}),Xn=(0,y.useRef)(new Set),[Zn,Qn]=(0,y.useState)({}),$n=(0,y.useRef)({}),er=(0,y.useRef)(new Set);(0,y.useEffect)(()=>{if(zt){let e={},t={};zt.forEach(n=>{n.external_camera_url&&!Xn.current.has(n.id)&&(e[n.id]=n.external_camera_url,Xn.current.add(n.id)),n.external_camera_snapshot_url&&!er.current.has(n.id)&&(t[n.id]=n.external_camera_snapshot_url,er.current.add(n.id))}),Object.keys(e).length>0&&Jn(t=>({...t,...e})),Object.keys(t).length>0&&Qn(e=>({...e,...t}))}},[zt]);let tr=(e,t)=>{Jn(n=>({...n,[e]:t})),Yn.current[e]&&clearTimeout(Yn.current[e]),Yn.current[e]=setTimeout(()=>{Wn.mutate({id:e,data:{external_camera_url:t||null}})},800)},nr=(e,t)=>{Qn(n=>({...n,[e]:t})),$n.current[e]&&clearTimeout($n.current[e]),$n.current[e]=setTimeout(()=>{Wn.mutate({id:e,data:{external_camera_snapshot_url:t||null}})},800)},rr=(e,t)=>{let n={};t.type!==void 0&&(n.external_camera_type=t.type||null),t.enabled!==void 0&&(n.external_camera_enabled=t.enabled),t.rotation!==void 0&&(n.camera_rotation=t.rotation),Wn.mutate({id:e,data:n})};if(wt||!A)return(0,K.jsx)(`div`,{className:`p-4 md:p-8 flex justify-center`,children:(0,K.jsx)(X,{className:`w-8 h-8 text-bambu-green animate-spin`})});let ar=ZUe().map(e=>({...e,label:i(e.labelKey,e.labelFallback??e.labelKey)})),or=ie.trim().toLowerCase(),sr=or?ar.filter(e=>e.label.toLowerCase().includes(or)||e.keywords.toLowerCase().includes(or)).slice(0,8):[],cr=e=>{ge(e.tab),e.subTab&&pe(e.subTab),H(``),setTimeout(()=>{let t=document.getElementById(e.anchor);t&&(t.scrollIntoView({behavior:`smooth`,block:`start`}),t.classList.add(`ring-2`,`ring-bambu-green`),setTimeout(()=>t.classList.remove(`ring-2`,`ring-bambu-green`),1500))},50)};return(0,K.jsx)(Dd,{density:`dense`,children:(0,K.jsxs)(`div`,{className:`p-4 md:p-8`,children:[(0,K.jsxs)(`div`,{className:`mb-4 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`h1`,{className:`text-2xl font-bold text-white flex items-center gap-3`,children:[(0,K.jsx)(Zl,{className:`w-7 h-7 text-bambu-green`}),i(`settings.title`)]}),(0,K.jsx)(`p`,{className:`text-bambu-gray mt-1`,children:i(`settings.configureBambuddy`)})]}),(0,K.jsxs)(`div`,{className:`relative sm:w-72`,children:[(0,K.jsx)(Kl,{className:`w-4 h-4 text-bambu-gray absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none`}),(0,K.jsx)(`input`,{type:`text`,value:ie,onChange:e=>H(e.target.value),placeholder:i(`settings.searchPlaceholder`,`Search settings…`),className:`w-full pl-9 pr-8 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-sm focus:outline-none focus:border-bambu-green`}),ie&&(0,K.jsx)(`button`,{onClick:()=>H(``),className:`absolute right-2 top-1/2 -translate-y-1/2 p-1 text-bambu-gray hover:text-white`,"aria-label":`Clear`,children:(0,K.jsx)(Yu,{className:`w-3.5 h-3.5`})}),sr.length>0&&(0,K.jsx)(`div`,{className:`absolute top-full left-0 right-0 mt-1 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg shadow-xl z-30 overflow-hidden`,children:sr.map(e=>(0,K.jsxs)(`button`,{onClick:()=>cr(e),className:`w-full px-3 py-2 text-left hover:bg-bambu-dark-tertiary transition-colors border-b border-bambu-dark-tertiary last:border-b-0`,children:[(0,K.jsx)(`p`,{className:`text-sm text-white`,children:e.label}),(0,K.jsxs)(`p`,{className:`text-xs text-bambu-gray`,children:[i(`settings.tabs.${e.tab===`virtual-printer`?`virtualPrinter`:e.tab===`failure-detection`?`failureDetection`:e.tab}`),e.subTab?` › ${i(`settings.tabs.${e.subTab}`,e.subTab)}`:``]})]},e.anchor))}),or&&sr.length===0&&(0,K.jsx)(`div`,{className:`absolute top-full left-0 right-0 mt-1 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg shadow-xl z-30 p-3`,children:(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray italic`,children:i(`settings.noSearchResults`,`No matching settings.`)})})]})]}),(0,K.jsxs)(`div`,{className:`flex flex-col lg:flex-row gap-4 lg:gap-6`,children:[(0,K.jsxs)(`nav`,{className:`flex flex-wrap gap-1 border-b border-bambu-dark-tertiary lg:flex-col lg:flex-nowrap lg:gap-0 lg:border-b-0 lg:border-r lg:w-48 lg:flex-shrink-0 lg:self-start lg:sticky lg:top-4`,children:[(0,K.jsxs)(`button`,{onClick:()=>ge(`general`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${ue===`general`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Zl,{className:`w-4 h-4`}),i(`settings.tabs.general`)]}),(0,K.jsxs)(`button`,{onClick:()=>ge(`plugs`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${ue===`plugs`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(kl,{className:`w-4 h-4`}),i(`settings.tabs.smartPlugs`),At&&At.length>0&&(0,K.jsx)(`span`,{className:`text-xs bg-bambu-dark-tertiary px-1.5 py-0.5 rounded-full`,children:At.length})]}),(0,K.jsxs)(`button`,{onClick:()=>ge(`notifications`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${ue===`notifications`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Wo,{className:`w-4 h-4`}),i(`settings.tabs.notifications`),Pt&&Pt.length>0&&(0,K.jsx)(`span`,{className:`text-xs bg-bambu-dark-tertiary px-1.5 py-0.5 rounded-full`,children:Pt.length})]}),(0,K.jsxs)(`button`,{onClick:()=>ge(`queue`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${ue===`queue`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Jc,{className:`w-4 h-4`}),i(`settings.tabs.queue`,`Workflow`)]}),(0,K.jsxs)(`button`,{onClick:()=>ge(`filament`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${ue===`filament`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Bs,{className:`w-4 h-4`}),i(`settings.tabs.filament`)]}),(0,K.jsxs)(`button`,{onClick:()=>ge(`network`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${ue===`network`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Gu,{className:`w-4 h-4`}),i(`settings.tabs.network`),(0,K.jsx)(`span`,{className:`w-2 h-2 rounded-full ${fn?.enabled?`bg-green-400`:`bg-gray-500`}`})]}),(0,K.jsxs)(`button`,{onClick:()=>ge(`apikeys`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${ue===`apikeys`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Vc,{className:`w-4 h-4`}),i(`settings.tabs.apiKeys`),It&&It.length>0&&(0,K.jsx)(`span`,{className:`text-xs bg-bambu-dark-tertiary px-1.5 py-0.5 rounded-full`,children:It.length})]}),(0,K.jsxs)(`button`,{onClick:()=>ge(`virtual-printer`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${ue===`virtual-printer`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Nl,{className:`w-4 h-4`}),i(`settings.tabs.virtualPrinter`),(0,K.jsx)(`span`,{className:`w-2 h-2 rounded-full ${Wt?`bg-green-400`:`bg-gray-500`}`})]}),(0,K.jsxs)(`button`,{onClick:()=>ge(`spoolbuddy`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${ue===`spoolbuddy`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Hl,{className:`w-4 h-4`}),i(`settings.tabs.spoolbuddy`),Kt>0&&(0,K.jsx)(`span`,{className:`text-xs bg-bambu-dark-tertiary px-1.5 py-0.5 rounded-full`,children:Kt}),(0,K.jsx)(`span`,{className:`w-2 h-2 rounded-full ${qt?`bg-green-400`:`bg-gray-500`}`})]}),(0,K.jsxs)(`button`,{onClick:()=>ge(`failure-detection`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${ue===`failure-detection`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Ul,{className:`w-4 h-4`}),i(`settings.tabs.failureDetection`),(0,K.jsx)(`span`,{className:`w-2 h-2 rounded-full ${Yt?`bg-green-400`:`bg-gray-500`}`})]}),(0,K.jsxs)(`button`,{onClick:()=>ge(`users`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${ue===`users`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Lu,{className:`w-4 h-4`}),i(`settings.tabs.users`),s&&(0,K.jsx)(`span`,{className:`w-2 h-2 rounded-full bg-green-400`})]}),(0,K.jsxs)(`button`,{onClick:()=>ge(`backup`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${ue===`backup`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Vs,{className:`w-4 h-4`}),i(`settings.tabs.backup`),(0,K.jsx)(`span`,{className:`w-2 h-2 rounded-full ${mn?.is_authenticated&&pn?.configured&&pn?.enabled||Ct?.local_backup_enabled?`bg-green-400`:`bg-gray-500`}`})]})]}),(0,K.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[ue===`general`&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`a`,{href:_f(Bt,`app-settings`),target:`_blank`,rel:`noopener noreferrer`,className:`group block mb-4 lg:mb-6 rounded-xl border border-bambu-green/30 bg-gradient-to-br from-bambu-green/15 via-bambu-green/5 to-transparent hover:border-bambu-green/50 hover:from-bambu-green/20 transition-colors`,children:(0,K.jsxs)(`div`,{className:`flex flex-col md:flex-row items-start md:items-center gap-4 p-4 md:p-5`,children:[(0,K.jsx)(`div`,{className:`p-3 rounded-lg bg-bambu-green/20 text-bambu-green flex-shrink-0`,children:Bt===`business`?(0,K.jsx)(Yo,{className:`w-6 h-6`}):(0,K.jsx)(Nc,{className:`w-6 h-6`})}),(0,K.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,K.jsx)(`p`,{className:`text-base font-semibold text-white`,children:Bt===`business`?i(`sponsors.businessTitle`,`Bambuddy for business`):i(`sponsors.sectionTitle`,`Independent & community-funded`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mt-0.5`,children:Bt===`business`?i(`sponsors.businessTagline`,`You're running {{count}} printers. Priority support, commercial licensing and invoicing are available for teams and print farms.`,{count:zt?.length??0}):i(`sponsors.tagline`,`Bambuddy is free and stays that way because people choose to support it. No VC, no cloud lock-in.`)})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 px-4 py-2 rounded-lg bg-bambu-green/20 text-bambu-green group-hover:bg-bambu-green/30 text-sm font-medium whitespace-nowrap self-start md:self-auto`,children:[Bt===`business`?i(`sponsors.businessCta`,`Bambuddy for business`):i(`sponsors.viewSupporters`,`View supporters`),(0,K.jsx)($s,{className:`w-4 h-4`})]})]})}),(0,K.jsxs)(`div`,{className:`flex flex-col lg:flex-row gap-4 lg:gap-6`,children:[(0,K.jsxs)(`div`,{className:`space-y-3 flex-1 lg:max-w-xl`,children:[(0,K.jsxs)(Od,{id:`card-general`,children:[(0,K.jsx)(kd,{children:(0,K.jsx)(`h2`,{className:`text-lg font-semibold text-white`,children:i(`settings.general`)})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:[(0,K.jsx)(Tc,{className:`w-4 h-4 inline mr-1`}),i(`settings.language`)]}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`select`,{value:a.language,onChange:e=>{let t=e.target.value;if(s&&!d(`settings:update`)){o(i(`settings.toast.noPermissionUpdate`),`error`);return}a.changeLanguage(t),Un.mutate({language:t})},className:`w-full px-3 py-2 pr-10 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none appearance-none cursor-pointer`,children:Ot.map(e=>(0,K.jsxs)(`option`,{value:e.code,children:[e.nativeName,` (`,e.name,`)`]},e.code))}),(0,K.jsx)(ls,{className:`absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray pointer-events-none`})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.languageDescription`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.defaultView`)}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`select`,{value:U,onChange:e=>St(e.target.value),className:`w-full px-3 py-2 pr-10 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none appearance-none cursor-pointer`,children:Up.map(e=>(0,K.jsx)(`option`,{value:e.to,children:i(e.labelKey)},e.id))}),(0,K.jsx)(ls,{className:`absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray pointer-events-none`})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.defaultViewDescription`)})]}),(0,K.jsxs)(`div`,{className:`grid grid-cols-2 gap-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.dateFormat`)}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsxs)(`select`,{value:A.date_format||`system`,onChange:e=>Gn(`date_format`,e.target.value),className:`w-full px-3 py-2 pr-10 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none appearance-none cursor-pointer`,children:[(0,K.jsx)(`option`,{value:`system`,children:i(`settings.systemDefault`)}),(0,K.jsx)(`option`,{value:`us`,children:i(`settings.dateFormatUs`)}),(0,K.jsx)(`option`,{value:`eu`,children:i(`settings.dateFormatEu`)}),(0,K.jsx)(`option`,{value:`iso`,children:i(`settings.dateFormatIso`)})]}),(0,K.jsx)(ls,{className:`absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray pointer-events-none`})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.timeFormat`)}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsxs)(`select`,{value:A.time_format||`system`,onChange:e=>Gn(`time_format`,e.target.value),className:`w-full px-3 py-2 pr-10 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none appearance-none cursor-pointer`,children:[(0,K.jsx)(`option`,{value:`system`,children:i(`settings.systemDefault`)}),(0,K.jsx)(`option`,{value:`12h`,children:i(`settings.timeFormat12`)}),(0,K.jsx)(`option`,{value:`24h`,children:i(`settings.timeFormat24`)})]}),(0,K.jsx)(ls,{className:`absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray pointer-events-none`})]})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.defaultPrinter`)}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsxs)(`select`,{value:A.default_printer_id??``,onChange:e=>Gn(`default_printer_id`,e.target.value?Number(e.target.value):null),className:`w-full px-3 py-2 pr-10 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none appearance-none cursor-pointer`,children:[(0,K.jsx)(`option`,{value:``,children:i(`settings.noDefaultPrinter`)}),zt?.map(e=>(0,K.jsx)(`option`,{value:e.id,children:e.name},e.id))]}),(0,K.jsx)(ls,{className:`absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray pointer-events-none`})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.defaultPrinterDescription`)})]})]})]}),(0,K.jsxs)(Od,{id:`card-appearance`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(bl,{className:`w-5 h-5`}),i(`settings.appearance`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 mb-2`,children:[(0,K.jsxs)(`label`,{className:`text-sm text-bambu-gray`,children:[i(`settings.theme`),`:`]}),(0,K.jsx)(`div`,{className:`flex gap-1`,children:[{id:`dark`,label:i(`settings.themeDark`)},{id:`light`,label:i(`settings.themeLight`)},{id:`system`,label:i(`settings.themeSystem`)}].map(({id:e,label:t})=>(0,K.jsx)(`button`,{onClick:()=>{x(e),o(i(`settings.toast.settingsSaved`),`success`)},className:`px-3 py-1 text-xs rounded-lg border transition-colors ${f===e?`border-bambu-green bg-bambu-green/10 text-bambu-green`:`border-gray-300 dark:border-bambu-dark-tertiary text-gray-500 dark:text-bambu-gray hover:text-gray-900 dark:hover:text-white cursor-pointer`}`,children:t},e))})]}),(0,K.jsxs)(`div`,{className:`space-y-3 p-4 rounded-lg border ${p===`dark`?`border-bambu-green bg-bambu-green/5`:`border-bambu-dark-tertiary`}`,children:[(0,K.jsxs)(`h3`,{className:`text-sm font-medium text-white flex items-center gap-2`,children:[i(`settings.darkMode`),p===`dark`&&(0,K.jsx)(`span`,{className:`text-xs text-bambu-green`,children:i(`settings.active`)})]}),(0,K.jsxs)(`div`,{className:`grid grid-cols-3 gap-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.background`)}),(0,K.jsxs)(`select`,{value:h,onChange:e=>{C(e.target.value),o(i(`settings.toast.settingsSaved`),`success`)},className:`w-full px-2 py-1.5 text-sm bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`neutral`,children:i(`settings.bgNeutral`)}),(0,K.jsx)(`option`,{value:`warm`,children:i(`settings.bgWarm`)}),(0,K.jsx)(`option`,{value:`cool`,children:i(`settings.bgCool`)}),(0,K.jsx)(`option`,{value:`oled`,children:i(`settings.bgOled`)}),(0,K.jsx)(`option`,{value:`slate`,children:i(`settings.bgSlate`)}),(0,K.jsx)(`option`,{value:`forest`,children:i(`settings.bgForest`)})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.accent`)}),(0,K.jsxs)(`select`,{value:g,onChange:e=>{w(e.target.value),o(i(`settings.toast.settingsSaved`),`success`)},className:`w-full px-2 py-1.5 text-sm bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`green`,children:i(`settings.accentGreen`)}),(0,K.jsx)(`option`,{value:`teal`,children:i(`settings.accentTeal`)}),(0,K.jsx)(`option`,{value:`blue`,children:i(`settings.accentBlue`)}),(0,K.jsx)(`option`,{value:`orange`,children:i(`settings.accentOrange`)}),(0,K.jsx)(`option`,{value:`purple`,children:i(`settings.accentPurple`)}),(0,K.jsx)(`option`,{value:`red`,children:i(`settings.accentRed`)})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.style`)}),(0,K.jsxs)(`select`,{value:m,onChange:e=>{S(e.target.value),o(i(`settings.toast.settingsSaved`),`success`)},className:`w-full px-2 py-1.5 text-sm bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`classic`,children:i(`settings.styleClassic`)}),(0,K.jsx)(`option`,{value:`glow`,children:i(`settings.styleGlow`)}),(0,K.jsx)(`option`,{value:`vibrant`,children:i(`settings.styleVibrant`)})]})]})]})]}),(0,K.jsxs)(`div`,{className:`space-y-3 p-4 rounded-lg border ${p===`light`?`border-bambu-green bg-bambu-green/5`:`border-bambu-dark-tertiary`}`,children:[(0,K.jsxs)(`h3`,{className:`text-sm font-medium text-white flex items-center gap-2`,children:[i(`settings.lightMode`),p===`light`&&(0,K.jsx)(`span`,{className:`text-xs text-bambu-green`,children:i(`settings.active`)})]}),(0,K.jsxs)(`div`,{className:`grid grid-cols-3 gap-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.background`)}),(0,K.jsxs)(`select`,{value:v,onChange:e=>{E(e.target.value),o(i(`settings.toast.settingsSaved`),`success`)},className:`w-full px-2 py-1.5 text-sm bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`neutral`,children:i(`settings.bgNeutral`)}),(0,K.jsx)(`option`,{value:`warm`,children:i(`settings.bgWarm`)}),(0,K.jsx)(`option`,{value:`cool`,children:i(`settings.bgCool`)})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.accent`)}),(0,K.jsxs)(`select`,{value:b,onChange:e=>{D(e.target.value),o(i(`settings.toast.settingsSaved`),`success`)},className:`w-full px-2 py-1.5 text-sm bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`green`,children:i(`settings.accentGreen`)}),(0,K.jsx)(`option`,{value:`teal`,children:i(`settings.accentTeal`)}),(0,K.jsx)(`option`,{value:`blue`,children:i(`settings.accentBlue`)}),(0,K.jsx)(`option`,{value:`orange`,children:i(`settings.accentOrange`)}),(0,K.jsx)(`option`,{value:`purple`,children:i(`settings.accentPurple`)}),(0,K.jsx)(`option`,{value:`red`,children:i(`settings.accentRed`)})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.style`)}),(0,K.jsxs)(`select`,{value:_,onChange:e=>{T(e.target.value),o(i(`settings.toast.settingsSaved`),`success`)},className:`w-full px-2 py-1.5 text-sm bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`classic`,children:i(`settings.styleClassic`)}),(0,K.jsx)(`option`,{value:`glow`,children:i(`settings.styleGlow`)}),(0,K.jsx)(`option`,{value:`vibrant`,children:i(`settings.styleVibrant`)})]})]})]})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.themeToggleHint`)}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between pt-2 border-t border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.progressInTitle`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.progressInTitleDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:O,onChange:e=>{k(e.target.checked),o(i(`settings.toast.settingsSaved`),`success`)},className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]})]})]}),(0,K.jsxs)(Od,{id:`card-archive`,children:[(0,K.jsx)(kd,{children:(0,K.jsx)(`h2`,{className:`text-lg font-semibold text-white`,children:i(`settings.archiveSettings`)})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.autoArchivePrints`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.autoArchiveDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.auto_archive,onChange:e=>Gn(`auto_archive`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.saveThumbnails`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.saveThumbnailsDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.save_thumbnails,onChange:e=>Gn(`save_thumbnails`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.captureFinishPhoto`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.captureFinishPhotoDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.capture_finish_photo,onChange:e=>Gn(`capture_finish_photo`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),A.capture_finish_photo&&(0,K.jsxs)(`div`,{className:`flex items-center justify-between pl-4 border-l-2 border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.finishPhotoRestorePlate`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.finishPhotoRestorePlateDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.finish_photo_restore_plate??!0,onChange:e=>Gn(`finish_photo_restore_plate`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),A.capture_finish_photo&&Xt&&!Xt.installed&&(0,K.jsxs)(`div`,{className:`flex items-start gap-2 p-3 bg-yellow-500/10 border border-yellow-500/30 rounded-lg`,children:[(0,K.jsx)(ju,{className:`w-5 h-5 text-yellow-500 flex-shrink-0 mt-0.5`}),(0,K.jsxs)(`div`,{className:`text-sm`,children:[(0,K.jsx)(`p`,{className:`text-yellow-500 font-medium`,children:i(`settings.ffmpegNotInstalled`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray mt-1`,children:i(`settings.ffmpegRequired`)})]})]}),nn&&rn&&(0,K.jsxs)(`div`,{className:`border-t border-bambu-dark-tertiary pt-3 mt-3 space-y-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`archiveAutoPurge.enableLabel`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`archiveAutoPurge.enableDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:rn.enabled,onChange:e=>on({enabled:e.target.checked}),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`archiveAutoPurge.ageLabel`)}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`input`,{type:`number`,min:7,max:3650,disabled:!rn.enabled,value:rn.days,onChange:e=>on({days:Math.max(7,Math.min(3650,parseInt(e.target.value||`0`,10)||0))}),className:`w-24 px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none disabled:opacity-50`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:i(`archiveAutoPurge.days`)})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`archiveAutoPurge.ageDescription`)})]}),(0,K.jsxs)(`label`,{className:`flex items-start gap-2 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,disabled:!rn.enabled,checked:rn.purge_stats,onChange:e=>on({purge_stats:e.target.checked}),className:`mt-0.5 shrink-0 disabled:opacity-50`}),(0,K.jsxs)(`span`,{className:`text-sm`,children:[(0,K.jsx)(`span`,{className:`text-white block`,children:i(`archiveAutoPurge.purgeStatsLabel`)}),(0,K.jsx)(`span`,{className:`text-xs text-bambu-gray block mt-0.5`,children:i(`archiveAutoPurge.purgeStatsDescription`)})]})]})]})]})]})]}),(0,K.jsxs)(`div`,{className:`space-y-3 flex-1 lg:max-w-md`,children:[(0,K.jsxs)(Od,{id:`card-camera`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(zu,{className:`w-5 h-5 text-bambu-green`}),i(`settings.camera`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.cameraViewMode`)}),(0,K.jsxs)(`select`,{value:A.camera_view_mode??`window`,onChange:e=>Gn(`camera_view_mode`,e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`window`,children:i(`settings.newWindow`)}),(0,K.jsx)(`option`,{value:`embedded`,children:i(`settings.embeddedOverlay`)})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:A.camera_view_mode===`embedded`?i(`settings.cameraOverlayDescription`):i(`settings.cameraWindowDescription`)})]}),(0,K.jsxs)(`div`,{className:`border-t border-bambu-dark-tertiary pt-4 mt-4`,children:[(0,K.jsx)(`h3`,{className:`text-sm font-medium text-white mb-2`,children:i(`settings.externalCameras`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mb-3`,children:i(`settings.externalCamerasDescription`)}),zt&&zt.length>0?(0,K.jsx)(`div`,{className:`space-y-3`,children:zt.map(e=>(0,K.jsxs)(`div`,{className:`p-3 bg-bambu-dark rounded-lg`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between mb-2`,children:[(0,K.jsx)(`span`,{className:`text-white font-medium text-sm`,children:e.name}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:e.external_camera_enabled,onChange:t=>rr(e.id,{enabled:t.target.checked}),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-9 h-5 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-bambu-green`})]})]}),e.external_camera_enabled&&(0,K.jsxs)(`div`,{className:`space-y-2 mt-2`,children:[(0,K.jsx)(`input`,{type:`text`,placeholder:e.external_camera_type===`usb`?i(`settings.cameraPlaceholderUsb`):i(`settings.cameraPlaceholderUrl`),value:qn[e.id]??e.external_camera_url??``,onChange:t=>tr(e.id,t.target.value),className:`w-full px-3 py-2 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded text-white text-sm focus:border-bambu-green focus:outline-none`}),(0,K.jsxs)(`div`,{className:`flex gap-2`,children:[(0,K.jsxs)(`select`,{value:e.external_camera_type||`mjpeg`,onChange:t=>rr(e.id,{type:t.target.value}),className:`flex-1 px-3 py-2 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded text-white text-sm focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`mjpeg`,children:i(`settings.cameraTypeMjpeg`)}),(0,K.jsx)(`option`,{value:`rtsp`,children:i(`settings.cameraTypeRtsp`)}),(0,K.jsx)(`option`,{value:`snapshot`,children:i(`settings.cameraTypeSnapshot`)}),(0,K.jsx)(`option`,{value:`usb`,children:i(`settings.cameraTypeUsb`)})]}),(0,K.jsx)($,{size:`sm`,variant:`secondary`,onClick:()=>Kn(e.id,qn[e.id]??e.external_camera_url??``,e.external_camera_type||`mjpeg`),disabled:bt[e.id]||!(qn[e.id]??e.external_camera_url),children:bt[e.id]?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):i(`settings.test`)})]}),vt[e.id]&&(0,K.jsx)(`div`,{className:`text-xs flex items-center gap-1 ${vt[e.id]?.success?`text-green-500`:`text-red-500`}`,children:vt[e.id]?.success?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(_s,{className:`w-3 h-3`}),i(`settings.connected`),vt[e.id]?.resolution&&` (${vt[e.id]?.resolution})`]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(Cs,{className:`w-3 h-3`}),vt[e.id]?.error||i(`settings.toast.connectionFailed`)]})}),(e.external_camera_type===`mjpeg`||e.external_camera_type===`rtsp`||e.external_camera_type===`usb`)&&(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsx)(`label`,{className:`text-xs text-bambu-gray`,children:i(`settings.cameraSnapshotUrl`,`Snapshot URL (optional)`)}),(0,K.jsxs)(`div`,{className:`flex gap-2`,children:[(0,K.jsx)(`input`,{type:`text`,placeholder:i(`settings.cameraSnapshotUrlPlaceholder`,`http://192.168.1.61:1984/api/frame.jpeg?src=printer`),value:Zn[e.id]??e.external_camera_snapshot_url??``,onChange:t=>nr(e.id,t.target.value),className:`flex-1 px-3 py-2 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded text-white text-sm focus:border-bambu-green focus:outline-none`}),(0,K.jsx)($,{size:`sm`,variant:`secondary`,onClick:()=>Kn(e.id,Zn[e.id]??e.external_camera_snapshot_url??``,`snapshot`),disabled:bt[e.id]||!(Zn[e.id]??e.external_camera_snapshot_url),children:bt[e.id]?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):i(`settings.test`)})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray opacity-75`,children:i(`settings.cameraSnapshotUrlHelp`,`Single-frame URL used for notification thumbnails, finish photos, timelapse and plate detection. Leave blank to capture from the live stream above. Useful for go2rtc (/api/frame.jpeg) and IP cameras with a dedicated snapshot endpoint.`)})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`label`,{className:`text-xs text-bambu-gray`,children:i(`settings.cameraRotation`)}),(0,K.jsxs)(`select`,{value:e.camera_rotation||0,onChange:t=>rr(e.id,{rotation:parseInt(t.target.value)}),className:`px-2 py-1 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded text-white text-xs focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:0,children:`0°`}),(0,K.jsx)(`option`,{value:90,children:`90°`}),(0,K.jsx)(`option`,{value:180,children:`180°`}),(0,K.jsx)(`option`,{value:270,children:`270°`})]})]})]})]},e.id))}):(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray italic`,children:i(`settings.noPrintersConfigured`)})]})]})]}),(0,K.jsxs)(Od,{id:`card-cost`,children:[(0,K.jsx)(kd,{children:(0,K.jsx)(`h2`,{className:`text-lg font-semibold text-white`,children:i(`settings.costTracking`)})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.currency`)}),(0,K.jsx)(`select`,{value:A.currency,onChange:e=>Gn(`currency`,e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:hf.map(e=>(0,K.jsx)(`option`,{value:e.code,children:e.label},e.code))})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.defaultFilamentCost`)}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`span`,{className:`absolute left-3 top-1/2 -translate-y-1/2 text-bambu-gray text-sm pointer-events-none`,children:mf(A.currency)}),(0,K.jsx)(`input`,{type:`number`,step:`0.01`,min:`0`,value:A.default_filament_cost,onChange:e=>Gn(`default_filament_cost`,parseFloat(e.target.value)||0),style:{paddingLeft:`${Math.max(2,mf(A.currency).length*.6+1)}rem`},className:`w-full pr-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.electricityCost`)}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`span`,{className:`absolute left-3 top-1/2 -translate-y-1/2 text-bambu-gray text-sm pointer-events-none`,children:mf(A.currency)}),(0,K.jsx)(`input`,{type:`number`,step:`0.001`,min:`0`,value:A.energy_cost_per_kwh,onChange:e=>Gn(`energy_cost_per_kwh`,parseFloat(e.target.value)||0),style:{paddingLeft:`${Math.max(2,mf(A.currency).length*.6+1)}rem`},className:`w-full pr-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.energyDisplayMode`)}),(0,K.jsxs)(`select`,{value:A.energy_tracking_mode||`total`,onChange:e=>Gn(`energy_tracking_mode`,e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`print`,children:i(`settings.printsOnly`)}),(0,K.jsx)(`option`,{value:`total`,children:i(`settings.totalConsumption`)})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:A.energy_tracking_mode===`print`?i(`settings.energyModePrintDescription`):i(`settings.energyModeTotalDescription`)})]})]})]}),(0,K.jsxs)(Od,{id:`card-filemanager`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(sc,{className:`w-5 h-5 text-bambu-green`}),i(`settings.fileManager`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.createArchiveEntry`)}),(0,K.jsxs)(`select`,{value:A.library_archive_mode??`ask`,onChange:e=>Gn(`library_archive_mode`,e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`always`,children:i(`settings.archiveMode.always`)}),(0,K.jsx)(`option`,{value:`never`,children:i(`settings.archiveMode.never`)}),(0,K.jsx)(`option`,{value:`ask`,children:i(`settings.archiveMode.ask`)})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.createArchiveEntryDescription`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.lowDiskSpaceWarning`)}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`input`,{type:`number`,min:`0.5`,max:`100`,step:`0.5`,value:A.library_disk_warning_gb??5,onChange:e=>Gn(`library_disk_warning_gb`,parseFloat(e.target.value)||5),className:`w-24 px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:`GB`})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.lowDiskSpaceDescription`)})]}),Qt&&$t&&(0,K.jsxs)(`div`,{className:`border-t border-bambu-dark-tertiary pt-3 mt-3 space-y-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`libraryAutoPurge.enableLabel`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`libraryAutoPurge.enableDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:$t.auto_purge_enabled,onChange:e=>tn({auto_purge_enabled:e.target.checked}),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`libraryAutoPurge.ageLabel`)}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`input`,{type:`number`,min:7,max:3650,disabled:!$t.auto_purge_enabled,value:$t.auto_purge_days,onChange:e=>tn({auto_purge_days:Math.max(7,Math.min(3650,parseInt(e.target.value||`0`,10)||0))}),className:`w-24 px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none disabled:opacity-50`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:i(`libraryAutoPurge.days`)})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`libraryAutoPurge.ageDescription`)})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-2 text-sm text-white cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,disabled:!$t.auto_purge_enabled,checked:$t.auto_purge_include_never_printed,onChange:e=>tn({auto_purge_include_never_printed:e.target.checked}),className:`rounded border-gray-300 disabled:opacity-50`}),i(`libraryAutoPurge.includeNeverPrinted`)]})]})]})]}),(0,K.jsxs)(Od,{id:`card-data`,children:[(0,K.jsx)(kd,{children:(0,K.jsx)(`h2`,{className:`text-lg font-semibold text-white`,children:i(`settings.dataManagement`)})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.clearNotificationLogs`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.clearNotificationLogsDescription`)})]}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,onClick:()=>Ne(!0),children:[(0,K.jsx)(Ou,{className:`w-4 h-4`}),i(`common.clear`)]})]}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.resetUiPreferences`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.resetUiPreferencesDescription`)})]}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,onClick:()=>Fe(!0),children:[(0,K.jsx)(Ou,{className:`w-4 h-4`}),i(`settings.reset`)]})]}),(0,K.jsxs)(`div`,{className:`pt-4 border-t border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.storageUsage`,`Storage Usage`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.storageUsageDescription`,`Breakdown of data usage by category`)})]}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,onClick:kt,disabled:Dt||Je,children:[(0,K.jsx)(Il,{className:`w-4 h-4 ${Dt||Je?`animate-spin`:``}`}),i(`common.refresh`,`Refresh`)]})]}),(0,K.jsx)(`div`,{className:`mt-3`,children:Et?(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-sm text-bambu-gray`,children:[(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}),i(`common.loading`,`Loading`)]}):Tt?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`div`,{className:`w-full h-3 bg-bambu-dark rounded-full overflow-hidden flex`,children:Tt.categories.filter(e=>e.bytes>0).map((e,t)=>(0,K.jsx)(`div`,{className:`${D6(e.key,t)} h-full`,style:{width:`${e.percent_of_total}%`},title:`${e.label}: ${e.formatted}`},e.key))}),(0,K.jsx)(`div`,{className:`mt-3 flex flex-wrap gap-3`,children:Tt.categories.filter(e=>e.bytes>0).map((e,t)=>(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-xs`,children:[(0,K.jsx)(`span`,{className:`w-3 h-3 rounded-full ${D6(e.key,t)}`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:e.label}),(0,K.jsx)(`span`,{className:`text-white`,children:e.formatted}),(0,K.jsxs)(`span`,{className:`text-bambu-gray`,children:[`(`,e.percent_of_total.toFixed(1),`%)`]})]},e.key))}),(0,K.jsxs)(`div`,{className:`mt-2 text-xs text-bambu-gray`,children:[i(`settings.storageUsageTotal`,`Total`),`: `,(0,K.jsx)(`span`,{className:`text-white`,children:Tt.total_formatted}),Tt.scan_errors>0&&(0,K.jsxs)(`span`,{className:`ml-2 text-amber-700 dark:text-amber-400`,children:[i(`settings.storageUsageErrors`,`Scan errors`),`: `,Tt.scan_errors]})]}),Tt.other_breakdown?.length>0&&(0,K.jsxs)(`div`,{className:`mt-4`,children:[(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mb-2`,children:i(`settings.storageUsageOtherBreakdown`,`Other breakdown`)}),(0,K.jsx)(`div`,{className:`space-y-2`,children:Tt.other_breakdown.map(e=>(0,K.jsxs)(`div`,{className:`flex items-center justify-between text-xs`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`span`,{className:`text-white`,children:e.label}),(0,K.jsx)(`span`,{className:`px-2 py-0.5 rounded-full border ${e.kind===`system`?`border-slate-500 text-slate-300`:`border-bambu-green text-bambu-green`}`,children:e.kind===`system`?i(`settings.storageUsageSystem`,`System`):i(`settings.storageUsageData`,`Data`)})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-bambu-gray`,children:[(0,K.jsx)(`span`,{className:`text-white`,children:e.formatted}),(0,K.jsxs)(`span`,{children:[`(`,e.percent_of_total.toFixed(1),`%)`]})]})]},`${e.bucket}-${e.kind}`))})]})]}):(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.storageUsageUnavailable`,`Storage usage data is unavailable`)})})]}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between pt-4 border-t border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.backupRestore`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.backupRestoreDescription`)})]}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,onClick:()=>ge(`backup`),children:[(0,K.jsx)(Vs,{className:`w-4 h-4`}),i(`settings.goToBackup`)]})]})]})]})]}),(0,K.jsxs)(`div`,{className:`space-y-3 flex-1 lg:max-w-sm`,children:[(0,K.jsxs)(Od,{id:`card-updates`,children:[(0,K.jsx)(kd,{children:(0,K.jsx)(`h2`,{className:`text-lg font-semibold text-white`,children:i(`settings.updates`)})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-xs font-medium text-bambu-gray uppercase tracking-wider`,children:i(`settings.printerFirmware`)}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.checkPrinterFirmware`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.checkFirmwareDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.check_printer_firmware??!0,onChange:e=>Gn(`check_printer_firmware`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),(0,K.jsx)(`div`,{className:`border-t border-bambu-dark-tertiary pt-4`,children:(0,K.jsx)(`p`,{className:`text-xs font-medium text-bambu-gray uppercase tracking-wider mb-4`,children:i(`settings.bambuddySoftware`)})}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.checkForUpdatesLabel`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.autoCheckDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.check_updates,onChange:e=>Gn(`check_updates`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between ${A.check_updates?``:`opacity-50`}`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.includeBetaUpdates`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.includeBetaUpdatesDesc`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.include_beta_updates??!1,onChange:e=>Gn(`include_beta_updates`,e.target.checked),disabled:!A.check_updates,className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between mb-2`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.currentVersion`)}),(0,K.jsxs)(`p`,{className:`text-sm text-bambu-gray`,children:[`v`,Zt?.version||`...`]})]}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,onClick:()=>cn(),disabled:ln,children:[ln?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(Il,{className:`w-4 h-4`}),i(`settings.checkNow`)]})]}),sn?.update_available?(0,K.jsxs)(`div`,{className:`mt-4 p-3 bg-bambu-green/10 border border-bambu-green/30 rounded-lg`,children:[(0,K.jsxs)(`div`,{className:`flex items-start justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`p`,{className:`text-bambu-green font-medium`,children:[`Update available: v`,sn.latest_version]}),sn.release_name&&sn.release_name!==sn.latest_version&&(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mt-1`,children:sn.release_name})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[sn.release_notes&&(0,K.jsx)(`button`,{onClick:()=>ze(!0),className:`text-bambu-gray hover:text-white transition-colors text-sm underline`,children:i(`settings.releaseNotes`)}),sn.release_url&&(0,K.jsx)(`a`,{href:sn.release_url,target:`_blank`,rel:`noopener noreferrer`,className:`text-bambu-gray hover:text-white transition-colors`,title:i(`settings.viewReleaseOnGitHub`),children:(0,K.jsx)($s,{className:`w-4 h-4`})})]})]}),un?.status===`downloading`||un?.status===`installing`?(0,K.jsxs)(`div`,{className:`mt-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-sm text-bambu-gray`,children:[(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}),(0,K.jsx)(`span`,{children:un.message})]}),(0,K.jsx)(`div`,{className:`mt-2 w-full bg-bambu-dark-tertiary rounded-full h-2`,children:(0,K.jsx)(`div`,{className:`bg-bambu-green h-2 rounded-full transition-all duration-300`,style:{width:`${un.progress}%`}})})]}):un?.status===`complete`?(0,K.jsx)(`div`,{className:`mt-3 p-2 bg-bambu-green/20 rounded text-sm text-bambu-green`,children:un.message}):un?.status===`error`?(0,K.jsx)(`div`,{className:`mt-3 p-2 bg-red-100 dark:bg-red-500/20 rounded text-sm text-red-700 dark:text-red-400`,children:un.error||un.message}):sn?.is_ha_addon?(0,K.jsx)(`div`,{className:`mt-3 p-3 bg-bambu-dark-tertiary rounded-lg`,children:(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.updateViaHomeAssistant`)})}):sn?.is_docker?(0,K.jsxs)(`div`,{className:`mt-3 p-3 bg-bambu-dark-tertiary rounded-lg`,children:[(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mb-2`,children:i(`settings.updateViaDocker`)}),(0,K.jsx)(`code`,{className:`block text-xs bg-bambu-dark p-2 rounded text-bambu-green font-mono`,children:`docker compose pull && docker compose up -d`})]}):sn?.update_method===`windows_installer`?(0,K.jsxs)(`div`,{className:`mt-3 p-3 bg-bambu-dark-tertiary rounded-lg`,children:[(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mb-3`,children:i(`settings.updateViaWindowsInstaller`)}),(0,K.jsxs)(`a`,{href:sn.installer_download_url||sn.release_url||`https://github.com/maziggy/bambuddy/releases/tag/v${sn.latest_version}`,target:`_blank`,rel:`noopener noreferrer`,className:`inline-flex items-center justify-center font-medium rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-bambu-dark disabled:opacity-50 bg-bambu-green hover:bg-bambu-green-light text-white focus:ring-bambu-green px-4 py-2 text-sm gap-2 min-h-[44px] md:min-h-0`,children:[(0,K.jsx)(Ks,{className:`w-4 h-4`}),i(`settings.downloadWindowsInstaller`,{version:sn.latest_version})]})]}):(0,K.jsxs)($,{className:`mt-3`,onClick:()=>Nn.mutate(),disabled:Nn.isPending,children:[Nn.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(Ks,{className:`w-4 h-4`}),i(`settings.installUpdate`)]})]}):sn?.error?(0,K.jsx)(`div`,{className:`mt-2 p-2 bg-red-50 dark:bg-red-500/10 border border-red-300 dark:border-red-500/30 rounded text-sm text-red-700 dark:text-red-400`,children:i(`settings.failedToCheckUpdates`,{error:sn.error})}):sn&&!sn.update_available?(0,K.jsx)(`p`,{className:`mt-2 text-sm text-bambu-gray`,children:i(`settings.latestVersionRunning`)}):null]})]})]}),(0,K.jsx)(DUe,{})]})]})]}),ue===`network`&&A&&(0,K.jsxs)(`div`,{className:`flex flex-col lg:flex-row gap-6`,children:[(0,K.jsxs)(`div`,{className:`flex-1 lg:max-w-xl space-y-3`,children:[(0,K.jsxs)(Od,{id:`card-externalurl`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(Tc,{className:`w-5 h-5 text-blue-600 dark:text-blue-400`}),i(`settings.externalUrl`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.externalUrlDescription`)}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.bambuddyUrl`)}),(0,K.jsx)(`input`,{type:`text`,value:A.external_url??``,onChange:e=>Gn(`external_url`,e.target.value),placeholder:`http://192.168.1.100:8000`,className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.externalUrlHint`)})]})]})]}),(0,K.jsxs)(Od,{id:`card-ftpretry`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(Il,{className:`w-5 h-5 text-blue-600 dark:text-blue-400`}),i(`settings.ftpRetry`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.ftpRetryDescription`)}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.enableRetry`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.autoRetryDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.ftp_retry_enabled??!0,onChange:e=>Gn(`ftp_retry_enabled`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),A.ftp_retry_enabled&&(0,K.jsxs)(`div`,{className:`space-y-3 pt-2 border-t border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.retryAttempts`)}),(0,K.jsxs)(`div`,{className:`relative w-44`,children:[(0,K.jsx)(`select`,{value:A.ftp_retry_count??3,onChange:e=>Gn(`ftp_retry_count`,parseInt(e.target.value)),className:`w-full px-3 py-2 pr-10 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none appearance-none cursor-pointer`,children:[1,2,3,4,5,6,7,8,9,10].map(e=>(0,K.jsx)(`option`,{value:e,children:i(`settings.time`,{count:e})},e))}),(0,K.jsx)(ls,{className:`absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray pointer-events-none`})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.retryDelay`)}),(0,K.jsxs)(`div`,{className:`relative w-44`,children:[(0,K.jsx)(`select`,{value:A.ftp_retry_delay??2,onChange:e=>Gn(`ftp_retry_delay`,parseInt(e.target.value)),className:`w-full px-3 py-2 pr-10 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none appearance-none cursor-pointer`,children:[1,2,3,5,10,15,20,30].map(e=>(0,K.jsx)(`option`,{value:e,children:i(`settings.second`,{count:e})},e))}),(0,K.jsx)(ls,{className:`absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray pointer-events-none`})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.connectionTimeout`)}),(0,K.jsxs)(`div`,{className:`relative w-44`,children:[(0,K.jsx)(`select`,{value:A.ftp_timeout??30,onChange:e=>Gn(`ftp_timeout`,parseInt(e.target.value)),className:`w-full px-3 py-2 pr-10 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none appearance-none cursor-pointer`,children:[10,15,20,30,45,60,90,120,180,300].map(e=>(0,K.jsx)(`option`,{value:e,children:i(`settings.nSeconds`,{count:e})},e))}),(0,K.jsx)(ls,{className:`absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray pointer-events-none`})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.increaseForWeakWifi`)})]})]})]})]})]}),(0,K.jsxs)(`div`,{className:`flex-1 lg:max-w-xl space-y-3`,children:[(0,K.jsxs)(Od,{id:`card-ha`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(Fc,{className:`w-5 h-5 text-bambu-green`}),i(`settings.homeAssistant`)]}),A.ha_enabled&&mt&&(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`span`,{className:`w-2.5 h-2.5 rounded-full ${mt.success?`bg-green-400`:`bg-red-400`}`}),(0,K.jsx)(`span`,{className:`text-sm ${mt.success?`text-green-700 dark:text-green-400`:`text-red-700 dark:text-red-400`}`,children:mt.success?i(`settings.connected`):i(`settings.disconnected`)})]})]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.homeAssistantFullDescription`)}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex-1`,children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.enableHomeAssistant`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.homeAssistantDescription`)}),A.ha_env_managed&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1 mt-1`,children:[(0,K.jsx)(Qc,{className:`w-3 h-3 text-bambu-green`}),(0,K.jsx)(`span`,{className:`text-xs text-bambu-green`,children:i(`settings.autoEnabledViaEnv`)})]})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.ha_enabled??!1,onChange:e=>Gn(`ha_enabled`,e.target.checked),disabled:A.ha_env_managed,className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green ${A.ha_env_managed?`opacity-60 cursor-not-allowed`:``}`})]})]}),A.ha_enabled&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:[i(`settings.homeAssistantUrl`),A.ha_url_from_env&&(0,K.jsx)(`span`,{className:`ml-2 text-xs text-bambu-green`,children:i(`settings.environmentManagedLabel`)})]}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`input`,{type:`text`,value:A.ha_url??``,onChange:e=>Gn(`ha_url`,e.target.value),placeholder:`http://192.168.1.100:8123`,disabled:A.ha_url_from_env,className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none ${A.ha_url_from_env?`opacity-60 cursor-not-allowed`:``}`}),A.ha_url_from_env&&(0,K.jsx)(Qc,{className:`absolute right-3 top-2.5 w-4 h-4 text-bambu-gray`})]}),A.ha_url_from_env&&(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.urlFromEnvReadOnly`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:[i(`settings.longLivedAccessToken`),A.ha_token_from_env&&(0,K.jsx)(`span`,{className:`ml-2 text-xs text-bambu-green`,children:i(`settings.environmentManagedLabel`)})]}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`input`,{type:`password`,value:A.ha_token??``,onChange:e=>Gn(`ha_token`,e.target.value),placeholder:`eyJ0eXAiOiJKV1QiLC...`,disabled:A.ha_token_from_env,className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none ${A.ha_token_from_env?`opacity-60 cursor-not-allowed`:``}`}),A.ha_token_from_env&&(0,K.jsx)(Qc,{className:`absolute right-3 top-2.5 w-4 h-4 text-bambu-gray`})]}),A.ha_token_from_env?(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.tokenFromEnvReadOnly`)}):(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.haTokenHint`)})]}),A.ha_url&&A.ha_token&&(0,K.jsx)(`div`,{className:`pt-2 border-t border-bambu-dark-tertiary`,children:(0,K.jsxs)($,{variant:`secondary`,size:`sm`,disabled:gt,onClick:async()=>{_t(!0),ht(null);try{ht(await Q.testHAConnection(A.ha_url,A.ha_token))}catch(e){ht({success:!1,message:null,error:e instanceof Error?e.message:i(`common.unknownError`)})}finally{_t(!1)}},children:[gt?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(Gu,{className:`w-4 h-4`}),i(`settings.testConnection`)]})})]})]})]}),(0,K.jsxs)(Od,{id:`card-mqtt`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(Gu,{className:`w-5 h-5 text-blue-600 dark:text-blue-400`}),i(`settings.mqttPublishing`)]}),fn?.enabled&&(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`span`,{className:`w-2.5 h-2.5 rounded-full ${fn.connected?`bg-green-400`:`bg-red-400`}`}),(0,K.jsx)(`span`,{className:`text-sm ${fn.connected?`text-green-700 dark:text-green-400`:`text-red-700 dark:text-red-400`}`,children:fn.connected?i(`settings.connected`):i(`settings.disconnected`)})]})]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.mqttDescription`)}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.enableMqtt`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.mqttEnableDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.mqtt_enabled??!1,onChange:e=>Gn(`mqtt_enabled`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),A.mqtt_enabled&&(0,K.jsxs)(`div`,{className:`space-y-3 pt-2 border-t border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.brokerHostname`)}),(0,K.jsx)(`input`,{type:`text`,value:A.mqtt_broker??``,onChange:e=>Gn(`mqtt_broker`,e.target.value),placeholder:`mqtt.example.com or 192.168.1.100`,className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`})]}),(0,K.jsxs)(`div`,{className:`flex items-end gap-4`,children:[(0,K.jsxs)(`div`,{className:`flex-1`,children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.port`)}),(0,K.jsx)(`input`,{type:`number`,min:`1`,max:`65535`,value:A.mqtt_port??1883,onChange:e=>Gn(`mqtt_port`,Math.min(65535,Math.max(1,parseInt(e.target.value)||1883))),className:`w-24 px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-3 pb-2`,children:[(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.mqtt_use_tls??!1,onChange:e=>{let t=e.target.checked;Gn(`mqtt_use_tls`,t);let n=A.mqtt_port??1883;t&&n===1883?Gn(`mqtt_port`,8883):!t&&n===8883&&Gn(`mqtt_port`,1883)},className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]}),(0,K.jsx)(`span`,{className:`text-white text-sm`,children:i(`settings.useTls`)})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.usernameOptional`)}),(0,K.jsx)(`input`,{type:`text`,value:A.mqtt_username??``,onChange:e=>Gn(`mqtt_username`,e.target.value),placeholder:i(`settings.leaveEmptyForAnonymous`),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.passwordOptional`)}),(0,K.jsx)(`input`,{type:`password`,value:A.mqtt_password??``,onChange:e=>Gn(`mqtt_password`,e.target.value),placeholder:i(`settings.leaveEmptyForAnonymous`),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.topicPrefix`)}),(0,K.jsx)(`input`,{type:`text`,value:A.mqtt_topic_prefix??`bambuddy`,onChange:e=>Gn(`mqtt_topic_prefix`,e.target.value),placeholder:`bambuddy`,className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.topicPrefixHint`,{prefix:A.mqtt_topic_prefix||`bambuddy`})})]}),fn&&(0,K.jsx)(`div`,{className:`pt-3 mt-3 border-t border-bambu-dark-tertiary`,children:(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-sm`,children:[(0,K.jsx)(`span`,{className:`w-2 h-2 rounded-full ${fn.connected?`bg-green-400`:`bg-red-400`}`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:fn.connected?(0,K.jsxs)(K.Fragment,{children:[i(`settings.mqttConnectedTo`),` `,(0,K.jsxs)(`span`,{className:`text-white`,children:[fn.broker,`:`,fn.port]})]}):i(`settings.spoolmanDisconnected`)})]})})]})]})]})]}),(0,K.jsx)(`div`,{className:`flex-1 lg:max-w-md space-y-3`,children:(0,K.jsxs)(Od,{id:`card-prometheus`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(Au,{className:`w-5 h-5 text-orange-600 dark:text-orange-400`}),i(`settings.prometheusMetrics`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.prometheusEndpointDescription`)}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.enableMetricsEndpoint`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.prometheusDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.prometheus_enabled??!1,onChange:e=>Gn(`prometheus_enabled`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),A.prometheus_enabled&&(0,K.jsxs)(`div`,{className:`space-y-3 pt-2 border-t border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.bearerTokenOptional`)}),(0,K.jsx)(`input`,{type:`password`,value:A.prometheus_token??``,onChange:e=>Gn(`prometheus_token`,e.target.value),placeholder:i(`settings.leaveEmptyForNoAuth`),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.bearerTokenHint`)})]}),(0,K.jsxs)(`div`,{className:`pt-2 border-t border-bambu-dark-tertiary`,children:[(0,K.jsx)(`p`,{className:`text-sm text-white mb-2`,children:i(`settings.availableMetrics`)}),(0,K.jsxs)(`div`,{className:`text-xs text-bambu-gray space-y-1`,children:[(0,K.jsxs)(`p`,{children:[(0,K.jsx)(`code`,{className:`text-orange-700 dark:text-orange-400`,children:`bambuddy_printer_connected`}),` - `,i(`settings.metricsConnectionStatus`)]}),(0,K.jsxs)(`p`,{children:[(0,K.jsx)(`code`,{className:`text-orange-700 dark:text-orange-400`,children:`bambuddy_printer_state`}),` - `,i(`settings.metricsPrinterState`)]}),(0,K.jsxs)(`p`,{children:[(0,K.jsx)(`code`,{className:`text-orange-700 dark:text-orange-400`,children:`bambuddy_print_progress`}),` - `,i(`settings.metricsPrintProgress`)]}),(0,K.jsxs)(`p`,{children:[(0,K.jsx)(`code`,{className:`text-orange-700 dark:text-orange-400`,children:`bambuddy_bed_temp_celsius`}),` - `,i(`settings.metricsBedTemp`)]}),(0,K.jsxs)(`p`,{children:[(0,K.jsx)(`code`,{className:`text-orange-700 dark:text-orange-400`,children:`bambuddy_nozzle_temp_celsius`}),` - `,i(`settings.metricsNozzleTemp`)]}),(0,K.jsxs)(`p`,{children:[(0,K.jsx)(`code`,{className:`text-orange-700 dark:text-orange-400`,children:`bambuddy_prints_total`}),` - `,i(`settings.metricsPrintsTotal`)]}),(0,K.jsx)(`p`,{className:`text-bambu-gray/70 italic`,children:i(`settings.metricsMore`)})]})]})]})]})]})})]}),mt&&(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/50 flex items-center justify-center z-50`,children:(0,K.jsxs)(`div`,{className:`bg-bambu-dark-secondary rounded-lg p-6 max-w-md w-full mx-4`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-3 mb-4`,children:[mt.success?(0,K.jsx)(_s,{className:`w-8 h-8 text-green-600 dark:text-green-400`}):(0,K.jsx)(Cs,{className:`w-8 h-8 text-red-600 dark:text-red-400`}),(0,K.jsx)(`h3`,{className:`text-lg font-medium text-white`,children:mt.success?i(`settings.connectionSuccessful`):i(`settings.connectionFailed`)})]}),(0,K.jsx)(`p`,{className:`text-bambu-gray mb-6`,children:mt.success?mt.message||i(`settings.haConnectionSuccess`):mt.error||i(`settings.haConnectionFailed`)}),(0,K.jsx)(`div`,{className:`flex justify-end`,children:(0,K.jsx)($,{variant:`primary`,onClick:()=>ht(null),children:i(`settings.ok`)})})]})}),ue===`plugs`&&(0,K.jsxs)(`div`,{id:`card-plugs`,children:[(0,K.jsxs)(`div`,{className:`flex items-start justify-between mb-6`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(kl,{className:`w-5 h-5 text-bambu-green`}),i(`settings.smartPlugs`)]}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mt-1`,children:i(`settings.smartPlugsDescription`)})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 pt-1 shrink-0`,children:[At&&At.filter(e=>e.enabled).length>1&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)($,{variant:`secondary`,size:`sm`,className:`whitespace-nowrap`,onClick:()=>Le(`on`),disabled:Ln.isPending,title:i(`settings.turnAllPlugsOn`),children:[Ln.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(Ml,{className:`w-4 h-4 text-bambu-green`}),i(`settings.allOn`)]}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,className:`whitespace-nowrap`,onClick:()=>Le(`off`),disabled:Ln.isPending,title:i(`settings.turnAllPlugsOff`),children:[Ln.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(jl,{className:`w-4 h-4 text-red-600 dark:text-red-400`}),i(`settings.allOff`)]})]}),(0,K.jsxs)($,{className:`whitespace-nowrap`,onClick:()=>{L(null),F(!0)},children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),i(`settings.addSmartPlug`)]})]})]}),At&&At.length>0&&(0,K.jsxs)(Od,{className:`mb-6`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-base font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(Zu,{className:`w-4 h-4 text-yellow-600 dark:text-yellow-400`}),i(`settings.energySummary`),Nt&&(0,K.jsx)(X,{className:`w-4 h-4 animate-spin text-bambu-gray ml-2`})]})}),(0,K.jsx)(Ad,{children:Mt?(0,K.jsxs)(`div`,{className:`grid grid-cols-2 md:grid-cols-4 gap-4`,children:[(0,K.jsxs)(`div`,{className:`bg-bambu-dark rounded-lg p-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-bambu-gray text-xs mb-1`,children:[(0,K.jsx)(Zu,{className:`w-3 h-3`}),i(`settings.currentPower`)]}),(0,K.jsxs)(`div`,{className:`text-xl font-bold text-white`,children:[Mt.totalPower.toFixed(1),(0,K.jsx)(`span`,{className:`text-sm font-normal text-bambu-gray ml-1`,children:`W`})]}),(0,K.jsx)(`div`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.plugsOnline`,{reachable:Mt.reachableCount,total:Mt.totalPlugs})})]}),(0,K.jsxs)(`div`,{className:`bg-bambu-dark rounded-lg p-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-bambu-gray text-xs mb-1`,children:[(0,K.jsx)(ts,{className:`w-3 h-3`}),i(`settings.today`)]}),(0,K.jsxs)(`div`,{className:`text-xl font-bold text-white`,children:[Mt.totalToday.toFixed(3),(0,K.jsx)(`span`,{className:`text-sm font-normal text-bambu-gray ml-1`,children:`kWh`})]}),(A?.energy_cost_per_kwh??0)>0&&(0,K.jsxs)(`div`,{className:`text-xs text-bambu-gray mt-1`,children:[`~`,(Mt.totalToday*(A?.energy_cost_per_kwh??0)).toFixed(2),` `,mf(A?.currency||`USD`)]})]}),(0,K.jsxs)(`div`,{className:`bg-bambu-dark rounded-lg p-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-bambu-gray text-xs mb-1`,children:[(0,K.jsx)(Au,{className:`w-3 h-3`}),i(`settings.yesterday`)]}),(0,K.jsxs)(`div`,{className:`text-xl font-bold text-white`,children:[Mt.totalYesterday.toFixed(3),(0,K.jsx)(`span`,{className:`text-sm font-normal text-bambu-gray ml-1`,children:`kWh`})]}),(A?.energy_cost_per_kwh??0)>0&&(0,K.jsxs)(`div`,{className:`text-xs text-bambu-gray mt-1`,children:[`~`,(Mt.totalYesterday*(A?.energy_cost_per_kwh??0)).toFixed(2),` `,mf(A?.currency||`USD`)]})]}),(0,K.jsxs)(`div`,{className:`bg-bambu-dark rounded-lg p-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-bambu-gray text-xs mb-1`,children:[(0,K.jsx)(Us,{className:`w-3 h-3`}),i(`settings.total`)]}),(0,K.jsxs)(`div`,{className:`text-xl font-bold text-white`,children:[Mt.totalLifetime.toFixed(1),(0,K.jsx)(`span`,{className:`text-sm font-normal text-bambu-gray ml-1`,children:`kWh`})]}),(A?.energy_cost_per_kwh??0)>0&&(0,K.jsxs)(`div`,{className:`text-xs text-bambu-gray mt-1`,children:[`~`,(Mt.totalLifetime*(A?.energy_cost_per_kwh??0)).toFixed(2),` `,mf(A?.currency||`USD`)]})]})]}):Nt?null:(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.enablePlugsForSummary`)})})]}),jt?(0,K.jsx)(`div`,{className:`flex justify-center py-12`,children:(0,K.jsx)(X,{className:`w-8 h-8 text-bambu-green animate-spin`})}):At&&At.length>0?(0,K.jsx)(`div`,{className:`grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4`,children:At.map(e=>(0,K.jsx)(GHe,{plug:e,onEdit:e=>{L(e),F(!0)}},e.id))}):(0,K.jsx)(Od,{children:(0,K.jsx)(Ad,{className:`py-12`,children:(0,K.jsxs)(`div`,{className:`text-center text-bambu-gray`,children:[(0,K.jsx)(kl,{className:`w-16 h-16 mx-auto mb-4 opacity-30`}),(0,K.jsx)(`p`,{className:`text-lg font-medium text-white mb-2`,children:i(`settings.noSmartPlugsTitle`)}),(0,K.jsx)(`p`,{className:`text-sm mb-4`,children:i(`settings.noSmartPlugsDescription`)}),(0,K.jsxs)($,{onClick:()=>{L(null),F(!0)},children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),i(`settings.addFirstSmartPlug`)]})]})})})]}),ue===`notifications`&&(0,K.jsxs)(`div`,{className:`grid grid-cols-1 lg:grid-cols-2 gap-4`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between mb-4`,children:[(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2`,id:`card-providers`,children:[(0,K.jsx)(Wo,{className:`w-5 h-5 text-bambu-green`}),i(`settings.providers`)]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsxs)($,{size:`sm`,variant:`secondary`,onClick:()=>oe(!0),children:[(0,K.jsx)(Pc,{className:`w-4 h-4`}),i(`settings.log`)]}),Pt&&Pt.length>0&&(0,K.jsxs)($,{size:`sm`,variant:`secondary`,onClick:()=>{Fn(null),In.mutate()},disabled:In.isPending,children:[In.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(ql,{className:`w-4 h-4`}),i(`settings.testAll`)]}),(0,K.jsxs)($,{size:`sm`,onClick:()=>{V(null),z(!0)},children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),i(`settings.addNotificationProvider`)]})]})]}),(0,K.jsx)(Od,{className:`mb-4`,children:(0,K.jsx)(Ad,{className:`py-3`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white text-sm font-medium`,children:i(`settings.notificationLanguage`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.notificationLanguageDescription`)})]}),(0,K.jsx)(`select`,{value:A.notification_language||`en`,onChange:e=>Gn(`notification_language`,e.target.value),className:`px-2 py-1.5 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-sm focus:outline-none focus:ring-1 focus:ring-bambu-green`,children:Ot.map(e=>(0,K.jsx)(`option`,{value:e.code,children:e.nativeName},e.code))})]})})}),(0,K.jsx)(Od,{className:`mb-4`,children:(0,K.jsx)(Ad,{className:`py-3`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white text-sm font-medium`,children:i(`settings.bedCooledThreshold`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.bedCooledThresholdDescription`)})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,K.jsx)(`input`,{type:`number`,min:20,max:80,step:1,value:A.bed_cooled_threshold??35,onChange:e=>Gn(`bed_cooled_threshold`,Number(e.target.value)),className:`w-16 px-2 py-1.5 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-sm text-center focus:outline-none focus:ring-1 focus:ring-bambu-green`}),(0,K.jsx)(`span`,{className:`text-sm text-bambu-gray`,children:`°C`})]})]})})}),(0,K.jsx)(Od,{className:`mb-4`,children:(0,K.jsx)(Ad,{className:`py-3`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between ${hn?.advanced_auth_enabled?``:`opacity-50`}`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white text-sm font-medium`,children:i(`settings.userNotificationsEnabled`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:hn?.advanced_auth_enabled?i(`settings.userNotificationsEnabledDescription`):i(`settings.userNotificationsDisabledHint`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,className:`sr-only peer`,checked:A.user_notifications_enabled??!0,disabled:!hn?.advanced_auth_enabled,onChange:e=>Gn(`user_notifications_enabled`,e.target.checked)}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green peer-disabled:cursor-not-allowed`})]})]})})}),Pn&&(0,K.jsx)(Od,{className:`mb-4`,children:(0,K.jsxs)(Ad,{className:`py-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between mb-2`,children:[(0,K.jsx)(`span`,{className:`text-sm font-medium text-white`,children:i(`settings.testResults`)}),(0,K.jsx)(`button`,{onClick:()=>Fn(null),className:`text-bambu-gray hover:text-white text-xs`,children:i(`common.dismiss`)})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-4 text-sm mb-2`,children:[(0,K.jsxs)(`span`,{className:`flex items-center gap-1 text-bambu-green`,children:[(0,K.jsx)(_s,{className:`w-4 h-4`}),i(`settings.testPassedCount`,{count:Pn.success})]}),Pn.failed>0&&(0,K.jsxs)(`span`,{className:`flex items-center gap-1 text-red-700 dark:text-red-400`,children:[(0,K.jsx)(Cs,{className:`w-4 h-4`}),i(`settings.testFailedCount`,{count:Pn.failed})]})]}),Pn.results.filter(e=>!e.success).length>0&&(0,K.jsx)(`div`,{className:`space-y-1 mt-2 pt-2 border-t border-bambu-dark-tertiary`,children:Pn.results.filter(e=>!e.success).map(e=>(0,K.jsxs)(`div`,{className:`text-xs text-red-700 dark:text-red-400`,children:[(0,K.jsxs)(`span`,{className:`font-medium`,children:[e.provider_name,`:`]}),` `,e.message]},e.provider_id))})]})}),Ft?(0,K.jsx)(`div`,{className:`flex justify-center py-12`,children:(0,K.jsx)(X,{className:`w-6 h-6 text-bambu-green animate-spin`})}):Pt&&Pt.length>0?(0,K.jsx)(`div`,{className:`space-y-3`,children:Pt.map(e=>(0,K.jsx)(qHe,{provider:e,onEdit:e=>{V(e),z(!0)}},e.id))}):(0,K.jsx)(Od,{children:(0,K.jsx)(Ad,{className:`py-8`,children:(0,K.jsxs)(`div`,{className:`text-center text-bambu-gray`,children:[(0,K.jsx)(Wo,{className:`w-12 h-12 mx-auto mb-3 opacity-30`}),(0,K.jsx)(`p`,{className:`text-sm font-medium text-white mb-2`,children:i(`settings.noProvidersTitle`)}),(0,K.jsx)(`p`,{className:`text-xs mb-3`,children:i(`settings.noProvidersDescription`)}),(0,K.jsxs)($,{size:`sm`,onClick:()=>{V(null),z(!0)},children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),i(`settings.addProvider`)]})]})})})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2 mb-2`,id:`card-templates`,children:[(0,K.jsx)(sc,{className:`w-5 h-5 text-bambu-green`}),i(`settings.messageTemplates`)]}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mb-3`,children:i(`settings.messageTemplatesDescription`)}),(0,K.jsxs)(`div`,{className:`relative mb-3`,children:[(0,K.jsx)(Kl,{className:`w-4 h-4 text-bambu-gray absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none`}),(0,K.jsx)(`input`,{type:`text`,value:ne,onChange:e=>re(e.target.value),placeholder:i(`settings.filterTemplates`,`Filter templates…`),className:`w-full pl-9 pr-8 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-sm focus:outline-none focus:border-bambu-green`}),ne&&(0,K.jsx)(`button`,{onClick:()=>re(``),className:`absolute right-2 top-1/2 -translate-y-1/2 p-1 text-bambu-gray hover:text-white`,"aria-label":`Clear filter`,children:(0,K.jsx)(Yu,{className:`w-3.5 h-3.5`})})]}),Ht?(0,K.jsx)(`div`,{className:`flex justify-center py-8`,children:(0,K.jsx)(X,{className:`w-6 h-6 text-bambu-green animate-spin`})}):Vt&&Vt.length>0?(()=>{let e=ne.trim().toLowerCase(),t=[...Vt].sort((e,t)=>e.name.localeCompare(t.name)).filter(t=>!e||t.name.toLowerCase().includes(e)||(t.title_template||``).toLowerCase().includes(e));return t.length===0?(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray italic text-center py-6`,children:i(`settings.noTemplatesMatch`,`No templates match your filter.`)}):(0,K.jsx)(`div`,{className:`space-y-2`,children:t.map(e=>(0,K.jsx)(Od,{className:`cursor-pointer hover:border-bambu-green/50 transition-colors`,onClick:()=>te(e),children:(0,K.jsx)(Ad,{className:`py-2.5 px-3`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsx)(`p`,{className:`text-white font-medium text-sm truncate`,children:e.name}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-xs truncate mt-0.5`,children:e.title_template})]}),(0,K.jsx)(`button`,{className:`p-1.5 hover:bg-bambu-dark-tertiary rounded transition-colors shrink-0 ml-2`,onClick:t=>{t.stopPropagation(),te(e)},children:(0,K.jsx)(Tl,{className:`w-4 h-4 text-bambu-gray`})})]})})},e.id))})})():(0,K.jsx)(Od,{children:(0,K.jsx)(Ad,{className:`py-8`,children:(0,K.jsxs)(`div`,{className:`text-center text-bambu-gray`,children:[(0,K.jsx)(sc,{className:`w-12 h-12 mx-auto mb-3 opacity-30`}),(0,K.jsx)(`p`,{className:`text-sm`,children:i(`settings.noTemplatesAvailable`)})]})})})]})]}),ue===`apikeys`&&(0,K.jsxs)(`div`,{className:d(`api_keys:read`)?`grid grid-cols-1 xl:grid-cols-2 gap-4`:`grid grid-cols-1 gap-4`,children:[(0,K.jsxs)(`div`,{children:[d(`api_keys:read`)&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{className:`flex items-start justify-between gap-4 mb-6`,children:[(0,K.jsxs)(`div`,{className:`flex-1`,children:[(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2`,id:`card-createapi`,children:[(0,K.jsx)(Vc,{className:`w-5 h-5 text-bambu-green`}),i(`settings.apiKeys`)]}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mt-1`,children:i(`settings.apiKeysDescription`)})]}),(0,K.jsxs)($,{size:`sm`,onClick:()=>ye(!0),className:`flex-shrink-0`,children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),i(`settings.createKey`)]})]}),we&&(0,K.jsx)(Od,{className:`mb-6 border-bambu-green`,children:(0,K.jsx)(Ad,{className:`py-4`,children:(0,K.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,K.jsx)(_s,{className:`w-5 h-5 text-bambu-green flex-shrink-0 mt-0.5`}),(0,K.jsxs)(`div`,{className:`flex-1`,children:[(0,K.jsx)(`p`,{className:`text-white font-medium mb-1`,children:i(`settings.apiKeyCreated`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mb-2`,children:i(`settings.apiKeyCopyWarning`)}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 bg-bambu-dark rounded-lg p-2`,children:[(0,K.jsx)(`code`,{className:`flex-1 text-sm text-bambu-green font-mono break-all`,children:we}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:async()=>{try{if(navigator.clipboard&&navigator.clipboard.writeText)await navigator.clipboard.writeText(we);else{let e=document.createElement(`textarea`);e.value=we,e.style.position=`fixed`,e.style.left=`-999999px`,document.body.appendChild(e),e.select(),document.execCommand(`copy`),document.body.removeChild(e)}o(i(`settings.toast.keyCopied`))}catch{o(i(`settings.toast.copyFailed`),`error`)}},children:(0,K.jsx)(Ls,{className:`w-4 h-4`})})]}),(0,K.jsxs)(`div`,{className:`flex gap-2 mt-3`,children:[(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>{je(we),o(i(`settings.toast.keyAddedToBrowser`))},children:i(`settings.useInApiBrowser`)}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,onClick:()=>De(!0),children:[(0,K.jsx)(Pl,{className:`w-4 h-4`}),i(`settings.apiKeyQrButton`)]}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>{De(!1),Te(null)},children:i(`common.dismiss`)})]})]})]})})}),Ee&&we&&(0,K.jsx)(uUe,{apiKey:we,baseUrl:A?.external_url||void 0,onClose:()=>De(!1)}),ve&&(0,K.jsxs)(Od,{className:`mb-6`,children:[(0,K.jsx)(kd,{children:(0,K.jsx)(`h3`,{className:`text-base font-semibold text-white`,children:i(`settings.createNewApiKey`)})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.keyName`)}),(0,K.jsx)(`input`,{type:`text`,value:be,onChange:e=>xe(e.target.value),placeholder:i(`settings.keyNamePlaceholder`),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-2`,children:i(`common.permissions`)}),(0,K.jsxs)(`div`,{className:`space-y-2`,children:[(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:Se.can_read_status,onChange:e=>Ce(t=>({...t,can_read_status:e.target.checked})),className:`w-4 h-4 text-bambu-green rounded border-bambu-dark-tertiary bg-bambu-dark focus:ring-bambu-green`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`span`,{className:`text-white`,children:i(`settings.readStatus`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.readStatusDescription`)})]})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:Se.can_queue,onChange:e=>Ce(t=>({...t,can_queue:e.target.checked})),className:`w-4 h-4 text-bambu-green rounded border-bambu-dark-tertiary bg-bambu-dark focus:ring-bambu-green`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`span`,{className:`text-white`,children:i(`settings.manageQueue`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.manageQueueDescription`)})]})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:Se.can_control_printer,onChange:e=>Ce(t=>({...t,can_control_printer:e.target.checked})),className:`w-4 h-4 text-bambu-green rounded border-bambu-dark-tertiary bg-bambu-dark focus:ring-bambu-green`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`span`,{className:`text-white`,children:i(`settings.controlPrinter`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.controlPrinterDescription`)})]})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:Se.can_manage_library,onChange:e=>Ce(t=>({...t,can_manage_library:e.target.checked})),className:`w-4 h-4 text-bambu-green rounded border-bambu-dark-tertiary bg-bambu-dark focus:ring-bambu-green`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`span`,{className:`text-white`,children:i(`settings.manageLibrary`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.manageLibraryDescription`)})]})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:Se.can_manage_inventory,onChange:e=>Ce(t=>({...t,can_manage_inventory:e.target.checked})),className:`w-4 h-4 text-bambu-green rounded border-bambu-dark-tertiary bg-bambu-dark focus:ring-bambu-green`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`span`,{className:`text-white`,children:i(`settings.manageInventory`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.manageInventoryDescription`)})]})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:Se.can_manage_maintenance,onChange:e=>Ce(t=>({...t,can_manage_maintenance:e.target.checked})),className:`w-4 h-4 text-bambu-green rounded border-bambu-dark-tertiary bg-bambu-dark focus:ring-bambu-green`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`span`,{className:`text-white`,children:i(`settings.manageMaintenance`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.manageMaintenanceDescription`)})]})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:Se.can_manage_archives,onChange:e=>Ce(t=>({...t,can_manage_archives:e.target.checked})),className:`w-4 h-4 text-bambu-green rounded border-bambu-dark-tertiary bg-bambu-dark focus:ring-bambu-green`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`span`,{className:`text-white`,children:i(`settings.manageArchives`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.manageArchivesDescription`)})]})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:Se.can_manage_projects,onChange:e=>Ce(t=>({...t,can_manage_projects:e.target.checked})),className:`w-4 h-4 text-bambu-green rounded border-bambu-dark-tertiary bg-bambu-dark focus:ring-bambu-green`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`span`,{className:`text-white`,children:i(`settings.manageProjects`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.manageProjectsDescription`)})]})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:Se.can_access_cloud,onChange:e=>Ce(t=>({...t,can_access_cloud:e.target.checked})),className:`w-4 h-4 text-bambu-green rounded border-bambu-dark-tertiary bg-bambu-dark focus:ring-bambu-green`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`span`,{className:`text-white`,children:i(`settings.cloudAccess`,`Allow cloud access`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.cloudAccessDescription`,`Read Bambu Cloud presets and filaments on your behalf. Requires you to be signed into Bambu Cloud.`)})]})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-3 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:Se.can_update_energy_cost,onChange:e=>Ce(t=>({...t,can_update_energy_cost:e.target.checked})),className:`w-4 h-4 text-bambu-green rounded border-bambu-dark-tertiary bg-bambu-dark focus:ring-bambu-green`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`span`,{className:`text-white`,children:i(`settings.updateEnergyCost`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.updateEnergyCostDescription`)})]})]})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 pt-2`,children:[(0,K.jsxs)($,{onClick:()=>G.mutate({name:be||i(`settings.unnamedKey`),...Se}),disabled:G.isPending,children:[G.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(Al,{className:`w-4 h-4`}),i(`settings.createKey`)]}),(0,K.jsx)($,{variant:`secondary`,onClick:()=>ye(!1),children:i(`common.cancel`)})]})]})]}),Lt?(0,K.jsx)(`div`,{className:`flex justify-center py-12`,children:(0,K.jsx)(X,{className:`w-8 h-8 text-bambu-green animate-spin`})}):It&&It.length>0?(0,K.jsx)(`div`,{className:`space-y-3`,children:It.map(e=>(0,K.jsx)(Od,{children:(0,K.jsx)(Ad,{className:`py-3`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,K.jsx)(Vc,{className:`w-5 h-5 ${e.enabled?`text-bambu-green`:`text-bambu-gray`}`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white font-medium`,children:e.name}),(0,K.jsxs)(`p`,{className:`text-xs text-bambu-gray`,children:[e.key_prefix,`••••••••`,e.last_used&&` · ${i(`settings.lastUsed`)}: ${Ff(e.last_used)}`]})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsxs)(`div`,{className:`flex gap-1 text-xs flex-wrap justify-end`,children:[e.can_read_status&&(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400 rounded`,children:i(`settings.read`)}),e.can_queue&&(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 bg-green-100 dark:bg-green-500/20 text-green-700 dark:text-green-400 rounded`,children:i(`queue.title`)}),e.can_control_printer&&(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 bg-orange-100 dark:bg-orange-500/20 text-orange-700 dark:text-orange-400 rounded`,children:i(`settings.control`)}),e.can_manage_library&&(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 bg-cyan-100 dark:bg-cyan-500/20 text-cyan-700 dark:text-cyan-400 rounded`,children:i(`settings.libraryBadge`)}),e.can_manage_inventory&&(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 bg-pink-100 dark:bg-pink-500/20 text-pink-700 dark:text-pink-400 rounded`,children:i(`settings.inventoryBadge`)}),e.can_manage_maintenance&&(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 bg-teal-100 dark:bg-teal-500/20 text-teal-700 dark:text-teal-400 rounded`,children:i(`settings.maintenanceBadge`)}),e.can_manage_archives&&(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 bg-indigo-100 dark:bg-indigo-500/20 text-indigo-700 dark:text-indigo-400 rounded`,children:i(`settings.archivesBadge`)}),e.can_manage_projects&&(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 bg-lime-100 dark:bg-lime-500/20 text-lime-700 dark:text-lime-400 rounded`,children:i(`settings.projectsBadge`)}),e.can_access_cloud&&(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-400 rounded`,children:i(`settings.cloudBadge`,`Cloud`)}),e.can_update_energy_cost&&(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 bg-amber-100 dark:bg-amber-500/20 text-amber-700 dark:text-amber-400 rounded`,children:i(`settings.energyCostBadge`)}),e.user_id===null&&(0,K.jsx)(`span`,{className:`px-1.5 py-0.5 bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400 rounded`,title:i(`settings.legacyKeyTooltip`,`Created before per-user ownership; recreate to use cloud access`),children:i(`settings.legacyKey`,`Legacy`)})]}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>ke(e.id),children:(0,K.jsx)(Ou,{className:`w-4 h-4 text-red-600 dark:text-red-400`})})]})]})})},e.id))}):(0,K.jsx)(Od,{children:(0,K.jsx)(Ad,{className:`py-12`,children:(0,K.jsxs)(`div`,{className:`text-center text-bambu-gray`,children:[(0,K.jsx)(Vc,{className:`w-16 h-16 mx-auto mb-4 opacity-30`}),(0,K.jsx)(`p`,{className:`text-lg font-medium text-white mb-2`,children:i(`settings.apiKeysEmptyTitle`)}),(0,K.jsx)(`p`,{className:`text-sm mb-4`,children:i(`settings.apiKeysEmptyDescription`)}),(0,K.jsxs)($,{onClick:()=>ye(!0),children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),i(`settings.createFirstKey`)]})]})})}),(0,K.jsxs)(Od,{className:`mt-6`,children:[(0,K.jsx)(kd,{children:(0,K.jsx)(`h3`,{className:`text-base font-semibold text-white`,id:`card-webhooks`,children:i(`settings.webhookEndpoints`)})}),(0,K.jsxs)(Ad,{className:`space-y-3 text-sm`,children:[(0,K.jsx)(`p`,{className:`text-bambu-gray`,children:i(`settings.webhookApiKeyHint`)}),(0,K.jsxs)(`div`,{className:`space-y-2 font-mono text-xs`,children:[(0,K.jsxs)(`div`,{className:`p-2 bg-bambu-dark rounded`,children:[(0,K.jsx)(`span`,{className:`text-blue-700 dark:text-blue-400`,children:`GET`}),` `,(0,K.jsx)(`span`,{className:`text-white`,children:`/api/v1/webhook/status`}),(0,K.jsxs)(`span`,{className:`text-bambu-gray`,children:[` - `,i(`settings.webhook.getAllStatus`)]})]}),(0,K.jsxs)(`div`,{className:`p-2 bg-bambu-dark rounded`,children:[(0,K.jsx)(`span`,{className:`text-blue-700 dark:text-blue-400`,children:`GET`}),` `,(0,K.jsx)(`span`,{className:`text-white`,children:`/api/v1/webhook/status/:id`}),(0,K.jsxs)(`span`,{className:`text-bambu-gray`,children:[` - `,i(`settings.webhook.getSpecificStatus`)]})]}),(0,K.jsxs)(`div`,{className:`p-2 bg-bambu-dark rounded`,children:[(0,K.jsx)(`span`,{className:`text-green-700 dark:text-green-400`,children:`POST`}),` `,(0,K.jsx)(`span`,{className:`text-white`,children:`/api/v1/webhook/queue`}),(0,K.jsxs)(`span`,{className:`text-bambu-gray`,children:[` - `,i(`settings.webhook.addToQueue`)]})]}),(0,K.jsxs)(`div`,{className:`p-2 bg-bambu-dark rounded`,children:[(0,K.jsx)(`span`,{className:`text-orange-700 dark:text-orange-400`,children:`POST`}),` `,(0,K.jsx)(`span`,{className:`text-white`,children:`/api/v1/webhook/printer/:id/pause`}),(0,K.jsxs)(`span`,{className:`text-bambu-gray`,children:[` - `,i(`settings.webhook.pausePrint`)]})]}),(0,K.jsxs)(`div`,{className:`p-2 bg-bambu-dark rounded`,children:[(0,K.jsx)(`span`,{className:`text-orange-700 dark:text-orange-400`,children:`POST`}),` `,(0,K.jsx)(`span`,{className:`text-white`,children:`/api/v1/webhook/printer/:id/resume`}),(0,K.jsxs)(`span`,{className:`text-bambu-gray`,children:[` - `,i(`settings.webhook.resumePrint`)]})]}),(0,K.jsxs)(`div`,{className:`p-2 bg-bambu-dark rounded`,children:[(0,K.jsx)(`span`,{className:`text-red-700 dark:text-red-400`,children:`POST`}),` `,(0,K.jsx)(`span`,{className:`text-white`,children:`/api/v1/webhook/printer/:id/stop`}),(0,K.jsxs)(`span`,{className:`text-bambu-gray`,children:[` - `,i(`settings.webhook.stopPrint`)]})]})]})]})]})]}),(0,K.jsxs)(Od,{className:`mt-6`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-base font-semibold text-white flex items-center gap-2`,id:`card-camera-tokens`,children:[(0,K.jsx)(zu,{className:`w-4 h-4 text-bambu-green`}),i(`cameraTokens.title`,`Camera API Tokens`)]})}),(0,K.jsx)(Ad,{children:(0,K.jsx)(WHe,{})})]})]}),d(`api_keys:read`)&&(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`div`,{className:`mb-6`,children:[(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white flex items-center gap-2`,id:`card-apibrowser`,children:[(0,K.jsx)(Tc,{className:`w-5 h-5 text-bambu-green`}),i(`settings.apiBrowser`)]}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mt-1`,children:i(`settings.apiBrowserDescription`)})]}),(0,K.jsx)(Od,{className:`mb-4`,children:(0,K.jsxs)(Ad,{className:`py-3`,children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-2`,children:i(`settings.apiKeyForTesting`)}),(0,K.jsx)(`input`,{type:`text`,value:Ae,onChange:e=>je(e.target.value),placeholder:i(`settings.apiKeyPlaceholder`),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white font-mono text-sm focus:border-bambu-green focus:outline-none`}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-2`,children:i(`settings.apiKeyHint`)})]})}),(0,K.jsx)(nWe,{apiKey:Ae})]})]}),ue===`virtual-printer`&&(0,K.jsx)(`div`,{id:`card-vp`,children:(0,K.jsx)(NUe,{})}),ue===`spoolbuddy`&&(0,K.jsx)(`div`,{id:`card-spoolbuddy`,children:(0,K.jsx)(FUe,{})}),ue===`queue`&&(0,K.jsxs)(`div`,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{className:`flex gap-1 border-b border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`button`,{onClick:()=>_e(`dispatch`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px flex items-center gap-2 ${me===`dispatch`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Jc,{className:`w-4 h-4`}),i(`settings.tabs.queueDispatch`,`Queue & Dispatch`)]}),(0,K.jsxs)(`button`,{onClick:()=>_e(`pipelines`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px flex items-center gap-2 ${me===`pipelines`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(qu,{className:`w-4 h-4`}),i(`settings.tabs.queuePipelines`,`Pipelines`)]})]}),me===`pipelines`&&(0,K.jsx)(IHe,{}),me===`dispatch`&&A&&(0,K.jsxs)(`div`,{className:`flex flex-col lg:flex-row gap-4 lg:gap-6`,children:[(0,K.jsxs)(`div`,{className:`lg:w-1/2 space-y-3`,children:[(0,K.jsxs)(Od,{id:`card-print-options`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-base font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(Jc,{className:`w-4 h-4 text-bambu-green`}),i(`settings.defaultPrintOptions`,`Default Print Options`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.defaultPrintOptionsDescription`,`Set default values for print options when starting new prints. These can be overridden per print in the print dialog.`)}),[{key:`default_bed_levelling`,label:i(`settings.defaultBedLevelling`,`Bed Levelling`),desc:i(`settings.defaultBedLevellingDesc`,`Auto-level bed before print`),fallback:!0,dualNozzleOnly:!1,tristate:!0},{key:`default_flow_cali`,label:i(`settings.defaultFlowCali`,`Flow Calibration`),desc:i(`settings.defaultFlowCaliDesc`,`Calibrate extrusion flow`),fallback:!1,dualNozzleOnly:!1,tristate:!0},{key:`default_vibration_cali`,label:i(`settings.defaultVibrationCali`,`Vibration Calibration`),desc:i(`settings.defaultVibrationCaliDesc`,`Reduce ringing artifacts`),fallback:!0,dualNozzleOnly:!1,tristate:!1},{key:`default_layer_inspect`,label:i(`settings.defaultLayerInspect`,`First Layer Inspection`),desc:i(`settings.defaultLayerInspectDesc`,`AI inspection of first layer`),fallback:!1,dualNozzleOnly:!1,tristate:!1},{key:`default_timelapse`,label:i(`settings.defaultTimelapse`,`Timelapse`),desc:i(`settings.defaultTimelapseDesc`,`Record timelapse video`),fallback:!1,dualNozzleOnly:!1,tristate:!1},{key:`default_nozzle_offset_cali`,label:i(`settings.defaultNozzleOffsetCali`,`Nozzle Offset Calibration`),desc:i(`settings.defaultNozzleOffsetCaliDesc`,`Calibrate nozzle offsets between extruders`),fallback:!0,dualNozzleOnly:!0,tristate:!0}].filter(({dualNozzleOnly:e})=>!e||(zt||[]).some(e=>e.nozzle_count===2)).map(({key:e,label:t,desc:n,fallback:r,tristate:a})=>(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex-1 mr-4`,children:[(0,K.jsx)(`p`,{className:`text-sm text-white`,children:t}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-0.5`,children:n})]}),a?(0,K.jsx)(`div`,{className:`flex gap-1 shrink-0`,children:uW.map(t=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>Gn(e,t),className:`px-2.5 py-1 text-xs rounded transition-colors ${(A[e]??`auto`)===t?dW[t]:`bg-bambu-dark-tertiary text-bambu-gray hover:text-white`}`,children:i(`settings.calibrationMode_${t}`)},t))}):(0,K.jsx)(`div`,{className:`flex gap-1 shrink-0`,children:[`off`,`on`].map(t=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>Gn(e,t===`on`),className:`px-2.5 py-1 text-xs rounded transition-colors ${(A[e]??r?`on`:`off`)===t?dW[t]:`bg-bambu-dark-tertiary text-bambu-gray hover:text-white`}`,children:i(`settings.calibrationMode_${t}`)},t))})]},e))]})]}),(0,K.jsxs)(Od,{id:`card-plate`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-base font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(tu,{className:`w-4 h-4 text-bambu-green`}),i(`settings.plateClear`,`Plate-Clear Confirmation`)]})}),(0,K.jsx)(Ad,{className:`space-y-3`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex-1 mr-4`,children:[(0,K.jsx)(`p`,{className:`text-sm text-white`,children:i(`settings.requirePlateClear`,`Require plate-clear confirmation`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.requirePlateClearDescription`,`When enabled, the scheduler waits for per-printer plate-clear confirmation before starting queued prints on printers with finished jobs. Disabling this also hides the plate status badge and the "Mark plate as cleared" button on printer cards.`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.require_plate_clear??!1,onChange:e=>Gn(`require_plate_clear`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]})})]}),(0,K.jsxs)(Od,{id:`card-temp-fan-presets`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-base font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(Eu,{className:`w-4 h-4 text-bambu-green`}),i(`settings.tempFanPresetsTitle`,`Temperature & Fan Presets`)]})}),(0,K.jsxs)(Ad,{className:`space-y-4`,children:[(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.tempFanPresetsDescription`,`Customize the quick-select values shown in printer-card temperature and fan-speed popovers. The Off button is always shown.`)}),oee.map(e=>{let t=Zp(A?.[e.key]??``,e.defaults,e.lo,e.hi),n=e.unit===`C`?`°C`:`%`;return(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between mb-1`,children:[(0,K.jsxs)(`label`,{className:`text-sm text-white`,children:[i(`settings.${{nozzle_temp_presets:`tempFanPresetsNozzle`,bed_temp_presets:`tempFanPresetsBed`,chamber_temp_presets:`tempFanPresetsChamber`,fan_speed_presets:`tempFanPresetsFan`}[e.key]}`,{nozzle_temp_presets:`Nozzle temperature`,bed_temp_presets:`Bed temperature`,chamber_temp_presets:`Chamber temperature`,fan_speed_presets:`Fan speed`}[e.key]),` `,(0,K.jsxs)(`span`,{className:`text-bambu-gray text-xs`,children:[`(`,n,` · `,e.lo,`–`,e.hi,`)`]})]}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>Gn(e.key,``),title:i(`settings.tempFanPresetsReset`,`Reset to defaults`),className:`text-bambu-gray hover:text-white transition-colors p-1 rounded hover:bg-bambu-dark-tertiary`,children:(0,K.jsx)(Rl,{className:`w-3.5 h-3.5`})})]}),(0,K.jsx)(`div`,{className:`flex gap-2`,children:[0,1,2].map(n=>(0,K.jsx)(`input`,{type:`number`,min:e.lo,max:e.hi,value:t[n],onChange:r=>{let i=[t[0],t[1],t[2]],a=parseInt(r.target.value,10);i[n]=Math.max(e.lo,Math.min(e.hi,Number.isFinite(a)?a:e.lo)),Gn(e.key,JSON.stringify(i))},className:`flex-1 px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-sm focus:outline-none focus:border-bambu-green`},n))})]},e.key)})]})]}),(0,K.jsxs)(Od,{id:`card-staggered`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-base font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(Uc,{className:`w-4 h-4 text-bambu-green`}),i(`settings.staggeredStart`,`Staggered Start`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.staggeredStartDescription`,`Default group size and interval when staggering multi-printer batch starts. Can be overridden per batch in the print modal.`)}),(0,K.jsxs)(`div`,{className:`flex gap-4`,children:[(0,K.jsxs)(`div`,{className:`flex-1`,children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.staggerGroupSize`,`Group size`)}),(0,K.jsx)(`input`,{type:`number`,min:1,max:50,value:A.stagger_group_size??2,onChange:e=>Gn(`stagger_group_size`,Math.max(1,Math.min(50,parseInt(e.target.value)||1))),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-sm focus:outline-none focus:border-bambu-green`}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.staggerGroupSizeHelp`,`Printers to start simultaneously per group`)})]}),(0,K.jsxs)(`div`,{className:`flex-1`,children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.staggerInterval`,`Interval (minutes)`)}),(0,K.jsx)(`input`,{type:`number`,min:1,max:60,value:A.stagger_interval_minutes??5,onChange:e=>Gn(`stagger_interval_minutes`,Math.max(1,Math.min(60,parseInt(e.target.value)||1))),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-sm focus:outline-none focus:border-bambu-green`}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.staggerIntervalHelp`,`Delay between each group starting`)})]})]})]})]}),(0,K.jsxs)(Od,{id:`card-concurrent-uploads`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-base font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(Os,{className:`w-4 h-4 text-bambu-green`}),i(`settings.concurrentUploadsTitle`,`Concurrent Uploads`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.concurrentUploadsDescription`,`How many printers the queue may send files to at the same time. Printers receive files slowly (a large print can take several minutes), and each one waits its turn — so on a bigger fleet, raising this is what stops the last printer in a batch from waiting out every transfer before it. Lower it if your network or Bambuddy host struggles with parallel transfers.`)}),(0,K.jsxs)(`div`,{className:`w-full sm:w-1/2`,children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.concurrentUploadsLabel`,`Printers uploaded to at once`)}),(0,K.jsx)(`input`,{type:`number`,min:1,max:16,value:A.queue_max_concurrent_uploads??4,onChange:e=>Gn(`queue_max_concurrent_uploads`,Math.max(1,Math.min(16,parseInt(e.target.value)||1))),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-sm focus:outline-none focus:border-bambu-green`}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.concurrentUploadsHelp`,`1 sends to one printer at a time (the old behaviour). Default is 4.`)})]})]})]}),(0,K.jsxs)(Od,{id:`card-preheat`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-base font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(uc,{className:`w-4 h-4 text-amber-600 dark:text-amber-400`}),i(`settings.preheatTitle`,`Preheat & Heat Soak`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.preheatDescription`,`Heat the bed (and chamber, if supported) and hold at temperature before each queued print starts. Helpful for engineering filaments (PA, ABS) on printers without an active chamber heater — the bed warms the chamber by radiation while the soak timer runs. The bed target is read from the print file; chamber behaviour depends on printer model.`)}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex-1 mr-4`,children:[(0,K.jsx)(`p`,{className:`text-sm text-white`,children:i(`settings.preheatEnabled`,`Enable preheat & soak`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-0.5`,children:i(`settings.preheatEnabledDesc`,`When off, queued prints dispatch immediately.`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.preheat_enabled??!1,onChange:e=>Gn(`preheat_enabled`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),(0,K.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 gap-3 pt-1`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.preheatMaxWait`,`Max wait (seconds)`)}),(0,K.jsx)(`input`,{type:`number`,min:60,max:3600,value:A.preheat_max_wait_seconds??900,onChange:e=>Gn(`preheat_max_wait_seconds`,Math.max(60,Math.min(3600,parseInt(e.target.value)||900))),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-sm focus:outline-none focus:border-bambu-green disabled:opacity-50`,disabled:!(A.preheat_enabled??!1)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.preheatMaxWaitHelp`,`Cap on the chamber warm-up phase before falling through.`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.preheatSoak`,`Soak (seconds)`)}),(0,K.jsx)(`input`,{type:`number`,min:0,max:1800,value:A.preheat_soak_seconds??300,onChange:e=>Gn(`preheat_soak_seconds`,Math.max(0,Math.min(1800,parseInt(e.target.value)||0))),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-sm focus:outline-none focus:border-bambu-green disabled:opacity-50`,disabled:!(A.preheat_enabled??!1)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.preheatSoakHelp`,`Hold time after target reached or max-wait elapsed.`)})]})]}),(0,K.jsxs)(`div`,{className:`pt-2 border-t border-bambu-dark-tertiary/50`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between mb-1`,children:[(0,K.jsx)(`label`,{className:`text-sm text-white`,children:i(`settings.preheatFilamentTargetsLabel`,`Per-filament chamber target (°C)`)}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>Gn(`preheat_filament_targets`,``),title:i(`settings.preheatFilamentTargetsReset`,`Reset to defaults`),className:`text-bambu-gray hover:text-white transition-colors p-1 rounded hover:bg-bambu-dark-tertiary`,children:(0,K.jsx)(Rl,{className:`w-3.5 h-3.5`})})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mb-2`,children:i(`settings.preheatFilamentTargetsHint`,`Bambuddy picks the highest target across the loaded AMS slots; PLA-only prints derive 0 and skip the chamber phase automatically.`)}),(0,K.jsx)(NHe,{value:A.preheat_filament_targets??``,onChange:e=>Gn(`preheat_filament_targets`,e),disabled:!(A.preheat_enabled??!1)})]}),(0,K.jsxs)(`p`,{className:`text-xs text-bambu-gray pt-1 border-t border-bambu-dark-tertiary/50`,children:[(0,K.jsx)(`span`,{className:`font-medium text-bambu-gray/90`,children:i(`settings.preheatHardwareTitle`,`Per-printer behaviour:`)}),` `,i(`settings.preheatHardwareDetail`,`H2C/H2D/H2D Pro/H2S/X2D/X1E actively heat the chamber via M141. X1C/P2S read chamber temp but rely on bed-radiation heating. P1S/P1P/A1/A1 Mini have no chamber sensor — only the soak timer applies.`)]})]})]}),(0,K.jsxs)(Od,{id:`card-gcode`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-base font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(js,{className:`w-4 h-4 text-bambu-green`}),i(`settings.gcodeInjection`,`G-code Injection`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`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.`)}),(()=>{let e=(()=>{try{return A.gcode_snippets?JSON.parse(A.gcode_snippets):{}}catch{return{}}})(),t=[...new Set((zt||[]).filter(e=>e.model).map(e=>e.model))].sort(),n=(t,n,r)=>{let i={...e};i[t]||(i[t]={start_gcode:``,end_gcode:``}),i[t][n]=r,!i[t].start_gcode&&!i[t].end_gcode&&delete i[t];let a=Object.keys(i).length>0?JSON.stringify(i):``;j(e=>e?{...e,gcode_snippets:a}:null),zn.current=a},r=()=>{zn.current!==null&&(Un.mutate({gcode_snippets:zn.current}),zn.current=null)};return t.length===0?(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray italic`,children:i(`settings.gcodeInjectionNoPrinters`,`No printers found. Add printers to configure G-code snippets.`)}):t.map(t=>{let a=e[t]||{start_gcode:``,end_gcode:``},o=!!(a.start_gcode||a.end_gcode);return(0,K.jsx)(Op,{defaultOpen:o,className:`border border-bambu-dark-tertiary rounded-lg px-3 py-2`,summary:(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`h4`,{className:`text-sm font-medium text-white`,children:t}),o&&(0,K.jsx)(`span`,{className:`text-xs px-1.5 py-0.5 rounded bg-bambu-green/20 text-bambu-green`,children:i(`settings.gcodeConfigured`,`Configured`)})]}),children:(0,K.jsxs)(`div`,{className:`space-y-2`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.gcodeStartLabel`,`Start G-code`)}),(0,K.jsx)(`textarea`,{value:a.start_gcode,onChange:e=>n(t,`start_gcode`,e.target.value),onBlur:r,placeholder:i(`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`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-xs text-bambu-gray mb-1`,children:i(`settings.gcodeEndLabel`,`End G-code`)}),(0,K.jsx)(`textarea`,{value:a.end_gcode,onChange:e=>n(t,`end_gcode`,e.target.value),onBlur:r,placeholder:i(`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`})]})]})},t)})})()]})]})]}),(0,K.jsxs)(`div`,{className:`lg:w-1/2 space-y-3`,children:[(0,K.jsxs)(Od,{id:`card-pipelines`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-base font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(qu,{className:`w-4 h-4 text-bambu-green`}),i(`settings.pipelineLimits.title`,`Slicer Pipeline limits`)]})}),(0,K.jsx)(Ad,{className:`space-y-2`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,K.jsxs)(`div`,{className:`flex-1`,children:[(0,K.jsx)(`p`,{className:`text-sm text-white`,children:i(`settings.pipelineLimits.maxCopiesLabel`,`Max copies per run`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-0.5`,children:i(`settings.pipelineLimits.maxCopiesDesc`,`Upper bound on the copies operators can request when running a pipeline. Server-side hard cap is 1000.`)})]}),(0,K.jsx)(`input`,{type:`number`,min:1,max:1e3,value:A.pipeline_max_copies??50,onChange:e=>{let t=parseInt(e.target.value,10);Number.isNaN(t)||Gn(`pipeline_max_copies`,Math.max(1,Math.min(1e3,t)))},"aria-label":i(`settings.pipelineLimits.maxCopiesLabel`,`Max copies per run`),className:`w-24 px-2 py-1 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-sm`})]})})]}),(0,K.jsxs)(Od,{id:`card-slicer`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-base font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(Ps,{className:`w-4 h-4 text-bambu-green`}),i(`settings.slicerCard`,`Slicer`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.preferredSlicer`)}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsxs)(`select`,{value:A.preferred_slicer??`bambu_studio`,onChange:e=>Gn(`preferred_slicer`,e.target.value),className:`w-full px-3 py-2 pr-10 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none appearance-none cursor-pointer`,children:[(0,K.jsx)(`option`,{value:`bambu_studio`,children:i(`settings.slicerBambuStudio`)}),(0,K.jsx)(`option`,{value:`orcaslicer`,children:i(`settings.slicerOrcaSlicer`)})]}),(0,K.jsx)(ls,{className:`absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray pointer-events-none`})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.preferredSlicerDescription`)}),(A.preferred_slicer??`bambu_studio`)===`orcaslicer`&&(0,K.jsx)(`div`,{role:`alert`,className:`text-xs text-amber-800 dark:text-amber-200 bg-amber-50 dark:bg-amber-900/20 border border-amber-300 dark:border-amber-700/40 rounded p-2 mt-2`,children:i(`settings.orcaslicerKnownIssuesWarning`,`OrcaSlicer 2.3.2 / 2.4.0-dev have known CLI bugs that block slicing many Bambu-authored 3MFs — see upstream issues #12426 (segfault on painted multi-extruder files) and #13386 (parameter-range strict-validation reject). Bambu Studio is recommended until the upstream fixes land.`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.openInSlicerLabel`,`Open in Slicer`)}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsxs)(`select`,{value:A.open_in_slicer??``,onChange:e=>Gn(`open_in_slicer`,e.target.value===``?null:e.target.value),className:`w-full px-3 py-2 pr-10 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none appearance-none cursor-pointer`,children:[(0,K.jsx)(`option`,{value:``,children:i(`settings.openInSlicerInherit`,`Same as API slicer`)}),(0,K.jsx)(`option`,{value:`bambu_studio`,children:i(`settings.slicerBambuStudio`)}),(0,K.jsx)(`option`,{value:`orcaslicer`,children:i(`settings.slicerOrcaSlicer`)})]}),(0,K.jsx)(ls,{className:`absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray pointer-events-none`})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.openInSlicerDescription`,`Desktop slicer used by the 'Open in Slicer' button. Leave on 'Same as API slicer' to inherit, or pick a different slicer to use locally.`)})]}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,K.jsxs)(`div`,{className:`min-w-0`,children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.useSlicerApi`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.useSlicerApiDescription`)})]}),(0,K.jsxs)(`label`,{className:`flex items-center cursor-pointer shrink-0`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.use_slicer_api??!1,onChange:e=>Gn(`use_slicer_api`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`relative w-11 h-6 bg-bambu-dark-tertiary rounded-full peer peer-checked:bg-bambu-green peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-bambu-green/50 transition-colors after:content-[''] after:absolute after:top-0.5 after:left-0.5 after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-transform peer-checked:after:translate-x-5`})]})]}),(A.use_slicer_api??!1)&&(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:(A.preferred_slicer??`bambu_studio`)===`orcaslicer`?i(`settings.orcaslicerApiUrl`,`OrcaSlicer sidecar URL`):i(`settings.bambuStudioApiUrl`,`Bambu Studio sidecar URL`)}),(0,K.jsx)(`input`,{type:`text`,value:((A.preferred_slicer??`bambu_studio`)===`orcaslicer`?A.orcaslicer_api_url:A.bambu_studio_api_url)??``,onChange:e=>Gn((A.preferred_slicer??`bambu_studio`)===`orcaslicer`?`orcaslicer_api_url`:`bambu_studio_api_url`,e.target.value),placeholder:(A.preferred_slicer??`bambu_studio`)===`orcaslicer`?`http://localhost:3003`:`http://localhost:3001`,className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none placeholder:text-bambu-gray/40`}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.slicerApiUrlDescription`,`URL of the slicer-API sidecar container. Leave blank to use the SLICER_API_URL / BAMBU_STUDIO_API_URL env var defaults.`)})]}),(A.use_slicer_api??!1)&&(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.slicerStallTimeout`)}),(0,K.jsx)(`input`,{type:`number`,min:1,max:240,value:A.slicer_stall_timeout_minutes??15,onChange:e=>Gn(`slicer_stall_timeout_minutes`,Number(e.target.value)),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:i(`settings.slicerStallTimeoutDescription`)})]})]})]}),(A.use_slicer_api??!1)&&(0,K.jsx)(PHe,{}),(0,K.jsxs)(Od,{children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-base font-semibold text-white flex items-center gap-2`,id:`card-drying`,children:[(0,K.jsx)(uc,{className:`w-4 h-4 text-amber-600 dark:text-amber-400`}),i(`settings.queueDrying`)]})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.queueDryingDescription`)}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-white`,children:i(`settings.queueDryingEnabled`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-0.5`,children:i(`settings.queueDryingEnabledDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.queue_drying_enabled??!1,onChange:e=>Gn(`queue_drying_enabled`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),A.queue_drying_enabled&&(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-white`,children:i(`settings.queueDryingBlock`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-0.5`,children:i(`settings.queueDryingBlockDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.queue_drying_block??!1,onChange:e=>Gn(`queue_drying_block`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-amber-500`})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-white`,children:i(`settings.ambientDryingEnabled`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-0.5`,children:i(`settings.ambientDryingEnabledDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.ambient_drying_enabled??!1,onChange:e=>Gn(`ambient_drying_enabled`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-white`,children:i(`settings.printDryingEnabled`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-0.5`,children:i(`settings.printDryingEnabledDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.print_drying_enabled??!1,onChange:e=>Gn(`print_drying_enabled`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),(0,K.jsxs)(`div`,{className:`space-y-2`,children:[(0,K.jsx)(`p`,{className:`text-sm text-white font-medium`,children:i(`settings.dryingPresets`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.dryingPresetsDescription`)}),(0,K.jsx)(`div`,{className:`overflow-x-auto`,children:(0,K.jsxs)(`table`,{className:`w-full text-xs`,children:[(0,K.jsx)(`thead`,{children:(0,K.jsxs)(`tr`,{className:`text-bambu-gray border-b border-bambu-dark-tertiary`,children:[(0,K.jsx)(`th`,{className:`text-left py-1.5`,children:i(`settings.dryingFilament`)}),(0,K.jsx)(`th`,{className:`text-center py-1.5`,colSpan:2,children:`AMS 2 Pro`}),(0,K.jsx)(`th`,{className:`text-center py-1.5`,colSpan:2,children:`AMS-HT`})]})}),(0,K.jsx)(`tbody`,{children:(()=>{let e={PLA:{n3f:45,n3s:45,n3f_hours:12,n3s_hours:12},PETG:{n3f:65,n3s:65,n3f_hours:12,n3s_hours:12},TPU:{n3f:65,n3s:75,n3f_hours:12,n3s_hours:18},ABS:{n3f:65,n3s:80,n3f_hours:12,n3s_hours:8},ASA:{n3f:65,n3s:80,n3f_hours:12,n3s_hours:8},PA:{n3f:65,n3s:85,n3f_hours:12,n3s_hours:12},PC:{n3f:65,n3s:80,n3f_hours:12,n3s_hours:8},PVA:{n3f:65,n3s:85,n3f_hours:12,n3s_hours:18}},t={...e};try{if(A.drying_presets){let n=JSON.parse(A.drying_presets);typeof n==`object`&&n&&(t={...e,...n})}}catch{}let n=(e,n,r)=>{let i={...t,[e]:{...t[e],[n]:r}};Gn(`drying_presets`,JSON.stringify(i))};return Object.entries(t).map(([e,t])=>(0,K.jsxs)(`tr`,{className:`border-b border-bambu-dark-tertiary/50`,children:[(0,K.jsx)(`td`,{className:`py-1.5 pr-2 text-white font-medium`,children:e}),(0,K.jsx)(`td`,{className:`py-1 px-1`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-end gap-1`,children:[(0,K.jsx)(`input`,{type:`number`,min:30,max:65,value:t.n3f,onChange:t=>n(e,`n3f`,Math.max(1,parseInt(t.target.value)||0)),className:`w-14 px-1.5 py-1 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-center text-xs focus:border-amber-500/50 focus:outline-none [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:`°C`})]})}),(0,K.jsx)(`td`,{className:`py-1 px-1`,children:(0,K.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,K.jsx)(`input`,{type:`number`,min:1,max:24,value:t.n3f_hours,onChange:t=>n(e,`n3f_hours`,Math.max(1,parseInt(t.target.value)||0)),className:`w-14 px-1.5 py-1 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-center text-xs focus:border-amber-500/50 focus:outline-none [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:`h`})]})}),(0,K.jsx)(`td`,{className:`py-1 px-1`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-end gap-1`,children:[(0,K.jsx)(`input`,{type:`number`,min:30,max:85,value:t.n3s,onChange:t=>n(e,`n3s`,Math.max(1,parseInt(t.target.value)||0)),className:`w-14 px-1.5 py-1 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-center text-xs focus:border-amber-500/50 focus:outline-none [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:`°C`})]})}),(0,K.jsx)(`td`,{className:`py-1 px-1`,children:(0,K.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,K.jsx)(`input`,{type:`number`,min:1,max:24,value:t.n3s_hours,onChange:t=>n(e,`n3s_hours`,Math.max(1,parseInt(t.target.value)||0)),className:`w-14 px-1.5 py-1 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-center text-xs focus:border-amber-500/50 focus:outline-none [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:`h`})]})})]},e))})()})]})})]}),(0,K.jsxs)(`div`,{className:`space-y-2`,children:[(0,K.jsx)(`p`,{className:`text-sm text-white font-medium`,children:i(`settings.humidityThresholds`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.humidityThresholdsDescription`)}),(0,K.jsx)(`div`,{className:`overflow-x-auto`,children:(0,K.jsxs)(`table`,{className:`w-full text-xs`,children:[(0,K.jsx)(`thead`,{children:(0,K.jsxs)(`tr`,{className:`text-bambu-gray border-b border-bambu-dark-tertiary`,children:[(0,K.jsx)(`th`,{className:`text-left py-1.5`,children:i(`settings.dryingFilament`)}),(0,K.jsx)(`th`,{className:`text-right py-1.5 pr-2`,children:i(`settings.humidityThresholdCol`)})]})}),(0,K.jsx)(`tbody`,{children:(()=>{let e=A.ams_humidity_fair??60,t=[`PLA`,`PETG`,`TPU`,`ABS`,`ASA`,`PA`,`PC`,`PVA`],n={};try{if(A.ams_humidity_thresholds){let e=JSON.parse(A.ams_humidity_thresholds);typeof e==`object`&&e&&(n=e)}}catch{}let r=[{key:`default`,label:i(`settings.humidityThresholdDefault`),value:Number(n.default??e),isDefault:!0},...t.map(t=>({key:t,label:t,value:Number(n[t]??n.default??e),isDefault:!1}))],a=(e,t)=>{if(t.trim()===``){let t={...n};delete t[e],Gn(`ams_humidity_thresholds`,JSON.stringify(t));return}let r=parseInt(t,10);if(Number.isNaN(r))return;let i=Math.max(5,Math.min(95,r)),a={...n,[e]:i};Gn(`ams_humidity_thresholds`,JSON.stringify(a))};return r.map(e=>{let t=M[e.key],n=t===void 0?String(e.value):t;return(0,K.jsxs)(`tr`,{className:`border-b border-bambu-dark-tertiary/50`,children:[(0,K.jsx)(`td`,{className:`py-1.5 pr-2 font-medium ${e.isDefault?`text-bambu-gray italic`:`text-white`}`,children:e.label}),(0,K.jsx)(`td`,{className:`py-1 pr-2`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-end gap-1`,children:[(0,K.jsx)(`input`,{type:`number`,min:5,max:95,value:n,onChange:t=>N(n=>({...n,[e.key]:t.target.value})),onBlur:t=>{a(e.key,t.target.value),N(t=>{let n={...t};return delete n[e.key],n})},onKeyDown:e=>{e.key===`Enter`&&e.currentTarget.blur()},className:`w-14 px-1.5 py-1 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white text-center text-xs focus:border-amber-500/50 focus:outline-none [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:`%`})]})})]},e.key)})})()})]})})]})]})]})]})]})]}),ue===`filament`&&A&&(0,K.jsx)(K.Fragment,{children:(0,K.jsxs)(`div`,{className:`flex flex-col lg:flex-row gap-4 lg:gap-6`,children:[(0,K.jsxs)(`div`,{className:`lg:w-1/3 space-y-3`,children:[(0,K.jsx)(mUe,{}),(0,K.jsxs)(Od,{id:`card-filamentchecks`,children:[(0,K.jsx)(kd,{children:(0,K.jsx)(`h2`,{className:`text-lg font-semibold text-white`,children:i(`settings.filamentChecks`)})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.disableFilamentWarnings`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.disableFilamentWarningsDesc`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.disable_filament_warnings,onChange:e=>Gn(`disable_filament_warnings`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.preferLowestFilament`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.preferLowestFilamentDesc`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray/70 mt-1`,children:i(`settings.preferLowestFilamentBackupNote`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.prefer_lowest_filament,onChange:e=>Gn(`prefer_lowest_filament`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]})]})]}),(0,K.jsxs)(Od,{id:`card-printmodal`,children:[(0,K.jsx)(kd,{children:(0,K.jsx)(`h2`,{className:`text-lg font-semibold text-white`,children:i(`settings.printModal`)})}),(0,K.jsx)(Ad,{className:`space-y-3`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.expandCustomMapping`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.expandCustomMappingDescription`)})]}),(0,K.jsxs)(`label`,{className:`relative inline-flex items-center cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.per_printer_mapping_expanded??!1,onChange:e=>Gn(`per_printer_mapping_expanded`,e.target.checked),className:`sr-only peer`}),(0,K.jsx)(`div`,{className:`w-11 h-6 bg-bambu-dark-tertiary peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-bambu-green`})]})]})})]}),(0,K.jsxs)(Od,{id:`card-amsthresholds`,children:[(0,K.jsx)(kd,{children:(0,K.jsx)(`h2`,{className:`text-lg font-semibold text-white`,children:i(`settings.amsDisplayThresholds`)})}),(0,K.jsxs)(Ad,{className:`space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.amsThresholdsDescription`)}),(0,K.jsxs)(`div`,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-white`,children:[(0,K.jsx)(Js,{className:`w-4 h-4 text-blue-600 dark:text-blue-400`}),(0,K.jsx)(`span`,{className:`font-medium`,children:i(`settings.humidity`)})]}),(0,K.jsxs)(`div`,{className:`grid grid-cols-2 gap-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:[i(`settings.goodGreen`),` ≤`]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`input`,{type:`number`,min:`0`,max:`100`,value:A.ams_humidity_good??40,onChange:e=>Gn(`ams_humidity_good`,parseInt(e.target.value)||40),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:`%`})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:[i(`settings.fairOrange`),` ≤`]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`input`,{type:`number`,min:`0`,max:`100`,value:A.ams_humidity_fair??60,onChange:e=>Gn(`ams_humidity_fair`,parseInt(e.target.value)||60),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:`%`})]})]})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.aboveFairBad`)}),(0,K.jsx)(`p`,{className:`text-xs text-amber-700/80 dark:text-amber-400/70`,children:i(`settings.fairAlsoDryingThreshold`)})]}),(0,K.jsxs)(`div`,{className:`space-y-3 pt-2 border-t border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-white`,children:[(0,K.jsx)(Eu,{className:`w-4 h-4 text-orange-600 dark:text-orange-400`}),(0,K.jsx)(`span`,{className:`font-medium`,children:i(`settings.temperature`)})]}),(0,K.jsxs)(`div`,{className:`grid grid-cols-2 gap-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:[i(`settings.goodBlue`),` ≤`]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`input`,{type:`number`,step:`0.5`,min:`0`,max:`60`,value:A.ams_temp_good??28,onChange:e=>Gn(`ams_temp_good`,parseFloat(e.target.value)||28),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:`°C`})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:[i(`settings.fairOrange`),` ≤`]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`input`,{type:`number`,step:`0.5`,min:`0`,max:`60`,value:A.ams_temp_fair??35,onChange:e=>Gn(`ams_temp_fair`,parseFloat(e.target.value)||35),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:`°C`})]})]})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.aboveFairHot`)})]}),(0,K.jsxs)(`div`,{className:`space-y-3 pt-4 border-t border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-white`,children:[(0,K.jsx)(Vs,{className:`w-4 h-4 text-purple-600 dark:text-purple-400`}),(0,K.jsx)(`span`,{className:`font-medium`,children:i(`settings.historyRetention`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:i(`settings.keepSensorHistory`)}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`input`,{type:`number`,min:`1`,max:`365`,value:A.ams_history_retention_days??30,onChange:e=>Gn(`ams_history_retention_days`,parseInt(e.target.value)||30),className:`w-24 px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:i(`common.days`)})]})]}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray`,children:i(`settings.historyRetentionDescription`)})]})]})]})]}),(0,K.jsxs)(`div`,{className:`lg:w-2/3 space-y-3`,children:[(0,K.jsx)(hUe,{}),(0,K.jsx)(TUe,{})]})]})}),Oe!==null&&(0,K.jsx)(Gd,{title:i(`settings.deleteApiKeyTitle`),message:i(`settings.deleteApiKeyMessage`),confirmText:i(`settings.deleteKey`),variant:`danger`,onConfirm:()=>{Rt.mutate(Oe),ke(null)},onCancel:()=>ke(null)}),P&&(0,K.jsx)(KHe,{plug:I,onClose:()=>{F(!1),L(null)}}),R&&(0,K.jsx)(YHe,{provider:B,onClose:()=>{z(!1),V(null)}}),ee&&(0,K.jsx)(XHe,{template:ee,onClose:()=>te(null)}),ae&&(0,K.jsx)(QHe,{onClose:()=>oe(!1)}),Me&&(0,K.jsx)(Gd,{title:i(`settings.clearNotificationLogs`),message:i(`settings.clearLogsMessage`),confirmText:i(`settings.clearLogs`),variant:`warning`,onConfirm:async()=>{Ne(!1);try{o((await Q.clearNotificationLogs(30)).message,`success`)}catch{o(i(`settings.toast.clearLogsFailed`),`error`)}},onCancel:()=>Ne(!1)}),Pe&&(0,K.jsx)(Gd,{title:i(`settings.resetUiPreferences`),message:i(`settings.resetUiPreferencesMessage`),confirmText:i(`settings.resetPreferences`),variant:`default`,onConfirm:()=>{Fe(!1),localStorage.clear(),o(i(`settings.toast.uiPreferencesReset`),`success`),setTimeout(()=>window.location.reload(),1e3)},onCancel:()=>Fe(!1)}),Ie&&(0,K.jsx)(Gd,{title:`Turn All Plugs ${Ie===`on`?`On`:`Off`}`,message:`This will turn ${Ie===`on`?`ON`:`OFF`} all ${At?.filter(e=>e.enabled).length||0} enabled smart plugs. ${Ie===`off`?`Any running printers may be affected!`:``}`,confirmText:`Turn All ${Ie===`on`?`On`:`Off`}`,variant:Ie===`off`?`danger`:`warning`,onConfirm:()=>{let e=Ie;Le(null),Ln.mutate(e)},onCancel:()=>Le(null)}),Re&&sn?.release_notes&&(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4`,onClick:()=>ze(!1),children:(0,K.jsxs)(Od,{className:`w-full max-w-2xl max-h-[80vh] flex flex-col`,onClick:e=>e.stopPropagation(),children:[(0,K.jsxs)(kd,{className:`flex flex-row items-center justify-between shrink-0`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`h2`,{className:`text-lg font-semibold text-white`,children:[`Release Notes - v`,sn.latest_version]}),sn.release_name&&sn.release_name!==sn.latest_version&&(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:sn.release_name})]}),(0,K.jsx)(`button`,{onClick:()=>ze(!1),className:`p-1 rounded hover:bg-bambu-dark-tertiary text-bambu-gray hover:text-white`,children:(0,K.jsx)(Yu,{className:`w-5 h-5`})})]}),(0,K.jsx)(Ad,{className:`overflow-y-auto flex-1`,children:(0,K.jsx)(`pre`,{className:`text-sm text-bambu-gray whitespace-pre-wrap font-sans`,children:sn.release_notes})}),(0,K.jsxs)(`div`,{className:`p-4 border-t border-bambu-dark-tertiary shrink-0 flex gap-2`,children:[sn.release_url&&(0,K.jsx)(`a`,{href:sn.release_url,target:`_blank`,rel:`noopener noreferrer`,className:`flex-1`,children:(0,K.jsxs)($,{variant:`secondary`,className:`w-full`,children:[(0,K.jsx)($s,{className:`w-4 h-4`}),`View on GitHub`]})}),(0,K.jsx)($,{onClick:()=>ze(!1),className:`flex-1`,children:`Close`})]})]})}),ue===`users`&&(0,K.jsxs)(`div`,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{className:`flex gap-1 border-b border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`button`,{onClick:()=>pe(`users`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${fe===`users`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Lu,{className:`w-4 h-4`}),i(`settings.tabs.users`)]}),(0,K.jsxs)(`button`,{onClick:()=>pe(`email`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${fe===`email`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(tl,{className:`w-4 h-4`}),i(`settings.tabs.emailAuth`)||`Email Authentication`,hn?.advanced_auth_enabled&&(0,K.jsx)(`span`,{className:`w-2 h-2 rounded-full bg-green-400`})]}),(0,K.jsxs)(`button`,{onClick:()=>pe(`ldap`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${fe===`ldap`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(tu,{className:`w-4 h-4`}),i(`settings.tabs.ldap`)||`LDAP`,gn?.ldap_enabled&&(0,K.jsx)(`span`,{className:`w-2 h-2 rounded-full bg-green-400`})]}),(0,K.jsxs)(`button`,{onClick:()=>pe(`twofa`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px flex items-center gap-2 ${fe===`twofa`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(tu,{className:`w-4 h-4`}),i(`settings.tabs.twoFa`),(0,K.jsx)(`span`,{className:`w-2 h-2 rounded-full ${_n?.totp_enabled||_n?.email_otp_enabled?`bg-green-400`:`bg-bambu-gray/40`}`})]}),l&&(0,K.jsxs)(`button`,{onClick:()=>pe(`oidc`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px flex items-center gap-2 ${fe===`oidc`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(Tc,{className:`w-4 h-4`}),i(`settings.tabs.oidc`),(0,K.jsx)(`span`,{className:`w-2 h-2 rounded-full ${vn.some(e=>e.is_enabled)?`bg-green-400`:`bg-bambu-gray/40`}`})]}),l&&(0,K.jsxs)(`button`,{onClick:()=>pe(`security`),className:`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px flex items-center gap-2 ${fe===`security`?`text-bambu-green border-bambu-green`:`text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent`}`,children:[(0,K.jsx)(tu,{className:`w-4 h-4`}),i(`settings.tabs.security`)]})]}),fe===`users`&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(Od,{children:(0,K.jsx)(Ad,{className:`py-4`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,K.jsx)(`div`,{className:`w-10 h-10 rounded-full flex items-center justify-center ${s?`bg-green-500/20`:`bg-gray-500/20`}`,children:s?(0,K.jsx)(Qc,{className:`w-5 h-5 text-green-600 dark:text-green-400`}):(0,K.jsx)(Zc,{className:`w-5 h-5 text-gray-400`})}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`text-white font-medium`,children:i(`settings.authentication`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(s?`settings.authEnabledDescription`:`settings.authDisabledDescription`)})]})]}),s?c?.is_admin&&(0,K.jsxs)($,{variant:`secondary`,onClick:()=>Ve(!0),children:[(0,K.jsx)(Zc,{className:`w-4 h-4`}),i(`common.disable`)]}):(0,K.jsxs)($,{onClick:()=>t(`/setup`),children:[(0,K.jsx)(Qc,{className:`w-4 h-4`}),i(`common.enable`)]})]})})}),hn?.advanced_auth_enabled&&(0,K.jsx)(Od,{className:`border-blue-500/30 bg-blue-500/5`,children:(0,K.jsx)(Ad,{className:`py-4`,children:(0,K.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,K.jsx)(`div`,{className:`w-10 h-10 rounded-full flex items-center justify-center bg-blue-500/20 flex-shrink-0`,children:(0,K.jsx)(tl,{className:`w-5 h-5 text-blue-600 dark:text-blue-400`})}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`text-white font-medium`,children:i(`settings.email.advancedAuthEnabled`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mt-1`,children:i(`settings.email.advancedAuthEnabledDesc`)})]})]})})}),s&&(0,K.jsxs)(`div`,{className:`grid grid-cols-1 xl:grid-cols-2 gap-6`,children:[(0,K.jsxs)(`div`,{className:`space-y-3`,children:[(0,K.jsxs)(Od,{id:`card-session-policy`,children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`h3`,{className:`text-lg font-semibold text-white flex items-center gap-2`,children:[(0,K.jsx)(Qc,{className:`w-5 h-5 text-bambu-green`}),i(`settings.sessionPolicy.title`)]})}),(0,K.jsxs)(Ad,{children:[(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mb-4`,children:i(`settings.sessionPolicy.description`)}),(0,K.jsxs)(`div`,{className:`grid grid-cols-2 sm:grid-cols-4 gap-2 mb-4`,children:[[{hours:24,labelKey:`settings.sessionPolicy.preset24h`},{hours:168,labelKey:`settings.sessionPolicy.preset7d`},{hours:720,labelKey:`settings.sessionPolicy.preset30d`}].map(e=>{let t=(A?.session_max_hours??24)===e.hours;return(0,K.jsx)(`button`,{type:`button`,onClick:()=>Gn(`session_max_hours`,e.hours),disabled:s&&!d(`settings:update`),className:`px-3 py-2 rounded-lg text-sm font-medium transition-colors ${t?`bg-bambu-green text-white`:`bg-bambu-dark-tertiary text-bambu-gray hover:text-white hover:bg-bambu-dark`} disabled:opacity-50 disabled:cursor-not-allowed`,children:i(e.labelKey)},e.hours)}),(0,K.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,K.jsx)(`input`,{type:`number`,min:1,max:720,value:A?.session_max_hours??24,onChange:e=>{let t=parseInt(e.target.value,10);Number.isNaN(t)||Gn(`session_max_hours`,Math.max(1,Math.min(720,t)))},disabled:s&&!d(`settings:update`),"aria-label":i(`settings.sessionPolicy.customHoursLabel`),className:`w-20 px-2 py-2 bg-bambu-dark-tertiary text-white text-sm rounded-lg border border-bambu-dark-tertiary focus:border-bambu-green focus:outline-none disabled:opacity-50`}),(0,K.jsx)(`span`,{className:`text-sm text-bambu-gray`,children:i(`settings.sessionPolicy.hoursSuffix`)})]})]}),(A?.session_max_hours??24)>24&&(0,K.jsxs)(`div`,{className:`flex items-start gap-2 p-3 rounded-lg bg-yellow-50 dark:bg-yellow-500/10 border border-yellow-300 dark:border-yellow-500/30`,children:[(0,K.jsx)(ju,{className:`w-4 h-4 text-yellow-600 dark:text-yellow-400 flex-shrink-0 mt-0.5`}),(0,K.jsx)(`p`,{className:`text-xs text-yellow-800 dark:text-yellow-200`,children:i(`settings.sessionPolicy.warning`)})]})]})]}),c&&(0,K.jsxs)(Od,{children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`h3`,{className:`text-lg font-semibold text-white flex items-center gap-2`,id:`card-currentuser`,children:[(0,K.jsx)(Lu,{className:`w-5 h-5 text-bambu-green`}),i(`settings.currentUser`)]}),c.auth_source!==`ldap`&&(0,K.jsxs)($,{size:`sm`,variant:`ghost`,onClick:()=>Ue(!0),children:[(0,K.jsx)(Vc,{className:`w-4 h-4`}),i(`settings.changePassword`)]})]})}),(0,K.jsx)(Ad,{children:(0,K.jsx)(`div`,{className:`flex items-center justify-between`,children:(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-white font-medium text-lg`,children:c.username}),(0,K.jsxs)(`div`,{className:`flex flex-wrap gap-1 mt-2`,children:[c.is_admin&&(0,K.jsx)(`span`,{className:`px-2 py-0.5 rounded-full text-xs font-medium bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-300`,children:i(`settings.admin`)}),c.groups?.map(e=>(0,K.jsx)(`span`,{className:`px-2 py-0.5 rounded-full text-xs font-medium ${e.name===`Administrators`?`bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-300`:e.name===`Operators`?`bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-300`:e.name===`Viewers`?`bg-green-100 dark:bg-green-500/20 text-green-700 dark:text-green-300`:`bg-gray-500/20 text-gray-300`}`,children:e.name},e.id))]})]})})})]}),(0,K.jsxs)(Od,{children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`h3`,{className:`text-lg font-semibold text-white flex items-center gap-2`,id:`card-users`,children:[(0,K.jsx)(Lu,{className:`w-5 h-5 text-bambu-green`}),i(`settings.users`)]}),d(`users:create`)&&(0,K.jsxs)($,{size:`sm`,onClick:()=>{Ze(!0),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]})},children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),i(`settings.addUser`)]})]})}),(0,K.jsx)(Ad,{children:bn?(0,K.jsx)(`div`,{className:`flex items-center justify-center py-8`,children:(0,K.jsx)(X,{className:`w-6 h-6 text-bambu-green animate-spin`})}):yn.length===0?(0,K.jsx)(`p`,{className:`text-center text-bambu-gray py-8`,children:i(`settings.noUsersFound`)}):(0,K.jsx)(`div`,{className:`divide-y divide-bambu-dark-tertiary`,children:yn.map(e=>(0,K.jsxs)(`div`,{className:`py-3 flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,K.jsx)(`p`,{className:`text-white font-medium truncate`,children:e.username}),(0,K.jsxs)(`div`,{className:`flex flex-wrap gap-1 mt-1`,children:[e.auth_source===`ldap`&&(0,K.jsx)(`span`,{className:`px-2 py-0.5 rounded-full text-xs font-medium bg-cyan-100 dark:bg-cyan-500/20 text-cyan-700 dark:text-cyan-300`,children:`LDAP`}),e.is_admin&&(0,K.jsx)(`span`,{className:`px-2 py-0.5 rounded-full text-xs font-medium bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-300`,children:i(`settings.admin`)}),e.groups?.map(e=>(0,K.jsx)(`span`,{className:`px-2 py-0.5 rounded-full text-xs font-medium ${e.name===`Administrators`?`bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-300`:e.name===`Operators`?`bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-300`:e.name===`Viewers`?`bg-green-100 dark:bg-green-500/20 text-green-700 dark:text-green-300`:`bg-gray-500/20 text-gray-300`}`,children:e.name},e.id))]})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-1 ml-4`,children:[d(`users:update`)&&(0,K.jsx)($,{size:`sm`,variant:`ghost`,onClick:()=>jn(e),children:(0,K.jsx)(Tl,{className:`w-4 h-4`})}),d(`users:delete`)&&e.id!==c?.id&&(0,K.jsx)($,{size:`sm`,variant:`ghost`,onClick:()=>Dn(e.id),children:(0,K.jsx)(Ou,{className:`w-4 h-4`})})]})]},e.id))})})]})]}),(0,K.jsx)(`div`,{children:(0,K.jsxs)(Od,{children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`h3`,{className:`text-lg font-semibold text-white flex items-center gap-2`,id:`card-groups`,children:[(0,K.jsx)(tu,{className:`w-5 h-5 text-bambu-green`}),i(`settings.groups`)]}),d(`groups:create`)&&(0,K.jsxs)($,{size:`sm`,onClick:()=>t(`/groups/new`),children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),i(`settings.addGroup`)]})]})}),(0,K.jsx)(Ad,{children:Sn?(0,K.jsx)(`div`,{className:`flex items-center justify-center py-8`,children:(0,K.jsx)(X,{className:`w-6 h-6 text-bambu-green animate-spin`})}):xn.length===0?(0,K.jsx)(`p`,{className:`text-center text-bambu-gray py-8`,children:i(`settings.noGroupsFound`)}):(0,K.jsx)(`div`,{className:`divide-y divide-bambu-dark-tertiary`,children:xn.map(e=>(0,K.jsxs)(`div`,{className:`py-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(tu,{className:`w-4 h-4 ${e.name===`Administrators`?`text-purple-600 dark:text-purple-400`:e.name===`Operators`?`text-blue-600 dark:text-blue-400`:e.name===`Viewers`?`text-green-600 dark:text-green-400`:`text-bambu-gray`}`}),(0,K.jsx)(`span`,{className:`text-white font-medium`,children:e.name}),e.is_system&&(0,K.jsx)(`span`,{className:`px-2 py-0.5 rounded text-xs bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400`,children:i(`settings.system`)})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-1`,children:[d(`groups:update`)&&(0,K.jsx)($,{size:`sm`,variant:`ghost`,onClick:()=>t(`/groups/${e.id}/edit`),children:(0,K.jsx)(Tl,{className:`w-4 h-4`})}),d(`groups:delete`)&&!e.is_system&&(0,K.jsx)($,{size:`sm`,variant:`ghost`,onClick:()=>pt(e.id),children:(0,K.jsx)(Ou,{className:`w-4 h-4`})})]})]}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mt-1 ml-6`,children:e.description||i(`settings.noDescription`)}),(0,K.jsxs)(`div`,{className:`flex items-center gap-4 mt-2 ml-6 text-xs text-bambu-gray`,children:[(0,K.jsx)(`span`,{children:i(`settings.userCount`,{count:e.user_count})}),(0,K.jsx)(`span`,{children:i(`settings.permissionCount`,{count:e.permissions.length})})]})]},e.id))})})]})})]}),!s&&(0,K.jsx)(Od,{children:(0,K.jsx)(Ad,{className:`py-6`,children:(0,K.jsxs)(`div`,{className:`text-center`,children:[(0,K.jsx)(Zc,{className:`w-12 h-12 text-bambu-gray mx-auto mb-4`}),(0,K.jsx)(`h3`,{className:`text-lg font-medium text-white mb-2`,children:i(`settings.authDisabledTitle`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mb-4 max-w-md mx-auto`,children:i(`settings.authDisabledMessage`)}),(0,K.jsxs)(`ul`,{className:`space-y-2 text-sm text-bambu-gray mb-6 text-left max-w-xs mx-auto`,children:[(0,K.jsxs)(`li`,{className:`flex items-start gap-2`,children:[(0,K.jsx)(_s,{className:`w-4 h-4 text-bambu-green mt-0.5 flex-shrink-0`}),(0,K.jsx)(`span`,{children:i(`settings.authDisabledFeature1`)})]}),(0,K.jsxs)(`li`,{className:`flex items-start gap-2`,children:[(0,K.jsx)(_s,{className:`w-4 h-4 text-bambu-green mt-0.5 flex-shrink-0`}),(0,K.jsx)(`span`,{children:i(`settings.authDisabledFeature2`)})]}),(0,K.jsxs)(`li`,{className:`flex items-start gap-2`,children:[(0,K.jsx)(_s,{className:`w-4 h-4 text-bambu-green mt-0.5 flex-shrink-0`}),(0,K.jsx)(`span`,{children:i(`settings.authDisabledFeature3`)})]})]}),(0,K.jsxs)($,{onClick:()=>t(`/setup`),children:[(0,K.jsx)(Qc,{className:`w-4 h-4`}),i(`settings.enableAuthentication`)]})]})})})]}),fe===`email`&&(0,K.jsx)(`div`,{className:`max-w-5xl`,id:`card-smtp`,children:(0,K.jsx)(UUe,{})}),fe===`ldap`&&(0,K.jsx)(`div`,{className:`max-w-5xl`,id:`card-ldap`,children:(0,K.jsx)(GUe,{})}),fe===`twofa`&&(0,K.jsx)(`div`,{className:`max-w-2xl`,children:(0,K.jsx)(qUe,{})}),fe===`oidc`&&l&&(0,K.jsxs)(`div`,{className:`max-w-3xl space-y-4`,children:[(0,K.jsx)(Od,{children:(0,K.jsx)(Ad,{className:`space-y-3 p-4`,children:(0,K.jsxs)(`label`,{className:`flex items-start gap-3 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:A.local_login_enabled===!1,onChange:e=>Gn(`local_login_enabled`,!e.target.checked),className:`mt-1 h-4 w-4 rounded border-bambu-dark-tertiary bg-bambu-dark-secondary text-bambu-green focus:ring-bambu-green/50 cursor-pointer`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`p`,{className:`text-sm font-medium text-white`,children:i(`settings.localLogin.disable`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-0.5`,children:i(`settings.localLogin.disableHint`)})]})]})})}),(0,K.jsx)(XUe,{})]}),fe===`security`&&l&&(0,K.jsx)(`div`,{className:`max-w-3xl`,children:(0,K.jsx)(QUe,{})})]}),Xe&&!hn?.advanced_auth_enabled&&(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black flex items-center justify-center z-50 p-4`,onClick:()=>{Ze(!1),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]})},children:(0,K.jsxs)(Od,{className:`w-full max-w-md`,onClick:e=>e.stopPropagation(),children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(Lu,{className:`w-5 h-5 text-bambu-green`}),(0,K.jsx)(`h2`,{className:`text-lg font-semibold text-white`,children:i(`settings.createUser`)})]}),(0,K.jsx)($,{variant:`ghost`,size:`sm`,onClick:()=>{Ze(!1),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]})},children:(0,K.jsx)(Yu,{className:`w-5 h-5`})})]})}),(0,K.jsxs)(Ad,{children:[gn?.ldap_enabled&&(0,K.jsxs)(`div`,{className:`mb-4 flex items-center gap-1 p-1 bg-bambu-dark-secondary rounded-lg`,role:`tablist`,"aria-label":i(`users.modal.tabsAriaLabel`),children:[(0,K.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":Qe===`local`,onClick:()=>$e(`local`),className:`flex-1 px-3 py-2 text-sm rounded-md transition-colors ${Qe===`local`?`bg-bambu-green/15 text-bambu-green`:`text-bambu-gray hover:text-white`}`,children:i(`users.modal.localTab`)}),(0,K.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":Qe===`ldap`,onClick:()=>$e(`ldap`),className:`flex-1 px-3 py-2 text-sm rounded-md transition-colors ${Qe===`ldap`?`bg-bambu-green/15 text-bambu-green`:`text-bambu-gray hover:text-white`}`,children:i(`users.modal.ldapTab`)})]}),Qe===`ldap`&&gn?.ldap_enabled?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(r6,{onSuccess:e=>{Ze(!1),$e(`local`),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]}),o(i(`users.toast.ldapProvisioned`,{username:e.username}))}}),(0,K.jsx)(`div`,{className:`mt-6 flex justify-end`,children:(0,K.jsx)($,{variant:`secondary`,onClick:()=>{Ze(!1),$e(`local`),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]})},children:i(`common.cancel`)})})]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm font-medium text-white mb-2`,children:i(`settings.username`)}),(0,K.jsx)(`input`,{type:`text`,value:ut.username,onChange:e=>dt({...ut,username:e.target.value}),className:`w-full px-4 py-3 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors`,placeholder:i(`settings.enterUsername`),autoComplete:`username`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm font-medium text-white mb-2`,children:i(`settings.password`)}),(0,K.jsx)(`input`,{type:`password`,value:ut.password,onChange:e=>dt({...ut,password:e.target.value}),className:`w-full px-4 py-3 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors`,placeholder:i(`settings.enterPassword`),autoComplete:`new-password`,minLength:8}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-xs mt-1`,children:i(`settings.passwordRequirements`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm font-medium text-white mb-2`,children:i(`settings.confirmPassword`)}),(0,K.jsx)(`input`,{type:`password`,value:ut.confirmPassword,onChange:e=>dt({...ut,confirmPassword:e.target.value}),className:`w-full px-4 py-3 bg-bambu-dark-secondary border rounded-lg text-white placeholder-bambu-gray focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors ${ut.confirmPassword&&ut.password!==ut.confirmPassword?`border-red-500`:`border-bambu-dark-tertiary`}`,placeholder:i(`settings.confirmPasswordPlaceholder`),autoComplete:`new-password`,minLength:6}),ut.confirmPassword&&ut.password!==ut.confirmPassword&&(0,K.jsx)(`p`,{className:`text-red-700 dark:text-red-400 text-xs mt-1`,children:i(`settings.passwordsDoNotMatch`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm font-medium text-white mb-2`,children:i(`settings.groups`)}),(0,K.jsxs)(`div`,{className:`space-y-2 max-h-40 overflow-y-auto p-2 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg`,children:[xn.map(e=>(0,K.jsxs)(`label`,{className:`flex items-center gap-3 px-2 py-1.5 rounded hover:bg-bambu-dark-tertiary cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:ut.group_ids.includes(e.id),onChange:()=>Mn(e.id),className:`w-4 h-4 rounded border-bambu-gray text-bambu-green focus:ring-bambu-green focus:ring-offset-0 bg-bambu-dark`}),(0,K.jsx)(`span`,{className:`text-sm text-white`,children:e.name}),e.is_system&&(0,K.jsx)(`span`,{className:`text-xs text-yellow-700 dark:text-yellow-400`,children:i(`settings.systemBadge`)})]},e.id)),xn.length===0&&(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`settings.noGroupsAvailable`)})]})]})]}),(0,K.jsxs)(`div`,{className:`mt-6 flex justify-end gap-3`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:()=>{Ze(!1),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]})},children:i(`common.cancel`)}),(0,K.jsx)($,{onClick:kn,disabled:Cn.isPending||!ut.username||!ut.password||ut.password!==ut.confirmPassword||k3(ut.password)!==null,children:Cn.isPending?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}),i(`settings.creating`)]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),i(`settings.createUser`)]})})]})]})]})]})}),Xe&&hn?.advanced_auth_enabled&&(0,K.jsx)(pUe,{formData:ut,setFormData:dt,groups:xn,onClose:()=>{Ze(!1),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]})},onCreate:kn,isCreating:Cn.isPending,isCreateButtonDisabled:Cn.isPending||!ut.username||!ut.email,ldapEnabled:gn?.ldap_enabled,onLdapProvisioned:e=>{Ze(!1),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]}),o(i(`users.toast.ldapProvisioned`,{username:e.username}))}}),et&&nt!==null&&(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black flex items-center justify-center z-50 p-4`,onClick:()=>{tt(!1),rt(null),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]})},children:(0,K.jsxs)(Od,{className:`w-full max-w-md`,onClick:e=>e.stopPropagation(),children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(Tl,{className:`w-5 h-5 text-bambu-green`}),(0,K.jsx)(`h2`,{className:`text-lg font-semibold text-white`,children:i(`settings.editUser`)})]}),(0,K.jsx)($,{variant:`ghost`,size:`sm`,onClick:()=>{tt(!1),rt(null),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]})},children:(0,K.jsx)(Yu,{className:`w-5 h-5`})})]})}),(0,K.jsxs)(Ad,{children:[(0,K.jsxs)(`div`,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:`block text-sm font-medium text-white mb-2`,children:[i(`settings.username`),` `,hn?.advanced_auth_enabled&&(0,K.jsx)(`span`,{className:`text-red-700 dark:text-red-400`,children:`*`})]}),(0,K.jsx)(`input`,{type:`text`,value:ut.username,onChange:e=>dt({...ut,username:e.target.value}),className:`w-full px-4 py-3 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors`,placeholder:i(`settings.enterUsername`),autoComplete:`username`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:`block text-sm font-medium text-white mb-2`,children:[i(`users.form.email`)||`Email`,` `,hn?.advanced_auth_enabled?(0,K.jsx)(`span`,{className:`text-red-700 dark:text-red-400`,children:`*`}):(0,K.jsxs)(`span`,{className:`text-bambu-gray font-normal`,children:[`(`,i(`users.form.optional`)||`optional`,`)`]})]}),(0,K.jsx)(`input`,{type:`email`,value:ut.email,onChange:e=>dt({...ut,email:e.target.value}),className:`w-full px-4 py-3 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors`,placeholder:i(`users.form.emailPlaceholder`)||`user@example.com`,required:hn?.advanced_auth_enabled})]}),!hn?.advanced_auth_enabled&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`label`,{className:`block text-sm font-medium text-white mb-2`,children:[i(`users.form.password`)||`Password`,` `,(0,K.jsxs)(`span`,{className:`text-bambu-gray font-normal`,children:[`(`,i(`users.form.leaveBlankToKeep`)||`leave blank to keep current`,`)`]})]}),(0,K.jsx)(`input`,{type:`password`,value:ut.password,onChange:e=>dt({...ut,password:e.target.value,confirmPassword:``}),className:`w-full px-4 py-3 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors`,placeholder:i(`settings.enterNewPassword`),autoComplete:`new-password`,minLength:8}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-xs mt-1`,children:i(`settings.passwordRequirements`)})]}),ut.password&&(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm font-medium text-white mb-2`,children:i(`settings.confirmPassword`)}),(0,K.jsx)(`input`,{type:`password`,value:ut.confirmPassword,onChange:e=>dt({...ut,confirmPassword:e.target.value}),className:`w-full px-4 py-3 bg-bambu-dark-secondary border rounded-lg text-white placeholder-bambu-gray focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors ${ut.confirmPassword&&ut.password!==ut.confirmPassword?`border-red-500`:`border-bambu-dark-tertiary`}`,placeholder:i(`settings.confirmNewPassword`),autoComplete:`new-password`,minLength:6}),ut.confirmPassword&&ut.password!==ut.confirmPassword&&(0,K.jsx)(`p`,{className:`text-red-700 dark:text-red-400 text-xs mt-1`,children:i(`settings.passwordsDoNotMatch`)})]})]}),hn?.advanced_auth_enabled&&(0,K.jsxs)(`div`,{className:`bg-bambu-dark-secondary/50 border border-bambu-green/20 rounded-lg p-3 space-y-3`,children:[(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:i(`users.form.passwordManagedByAdvancedAuth`)||`Password is managed by Advanced Authentication. Use "Reset Password" to send a new password to the user via email.`}),(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>nt&&En.mutate(nt),disabled:En.isPending||!ut.email,className:`w-full`,children:En.isPending?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}),i(`users.form.resettingPassword`)||`Resetting Password...`]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(Rl,{className:`w-4 h-4`}),i(`users.form.resetPassword`)||`Reset Password`]})})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm font-medium text-white mb-2`,children:i(`users.form.groups`)||`Groups`}),(0,K.jsx)(`div`,{className:`space-y-2 max-h-40 overflow-y-auto p-2 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg`,children:xn.map(e=>(0,K.jsxs)(`label`,{className:`flex items-center gap-3 px-2 py-1.5 rounded hover:bg-bambu-dark-tertiary cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:ut.group_ids.includes(e.id),onChange:()=>Mn(e.id),className:`w-4 h-4 rounded border-bambu-gray text-bambu-green focus:ring-bambu-green focus:ring-offset-0 bg-bambu-dark`}),(0,K.jsx)(`span`,{className:`text-sm text-white`,children:e.name}),e.is_system&&(0,K.jsxs)(`span`,{className:`text-xs text-yellow-700 dark:text-yellow-400`,children:[`(`,i(`users.system`)||`System`,`)`]})]},e.id))})]})]}),(0,K.jsxs)(`div`,{className:`mt-6 flex justify-end gap-3`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:()=>{tt(!1),rt(null),dt({username:``,password:``,email:``,confirmPassword:``,role:`user`,group_ids:[]})},children:i(`users.modal.cancel`)||`Cancel`}),(0,K.jsx)($,{onClick:()=>An(nt),disabled:wn.isPending||!ut.username||hn?.advanced_auth_enabled&&!ut.email||!!(!hn?.advanced_auth_enabled&&ut.password&&(ut.password!==ut.confirmPassword||k3(ut.password)!==null)),children:wn.isPending?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}),i(`users.modal.saving`)||`Saving...`]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(Vl,{className:`w-4 h-4`}),i(`users.modal.saveChanges`)||`Save Changes`]})})]})]})]})}),it!==null&&(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/80 flex items-center justify-center z-50 p-4`,onClick:()=>{at(null),st(null)},children:(0,K.jsxs)(Od,{className:`w-full max-w-md`,onClick:e=>e.stopPropagation(),children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-red-700 dark:text-red-400`,children:[(0,K.jsx)(Ou,{className:`w-5 h-5`}),(0,K.jsx)(`h3`,{className:`text-lg font-semibold`,children:i(`settings.deleteUserTitle`)})]})}),(0,K.jsx)(Ad,{className:`space-y-3`,children:ct?(0,K.jsx)(`div`,{className:`flex items-center justify-center py-4`,children:(0,K.jsx)(`div`,{className:`animate-spin rounded-full h-6 w-6 border-2 border-bambu-green border-t-transparent`})}):ot&&ot.archives+ot.queue_items+ot.library_files>0?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.userHasCreated`)}),(0,K.jsxs)(`ul`,{className:`list-disc list-inside text-bambu-gray space-y-1`,children:[ot.archives>0&&(0,K.jsxs)(`li`,{children:[ot.archives,` archive`,ot.archives===1?``:`s`]}),ot.queue_items>0&&(0,K.jsxs)(`li`,{children:[ot.queue_items,` queue item`,ot.queue_items===1?``:`s`]}),ot.library_files>0&&(0,K.jsxs)(`li`,{children:[ot.library_files,` library file`,ot.library_files===1?``:`s`]})]}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-sm`,children:i(`settings.userItemsQuestion`)}),(0,K.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[(0,K.jsx)($,{variant:`danger`,onClick:()=>Tn.mutate({id:it,deleteItems:!0}),disabled:Tn.isPending,className:`justify-center`,children:i(`settings.deleteUserAndItems`)}),(0,K.jsx)($,{variant:`secondary`,onClick:()=>Tn.mutate({id:it,deleteItems:!1}),disabled:Tn.isPending,className:`justify-center`,children:i(`settings.deleteUserKeepItems`)}),(0,K.jsx)($,{variant:`ghost`,onClick:()=>{at(null),st(null)},disabled:Tn.isPending,className:`justify-center`,children:i(`common.cancel`)})]})]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`p`,{className:`text-white`,children:i(`settings.deleteUserConfirm`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-sm`,children:i(`settings.actionCannotBeUndone`)}),(0,K.jsxs)(`div`,{className:`flex gap-2 justify-end`,children:[(0,K.jsx)($,{variant:`ghost`,onClick:()=>{at(null),st(null)},disabled:Tn.isPending,children:i(`common.cancel`)}),(0,K.jsx)($,{variant:`danger`,onClick:()=>Tn.mutate({id:it,deleteItems:!1}),disabled:Tn.isPending,children:i(`settings.deleteUserTitle`)})]})]})})]})}),ft!==null&&(0,K.jsx)(Gd,{title:i(`settings.deleteGroupTitle`),message:i(`settings.deleteGroupMessage`),confirmText:i(`settings.deleteGroup`),variant:`danger`,onConfirm:()=>{On.mutate(ft),pt(null)},onCancel:()=>pt(null)}),ue===`failure-detection`&&(0,K.jsx)(`div`,{id:`card-failure-detection`,children:(0,K.jsx)(BUe,{})}),ue===`backup`&&(0,K.jsxs)(`div`,{id:`card-backup`,children:[(0,K.jsxs)(`div`,{className:`mb-4 p-3 bg-amber-50 dark:bg-amber-500/10 border border-amber-300 dark:border-amber-500/30 rounded-lg flex items-start gap-2`,children:[(0,K.jsx)(tu,{className:`text-amber-600 dark:text-amber-400 flex-shrink-0 mt-0.5`,size:16}),(0,K.jsx)(`p`,{className:`text-sm text-amber-700 dark:text-amber-400`,children:i(`backup.includesEncryptionKey`)})]}),(0,K.jsx)(zUe,{})]}),Be&&(0,K.jsx)(Gd,{title:i(`settings.disableAuthenticationTitle`),message:i(`settings.disableAuthenticationMessage`),confirmText:i(`settings.disableAuthentication`),variant:`danger`,onConfirm:async()=>{try{await Q.disableAuth(),o(i(`settings.toast.authDisabled`),`success`),await u(),Ve(!1),window.location.href=`/`}catch(e){o(e instanceof Error?e.message:i(`settings.toast.authDisableFailed`),`error`)}},onCancel:()=>Ve(!1)}),He&&(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/70 flex items-center justify-center z-50 p-4`,onClick:()=>{Ue(!1),Ge({currentPassword:``,newPassword:``,confirmPassword:``})},children:(0,K.jsxs)(Od,{className:`w-full max-w-md`,onClick:e=>e.stopPropagation(),children:[(0,K.jsx)(kd,{children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(Vc,{className:`w-5 h-5 text-bambu-green`}),(0,K.jsx)(`h2`,{className:`text-lg font-semibold text-white`,children:i(`settings.changePassword`)})]}),(0,K.jsx)($,{variant:`ghost`,size:`sm`,onClick:()=>{Ue(!1),Ge({currentPassword:``,newPassword:``,confirmPassword:``})},children:(0,K.jsx)(Yu,{className:`w-5 h-5`})})]})}),(0,K.jsxs)(Ad,{children:[(0,K.jsxs)(`div`,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm font-medium text-white mb-2`,children:`Current Password`}),(0,K.jsx)(`input`,{type:`password`,value:We.currentPassword,onChange:e=>Ge({...We,currentPassword:e.target.value}),className:`w-full px-4 py-3 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors`,placeholder:i(`settings.enterCurrentPassword`),autoComplete:`current-password`})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm font-medium text-white mb-2`,children:`New Password`}),(0,K.jsx)(`input`,{type:`password`,value:We.newPassword,onChange:e=>Ge({...We,newPassword:e.target.value}),className:`w-full px-4 py-3 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors`,placeholder:i(`settings.enterNewPasswordMin6`),autoComplete:`new-password`,minLength:6})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm font-medium text-white mb-2`,children:`Confirm New Password`}),(0,K.jsx)(`input`,{type:`password`,value:We.confirmPassword,onChange:e=>Ge({...We,confirmPassword:e.target.value}),className:`w-full px-4 py-3 bg-bambu-dark-secondary border rounded-lg text-white placeholder-bambu-gray focus:outline-none focus:ring-2 focus:ring-bambu-green/50 focus:border-bambu-green transition-colors ${We.confirmPassword&&We.newPassword!==We.confirmPassword?`border-red-500`:`border-bambu-dark-tertiary`}`,placeholder:i(`settings.confirmNewPassword`),autoComplete:`new-password`,minLength:6}),We.confirmPassword&&We.newPassword!==We.confirmPassword&&(0,K.jsx)(`p`,{className:`text-red-700 dark:text-red-400 text-xs mt-1`,children:i(`settings.passwordsDoNotMatch`)})]})]}),(0,K.jsxs)(`div`,{className:`mt-6 flex justify-end gap-3`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:()=>{Ue(!1),Ge({currentPassword:``,newPassword:``,confirmPassword:``})},children:i(`common.cancel`)}),(0,K.jsx)($,{onClick:async()=>{if(We.newPassword!==We.confirmPassword){o(i(`settings.toast.passwordsDoNotMatch`),`error`);return}if(We.newPassword.length<6){o(i(`settings.toast.passwordTooShort`),`error`);return}qe(!0);try{await Q.changePassword(We.currentPassword,We.newPassword),o(i(`settings.toast.passwordChanged`),`success`),Ue(!1),Ge({currentPassword:``,newPassword:``,confirmPassword:``})}catch(e){o(e instanceof Error?e.message:`Failed to change password`,`error`)}finally{qe(!1)}},disabled:Ke||!We.currentPassword||!We.newPassword||We.newPassword!==We.confirmPassword||We.newPassword.length<6,children:Ke?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}),i(`settings.changing`)]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(Vc,{className:`w-4 h-4`}),i(`settings.changePassword`)]})})]})]})]})})]})]})]})})}var O6={PLA:`GFL99`,"PLA-CF":`GFL98`,"PLA SILK":`GFL96`,"PLA HIGH SPEED":`GFL95`,PETG:`GFG99`,"PETG HF":`GFG96`,"PETG-CF":`GFG98`,PCTG:`GFG97`,ABS:`GFB99`,ASA:`GFB98`,PC:`GFC99`,PA:`GFN99`,"PA-CF":`GFN98`,NYLON:`GFN99`,TPU:`GFU99`,PVA:`GFS99`,HIPS:`GFS98`,PE:`GFP99`,PP:`GFP97`};function k6(e){let t=(e||``).toUpperCase().trim();return t&&(O6[t]||O6[t.replace(/[-\s]?CF$/,``)]||O6[t.replace(/\+$/,``)]||O6[t.split(/[-\s]/)[0]])||``}function A6(e){let t=e.replace(/@.+$/,``).trim();return t.startsWith(`# `)?t.slice(2).trim():t}var j6={local:0,orca_cloud:1,cloud:2,builtin:3};function oWe(e){let{localPresets:t,orcaProfiles:n,cloudSettings:r,builtinFilaments:i}=e,a=[],o=e=>e.trim().toLowerCase(),s=new Set,c=new Set,l=new Set,u=(e,t,...n)=>{let r=n.filter(e=>!!e);if(r.some(e=>s.has(e)))return!1;let i=`${e}|${o(t)}`;return c.has(i)?!1:(r.forEach(e=>s.add(e)),c.add(i),l.add(o(t)),!0)};for(let e of t??[]){let t=A6(e.name),n=e.filament_type||kU(t).material;u(`local`,t)&&a.push({id:`local_${e.id}`,name:t,source:`local`,filamentId:k6(n),filamentType:n||``})}for(let e of n??[]){let t=A6(e.name),n=kU(t).material;u(`orca_cloud`,t,e.setting_id)&&a.push({id:`orca_${e.setting_id}`,name:t,source:`orca_cloud`,filamentId:k6(n),filamentType:n})}for(let e of r??[]){let t=A6(e.name),n=e.setting_id.startsWith(`GFS`)?LU(e.setting_id):``;u(`cloud`,t,e.setting_id,n||void 0)&&a.push({id:e.setting_id,name:t,source:`cloud`,filamentId:n,filamentType:kU(t).material})}for(let e of i??[]){let t=e.filament_id.startsWith(`GF`)?`GFS${e.filament_id.slice(2)}`:e.filament_id;l.has(o(e.name))||u(`builtin`,e.name,e.filament_id,t)&&a.push({id:`builtin_${e.filament_id}`,name:e.name,source:`builtin`,filamentId:e.filament_id,filamentType:kU(e.name).material})}return a.sort((e,t)=>e.source===t.source?e.name.localeCompare(t.name):j6[e.source]-j6[t.source])}async function sWe(e,t){if(e.filamentId)return e.filamentId;if(e.source!==`cloud`||!t)return``;try{return(await t(e.id)).filament_id||``}catch{return``}}var M6=e=>(Math.trunc(parseFloat(e)*1e3)/1e3).toFixed(3),N6=`HS00`,P6=`HH00`,F6=e=>{let t=e.match(/^([A-Z]{2}\d{2})/);return t?t[1]:N6},cWe=e=>F6(e)===P6?`HF`:`S`,I6=e=>{for(let t of[`High Flow_`,`High Flow `,`Standard_`,`Standard `,`HF_`,`HF `,`S_`,`S `])if(e.startsWith(t))return e.slice(t.length);let t=e.indexOf(`_`);return t>0?e.slice(t+1):e};function L6({profile:e,onEdit:t,onCopy:n,selectionMode:r,isSelected:i,onToggleSelect:a,note:o}){let s=cWe(e.nozzle_id),c=e.nozzle_diameter;return(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[r&&(0,K.jsx)(`button`,{onClick:a,className:`text-bambu-gray hover:text-white transition-colors p-1`,children:i?(0,K.jsx)(fu,{className:`w-4 h-4 text-bambu-green`}):(0,K.jsx)(mu,{className:`w-4 h-4`})}),(0,K.jsxs)(`button`,{onClick:()=>{r&&a?a():t()},className:`flex-1 text-left px-3 py-2 bg-bambu-dark rounded hover:bg-bambu-dark-tertiary transition-colors ${i?`ring-1 ring-bambu-green`:``}`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`span`,{className:`text-bambu-green font-mono text-sm font-bold whitespace-nowrap`,children:M6(e.k_value)}),(0,K.jsx)(`span`,{className:`text-white text-sm truncate flex-1`,title:e.name,children:e.name||`Unnamed`}),o&&(0,K.jsx)(`span`,{title:`Has note`,children:(0,K.jsx)(_u,{className:`w-3 h-3 text-yellow-500`})}),(0,K.jsxs)(`span`,{className:`text-xs text-bambu-gray whitespace-nowrap`,children:[s,` `,c]})]}),o&&(0,K.jsxs)(`div`,{className:`text-xs mt-0.5 truncate text-yellow-500/70`,title:o,children:[`Note: `,o.length>50?o.substring(0,50)+`...`:o]})]}),!r&&n&&(0,K.jsx)(`button`,{onClick:e=>{e.stopPropagation(),n()},className:`text-bambu-gray hover:text-white transition-colors p-1`,title:`Copy profile`,children:(0,K.jsx)(Ls,{className:`w-4 h-4`})})]})}function R6({profile:e,printerId:t,nozzleDiameter:n,existingProfiles:r=[],builtinFilaments:i=[],filamentPresets:a=[],isDualNozzle:o=!1,supportsFlowType:s=!0,initialNote:c=``,initialNoteKey:l=null,onClose:u,onSave:d,onSaveNote:f,hasPermission:p}){let{t:m}=W(),{showToast:h}=Id(),[g,_]=(0,y.useState)(e?.name||``),[v,b]=(0,y.useState)(e?.k_value?M6(e.k_value):`0.020`),[x,S]=(0,y.useState)(e?.filament_id||``),[C,w]=(0,y.useState)(e?F6(e.nozzle_id):N6),[T,E]=(0,y.useState)(e?.nozzle_diameter||n),[D,O]=(0,y.useState)(e?[e.extruder_id]:o?[0,1]:[0]),[k,A]=(0,y.useState)(!1),[j,M]=(0,y.useState)({current:0,total:0}),[N,P]=(0,y.useState)(c),[F,I]=(0,y.useState)(``),{schedule:L}=BU(),R=y.useMemo(()=>e?.filament_id?i.find(t=>t.filament_id===e.filament_id)?.name||I6(r.find(t=>t.filament_id===e.filament_id)?.name||e.name||``)||e.filament_id:``,[e,r,i]),z=y.useMemo(()=>{let e=[[`local`,m(`kProfiles.modal.source.local`)],[`orca_cloud`,m(`kProfiles.modal.source.orcaCloud`)],[`cloud`,m(`kProfiles.modal.source.bambuCloud`)],[`builtin`,m(`kProfiles.modal.source.builtin`)]],t=F.trim().toLowerCase(),n=t?a.filter(e=>e.name.toLowerCase().includes(t)):a;return e.map(([e,t])=>({source:e,label:t,items:n.filter(t=>t.source===e)})).filter(e=>e.items.length>0)},[a,F,m]),B=J({mutationFn:e=>(console.log(`[KProfile] Calling API...`),Q.setKProfile(t,e)),onSuccess:(t,n)=>{if(console.log(`[KProfile] Save success:`,t),h(m(`kProfiles.toast.profileSaved`)),f&&N!==c){let t;t=N===``&&l?l:e&&e.slot_id>0?e.setting_id||`slot_${e.slot_id}_${e.filament_id}_${e.extruder_id}`:`name_${g}_${n.filament_id}`,f(t,N)}A(!0),L(()=>{A(!1),d()},2500)},onError:e=>{console.error(`[KProfile] Save error:`,e),h(e.message,`error`),A(!1)}}),V=J({mutationFn:e=>(console.log(`[KProfile] Deleting profile...`),Q.deleteKProfile(t,e)),onSuccess:e=>{console.log(`[KProfile] Delete success:`,e),h(m(`kProfiles.toast.profileDeleted`)),A(!0),L(()=>{A(!1),u()},4e3)},onError:e=>{console.error(`[KProfile] Delete error:`,e),h(e.message,`error`),A(!1)}}),[ee,te]=(0,y.useState)(!1),ne=()=>{e&&V.mutate({slot_id:e.slot_id,extruder_id:e.extruder_id,nozzle_id:e.nozzle_id,nozzle_diameter:e.nozzle_diameter,filament_id:e.filament_id,setting_id:e.setting_id})};return(0,K.jsxs)(`div`,{className:`fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4`,children:[(0,K.jsxs)(Od,{className:`w-full max-w-md relative`,children:[k&&(0,K.jsxs)(`div`,{className:`absolute inset-0 bg-bambu-dark-secondary/90 flex flex-col items-center justify-center z-10 rounded-lg`,children:[(0,K.jsx)(X,{className:`w-8 h-8 text-bambu-green animate-spin mb-3`}),(0,K.jsx)(`p`,{className:`text-white font-medium`,children:j.total>1?m(`kProfiles.modal.savingExtruder`,{current:j.current,total:j.total}):m(`kProfiles.modal.syncing`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray text-sm mt-1`,children:m(`kProfiles.modal.pleaseWait`)})]}),(0,K.jsxs)(Ad,{className:`p-0`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between p-4 border-b border-bambu-dark-tertiary`,children:[(0,K.jsx)(`h2`,{className:`text-xl font-semibold text-white`,children:m(e?`kProfiles.modal.editTitle`:`kProfiles.modal.addTitle`)}),(0,K.jsx)(`button`,{onClick:u,className:`text-bambu-gray hover:text-white transition-colors`,disabled:k,children:(0,K.jsx)(Yu,{className:`w-5 h-5`})})]}),(0,K.jsxs)(`form`,{onSubmit:async n=>{if(n.preventDefault(),o&&!e&&D.length===0){h(m(`kProfiles.toast.selectAtLeastOneExtruder`),`error`);return}let r=parseFloat(v).toFixed(6),i=`${C}-${T}`,s=e&&e.nozzle_id||i,c=e?e.nozzle_diameter:T,l=e?.filament_id||``;if(!e){let e=a.find(e=>e.id===x);if(!e){h(m(`kProfiles.toast.selectFilament`),`error`);return}if(l=await sWe(e,Q.getCloudSettingDetail),!l){h(m(`kProfiles.toast.filamentNotResolvable`,{name:e.name}),`error`);return}}if(e||D.length===1){let t={name:g,k_value:r,filament_id:l,nozzle_id:s,nozzle_diameter:c,extruder_id:e?e.extruder_id:D[0],setting_id:e?.setting_id,slot_id:e?.slot_id??0};console.log(`[KProfile] Saving profile:`,t),B.mutate(t);return}A(!0),M({current:1,total:D.length});let u=D.map(e=>({name:g,k_value:r,filament_id:l,nozzle_id:i,nozzle_diameter:T,extruder_id:e,setting_id:void 0,slot_id:0}));console.log(`[KProfile] Saving ${u.length} profiles in batch:`,u);try{await Q.setKProfilesBatch(t,u),h(m(`kProfiles.toast.profilesSaved`,{count:D.length})),f&&N&&f(`name_${g}_${l}`,N)}catch(e){console.error(`[KProfile] Failed to save batch:`,e),h(m(`kProfiles.toast.failedToSaveBatch`),`error`),A(!1),M({current:0,total:0});return}M({current:D.length,total:D.length}),L(()=>{A(!1),M({current:0,total:0}),d()},3e3)},className:`p-4 space-y-4`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:m(`kProfiles.modal.profileName`)}),(0,K.jsx)(`input`,{type:`text`,value:g,onChange:e=>_(e.target.value),disabled:!!e,className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none ${e?`opacity-60 cursor-not-allowed`:``}`,placeholder:m(`kProfiles.modal.profileNamePlaceholder`),required:!e})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:m(`kProfiles.modal.kValue`)}),(0,K.jsx)(`input`,{type:`text`,inputMode:`decimal`,value:v,onChange:e=>{let t=e.target.value;(t===``||/^\d*\.?\d*$/.test(t))&&b(t)},onBlur:e=>{let t=parseFloat(e.target.value);isNaN(t)||b((Math.trunc(t*1e3)/1e3).toFixed(3))},className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none font-mono`,placeholder:m(`kProfiles.modal.kValuePlaceholder`),required:!0}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:m(`kProfiles.modal.kValueHelp`)})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:m(`kProfiles.modal.filament`)}),e?(0,K.jsx)(`div`,{className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white opacity-60`,children:R||e.filament_id}):(0,K.jsxs)(`div`,{className:`border border-bambu-dark-tertiary rounded-lg overflow-hidden`,children:[(0,K.jsxs)(`div`,{className:`relative border-b border-bambu-dark-tertiary`,children:[(0,K.jsx)(Kl,{className:`absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray`}),(0,K.jsx)(`input`,{type:`text`,value:F,onChange:e=>I(e.target.value),placeholder:m(`kProfiles.modal.searchFilaments`),className:`w-full pl-10 pr-3 py-2 bg-bambu-dark text-white placeholder-bambu-gray focus:outline-none`})]}),(0,K.jsx)(`div`,{className:`max-h-56 overflow-y-auto bg-bambu-dark`,children:z.length===0?(0,K.jsx)(`p`,{className:`px-3 py-3 text-xs text-bambu-gray`,children:a.length===0?m(`kProfiles.modal.noFilamentsHelp`):m(`kProfiles.modal.noFilamentMatches`)}):z.map(e=>(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`div`,{className:`sticky top-0 z-10 flex items-center gap-2 px-3 py-1.5 bg-bambu-dark-secondary border-y border-bambu-dark-tertiary`,children:[(0,K.jsx)(`span`,{className:`text-xs font-bold uppercase tracking-wider text-bambu-green`,children:e.label}),(0,K.jsx)(`span`,{className:`text-[10px] text-bambu-gray`,children:e.items.length})]}),e.items.map(e=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>{S(e.id),g||_(`${C===P6?`HF`:`S`} ${e.name}`)},className:`w-full text-left px-3 py-1.5 text-sm transition-colors ${x===e.id?`bg-bambu-green/20 text-white`:`text-white hover:bg-bambu-dark-tertiary`}`,children:e.name},e.id))]},e.source))})]})]}),(0,K.jsxs)(`div`,{className:s?`grid grid-cols-2 gap-4`:``,children:[(0,K.jsxs)(`div`,{className:s?``:`hidden`,children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:m(`kProfiles.modal.flowType`)}),(0,K.jsxs)(`select`,{value:C,onChange:t=>{let n=t.target.value;if(w(n),!e&&x&&!g){let e=a.find(e=>e.id===x);e&&_(`${n===P6?`HF`:`S`} ${e.name}`)}},disabled:!!e,className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none ${e?`opacity-60 cursor-not-allowed`:``}`,children:[(0,K.jsx)(`option`,{value:P6,children:m(`kProfiles.modal.highFlow`)}),(0,K.jsx)(`option`,{value:N6,children:m(`kProfiles.modal.standard`)})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:m(`kProfiles.modal.nozzleSize`)}),(0,K.jsxs)(`select`,{value:T,onChange:e=>E(e.target.value),disabled:!!e,className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none ${e?`opacity-60 cursor-not-allowed`:``}`,children:[(0,K.jsx)(`option`,{value:`0.2`,children:`0.2mm`}),(0,K.jsx)(`option`,{value:`0.4`,children:`0.4mm`}),(0,K.jsx)(`option`,{value:`0.6`,children:`0.6mm`}),(0,K.jsx)(`option`,{value:`0.8`,children:`0.8mm`})]})]})]}),o&&(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:m(e?`kProfiles.modal.extruder`:`kProfiles.modal.extruders`)}),e?(0,K.jsx)(`div`,{className:`px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white opacity-60`,children:e.extruder_id===1?m(`kProfiles.modal.left`):m(`kProfiles.modal.right`)}):(0,K.jsxs)(`div`,{className:`flex gap-4`,children:[(0,K.jsxs)(`label`,{className:`flex items-center gap-2 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:D.includes(1),onChange:e=>{e.target.checked?O([...D,1]):O(D.filter(e=>e!==1))},className:`w-4 h-4 rounded border-bambu-dark-tertiary bg-bambu-dark text-bambu-green focus:ring-bambu-green focus:ring-offset-0 accent-bambu-green`}),(0,K.jsx)(`span`,{className:`text-white`,children:m(`kProfiles.modal.left`)})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-2 cursor-pointer`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:D.includes(0),onChange:e=>{e.target.checked?O([...D,0]):O(D.filter(e=>e!==0))},className:`w-4 h-4 rounded border-bambu-dark-tertiary bg-bambu-dark text-bambu-green focus:ring-bambu-green focus:ring-offset-0 accent-bambu-green`}),(0,K.jsx)(`span`,{className:`text-white`,children:m(`kProfiles.modal.right`)})]})]})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:m(`kProfiles.modal.notes`)}),(0,K.jsx)(`textarea`,{value:N,onChange:e=>P(e.target.value),placeholder:m(`kProfiles.modal.notesPlaceholder`),rows:2,className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none resize-none`}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:m(`kProfiles.modal.notesHelp`)})]}),(0,K.jsxs)(`div`,{className:`flex gap-2 pt-4`,children:[e&&(0,K.jsx)($,{type:`button`,variant:`secondary`,onClick:()=>te(!0),disabled:V.isPending||k||!p(`kprofiles:delete`),title:p(`kprofiles:delete`)?void 0:m(`kProfiles.permission.noDelete`),className:`text-red-500 hover:bg-red-500/10`,children:V.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(Ou,{className:`w-4 h-4`})}),(0,K.jsx)($,{type:`button`,variant:`secondary`,onClick:u,disabled:k,className:`flex-1`,children:m(`common.cancel`)}),(0,K.jsxs)($,{type:`submit`,disabled:B.isPending||k||!p(e?`kprofiles:update`:`kprofiles:create`),title:p(e?`kprofiles:update`:`kprofiles:create`)?void 0:m(e?`kProfiles.permission.noUpdate`:`kProfiles.permission.noCreate`),className:`flex-1`,children:[B.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(bc,{className:`w-4 h-4`}),m(`common.save`)]})]})]})]})]}),ee&&(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/70 flex items-center justify-center z-[60]`,children:(0,K.jsx)(Od,{className:`w-full max-w-sm`,children:(0,K.jsxs)(Ad,{className:`p-6`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-3 mb-4`,children:[(0,K.jsx)(`div`,{className:`w-10 h-10 rounded-full bg-red-500/20 flex items-center justify-center`,children:(0,K.jsx)(Ou,{className:`w-5 h-5 text-red-500`})}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`text-lg font-semibold text-white`,children:m(`kProfiles.deleteConfirm.title`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:m(`kProfiles.deleteConfirm.cannotUndo`)})]})]}),(0,K.jsx)(`p`,{className:`text-bambu-gray mb-6`,children:m(`kProfiles.deleteConfirm.message`,{name:e?.name})}),(0,K.jsxs)(`div`,{className:`flex gap-3`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:()=>te(!1),className:`flex-1`,children:m(`common.cancel`)}),(0,K.jsxs)($,{onClick:()=>{te(!1),ne()},disabled:V.isPending,className:`flex-1 bg-red-500 hover:bg-red-600 text-white`,children:[V.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(Ou,{className:`w-4 h-4`}),m(`common.delete`)]})]})]})})})]})}var z6={NOZZLE_DIAMETER:`bambusy_kprofiles_nozzle`,SORT_OPTION:`bambusy_kprofiles_sort`};function lWe(){let{t:e}=W(),{showToast:t}=Id(),{hasPermission:n}=Sd(),[r,i]=(0,y.useState)(null),[a,o]=(0,y.useState)(()=>localStorage.getItem(z6.NOZZLE_DIAMETER)||`0.4`),[s,c]=(0,y.useState)(null),[l,u]=(0,y.useState)(!1),[d,f]=(0,y.useState)(null),[p,m]=(0,y.useState)(``),[h,g]=(0,y.useState)(`all`),[_,v]=(0,y.useState)(`all`),[b,x]=(0,y.useState)(()=>localStorage.getItem(z6.SORT_OPTION)||`name`),[S,C]=(0,y.useState)(!1),[w,T]=(0,y.useState)(new Set),[E,D]=(0,y.useState)(!1),[O,k]=(0,y.useState)(!1),A=(0,y.useCallback)(e=>`${e.slot_id}_${e.extruder_id}`,[]);(0,y.useEffect)(()=>{localStorage.setItem(z6.NOZZLE_DIAMETER,a)},[a]),(0,y.useEffect)(()=>{localStorage.setItem(z6.SORT_OPTION,b)},[b]);let{data:j,isLoading:M}=q({queryKey:[`printers`],queryFn:Q.getPrinters}),{data:N,isLoading:P,isFetching:F,error:I,refetch:L}=q({queryKey:[`kprofiles`,r,a],queryFn:async()=>{console.log(`[KProfiles] Fetching profiles for printer`,r,`nozzle`,a);let e=await Q.getKProfiles(r,a);return console.log(`[KProfiles] Received profiles:`,e?.profiles?.length||0,`profiles`),e},enabled:!!r,retry:!1,staleTime:0,gcTime:0,refetchOnMount:`always`}),{data:R}=q({queryKey:[`builtinFilaments`],queryFn:()=>Q.getBuiltinFilaments(),staleTime:3e5}),{data:z}=q({queryKey:[`filamentIdMap`],queryFn:()=>Q.getFilamentIdMap(),staleTime:3e5}),{data:B}=q({queryKey:[`localPresets`],queryFn:()=>Q.getLocalPresets(),retry:!1}),{data:V}=q({queryKey:[`orcaCloudProfilesForKProfiles`],queryFn:()=>Q.orcaCloudListProfiles(),retry:!1}),{data:ee}=q({queryKey:[`cloudSettings`],queryFn:()=>Q.getCloudSettings(),retry:!1}),{data:te,refetch:ne}=q({queryKey:[`kprofile-notes`,r],queryFn:()=>Q.getKProfileNotes(r),enabled:!!r,staleTime:3e4}),re=I?.message?.includes(`not connected`);(0,y.useEffect)(()=>{if(!r&&j&&j.length>0){let e=j.find(e=>e.is_active);e&&i(e.id)}},[r,j]),(0,y.useEffect)(()=>{if(r){let e=setTimeout(()=>{L()},150);return()=>clearTimeout(e)}},[r,a]);let ie=j?.filter(e=>e.is_active)||[],H=y.useMemo(()=>{let e=new Map;if(R)for(let t of R)e.set(t.filament_id,t.name);if(z)for(let[t,n]of Object.entries(z))e.has(t)||e.set(t,n);return e},[R,z]),ae=y.useMemo(()=>Array.from(H.entries()).map(([e,t])=>({filament_id:e,name:t})),[H]),oe=y.useMemo(()=>oWe({localPresets:B?.filament,orcaProfiles:V?.filament,cloudSettings:ee?.filament,builtinFilaments:R}),[B?.filament,V?.filament,ee?.filament,R]),U=y.useCallback(e=>H.get(e.filament_id)||I6(e.name),[H]),se=y.useMemo(()=>N?.profiles?N.profiles.filter(e=>{let t=p.toLowerCase(),n=!t||e.name.toLowerCase().includes(t)||e.filament_id.toLowerCase().includes(t),r=h===`all`||h===`left`&&e.extruder_id===1||h===`right`&&e.extruder_id===0,i=_===`all`||_===`hf`&&e.nozzle_id.startsWith(`HH`)||_===`s`&&e.nozzle_id.startsWith(`HS`);return n&&r&&i}).sort((e,t)=>{switch(b){case`k_value`:return parseFloat(e.k_value)-parseFloat(t.k_value);case`filament`:return U(e).localeCompare(U(t));default:return e.name.localeCompare(t.name)}}):[],[N?.profiles,p,h,_,b,U]),ce=j?.find(e=>e.id===r),le=ce?.nozzle_count===2,ue=ce?.supports_nozzle_flow_type??!0;(0,y.useEffect)(()=>{ue||v(`all`)},[ue]),(0,y.useEffect)(()=>{let e=e=>{e.target instanceof HTMLInputElement||e.target instanceof HTMLTextAreaElement||e.target instanceof HTMLSelectElement||s||l||d||(e.key===`r`||e.key===`R`?(e.preventDefault(),L()):e.key===`n`||e.key===`N`?(e.preventDefault(),u(!0)):e.key===`Escape`&&S&&(e.preventDefault(),C(!1),T(new Set)))};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[s,l,d,S,L]);let de=(0,y.useCallback)(()=>{if(!N?.profiles||N.profiles.length===0){t(e(`kProfiles.toast.noProfilesToExport`),`error`);return}let n={version:1,exported_at:new Date().toISOString(),printer:ce?.name||`Unknown`,nozzle_diameter:a,profiles:N.profiles.map(e=>({name:e.name,k_value:e.k_value,filament_id:e.filament_id,nozzle_id:e.nozzle_id,nozzle_diameter:e.nozzle_diameter,extruder_id:e.extruder_id}))},r=new Blob([JSON.stringify(n,null,2)],{type:`application/json`}),i=URL.createObjectURL(r),o=document.createElement(`a`);o.href=i,o.download=`kprofiles_${ce?.name||`printer`}_${a}mm_${new Date().toISOString().split(`T`)[0]}.json`,document.body.appendChild(o),o.click(),document.body.removeChild(o),URL.revokeObjectURL(i),t(e(`kProfiles.toast.exportedProfiles`,{count:N.profiles.length}))},[N?.profiles,ce,a,t,e]),fe=(0,y.useCallback)(()=>{let n=document.createElement(`input`);n.type=`file`,n.accept=`.json`,n.onchange=async n=>{let i=n.target.files?.[0];if(i)try{let n=await i.text(),o=JSON.parse(n);if(!o.profiles||!Array.isArray(o.profiles)){t(e(`kProfiles.toast.invalidFileFormat`),`error`);return}let s=0;for(let e of o.profiles)if(!(!e.name||!e.k_value||!e.filament_id))try{await Q.setKProfile(r,{name:e.name,k_value:parseFloat(e.k_value).toFixed(6),filament_id:e.filament_id,nozzle_id:e.nozzle_id||`${N6}-${a}`,nozzle_diameter:e.nozzle_diameter||a,extruder_id:e.extruder_id??0,slot_id:0}),s++,await new Promise(e=>setTimeout(e,500))}catch(t){console.error(`Failed to import profile:`,e.name,t)}t(e(`kProfiles.toast.importedProfiles`,{count:s,total:o.profiles.length})),L()}catch(n){console.error(`Import error:`,n),t(e(`kProfiles.toast.failedToParseImport`),`error`)}},n.click()},[r,a,t,L,e]),pe=(0,y.useCallback)(e=>{T(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},[]),me=(0,y.useCallback)(()=>{T(new Set(se.map(e=>A(e))))},[se,A]),he=(0,y.useCallback)(()=>{w.size!==0&&D(!0)},[w.size]),ge=(0,y.useCallback)(async()=>{let n=se.filter(e=>w.has(A(e)));k(!0);let i=0;for(let e of n)try{await Q.deleteKProfile(r,{slot_id:e.slot_id,extruder_id:e.extruder_id,nozzle_id:e.nozzle_id,nozzle_diameter:e.nozzle_diameter,filament_id:e.filament_id,setting_id:e.setting_id}),i++,await new Promise(e=>setTimeout(e,300))}catch(t){console.error(`Failed to delete profile:`,e.name,t)}t(e(`kProfiles.toast.profilesDeleted`,{count:i})),k(!1),D(!1),C(!1),T(new Set),L()},[r,w,se,t,L,A,e]),_e=(0,y.useCallback)(e=>{let t=[];return e.setting_id&&t.push(e.setting_id),t.push(`slot_${e.slot_id}_${e.filament_id}_${e.extruder_id}`),t.push(`name_${e.name}_${e.filament_id}`),t},[]),ve=(0,y.useCallback)(async(n,i)=>{if(r)try{await Q.setKProfileNote(r,n,i),ne()}catch(n){console.error(`Failed to save note:`,n),t(e(`kProfiles.toast.failedToSaveNote`),`error`)}},[r,ne,t,e]),ye=(0,y.useCallback)(e=>{if(!te?.notes)return{note:``,key:null};let t=_e(e);for(let e of t)if(te.notes[e])return{note:te.notes[e],key:e};return{note:``,key:null}},[te,_e]),be=(0,y.useCallback)(e=>ye(e).note,[ye]);return M?(0,K.jsx)(`div`,{className:`flex justify-center py-12`,children:(0,K.jsx)(X,{className:`w-8 h-8 text-bambu-green animate-spin`})}):!j||j.length===0?(0,K.jsx)(Od,{children:(0,K.jsxs)(Ad,{className:`py-12 text-center`,children:[(0,K.jsx)(hs,{className:`w-12 h-12 text-bambu-gray mx-auto mb-4`}),(0,K.jsx)(`h3`,{className:`text-lg font-semibold text-white mb-2`,children:e(`kProfiles.noPrintersConfigured`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray`,children:e(`kProfiles.addPrinterInSettings`)})]})}):ie.length===0?(0,K.jsx)(Od,{children:(0,K.jsxs)(Ad,{className:`py-12 text-center`,children:[(0,K.jsx)(Nl,{className:`w-12 h-12 text-bambu-gray mx-auto mb-4`}),(0,K.jsx)(`h3`,{className:`text-lg font-semibold text-white mb-2`,children:e(`kProfiles.noActivePrinters`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray`,children:e(`kProfiles.enablePrinterConnection`)})]})}):(0,K.jsxs)(K.Fragment,{children:[F&&!P&&(0,K.jsxs)(`div`,{className:`fixed inset-0 bg-black/50 flex flex-col items-center justify-center z-40`,children:[(0,K.jsx)(X,{className:`w-10 h-10 text-bambu-green animate-spin mb-3`}),(0,K.jsx)(`p`,{className:`text-white font-medium`,children:e(`kProfiles.loadingProfiles`)})]}),(0,K.jsxs)(`div`,{className:`flex flex-wrap gap-4 mb-6`,children:[(0,K.jsxs)(`div`,{className:`flex-1 min-w-48`,children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:e(`kProfiles.printer`)}),(0,K.jsx)(`select`,{value:r||``,onChange:e=>i(parseInt(e.target.value)),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:ie.map(e=>(0,K.jsx)(`option`,{value:e.id,children:e.name},e.id))})]}),(0,K.jsxs)(`div`,{className:`w-32`,children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:e(`kProfiles.nozzle`)}),(0,K.jsxs)(`select`,{value:a,onChange:e=>o(e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`0.2`,children:`0.2mm`}),(0,K.jsx)(`option`,{value:`0.4`,children:`0.4mm`}),(0,K.jsx)(`option`,{value:`0.6`,children:`0.6mm`}),(0,K.jsx)(`option`,{value:`0.8`,children:`0.8mm`})]})]}),(0,K.jsxs)(`div`,{className:`flex items-end gap-2`,children:[(0,K.jsxs)($,{variant:`secondary`,onClick:()=>L(),disabled:F||!n(`kprofiles:read`),title:n(`kprofiles:read`)?void 0:e(`kProfiles.permission.noRead`),children:[(0,K.jsx)(Il,{className:`w-4 h-4 ${F?`animate-spin`:``}`}),e(`kProfiles.refresh`)]}),(0,K.jsxs)($,{onClick:()=>u(!0),disabled:!n(`kprofiles:create`),title:n(`kprofiles:create`)?void 0:e(`kProfiles.permission.noCreate`),children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),e(`kProfiles.addProfile`)]})]})]}),(0,K.jsxs)(`div`,{className:`flex flex-wrap gap-4 mb-4`,children:[(0,K.jsxs)(`div`,{className:`flex-1 min-w-48 relative`,children:[(0,K.jsx)(Kl,{className:`absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray`}),(0,K.jsx)(`input`,{type:`text`,value:p,onChange:e=>m(e.target.value),placeholder:e(`kProfiles.searchPlaceholder`),className:`w-full pl-10 pr-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray focus:border-bambu-green focus:outline-none`})]}),le&&(0,K.jsx)(`div`,{className:`w-36`,children:(0,K.jsxs)(`select`,{value:h,onChange:e=>g(e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`all`,children:e(`kProfiles.allExtruders`)}),(0,K.jsx)(`option`,{value:`left`,children:e(`kProfiles.leftOnly`)}),(0,K.jsx)(`option`,{value:`right`,children:e(`kProfiles.rightOnly`)})]})}),ue&&(0,K.jsx)(`div`,{className:`w-32`,children:(0,K.jsxs)(`select`,{value:_,onChange:e=>v(e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`all`,children:e(`kProfiles.allFlow`)}),(0,K.jsx)(`option`,{value:`hf`,children:e(`kProfiles.hfOnly`)}),(0,K.jsx)(`option`,{value:`s`,children:e(`kProfiles.sOnly`)})]})}),(0,K.jsx)(`div`,{className:`w-32`,children:(0,K.jsxs)(`select`,{value:b,onChange:e=>x(e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`name`,children:e(`kProfiles.sortName`)}),(0,K.jsx)(`option`,{value:`k_value`,children:e(`kProfiles.sortKValue`)}),(0,K.jsx)(`option`,{value:`filament`,children:e(`kProfiles.sortFilament`)})]})})]}),(0,K.jsxs)(`div`,{className:`flex flex-wrap gap-2 mb-6`,children:[(0,K.jsxs)($,{variant:`secondary`,onClick:de,disabled:!N?.profiles?.length||!n(`kprofiles:read`),title:n(`kprofiles:read`)?void 0:e(`kProfiles.permission.noExport`),children:[(0,K.jsx)(Ks,{className:`w-4 h-4`}),e(`kProfiles.export`)]}),(0,K.jsxs)($,{variant:`secondary`,onClick:fe,disabled:!n(`kprofiles:create`),title:n(`kprofiles:create`)?void 0:e(`kProfiles.permission.noImport`),children:[(0,K.jsx)(Fu,{className:`w-4 h-4`}),e(`kProfiles.import`)]}),(0,K.jsx)(`div`,{className:`flex-1`}),S?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)($,{variant:`secondary`,onClick:me,children:[(0,K.jsx)(fu,{className:`w-4 h-4`}),e(`kProfiles.selectAll`)]}),(0,K.jsxs)($,{variant:`secondary`,onClick:he,disabled:w.size===0||!n(`kprofiles:delete`),className:`text-red-500 hover:bg-red-500/10`,title:n(`kprofiles:delete`)?void 0:e(`kProfiles.permission.noDelete`),children:[(0,K.jsx)(Ou,{className:`w-4 h-4`}),e(`kProfiles.delete`),` (`,w.size,`)`]}),(0,K.jsxs)($,{variant:`secondary`,onClick:()=>{C(!1),T(new Set)},children:[(0,K.jsx)(Yu,{className:`w-4 h-4`}),e(`common.cancel`)]})]}):(0,K.jsxs)($,{variant:`secondary`,onClick:()=>C(!0),disabled:!se.length||!n(`kprofiles:delete`),title:n(`kprofiles:delete`)?void 0:e(`kProfiles.permission.noDelete`),children:[(0,K.jsx)(fu,{className:`w-4 h-4`}),e(`kProfiles.select`)]})]}),P?(0,K.jsx)(`div`,{className:`flex justify-center py-12`,children:(0,K.jsx)(X,{className:`w-8 h-8 text-bambu-green animate-spin`})}):re?(0,K.jsx)(Od,{children:(0,K.jsxs)(Ad,{className:`py-12 text-center`,children:[(0,K.jsx)(Wu,{className:`w-12 h-12 text-bambu-gray mx-auto mb-4`}),(0,K.jsx)(`h3`,{className:`text-lg font-semibold text-white mb-2`,children:e(`kProfiles.printerOffline`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray mb-4`,children:e(`kProfiles.printerOfflineDesc`)}),(0,K.jsxs)($,{variant:`secondary`,onClick:()=>L(),children:[(0,K.jsx)(Il,{className:`w-4 h-4`}),e(`common.refresh`)]})]})}):se.length>0?le?(0,K.jsxs)(`div`,{className:`grid grid-cols-2 gap-4`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`text-sm font-medium text-bambu-gray mb-2 px-1`,children:e(`kProfiles.leftExtruder`)}),(0,K.jsx)(`div`,{className:`space-y-1`,children:se.filter(e=>e.extruder_id===1).map(e=>(0,K.jsx)(L6,{profile:e,onEdit:()=>c(e),onCopy:()=>f(e),selectionMode:S,isSelected:w.has(A(e)),onToggleSelect:()=>pe(A(e)),note:be(e)},A(e)))})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`text-sm font-medium text-bambu-gray mb-2 px-1`,children:e(`kProfiles.rightExtruder`)}),(0,K.jsx)(`div`,{className:`space-y-1`,children:se.filter(e=>e.extruder_id===0).map(e=>(0,K.jsx)(L6,{profile:e,onEdit:()=>c(e),onCopy:()=>f(e),selectionMode:S,isSelected:w.has(A(e)),onToggleSelect:()=>pe(A(e)),note:be(e)},A(e)))})]})]}):(0,K.jsx)(`div`,{className:`space-y-1`,children:se.map(e=>(0,K.jsx)(L6,{profile:e,onEdit:()=>c(e),onCopy:()=>f(e),selectionMode:S,isSelected:w.has(A(e)),onToggleSelect:()=>pe(A(e)),note:be(e)},A(e)))}):p||h!==`all`||_!==`all`?(0,K.jsx)(Od,{children:(0,K.jsxs)(Ad,{className:`py-12 text-center`,children:[(0,K.jsx)(Kl,{className:`w-12 h-12 text-bambu-gray mx-auto mb-4`}),(0,K.jsx)(`h3`,{className:`text-lg font-semibold text-white mb-2`,children:e(`kProfiles.noMatchingProfiles`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray`,children:e(`kProfiles.noMatchingProfilesDesc`)})]})}):(0,K.jsx)(Od,{children:(0,K.jsxs)(Ad,{className:`py-12 text-center`,children:[(0,K.jsx)(bc,{className:`w-12 h-12 text-bambu-gray mx-auto mb-4`}),(0,K.jsx)(`h3`,{className:`text-lg font-semibold text-white mb-2`,children:e(`kProfiles.noKProfiles`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray mb-4`,children:e(`kProfiles.noKProfilesDesc`,{diameter:a})}),(0,K.jsxs)($,{onClick:()=>u(!0),children:[(0,K.jsx)(Al,{className:`w-4 h-4`}),e(`kProfiles.createFirstProfile`)]})]})}),s&&r&&(()=>{let{note:e,key:t}=ye(s);return(0,K.jsx)(R6,{profile:s,printerId:r,nozzleDiameter:a,existingProfiles:N?.profiles,builtinFilaments:ae,filamentPresets:oe,isDualNozzle:le,supportsFlowType:ue,initialNote:e,initialNoteKey:t,onSaveNote:ve,hasPermission:n,onClose:()=>{console.log(`[KProfiles] Edit modal onClose - refetching profiles...`),c(null),L()},onSave:()=>{c(null),L()}})})(),l&&r&&(0,K.jsx)(R6,{printerId:r,nozzleDiameter:a,existingProfiles:N?.profiles,builtinFilaments:ae,filamentPresets:oe,isDualNozzle:le,supportsFlowType:ue,onSaveNote:ve,hasPermission:n,onClose:()=>{u(!1),L()},onSave:()=>{u(!1),L()}}),d&&r&&(0,K.jsx)(R6,{printerId:r,nozzleDiameter:a,existingProfiles:N?.profiles,builtinFilaments:ae,filamentPresets:oe,isDualNozzle:le,supportsFlowType:ue,onSaveNote:ve,hasPermission:n,profile:{...d,slot_id:0,name:`${d.name} (Copy)`},onClose:()=>{f(null),L()},onSave:()=>{f(null),L()}}),E&&(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4`,children:(0,K.jsx)(Od,{className:`w-full max-w-sm`,children:(0,K.jsxs)(Ad,{className:`p-6`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-3 mb-4`,children:[(0,K.jsx)(`div`,{className:`w-10 h-10 rounded-full bg-red-500/20 flex items-center justify-center`,children:(0,K.jsx)(Ou,{className:`w-5 h-5 text-red-500`})}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h3`,{className:`text-lg font-semibold text-white`,children:e(`kProfiles.bulkDelete.title`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:e(`kProfiles.bulkDelete.cannotUndo`)})]})]}),(0,K.jsx)(`p`,{className:`text-bambu-gray mb-6`,children:e(`kProfiles.bulkDelete.message`,{count:w.size})}),(0,K.jsxs)(`div`,{className:`flex gap-3`,children:[(0,K.jsx)($,{variant:`secondary`,onClick:()=>D(!1),disabled:O,className:`flex-1`,children:e(`common.cancel`)}),(0,K.jsxs)($,{onClick:ge,disabled:O,className:`flex-1 bg-red-500 hover:bg-red-600 text-white`,children:[O?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(Ou,{className:`w-4 h-4`}),e(`common.delete`)]})]})]})})})]})}var B6=[`PLA`,`PETG`,`PCTG`,`ABS`,`ASA`,`TPU`,`PC`,`PA`,`PVA`,`HIPS`,`PP`,`PET`,`NYLON`],uWe={PLA:`E8E8E8`,PETG:`4A90D9`,ABS:`E67E22`,ASA:`D35400`,TPU:`9B59B6`,PC:`BDC3C7`,PA:`2ECC71`,NYLON:`2ECC71`,PVA:`F1C40F`,HIPS:`95A5A6`,PP:`ECF0F1`,PET:`3498DB`};function dWe(e){let t=e.toUpperCase();for(let e of B6)if(RegExp(`\\b${e}\\b`).test(t))return e;return null}function fWe(e){let t=e.replace(/@.+$/,``).trim(),n=t.toUpperCase();for(let e of B6){let r=n.indexOf(e);if(r>0){let e=t.slice(0,r).trim();if(e&&e.length>1)return e}}return null}function V6({preset:e,onDelete:t,onExpand:n,isExpanded:r}){let{t:i}=W(),{hasPermission:a}=Sd(),o=e.filament_type||dWe(e.name),s=e.filament_vendor||fWe(e.name),c=null,l=!1;if(e.default_filament_colour)try{let t=JSON.parse(e.default_filament_colour),n=Array.isArray(t)?t[0]:t;typeof n==`string`&&/^#?[0-9a-fA-F]{6,8}$/.test(n.replace(`#`,``))&&(c=n.replace(`#`,``).slice(0,6),l=!0)}catch{let t=e.default_filament_colour;/^#?[0-9a-fA-F]{6,8}$/.test(t.replace(`#`,``))&&(c=t.replace(`#`,``).slice(0,6),l=!0)}return!c&&o&&(c=uWe[o.toUpperCase()]||null),(0,K.jsx)(Od,{className:`bg-bambu-dark border-bambu-dark-tertiary hover:border-bambu-dark-tertiary/80 transition-colors`,children:(0,K.jsxs)(Ad,{className:`p-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-start justify-between gap-2`,children:[(0,K.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 mb-1`,children:[e.preset_type===`filament`&&(0,K.jsx)(`div`,{className:`w-4 h-4 rounded-full border border-black/20 flex-shrink-0 ${!l&&!c?`opacity-25`:l?``:`opacity-50`}`,style:{backgroundColor:c?`#${c}`:`#666`}}),(0,K.jsx)(`span`,{className:`text-sm font-medium text-white truncate`,children:e.name})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 flex-wrap`,children:[o&&(0,K.jsx)(`span`,{className:`text-xs px-1.5 py-0.5 rounded bg-bambu-green/20 text-bambu-green`,children:o}),s&&(0,K.jsx)(`span`,{className:`text-xs text-bambu-gray`,children:s}),(0,K.jsx)(`span`,{className:`text-xs px-1.5 py-0.5 rounded bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400`,children:i(`profiles.localProfiles.badge`)})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-1 flex-shrink-0`,children:[a(`settings:update`)&&(0,K.jsx)(`button`,{onClick:()=>t(e.id),className:`p-1 text-bambu-gray hover:text-red-600 dark:hover:text-red-400 transition-colors`,title:i(`profiles.localProfiles.delete`),children:(0,K.jsx)(Ou,{className:`w-3.5 h-3.5`})}),(0,K.jsx)(`button`,{onClick:()=>n(r?null:e.id),className:`p-1 text-bambu-gray hover:text-white transition-colors`,children:r?(0,K.jsx)(fs,{className:`w-3.5 h-3.5`}):(0,K.jsx)(ls,{className:`w-3.5 h-3.5`})})]})]}),r&&(0,K.jsxs)(`div`,{className:`mt-3 pt-3 border-t border-bambu-dark-tertiary text-xs space-y-1.5`,children:[o&&(0,K.jsxs)(`div`,{className:`flex justify-between`,children:[(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:i(`profiles.localProfiles.filamentType`)}),(0,K.jsx)(`span`,{className:`text-white`,children:o})]}),s&&(0,K.jsxs)(`div`,{className:`flex justify-between`,children:[(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:i(`profiles.localProfiles.vendor`)}),(0,K.jsx)(`span`,{className:`text-white`,children:s})]}),e.nozzle_temp_min!=null&&e.nozzle_temp_max!=null&&(0,K.jsxs)(`div`,{className:`flex justify-between`,children:[(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:i(`profiles.localProfiles.nozzleTemp`)}),(0,K.jsxs)(`span`,{className:`text-white`,children:[e.nozzle_temp_min,`–`,e.nozzle_temp_max,`°C`]})]}),e.filament_cost&&(0,K.jsxs)(`div`,{className:`flex justify-between`,children:[(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:i(`profiles.localProfiles.cost`)}),(0,K.jsx)(`span`,{className:`text-white`,children:e.filament_cost})]}),e.filament_density&&(0,K.jsxs)(`div`,{className:`flex justify-between`,children:[(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:i(`profiles.localProfiles.density`)}),(0,K.jsxs)(`span`,{className:`text-white`,children:[e.filament_density,` g/cm³`]})]}),e.pressure_advance&&(0,K.jsxs)(`div`,{className:`flex justify-between`,children:[(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:i(`profiles.localProfiles.pressureAdvance`)}),(0,K.jsx)(`span`,{className:`text-white`,children:e.pressure_advance})]}),e.compatible_printers&&(0,K.jsxs)(`div`,{className:`flex justify-between`,children:[(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:i(`profiles.localProfiles.compatiblePrinters`)}),(0,K.jsx)(`span`,{className:`text-white truncate ml-2`,children:(()=>{try{return JSON.parse(e.compatible_printers).join(`, `)}catch{return e.compatible_printers}})()})]}),e.inherits&&e.inherits!==e.name&&(0,K.jsxs)(`div`,{className:`flex justify-between`,children:[(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:i(`profiles.localProfiles.inheritsFrom`)}),(0,K.jsx)(`span`,{className:`text-white truncate ml-2`,children:e.inherits})]}),(0,K.jsxs)(`div`,{className:`flex justify-between`,children:[(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:i(`profiles.localProfiles.source`)}),(0,K.jsx)(`span`,{className:`text-white capitalize`,children:e.source})]})]})]})})}function pWe(){let{t:e}=W(),{hasPermission:t}=Sd(),n=oo(),{showToast:r}=Id(),[i,a]=(0,y.useState)(``),[o,s]=(0,y.useState)(null),[c,l]=(0,y.useState)(!1),[u,d]=(0,y.useState)(null),{data:f,isLoading:p}=q({queryKey:[`localPresets`],queryFn:()=>Q.getLocalPresets()}),m=J({mutationFn:async e=>{let t=[];for(let n of Array.from(e)){let e=new FormData;e.append(`file`,n),t.push(await Q.importLocalPresets(e))}return t},onSuccess:t=>{n.invalidateQueries({queryKey:[`localPresets`]}),n.invalidateQueries({queryKey:[`slicerPresets`]});let i=0,a=0,o=0;for(let e of t)i+=e.imported,a+=e.skipped,o+=e.errors.length;i>0&&r(e(`profiles.localProfiles.toast.importSuccess`,{count:i})),a>0&&r(e(`profiles.localProfiles.toast.importSkipped`,{count:a}),`warning`),o>0&&r(e(`profiles.localProfiles.toast.importError`,{count:o}),`error`)},onError:e=>{r(e.message,`error`)}}),h=J({mutationFn:e=>Q.deleteLocalPreset(e),onSuccess:(t,i)=>{n.setQueryData([`localPresets`],e=>e&&{filament:e.filament.filter(e=>e.id!==i),printer:e.printer.filter(e=>e.id!==i),process:e.process.filter(e=>e.id!==i)}),n.invalidateQueries({queryKey:[`localPresets`]}),n.invalidateQueries({queryKey:[`slicerPresets`]}),d(null),r(e(`profiles.localProfiles.toast.deleted`))}}),g=(0,y.useCallback)(e=>{!e||e.length===0||m.mutate(e)},[m]),_=(0,y.useCallback)(e=>{e.preventDefault(),l(!1),g(e.dataTransfer.files)},[g]),v=(0,y.useCallback)(e=>{if(!i)return e;let t=i.toLowerCase();return e.filter(e=>e.name.toLowerCase().includes(t)||e.filament_type?.toLowerCase().includes(t)||e.filament_vendor?.toLowerCase().includes(t))},[i]),b=(0,y.useMemo)(()=>v(f?.filament||[]),[f?.filament,v]),x=(0,y.useMemo)(()=>v(f?.printer||[]),[f?.printer,v]),S=(0,y.useMemo)(()=>v(f?.process||[]),[f?.process,v]),C=b.length+x.length+S.length,w=(f?.filament?.length??0)+(f?.printer?.length??0)+(f?.process?.length??0)>0;return p?(0,K.jsx)(`div`,{className:`flex items-center justify-center py-16`,children:(0,K.jsx)(X,{className:`w-8 h-8 text-bambu-green animate-spin`})}):(0,K.jsxs)(`div`,{className:`space-y-6`,children:[t(`settings:update`)&&(0,K.jsxs)(`div`,{onDragOver:e=>{e.preventDefault(),l(!0)},onDragLeave:()=>l(!1),onDrop:_,className:`relative border-2 border-dashed rounded-lg p-6 text-center transition-colors ${c?`border-bambu-green bg-bambu-green/10`:`border-bambu-dark-tertiary hover:border-bambu-gray`}`,children:[(0,K.jsx)(`input`,{type:`file`,accept:`.json,.zip,.orca_filament,.bbscfg,.bbsflmt`,multiple:!0,className:`absolute inset-0 w-full h-full opacity-0 cursor-pointer`,onChange:e=>g(e.target.files)}),m.isPending?(0,K.jsxs)(`div`,{className:`flex items-center justify-center gap-2`,children:[(0,K.jsx)(X,{className:`w-5 h-5 text-bambu-green animate-spin`}),(0,K.jsx)(`span`,{className:`text-bambu-gray`,children:e(`profiles.localProfiles.importing`)})]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(Fu,{className:`w-8 h-8 text-bambu-gray mx-auto mb-2`}),(0,K.jsx)(`p`,{className:`text-sm text-white font-medium`,children:e(`profiles.localProfiles.import`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-1`,children:e(`profiles.localProfiles.importDesc`)})]})]}),w&&(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(Kl,{className:`absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray`}),(0,K.jsx)(`input`,{type:`text`,value:i,onChange:e=>a(e.target.value),placeholder:e(`profiles.localProfiles.search`),className:`w-full pl-9 pr-4 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-sm text-white placeholder-bambu-gray focus:outline-none focus:border-bambu-green`})]}),!w&&!p&&(0,K.jsxs)(`div`,{className:`text-center py-12`,children:[(0,K.jsx)(kc,{className:`w-12 h-12 text-bambu-gray mx-auto mb-3 opacity-50`}),(0,K.jsx)(`p`,{className:`text-bambu-gray`,children:e(`profiles.localProfiles.noPresets`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray/60 mt-1`,children:e(`profiles.localProfiles.importDesc`)})]}),w&&C===0&&!p&&(0,K.jsxs)(`div`,{className:`text-center py-12`,children:[(0,K.jsx)(Kl,{className:`w-12 h-12 text-bambu-gray mx-auto mb-3 opacity-50`}),(0,K.jsx)(`p`,{className:`text-bambu-gray`,children:e(`profiles.localProfiles.noSearchResults`)})]}),C>0&&(0,K.jsxs)(`div`,{className:`grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6`,children:[b.length>0&&(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 mb-3`,children:[(0,K.jsx)(qs,{className:`w-4 h-4 text-bambu-green`}),(0,K.jsx)(`h3`,{className:`text-sm font-medium text-white`,children:e(`profiles.localProfiles.filament`)}),(0,K.jsxs)(`span`,{className:`text-xs text-bambu-gray`,children:[`(`,b.length,`)`]})]}),(0,K.jsx)(`div`,{className:`space-y-2`,children:b.map(e=>(0,K.jsx)(V6,{preset:e,onDelete:e=>d(e),onExpand:s,isExpanded:o===e.id},e.id))})]}),S.length>0&&(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 mb-3`,children:[(0,K.jsx)(Uc,{className:`w-4 h-4 text-blue-600 dark:text-blue-400`}),(0,K.jsx)(`h3`,{className:`text-sm font-medium text-white`,children:e(`profiles.localProfiles.process`)}),(0,K.jsxs)(`span`,{className:`text-xs text-bambu-gray`,children:[`(`,S.length,`)`]})]}),(0,K.jsx)(`div`,{className:`space-y-2`,children:S.map(e=>(0,K.jsx)(V6,{preset:e,onDelete:e=>d(e),onExpand:s,isExpanded:o===e.id},e.id))})]}),x.length>0&&(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 mb-3`,children:[(0,K.jsx)(Xl,{className:`w-4 h-4 text-orange-600 dark:text-orange-400`}),(0,K.jsx)(`h3`,{className:`text-sm font-medium text-white`,children:e(`profiles.localProfiles.printer`)}),(0,K.jsxs)(`span`,{className:`text-xs text-bambu-gray`,children:[`(`,x.length,`)`]})]}),(0,K.jsx)(`div`,{className:`space-y-2`,children:x.map(e=>(0,K.jsx)(V6,{preset:e,onDelete:e=>d(e),onExpand:s,isExpanded:o===e.id},e.id))})]})]}),u!==null&&(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/50 flex items-center justify-center z-50`,children:(0,K.jsxs)(`div`,{className:`bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg p-6 max-w-sm mx-4`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 mb-3`,children:[(0,K.jsx)(hs,{className:`w-5 h-5 text-red-600 dark:text-red-400`}),(0,K.jsx)(`h3`,{className:`text-white font-medium`,children:e(`profiles.localProfiles.deleteConfirmTitle`)})]}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mb-4`,children:e(`profiles.localProfiles.deleteConfirm`)}),(0,K.jsxs)(`div`,{className:`flex justify-end gap-2`,children:[(0,K.jsx)($,{variant:`secondary`,size:`sm`,onClick:()=>d(null),children:e(`profiles.localProfiles.cancel`)}),(0,K.jsxs)($,{variant:`danger`,size:`sm`,onClick:()=>h.mutate(u),disabled:h.isPending,children:[h.isPending?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(Ou,{className:`w-4 h-4`}),e(`profiles.localProfiles.delete`)]})]})]})})]})}function mWe(e){let t=e.match(/@?\s*(?:BBL\s+)?(?:Bambu\s+Lab\s+)?([XPAH][1-9][A-Z]?(?:\s*(?:Carbon|mini))?|H2D)/i),n=e.match(/(\d+\.?\d*)\s*(?:mm\s*)?nozzle|nozzle\s*(\d+\.?\d*)/i),r=e.match(/(\d+\.?\d*)mm\s*(?:Standard|Fine|Extra Fine|Draft|Quality)?/i),i=e.match(/\b(PLA|PETG|ABS|ASA|TPU|PC|PA|PVA|HIPS|PP|PET(?:-?CF)?|PA(?:-?CF)?|PLA(?:-?CF)?)\b/i);return{printer:t?t[1].trim():null,nozzle:n?(n[1]||n[2])+`mm`:null,layerHeight:r?r[1]+`mm`:null,filamentType:i?i[1].toUpperCase():null}}function hWe({settings:e,lastSyncTime:t,onRefresh:n,isRefreshing:r,printers:i,t:a}){let[o,s]=(0,y.useState)(``),[c,l]=(0,y.useState)(`all`),[u,d]=(0,y.useState)(`all`),[f,p]=(0,y.useState)(`all`),[m,h]=(0,y.useState)(`all`),[g,_]=(0,y.useState)(`all`),[v,b]=(0,y.useState)(null),x=(0,y.useMemo)(()=>[...e.filament.map(e=>({...e,type:`filament`})),...e.printer.map(e=>({...e,type:`printer`})),...e.process.map(e=>({...e,type:`process`}))].map(e=>({...e,meta:mWe(e.name)})),[e]),S=(0,y.useMemo)(()=>{let e=new Set,t=new Set,n=new Set;return x.forEach(r=>{r.meta.nozzle&&e.add(r.meta.nozzle),r.meta.filamentType&&t.add(r.meta.filamentType),r.meta.layerHeight&&n.add(r.meta.layerHeight)}),{printers:i.map(e=>({id:e.id.toString(),name:e.name})),nozzles:Array.from(e).sort((e,t)=>parseFloat(e)-parseFloat(t)),filaments:Array.from(t).sort(),layerHeights:Array.from(n).sort((e,t)=>parseFloat(e)-parseFloat(t))}},[x,i]),C=(0,y.useMemo)(()=>u===`all`?null:i.find(e=>e.id.toString()===u)?.model||null,[u,i]),w=(0,y.useMemo)(()=>x.filter(e=>c===`all`||e.type===c).filter(e=>{if(u===`all`||!C)return!0;let t=e.meta.printer?.toLowerCase()||``,n=C.toLowerCase();return t.includes(n)||n.includes(t)}).filter(e=>f===`all`||e.meta.nozzle===f).filter(e=>m===`all`||e.meta.filamentType===m).filter(e=>g===`all`||e.meta.layerHeight===g).filter(e=>o===``||e.name.toLowerCase().includes(o.toLowerCase())).sort((e,t)=>e.name.localeCompare(t.name)),[x,c,u,C,f,m,g,o]),T=()=>{l(`all`),d(`all`),p(`all`),h(`all`),_(`all`),s(``)},E=c!==`all`||u!==`all`||f!==`all`||m!==`all`||g!==`all`||o!==``,D=e.filament.length+e.printer.length+e.process.length,O=e=>w.filter(t=>t.type===e);return(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{className:`space-y-4 mb-6`,children:[(0,K.jsxs)(`div`,{className:`flex flex-col sm:flex-row gap-3`,children:[(0,K.jsxs)(`div`,{className:`relative flex-1`,children:[(0,K.jsx)(Kl,{className:`absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray`}),(0,K.jsx)(`input`,{type:`text`,value:o,onChange:e=>s(e.target.value),placeholder:a(`profiles.cloudView.searchPlaceholder`),className:`w-full pl-10 pr-4 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray-dark focus:border-bambu-green focus:outline-none`})]}),(0,K.jsx)(`div`,{className:`flex gap-2`,children:(0,K.jsxs)($,{variant:`secondary`,onClick:n,disabled:r,children:[(0,K.jsx)(Il,{className:`w-4 h-4 ${r?`animate-spin`:``}`}),a(`profiles.cloudView.refresh`)]})})]}),(0,K.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,K.jsx)(yc,{className:`w-4 h-4 text-bambu-gray`}),(0,K.jsx)(G6,{label:a(`profiles.cloudView.filters.type`),value:c,options:[{value:`all`,label:a(`profiles.cloudView.filters.all`),count:D},{value:`filament`,label:a(`profiles.cloudView.filters.filament`),count:e.filament.length},{value:`printer`,label:a(`profiles.cloudView.filters.printer`),count:e.printer.length},{value:`process`,label:a(`profiles.cloudView.filters.process`),count:e.process.length}],onChange:e=>l(e)}),S.printers.length>0&&(0,K.jsx)(G6,{label:a(`profiles.cloudView.filters.printer`),value:u,options:[{value:`all`,label:a(`profiles.cloudView.filters.all`)},...S.printers.map(e=>({value:e.id,label:e.name}))],onChange:d}),S.nozzles.length>0&&(0,K.jsx)(G6,{label:a(`profiles.cloudView.filters.nozzle`),value:f,options:[{value:`all`,label:a(`profiles.cloudView.filters.all`)},...S.nozzles.map(e=>({value:e,label:e}))],onChange:p}),S.filaments.length>0&&(c===`all`||c===`filament`)&&(0,K.jsx)(G6,{label:a(`profiles.cloudView.filters.filament`),value:m,options:[{value:`all`,label:a(`profiles.cloudView.filters.all`)},...S.filaments.map(e=>({value:e,label:e}))],onChange:h}),S.layerHeights.length>0&&(c===`all`||c===`process`)&&(0,K.jsx)(G6,{label:a(`profiles.cloudView.filters.layer`),value:g,options:[{value:`all`,label:a(`profiles.cloudView.filters.all`)},...S.layerHeights.map(e=>({value:e,label:e}))],onChange:_}),E&&(0,K.jsx)(`button`,{onClick:T,className:`px-3 py-2 text-sm text-bambu-gray hover:text-white transition-colors`,children:a(`profiles.cloudView.clearFilters`)})]})]}),(0,K.jsxs)(`div`,{className:`flex flex-wrap items-center gap-4 mb-4 text-sm text-bambu-gray`,children:[t&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,K.jsx)(Es,{className:`w-3 h-3`}),a(`profiles.cloudView.lastSynced`),` `,Bf(t.toISOString(),`system`,a)]}),(0,K.jsx)(`span`,{children:a(`profiles.cloudView.showingCount`,{showing:w.length,total:D})})]}),w.length===0?(0,K.jsxs)(`div`,{className:`text-center py-16`,children:[(0,K.jsx)(Uc,{className:`w-12 h-12 text-bambu-gray-dark mx-auto mb-4`}),(0,K.jsx)(`p`,{className:`text-bambu-gray`,children:a(`profiles.cloudView.noPresetsFound`)}),E&&(0,K.jsx)(`button`,{onClick:T,className:`mt-2 text-sm text-bambu-green hover:text-bambu-green-light`,children:a(`profiles.cloudView.clearFilters`)})]}):(0,K.jsxs)(`div`,{className:`grid grid-cols-1 md:grid-cols-3 gap-6`,children:[(0,K.jsx)(H6,{icon:(0,K.jsx)(qs,{className:`w-4 h-4 text-amber-600 dark:text-amber-400`}),title:a(`profiles.cloudView.columns.filament`),presets:O(`filament`),emptyText:a(`profiles.cloudView.noFilamentPresets`),onSelect:b}),(0,K.jsx)(H6,{icon:(0,K.jsx)(Xl,{className:`w-4 h-4 text-blue-600 dark:text-blue-400`}),title:a(`profiles.cloudView.columns.process`),presets:O(`process`),emptyText:a(`profiles.cloudView.noProcessPresets`),onSelect:b}),(0,K.jsx)(H6,{icon:(0,K.jsx)(Nl,{className:`w-4 h-4 text-purple-600 dark:text-purple-400`}),title:a(`profiles.cloudView.columns.printer`),presets:O(`printer`),emptyText:a(`profiles.cloudView.noPrinterPresets`),onSelect:b})]}),v&&(0,K.jsx)(_We,{setting:v,onClose:()=>b(null),t:a})]})}function H6({icon:e,title:t,presets:n,emptyText:r,onSelect:i}){return(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 mb-3 px-1`,children:[e,(0,K.jsx)(`h3`,{className:`text-sm font-medium text-bambu-gray`,children:t}),(0,K.jsxs)(`span`,{className:`text-xs text-bambu-gray-dark`,children:[`(`,n.length,`)`]})]}),(0,K.jsx)(`div`,{className:`space-y-1 max-h-[calc(100vh-320px)] overflow-y-auto pr-1`,children:n.length===0?(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray-dark px-3 py-2`,children:r}):n.map(e=>(0,K.jsx)(gWe,{preset:e,onClick:()=>i(e)},e.setting_id))})]})}function gWe({preset:e,onClick:t}){return(0,K.jsx)(`button`,{onClick:t,className:`w-full text-left px-3 py-2 rounded bg-bambu-dark hover:bg-bambu-dark-tertiary transition-colors`,children:(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`span`,{className:`text-white text-sm truncate flex-1`,title:e.name,children:e.name}),e.meta.filamentType&&e.type===`filament`&&(0,K.jsx)(`span`,{className:`text-xs text-bambu-gray whitespace-nowrap`,children:e.meta.filamentType}),e.meta.layerHeight&&e.type===`process`&&(0,K.jsx)(`span`,{className:`text-xs text-bambu-gray whitespace-nowrap`,children:e.meta.layerHeight}),e.meta.printer&&(0,K.jsx)(`span`,{className:`text-xs text-bambu-gray whitespace-nowrap`,children:e.meta.printer})]})})}function _We({setting:e,onClose:t,t:n}){let{data:r,isLoading:i,error:a}=q({queryKey:[`orcaCloudProfileDetail`,e.setting_id],queryFn:()=>Q.orcaCloudGetProfile(e.setting_id),retry:!1});return(0,K.jsx)(`div`,{className:`fixed inset-0 bg-black/60 z-50 flex items-center justify-center p-4`,onClick:t,children:(0,K.jsxs)(`div`,{className:`bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg shadow-2xl max-w-4xl w-full max-h-[90vh] flex flex-col`,onClick:e=>e.stopPropagation(),children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between p-4 border-b border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h2`,{className:`text-lg font-bold text-white`,children:e.name}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mt-0.5`,children:e.type})]}),(0,K.jsx)(`button`,{onClick:t,className:`text-bambu-gray hover:text-white p-1`,children:(0,K.jsx)(Yu,{className:`w-5 h-5`})})]}),(0,K.jsx)(`div`,{className:`flex-1 overflow-y-auto p-4`,children:i?(0,K.jsx)(`div`,{className:`flex items-center justify-center py-16`,children:(0,K.jsx)(X,{className:`w-8 h-8 text-bambu-green animate-spin`})}):a?(0,K.jsx)(`p`,{className:`text-center text-bambu-gray py-16`,children:a.message}):r?(0,K.jsx)(`pre`,{className:`text-xs font-mono text-bambu-gray bg-bambu-dark p-3 rounded overflow-x-auto whitespace-pre`,children:JSON.stringify(r.setting,null,2)}):(0,K.jsx)(`p`,{className:`text-center text-bambu-gray py-16`,children:n(`profiles.cloudView.noPresetsFound`)})})]})})}function vWe(){let{t:e}=W(),t=oo(),{showToast:n}=Id(),{hasPermission:r}=Sd(),i=r(`orca_cloud:auth`),[a,o]=(0,y.useState)(null),[s,c]=(0,y.useState)(5e3),[l,u]=(0,y.useState)(null),{data:d,isLoading:f}=q({queryKey:[`orcaCloudStatus`],queryFn:Q.orcaCloudStatus}),p=!!d?.connected,{data:m,isLoading:h,refetch:g,isRefetching:_,error:v,dataUpdatedAt:b}=q({queryKey:[`orcaCloudProfiles`],queryFn:Q.orcaCloudListProfiles,enabled:p,retry:!1,staleTime:1e3*60*5}),{data:x=[]}=q({queryKey:[`printers`],queryFn:Q.getPrinters,enabled:p}),[S,C]=(0,y.useState)();(0,y.useEffect)(()=>{b&&C(new Date(b))},[b]);let w=()=>{o(null),c(5e3)},T=t=>{t===`access_denied`?u(e(`profiles.orcaCloud.errors.denied`)):t===`expired_token`&&u(e(`profiles.orcaCloud.errors.expired`)),w()},E=J({mutationFn:Q.orcaCloudDeviceStart,onSuccess:e=>{u(null),c(Math.max(1,e.interval)*1e3),o(e)},onError:t=>{u(t.message||e(`profiles.orcaCloud.errors.startFailed`))}}),D=J({mutationFn:Q.orcaCloudLogout,onSuccess:()=>{t.invalidateQueries({queryKey:[`orcaCloudStatus`]}),t.removeQueries({queryKey:[`orcaCloudProfiles`]}),n(e(`profiles.orcaCloud.toast.disconnected`))}}),{data:O,error:k}=q({queryKey:[`orcaCloudDevicePoll`,a?.user_code??`none`],queryFn:Q.orcaCloudDevicePoll,enabled:a!==null,gcTime:0,retry:!1,refetchOnWindowFocus:!1,refetchInterval:a===null?!1:s}),A=(0,y.useRef)(null);return(0,y.useEffect)(()=>{if(!a||!O)return;let r=O.status;if(r===`slow_down`){c(e=>e+5e3);return}r!==`authorization_pending`&&A.current!==r&&(A.current=r,r===`complete`?(w(),t.invalidateQueries({queryKey:[`orcaCloudStatus`]}),t.invalidateQueries({queryKey:[`orcaCloudProfiles`]}),n(e(`profiles.orcaCloud.connectedShort`))):T(r))},[O,a]),(0,y.useEffect)(()=>{a&&k&&(u(e(`profiles.orcaCloud.errors.pollFailed`)),w())},[k,a]),(0,y.useEffect)(()=>{a&&(A.current=null)},[a]),f?(0,K.jsx)(`div`,{className:`flex items-center justify-center py-16`,children:(0,K.jsx)(X,{className:`w-8 h-8 text-bambu-green animate-spin`})}):(0,K.jsxs)(`div`,{children:[p&&(0,K.jsxs)(`div`,{className:`flex items-center justify-between p-3 mb-6 bg-bambu-dark rounded-lg border border-bambu-dark-tertiary`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,K.jsx)(`div`,{className:`w-2 h-2 rounded-full bg-bambu-green animate-pulse`}),(0,K.jsx)(`span`,{className:`text-sm text-bambu-gray`,children:d?.email?(0,K.jsxs)(K.Fragment,{children:[e(`profiles.orcaCloud.connectedAs`),` `,(0,K.jsx)(`span`,{className:`text-white`,children:d.email})]}):(0,K.jsx)(`span`,{className:`text-white`,children:e(`profiles.orcaCloud.connectedShort`)})})]}),(0,K.jsxs)($,{variant:`secondary`,size:`sm`,onClick:()=>D.mutate(),disabled:D.isPending||!i,title:i?void 0:e(`profiles.orcaCloud.noLogoutPermission`),children:[(0,K.jsx)(el,{className:`w-4 h-4`}),e(`profiles.orcaCloud.logout`)]})]}),p?h?(0,K.jsx)(`div`,{className:`flex items-center justify-center py-16`,children:(0,K.jsx)(X,{className:`w-8 h-8 text-bambu-green animate-spin`})}):v?(0,K.jsxs)(`div`,{className:`text-center py-16`,children:[(0,K.jsx)(`p`,{className:`text-bambu-gray mb-4`,children:v.message}),(0,K.jsx)($,{onClick:()=>g(),children:e(`profiles.orcaCloud.retry`)})]}):m?(0,K.jsx)(hWe,{settings:m,lastSyncTime:S,onRefresh:()=>g(),isRefreshing:_,printers:x,t:e}):null:(0,K.jsx)(yWe,{pairing:a,connectError:l,onConnect:()=>E.mutate(),onCancel:w,isStarting:E.isPending,canManage:i,t:e})]})}function yWe({pairing:e,connectError:t,onConnect:n,onCancel:r,isStarting:i,canManage:a,t:o}){return e?(0,K.jsx)(Od,{children:(0,K.jsxs)(Ad,{className:`p-8 text-center max-w-md mx-auto`,children:[(0,K.jsx)(ks,{className:`w-12 h-12 text-bambu-green mx-auto mb-4`}),(0,K.jsx)(`h2`,{className:`text-xl font-bold text-white mb-2`,children:o(`profiles.orcaCloud.device.title`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray mb-6`,children:o(`profiles.orcaCloud.device.instruction`)}),(0,K.jsx)(`p`,{className:`text-xs uppercase tracking-wide text-bambu-gray mb-2`,children:o(`profiles.orcaCloud.device.codeLabel`)}),(0,K.jsx)(`div`,{className:`mb-6 py-3 px-4 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg`,children:(0,K.jsx)(`span`,{className:`text-2xl font-mono font-bold tracking-[0.3em] text-white select-all`,children:e.user_code})}),(0,K.jsx)(`a`,{href:e.verification_uri_complete,target:`_blank`,rel:`noopener noreferrer`,children:(0,K.jsxs)($,{className:`w-full mb-3`,children:[(0,K.jsx)($s,{className:`w-4 h-4`}),o(`profiles.orcaCloud.device.openButton`)]})}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray break-all mb-6`,children:o(`profiles.orcaCloud.device.manualHint`,{url:e.verification_uri})}),(0,K.jsxs)(`div`,{className:`flex items-center justify-center gap-2 text-sm text-bambu-gray mb-4`,children:[(0,K.jsx)(X,{className:`w-4 h-4 animate-spin text-bambu-green`}),o(`profiles.orcaCloud.device.waiting`)]}),(0,K.jsx)(`button`,{type:`button`,onClick:r,className:`text-bambu-gray hover:text-white text-sm`,children:o(`profiles.orcaCloud.device.cancel`)})]})}):(0,K.jsx)(Od,{children:(0,K.jsxs)(Ad,{className:`p-8 text-center`,children:[(0,K.jsx)(ks,{className:`w-12 h-12 text-bambu-green mx-auto mb-4`}),(0,K.jsx)(`h2`,{className:`text-xl font-bold text-white mb-2`,children:o(`profiles.orcaCloud.connect.title`)}),(0,K.jsx)(`p`,{className:`text-bambu-gray mb-6 max-w-xl mx-auto`,children:o(`profiles.orcaCloud.connect.description`)}),(0,K.jsxs)(`div`,{className:`max-w-sm mx-auto`,children:[(0,K.jsxs)($,{onClick:n,disabled:i||!a,title:a?void 0:o(`profiles.orcaCloud.noConnectPermission`),className:`w-full`,children:[i?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)(cs,{className:`w-4 h-4`}),o(`profiles.orcaCloud.connectButton`)]}),t&&(0,K.jsxs)(`p`,{className:`mt-3 text-sm text-red-700 dark:text-red-400 flex items-center justify-center gap-2`,children:[(0,K.jsx)(hs,{className:`w-4 h-4 flex-shrink-0`}),t]})]})]})})}function U6(e,t){let n=`${e} ${t||``}`,r=n.match(/@?\s*(?:BBL\s+)?(?:Bambu\s+Lab\s+)?([XPAH][1-9][A-Z]?(?:\s*(?:Carbon|mini))?|H2D)/i),i=r?r[1].trim():null,a=n.match(/(\d+\.?\d*)\s*(?:mm\s*)?nozzle|nozzle\s*(\d+\.?\d*)/i),o=a?(a[1]||a[2])+`mm`:null,s=n.match(/(\d+\.?\d*)mm\s*(?:Standard|Fine|Extra Fine|Draft|Quality)?/i),c=s?s[1]+`mm`:null,l=n.match(/\b(PLA|PETG|ABS|ASA|TPU|PC|PA|PVA|HIPS|PP|PET(?:-?CF)?|PA(?:-?CF)?|PLA(?:-?CF)?)\b/i);return{printer:i,nozzle:o,layerHeight:c,filamentType:l?l[1].toUpperCase():null}}function W6(e){return/^(P[FPM]US|PF\d|PP\d)/.test(e)}function bWe({onSuccess:e,t}){let{showToast:n}=Id(),[r,i]=(0,y.useState)(`email`),[a,o]=(0,y.useState)(``),[s,c]=(0,y.useState)(``),[l,u]=(0,y.useState)(``),[d,f]=(0,y.useState)(``),[p,m]=(0,y.useState)(`global`),[h,g]=(0,y.useState)(null),[_,v]=(0,y.useState)(null),b=J({mutationFn:()=>Q.cloudLogin(a,s,p),onSuccess:r=>{r.success?(n(t(`profiles.login.toast.loggedIn`)),e()):r.needs_verification?(g(r.verification_type||`email`),v(r.tfa_key||null),r.verification_type===`totp`?n(t(`profiles.login.toast.enterTotp`)):n(t(`profiles.login.toast.codeSent`)),i(`code`)):n(r.message,`error`)},onError:e=>n(e.message,`error`)}),x=J({mutationFn:()=>Q.cloudVerify(a,l,_||void 0,p),onSuccess:r=>{r.success?(n(t(`profiles.login.toast.loggedIn`)),e()):n(r.message,`error`)},onError:e=>n(e.message,`error`)}),S=J({mutationFn:()=>Q.cloudSetToken(d,p),onSuccess:()=>{n(t(`profiles.login.toast.tokenSet`)),e()},onError:e=>n(e.message,`error`)}),C=e=>{e.preventDefault(),r===`email`?b.mutate():r===`code`?x.mutate():r===`token`&&S.mutate()},w=b.isPending||x.isPending||S.isPending;return(0,K.jsx)(Od,{className:`max-w-md mx-auto`,children:(0,K.jsxs)(Ad,{children:[(0,K.jsxs)(`div`,{className:`text-center mb-6`,children:[(0,K.jsx)(`div`,{className:`inline-flex items-center justify-center w-12 h-12 rounded-xl bg-bambu-green/20 mb-3`,children:(0,K.jsx)(ks,{className:`w-6 h-6 text-bambu-green`})}),(0,K.jsx)(`h2`,{className:`text-xl font-semibold text-white`,children:t(`profiles.login.title`)}),(0,K.jsx)(`p`,{className:`text-sm text-bambu-gray mt-1`,children:t(`profiles.login.subtitle`)})]}),(0,K.jsxs)(`form`,{onSubmit:C,className:`space-y-4`,children:[r===`email`&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:t(`profiles.login.email`)}),(0,K.jsx)(`input`,{type:`email`,value:a,onChange:e=>o(e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray-dark focus:border-bambu-green focus:outline-none`,placeholder:`your@email.com`,required:!0})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:t(`profiles.login.password`)}),(0,K.jsx)(`input`,{type:`password`,value:s,onChange:e=>c(e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white placeholder-bambu-gray-dark focus:border-bambu-green focus:outline-none`,placeholder:`••••••••`,required:!0})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:t(`profiles.login.region`)}),(0,K.jsxs)(`select`,{value:p,onChange:e=>m(e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`global`,children:t(`profiles.login.regionGlobal`)}),(0,K.jsx)(`option`,{value:`china`,children:t(`profiles.login.regionChina`)})]})]})]}),r===`code`&&(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:t(h===`totp`?`profiles.login.totpCode`:`profiles.login.verificationCode`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mb-2`,children:h===`totp`?t(`profiles.login.enterTotpHint`):t(`profiles.login.checkEmail`,{email:a})}),(0,K.jsx)(`input`,{type:`text`,value:l,onChange:e=>u(e.target.value.replace(/\D/g,``).slice(0,6)),className:`w-full px-3 py-3 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-center text-2xl tracking-widest font-mono focus:border-bambu-green focus:outline-none`,placeholder:`000000`,maxLength:6,required:!0})]}),r===`token`&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:t(`profiles.login.accessToken`)}),(0,K.jsx)(`p`,{className:`text-xs text-bambu-gray mb-2`,children:t(`profiles.login.accessTokenHint`)}),(0,K.jsx)(`textarea`,{value:d,onChange:e=>f(e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-xs font-mono placeholder-bambu-gray-dark focus:border-bambu-green focus:outline-none resize-none`,placeholder:`eyJ...`,rows:4,required:!0})]}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`block text-sm text-bambu-gray mb-1`,children:t(`profiles.login.region`)}),(0,K.jsxs)(`select`,{value:p,onChange:e=>m(e.target.value),className:`w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none`,children:[(0,K.jsx)(`option`,{value:`global`,children:t(`profiles.login.regionGlobal`)}),(0,K.jsx)(`option`,{value:`china`,children:t(`profiles.login.regionChina`)})]})]})]}),(0,K.jsxs)(`div`,{className:`flex gap-2 max-[550px]:flex-wrap max-[550px]:items-center`,children:[r===`code`&&(0,K.jsx)($,{type:`button`,variant:`secondary`,onClick:()=>i(`email`),className:`flex-1`,children:t(`profiles.login.back`)}),(0,K.jsxs)($,{type:`submit`,disabled:w,className:`flex-1`,children:[w?(0,K.jsx)(X,{className:`w-4 h-4 animate-spin`}):(0,K.jsx)($c,{className:`w-4 h-4`}),t(r===`email`?`profiles.login.loginButton`:r===`code`?`profiles.login.verifyButton`:`profiles.login.setTokenButton`)]})]}),r===`email`&&(0,K.jsx)(`div`,{className:`pt-4 border-t border-bambu-dark-tertiary`,children:(0,K.jsxs)(`button`,{type:`button`,onClick:()=>i(`token`),className:`text-sm text-bambu-gray hover:text-white flex items-center gap-2 transition-colors`,children:[(0,K.jsx)(Vc,{className:`w-4 h-4`}),t(`profiles.login.useToken`)]})}),r===`token`&&(0,K.jsx)(`div`,{className:`pt-4 border-t border-bambu-dark-tertiary`,children:(0,K.jsxs)(`button`,{type:`button`,onClick:()=>i(`email`),className:`text-sm text-bambu-gray hover:text-white flex items-center gap-2 transition-colors`,children:[(0,K.jsx)($c,{className:`w-4 h-4`}),t(`profiles.login.useEmail`)]})})]})]})})}function G6({label:e,value:t,options:n,onChange:r}){let[i,a]=(0,y.useState)(!1),o=n.find(e=>e.value===t);return(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsxs)(`button`,{onClick:()=>a(!i),className:`flex items-center gap-2 px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-sm text-white hover:border-bambu-gray-dark transition-colors`,children:[(0,K.jsxs)(`span`,{className:`text-bambu-gray`,children:[e,`:`]}),(0,K.jsx)(`span`,{children:o?.label||`All`}),(0,K.jsx)(ls,{className:`w-4 h-4 text-bambu-gray transition-transform ${i?`rotate-180`:``}`})]}),i&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`div`,{className:`fixed inset-0 z-10`,onClick:()=>a(!1)}),(0,K.jsx)(`div`,{className:`absolute top-full left-0 mt-1 min-w-[160px] bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg shadow-xl z-20 py-1 max-h-60 overflow-y-auto`,children:n.map(e=>(0,K.jsxs)(`button`,{onClick:()=>{r(e.value),a(!1)},className:`w-full px-3 py-2 text-left text-sm flex items-center justify-between hover:bg-bambu-dark-tertiary transition-colors ${t===e.value?`text-bambu-green`:`text-white`}`,children:[(0,K.jsx)(`span`,{children:e.label}),e.count!==void 0&&(0,K.jsx)(`span`,{className:`text-bambu-gray text-xs`,children:e.count})]},e.value))})]})]})}function xWe(){let[e,t]=(0,y.useState)(!1);return(0,y.useEffect)(()=>{let e=()=>{t(window.scrollY>300)};return window.addEventListener(`scroll`,e),()=>window.removeEventListener(`scroll`,e)},[]),e?(0,K.jsx)(`button`,{onClick:()=>{window.scrollTo({top:0,behavior:`smooth`})},className:`fixed bottom-6 right-6 p-3 bg-bambu-green hover:bg-bambu-green-light text-white rounded-full shadow-lg shadow-bambu-green/25 transition-all z-40`,"aria-label":`Scroll to top`,children:(0,K.jsx)(Bo,{className:`w-5 h-5`})}):null}function K6({setting:e,onClick:t,onDuplicate:n,compareMode:r,isCompareSelected:i,compareIndex:a,compareDisabled:o,t:s}){let c=U6(e.name),l=W6(e.setting_id);return(0,K.jsxs)(`div`,{className:`flex items-center gap-2 group`,children:[(0,K.jsx)(`button`,{onClick:t,disabled:o,className:`flex-1 text-left px-3 py-2 rounded transition-colors ${i?`bg-blue-500/20 border border-blue-500/50`:o?`bg-bambu-dark/50 opacity-40 cursor-not-allowed`:`bg-bambu-dark hover:bg-bambu-dark-tertiary`} ${r&&!o?`cursor-pointer`:``}`,children:(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[i&&a!==void 0&&(0,K.jsx)(`span`,{className:`flex-shrink-0 w-5 h-5 rounded-full bg-blue-500 text-white text-xs flex items-center justify-center font-medium`,children:a+1}),!i&&l&&(0,K.jsx)(`span`,{className:`flex-shrink-0 w-1.5 h-1.5 rounded-full bg-bambu-green`,title:s(`profiles.presets.myPreset`)}),(0,K.jsx)(`span`,{className:`text-white text-sm truncate flex-1`,title:e.name,children:e.name}),c.filamentType&&e.type===`filament`&&(0,K.jsx)(`span`,{className:`text-xs text-bambu-gray whitespace-nowrap`,children:c.filamentType}),c.layerHeight&&e.type===`process`&&(0,K.jsx)(`span`,{className:`text-xs text-bambu-gray whitespace-nowrap`,children:c.layerHeight}),c.printer&&(0,K.jsx)(`span`,{className:`text-xs text-bambu-gray whitespace-nowrap`,children:c.printer})]})}),(0,K.jsx)(`button`,{onClick:e=>{e.stopPropagation(),n()},className:`opacity-0 group-hover:opacity-100 text-bambu-gray hover:text-white transition-all p-1`,title:s(`profiles.presets.duplicate`),children:(0,K.jsx)(Ls,{className:`w-4 h-4`})})]})}function q6(e,t=0){let n=` `.repeat(t);if(e===null)return`null`;if(e===void 0)return`undefined`;if(typeof e==`string`){if(e.includes(`\\n`)||e.includes(` `)){let t=e.replace(/\\n/g,` `).replace(/\\"/g,`"`).replace(/\\t/g,` `).split(` `);if(t.length>1)return`""" diff --git a/static/index.html b/static/index.html index e223fce96..a29603fc7 100644 --- a/static/index.html +++ b/static/index.html @@ -26,7 +26,7 @@ - + From 9259763179cc72dfb397bd5d54344c3f2a3facb0 Mon Sep 17 00:00:00 2001 From: maziggy Date: Sat, 1 Aug 2026 12:53:37 +0200 Subject: [PATCH 25/25] Updated README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1a281c22e..f287b8f53 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@

Your printers. No cloud. Your rules.
- Self-hosted command center for Bambu Lab — from one A1 to a 40-printer farm. + Self-hosted command center for Bambu Lab — from one A1 to an entire print farm.