Files
electronics-inventory/public/lib/api.mjs
mikael-lovqvists-claude-agent 090f6f3154 Add bin types: reusable named dimension presets for bins
Bin types store a name, physical W×H in mm, and optional description.
When editing a bin, a type can be selected from a dropdown; this
pre-fills and locks the dimension inputs. Custom dimensions remain
available when no type is selected.

- lib/storage.mjs: bin type CRUD with bt: prefix
- server.mjs: /api/bin-types CRUD routes; type_id accepted on bin
  create/update routes; DELETE protected if any bin references the type;
  type dims copied onto bin when type_id is set
- public/lib/api.mjs: bin type wrappers; rename_bin → update_bin (accepts
  any fields)
- public/templates.html: Types tab in bins section; t-bin-type-row;
  t-dialog-bin-type; type selector in bin editor dialog
- public/app.mjs: all_bin_types state loaded at startup; render_bin_types_list();
  open_bin_type_dialog(); type selector in open_bin_editor(); /bins/types routing
- public/style.css: bin types list styles

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

96 lines
4.6 KiB
JavaScript

async function req(method, path, body) {
const opts = { method, headers: {} };
if (body !== undefined) {
opts.headers['Content-Type'] = 'application/json';
opts.body = JSON.stringify(body);
}
const res = await fetch(path, opts);
const data = await res.json();
if (!data.ok) throw new Error(data.error ?? 'Request failed');
return data;
}
// Fields
export const get_fields = () => req('GET', '/api/fields');
export const create_field = (body) => req('POST', '/api/fields', body);
export const update_field = (id, body) => req('PUT', `/api/fields/${id}`, body);
export const delete_field = (id) => req('DELETE', `/api/fields/${id}`);
// Components
export const get_components = () => req('GET', '/api/components');
export const create_component = (body) => req('POST', '/api/components', body);
export const update_component = (id, body) => req('PUT', `/api/components/${id}`, body);
export const delete_component = (id) => req('DELETE', `/api/components/${id}`);
// Inventory
export const get_inventory = () => req('GET', '/api/inventory');
export const create_inventory = (body) => req('POST', '/api/inventory', body);
export const update_inventory = (id, body) => req('PUT', `/api/inventory/${id}`, body);
export const delete_inventory = (id) => req('DELETE', `/api/inventory/${id}`);
// Grid drafts
export const get_grid_drafts = () => req('GET', '/api/grid-drafts');
export const create_grid_draft = (body) => req('POST', '/api/grid-drafts', body);
export const update_grid_draft = (id, body) => req('PUT', `/api/grid-drafts/${id}`, body);
export const delete_grid_draft = (id) => req('DELETE', `/api/grid-drafts/${id}`);
// Source images
export const get_source_images = () => req('GET', '/api/source-images');
export const update_source_image_uses = (id, uses) => req('PUT', `/api/source-images/${id}`, { uses });
export const delete_source_image = (id) => req('DELETE', `/api/source-images/${id}`);
// Component templates
export const get_component_templates = () => req('GET', '/api/component-templates');
export const create_component_template = (body) => req('POST', '/api/component-templates', body);
export const update_component_template = (id, body) => req('PUT', `/api/component-templates/${id}`, body);
export const delete_component_template = (id) => req('DELETE', `/api/component-templates/${id}`);
// PDF files
export const get_pdfs = () => req('GET', '/api/pdfs');
export const rename_pdf = (id, display_name, filename) => req('PUT', `/api/pdfs/${id}`, { display_name, filename });
export const delete_pdf = (id) => req('DELETE', `/api/pdfs/${id}`);
export async function upload_pdf(file, display_name, filename) {
const form = new FormData();
form.append('file', file);
if (display_name) form.append('display_name', display_name);
if (filename) form.append('filename', filename);
const res = await fetch('/api/pdfs', { method: 'POST', body: form });
const data = await res.json();
if (!data.ok) throw new Error(data.error ?? 'Upload failed');
return data;
}
// Bin types
export const get_bin_types = () => req('GET', '/api/bin-types');
export const create_bin_type = (body) => req('POST', '/api/bin-types', body);
export const update_bin_type = (id, body) => req('PUT', `/api/bin-types/${id}`, body);
export const delete_bin_type = (id) => req('DELETE', `/api/bin-types/${id}`);
// Bins
export const get_bins = () => req('GET', '/api/bins');
export const create_bin_from_source = (source_id, name) => req('POST', '/api/bins/from-source', { source_id, name });
export const get_bin = (id) => req('GET', `/api/bins/${id}`);
export const update_bin = (id, body) => req('PUT', `/api/bins/${id}`, body);
export const update_bin_corners = (id, corners, phys_w, phys_h) => req('PUT', `/api/bins/${id}/corners`, { corners, phys_w, phys_h });
export const delete_bin = (id) => req('DELETE', `/api/bins/${id}`);
export async function upload_bin(file, name) {
const form = new FormData();
form.append('image', file);
if (name) form.append('name', name);
const res = await fetch('/api/bins', { method: 'POST', body: form });
const data = await res.json();
if (!data.ok) throw new Error(data.error ?? 'Upload failed');
return data;
}
// Maintenance
export const maintenance_pdf_thumbs = () => req('POST', '/api/maintenance/pdf-thumbs');
// Grid images
export const get_grids = () => req('GET', '/api/grid-images');
export const get_grid = (id) => req('GET', `/api/grid-images/${id}`);
export const delete_grid = (id) => req('DELETE', `/api/grid-images/${id}`);
export const update_grid_panel = (id, pi, body) => req('PUT', `/api/grid-images/${id}/panels/${pi}`, body);