From 13ab5867c72dd1f9cd8007a6f1ca0c7e05231bbd Mon Sep 17 00:00:00 2001 From: mikael-lovqvists-claude-agent Date: Sun, 22 Mar 2026 02:54:14 +0000 Subject: [PATCH] Update README and future-plans to reflect current state README: add PDF attachments, maintenance menu, mv-sync build step, resizable pane, URL-based navigation, word-split search, grid highlights. future-plans: add render_field_value integrations, field types, PDF paging, inventory/grid URL state; update state variable list. Co-Authored-By: Claude Sonnet 4.6 --- README.md | 65 +++++++++++++++++++++++++++++++++++++++++++------ future-plans.md | 59 +++++++++++++++++++++++++++++++------------- 2 files changed, 99 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 70b7b8c..103ed76 100644 --- a/README.md +++ b/README.md @@ -9,24 +9,49 @@ field values, physical storage locations, and visual panel/grid layouts. 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`) that can be attached -to any component. Field values are entered per-component instance. +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) +- **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 +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 +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 @@ -48,10 +73,18 @@ 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 @@ -69,6 +102,15 @@ cd electronics-inventory npm install ``` +## Build native tools + +```bash +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 ```bash @@ -94,8 +136,9 @@ PORT=8080 BIND_ADDRESS=0.0.0.0 npm start # both All data is stored locally in a `data/` directory created automatically on first run: -- `data/db.json` — component, field, inventory, grid, and template records (flat key-value store) -- `data/uploads/` — source images uploaded for grid setup +- `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. @@ -107,11 +150,17 @@ 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 + lib/ + api.mjs Fetch wrappers for the REST API + dom.mjs DOM helpers views/ grid-setup.mjs Canvas-based grid corner editor ``` diff --git a/future-plans.md b/future-plans.md index 6d71dd2..59e36c3 100644 --- a/future-plans.md +++ b/future-plans.md @@ -1,26 +1,25 @@ # Future Plans -## Big refactor: app architecture +## App architecture ### parse_url mutates too many module-level variables `parse_url()` directly assigns to a large number of module-level state variables (`section`, `grid_view_state`, `grid_tab`, `current_grid_id`, `grid_draft`, -`current_panel_idx`, `grid_source_id`). This is fragile and hard to reason about. +`current_panel_idx`, `grid_source_id`, `highlight_cell`, `selected_component_id`). +This is fragile and hard to reason about. Preferred direction: represent the full UI state as a single immutable state object, -and have `parse_url()` return a new state value rather than mutating globals. -Something like: +and have `parse_url()` return a new state value rather than mutating globals: ```js function parse_url(path) { - // returns a state object, touches nothing external return { section, grid_view_state, current_grid_id, ... }; } +state = parse_url(location.pathname); render(state); ``` -Then the caller assigns it: `state = parse_url(location.pathname); render(state);` ### render() if/else chain -The render dispatcher violates stated preferences — long chains of bare `else if` -branches. Replace with a lookup table of arrow functions: +The render dispatcher is a long chain of bare `else if` branches. Replace with a +lookup table: ```js const SECTION_RENDERERS = { components: render_components, @@ -29,14 +28,40 @@ const SECTION_RENDERERS = { grids: render_grids, templates: render_templates, }; - -function render() { - sync_nav(); - SECTION_RENDERERS[section]?.(); -} +function render() { sync_nav(); SECTION_RENDERERS[section]?.(); } ``` -### General module structure -As the app grows, `app.mjs` is becoming a monolith. Consider splitting into -per-section modules (e.g. `views/components.mjs`, `views/grids.mjs`) that each -export their render function and own their local state. +### app.mjs monolith +`app.mjs` is large. Consider splitting into per-section modules +(`views/components.mjs`, `views/grids.mjs`, etc.) that each export their render +function and own their local state. + +## Field system + +### Field rendering integrations +`render_field_value()` in `app.mjs` is the central place for field display logic. +Planned extensions: +- Mouser/Digi-Key part number fields → auto-craft links to product pages +- More URL-like patterns (without `https://` prefix) + +### Field types +Currently all field values are free-text strings. Could benefit from typed fields +(numeric, enum/dropdown) for better formatting and validation. + +## PDF / files + +### PDF page count and multi-page navigation +Currently only the first page thumbnail is shown. Could show page count and allow +browsing pages in the lightbox. + +## Inventory + +### Inventory URL reflects selected entry +Similar to how components now reflect `/components/:id` in the URL, inventory +entries have no URL state — refreshing loses context. + +## Grids + +### Grid URL state +Navigating into a grid viewer updates the URL correctly, but the grid list and +draft state have no URL representation.