summaryrefslogtreecommitdiffstats
path: root/views/admin
diff options
context:
space:
mode:
authorKen D'Ambrosio <ken@jots.org>2026-05-13 17:46:28 +0000
committerKen D'Ambrosio <ken@jots.org>2026-05-13 17:46:28 +0000
commit7950acb21b22e7bc6f10c50e1427850de2834b24 (patch)
tree4502b913f9719e60d363a9d08b979fd9578207d1 /views/admin
parent63ee58aac2ab7b24eecbec791757cf6ecb5a2296 (diff)
Add folder rename and background update trigger to admin UI
- Admin edit form: "Folder name" field renames the directory on save; also moves the thumbnail cache subtree to match the new path - Admin edit page: "Run Update" button spawns update.rb in a background thread, streams output into a terminal-style log panel via 1.5s polling; shows Done/Error status when complete Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'views/admin')
-rw-r--r--views/admin/album.erb65
1 files changed, 65 insertions, 0 deletions
diff --git a/views/admin/album.erb b/views/admin/album.erb
index 9d98c5e..49ec4ca 100644
--- a/views/admin/album.erb
+++ b/views/admin/album.erb
@@ -14,6 +14,13 @@
<form method="post" action="/admin/edit/<%= @rel %>">
<fieldset class="album-settings">
<legend>Album</legend>
+ <% unless @rel.empty? %>
+ <div class="form-row">
+ <label>Folder name
+ <input type="text" name="folder_name" value="<%= File.basename(@dir) %>">
+ </label>
+ </div>
+ <% end %>
<div class="form-row">
<label>Title override
<input type="text" name="album_title" value="<%= @data['title'] %>" placeholder="(use directory name)">
@@ -108,4 +115,62 @@
</ul>
</section>
<% end %>
+
+ <section class="admin-update">
+ <h2>Update</h2>
+ <p class="update-hint">Scans this album for new/removed files, extracts EXIF data, and generates missing thumbnails.</p>
+ <button id="update-btn" class="btn" onclick="startUpdate()">Run Update</button>
+ <div id="update-panel" class="update-panel hidden">
+ <div id="update-status" class="update-status"></div>
+ <pre id="update-log" class="update-log"></pre>
+ </div>
+ </section>
+
+ <script>
+ async function startUpdate() {
+ const btn = document.getElementById('update-btn');
+ const panel = document.getElementById('update-panel');
+ const log = document.getElementById('update-log');
+ const status = document.getElementById('update-status');
+ const rel = <%= @rel.to_json %>;
+
+ btn.disabled = true;
+ btn.textContent = 'Running…';
+ log.textContent = '';
+ status.textContent = 'Running…';
+ status.className = 'update-status running';
+ panel.classList.remove('hidden');
+
+ const res = await fetch('/admin/update', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+ body: new URLSearchParams({ rel })
+ });
+ const { job_id } = await res.json();
+
+ let seen = 0;
+ const poll = setInterval(async () => {
+ const r = await fetch('/admin/update/' + job_id);
+ const data = await r.json();
+ const fresh = data.lines.slice(seen);
+ if (fresh.length) {
+ log.textContent += fresh.join('\n') + '\n';
+ log.scrollTop = log.scrollHeight;
+ seen = data.lines.length;
+ }
+ if (data.status !== 'running') {
+ clearInterval(poll);
+ btn.disabled = false;
+ btn.textContent = 'Run Update';
+ if (data.status === 'done') {
+ status.textContent = 'Done ✓';
+ status.className = 'update-status done';
+ } else {
+ status.textContent = 'Error ✗';
+ status.className = 'update-status error';
+ }
+ }
+ }, 1500);
+ }
+ </script>
</div>