mikael-lovqvists-claude-agent 53bd086661 Make source-use badges read-only display labels
Removing toggle interactivity from use badges — they were confusing
and the wrong place to manage uses. The uses array is now managed
automatically by upload context. Badges are plain spans.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 04:41:44 +00:00

Electronics Inventory

A self-hosted web app for managing an electronics component collection. Track components, their field values, physical storage locations, and visual panel/grid layouts.

Features

Components

Define reusable component types (e.g. Resistor, Capacitor, IC) with custom fields per component. Components show up in inventory entries and can be navigated to directly from storage locations.

  • Word-split search: searching 0603 res matches Resistor 0603
  • Selected component reflected in URL (/components/:id) — survives page refresh
  • Resizable list pane (width persisted in localStorage)
  • Duplicate button to quickly clone a component
  • Field values sorted alphabetically, rendered centrally (units, URLs as links, extensible)

Fields

Create custom field definitions (e.g. resistance, capacitance, package) with an optional unit suffix. Unit is appended directly to the value with no space, so you can write 4k7 for a resistance field with unit Ω and it displays as 4k7Ω.

URL-like field values (beginning with http:// or https://) are automatically rendered as clickable links.

Inventory

Log where things are stored. Each inventory entry links a component to a storage location. Supported location types:

  • Grid cell — a specific row/column in a named grid (e.g. drawer divider box), picked visually with a graphical cell picker
  • (plain entries without a grid reference work too)

Notes on inventory entries are per storage location (not per component).

Grids

Model physical storage grids (drawer organizers, parts boxes, etc.).

  1. Upload a photo of the grid
  2. Set up corner points to map the image to a logical grid (corners can extend outside image bounds)
  3. Define row/column counts
  4. Click any cell to see what's stored there — component entries are links, middle-click opens in new tab
  5. Each cell shows a green count badge of how many components reference it
  6. Navigating to a grid from a component detail highlights and scrolls to the relevant cell

PDF Attachments

Attach PDF datasheets or other documents to components.

  • PDFs are stored with a sanitized human-readable filename derived from the display name
  • Rename a PDF and the file on disk is also renamed, atomically (uses renameat2 RENAME_NOREPLACE via tools/mv-sync)
  • First-page thumbnails generated automatically via pdftoppm (poppler-utils) if available
  • Multiple components can share the same PDF
  • Click any thumbnail to open it full-size in a lightbox

Templates (Name Formatters)

Write JavaScript formatter functions that generate smart display names for components based on their field values. Example:

(c) => {
    const F = c.fields;
    if (F.resistance && F.imperial_package) {
        return `${F.resistance}Ω ${F.imperial_package}`;
    }
}

Fields are accessed by name (e.g. c.fields.resistance). If the formatter returns a non-empty string it's used as the display name; otherwise the component's base name is used as fallback. Multiple formatters are tried in order.

The template editor includes a test data box so you can preview the output without needing real inventory data.

Maintenance

A ⚙ menu in the top-right corner provides maintenance operations:

  • Generate missing PDF thumbnails — scans all PDFs and generates thumbnails for any that don't have one yet (useful if pdftoppm was unavailable at upload time)

Requirements

  • Node.js >= 25
  • npm
  • gcc (to build tools/mv-sync — only needed once)
  • pdftoppm from poppler-utils (optional, for PDF thumbnails)

Install

Install directly from the git repository — there is no npm package yet:

npm install git+https://gitea.efforting.tech/mikael-lovqvists-claude-agent/electronics-inventory.git

Or clone if you prefer to keep the source around:

git clone https://gitea.efforting.tech/mikael-lovqvists-claude-agent/electronics-inventory
cd electronics-inventory
npm install

Build native tools

cd tools && make

This compiles mv-sync, a small helper that performs an atomic rename-without-overwrite using renameat2(RENAME_NOREPLACE) (Linux 3.15+). It is required for PDF file operations.

Run

npm start

The server starts on port 3020, bound to localhost only, by default. Open http://localhost:3020 in your browser.

Both can be overridden with environment variables:

PORT=8080 npm start                        # different port
BIND_ADDRESS=0.0.0.0 npm start             # all interfaces (LAN accessible)
BIND_ADDRESS=192.168.1.50 npm start        # specific interface
PORT=8080 BIND_ADDRESS=0.0.0.0 npm start   # both

Note: The default localhost binding means the app is only reachable from the same machine. Set BIND_ADDRESS=0.0.0.0 to expose it on your local network.

Data Storage

All data is stored locally in a data/ directory created automatically on first run:

  • data/db.json — component, field, inventory, grid, template, and PDF records (flat KV store)
  • data/images/ — uploaded source images and component/inventory photos
  • data/pdfs/ — uploaded PDF files and their thumbnails

No external database is required.

Project Structure

server.mjs          Express 5 API server + SPA host
lib/
  storage.mjs       Server-side KV store wrappers
  kv-store.mjs      JSON file-backed key-value store
  ids.mjs           ID generation
  grid-image.mjs    Grid image processing helpers
tools/
  mv-sync.c         Atomic rename helper (renameat2 RENAME_NOREPLACE)
  Makefile
public/
  app.mjs           Single-page app (vanilla JS ES modules)
  templates.html    HTML templates (lazy-loaded)
  style.css         Styles
  lib/
    api.mjs         Fetch wrappers for the REST API
    dom.mjs         DOM helpers
  views/
    grid-setup.mjs  Canvas-based grid corner editor
Description
Electronics component inventory webapp with grid photography, component templates, and cell-based location tracking
Readme 1.2 MiB
Languages
JavaScript 71.7%
CSS 14.6%
HTML 13.3%
C 0.3%