Skip to main content

max / makenotwork

Fix item save feedback, redesign public download list Return 'Saved.' HTML for HTMX item update requests instead of raw JSON. Redesign public item page version history as a flat download list showing version number, label (or filename), size, and download button. Renamed section from "Version History" to "Downloads". Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author: Max J. <87768334+MaxJMath@users.noreply.github.com> · 2026-05-10 23:17 UTC
Commit: f92d110c79f70a854ef9545ca44d030e2b79ba49
Parent: 4efd27a
2 files changed, +19 insertions, -14 deletions
@@ -165,10 +165,11 @@ pub struct UpdateItemRequest {
165 165 #[tracing::instrument(skip_all, name = "items::update_item", fields(item_id))]
166 166 pub(in crate::routes::api) async fn update_item(
167 167 State(state): State<AppState>,
168 + headers: HeaderMap,
168 169 AuthUser(user): AuthUser,
169 170 Path(id): Path<ItemId>,
170 171 Form(req): Form<UpdateItemRequest>,
171 - ) -> Result<impl IntoResponse> {
172 + ) -> Result<Response> {
172 173 tracing::Span::current().record("item_id", tracing::field::display(&id));
173 174 user.check_not_suspended()?;
174 175 verify_item_ownership(&state, id, user.id).await?;
@@ -254,6 +255,10 @@ pub(in crate::routes::api) async fn update_item(
254 255
255 256 db::projects::bump_cache_generation(&state.db, updated.project_id).await?;
256 257
258 + if is_htmx_request(&headers) {
259 + return Ok(axum::response::Html("Saved.".to_string()).into_response());
260 + }
261 +
257 262 Ok(Json(ItemResponse {
258 263 id: updated.id,
259 264 project_id: updated.project_id,
@@ -266,7 +271,7 @@ pub(in crate::routes::api) async fn update_item(
266 271 web_only: updated.web_only,
267 272 ai_tier: updated.ai_tier,
268 273 ai_disclosure: updated.ai_disclosure,
269 - }))
274 + }).into_response())
270 275 }
271 276
272 277 /// Soft-delete an item owned by the authenticated user (recoverable for 7 days).
@@ -366,21 +366,21 @@
366 366
367 367 {% if !versions.is_empty() %}
368 368 <section class="item-versions">
369 - <h2>Version History</h2>
369 + <h2>Downloads</h2>
370 370 {% for version in versions %}
371 - <div class="version-item">
372 - <div class="version-header">
373 - <span class="version-number">v{{ version.number }}</span>
374 - <span class="version-date">{{ version.uploaded_date }}</span>
375 - </div>
376 - {% if version.has_file %}
377 - <div class="version-download" style="margin-top: 0.5rem;">
378 - <span class="version-notes" style="margin-right: 1rem;">{{ version.size }}</span>
379 - <button class="secondary" style="padding: 0.4rem 0.8rem; font-size: 0.85rem;"
380 - onclick="downloadVersion('{{ version.id }}')">Download</button>
381 - </div>
371 + {% if version.has_file %}
372 + <div style="display: flex; align-items: center; gap: 1rem; padding: 0.6rem 0; border-bottom: 1px solid var(--border);">
373 + <span style="min-width: 4em; font-family: var(--font-mono); font-size: 0.9rem;">v{{ version.number }}</span>
374 + {% if let Some(label) = version.label %}
375 + <span style="flex: 1;">{{ label }}</span>
376 + {% else %}
377 + <span style="flex: 1; opacity: 0.5;">{% match version.file_name %}{% when Some with (name) %}{{ name }}{% when None %}Download{% endmatch %}</span>
382 378 {% endif %}
379 + <span style="font-size: 0.85rem; opacity: 0.6; min-width: 5em; text-align: right;">{{ version.size }}</span>
380 + <button class="secondary" style="padding: 0.4rem 0.8rem; font-size: 0.85rem;"
381 + onclick="downloadVersion('{{ version.id }}')">Download</button>
383 382 </div>
383 + {% endif %}
384 384 {% endfor %}
385 385 </section>
386 386 {% endif %}