Files
bambuddy/frontend
maziggy 5bbb6a73cc fix(kprofiles): populate the filament picker from all preset tiers (issue #2719)
Add K-Profile built its Filament dropdown from the profiles already on
    the printer, so on a printer with none the field was empty, required
    and unsatisfiable (#2719, reporter @jmoore-skild). The modal's own
    hint described the dead end: create the profile in Bambu Studio first.

    The dropdown now uses the app-wide lookup order -- local imported,
    Orca Cloud, Bambu Cloud, hardcoded built-in table -- same as the AMS
    slot picker and the SliceModal tier groups. The built-in table is
    compiled into the backend, so the list can never be empty: a new
    printer with no cloud account and nothing imported still gets a first
    profile.

    Not fixed the way the report suggested. Seeding from
    /printers/available-filaments would have offered only what happens to
    be in an AMS right now, which on the reported printer is nothing; its
    tray_info_idx is empty or a cloud user preset rather than a filament
    id; it aggregates across every printer of the same model; and it is
    gated on QUEUE_CREATE, which the K-Profiles page does not hold.

    The printer indexes its calibration table by filament_id, so the
    picked preset is reduced to one before anything is sent. Built-in
    entries and Bambu official cloud presets carry one; a cloud user
    preset needs its detail fetched (never base_id -- that collapses a
    custom preset onto its inherited generic, #1053); imported and Orca
    presets have no Bambu id at all and take the closest generic for
    their material, via the same table the AMS slot configure flow uses
    so the two agree. A filament that resolves to nothing is refused with
    a named error rather than written under a wrong id.

    Collapses duplicates from two separate causes. A cloud account
    carries one copy of each filament per printer model, and with the
    "@BBL <model>" suffix stripped for display those rows are
    indistinguishable -- deduped within each tier by resolved filament id,
    by display name for user presets that have none. Cloud setting_ids
    also carry a "_NN" variant suffix, so the built-in tier's
    already-covered check never matched and listed the same filament
    again; the bare id is now recorded alongside.

    Groups the options by source with an optgroup per tier, styled in
    index.css: browsers render optgroup labels small, grey and italic,
    which buries the one thing distinguishing a "Bambu PLA Basic" you
    imported from the one the built-in table ships.

    Drops the second getKProfiles(printer, "0.4") query that existed only
    to seed the old dropdown. It ran concurrently with the main fetch
    whenever a non-0.4mm nozzle was selected -- the two-requests-in-flight
    case that made K-profile fetches time out.

    ---

    fix(ui): cancel a dialog's deferred close when it unmounts

    The AMS slot configure and K-Profile dialogs hold a success state
    briefly and then close themselves -- 1.5s to 4s after the command
    goes out, so the printer has time to process it before the list
    refetches. Each did that with a bare setTimeout closing over setState
    and the parent's onClose, and nothing cancelled it.

    The timer therefore ran whether or not the dialog was still there.
    Dismissing it inside that window, or the printer card re-rendering
    underneath it, left a pending close that fired later and dismissed
    whatever dialog was open by then. It also threw outright when the
    surrounding environment was gone first: a test tearing down its DOM
    before the 1.5s elapsed produced "ReferenceError: window is not
    defined" out of react-dom's resolveUpdatePriority, reported as an
    unhandled error against a suite that otherwise passed.

    Routes all five through a useCancellableTimeout hook -- two in
    ConfigureAmsSlotModal, three in KProfileModal, the latter with the
    longest windows and so the widest exposure. Scheduling replaces any
    pending timer and unmounting clears it.
2026-08-02 09:53:27 +02:00
..
…
…
…

React + TypeScript + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

React Compiler

The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see this documentation.

Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:

export default defineConfig([
  globalIgnores(['dist']),
  {
    files: ['**/*.{ts,tsx}'],
    extends: [
      // Other configs...

      // Remove tseslint.configs.recommended and replace with this
      tseslint.configs.recommendedTypeChecked,
      // Alternatively, use this for stricter rules
      tseslint.configs.strictTypeChecked,
      // Optionally, add this for stylistic rules
      tseslint.configs.stylisticTypeChecked,

      // Other configs...
    ],
    languageOptions: {
      parserOptions: {
        project: ['./tsconfig.node.json', './tsconfig.app.json'],
        tsconfigRootDir: import.meta.dirname,
      },
      // other options...
    },
  },
])

You can also install eslint-plugin-react-x and eslint-plugin-react-dom for React-specific lint rules:

// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'

export default defineConfig([
  globalIgnores(['dist']),
  {
    files: ['**/*.{ts,tsx}'],
    extends: [
      // Other configs...
      // Enable lint rules for React
      reactX.configs['recommended-typescript'],
      // Enable lint rules for React DOM
      reactDom.configs.recommended,
    ],
    languageOptions: {
      parserOptions: {
        project: ['./tsconfig.node.json', './tsconfig.app.json'],
        tsconfigRootDir: import.meta.dirname,
      },
      // other options...
    },
  },
])