Skip to main content

max / makenotwork

Add upload logic for generic file type in item wizard The content step's generic file upload (digital, plugin, etc) had a dropzone and Choose File button but no JS to handle the selected file. Wire up initDropzone, create a version, presign, upload to S3, and confirm. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author: Max J. <87768334+MaxJMath@users.noreply.github.com> · 2026-05-10 21:06 UTC
Commit: b2ec2b1a8605660a9dd7c22e35abb4bf5ff3c31e
Parent: 86d718e
1 file changed, +74 insertions, -0 deletions
@@ -441,6 +441,80 @@
441 441 <button type="button" class="secondary" style="margin-top: 0.5rem;"
442 442 onclick="document.getElementById('file-input').click()">Choose File</button>
443 443 </div>
444 + <script>
445 + (function() {
446 + 'use strict';
447 + var itemId = '{{ item_id }}';
448 + var dropArea = document.getElementById('file-upload-area');
449 + var fileInput = document.getElementById('file-input');
450 + var statusEl = document.getElementById('file-upload-status');
451 +
452 + initDropzone(dropArea, fileInput, function(file) {
453 + uploadFile(file);
454 + });
455 +
456 + function uploadFile(file) {
457 + var contentType = file.type || 'application/octet-stream';
458 + statusEl.innerHTML =
459 + '<div style="margin-top:0.5rem;">' +
460 + '<div style="display:flex;align-items:center;gap:0.5rem;">' +
461 + '<span id="file-upload-filename" style="font-size:0.85rem;"></span>' +
462 + '<span id="file-upload-percent" style="font-size:0.85rem;">0%</span></div>' +
463 + '<div style="height:6px;background:var(--border);border-radius:3px;overflow:hidden;margin-top:0.25rem;">' +
464 + '<div id="file-progress-bar" style="height:100%;width:0%;background:var(--accent,#6c5ce7);transition:width 0.15s;"></div></div></div>';
465 +
466 + var uploader = new S3Uploader({
467 + filenameEl: document.getElementById('file-upload-filename'),
468 + percentEl: document.getElementById('file-upload-percent'),
469 + progressBar: document.getElementById('file-progress-bar'),
470 + });
471 +
472 + // Create version then upload
473 + fetch('/api/items/' + itemId + '/versions', {
474 + method: 'POST',
475 + headers: Object.assign({'Content-Type': 'application/json'}, csrfHeaders()),
476 + body: JSON.stringify({ version_number: '1.0', changelog: null })
477 + })
478 + .then(function(res) {
479 + if (!res.ok) return res.json().catch(function() { return {}; }).then(function(d) {
480 + throw new Error(d.error || 'Failed to create version');
481 + });
482 + return res.json();
483 + })
484 + .then(function(verData) {
485 + return fetch('/api/versions/' + verData.id + '/upload/presign', {
486 + method: 'POST',
487 + headers: Object.assign({'Content-Type': 'application/json'}, csrfHeaders()),
488 + body: JSON.stringify({ file_name: file.name, content_type: contentType })
489 + }).then(function(res) {
490 + if (!res.ok) return res.json().catch(function() { return {}; }).then(function(d) {
491 + throw new Error(d.error || 'Failed to get upload URL');
492 + });
493 + return res.json();
494 + }).then(function(data) {
495 + return uploader.upload(data.upload_url, file, data.s3_key, contentType, data.cache_control)
496 + .then(function(s3Key) { return { s3Key: s3Key, versionId: verData.id }; });
497 + });
498 + })
499 + .then(function(result) {
500 + return fetch('/api/versions/' + result.versionId + '/upload/confirm', {
501 + method: 'POST',
502 + headers: Object.assign({'Content-Type': 'application/json'}, csrfHeaders()),
503 + body: JSON.stringify({ s3_key: result.s3Key, file_size_bytes: file.size })
504 + });
505 + })
506 + .then(function(res) {
507 + if (!res.ok) return res.json().catch(function() { return {}; }).then(function(d) {
508 + throw new Error(d.error || 'Failed to confirm upload');
509 + });
510 + statusEl.innerHTML = '<div style="margin-top:0.5rem;">Upload complete.</div>';
511 + })
512 + .catch(function(err) {
513 + statusEl.innerHTML = '<div style="margin-top:0.5rem;color:var(--error,#c0392b);">' + (err.message || 'Upload failed') + '</div>';
514 + });
515 + }
516 + })();
517 + </script>
444 518 {% endif %}
445 519
446 520 <div class="wizard-actions">