From c41e73ef8bda99c7d35c2c0ce8fb965e454ec7a4 Mon Sep 17 00:00:00 2001 From: Franco Bulgarelli Date: Thu, 30 Jul 2020 12:41:51 -0300 Subject: [PATCH 1/6] Introducing submission store --- .../mumuki_laboratory/application/bridge.js | 16 +++++- .../application/current-exercise.js | 11 ++++ .../application/results-renderer.js | 7 +-- .../application/submissions-store.js | 55 +++++++++++++++++++ app/views/exercises/show.html.erb | 1 + app/views/layouts/_progress_bar.html.erb | 8 ++- 6 files changed, 92 insertions(+), 6 deletions(-) create mode 100644 app/assets/javascripts/mumuki_laboratory/application/current-exercise.js create mode 100644 app/assets/javascripts/mumuki_laboratory/application/submissions-store.js diff --git a/app/assets/javascripts/mumuki_laboratory/application/bridge.js b/app/assets/javascripts/mumuki_laboratory/application/bridge.js index 63b01a84c..12a7a5d97 100644 --- a/app/assets/javascripts/mumuki_laboratory/application/bridge.js +++ b/app/assets/javascripts/mumuki_laboratory/application/bridge.js @@ -1,14 +1,25 @@ /** - * @typedef {{status: string, test_results: [{status: string, title: string}]}} ClientResult + * @typedef {{status: SubmissionStatus, test_results: [{status: SubmissionStatus, title: string}]}} ClientResult */ /** * @typedef {{solution: object, client_result?: ClientResult}} Submission */ +/** + * @typedef {"errored"|"failed"|"passed_with_warnings"|"passed"|"pending"} SubmissionStatus + */ + +/** + * @typedef {{content?: {solution: object}, result?: object}} SubmissionAndResult + */ + var mumuki = mumuki || {}; (function (mumuki) { + /** + * @type {SubmissionAndResult} + */ var lastSubmission = {}; function Laboratory(exerciseId){ @@ -27,6 +38,9 @@ var mumuki = mumuki || {}; return lastSubmission.result && lastSubmission.result.status !== 'aborted'; } + /** + * @param {Submission} submission the submission object + */ function sendNewSolution(submission){ var token = new mumuki.CsrfToken(); var request = token.newRequest({ diff --git a/app/assets/javascripts/mumuki_laboratory/application/current-exercise.js b/app/assets/javascripts/mumuki_laboratory/application/current-exercise.js new file mode 100644 index 000000000..e1ef8ea10 --- /dev/null +++ b/app/assets/javascripts/mumuki_laboratory/application/current-exercise.js @@ -0,0 +1,11 @@ +(() => { + mumuki.load(() => { + // Set global currentExerciseId + const $muExerciseId = $('#mu-exercise-id'); + if ($muExerciseId) { + mumuki.currentExerciseId = Number($muExerciseId.val()); + } else { + mumuki.currentExerciseId = null; + } + }) +})(); diff --git a/app/assets/javascripts/mumuki_laboratory/application/results-renderer.js b/app/assets/javascripts/mumuki_laboratory/application/results-renderer.js index 90ff77ba2..bb1b3d7cb 100644 --- a/app/assets/javascripts/mumuki_laboratory/application/results-renderer.js +++ b/app/assets/javascripts/mumuki_laboratory/application/results-renderer.js @@ -6,7 +6,7 @@ // ========================== /** - * @param {string} status + * @param {SubmissionStatus} status * @returns {string} */ function iconForStatus(status) { @@ -20,8 +20,7 @@ } /** - * - * @param {string} status + * @param {SubmissionStatus} status * @returns {string} */ function classForStatus(status) { @@ -36,7 +35,7 @@ /** - * @param {string} status + * @param {SubmissionStatus} status * @param {boolean} [active] * @returns {string} */ diff --git a/app/assets/javascripts/mumuki_laboratory/application/submissions-store.js b/app/assets/javascripts/mumuki_laboratory/application/submissions-store.js new file mode 100644 index 000000000..8d8a9a185 --- /dev/null +++ b/app/assets/javascripts/mumuki_laboratory/application/submissions-store.js @@ -0,0 +1,55 @@ +(() => { + const SubmissionsStore = new class { + /** + * @param {number} exerciseId + * @returns {SubmissionStatus} + */ + getLastSubmissionStatus(exerciseId) { + const submission = this.getLastSubmission(exerciseId); + return submission ? submission.result.status : 'pending'; + } + + /** + * @param {number} exerciseId + * @returns {SubmissionAndResult} + */ + getLastSubmission(exerciseId) { + const submission = window.localStorage.getItem(this._keyFor(exerciseId)); + if (!submission) return null; + return JSON.parse(submission); + } + + /** + * @param {number} exerciseId + * @param {SubmissionAndResult} submission + */ + setLastSubmission(exerciseId, submission) { + window.localStorage.setItem(this._keyFor(exerciseId), this._asString(submission)); + } + + getCachedResultFor(exerciseId, newSolution) { + const lastSubmission = this.getLastSubmission(exerciseId); + if (!lastSubmission + || lastSubmission.result.status === 'aborted' + || !this._solutionEquals(lastSubmission, newSolution)) { + return null; + } + return lastSubmission.result; + } + + // private API + + _asString(object) { + return JSON.stringify(object); + } + + _keyFor(exerciseId) { + return `/exercise/${exerciseId}/submission`; + } + + _solutionEquals(submission, solution) { + return this._asString(submission.content) === this._asString(solution); + } + }; + mumuki.SubmissionsStore = SubmissionsStore; +})(); diff --git a/app/views/exercises/show.html.erb b/app/views/exercises/show.html.erb index 742b76cbf..782a6f5e9 100644 --- a/app/views/exercises/show.html.erb +++ b/app/views/exercises/show.html.erb @@ -45,6 +45,7 @@ <%= render_exercise_input_layout(@exercise) %> <%= hidden_field_tag default_content_tag_id(@exercise), @default_content %> +<%= hidden_field_tag "mu-exercise-id", @exercise.id %>