Commit 147bab5
Sync PR867 branch to english-only + latest master (#17)
* Add conditional logic to drop permissions for unprivileged Docker
This change enables the container to run in unprivileged mode (without
--privileged or additional capabilities) by making permission drops
conditional:
- Changed users group GID from 1000 to 1001 to avoid conflicts with
the app user's primary group (UID 1000)
- Only modify user/group IDs when PUID/PGID environment variables differ
from the default value of 1000, avoiding unnecessary privilege
requirements
- Skip su-exec entirely when running as the default user, since changing
user context requires additional capabilities that unprivileged
containers don't have
This allows the container to work in restricted environments like
Kubernetes with security contexts or rootless Docker while maintaining
backward compatibility for users who customize PUID/PGID.
Fixes Donkie#791
* Allow archived spool export
* Tidy up docker file and entrypoint
* Fix spool price disappearing from the list on live updates (Donkie#814)
The REST endpoints serialize with response_model_exclude_none=True (unset fields
are omitted), but websocket events were serialized with a plain .json() that
includes unset fields as explicit null. The spool list fills a missing price
from the filament price only when it is `undefined`, so a live update carrying
`price: null` (e.g. after a quick weight adjust) blanked the price column until
a full page reload.
Fixed on both sides so the two serialization paths can no longer drift:
- Server: websocket payloads now use exclude_none=True (spoolman/ws.py), giving
live updates and REST responses an identical shape. Note this is a small
websocket wire-format change external consumers will see: unset fields are now
omitted instead of sent as null, matching REST.
- Client: collapseSpool and the price column now fall back for both `null` and
`undefined`, keeping the list resilient regardless of serialization.
* Commit generated requirements.txt for bare-metal/Moonraker installs (Donkie#830)
requirements.txt was moved to .gitignore when the project switched to uv, so
bare-metal installs lost it. Moonraker's update_manager runs
`pip install -r requirements.txt` against the checkout, so upgrading to 0.23
broke with "Invalid path for option `requirements`".
Track requirements.txt again and regenerate it from uv on every release
(spoolman/bump.py exports it alongside the uv.lock bump), keeping uv as the
single source of truth while staying backwards compatible with installs that
expect a requirements.txt.
* Document that extra field values are JSON-encoded strings (Donkie#849)
The `extra` map on vendors, filaments and spools is intentionally typed as
dict[str, str] where every value is a JSON-encoded string (the client round-
trips them through JSON.parse/stringify). This surprised API consumers, who
saw numeric fields come back as strings.
Spell out the encoding on all three response models via a shared helper so the
generated OpenAPI docs make clear that consumers must JSON-decode each value.
No behaviour change.
* Update Python dependencies (uv lock --upgrade)
Refresh all backend dependencies to the latest versions allowed by the
pyproject constraints and regenerate requirements.txt to match. Notable bumps:
starlette 0.50 -> 1.3, fastapi 0.128 -> 0.139, cryptography 46 -> 49,
uvicorn 0.40 -> 0.50, pydantic 2.12 -> 2.13, sqlalchemy 2.0.45 -> 2.0.51,
alembic 1.17 -> 1.18.
Locally verified: uv sync, ruff check, uv lock --check, app import, and a live
startup smoke (SQLite) — migrations run, /health + /info respond, vendor CRUD
works, and a websocket update event is delivered correctly on starlette 1.x.
The Docker-based 4-DB integration suite still needs to run (CI).
* Update client dependencies (npm update)
Refresh transitive client dependencies to the latest versions within the
existing package.json semver ranges (package.json unchanged).
Verified: npm ci, tsc --noEmit, eslint, prettier --check, and npm run build all
pass. (3 high-severity advisories remain that require major/breaking bumps via
`npm audit fix --force`; left for a separate, deliberate change.)
* Make the integration test suite runnable under Podman
Running tests_integration against rootless Podman surfaced three issues; none
affect the Docker/CI path:
- run.py: add a SPOOLMAN_CONTAINER_ENGINE env var (defaults to "docker") so the
build/compose commands can be driven by podman instead.
- Dockerfile: drop `--chown=app:app` from the builder-stage COPYs. The "app"
user only exists in the runner stage; Docker/BuildKit tolerated the dangling
reference but Podman rejects it. Final ownership is unchanged — it is set when
the files are copied into the runner stage.
- docker-compose-postgres.yml: add a pg_isready healthcheck and gate spoolman on
`condition: service_healthy`, matching the mariadb/cockroachdb compose files.
Without it spoolman raced postgres' initdb and died on connection-refused
before running migrations.
Verified: full 4-DB suite (sqlite/postgres/mariadb/cockroachdb) green via
`SPOOLMAN_CONTAINER_ENGINE=podman uv run poe itest` — 223 tests each.
* Fix commit-before-notify races in write paths (flaky postgres deletes)
Several DB write functions mutated and then sent their websocket notification (or
just returned) without committing, relying on the request session's teardown
commit. On async postgres that commit races the HTTP response, so a fast
follow-up read could still see the pre-write state — e.g. `DELETE /vendor/{id}`
returns 200 but an immediate `GET` still returns 200. Latent since 2023 (a6d527a);
the async-timing dependency bump widened the window enough to intermittently fail
`test (postgres)` in CI.
Commit inline before notifying, matching the functions that already did
(filament.delete, vendor/spool create/update) and the commit-first invariant from
the earlier websocket-ordering fix:
- vendor.delete, spool.delete
- setting.update, setting.delete
- vendor/filament/spool.clear_extra_field
- spool.rename_location
(use/measure already commit via their wrappers; reads are unaffected.)
Verified via `SPOOLMAN_CONTAINER_ENGINE=podman poe itest`: full 4-DB suite green
plus 7/7 repeat postgres runs with zero flakes (was ~66% failing before).
* Bump deps to clear Dependabot alerts (path-to-regexp, pytest)
- path-to-regexp: force >=8.4.0 (8.4.2) under @ant-design/pro-layout via a
scoped npm override, fixing the ReDoS advisories (GHSA sequential optional
groups + multiple wildcards). Express keeps its own 0.1.x.
- pytest 8.3 -> 9.1.1 and pytest-asyncio 0.23/0.25 -> 1.4.0 in
tests_integration/requirements.txt and the dev group; regenerated uv.lock.
Verified: client build + typecheck pass, npm audit clean, and the full
integration suite (223 tests) passes on postgres, sqlite, mariadb, and
cockroachdb under podman.
Claude-Session: https://claude.ai/code/session_01BQjJiwEbu6bHbeDjPPDm3V
* Add Playwright frontend integration tests; fix broken SPA static serving
Add a browser-driven integration suite (tests_frontend/) that runs against
the real production image + PostgreSQL and drives the UI with Playwright:
a smoke test that navigates every page via the sidebar with no console
errors, and a CRUD test that creates a vendor -> filament -> spool entirely
through the UI. Wired up as `poe itest-frontend` and a new `test-frontend`
CI job (reusing the image built for the backend tests, gating releases).
Navigation goes through real UI buttons (language-independent link targets)
and the app language is forced to English so label matchers are stable
regardless of the runner's browser locale.
This immediately caught a real regression: Starlette 1.3.1 (pulled by a
recent dep bump) removed the `method` kwarg from FileResponse, so
SinglePageApplication 500'd on every static asset and the whole UI was dead.
Drop the removed kwarg — Starlette now derives HEAD handling from the scope.
Claude-Session: https://claude.ai/code/session_01BQjJiwEbu6bHbeDjPPDm3V
* Add CI guard blocking manual edits to non-English translations
Non-English locales are managed exclusively through Weblate; any manual
edit to an existing translation file gets silently overwritten on the
next Weblate sync. This workflow fails any PR (except Weblate's own,
detected via PR author login) that modifies or deletes an existing
non-English file under client/public/locales/. Adding a brand-new
language file is still allowed so contributors can bootstrap a new
language alongside the client/src/i18n.ts entry.
Claude-Session: https://claude.ai/code/session_01BQjJiwEbu6bHbeDjPPDm3V
* Update sync interval for external database synchronization (Donkie#943)
The external database sync scheduler was ignoring the configured
EXTERNAL_DB_SYNC_INTERVAL environment variable and always using the DEFAULT_SYNC_INTERVAL constant (3600 seconds).
* Auto-merge Weblate translation PRs on green CI
Weblate opens a PR for every translation sync. These are machine-generated,
always scoped to client/public/locales/, and gated by the full CI suite, so
hand-merging each one is pure friction. This enables GitHub auto-merge on
Weblate-authored PRs so they merge themselves once required checks pass.
A scope-guard step reads the PR's file list from the API and refuses to enable
auto-merge unless every changed file is a .json under client/public/locales/,
so the trust is in the diff, not just the author: a compromised Weblate token
can open a PR but can only be auto-merged if it is confined to translations.
Claude-Session: https://claude.ai/code/session_01BQjJiwEbu6bHbeDjPPDm3V
* Remove hashes from requirements.txt
* Bump uuid from 13.0.2 to 14.0.0 in /client (Donkie#927)
Bumps [uuid](https://github.com/uuidjs/uuid) from 13.0.2 to 14.0.0.
- [Release notes](https://github.com/uuidjs/uuid/releases)
- [Changelog](https://github.com/uuidjs/uuid/blob/main/CHANGELOG.md)
- [Commits](uuidjs/uuid@v13.0.2...v14.0.0)
---
updated-dependencies:
- dependency-name: uuid
dependency-version: 14.0.0
dependency-type: direct:production
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* docs: add MCP server to integrations list (Donkie#890)
Add spoolman-mcp to the list of integrations. It's a Model Context
Protocol server that lets you manage your filament inventory through
AI assistants like Claude.
* feat(scanner): accept Data Matrix and other 2D codes (Donkie#887)
Widen the code scanner's accepted formats beyond qr_code to the common 2D
matrix codes (micro/rm QR, Data Matrix, Aztec, PDF417) so manually-generated
labels using those symbologies can be scanned. Payloads that don't match the
spoolman spool format are ignored, so this is a safe superset.
Claude-Session: https://claude.ai/code/session_01BQjJiwEbu6bHbeDjPPDm3V
* feat(theme): add 'System' option that follows OS/browser theme (Donkie#947)
Replace the light/dark switch with a 3-way System/Light/Dark control. The new
'System' preference follows prefers-color-scheme live via a matchMedia listener.
New installs default to System; existing users keep their stored light/dark
choice (legacy values remain valid preferences).
Claude-Session: https://claude.ai/code/session_01BQjJiwEbu6bHbeDjPPDm3V
* Translations update (Donkie#825)
* Translated using Weblate (Estonian)
Currently translated at 17.3% (50 of 288 strings)
Translated using Weblate (Persian)
Currently translated at 96.5% (278 of 288 strings)
Translated using Weblate (French)
Currently translated at 98.9% (285 of 288 strings)
Translated using Weblate (Greek)
Currently translated at 72.9% (210 of 288 strings)
Translated using Weblate (Dutch)
Currently translated at 99.3% (286 of 288 strings)
Translated using Weblate (Hungarian)
Currently translated at 72.2% (208 of 288 strings)
Translated using Weblate (Danish)
Currently translated at 85.4% (246 of 288 strings)
Translated using Weblate (Thai)
Currently translated at 98.6% (284 of 288 strings)
Translated using Weblate (Japanese)
Currently translated at 99.3% (286 of 288 strings)
Co-authored-by: Anonymous <noreply@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/da/
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/el/
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/et/
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/fa/
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/fr/
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/hu/
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/ja/
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/nl/
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/th/
Translation: Spoolman/Web Client
* Translated using Weblate (Ukrainian)
Currently translated at 93.0% (268 of 288 strings)
Translated using Weblate (Greek)
Currently translated at 72.9% (210 of 288 strings)
Translated using Weblate (Hungarian)
Currently translated at 72.2% (208 of 288 strings)
Co-authored-by: Daniel Hultgren <daniel.cf.hultgren@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/el/
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/hu/
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/uk/
Translation: Spoolman/Web Client
* Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 98.6% (284 of 288 strings)
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.3% (286 of 288 strings)
Translated using Weblate (Hindi (Latin script))
Currently translated at 3.8% (11 of 288 strings)
Translated using Weblate (Swedish)
Currently translated at 94.7% (273 of 288 strings)
Translated using Weblate (Ukrainian)
Currently translated at 93.0% (268 of 288 strings)
Co-authored-by: Anonymous <noreply@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/hi_Latn/
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/sv/
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/uk/
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/zh_Hant/
Translation: Spoolman/Web Client
* Translated using Weblate (Danish)
Currently translated at 87.1% (251 of 288 strings)
Co-authored-by: srbjessen <srbjessen@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/da/
Translation: Spoolman/Web Client
* Translated using Weblate (Czech)
Currently translated at 100.0% (288 of 288 strings)
Co-authored-by: Miloslav Kos <kos.m@post.cz>
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/cs/
Translation: Spoolman/Web Client
* Translated using Weblate (Korean)
Currently translated at 100.0% (288 of 288 strings)
Translated using Weblate (Korean)
Currently translated at 78.1% (225 of 288 strings)
Added translation using Weblate (Korean)
Co-authored-by: 김태남 <imedia0@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/ko/
Translation: Spoolman/Web Client
* Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (288 of 288 strings)
Co-authored-by: Kayz C <kayzed.x@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/zh_Hant/
Translation: Spoolman/Web Client
* Translated using Weblate (Slovenian)
Currently translated at 100.0% (288 of 288 strings)
Translated using Weblate (Slovenian)
Currently translated at 38.1% (110 of 288 strings)
Translated using Weblate (Slovenian)
Currently translated at 14.9% (43 of 288 strings)
Added translation using Weblate (Slovenian)
Co-authored-by: Jernej Pangerc <jernejp21@tuta.com>
Co-authored-by: jernejp21 <jernejp21@tuta.com>
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/sl/
Translation: Spoolman/Web Client
* Translated using Weblate (Slovak)
Currently translated at 10.4% (30 of 288 strings)
Translated using Weblate (Slovak)
Currently translated at 9.7% (28 of 288 strings)
Added translation using Weblate (Slovak)
Co-authored-by: Pavol Vrba <pvrba2000@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/sk/
Translation: Spoolman/Web Client
* Translated using Weblate (Hungarian)
Currently translated at 94.0% (271 of 288 strings)
Co-authored-by: Tamas Veres <tamas.veres@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/hu/
Translation: Spoolman/Web Client
* Translated using Weblate (Danish)
Currently translated at 100.0% (288 of 288 strings)
Translated using Weblate (Danish)
Currently translated at 92.0% (265 of 288 strings)
Co-authored-by: JonasBentin <jonasbentin19+github@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/da/
Translation: Spoolman/Web Client
* Translated using Weblate (Latvian)
Currently translated at 4.5% (13 of 288 strings)
Added translation using Weblate (Latvian)
Co-authored-by: Jurijs Kiricenko <jurijskiricenko@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/spoolman/web-client/lv/
Translation: Spoolman/Web Client
---------
Co-authored-by: Daniel Hultgren <daniel.cf.hultgren@gmail.com>
Co-authored-by: srbjessen <srbjessen@gmail.com>
Co-authored-by: Miloslav Kos <kos.m@post.cz>
Co-authored-by: 김태남 <imedia0@gmail.com>
Co-authored-by: Kayz C <kayzed.x@gmail.com>
Co-authored-by: jernejp21 <jernejp21@tuta.com>
Co-authored-by: Pavol Vrba <pvrba2000@gmail.com>
Co-authored-by: Tamas Veres <tamas.veres@gmail.com>
Co-authored-by: JonasBentin <jonasbentin19+github@gmail.com>
Co-authored-by: Jurijs Kiricenko <jurijskiricenko@gmail.com>
* feat(i18n): add Lithuanian and Turkish locales
Rework check-i18n to measure real translation coverage against en
(non-empty and differing from the reference) instead of file size,
gating inclusion at 50%. Add lt and tr, both ~96% translated.
Claude-Session: https://claude.ai/code/session_01BQjJiwEbu6bHbeDjPPDm3V
* Bump version to 0.24.0
* Add filtering and sorting for custom fields (Donkie#773)
* Add filtering and sorting for custom fields
* Fix tests and make code postgres compatible
* Fix bugs and expand test coverage for custom field filter/sort
* trigger CI
* fix: address extra field filter review feedback
* fix: clean up custom field table state handling
* docs: update extra field table view description
* fix: narrow boolean custom field filter syntax
* Expand test coverage for all custom field types/entities and fix range filter/sort
- Add comprehensive tests covering all 9 field types (text, integer, float,
boolean, single-choice, multi-choice, datetime, integer_range, float_range)
for filter and sort on spool, filament, and vendor entities
- Add invalid-filter 400 tests for float, integer_range, and float_range
- Fix integer_range/float_range filter to use LIKE pattern matching against
Python's deterministic json.dumps output instead of fragile .contains()
- Add integer_range/float_range sort support via a @compiles helper
(_JsonArrayFirstElement) that emits CAST(col AS JSON)->>0 on PostgreSQL
and JSON_EXTRACT(col, '$[0]') on SQLite/MariaDB
- Add logger and __all__ to extra_fields.py (aligns with PR Donkie#893)
- All tests verified passing on postgres, sqlite, and mariadb
* Add filter UI for all custom field types and fix range filters
- Add text input filter dropdown for text fields (substring search)
- Add range input filter dropdowns (min/max) for integer, float, integer_range, and float_range fields
- Add datetime picker filter dropdown for datetime fields
- Fix boolean "No" filter to use empty value so it correctly matches unset/false fields
- Fix integer_range/float_range filter to use numeric comparisons instead of LIKE-based exact matching (stored_min >= filter_min, stored_max <= filter_max)
- Add range filter support for integer/float fields (min:max format)
- Add _JsonArraySecondElement cross-database helper for extracting second JSON array element
* Range filter for integer/float fields and fix range_field filter semantics
Backend:
- Add _JsonArraySecondElement cross-database helper (mirrors _JsonArrayFirstElement)
- integer_range/float_range filter now uses numeric comparisons:
stored_min >= filter_min and stored_max <= filter_max (was LIKE exact match)
- integer/float filter now supports min:max range format in addition to exact match:
stored_value >= min and/or stored_value <= max
Frontend:
- integer and float fields now use a range filter dropdown (min/max inputs)
instead of a single exact-value input
Tests:
- Fix integer_range/float_range spool and vendor tests broken by new >= semantics
(filter values updated to discriminate between test entries)
- Add range filter tests (min only, max only, both) for integer and float fields
* Replace 12 copy-pasted numeric field tests with 4 parametrized tests
Introduce a _create_entity helper and @pytest.mark.parametrize("entity_type",
["spool", "filament", "vendor"]) to run each numeric field type test against
all three entity types from a single test function.
- Removes 12 individual tests (integer/float/integer_range/float_range × 3 entities)
- Adds 4 parametrized tests covering the same ground plus the previously missing
min-only / max-only range filter cases for filament and vendor
- Uses try/finally for cleanup so entities are always deleted even on assertion failure
* Add datetime range filter and restore integer/float range filter support
- Backend: add datetime range filter using '|' separator (ISO dates contain ':')
- Backend: restore integer/float range filter support (lost during attribution rewrite)
- Frontend: replace single DateTimePicker with From/To range pickers for datetime fields
* Use local timezone in filter picker; add range filter tests
The DateTimeRangeFilterDropdown was initializing pickers with dayjs.utc(),
causing them to display and accept UTC times directly. The entry form shows
local time and converts to UTC, so the filter was inconsistent: entering
the same displayed time would produce a filter value 2h offset from what
was stored (in UTC+2), making exact boundaries fail unexpectedly.
Fix: initialize picker values with dayjs() (local mode) so the filter picker
behaves the same as the entry form — shows local times and converts to UTC.
Tests: replace 3 separate entity-specific datetime tests with one parametrized
test covering spool/filament/vendor, and add range filter cases (start|, |end,
start|end).
* Replace all entity-specific tests with parametrized tests
Replace 16 separate spool/filament/vendor tests for text, boolean,
single-choice, multi-choice, and empty-filter with 5 parametrized tests
that run against all three entity types. Each test is now defined once
and executed 3 times, eliminating copy-paste and ensuring consistent
coverage across all entity types.
Parametrize invalid-filter-value 400 tests across all entity types
The non-numeric-value error uses "Invalid integer/float range filter value"
while the missing-colon error uses "Invalid range filter value". Both contain
"range filter value", so use that as the assertion substring.
* Align custom filter dropdowns with Ant Design choice filter style
All three custom filter dropdowns (text, number range, datetime range) now
match the built-in choice filter footer: a border-top separator, Reset as a
link button on the left (disabled when no filter is active), and OK as a
primary button on the right.
* fix(fields): correct custom-field filter edge cases across databases
- Float exact-match filters now compare numerically (cast to Float) instead of
by JSON string, so float fields stored as integer JSON (e.g. "2") or
non-canonical decimals (e.g. "2.50") match an equivalent filter.
- integer_range/float_range filter and sort no longer return HTTP 500 on
CockroachDB: the PostgreSQL '->>' JSON extraction is now also registered for
the cockroachdb dialect, which previously fell back to the unsupported
JSON_EXTRACT function.
- Text exact-match and single-choice equality use ensure_ascii=False so
non-ASCII values match how the frontend's JSON.stringify stores them.
Co-authored-by: Dieter Blomme <dieterblomme@gmail.com>
* test(fields): expand custom-field filter/sort coverage
Add tests covering filter composition (multiple extra fields, extra + built-in,
filter one field / sort another), pagination total-count, unknown-field
handling, text case-insensitivity/substring/non-ASCII, numeric multi-value OR,
boolean empty semantics and token rejection, multi-choice substring collisions,
empty filters on numeric fields, null-bounded ranges, and additional
invalid-value 400 paths.
Verified against sqlite, postgres, mariadb and cockroachdb.
Co-authored-by: Dieter Blomme <dieterblomme@gmail.com>
* style(client): format column.tsx with prettier
The custom-field filter dropdowns' Reset buttons were written as one-line
onClick handlers that prettier wraps across multiple lines. Apply prettier
so the CI style check passes.
Co-authored-by: Dieter Blomme <dieterblomme@gmail.com>
* fix(fields): decode JSON scalars in-DB for text/choice/datetime custom-field filters
Match text, single-choice and datetime custom-field filters against the
database-decoded JSON scalar (new _JsonScalarText cross-dialect helper:
#>> '{}' on postgres/cockroachdb, JSON_UNQUOTE(JSON_EXTRACT) on mysql,
json_extract on sqlite) instead of reconstructing the exact JSON
serialization the client wrote. This decouples matching from
json.dumps/JSON.stringify encoding quirks (non-ASCII escaping, surrounding
quotes). Also escape LIKE wildcards so '%' and '_' in text and multi-choice
queries match literally rather than acting as wildcards.
Verified against sqlite, postgres, mariadb and cockroachdb.
Co-authored-by: Dieter Blomme <dieterblomme@gmail.com>
* test(fields): cover LIKE-wildcard escaping in custom-field filters
Add parametrized tests (spool/filament/vendor) asserting that '%' and '_'
are matched literally in text and multi-choice filters, that a literal '/'
(the internal LIKE escape char) matches literally, and that single-choice
equality handles a '%' value exactly.
Co-authored-by: Dieter Blomme <dieterblomme@gmail.com>
---------
Co-authored-by: Donkie <daniel.cf.hultgren@gmail.com>
Co-authored-by: akira69 <akira69@gmail.com>
* chore(ui): rename Hide Columns button label to Columns
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Joshua Piccari <joshua.piccari@gmail.com>
Co-authored-by: Veli-Matti Leppänen <vellu@velhot.net>
Co-authored-by: Donkie <daniel.cf.hultgren@gmail.com>
Co-authored-by: chruoss <chrigi.ruoss@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Marco Thiel <mfranke87@icloud.com>
Co-authored-by: Weblate (bot) <noreply@weblate.org>
Co-authored-by: srbjessen <srbjessen@gmail.com>
Co-authored-by: Miloslav Kos <kos.m@post.cz>
Co-authored-by: 김태남 <imedia0@gmail.com>
Co-authored-by: Kayz C <kayzed.x@gmail.com>
Co-authored-by: jernejp21 <jernejp21@tuta.com>
Co-authored-by: Pavol Vrba <pvrba2000@gmail.com>
Co-authored-by: Tamas Veres <tamas.veres@gmail.com>
Co-authored-by: JonasBentin <jonasbentin19+github@gmail.com>
Co-authored-by: Jurijs Kiricenko <jurijskiricenko@gmail.com>
Co-authored-by: Donkie <2332094+Donkie@users.noreply.github.com>
Co-authored-by: Dieter Blomme <dieterblomme@gmail.com>1 parent 7aaaa01 commit 147bab5
76 files changed
Lines changed: 8039 additions & 2689 deletions
File tree
- .github/workflows
- client
- public/locales
- cs
- da
- el
- en
- et
- fa
- fr
- hi-Latn
- hu
- ja
- ko
- lv
- nl
- sk
- sl
- sv
- th
- uk
- zh-Hant
- zh
- scripts
- src
- components
- header
- contexts/color-mode
- pages/spools
- utils
- spoolman
- api/v1
- database
- tests_frontend
- tests
- tests_integration
- tests/fields
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
249 | 249 | | |
250 | 250 | | |
251 | 251 | | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
252 | 305 | | |
253 | 306 | | |
254 | 307 | | |
| |||
336 | 389 | | |
337 | 390 | | |
338 | 391 | | |
339 | | - | |
| 392 | + | |
340 | 393 | | |
341 | 394 | | |
342 | 395 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
29 | | - | |
| 29 | + | |
| 30 | + | |
30 | 31 | | |
31 | 32 | | |
32 | 33 | | |
| |||
204 | 205 | | |
205 | 206 | | |
206 | 207 | | |
207 | | - | |
| 208 | + | |
| 209 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
27 | | - | |
28 | | - | |
29 | | - | |
30 | | - | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
31 | 33 | | |
32 | 34 | | |
33 | 35 | | |
| |||
44 | 46 | | |
45 | 47 | | |
46 | 48 | | |
47 | | - | |
48 | | - | |
49 | | - | |
| 49 | + | |
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
32 | 32 | | |
33 | 33 | | |
34 | 34 | | |
| 35 | + | |
35 | 36 | | |
36 | 37 | | |
37 | 38 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
| 21 | + | |
| 22 | + | |
21 | 23 | | |
22 | 24 | | |
23 | 25 | | |
| |||
0 commit comments