Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
232 changes: 232 additions & 0 deletions .copilot/logo-plan-pr857.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
# Logo Integration Plan: Spoolman PR 857 into FilaMan

## Goal

Bring manufacturer logos into FilaMan, based on the non-print parts of Spoolman PR 857.

This phase covers:
- manufacturer management
- manufacturer list visibility
- filament show and edit visibility
- spool show and edit visibility

This phase explicitly does not cover any print or label-export logo work.

## Current FilaMan Reality

- FilaMan does not have a separate manufacturer edit page.
- Manufacturer create and edit currently happen inside the modal in `frontend/src/pages/manufacturers/index.astro`.
- The backend manufacturer model currently has no dedicated logo fields.
- Manufacturer data already flows into filament and spool detail responses, so logo visibility can piggyback on the existing nested manufacturer payload once the backend schema is extended.

## Requested UX

On the manufacturer editor surface:
- allow upload of a logo file
- allow manual entry of a logo URL
- show the stored file path for the uploaded logo
- show a live preview of the effective logo

On other surfaces:
- show the logo in the manufacturer table
- show the logo in filament show and edit screens
- show the logo in spool show and edit screens

## Scope

### In Scope

1. Backend manufacturer logo persistence.
2. Logo upload endpoint and file storage.
3. Manufacturer modal updates for upload, URL, file path display, and preview.
4. Manufacturer list/table logo column.
5. Logo visibility on filament show and filament edit.
6. Logo visibility on spool show and spool edit.

### Out Of Scope

- Print page logo rendering.
- Print-specific monochrome conversion.
- Export/AML/PNG behavior.
- Vendor-logo manifest auto-discovery from Spoolman.
- Logo packs or bundled static logo libraries.

## Proposed Data Model

Add dedicated logo fields to `Manufacturer` instead of burying this in generic custom fields.

Recommended fields:
- `logo_url`: optional manually entered external or absolute app URL
- `logo_file_path`: optional server-managed relative path for uploaded files

Recommended response convenience field:
- `resolved_logo_url`: computed URL the frontend should use for display

Why this shape:
- supports both upload and manual URL cleanly
- preserves the actual stored file path the user asked to see
- keeps rendering logic simple in the frontend

Assumed precedence:
- if `logo_file_path` exists, use the uploaded local file as the effective logo
- otherwise use `logo_url`

If we want explicit user override later, we can add a source selector, but that is unnecessary for the first pass.

## Backend Plan

### 1. Schema and migration

Update:
- `backend/app/models/filament.py`
- `backend/app/api/v1/schemas_filament.py`

Add a migration for the `manufacturers` table with:
- `logo_url`
- `logo_file_path`

Extend create, update, and response schemas so these fields round-trip through the API.

### 2. Upload handling

Add a dedicated upload endpoint instead of overloading the JSON `PATCH` endpoint.

Recommended endpoint:
- `POST /api/v1/manufacturers/{manufacturer_id}/logo`

Behavior:
- accept multipart form upload via `UploadFile`
- validate file is an image
- validate non-empty payload
- generate a safe unique filename
- save the file under a dedicated manufacturer-logo storage directory
- return updated manufacturer data including `logo_file_path` and `resolved_logo_url`

Also add a delete/clear path via existing `PATCH` or a small dedicated route so users can remove uploaded logos cleanly.

### 3. File storage and serving

Store uploaded logos in a single predictable location, for example:
- `backend/data/manufacturer-logos/`

Serve them under a stable frontend-visible URL, for example:
- `/media/manufacturer-logos/<filename>`

Implementation notes:
- keep stored path relative, not absolute
- do not store raw temporary upload names
- keep final URL generation centralized in backend code

### 4. Validation rules

Initial pass should validate:
- MIME type starts with `image/`
- empty files are rejected
- filename sanitized before persistence

Nice-to-have but not mandatory in phase 1:
- max file size guard
- dimension normalization
- image transcoding

## Frontend Plan

### 1. Shared API helper updates

Update `frontend/src/lib/api.ts` with a `postFormData` helper so the manufacturer editor can upload files without bypassing the shared API wrapper.

### 2. Manufacturer editor surface

Primary file:
- `frontend/src/pages/manufacturers/index.astro`

Extend the existing modal form with a new `Logo` section containing:
- file upload input
- logo URL input
- read-only display of the saved uploaded file path
- preview box showing the effective logo
- clear/remove controls for upload and URL when needed

Because manufacturer edit is modal-based in FilaMan, this plan treats that modal as the requested “manufacturer edit page.”

### 3. Manufacturer table

Add a logo column to the manufacturers table in `frontend/src/pages/manufacturers/index.astro`.

Column behavior:
- small logo thumbnail when available
- simple fallback text or placeholder when absent
- keep sorting/filtering behavior unchanged for the first pass

### 4. Shared logo rendering helper

Add a small shared frontend helper/component, likely:
- `frontend/src/components/manufacturer-logo.astro` or a small TS utility + render helper

Responsibilities:
- prefer `resolved_logo_url`
- fall back cleanly when no logo exists
- keep image sizing consistent across list/detail/edit contexts

### 5. Filament surfaces

Files:
- `frontend/src/pages/filaments/[id]/index.astro`
- `frontend/src/pages/filaments/[id]/edit.astro`

Planned visibility:
- show manufacturer logo near manufacturer name on the filament detail page
- show a small preview of the selected manufacturer logo in the filament edit page near the manufacturer selector

