-
Notifications
You must be signed in to change notification settings - Fork 1
Test AMD Data Tracker with Multiple Attachments - Flag that not all records created if on bad connection #210
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1177,4 +1177,181 @@ $(document).on("knack-scene-render.scene_1607", function (event, scene) { | |
| /***************************************************************/ | ||
| $(document).on("knack-scene-render.any", function (event, scene) { | ||
| $(".kn-modal-bg").off("click"); | ||
| }); | ||
| }); | ||
|
|
||
| /***************************************/ | ||
| /*** TEST - Add multiple attachments ***/ | ||
| /***************************************/ | ||
| const KNACK_APP_ID = Knack.application_id; | ||
| var fieldId = 'field_4212'; | ||
| var viewId = 'view_4214'; | ||
| var sceneId = 'scene_1688'; | ||
| var maxFilesLoaded = 10; // Maximum amount of files uploaded in dropzone | ||
|
|
||
| $(document).on(`knack-view-render.${viewId}`, function (event, view, data) { | ||
| var knackHeaders = { | ||
| 'X-Knack-Application-ID': KNACK_APP_ID, | ||
| 'Authorization': Knack.getUserToken() | ||
| } | ||
| LazyLoad.css('https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.7.2/dropzone.min.css', function () {}); | ||
| LazyLoad.js(['https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.7.2/min/dropzone.min.js'], function () { | ||
| Dropzone.autoDiscover = false; | ||
| initialize(); | ||
| }); | ||
|
|
||
| var $fileInputBtn=$(`#kn-input-${fieldId} input[type=file]`); | ||
| var $formSubmitBtn = $(`#${viewId} .kn-submit button[type=submit]`); | ||
| $formSubmitBtn.prop('disabled', true); | ||
|
|
||
| $fileInputBtn.prop("multiple", true); | ||
| $fileInputBtn.after(`<div id="dropzone-${fieldId}" class="dropzone dropzone-knack" />`); | ||
| $fileInputBtn.hide(); | ||
|
|
||
| var $buFiledrag=$(`#filedrag-${fieldId}`); | ||
| var $form = $(`#${viewId} form`); | ||
| var $formConfirmation = $(`#${viewId} .kn-form-confirmation`); | ||
|
|
||
| var files = []; | ||
|
|
||
| function initialize() { | ||
| var upurl = `${Knack.api_url}/v1/applications/${KNACK_APP_ID}/assets/file/upload`; | ||
|
|
||
| var dz = new Dropzone(`div#dropzone-${fieldId}`, | ||
| { | ||
| url: upurl, | ||
| headers: knackHeaders, | ||
| paramName: 'files', | ||
| addRemoveLinks: true, | ||
| maxFiles: maxFilesLoaded, | ||
| dictDefaultMessage: '<div class="dz-message needsclick"><button type="button" class="dz-button">Drop files here or click to upload.</button><br></div>', | ||
| }); | ||
| // Only allow submission when we are not actively processing images | ||
| dz.on("addedfile", function(file) { $formSubmitBtn.prop('disabled', true); }); | ||
| dz.on("queuecomplete", function(file) { $formSubmitBtn.prop('disabled', false); }); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is currently happening is when the upload request times out (takes longer than 30 sec to upload), the queue is considered complete and this is enabling the submit button. I added an error event listener But the queue still is being completed, so theres a race condition where the button will still be enabled. so I took that queuecomplete event handler out. But now we need to know when to enable the button. I experimented with enabling the submit button on the
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I shared this in dev sync and @mateoclarke had a good idea, that if a file upload fails, to automatically remove it from the UI instead of making a user do that step. I can look at the code to this if you want!
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like the idea of the drop zone automatically removing the failed uploaded file from the UI to enable the submit button.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ooo I really like that approach! If all of them failed would they essentially just start back at the beginning with the original step to add files again? And if failed upload files were removed, could we have a message at the top of the pop up letting users know that occurred? |
||
| dz.on("removedfile", deleteFile); | ||
| dz.on("maxfilesexceeded", function(file) { this.removeFile(file); }); | ||
| dz.on("success", function(file, responseText, e) { | ||
| file['responseText'] = responseText; | ||
| files.push(file); | ||
| }); | ||
| $formSubmitBtn.on('click', handleFormSubmit); | ||
| } | ||
|
|
||
| function deleteFile(removedFile) { | ||
| // Update the files array | ||
| files = files.filter(file => file.name != removedFile.name); | ||
| } | ||
|
|
||
| function showMessage(err, message) { | ||
| $formConfirmation.show(); | ||
| var clazz = err === true ? "is-error" : "success"; | ||
| $formConfirmation.append(`<div class="kn-message ${clazz}"><p>${message}</p></div>`); | ||
| if (err === true) { | ||
| $formConfirmation.find('.kn-form-reload').hide(); | ||
| } else { | ||
| $formConfirmation.find('.kn-form-reload').show(); | ||
| } | ||
| } | ||
|
|
||
| function clearMessages() { | ||
| // Form messages come from Knack JS - they know the form is still visible. form-confirm is used | ||
| // when form might have been hidden | ||
| $formConfirmation.find('.kn-message').remove(); | ||
| $form.find('.kn-message').remove(); | ||
| $formConfirmation.hide(); | ||
| } | ||
|
|
||
| function handleFormSubmit(event) { | ||
| event.preventDefault(); | ||
|
|
||
| // Show progress and prevent an impatient click | ||
| Knack.showSpinner(); | ||
| $formSubmitBtn.addClass("is-loading"); | ||
| $formSubmitBtn.prop('disabled', true); | ||
|
|
||
| // Grab all other data items from the form into a simple key-value object | ||
| var formData = $form.serializeArray().reduce(function (output, value) { | ||
| var field = value.name.split('-').pop(); // Not sure why but multichoice does `view_id-field_id` | ||
| output[field] = value.value | ||
| return output | ||
| }, {}); | ||
|
|
||
| var targetUrl = `${Knack.api_url}/v1/pages/${sceneId}/views/${viewId}/records` | ||
|
|
||
| const upload = file => new Promise((res, rej) => { | ||
| // Add the one file we are submitting to the existing form data | ||
| formDataClone = { ...formData }; | ||
| formDataClone[fieldId] = file.responseText.id; | ||
|
|
||
| var jqXHR = $.ajax({ | ||
| type: 'POST', | ||
| url: targetUrl, | ||
| headers: knackHeaders, | ||
| data: formDataClone, | ||
| enctype: 'multipart/form-data' | ||
| }); | ||
|
|
||
| // Mark uploaded file with record created | ||
| // TODO - should we just remove it from the dropzone? That might be | ||
| // simpler than maintaining a list in memory | ||
| jqXHR.done(() => { | ||
| file['knackRecordCreated'] = true; | ||
| res(); | ||
| }); | ||
|
|
||
| jqXHR.fail((xhr, textStatus, errorThrown) => { | ||
| let json = JSON.parse(xhr.responseText); | ||
| let errMsg = "Unknown Error"; | ||
| if (json && json.errors) { | ||
| errMsg = json.errors.reduce((acc, cur) => acc + `<p>${cur.message}</p>`, ""); | ||
| } | ||
| rej(errMsg); | ||
| }); | ||
| }); | ||
|
|
||
| clearMessages(); | ||
| // TODO handle HTTP 429 events | ||
| // TODO try #s > 2 to see how well it works | ||
| asyncPool(2, files, upload) | ||
| .then(() => { | ||
| console.log("success"); | ||
| $form.hide(); | ||
| history.back(); // go back to parent page | ||
| //showMessage(false, "Form submitted"); // reload form | ||
| }) | ||
| .catch((errors) => { | ||
| log("errors"); | ||
| console.log(errors); | ||
| $formSubmitBtn.removeClass("is-loading"); | ||
| Knack.hideSpinner(); | ||
| showMessage(true, errors); | ||
| $formSubmitBtn.prop('disabled', false); | ||
| }); | ||
| } | ||
| }); | ||
|
|
||
| function asyncPool(poolLimit, array, iteratorFn) { | ||
| let i = 0; | ||
| const ret = []; | ||
| const executing = []; | ||
| const enqueue = function() { | ||
| if (i === array.length) { | ||
| return Promise.resolve(); | ||
| } | ||
| const item = array[i++]; | ||
| const p = Promise.resolve().then(() => iteratorFn(item, array)); | ||
| ret.push(p); | ||
|
|
||
| let r = Promise.resolve(); | ||
|
|
||
| if (poolLimit <= array.length) { | ||
| const e = p.then(() => executing.splice(executing.indexOf(e), 1)); | ||
| executing.push(e); | ||
| if (executing.length >= poolLimit) { | ||
| r = Promise.race(executing); | ||
| } | ||
| } | ||
| return r.then(() => enqueue()); | ||
| }; | ||
| return enqueue().then(() => Promise.all(ret)); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is declared but never used