Skip to content

Commit

Permalink
66 - Upload Form in Item Detail View
Browse files Browse the repository at this point in the history
  • Loading branch information
codingforentrepreneurs committed Jan 16, 2024
1 parent 468e74e commit f15ab5b
Show file tree
Hide file tree
Showing 7 changed files with 206 additions and 120 deletions.
4 changes: 4 additions & 0 deletions src/items/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ def get_files_url(self):
# return f"/items/{self.id}/"
return reverse("items:files", kwargs={"id": self.id})

def get_upload_url(self):
# return f"/items/{self.id}/"
return reverse("items:upload", kwargs={"id": self.id})

def get_edit_url(self):
# return f"/items/{self.id}/"
return reverse("items:edit", kwargs={"id": self.id})
Expand Down
2 changes: 2 additions & 0 deletions src/items/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ def item_upload_view(request, id=None):
# detail_url = instance.get_absolute_url()
# return redirect(detail_url)
template_name = 'items/file-upload.html'
if request.htmx:
template_name = 'items/snippets/upload.html'
if request.method == "POST":
print(request.POST)
file_name = request.POST.get('file_name')
Expand Down
32 changes: 32 additions & 0 deletions src/static/css/cfehome-ui.css
Original file line number Diff line number Diff line change
Expand Up @@ -1563,6 +1563,14 @@ input:checked + .toggle-bg {
max-height: 80vh;
}

.max-h-\[10vh\] {
max-height: 10vh;
}

.max-h-10 {
max-height: 2.5rem;
}

.w-1\/2 {
width: 50%;
}
Expand Down Expand Up @@ -1743,6 +1751,12 @@ input:checked + .toggle-bg {
margin-bottom: calc(1rem * var(--tw-space-y-reverse));
}

.space-y-2 > :not([hidden]) ~ :not([hidden]) {
--tw-space-y-reverse: 0;
margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));
margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));
}

.divide-y > :not([hidden]) ~ :not([hidden]) {
--tw-divide-y-reverse: 0;
border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse)));
Expand Down Expand Up @@ -2053,6 +2067,11 @@ input:checked + .toggle-bg {
line-height: 1rem;
}

.text-3xl {
font-size: 1.875rem;
line-height: 2.25rem;
}

.font-extrabold {
font-weight: 800;
}
Expand All @@ -2065,6 +2084,10 @@ input:checked + .toggle-bg {
font-weight: 600;
}

.font-bold {
font-weight: 700;
}

.uppercase {
text-transform: uppercase;
}
Expand Down Expand Up @@ -2256,6 +2279,10 @@ input:checked + .toggle-bg {
text-decoration-line: underline;
}

.focus\:z-10:focus {
z-index: 10;
}

.focus\:border-0:focus {
border-width: 0px;
}
Expand Down Expand Up @@ -2527,6 +2554,11 @@ input:checked + .toggle-bg {
--tw-ring-color: rgb(30 58 138 / var(--tw-ring-opacity));
}

:is(.dark .dark\:focus\:ring-gray-700:focus) {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(55 65 81 / var(--tw-ring-opacity));
}

