feat: Add color column with filter to spool list
Some checks failed
CI / style (push) Has been cancelled
CI / build-client (push) Has been cancelled
CI / build-amd64 (push) Has been cancelled
CI / build-tester (push) Has been cancelled
CI / test (cockroachdb) (push) Has been cancelled
CI / test (mariadb) (push) Has been cancelled
CI / test (postgres) (push) Has been cancelled
CI / test (sqlite) (push) Has been cancelled
CI / build-arm64 (push) Has been cancelled
CI / build-armv7 (push) Has been cancelled
CI / publish-images (push) Has been cancelled
CI / publish-release (push) Has been cancelled

Add optional color column to spool list showing filament color swatches
with multi-select filtering capability.

Backend:
- GET /api/v1/color endpoint to list distinct filament colors
- filament.color_hex query param on spool list for filtering

Frontend:
- ColorFilterColumn component renders color swatches
- useSpoolmanColors() hook fetches available colors
- Filter dropdown shows swatches with hex codes
- Column hidden by default (enable via column selector)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-21 21:11:18 -06:00
parent 8fc06cdb18
commit 9bfc322f32
9 changed files with 193 additions and 11 deletions

View File

@@ -241,6 +241,16 @@ async def find_materials(
return [row[0] for row in rows.all() if row[0] is not None]
async def find_colors(
*,
db: AsyncSession,
) -> list[str]:
"""Find a list of unique filament colors (hex codes) from the filament table."""
stmt = select(models.Filament.color_hex).distinct()
rows = await db.execute(stmt)
return sorted([row[0] for row in rows.all() if row[0] is not None])
async def find_article_numbers(
*,
db: AsyncSession,

View File

@@ -118,6 +118,7 @@ async def find( # noqa: C901, PLR0912
filament_name: Optional[str] = None,
filament_id: Optional[Union[int, Sequence[int]]] = None,
filament_material: Optional[str] = None,
filament_color_hex: Optional[Union[str, Sequence[str]]] = None,
vendor_name: Optional[str] = None,
vendor_id: Optional[Union[int, Sequence[int]]] = None,
location: Optional[str] = None,
@@ -152,6 +153,15 @@ async def find( # noqa: C901, PLR0912
stmt = add_where_clause_str_opt(stmt, models.Spool.location, location)
stmt = add_where_clause_str_opt(stmt, models.Spool.lot_nr, lot_nr)
# Filter by color_hex (exact match, supports multiple comma-separated values)
if filament_color_hex is not None:
if isinstance(filament_color_hex, str):
colors = [c.strip() for c in filament_color_hex.split(",") if c.strip()]
else:
colors = list(filament_color_hex)
if colors:
stmt = stmt.where(models.Filament.color_hex.in_(colors))
if not allow_archived:
# Since the archived field is nullable, and default is false, we need to check for both false or null
stmt = stmt.where(