From 9227578a9b5381e6447808f0899050b08540186f Mon Sep 17 00:00:00 2001 From: Michael Olund Date: Mon, 28 Sep 2020 15:28:40 -0700 Subject: [PATCH 01/20] restoring upload state #1 --- edivorce/apps/core/models.py | 21 +++++++++++ edivorce/apps/core/views/api.py | 23 ++----------- vue/src/components/Uploader/Uploader.vue | 44 +++++++++++++++++++++--- 3 files changed, 64 insertions(+), 24 deletions(-) diff --git a/edivorce/apps/core/models.py b/edivorce/apps/core/models.py index 39d186f1..0b1dddfa 100644 --- a/edivorce/apps/core/models.py +++ b/edivorce/apps/core/models.py @@ -1,3 +1,5 @@ +import re + from django.contrib import admin from django.db import models from django.db.models import F @@ -173,6 +175,9 @@ class Document(models.Model): def get_file_url(self): return reverse('document', kwargs={'filename': self.filename, 'doc_type': self.doc_type, 'party_code': self.party_code, 'size': self.size}) + def get_content_type(self): + return Document.content_type_from_filename(self.filename) + def update_sort_orders(self): q = Document.objects.filter(bceid_user=self.bceid_user, doc_type=self.doc_type, party_code=self.party_code, sort_order__gt=self.sort_order) q.update(sort_order=F('sort_order') - 1) @@ -181,6 +186,22 @@ class Document(models.Model): def get_file(file_key): return redis.RedisStorage().open(file_key) + @staticmethod + def content_type_from_filename(filename): + content_types = { + "pdf": "application/pdf", + "gif": "image/gif", + "png": "image/png", + "jpe": "image/jpeg", + "jpg": "image/jpeg", + "jpeg": "image/jpeg" + } + extension = re.split(r'[\._]', filename.lower())[-1] + content_type = content_types.get(extension) + if not content_type: + return "application/unknown" + return content_type + class DontLog: def log_addition(self, *args): diff --git a/edivorce/apps/core/views/api.py b/edivorce/apps/core/views/api.py index 819e2c11..bde64568 100644 --- a/edivorce/apps/core/views/api.py +++ b/edivorce/apps/core/views/api.py @@ -1,5 +1,3 @@ -import re - import graphene import graphene_django from django.http import Http404, HttpResponse, HttpResponseGone @@ -82,7 +80,7 @@ class DocumentView(RetrieveUpdateDestroyAPIView): def retrieve(self, request, *args, **kwargs): """ Return the file instead of meta data """ document = self.get_object() - content_type = _content_type_from_filename(document.filename) + content_type = Document.content_type_from_filename(document.filename) # If file doesn't exist anymore, delete it try: @@ -95,31 +93,16 @@ class DocumentView(RetrieveUpdateDestroyAPIView): def get_document_file_by_key(request, file_key): file = Document.get_file(file_key) - content_type = _content_type_from_filename(file.name) + content_type = Document.content_type_from_filename(file.name) try: return HttpResponse(file, content_type=content_type) except TypeError: raise Http404("File not found") -def _content_type_from_filename(filename): - content_types = { - "pdf": "application/pdf", - "gif": "image/gif", - "png": "image/png", - "jpe": "image/jpeg", - "jpg": "image/jpeg", - "jpeg": "image/jpeg" - } - extension = re.split(r'[\._]', filename.lower())[-1] - content_type = content_types.get(extension) - if not content_type: - raise TypeError(f'Filetype "{extension}" not supported') - return content_type - - class DocumentType(graphene_django.DjangoObjectType): file_url = graphene.String(source='get_file_url') + content_type = graphene.String(source='get_content_type') class Meta: model = Document diff --git a/vue/src/components/Uploader/Uploader.vue b/vue/src/components/Uploader/Uploader.vue index 5b3b6a00..d811f297 100644 --- a/vue/src/components/Uploader/Uploader.vue +++ b/vue/src/components/Uploader/Uploader.vue @@ -248,8 +248,8 @@ export default { newFile.rotation = 0; const img = new Image(); img.onload = function() { - newFile.width = this.width; - newFile.height = this.height; + newFile.width = this.width || 0; + newFile.height = this.height || 0; } img.src = newFile.objectURL; } @@ -261,7 +261,10 @@ export default { const url = `${urlbase}/${this.docType}/${this.party}/${file.size}/${encFilename}`; axios.delete(url) .then(response => { - this.$refs.upload.remove(file) + var pos = this.files.findIndex(f => f.docType === file.docType && f.size === file.size); + if (pos > -1) { + this.files.splice(pos, 1); + } }) .catch((error) => { this.showError('Error deleting document from the server: ' + file.name); @@ -320,7 +323,7 @@ export default { query: ` mutation updateMetadata { updateMetadata(input:${graphQLData}){ - documents{filename size width height rotation} + documents{filename size width height rotation contentType} } } `}) @@ -334,6 +337,39 @@ export default { } }, created() { + // get saved state from the server + const url = `${this.$parent.proxyRootPath}api/graphql/`; + axios.post(url, { + query: ` + query getMetadata { + documents(docType:"${this.docType}",partyCode:${this.party}) { + filename size width height rotation contentType + } + } + `, + variables: null}) + .then(response => { + console.log('response', response); + response.data.data.documents.forEach((doc) => { + this.files.push({ + name: doc.filename, + size: doc.size, + width: doc.width, + height: doc.height, + rotation: doc.rotation, + type: doc.contentType, + error: false, + success: true, + progress: '100.00', + objectURL: `${this.$parent.proxyRootPath}api/documents/${this.docType}/${this.party}/${doc.size}/${doc.filename}` + }); + }); + }) + .catch((error) => { + this.showError('Error getting metadata'); + console.log('error', error); + }); + // call the API to update the metadata every second, but only if // the data has changed (throttling requests because rotating and // re-ordering images can cause a lot of traffic and possibly From 77aab85a426326d726e285690208d80079a08e36 Mon Sep 17 00:00:00 2001 From: Michael Olund Date: Mon, 28 Sep 2020 18:10:29 -0700 Subject: [PATCH 02/20] Fixed broken test --- edivorce/apps/core/tests/test_logic.py | 33 ++++++++++++-------------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/edivorce/apps/core/tests/test_logic.py b/edivorce/apps/core/tests/test_logic.py index f40c7186..94dc2b37 100644 --- a/edivorce/apps/core/tests/test_logic.py +++ b/edivorce/apps/core/tests/test_logic.py @@ -5,7 +5,7 @@ from django.test import TestCase from edivorce.apps.core.models import BceidUser, UserResponse from edivorce.apps.core.utils.conditional_logic import get_cleaned_response_value, get_num_children_living_with from edivorce.apps.core.utils.user_response import get_data_for_user -from edivorce.apps.core.views.api import _content_type_from_filename +from edivorce.apps.core.models import Document class ConditionalLogicTestCase(TestCase): @@ -56,20 +56,17 @@ class ConditionalLogicTestCase(TestCase): class ViewLogic(TestCase): def test_content_type_from_filename(self): - self.assertEqual(_content_type_from_filename('test_file1.pdf'), 'application/pdf') - self.assertEqual(_content_type_from_filename('redis_key_test_file1_pdf'), 'application/pdf') - self.assertEqual(_content_type_from_filename('test_file2.png'), 'image/png') - self.assertEqual(_content_type_from_filename('redis_key_test_file2_png'), 'image/png') - self.assertEqual(_content_type_from_filename('Test File 3.GIF'), 'image/gif') - self.assertEqual(_content_type_from_filename('redis_key_test_file_3_GIF'), 'image/gif') - self.assertEqual(_content_type_from_filename('Test_File--4.JPEG'), 'image/jpeg') - self.assertEqual(_content_type_from_filename('redis_key_test_file_4_jpeg'), 'image/jpeg') - self.assertEqual(_content_type_from_filename('TestFile5.jpe'), 'image/jpeg') - self.assertEqual(_content_type_from_filename('redis_key_test_file_5_jpe'), 'image/jpeg') - self.assertEqual(_content_type_from_filename('testFile6.jpeg'), 'image/jpeg') - self.assertEqual(_content_type_from_filename('redis_key_testfile_6_jpeg'), 'image/jpeg') - - with self.assertRaises(TypeError): - _content_type_from_filename('test_file7.HEIC') - with self.assertRaises(TypeError): - _content_type_from_filename('redis_key_testfile_7_svg') + self.assertEqual(Document.content_type_from_filename('test_file1.pdf'), 'application/pdf') + self.assertEqual(Document.content_type_from_filename('redis_key_test_file1_pdf'), 'application/pdf') + self.assertEqual(Document.content_type_from_filename('test_file2.png'), 'image/png') + self.assertEqual(Document.content_type_from_filename('redis_key_test_file2_png'), 'image/png') + self.assertEqual(Document.content_type_from_filename('Test File 3.GIF'), 'image/gif') + self.assertEqual(Document.content_type_from_filename('redis_key_test_file_3_GIF'), 'image/gif') + self.assertEqual(Document.content_type_from_filename('Test_File--4.JPEG'), 'image/jpeg') + self.assertEqual(Document.content_type_from_filename('redis_key_test_file_4_jpeg'), 'image/jpeg') + self.assertEqual(Document.content_type_from_filename('TestFile5.jpe'), 'image/jpeg') + self.assertEqual(Document.content_type_from_filename('redis_key_test_file_5_jpe'), 'image/jpeg') + self.assertEqual(Document.content_type_from_filename('testFile6.jpeg'), 'image/jpeg') + self.assertEqual(Document.content_type_from_filename('redis_key_testfile_6_jpeg'), 'image/jpeg') + self.assertEqual(Document.content_type_from_filename('test_file7.HEIC'), 'application/unknown') + self.assertEqual(Document.content_type_from_filename('redis_key_testfile_7_svgg'), 'application/unknown') From 54e54049a52ccbb50739219e77e910812bf154ee Mon Sep 17 00:00:00 2001 From: Michael Olund Date: Mon, 28 Sep 2020 20:05:35 -0700 Subject: [PATCH 03/20] Bug fixes to uploader --- vue/src/components/Uploader/Uploader.vue | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/vue/src/components/Uploader/Uploader.vue b/vue/src/components/Uploader/Uploader.vue index d811f297..066f7a8e 100644 --- a/vue/src/components/Uploader/Uploader.vue +++ b/vue/src/components/Uploader/Uploader.vue @@ -241,15 +241,19 @@ export default { } // Add extra data to to the file object - newFile.objectURL = '' + newFile.objectURL = ''; + newFile.width = 0; + newFile.height = 0; + newFile.rotation = 0; let URL = window.URL || window.webkitURL if (URL && URL.createObjectURL) { newFile.objectURL = URL.createObjectURL(newFile.file) - newFile.rotation = 0; const img = new Image(); + const self = this; img.onload = function() { newFile.width = this.width || 0; newFile.height = this.height || 0; + self.saveMetaData(); } img.src = newFile.objectURL; } From 2983562398296dfb46f25c411f0696ba05585c0b Mon Sep 17 00:00:00 2001 From: Michael Olund Date: Mon, 28 Sep 2020 20:06:14 -0700 Subject: [PATCH 04/20] DIV-1148 - Started implementing fixes from visual design review --- vue/src/components/Uploader/Image.vue | 15 +++++----- vue/src/components/Uploader/ItemTile.vue | 35 ++++++++++++++++++------ vue/src/components/Uploader/Uploader.vue | 3 +- 3 files changed, 36 insertions(+), 17 deletions(-) diff --git a/vue/src/components/Uploader/Image.vue b/vue/src/components/Uploader/Image.vue index 12dd6ec0..e0b8a448 100644 --- a/vue/src/components/Uploader/Image.vue +++ b/vue/src/components/Uploader/Image.vue @@ -92,11 +92,12 @@ export default { i.fa-file-pdf-o, i.fa-frown-o { display: block; - font-size: 105px; - margin-left: 32px; - margin-top: 15px; - position: absolute; - top: 0; + font-size: 48px; + margin-left: 60px; + } + + i.fa-file-pdf-o { + color: #D5D5D5; } i.fa-frown-o { @@ -112,7 +113,7 @@ export default { } &.valid:hover { - background-color: #6484d3; + background-color: #365EBE; cursor: pointer; button.btn-remove { @@ -129,7 +130,7 @@ export default { } &:hover img { - opacity: 0.3; + opacity: 0.12; } } diff --git a/vue/src/components/Uploader/ItemTile.vue b/vue/src/components/Uploader/ItemTile.vue index b9c44196..7459e78e 100644 --- a/vue/src/components/Uploader/ItemTile.vue +++ b/vue/src/components/Uploader/ItemTile.vue @@ -3,7 +3,12 @@
- {{file.name}} ({{ Math.round(file.size/1024/1024 * 100) / 100 }} MB) +
+ {{file.name}} +
+
+ ({{ Math.round(file.size/1024/1024 * 100) / 100 }} MB) +
@@ -71,19 +76,31 @@ export default { .item-text { text-align: center; - min-height: 75px; - max-height: 75px; - overflow: hidden; - padding: 5px; - line-height: 1.05; - font-size: 0.95em; + padding: 10px; + padding-bottom: 4px; + font-size: 16px; + line-height: 24px; + min-height: 87px; + + + .filename-text { + min-height: 25px; + max-height: 50px; + overflow: hidden; + overflow-wrap: anywhere;; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + } - .no-wrap { - white-space: nowrap; + .size-text { + min-height: 25px; + max-height: 25px; } } .button-wrapper { + margin-top: -4px; text-align: center; } diff --git a/vue/src/components/Uploader/Uploader.vue b/vue/src/components/Uploader/Uploader.vue index 066f7a8e..99a81b79 100644 --- a/vue/src/components/Uploader/Uploader.vue +++ b/vue/src/components/Uploader/Uploader.vue @@ -409,9 +409,10 @@ export default { border: 2px #365EBE dashed; border-radius: 6px; padding: 18px; + margin-bottom: 5px; &.dragging { - background-color: #F2E3F2; + background-color: #D7DFF2; } .cards { From 090425150b71035906475521576418ec91c896cc Mon Sep 17 00:00:00 2001 From: Michael Olund Date: Mon, 28 Sep 2020 20:47:58 -0700 Subject: [PATCH 05/20] Refactored calls to saveMetaData() --- vue/src/components/Uploader/Uploader.vue | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/vue/src/components/Uploader/Uploader.vue b/vue/src/components/Uploader/Uploader.vue index 99a81b79..1a3120ec 100644 --- a/vue/src/components/Uploader/Uploader.vue +++ b/vue/src/components/Uploader/Uploader.vue @@ -163,8 +163,6 @@ export default { // upload is complete if (newFile && oldFile && !newFile.active && oldFile.active) { - this.saveMetaData(); - if (newFile.xhr) { // Error Handling const statusCode = newFile.xhr.status; @@ -173,6 +171,8 @@ export default { const message = JSON.parse(newFile.xhr.responseText)[0]; this.showError(message); this.$refs.upload.remove(newFile); + } else if (statusCode === 403) { + this.showError('Error: Your user session has expired. Please log in again.'); } else if (statusCode !== 200 && statusCode !== 201 ) { // 500 server error: show the status text and a generic message this.showError('Error: ' + newFile.xhr.statusText + '. Please try the upload again. If this doesn\'t work, try again later.'); @@ -253,7 +253,7 @@ export default { img.onload = function() { newFile.width = this.width || 0; newFile.height = this.height || 0; - self.saveMetaData(); + self.isDirty = true; } img.src = newFile.objectURL; } @@ -321,7 +321,6 @@ export default { files: allFiles }; const graphQLData = graphQLStringify(data,{singleQuotes: false, inlineCharacterLimit: 99999}); - console.log('Call API', graphQLData); const url = `${this.$parent.proxyRootPath}api/graphql/`; axios.post(url, { query: ` From 70805bfc6f6923d28b818ff21d0d498c88b54dc2 Mon Sep 17 00:00:00 2001 From: Michael Olund Date: Mon, 28 Sep 2020 20:48:21 -0700 Subject: [PATCH 06/20] Implemented design update for uploader plus icon --- vue/src/components/Uploader/Uploader.vue | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/vue/src/components/Uploader/Uploader.vue b/vue/src/components/Uploader/Uploader.vue index 1a3120ec..3a2010ea 100644 --- a/vue/src/components/Uploader/Uploader.vue +++ b/vue/src/components/Uploader/Uploader.vue @@ -57,7 +57,7 @@ @rotateleft="rotateLeft(index)" @rotateright="rotateRight(index)"/>
-
+
@@ -407,7 +407,7 @@ export default { text-align: left; border: 2px #365EBE dashed; border-radius: 6px; - padding: 18px; + padding: 18px 32px 18px 18px; margin-bottom: 5px; &.dragging { @@ -425,14 +425,14 @@ export default { margin-bottom: 10px; width: 160px; margin-right: 18px; - - &.upload-button { - display: flex; - flex-direction: column; - justify-content: center; - } } + .upload-button { + position: absolute; + right: 18px; + top: 18px; + } + .fa-plus-circle { font-size: 3rem; margin-bottom: 8px; From b97a5382727bc6c9aa03fd07b0c148ddc8dfcbd4 Mon Sep 17 00:00:00 2001 From: Michael Olund Date: Tue, 29 Sep 2020 10:06:16 -0700 Subject: [PATCH 07/20] DIV-1148 visual design updates part 2 - error states & padding --- vue/README.md | 7 +----- vue/src/components/Uploader/ItemTile.vue | 29 ++++++++++++++++++++---- vue/src/components/Uploader/Uploader.vue | 6 ++--- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/vue/README.md b/vue/README.md index e021a491..bcf8b254 100644 --- a/vue/README.md +++ b/vue/README.md @@ -5,12 +5,7 @@ npm install ``` -### Compiles and hot-reloads for development -``` -npm run serve -``` - -### Compiles and minifies for production +### Compile and minify ``` npm run build ``` diff --git a/vue/src/components/Uploader/ItemTile.vue b/vue/src/components/Uploader/ItemTile.vue index 7459e78e..e6d39309 100644 --- a/vue/src/components/Uploader/ItemTile.vue +++ b/vue/src/components/Uploader/ItemTile.vue @@ -1,5 +1,5 @@