Files
bambuddy/frontend
maziggy accafafa64 fix(backup): report the rows a failed K-profile step already committed (#2656)
`_apply` commits the database categories before the K-profile phase, and the
    comment there is right about why: `get_kprofiles` is 3 x 5 s per printer per
    nozzle and SQLite's `busy_timeout` is 15 s, so holding the writer across the
    MQTT phase would fail every concurrent writer in the app.

    But `run_restore`'s handler returns `{"success": False, ..., "results": {}}`
    for anything raised after that point, and the per-call guards inside
    `_restore_kprofiles` do not cover the whole phase. Two consequences, and the
    second is worse:

    * The user is told the restore failed and handed an empty `results` while the
      archive, spool and settings rows are durable on disk. The honest-reporting
      theme this whole feature is built on inverted on exactly the path where it
      matters most.
    * `_reconfigure_mqtt_relay` sits inside the same `try`, downstream of the
      raise. A restore that rewrote the mqtt_* rows left the relay pointed at the
      pre-restore broker until something else reconfigured it.

    `_apply` now contains the K-profile phase: fold the error into that category's
    tally as `failed` plus a `kprofilesStepFailed` note, and let the results it has
    already committed be returned and reported. Every profile the payload carried
    and the phase did not account for is counted failed — silence would have been
    the same lie in a smaller font. `_reconfigure_mqtt_relay` is reached again
    because `_apply` returns normally. The rollback in the handler discards only
    the phase's own read transaction, so a database error cannot leave the session
    in a state that turns the caller's commit into the very report this prevents.

    `kprofilesSendFailed` was the obvious note to reuse and is the wrong one: it
    names a nozzle, a printer and a serial that a phase-level failure does not
    have, and "failed to send" is untrue of a step that never got as far as
    sending. One new leaf x 13 locales instead.

    Belt-and-braces on the trigger that found this:
    `sum(len(c.get("profiles") or []) ...)` raises TypeError on a hand-edited or
    truncated backup whose `profiles` is not a list, and it runs before the guards.
    Counting defensively makes that a skipped category rather than an exception
    thrown over committed rows.

    Control kept explicit: a failure *before* the commit still rolls back, still
    reports nothing restored, and still does not touch the relay.

    Tests: +5 (280 -> 285 across the three restore files, 328 -> 337 across
    `-k github`). Fail-pre-fix 4 — 3 for the containment, 1 for the defensive
    count, checked separately. i18n parity 13 locales at 5771 leaves.

    Bundle rebuilt for the new leaf: index-CHCEEMgx.js -> index-DhOfNgMz.js. CSS
    hash unchanged.
2026-08-15 14:16:44 +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...
    },
  },
])