Part-DB-server/templates/tools/value_calculator/_generate_modal.html.twig
Sebastian Almberg d73bc42362 Add a component value calculator & image generator
Adds a "Value calculator" tool (Tools menu) that decodes/encodes the value of
common components and generates a clean SVG picture you can attach to a part —
handy for assortments imported with blank thumbnails and sparse data.

Calculator tabs (bidirectional decode <-> encode), each drawing the part to the
selected package with a collapsible appearance panel and an "attach to part"
action (optionally as the master picture):
- Resistor: 4/5/6-band colour code
- Capacitor: value <-> 3-digit code <-> tolerance
- SMD resistor: value <-> 3-digit / 4-digit / EIA-96 code
- Inductor: colour-band code
- SMD inductor: value <-> uH code

Bulk "Generate component images" parts-table action:
- Classifies each selected part (resistor / capacitor / inductor / diode / LED,
  THT or SMD) with ComponentValueGuesser and detects value, voltage, tolerance,
  power, ppm, pitch, diameter, colour, SMD package and marking from the name,
  description and parameters.
- Renders a preview per part, lets you tweak appearance, and attaches the images
  in one go; can also write matching KiCad symbol/footprint/reference-prefix EDA
  fields.

Backend: ComponentValueGuesser (classification + detection + EDA suggestion),
GeneratedImageAttachmentHelper (stores the SVG through the existing attachment
pipeline, so it is sanitised on save), two POST endpoints on PartController
(generate_image, set_eda) guarded by `edit` + CSRF, a new `@tools.value_calculator`
permission, a Tools-tree entry and docs. All drawing is client-side in a Stimulus
controller; the un-sanitised live preview escapes part-derived text and validates
colours as defence-in-depth.

Tests: unit tests for ComponentValueGuesser and functional tests for the
endpoints, including permission and CSRF enforcement and the persisted side
effects.
2026-07-30 17:49:18 +02:00

23 lines
1.3 KiB
Twig

{# The value-calculator generator modal (lazy-loaded via a Turbo frame). Include ONCE per page
where a generate trigger button is shown. Expects `part` in scope. #}
{% if part.id is not null and is_granted('edit', part) and is_granted('@tools.component_image_generator') %}
<div class="modal fade" id="vcGenerateModal" tabindex="-1" aria-labelledby="vcGenerateModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xl modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="vcGenerateModalLabel">
<i class="fas fa-palette"></i> {% trans %}tools.value_calc.title{% endtrans %}
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<turbo-frame id="vc-modal-frame" src="{{ path('tools_component_image_generator', {part: part.id, modal: 1}) }}" loading="lazy">
<div class="text-center text-muted py-5">
<span class="spinner-border spinner-border-sm"></span>
</div>
</turbo-frame>
</div>
</div>
</div>
</div>
{% endif %}