Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
1861cbb
feat(printing): add filament label printing foundation
akira69 Feb 24, 2026
9e4cf60
docs: add changelog entry for printing updates
akira69 Feb 11, 2026
dcfc8e7
perf(printing): paginate filament selector and clarify print page titles
akira69 Feb 25, 2026
b9432d0
i18n(printing): use explicit filament/spool print page titles
akira69 Feb 25, 2026
8420604
refactor: Extract search filter logic to helper function
akira69 Mar 16, 2026
1816839
perf(printing): Memoize filament selector callbacks with useCallback
akira69 Mar 16, 2026
bd56610
refactor(api): Cache get_extra_fields once per endpoint (Donkie feedb…
akira69 Mar 17, 2026
012b8f3
feat(export): add separate AML/PNG label export flows and improvements
akira69 Mar 10, 2026
476c269
docs(export): clarify PR 860 label export comments
akira69 Mar 13, 2026
58a5045
Harden export dialog preset recovery
akira69 Mar 14, 2026
2ab3e4a
Carry filament search foundation into export flow
akira69 Mar 15, 2026
db85224
Harden QR dialog base URL parsing
akira69 Mar 15, 2026
4c242a4
feat(export): add separate AML/PNG label export flows with improved b…
akira69 Mar 15, 2026
e81b670
perf(export): Memoize spool selector callbacks with useCallback
akira69 Mar 16, 2026
f20897d
feat(manufacturers): add logo-aware UI and label workflows on top of …
akira69 Mar 16, 2026
d127692
fix: unified search param for filament modal + Ruff violations
akira69 Mar 17, 2026
fda598b
fix(typescript): add missing exports, props, and export button in PR857
akira69 Mar 18, 2026
5e1260b
fix(react): propagate spread/Set/module-scope fixes from PR846 + PR860
akira69 Mar 18, 2026
a5a892e
fix(printing): carry forward legacy-state logo fixes
akira69 Mar 27, 2026
6ef61bd
feat(export): carry forward logo-aware label rendering
akira69 Mar 27, 2026
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
Empty file.
1 change: 1 addition & 0 deletions .playwright-cli/page-2026-03-14T13-04-28-164Z.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- generic [ref=e2]: loading
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Changelog

## Unreleased
- Add filament label printing with separate presets, QR codes, and filament QR scanning support.
90 changes: 88 additions & 2 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 5 additions & 4 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"i18next": "^25.7.3",
"i18next-browser-languagedetector": "^8.2.0",
"i18next-http-backend": "^3.0.2",
"jszip": "3.10.1",
"react": "^19.2.3",
"react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1",
Expand All @@ -39,19 +40,19 @@
"@refinedev/cli": "^2.16.50",
"@types/loadable__component": "^5.13.10",
"@types/node": "^25.0.3",
"@types/react-dom": "^19.2.3",
"@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3",
"@types/uuid": "^10.0.0",
"@vitejs/plugin-react": "^5.1.2",
"eslint": "^9.39.2",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.4.26",
"eslint-plugin-react": "^7.37.5",
"eslint": "^9.39.2",
"globals": "^17.0.0",
"prettier": "3.7.4",
"typescript-eslint": "^8.52.0",
"typescript": "^5.9.3",
"typescript-eslint": "^8.52.0",
"vite": "^7.3.0",
"vite-plugin-mkcert": "^1.17.9",
"vite-plugin-pwa": "^1.2.0"
Expand Down
133 changes: 126 additions & 7 deletions client/public/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
"paperSize": "Paper Size",
"customSize": "Custom",
"dimensions": "Dimensions",
"amlLabelSize": "AML Label Size",
"showBorder": "Show Border",
"previewScale": "Preview Scale",
"skipItems": "Skip Items",
Expand Down Expand Up @@ -100,15 +101,76 @@
"deleteSettingsConfirm": "Are you sure you want to delete this preset?",
"settingsName": "Preset Name",
"saveSetting": "Save Presets",
"saveAsImage": "Save as Image"
"savePreset": "Save Preset",
"saveAsImage": "Save as Image",
"saveAsAmlLabels": "Save as AML (Labels)",
"saveAsAmlPages": "Save as AML (Pages)",
"spoolImagePresets": "Spool Image Presets",
"filamentImagePresets": "Filament Image Presets",
"exportFormat": "Export Format",
"exportFormatOptions": {
"png": "PNG",
"aml": "AML"
},
"exportAsZip": "Export as .zip",
"exportDpi": "Export DPI",
"exportDpiHelp": "Higher DPI improves image quality for exports but increases file size.",
"exportLabels": "Export Labels",
"filenamePreview": "Filename Preview",
"filenamePreviewAdditional": "Additional Example",
"zipFilenamePreview": "ZIP Filename"
},
"qrcode": {
"button": "Print Labels",
"selectButton": "Print / Export Labels",
"exportButton": "Export Labels",
"selectTitle": "Export / Print Labels",
"exportFilamentTitle": "Export Filament Labels",
"exportSpoolTitle": "Export Spool Labels",
"printFilamentTitle": "Print Filament Labels",
"printSpoolTitle": "Print Spool Labels",
"title": "Label Printing",
"sectionLogo": "Logo",
"sectionTitle": "Title",
"sectionQRCode": "QR Code",
"sectionInformation": "Information",
"template": "Label Template",
"templateHelp": "Use {} to insert values of the spool object as text. For example, {id} will be replaced with the spool id, or {filament.material} will be replaced with the material of the spool. if a value is missing it will be replaced with \"?\". A second set of {} can be used to remove this. In addition, any text between the sets of {} will be removed if the value is missing. For example, {Lot Nr: {lot_nr}} will only show the label if the spool has a lot number. Enclose text with double asterix ** to make it bold. Click the button to view a list of all available tags.",
"titleTemplate": "Title Template",
"infoTemplate": "Information Template",
"templateHelp": "Use {} to insert values of the spool object as text. For example, {id} will be replaced with the spool id, or {filament.material} will be replaced with the material of the spool. if a value is missing it will be replaced with \"?\". A second set of {} can be used to remove this. In addition, any text between the sets of {} will be removed if the value is missing. For example, {Lot Nr: {lot_nr}} will only show the label if the spool has a lot number. Enclose text with double asterix ** to make it bold, and use ==text== to invert text. Click the button to view a list of all available tags.",
"templateHelpFilament": "Use {} to insert values of the filament object as text. For example, {id} will be replaced with the filament id, or {vendor.name} will be replaced with the vendor name. If a value is missing it will be replaced with \"?\". A second set of {} can be used to remove this. In addition, any text between the sets of {} will be removed if the value is missing. For example, {Article: {article_number}} will only show the label if a filament has an article number. Enclose text with double asterix ** to make it bold, and use ==text== to invert text. Click the button to view a list of all available tags.",
"textSize": "Label Text Size",
"showContent": "Print Label",
"infoTextSize": "Information Text Size",
"titleTextSize": "Title Text Size",
"titleMaxTextSize": "Title Max Text Size",
"titleAreaHeight": "Title Area Height",
"showContent": "Show Information on label",
"showManufacturerLogo": "Show Manufacturer Logo",
"logoSource": "Logo Source",
"logoSourceOptions": {
"print": "Print Logo",
"color": "Color Logo"
},
"showTitle": "Show Title",
"titleFitToWidth": "Fit Title to Width",
"titleFitToWidthOptions": {
"on": "On",
"off": "Off"
},
"appliedTextSize": "Applied Size",
"logoSize": "Logo Size",
"logoAlign": "Logo Horizontal Align",
"titleAlign": "Title Horizontal Align",
"qrCodePosition": "QR Code Position",
"qrCodePositionLeft": "Left",
"qrCodePositionRight": "Right",
"qrCodeAlign": "QR Code Vertical Align",
"qrCodeAlignTop": "Top",
"qrCodeAlignCenter": "Center",
"qrCodeAlignBottom": "Bottom",
"qrCodeSize": "QR Code Size",
"infoAlign": "Information Horizontal Align",
"infoVerticalAlign": "Information Vertical Align",
"useHTTPUrl": {
"label": "QR code link",
"tooltip": "Will use proprietary link that will work only if scanned from Spoolman's scanning feature (default). URL uses either the base URL specified in settings, or the current page URL if not set.",
Expand All @@ -123,16 +185,31 @@
"no": "No",
"simple": "Simple",
"withIcon": "With Icon"
}
},
"filenameTemplate": "Filename Template",
"filenameTemplateTooltipSpool": "Use {} to insert values of the spool object as text. Refer to the label template rules and available tags for details.",
"filenameTemplateTooltipFilament": "Use {} to insert values of the filament object as text. Refer to the label template rules and available tags for details.",
"titleTemplateTooltipSpool": "Use {} to insert values of the spool object as text. Refer to the label template rules and available tags for details.",
"titleTemplateTooltipFilament": "Use {} to insert values of the filament object as text. Refer to the label template rules and available tags for details."
},
"spoolSelect": {
"title": "Select Spools",
"description": "Select spools to print labels for.",
"searchPlaceholder": "Search vendor, name, material, lot #",
"showArchived": "Show Archived",
"noSpoolsSelected": "You have not selected any spools.",
"selectAll": "Select/Unselect All",
"selectedTotal_one": "{{count}} spool selected",
"selectedTotal_other": "{{count}} spools selected"
},
"filamentSelect": {
"title": "Select Filaments",
"description": "Select filaments to print labels for.",
"searchPlaceholder": "Search vendor, name, material, article #",
"noFilamentsSelected": "You have not selected any filaments.",
"selectAll": "Select/Unselect All",
"selectedTotal_one": "{{count}} filament selected",
"selectedTotal_other": "{{count}} filaments selected"
}
},
"scanner": {
Expand Down Expand Up @@ -269,14 +346,27 @@
"vendor": "Manufacturers",
"fields": {
"id": "ID",
"logo": "Logo",
"logo_url": "Logo URL",
"print_logo_url": "Print Logo URL",
"logo_preview": "Logo Preview",
"print_logo_preview": "Print Logo Preview",
"name": "Name",
"empty_spool_weight": "Empty Spool Weight",
"external_id": "External ID",
"registered": "Registered",
"comment": "Comment"
"comment": "Comment",
"logo_suggestions": "Logo Suggestions",
"print_logo_suggestions": "Print Logo Suggestions",
"logo_suggestions_placeholder": "Select a suggested logo path",
"logo_suggestions_none": "None"
},
"fields_help": {
"empty_spool_weight": "The weight of an empty spool from this manufacturer."
"empty_spool_weight": "The weight of an empty spool from this manufacturer.",
"logo_url": "Optional custom logo used in the UI. Supports absolute URLs or local paths like /vendor-logos/web/bambu-lab-web.png. Use any image your browser can display from that path or URL.",
"print_logo_url": "Optional custom logo used for label rendering. Supports absolute URLs or local paths like /vendor-logos/print/bambu-lab.png. Use any image your browser can display from that path or URL.",
"logo_suggestions": "Checks available logo files in /vendor-logos/web for names similar to this manufacturer.",
"print_logo_suggestions": "Checks available logo files in /vendor-logos/print for names similar to this manufacturer."
},
"titles": {
"create": "Create Manufacturer",
Expand All @@ -286,8 +376,27 @@
"show": "Show Manufacturer",
"show_title": "[Manufacturer #{{id}}] {{name}}"
},
"buttons": {
"sync_logos": "Sync Logos",
"clear_logo_url": "Clear URL",
"convert_logo_to_print": "Convert Logo to Print",
"convert_logo_to_print_help": "Creates a black-and-white print logo from the current Logo URL and stores it as a separate local print logo file.",
"convert_logo_to_print_help_locked": "A Print Logo URL is already set. Clear Print Logo URL to enable creating a new print logo from the current Logo URL."
},
"logo_filter": {
"has_logo": "Has Logo",
"no_logo": "No Logo"
},
"form": {
"vendor_updated": "This manufacturer has been updated by someone/something else since you opened this page. Saving will overwrite those changes!"
"vendor_updated": "This manufacturer has been updated by someone/something else since you opened this page. Saving will overwrite those changes!",
"logo_sync_no_match": "No matching logos found for this manufacturer name.",
"logo_sync_applied": "Suggested logo paths applied.",
"logo_preview_auto_notice": "using auto-matched logo from available logo files",
"logo_preview_default_notice": "no logo defined, using default generated text logo",
"logo_convert_requires_web_logo": "Set a Logo URL first.",
"logo_convert_requires_empty_print_logo": "Clear Print Logo URL first to generate a new print logo.",
"logo_convert_success": "Generated print logo from web logo.",
"logo_convert_error": "Could not generate a print logo from this Logo URL."
}
},
"home": {
Expand Down Expand Up @@ -322,6 +431,16 @@
"round_prices": {
"label": "Round prices",
"tooltip": "Round prices to the nearest whole number."
},
"logo_sync": {
"title": "Global Manufacturer Logo Sync",
"description": "Syncs missing logo URLs across the whole manufacturer database using the bundled logo manifest. Existing logo URLs are not overwritten.",
"where": "Source: /vendor-logos/manifest.json (bundled static web/print logo files). Matching ignores minor punctuation/case differences in names.",
"button": "Sync Logos Now",
"not_ready": "Logo manifest is not available yet.",
"load_error": "Could not load manufacturers for logo sync.",
"done": "Logo sync complete. Matched {{matched}}, updated {{updated}}.",
"scope_note": "This action syncs the whole manufacturer database. You can sync a single manufacturer from its Edit page."
}
},
"extra_fields": {
Expand Down
Loading