@media (min-width: 640px) {
.sm\:flex-row {
flex-direction: row;
Expand Down
13 changes: 10 additions & 3 deletions src/templates/items/detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,22 @@
{% block content %}

<div class="flex space-x-4">
<div class="grow">
<div class="grow space-y-4">
<div
class=""
hx-get="{{ instance.get_upload_url }}"
hx-trigger="load"></div>

<div
class="max-h-[80vh] overflow-y-auto"
hx-get="{{ instance.get_files_url }}"
hx-trigger="load"></div>
</div>
<div>
<h1>{{ instance.title }}</h1>
<h1>{{ instance.get_prefix }}</h1>
<h1 class="text-4xl font-extrabold dark:text-white">{{ instance.title }}</h1>
{% if instance.description %}
<div class="my-4 text-lg text-gray-500">{{ instance.description|linebreaks }}</div>
{% endif %}



Expand Down
111 changes: 1 addition & 110 deletions src/templates/items/file-upload.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,116 +5,7 @@

<div class="flex space-x-4">
<div class="grow">
<div class="hidden upload-progress-display">Loading</div>
<form method="post" id="upload-form">
<input type="hidden" value="{{ request.build_absolute_uri }}" name="endpoint" />
<input type="file" id="file-id" name="file" multiple />
<button type="submit" id="upload-button" >Upload to S3</button>
</form>

{% include 'items/snippets/upload.html' with instance=instance %}
</div>
</div>

<script>
const uploadForm = document.getElementById('upload-form')
if (uploadForm) {
uploadForm.addEventListener("submit", handleSubmitEvent)
}

function toggleLoadingDisplay (isLoading){
const loadingDisplayElement = document.getElementsByClassName('upload-progress-display')
for (let el of loadingDisplayElement) {
if (isLoading) {
el.classList.remove('hidden')
} else {
el.classList.add('hidden')
}


}
}

function handleSubmitEvent(event) {
event.preventDefault()
const fileInput = uploadForm.querySelector('[name="file"]')
const endpointInput = uploadForm.querySelector('[name="endpoint"]')
const signingEndpoint = endpointInput.value
const file = fileInput.files[0]
const hxHeaders = document.body.getAttribute('hx-headers')
const csrfToken = JSON.parse(hxHeaders)['X-CSRFToken'];
let completedFiles = []
for (let file of fileInput.files) {
toggleLoadingDisplay(true)
presignFileForUpload(file, signingEndpoint, csrfToken, (data)=>{
handleS3Upload(file, data, (progressEvent)=>{
console.log(progressEvent)
if (progressEvent.loaded/progressEvent.total > 0.98) {
completedFiles.push(file)
}
if (completedFiles.length == fileInput.files.length) {
resetForm()
}
})
})
}
}

function resetForm(){
const uploadForm = document.getElementById('upload-form')
toggleLoadingDisplay(false)
uploadForm.reset()
}

function handleS3Upload(file, data, callback){
const fileName = data.filename ? data.filename : file.name
const newFileObject = new File([file], fileName, {type: file.type})
console.log("ready for s3", data, newFileObject)
const url = data.url ? data.url : null
if (!url) {
alert("Error with your request, please try again.")
return
} else {
// perform the upload to s3 bucket
const xhr = new XMLHttpRequest()
xhr.open('PUT', url, true)
xhr.upload.onprogress = (event) => {
callback(event)
// setFileUploadState(event)
}
xhr.onload = function() {
// console.log('no error', xhr.status, xhr)
// if (xhr.status === 200) {
// resetForm()
// } else {
// alert(xhr.statusText)
// }

}
xhr.onerror = function() {
// console.log('error', xhr.status)
resetForm()
}
xhr.setRequestHeader('Content-Type', newFileObject.type)
xhr.send(newFileObject)

}

}
function presignFileForUpload(file, endpoint, csrfToken, callback) {
const fileName = file.name
const formData = new FormData()
formData.append("file_name", fileName)
fetch(endpoint,
{
method: "POST",
body: formData,
headers: {
"X-CSRFTOKEN": csrfToken,
}
}).then(response=>response.json())
.then(data=>{
callback(data)
}).catch(err=>console.log('err', err))
}
</script>
{% endblock content %}
41 changes: 34 additions & 7 deletions src/templates/items/snippets/object-table.html
Original file line number Diff line number Diff line change
@@ -1,12 +1,35 @@





<div class="relative overflow-x-auto">
<table class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">
<thead class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
<tr>
<th scope="col" class="px-6 py-3">
File
</th>
<th scope="col" class="px-6 py-3">
Actions
</th>
</tr>
</thead>
<tbody>



{% for object_dict in object_list %}
<tr class="bg-white dark:bg-gray-800">
<th scope="row" class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white">
{% if object_dict.is_image %}
<img class="max-h-10" src="{{ object_dict.url }}" />
{% endif %} {{ object_dict.name }}

</th>

<div class="mb-5" id="object-{{ forloop.counter }}">
{{ object_dict.name }}
{% if object_dict.is_image %}
<img src="{{ object_dict.url }}" />
{% endif %}
<a class="hover:pointer font-medium text-blue-600 dark:text-blue-500 hover:underline" href="{{ object_dict.download_url }}">Download</a>
<td class="px-6 py-4">
<a class="hover:pointer font-medium text-blue-600 dark:text-blue-500 hover:underline" href="{{ object_dict.download_url }}">Download</a>
<a class="hover:pointer font-medium text-gray-800 dark:text-gray-300 hover:underline" href="{{ object_dict.url }}">View in Browser</a>
{% if instance %}
<button
Expand All @@ -18,6 +41,10 @@
Delete
</button>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>

{% endfor %}
Loading

0 comments on commit f15ab5b

Please sign in to comment.