Merge upstream features: extra-field filter/sort, 3D Filament Profiles import, weight-delta events - #2
Merged
Merged
Conversation
Drops the always-on overflow-y: scroll from .loc-container .location so the locations view no longer shows a permanent scrollbar. Ported from upstream Donkie#859 by @VeeBack. Co-authored-by: VeeBack <VeeBack@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqPtZvXQkraNt9ttEhLsBt
schedule_tasks scheduled the cyclic sync with DEFAULT_SYNC_INTERVAL instead of the user-configured sync_interval value, so the configured interval had no effect. Use sync_interval. Ported from upstream Donkie#943 by @chruoss. Co-authored-by: chruoss <chruoss@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqPtZvXQkraNt9ttEhLsBt
Adds an allow_archived query parameter to the spool export endpoint, passed through to spool.find(allow_archived=...), which already supports it. Defaults to False to preserve existing behavior. Ported from upstream Donkie#919 by @velzi. Co-authored-by: velzi <velzi@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqPtZvXQkraNt9ttEhLsBt
Adds a prometheus_client Info metric exposing version, commit and build_date so build provenance is scrapeable. Ported from upstream Donkie#877 by @sw1nn. Co-authored-by: sw1nn <sw1nn@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqPtZvXQkraNt9ttEhLsBt
README documentation only. Ported from upstream Donkie#890 by @Disane87. Co-authored-by: Disane87 <Disane87@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqPtZvXQkraNt9ttEhLsBt
Adds a container HEALTHCHECK that probes /api/v1/health (which exists) using the bundled Python interpreter, plus a sample docker-compose.yml. Ported from upstream Donkie#908 by @meek2100. Co-authored-by: meek2100 <meek2100@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqPtZvXQkraNt9ttEhLsBt
Adds an axios response interceptor that reloads the SPA on 401 for idempotent requests (with a cooldown and service-worker unregister) so forward-auth proxies can re-run their login flow. Ported from upstream Donkie#924 by @sherrmann. Co-authored-by: sherrmann <sherrmann@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqPtZvXQkraNt9ttEhLsBt
Wires the existing comma-aware formatNumberOnUserInput / numberParser(AllowEmpty) helpers into the remaining InputNumber fields across filaments, spools, vendors, printing, extra fields and settings. Ported from upstream Donkie#948 by @nkgotcode. Co-authored-by: nkgotcode <nkgotcode@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqPtZvXQkraNt9ttEhLsBt
Regenerates client/package-lock.json to pull the security/patch bumps from the upstream dependabot PRs. uuid required a major bump (only used via the stable `v4` export). Resulting versions meet or exceed each PR's target: uuid 13 -> 14.0.1 (Donkie#927) axios -> 1.18.1 (Donkie#928) vite -> 7.3.6 (Donkie#906) i18next-http-backend -> 3.0.6 (Donkie#920) qs -> 6.14.2 (Donkie#850) minimatch (transitive bump) (Donkie#873) flatted -> 3.4.2 (Donkie#889) handlebars -> 4.7.9 (Donkie#894) lodash-es -> 4.18.1 (Donkie#901) lodash -> 4.18.1 (Donkie#909) follow-redirects -> 1.16.0 (Donkie#914) fast-uri -> 3.1.2 (Donkie#930) @babel/plugin-transform-modules-systemjs 7.29.7 (Donkie#931) Verified with `npm run build` (tsc typecheck + refine/vite build). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqPtZvXQkraNt9ttEhLsBt
… bumps) Bumps two transitive dependencies in uv.lock to the security/patch versions targeted by the upstream dependabot PRs: cryptography 46.0.3 -> 46.0.7 (Donkie#907) mako 1.3.10 -> 1.3.12 (Donkie#929) Pinned to the dependabot targets rather than the newest available (cryptography 49.x) to keep the change to a patch-level security update. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqPtZvXQkraNt9ttEhLsBt
- numberFormatter: render a legitimate 0 as "0" instead of a blank field. The previous truthiness check formatted 0 as an empty string, so inputs where 0 is common (printing margins/spacing) looked blank / like state loss when not focused. Now only undefined/empty/non-finite values blank out. - InputNumberRange.parseInputNumberValue: parse string values (antd typings allow them, e.g. stringMode) instead of dropping them to null, while still treating empty/null as a deliberate clear. - authReloadHandler: guard the axios response interceptor against double-registration. Vite/React fast refresh can re-evaluate the module and stack duplicate interceptors, firing multiple reloads per 401; the flag now lives on the shared axios instance so it survives module re-evaluation. Verified with npm run build (tsc typecheck + vite build) and prettier. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqPtZvXQkraNt9ttEhLsBt
The Prometheus BUILD_INFO block (ported from upstream Donkie#877) wasn't ruff-format compliant, failing the `style` job's `ruff format --check`. Wrap the BUILD_INFO.info({...}) dict argument per ruff's formatting. No behavior change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqPtZvXQkraNt9ttEhLsBt
Adds an optional payload_extras field to SpoolEvent and passes {"weight_delta": weight} from use_weight/use_length so websocket consumers can see the change amount. Follow-up to upstream Donkie#689.
Ported from upstream Donkie#902 by @chof747.
Co-authored-by: chof747 <chof747@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqPtZvXQkraNt9ttEhLsBt
Adds a 3D Filament Profiles ID input to the filament create/edit forms and a backend proxy endpoint to fetch and map that profile data. Resolves upstream Donkie#939. Ported from upstream Donkie#940 by @t0ny-peng. Co-authored-by: t0ny-peng <t0ny-peng@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqPtZvXQkraNt9ttEhLsBt
Ports upstream Donkie#773: extra fields can now be shown, sorted, and filtered in the spool/filament/vendor tables. Adds an extra-field query subsystem (extra_field_query.py, extra_field_registry.py) and the frontend filtering/ sorting utilities and column filter dropdowns. Choice and boolean fields get filter options; all extra field types support filtering for empty values. Chosen over the overlapping Donkie#904 (filtering-only) as the more complete superset implementation. Ported from upstream Donkie#773 by @daften. Co-authored-by: daften <daften@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqPtZvXQkraNt9ttEhLsBt
Fixes issues surfaced by the local CI checks (ruff, eslint, prettier, build) on the three ported feature PRs so the branch passes the style job: - spool.py (Donkie#902): fix a real NameError -- spool_changed used Optional[dict] without importing Optional. Switched to "dict | None" (codebase style); the app failed to import before this. - externaldb.py (Donkie#940): hoist inline imports to module top, narrow the blind except to httpx.HTTPError, use logging.exception + "raise ... from e", add the return annotation, wrap long lines, and noqa the complexity warnings (consistent with find()). - filaments/edit.tsx (Donkie#940): replace an "as any" cast (eslint no-explicit-any) with a cast to setFieldsValue's parameter type. - ruff format + prettier formatting on the remaining ported files. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqPtZvXQkraNt9ttEhLsBt
There was a problem hiding this comment.
Pull request overview
This PR merges a second batch of upstream Spoolman features into the fork: (1) filtering/sorting on extra/custom fields across core entity lists, (2) importing filament details from 3dfilamentprofiles.com via a backend proxy endpoint, and (3) enriching spool websocket “updated” events with a weight_delta. It also includes various conformance/infra changes (metrics, healthcheck, dependency bumps) needed to keep lint/build/test pipelines green.
Changes:
- Add server + client support for filtering/sorting by extra fields on spool/filament/vendor list endpoints and tables.
- Add
/external/profile/{profile_id}proxy endpoint and UI form controls to import filament details by 3D Filament Profiles ID. - Include
payload_extras.weight_deltain spool websocket update events and add integration coverage.
Reviewed changes
Copilot reviewed 45 out of 47 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| uv.lock | Updates Python dependency lock entries (cryptography, mako). |
| tests_integration/tests/spool/test_spool_event.py | Adds integration test asserting weight_delta appears in spool websocket events. |
| tests_integration/tests/fields/test_filter_sort.py | Adds integration tests for extra-field filter/sort behavior across entity types and field types. |
| tests_integration/requirements.txt | Adds websockets dependency for websocket integration tests. |
| spoolman/prometheus/metrics.py | Adds BUILD_INFO Info metric. |
| spoolman/main.py | Populates build info metric at startup and logs build metadata consistently. |
| spoolman/extra_fields.py | Refactors to re-export shared registry/types and keeps delete/default helpers in place. |
| spoolman/extra_field_registry.py | New shared module containing extra-field schema + settings-backed registry access/validation. |
| spoolman/externaldb.py | Fixes scheduler to use configured external DB sync interval. |
| spoolman/database/vendor.py | Adds extra-field filter/sort support to vendor queries + adjusts count query behavior. |
| spoolman/database/spool.py | Adds extra-field filter/sort support; includes weight_delta in spool update websocket events. |
| spoolman/database/filament.py | Adds extra-field filter/sort support to filament queries + adjusts count query behavior. |
| spoolman/database/extra_field_query.py | New query helper module implementing DB-agnostic extra-field filtering/sorting behavior. |
| spoolman/api/v1/vendor.py | Extracts extra.* query params and returns 400 on invalid extra-field filters. |
| spoolman/api/v1/spool.py | Extracts extra.* query params and returns 400 on invalid extra-field filters. |
| spoolman/api/v1/models.py | Extends SpoolEvent with optional payload_extras (e.g., weight_delta). |
| spoolman/api/v1/filament.py | Extracts extra.* query params and returns 400 on invalid extra-field filters. |
| spoolman/api/v1/externaldb.py | Adds /external/profile/{profile_id} endpoint to fetch/parse 3dfilamentprofiles.com filament details. |
| spoolman/api/v1/export.py | Adds allow_archived parameter to spool export endpoint. |
| README.md | Documents MCP Server integration link. |
| Dockerfile | Adds container healthcheck probing /api/v1/health. |
| docker-compose.yml | Adds example compose file for running Spoolman with a mounted data directory. |
| client/src/utils/sorting.ts | Expands sorter typing to allow custom-field identifiers and adds helpers for custom-field sorters. |
| client/src/utils/queryFields.ts | Adds helpers to identify/extract custom-field keys (extra.*). |
| client/src/utils/parsing.tsx | Fixes number formatting to correctly render 0 instead of blank. |
| client/src/utils/filtering.ts | Expands filter typing to allow custom-field identifiers and adds custom-field filter helpers. |
| client/src/utils/authReloadHandler.ts | Adds axios interceptor to reload on idempotent 401s for forward-auth proxy flows. |
| client/src/pages/vendors/edit.tsx | Applies consistent numeric formatter/parser to empty spool weight input. |
| client/src/pages/vendors/create.tsx | Applies consistent numeric formatter/parser to empty spool weight input. |
| client/src/pages/spools/functions.tsx | Applies numeric formatter/parser in spool adjustment modal input. |
| client/src/pages/spools/edit.tsx | Applies numeric formatter/parser for spool weight fields. |
| client/src/pages/spools/create.tsx | Applies numeric formatter/parser for spool weight fields. |
| client/src/pages/settings/extraFieldsSettings.tsx | Applies numeric formatter/parser for float extra-field editing. |
| client/src/pages/printing/qrCodePrintingDialog.tsx | Applies numeric formatter/parser to text-size input. |
| client/src/pages/printing/printingDialog.tsx | Applies numeric formatter/parser across print settings number inputs. |
| client/src/pages/locations/locations.css | Removes forced overflow-y: scroll from locations list container. |
| client/src/pages/filaments/edit.tsx | Adds 3D Filament Profiles ID fetch/import UI and applies numeric formatter/parser to weight fields. |
| client/src/pages/filaments/create.tsx | Adds 3D Filament Profiles ID fetch/import UI and applies numeric formatter/parser to weight fields. |
| client/src/index.tsx | Registers auth reload handler module at app startup. |
| client/src/components/inputNumberRange.tsx | Improves parsing of InputNumber string-mode values + adds formatter/parser to range inputs. |
| client/src/components/extraFields.tsx | Applies numeric formatter/parser to float extra-field form inputs. |
| client/src/components/dataProvider.ts | Adds serialization of extra.* filters to query params and ensures custom-field sorting passes through. |
| client/src/components/column.tsx | Adds custom filter dropdown UIs for extra fields and enables custom-field sorting in tables. |
| client/public/locales/zh/common.json | Adds translations for 3D Filament Profiles import UI strings and “Fetch” button. |
| client/public/locales/en/common.json | Adds translations for 3D Filament Profiles import UI strings; updates extra-fields description for filter/sort support. |
| client/package.json | Bumps uuid dependency. |
| client/package-lock.json | Updates lockfile to match dependency bumps. |
Files not reviewed (1)
- client/package-lock.json: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- extra_field_query.py: the int/float-range extra-field filters compiled to json_extract(), which CockroachDB lacks. CockroachDB's SQLAlchemy dialect name is "cockroachdb" (not "postgresql"), so the existing PG @compiles variant didn't apply and it fell back to the json_extract default -- test (cockroachdb) failed with "unknown function: json_extract()". Add a cockroachdb variant emitting CAST(value AS JSONB)->>N. Verified the generated SQL for sqlite/mysql/postgresql/cockroachdb locally. - filaments/create.tsx, edit.tsx: await importFilament so errors propagate to the catch and the success toast only shows after the import completes. - externaldb.py: reject a non-numeric profile_id before interpolating it into the upstream URL (prevents path injection / unintended fetches). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqPtZvXQkraNt9ttEhLsBt
Ports upstream Donkie#855: a calibration module with DB tables, REST API, and a multi-step calibration wizard UI. Includes two Alembic migrations (c3a7f2e8b091 calibration_tables, a1b2c3d4e5f6 calibration_filament_fk) that chain from the current head, and integration tests. Ruff-formatted to the fork's style; verified imports and a single Alembic head. Ported from upstream Donkie#855 by @SmoothBrainIT. Co-authored-by: SmoothBrainIT <SmoothBrainIT@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqPtZvXQkraNt9ttEhLsBt
The a1b2c3d4e5f6 (calibration_filament_fk) migration used batch_alter_table(recreate="always"), which forces Alembic's SQLite-style table-copy workflow on every backend. On PostgreSQL/CockroachDB/MariaDB the copy drops calibration_session's primary key, which calibration_step_result's foreign key depends on -- "cannot drop constraint calibration_session_pkey because other objects depend on it" -- so app startup (alembic upgrade) failed and test (postgres) went red. Use recreate="auto": only SQLite recreates the table (it must); the other backends apply direct ALTERs that don't touch the PK. Verified the full upgrade chain on a fresh SQLite DB locally; CI validates the other three. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqPtZvXQkraNt9ttEhLsBt
test (sqlite) failed test_delete_filament_cascades_to_sessions: deleting a
filament left its calibration sessions orphaned (expected 404, got 200). The
codebase does not enable SQLite's PRAGMA foreign_keys, so DB-level
ON DELETE CASCADE is not enforced there -- cascades are done at the ORM level
instead. The Filament model had no relationship to CalibrationSession, so
nothing deleted the sessions on SQLite (the other three DBs enforce the FK, so
they passed).
Add Filament.calibration_sessions with cascade "save-update, merge, delete,
delete-orphan" (matching the extra-field pattern) plus the
CalibrationSession.filament back-reference. The delete path loads relations via
joinedload("*"), so the ORM cascade fires on every backend. Verified ruff,
imports, the relationship registration, and the full SQLite migration chain
locally; CI validates the cascade test across all four databases.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqPtZvXQkraNt9ttEhLsBt
After switching to recreate="auto", MariaDB failed alembic upgrade with "Cannot drop index 'spool_id': needed in a foreign key constraint" -- MySQL/ MariaDB refuse to drop a column still referenced by a foreign key, whereas PostgreSQL/CockroachDB drop the FK together with the column. Drop the spool_id FK explicitly before dropping the column. It was created unnamed, so reflect its real name; skip on SQLite (no named FK there, and the batch recreate handles it). Apply the same guard to the downgrade for the named filament_id FK. Verified upgrade + downgrade + re-upgrade on a fresh SQLite DB locally; CI validates MariaDB/PostgreSQL/CockroachDB. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqPtZvXQkraNt9ttEhLsBt
The calibration feature shipped two migrations: create calibration_session with spool_id, then swap spool_id -> filament_id. That swap was an artifact of the PR's development history and broke differently on every backend (PostgreSQL pkey drop, MariaDB drop-column-with-FK, CockroachDB DDL+DML in one transaction). Calibration tables are brand new, so there is no data to migrate. Create calibration_session with filament_id (FK filament.id ON DELETE CASCADE) directly in the first migration and delete the second migration. Verified on a fresh SQLite DB: single head c3a7f2e8b091, calibration_session has filament_id and no spool_id. The ORM cascade relationship added earlier is unchanged, so filament deletion still cascades to sessions on SQLite. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqPtZvXQkraNt9ttEhLsBt
…t events) Backend: - spool.delete: commit in-request like filament.delete. Fixes a deterministic Postgres StaleDataError 500 when deleting a filament after a websocket+use flow (uncommitted spool delete left a phantom row in the next request's unit of work). - use_weight_safe: return the actually-applied delta (after clamping at 0) and broadcast that as weight_delta instead of the requested weight. Consumption (weight>=0, the concurrent hot path) stays a single atomic UPDATE with no read-before-write, so concurrent /use no longer loses updates on MariaDB/CockroachDB; only refills (weight<0) read the prior value to report the clamped delta. - calibration.list_sessions: load steps via selectinload, not joinedload, so LIMIT/OFFSET paginate sessions rather than joined step rows. - calibration delete_session/delete_step_result: commit in-request. - extra-field float exact-match filter: match both "5" and "5.0" so whole-number floats stored verbatim are found. - export_spools: default allow_archived to True (backups include archived spools). - Sorting: shared parse_sort() helper rejects malformed sort params with 400 instead of an uncaught 500 (spool/filament/vendor). Frontend: - Calibration VFA step: stop nulling restored/typed min/max_avoidance_speed when the artifact-speeds list is empty (was wiping saved values on edit/resume). Tests: regression tests for calibration pagination, weight_delta clamping, whole-number float filtering, malformed-sort 400, and export-includes-archived. Full integration matrix (sqlite/postgres/mariadb/cockroachdb) passes 297 each. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…cks) - Add a fast, non-Docker pytest unit suite under tests/ (26 tests for spoolman.math and extra-field validation) plus pytest config ([tool.pytest.ini_options]) and pytest-cov. - lefthook ci: run client `tsc --noEmit` and `npm run check-i18n` so type and translation regressions fail CI. Register the previously-unwired `lt` and `tr` locales in client/src/i18n.ts so check-i18n passes. - Add .github/dependabot.yml (weekly pip + npm). - Expand .dockerignore (.git, .github, tests, env files, etc.). - Drop the obsolete top-level `version:` key from the compose files. Note: the matching .github/workflows/ci.yml additions (unit-tests, CodeQL and Hadolint jobs) are kept as a separate patch (ci-workflow-additions.patch) because pushing workflow changes needs a token with the `workflow` scope. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- unit-tests: run the fast non-Docker pytest suite (uv run pytest tests/) with coverage, no fail threshold. - codeql: static analysis for python and javascript-typescript. - hadolint: lint the Dockerfile. Split from the hardening commit because pushing workflow files needs a token with the `workflow` scope. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Backend: - Deduplicate utc_timezone_naive into spoolman/database/utils.py (was copied in spool.py and calibration.py). - Collapse the two _JsonArray*Element classes into one parametrized _JsonArrayElement(col, index). - Introduce EXTRA_FIELD_PREFIX constant (extra_field_registry) and use it instead of the hardcoded "extra."/[6:] in the spool/filament/vendor find endpoints and the query builder. - Escape LIKE/ILIKE wildcards (% and _) in extra-field text/multi-choice filters so a value like "50%" matches literally instead of acting as a wildcard. - calibration_models.from_db: parse JSON columns with `is not None` instead of truthiness so an empty stored value isn't dropped to None. - get_external_db_sync_interval: tolerate a non-integer EXTERNAL_DB_SYNC_INTERVAL (warn + default) instead of crashing startup. - Dockerfile HEALTHCHECK: add a urlopen timeout. Frontend: - Extract the duplicated 3DFP fetchProfile + field-mapping into shared utils/queryExternalDB.ts::fetchExternalProfile, using the axios instance (so it carries auth and works behind forward-auth proxies instead of a bare fetch). - Extract a shared FilterDropdownFooter and translate the custom-field filter dropdown labels via the i18n instance (antd renders filterDropdown as a callback, so translate statically, not via a prop/hook); add the table.filter.* en keys. - Add CUSTOM_FIELD_PREFIX constant in queryFields.ts; remove dead formatCustomFieldFilterValue / getCustomFieldSorters / isCustomFieldSorter. - CalibrationWizard: re-initialise when the session prop changes while mounted (deps), and guard the "skip step" handler against double-submit. Verified: ruff/eslint/tsc/prettier/check-i18n, 26 unit tests, and the full integration matrix (sqlite/postgres/mariadb/cockroachdb) all pass 297 each. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The hadolint job (added in b3ed419) runs with the action's default failure-threshold of "info", which flagged five findings on the pre-existing build/runtime apt+pip layers. - Add --no-install-recommends to both apt-get install layers. This is the exact remediation hadolint recommends for DL3015 and trims the images by skipping recommended-but-unneeded packages. - Add .hadolint.yaml ignoring DL3008 (pin apt versions) and DL3013 (pin pip versions). The images build on the rolling python:3.x-slim-bookworm base, whose apt package index moves over time; pinning exact apt/pip versions would break the build as soon as those versions are superseded upstream. Reproducibility of the actual Python dependency set is already handled by uv.lock. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqPtZvXQkraNt9ttEhLsBt
Replace the two parallel if/elif ladders in _get_field_table_for_entity and _get_entity_id_column with a single _ENTITY_FIELD_TABLES dict mapping each EntityType to its (field table, owning-entity id column). Pure refactor: verified the dict returns the identical table/column objects the ladders did for spool/filament/vendor and still raises ValueError on unknown inputs. Verified: ruff, 26 unit tests, and sqlite+postgres integration matrix (297 each) all pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Second batch of upstream Donkie/Spoolman PRs — the "filtering & small features" set. Three self-contained features plus the conformance fixes needed to pass the fork's lint/format/type checks.
Features ported
weight_deltain spool websocket events (upstream Follow up of #689 - providing spool weight deltas as part of new payload_extras attribute in Spool Event Donkie/Spoolman#902 by @chof747) — spool update events now carry the change amount.Conformance fixes
Local verification (ruff, eslint, prettier, build, import smoke test) surfaced issues in the ported code, fixed in the final commit:
NameErrorin Follow up of #689 - providing spool weight deltas as part of new payload_extras attribute in Spool Event Donkie/Spoolman#902 (Optionalused but not imported) that broke app startup → switched todict | None.externaldb.py: hoisted inline imports, narrowed the blindexcepttohttpx.HTTPError, added a return annotation, wrapped long lines,raise ... from e.edit.tsx: replaced anas anycast with a typed cast.Verification
All CI-equivalent checks pass locally:
ruff check,ruff format --check,uv lock --check,eslint,prettier --check, client build (tsc + vite), and a backend import smoke test. The integration tests (Donkie#773 and Donkie#902 ship them) require Docker and will be validated by CI here.🤖 Generated with Claude Code
https://claude.ai/code/session_01JqPtZvXQkraNt9ttEhLsBt
Generated by Claude Code