Files
bookshelf/static/index.html
Petr Polezhaev b94f222c96 Add per-request AI logging, DB batch queue, WS entity updates, and UI polish
- log_thread.py: thread-safe ContextVar bridge so executor threads can log
  individual LLM calls and archive searches back to the event loop
- ai_log.py: init_thread_logging(), notify_entity_update(); WS now pushes
  entity_update messages when book data changes after any plugin or batch run
- batch.py: replace batch_pending.json with batch_queue SQLite table;
  run_batch_consumer() reads queue dynamically so new books can be added
  while batch is running; add_to_queue() deduplicates
- migrate.py: fix _migrate_v1 (clear-on-startup bug); add _migrate_v2 for
  batch_queue table
- _client.py / archive.py / identification.py: wrap each LLM API call and
  archive search with log_thread start/finish entries
- api.py: POST /api/batch returns {already_running, added}; notify_entity_update
  after identify pipeline
- models.default.yaml: strengthen ai_identify confidence-scoring instructions;
  warn against placeholder data
- detail-render.js: book log entries show clickable ID + spine thumbnail;
  book spine/title images open full-screen popup
- events.js: batch-start handles already_running+added; open-img-popup action
- init.js: entity_update WS handler; image popup close listeners
- overlays.css / index.html: full-screen image popup overlay
- eslint.config.js: add new globals; fix no-redeclare/no-unused-vars for
  multi-file global architecture; all lint errors resolved

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 12:10:54 +03:00

91 lines
3.9 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
<meta name="theme-color" content="#1e3a5f">
<title>Bookshelf</title>
<!-- Global reset, body font/background, and .hidden utility -->
<link rel="stylesheet" href="css/base.css">
<!-- Sticky header, two-column desktop layout, mobile single-column default -->
<link rel="stylesheet" href="css/layout.css">
<!-- Sidebar tree: node rows, drag handle, toggle, name, action buttons, book thumbnails, status/source badges -->
<link rel="stylesheet" href="css/tree.css">
<!-- Generic button variants, book detail panel, image/canvas wrapper, identification form -->
<link rel="stylesheet" href="css/forms.css">
<!-- Fixed-position overlays: toast notification, loading spinner, photo queue -->
<link rel="stylesheet" href="css/overlays.css">
</head>
<body>
<!-- Main app mount point — entire UI is rendered here by render() in js/init.js -->
<div id="app"></div>
<!-- Photo queue overlay: full-screen mobile UI for sequential book photography.
Lives outside #app so its event listener does not conflict with the tree. -->
<div id="photo-queue-overlay" style="display:none"></div>
<!-- Shared file input for all photo uploads (cabinet, shelf, book, room).
Triggered programmatically by triggerPhoto() in js/photo.js. -->
<input type="file" id="gphoto" accept="image/*" class="hidden">
<!-- Slide-in toast notification; text set by toast() in js/helpers.js -->
<div class="toast" id="toast"></div>
<!-- Full-screen image popup: shown when user clicks a book spine or title-page image.
Closed by clicking outside or the × button. -->
<div id="img-popup" class="img-popup">
<div class="img-popup-inner">
<button class="img-popup-close" id="img-popup-close">×</button>
<img id="img-popup-img" src="" alt="">
</div>
</div>
<!-- SortableJS: drag-and-drop reordering for rooms, cabinets, shelves, and books -->
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.2/Sortable.min.js"></script>
<!-- All mutable application state (S, _plugins, _batchState, _bnd, _photoQueue).
Must load first — every subsequent module reads these globals. -->
<script src="js/state.js"></script>
<!-- Pure utilities: esc(), toast(), isDesktop(). No dependencies. -->
<script src="js/helpers.js"></script>
<!-- Fetch wrapper req(). Throws on non-2xx with server detail message. -->
<script src="js/api.js"></script>
<!-- Boundary-line canvas editor: draw, drag, snap-to-AI, Ctrl+Alt+Click to add.
Defines _bnd structure — loaded before detail-render.js which reads it. -->
<script src="js/canvas-boundary.js"></script>
<!-- Tree HTML generators: vApp(), vRoom/Cabinet/Shelf/Book(), vBatchBtn(),
plugin helpers, candidate suggestion rows, walkTree/findNode/removeNode. -->
<script src="js/tree-render.js"></script>
<!-- Detail panel HTML generators: vDetailBody(), vCabinetDetail(),
vShelfDetail(), vBookDetail(). Reads _bnd for boundary plugin selection. -->
<script src="js/detail-render.js"></script>
<!-- In-place crop tool: draggable rectangle on canvas, POSTs pixel coords.
Calls drawBnd() on cancel to restore the boundary overlay. -->
<script src="js/canvas-crop.js"></script>
<!-- Inline contenteditable name editing (blur-to-save) and SortableJS wiring. -->
<script src="js/editing.js"></script>
<!-- Photo upload for all entity types and mobile Photo Queue feature.
Registers the gphoto 'change' handler at parse time. -->
<script src="js/photo.js"></script>
<!-- Event delegation on #app and #photo-queue-overlay; central handle() dispatcher
with all action cases; accordion expand helpers. -->
<script src="js/events.js"></script>
<!-- render(), renderDetail(), loadConfig(), connectBatchWs(), loadTree(),
and the bootstrap Promise.all([loadConfig(), loadTree()]) call. -->
<script src="js/init.js"></script>
</body>
</html>