-
Notifications
You must be signed in to change notification settings - Fork 9
Refactored code and added await to stop race conditions #507
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
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 |
|---|---|---|
|
|
@@ -11,73 +11,93 @@ class AutosaveModal extends AutosaveBase { | |
| async initAutosave() { | ||
| const $modal = $(this.element); | ||
| const $form = $('.form-edit'); | ||
|
|
||
| $modal.find('.btn-js-restore-values').on('click', async (e) => { | ||
| this.storage.setItem('recovering', true); | ||
| let curvalCount = $form.find('.linkspace-field[data-column-type="curval"]').length; | ||
|
|
||
| e.preventDefault(); | ||
| e.stopPropagation(); | ||
|
|
||
| // This need awaiting or it returns before the value is fully set meaning if the recovery is "fast" it will not clear | ||
| await this.storage.setItem('recovering', true); | ||
| // Count the curvals so we don't return too early | ||
| let curvalCount = $form.find('.linkspace-field[data-column-type="curval"]').length; | ||
|
|
||
| let errored = false; | ||
|
|
||
| let $list = $("<ul></ul>"); | ||
| const $body = $modal.find(".modal-body"); | ||
| $body.html("<p>Restoring values...</p>").append($list); | ||
| await Promise.all($form.find('.linkspace-field').map(async (_,field) => { | ||
|
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. Don't need this to be awaited because the finally (after this) encapsulates what would happen at the end either way. |
||
| // Convert the fields to promise functions (using the fields) that are run in parallel | ||
| // This is only done because various parts of the codebase use the fields in different ways dependent on types (i.e. curval) | ||
| Promise.all($form.find('.linkspace-field').map(async (_, field) => { | ||
| const $field = $(field); | ||
| await this.storage.getItem(this.columnKey($field)).then(json => { | ||
| // This was originally a bunch of promises, but as the code is async, we can await things here | ||
| try { | ||
| const json = await this.storage.getItem(this.columnKey($field)) | ||
|
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 was being a little overzealous with my usage of |
||
| let values = json ? JSON.parse(json) : undefined; | ||
| return values && Array.isArray(values) ? values : undefined; | ||
| }).then(values => { | ||
| // If the value can't be parsed, ignore it | ||
| if (!values) return; | ||
| // If we are in view mode and we need to switch to edit mode, do that | ||
| const $editButton = $field.closest('.card--topic').find('.btn-js-edit'); | ||
| if ($editButton && $editButton.length) $editButton.trigger('click'); | ||
| if (Array.isArray(values)) { | ||
| const name = $field.data("name"); | ||
| const type = $field.data("column-type"); | ||
| if (type === "curval") { | ||
| // Curvals need to work event-driven - this is because the modal doesn't always load fully, | ||
| // meaning the setvalue doesn't work correctly for dropdowns (mainly) | ||
| $field.off("validationFailed"); | ||
| $field.off("validationPassed"); | ||
| $field.on("validationFailed", (e) => { | ||
| // Decrement the curval count | ||
| curvalCount--; | ||
| const $li = $(`<li class="li-error">Error restoring ${name}, please check these values before submission<ul><li class="warning">${e.message}</li></ul></li>`); | ||
| $list.append($li); | ||
| if(!curvalCount) this.storage.removeItem('recovering'); | ||
| // If we've done all fields, turn off the recovery flag | ||
| if (!curvalCount) this.storage.removeItem('recovering'); | ||
| }); | ||
| $field.on("validationPassed", () => { | ||
| // Decrement the curval count | ||
| curvalCount--; | ||
| const $li = $(`<li class="li-success">Restored ${name}</li>`); | ||
| $list.append($li); | ||
| if(!curvalCount) this.storage.removeItem('recovering'); | ||
| // If we've done all fields, turn off the recovery flag | ||
| if (!curvalCount) this.storage.removeItem('recovering'); | ||
| }); | ||
| } | ||
| setFieldValues($field, values); | ||
| if(type !== "curval") { | ||
| if (type !== "curval") { | ||
| const $li = $(`<li class="li-success">Restored ${name}</li>`); | ||
| $list.append($li); | ||
| } | ||
| $field.addClass("field--changed"); | ||
| } | ||
| }).catch(e => { | ||
| } catch (e) { | ||
| // Catch anything within the mapped promises | ||
| const name = $field.data("name"); | ||
| const $li = $(`<li class="li-error">Failed to restore ${name}<ul><li class="warning">${e.message}</li></ul></li>`); | ||
| console.error(e); | ||
| $list.append($li); | ||
| errored = true; | ||
| }); | ||
| } | ||
| })).then(() => { | ||
| // If there are errors, show an appropriate message, otherwise show a success message | ||
| $body.append(`<p>${errored ? "Values restored with errors." : "All values restored."} Please check that all field values are as expected.</p>`); | ||
| }).catch(e => { | ||
| // If there are any errors that can't be handled in the mapped promises, show a critical error message | ||
| $body.append(`<div class="alert alert-danger"><h4>Critical error restoring values</h4><p>${e}</p></div>`); | ||
| }).finally(() => { | ||
| // Hide the restore button and show the close button | ||
| $modal.find(".modal-footer").find("button:not(.btn-cancel)").hide(); | ||
| $modal.find(".modal-footer").find(".btn-cancel").text("Close"); | ||
| if(!curvalCount) this.storage.removeItem('recovering'); | ||
| // If we've done all fields, turn off the recovery flag | ||
| if (!curvalCount) this.storage.removeItem('recovering'); | ||
| }); | ||
| }); | ||
|
|
||
| // Do we need to run an autorecover? | ||
| const item = await this.storage.getItem(this.table_key); | ||
|
|
||
| if (item){ | ||
| if (item) { | ||
| $modal.modal('show'); | ||
| $modal.find('.btn-js-delete-values').attr('disabled', 'disabled').hide(); | ||
| } | ||
|
|
||
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 was causing a race condition that was borken