### 6. Spool surfaces

Files:
- `frontend/src/pages/spools/[id]/index.astro`
- `frontend/src/pages/spools/[id]/edit.astro`

Planned visibility:
- show manufacturer logo in spool detail alongside filament/manufacturer context
- show the currently selected filament's manufacturer logo in spool edit once a filament is selected

Note:
- spool edit selects filament, not manufacturer directly, so the logo preview there should derive from the chosen filament's nested manufacturer data.

## Suggested Execution Order

1. Add backend manufacturer logo columns and migration.
2. Add response fields and resolved URL logic.
3. Add upload endpoint and media serving.
4. Add shared frontend `postFormData` helper.
5. Extend manufacturer modal with URL, upload, file path, preview.
6. Add manufacturer table logo column.
7. Add logo visibility to filament show/edit.
8. Add logo visibility to spool show/edit.
9. Add i18n strings and final polish.

## Main Risks

- Upload storage needs a stable served path or the frontend will only be able to show local preview, not persisted images.
- Spool edit does not edit manufacturer directly, so the preview logic must stay read-only and derived from the selected filament.
- If we only store one logo field, upload and URL support become ambiguous. Keeping both fields avoids this.
- Large images could hurt list rendering if thumbnails are not constrained in CSS.

## Validation Targets

- Create a manufacturer with only a logo URL and verify preview and persistence.
- Upload a manufacturer logo file and verify the returned file path is shown.
- Edit a manufacturer with both fields present and verify the effective logo preview is stable.
- Confirm the manufacturer list renders logo thumbnails without breaking table layout.
- Confirm filament detail and filament edit show the correct manufacturer logo.
- Confirm spool detail and spool edit show the correct manufacturer logo for the selected filament.
- Confirm removing a logo does not break existing manufacturer data.

## Deliberate Difference From Spoolman PR 857

Spoolman PR 857 includes broader logo-pack and print-logo behavior.

For FilaMan phase 1, we should port only the core business value:
- manufacturer logo persistence
- upload plus URL support
- UI visibility across manufacturer, filament, and spool screens

Print-specific logo workflows can follow in a later phase once the base logo model is stable.
24 changes: 14 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
# FilaMan - Filament Management System

### Support the FilaMan Project
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/X8X51V6SLP)
## Fork Project Status / Roadmap

### ♻️ Support Recycling Fabrik
Empty spools don't belong in the trash! We support the [Recycling Fabrik](https://recyclingfabrik.com/). Send your empty filament spools and 3D printing waste there to have it recycled into new filament.
See [ROADMAP.md](./ROADMAP.md) for planned features and ongoing ideas for eventual PR push upstream.

**Exciting News:** Recycling Fabrik is the first manufacturer that will soon start shipping their filament spools with pre-programmed, FilaMan-compatible RFID tags!

*Looking for the German version? Read the [README.de.md](README.de.md).*

## About the Project
## About the Upstream Project
FilaMan is a comprehensive filament management system for 3D printing. It helps you keep track of your filament spools, manufacturers, colors, and current stock levels. It also features integrations with printers and AMS (Automatic Material System) units.

### Documentation
Expand Down Expand Up @@ -187,4 +181,14 @@ OIDC_ENC_KEY=your-fernet-key
- Static Build

## License
MIT
MIT

### Support the FilaMan Project
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/X8X51V6SLP)

### ♻️ Support Recycling Fabrik
Empty spools don't belong in the trash! We support the [Recycling Fabrik](https://recyclingfabrik.com/). Send your empty filament spools and 3D printing waste there to have it recycled into new filament.

**Exciting News:** Recycling Fabrik is the first manufacturer that will soon start shipping their filament spools with pre-programmed, FilaMan-compatible RFID tags!

*Looking for the German version? Read the [README.de.md](README.de.md).*
14 changes: 14 additions & 0 deletions Roadmap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
1) create plugin for filament-swatch to work in Filaman
2) speed up screen refresh from database read - is slow to populate
3) Add filament print PR (PR846 spoolman basis)
4) Add label export workflow (PNG/AML) (PR860 spoolman basis)
5) Add Manufacturer Logo inclusion and improvement to Label design & filament/spool show pages (PR857)
a) template text field instead of clicks (select "simple" vs "detail")
7) Add Plugin for manufacturer logo sync (PR872)
8) Add Formula field extra field capability JSON (PR885)
9) Move spool & filament list filtering to columns
10) column resize and reorder
11) global action buttons (edit/delete) from text to icons
12) extra fields as selectable in table views
13) Spoolmandb import bug: fails
14) Spoolmandb language
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""add_manufacturer_logo_fields

Revision ID: c9a1e6f4b2d0
Revises: b37af859a415
Create Date: 2026-04-01 16:30:00.000000

"""

from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision: str = "c9a1e6f4b2d0"
down_revision: Union[str, Sequence[str], None] = "b37af859a415"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
with op.batch_alter_table("manufacturers") as batch_op:
batch_op.add_column(sa.Column("logo_url", sa.String(length=500), nullable=True))
batch_op.add_column(sa.Column("logo_file_path", sa.String(length=500), nullable=True))


def downgrade() -> None:
with op.batch_alter_table("manufacturers") as batch_op:
batch_op.drop_column("logo_file_path")
batch_op.drop_column("logo_url")
Loading