Refactor code execution to use async functions
This refactoring is required for Sentry tracing. It ensures that the respective functions only return as soon as a code execution finished. With this approach, we can then instrument the duration of the functions, so that Sentry spans are created as desired. Co-authored-by: Jan Graichen <jgraichen@altimos.de>
This commit is contained in:

committed by
Sebastian Serth

parent
c8609e5392
commit
86c67f3c9a
@ -28,13 +28,13 @@ $(document).on('turbolinks:load', function() {
|
|||||||
function submitCode(event) {
|
function submitCode(event) {
|
||||||
const button = $(event.target) || $('#submit');
|
const button = $(event.target) || $('#submit');
|
||||||
this.startSentryTransaction(button);
|
this.startSentryTransaction(button);
|
||||||
this.createSubmission(button, null, function (response) {
|
const submission = await this.createSubmission(button, null).catch(this.ajaxError.bind(this));
|
||||||
if (response.redirect) {
|
if (!submission) return;
|
||||||
this.autosaveIfChanged();
|
if (!submission.redirect) return;
|
||||||
this.stopCode(event);
|
|
||||||
this.editors = [];
|
this.autosaveIfChanged();
|
||||||
Turbolinks.clearCache();
|
this.stopCode(event);
|
||||||
Turbolinks.visit(response.redirect);
|
this.editors = [];
|
||||||
}
|
Turbolinks.clearCache();
|
||||||
})
|
Turbolinks.visit(submission.redirect);
|
||||||
}
|
}
|
||||||
|
@ -894,12 +894,14 @@ var CodeOceanEditor = {
|
|||||||
Sentry.captureException(JSON.stringify(error, ["message", "arguments", "type", "name", "data"]));
|
Sentry.captureException(JSON.stringify(error, ["message", "arguments", "type", "name", "data"]));
|
||||||
},
|
},
|
||||||
|
|
||||||
showFileDialog: function (event) {
|
showFileDialog: async function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.createSubmission('#create-file', null, function (response) {
|
|
||||||
$('#code_ocean_file_context_id').val(response.id);
|
const submission = await this.createSubmission('#create-file', null).catch(this.ajaxError.bind(this));
|
||||||
new bootstrap.Modal($('#modal-file')).show();
|
if (!submission) return;
|
||||||
}.bind(this));
|
|
||||||
|
$('#code_ocean_file_context_id').val(submission.id);
|
||||||
|
new bootstrap.Modal($('#modal-file')).show();
|
||||||
},
|
},
|
||||||
|
|
||||||
initializeOutputBarToggle: function () {
|
initializeOutputBarToggle: function () {
|
||||||
|
@ -8,17 +8,19 @@ CodeOceanEditorEvaluation = {
|
|||||||
* Scoring-Functions
|
* Scoring-Functions
|
||||||
*/
|
*/
|
||||||
scoreCode: function (event) {
|
scoreCode: function (event) {
|
||||||
|
event.preventDefault();
|
||||||
const cause = $('#assess');
|
const cause = $('#assess');
|
||||||
this.startSentryTransaction(cause);
|
this.startSentryTransaction(cause);
|
||||||
event.preventDefault();
|
|
||||||
this.stopCode(event);
|
this.stopCode(event);
|
||||||
this.clearScoringOutput();
|
this.clearScoringOutput();
|
||||||
$('#submit').addClass("d-none");
|
$('#submit').addClass("d-none");
|
||||||
this.createSubmission(cause, null, function (submission) {
|
|
||||||
this.showSpinner($('#assess'));
|
const submission = await this.createSubmission(cause, null).catch(this.ajaxError.bind(this));
|
||||||
$('#score_div').removeClass('d-none');
|
if (!submission) return;
|
||||||
this.initializeSocketForScoring(submission.id);
|
|
||||||
}.bind(this));
|
this.showSpinner($('#assess'));
|
||||||
|
$('#score_div').removeClass('d-none');
|
||||||
|
await this.socketScoreCode(submission.id);
|
||||||
},
|
},
|
||||||
|
|
||||||
handleScoringResponse: function (results) {
|
handleScoringResponse: function (results) {
|
||||||
|
@ -3,7 +3,7 @@ CodeOceanEditorWebsocket = {
|
|||||||
// Replace `http` with `ws` for the WebSocket connection. This also works with `https` and `wss`.
|
// Replace `http` with `ws` for the WebSocket connection. This also works with `https` and `wss`.
|
||||||
webSocketProtocol: window.location.protocol.replace(/^http/, 'ws').split(':')[0],
|
webSocketProtocol: window.location.protocol.replace(/^http/, 'ws').split(':')[0],
|
||||||
|
|
||||||
initializeSocket: function(urlHelper, params, closeCallback) {
|
runSocket: function(urlHelper, params, setupFunction) {
|
||||||
// 1. Specify the protocol for all URLs to generate
|
// 1. Specify the protocol for all URLs to generate
|
||||||
params.protocol = this.webSocketProtocol;
|
params.protocol = this.webSocketProtocol;
|
||||||
params._options = true;
|
params._options = true;
|
||||||
@ -32,48 +32,73 @@ CodeOceanEditorWebsocket = {
|
|||||||
|
|
||||||
// 4. Connect to the given URL.
|
// 4. Connect to the given URL.
|
||||||
this.websocket = new CommandSocket(url,
|
this.websocket = new CommandSocket(url,
|
||||||
function (evt) {
|
function (evt) {
|
||||||
this.resetOutputTab();
|
this.resetOutputTab();
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Attach custom handlers for messages received.
|
||||||
|
setupFunction(this.websocket);
|
||||||
|
|
||||||
CodeOceanEditorWebsocket.websocket = this.websocket;
|
CodeOceanEditorWebsocket.websocket = this.websocket;
|
||||||
this.websocket.onError(this.showWebsocketError.bind(this));
|
|
||||||
this.websocket.onClose(function(span, callback){
|
// Create and return a new Promise. It will only resolve (or fail) once the connection has ended.
|
||||||
span?.finish();
|
return new Promise((resolve, reject) => {
|
||||||
if(callback != null){
|
this.websocket.onError(this.showWebsocketError.bind(this));
|
||||||
callback();
|
|
||||||
}
|
// Remove event listeners for Promise handling.
|
||||||
}.bind(this, span, closeCallback));
|
// This is especially useful in case of an error, where a `close` event might follow the `error` event.
|
||||||
|
const teardown = () => {
|
||||||
|
this.websocket.websocket.removeEventListener(closeListener);
|
||||||
|
this.websocket.websocket.removeEventListener(errorListener);
|
||||||
|
};
|
||||||
|
|
||||||
|
// We are using event listeners (and not `onError` or `onClose`) here, since these listeners should never be overwritten.
|
||||||
|
// With `onError` or `onClose`, a new assignment would overwrite a previous one.
|
||||||
|
const closeListener = this.websocket.websocket.addEventListener('close', () => {
|
||||||
|
span?.finish();
|
||||||
|
resolve();
|
||||||
|
teardown();
|
||||||
|
});
|
||||||
|
const errorListener = this.websocket.websocket.addEventListener('error', (error) => {
|
||||||
|
reject(error);
|
||||||
|
teardown();
|
||||||
|
this.websocket.killWebSocket(); // In case of error, ensure we always close the connection.
|
||||||
|
});
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
initializeSocketForTesting: function(submissionID, filename) {
|
socketTestCode: function(submissionID, filename) {
|
||||||
this.initializeSocket(Routes.test_submission_url, {id: submissionID, filename: filename});
|
return this.runSocket(Routes.test_submission_url, {id: submissionID, filename: filename}, (websocket) => {
|
||||||
this.websocket.on('default',this.handleTestResponse.bind(this));
|
websocket.on('default', this.handleTestResponse.bind(this));
|
||||||
this.websocket.on('exit', this.handleExitCommand.bind(this));
|
websocket.on('exit', this.handleExitCommand.bind(this));
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
initializeSocketForScoring: function(submissionID) {
|
socketScoreCode: function(submissionID) {
|
||||||
this.initializeSocket(Routes.score_submission_url, {id: submissionID}, function() {
|
return this.runSocket(Routes.score_submission_url, {id: submissionID}, (websocket) => {
|
||||||
$('#assess').one('click', this.scoreCode.bind(this))
|
websocket.on('default', this.handleScoringResponse.bind(this));
|
||||||
}.bind(this));
|
websocket.on('hint', this.showHint.bind(this));
|
||||||
this.websocket.on('default',this.handleScoringResponse.bind(this));
|
websocket.on('exit', this.handleExitCommand.bind(this));
|
||||||
this.websocket.on('hint', this.showHint.bind(this));
|
websocket.on('status', this.showStatus.bind(this));
|
||||||
this.websocket.on('exit', this.handleExitCommand.bind(this));
|
}).then(() => {
|
||||||
this.websocket.on('status', this.showStatus.bind(this));
|
$('#assess').one('click', this.scoreCode.bind(this));
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
initializeSocketForRunning: function(submissionID, filename) {
|
socketRunCode: function(submissionID, filename) {
|
||||||
this.initializeSocket(Routes.run_submission_url, {id: submissionID, filename: filename});
|
return this.runSocket(Routes.run_submission_url, {id: submissionID, filename: filename}, (websocket) => {
|
||||||
this.websocket.on('input',this.showPrompt.bind(this));
|
websocket.on('input', this.showPrompt.bind(this));
|
||||||
this.websocket.on('write', this.printWebsocketOutput.bind(this));
|
websocket.on('write', this.printWebsocketOutput.bind(this));
|
||||||
this.websocket.on('clear', this.clearOutput.bind(this));
|
websocket.on('clear', this.clearOutput.bind(this));
|
||||||
this.websocket.on('turtle', this.handleTurtleCommand.bind(this));
|
websocket.on('turtle', this.handleTurtleCommand.bind(this));
|
||||||
this.websocket.on('turtlebatch', this.handleTurtlebatchCommand.bind(this));
|
websocket.on('turtlebatch', this.handleTurtlebatchCommand.bind(this));
|
||||||
this.websocket.on('render', this.printWebsocketOutput.bind(this));
|
websocket.on('render', this.printWebsocketOutput.bind(this));
|
||||||
this.websocket.on('exit', this.handleExitCommand.bind(this));
|
websocket.on('exit', this.handleExitCommand.bind(this));
|
||||||
this.websocket.on('status', this.showStatus.bind(this));
|
websocket.on('status', this.showStatus.bind(this));
|
||||||
this.websocket.on('hint', this.showHint.bind(this));
|
websocket.on('hint', this.showHint.bind(this));
|
||||||
this.websocket.on('files', this.prepareFileDownloads.bind(this));
|
websocket.on('files', this.prepareFileDownloads.bind(this));
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
handleExitCommand: function() {
|
handleExitCommand: function() {
|
||||||
|
@ -114,41 +114,42 @@ CodeOceanEditorRequestForComments = {
|
|||||||
questionElement.prop("disabled", true);
|
questionElement.prop("disabled", true);
|
||||||
$('#closeAskForCommentsButton').addClass('d-none');
|
$('#closeAskForCommentsButton').addClass('d-none');
|
||||||
|
|
||||||
var exercise_id = editor.data('exercise-id');
|
const exercise_id = editor.data('exercise-id');
|
||||||
var file_id = $('.editor').data('id');
|
const file_id = $('.editor').data('id');
|
||||||
var question = questionElement.val();
|
const question = questionElement.val();
|
||||||
|
|
||||||
var createRequestForComments = function (submission) {
|
const submission = await this.createSubmission(cause, null).catch(this.ajaxError.bind(this));
|
||||||
this.showSpinner($('#askForCommentsButton'));
|
if (!submission) return;
|
||||||
$.ajax({
|
|
||||||
method: 'POST',
|
this.showSpinner($('#askForCommentsButton'));
|
||||||
url: Routes.request_for_comments_path(),
|
|
||||||
data: {
|
const response = await $.ajax({
|
||||||
request_for_comment: {
|
method: 'POST',
|
||||||
exercise_id: exercise_id,
|
url: Routes.request_for_comments_path(),
|
||||||
file_id: file_id,
|
data: {
|
||||||
submission_id: submission.id,
|
request_for_comment: {
|
||||||
question: question
|
exercise_id: exercise_id,
|
||||||
}
|
file_id: file_id,
|
||||||
|
submission_id: submission.id,
|
||||||
|
question: question
|
||||||
}
|
}
|
||||||
}).done(function() {
|
}
|
||||||
// trigger a run
|
}).catch(this.ajaxError.bind(this));
|
||||||
this.runSubmission.call(this, submission);
|
|
||||||
$.flash.success({text: $('#askForCommentsButton').data('message-success')});
|
bootstrap.Modal.getInstance($('#comment-modal')).hide();
|
||||||
}.bind(this)).fail(this.ajaxError.bind(this))
|
this.hideSpinner();
|
||||||
.always(function () {
|
$('#question').prop("disabled", false).val('');
|
||||||
bootstrap.Modal.getInstance($('#comment-modal')).hide();
|
$('#closeAskForCommentsButton').removeClass('d-none');
|
||||||
this.hideSpinner();
|
$('#askForCommentsButton').one('click', this.requestComments.bind(this));
|
||||||
$('#question').prop("disabled", false).val('');
|
|
||||||
$('#closeAskForCommentsButton').removeClass('d-none');
|
|
||||||
$('#askForCommentsButton').one('click', this.requestComments.bind(this));
|
|
||||||
}.bind(this));
|
|
||||||
};
|
|
||||||
|
|
||||||
this.createSubmission(cause, null, createRequestForComments.bind(this));
|
|
||||||
// we disabled the button to prevent that the user spams RFCs, but decided against this now.
|
// we disabled the button to prevent that the user spams RFCs, but decided against this now.
|
||||||
//var button = $('#requestComments');
|
//var button = $('#requestComments');
|
||||||
//button.prop('disabled', true);
|
//button.prop('disabled', true);
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
await this.runSubmission(submission);
|
||||||
|
$.flash.success({text: $('#askForCommentsButton').data('message-success')});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6,10 +6,10 @@ CodeOceanEditorSubmissions = {
|
|||||||
/**
|
/**
|
||||||
* Submission-Creation
|
* Submission-Creation
|
||||||
*/
|
*/
|
||||||
createSubmission: function (initiator, filter, callback) {
|
createSubmission: async function (initiator, filter) {
|
||||||
const editor = $('#editor');
|
const editor = $('#editor');
|
||||||
this.showSpinner(initiator);
|
this.showSpinner(initiator);
|
||||||
var url = $(initiator).data('url') || editor.data('submissions-url');
|
const url = $(initiator).data('url') || editor.data('submissions-url');
|
||||||
|
|
||||||
if (url === undefined) {
|
if (url === undefined) {
|
||||||
const data = {
|
const data = {
|
||||||
@ -19,25 +19,29 @@ CodeOceanEditorSubmissions = {
|
|||||||
Sentry.captureException(JSON.stringify(data));
|
Sentry.captureException(JSON.stringify(data));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var jqxhr = this.ajax({
|
|
||||||
data: {
|
|
||||||
submission: {
|
|
||||||
cause: $(initiator).data('cause') || $(initiator).prop('id'),
|
|
||||||
exercise_id: editor.data('exercise-id') || $(initiator).data('exercise-id'),
|
|
||||||
files_attributes: (filter || _.identity)(this.collectFiles())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
dataType: 'json',
|
|
||||||
method: $(initiator).data('http-method') || 'POST',
|
|
||||||
url: url,
|
|
||||||
});
|
|
||||||
jqxhr.always(this.hideSpinner.bind(this));
|
|
||||||
jqxhr.done(this.createSubmissionCallback.bind(this));
|
|
||||||
if(callback != null){
|
|
||||||
jqxhr.done(callback.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
jqxhr.fail(this.ajaxError.bind(this));
|
try {
|
||||||
|
const response = await this.ajax({
|
||||||
|
data: {
|
||||||
|
submission: {
|
||||||
|
cause: $(initiator).data('cause') || $(initiator).prop('id'),
|
||||||
|
exercise_id: editor.data('exercise-id') || $(initiator).data('exercise-id'),
|
||||||
|
files_attributes: (filter || _.identity)(this.collectFiles())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
method: $(initiator).data('http-method') || 'POST',
|
||||||
|
url: url,
|
||||||
|
});
|
||||||
|
this.hideSpinner();
|
||||||
|
this.createSubmissionCallback(response);
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
this.hideSpinner();
|
||||||
|
|
||||||
|
// We require the callee to handle this error, e.g., through `this.ajaxError(error)`
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
collectFiles: function() {
|
collectFiles: function() {
|
||||||
@ -81,34 +85,42 @@ CodeOceanEditorSubmissions = {
|
|||||||
/**
|
/**
|
||||||
* File-Management
|
* File-Management
|
||||||
*/
|
*/
|
||||||
destroyFile: function() {
|
destroyFile: async function() {
|
||||||
this.createSubmission($('#destroy-file'), function(files) {
|
const submission = await this.createSubmission($('#destroy-file'), function(files) {
|
||||||
return _.reject(files, function(file) {
|
return _.reject(files, function(file) {
|
||||||
return file.file_id === CodeOceanEditor.active_file.id;
|
return file.file_id === CodeOceanEditor.active_file.id;
|
||||||
});
|
});
|
||||||
}, window.CodeOcean.refresh);
|
}).catch(this.ajaxError.bind(this));
|
||||||
|
if(!submission) return;
|
||||||
|
|
||||||
|
window.CodeOcean.refresh();
|
||||||
},
|
},
|
||||||
|
|
||||||
downloadCode: function(event) {
|
downloadCode: async function(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.createSubmission('#download', null,function(submission) {
|
|
||||||
// to download just a single file, use the following url
|
const submission = await this.createSubmission('#download', null).catch(this.ajaxError.bind(this));
|
||||||
// window.location = Routes.download_file_submission_url(submission.id, CodeOceanEditor.active_file.filename);
|
if(!submission) return;
|
||||||
window.location = Routes.download_submission_url(submission.id);
|
|
||||||
});
|
// to download just a single file, use the following url
|
||||||
|
// window.location = Routes.download_file_submission_url(submission.id, CodeOceanEditor.active_file.filename);
|
||||||
|
window.location = Routes.download_submission_url(submission.id);
|
||||||
},
|
},
|
||||||
|
|
||||||
resetCode: function(initiator, onlyActiveFile = false) {
|
resetCode: function(initiator, onlyActiveFile = false) {
|
||||||
this.startSentryTransaction(initiator);
|
this.startSentryTransaction(initiator);
|
||||||
this.showSpinner(initiator);
|
this.showSpinner(initiator);
|
||||||
this.ajax({
|
|
||||||
|
const response = await this.ajax({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: $('#start-over').data('url') || $('#start-over-active-file').data('url')
|
url: $('#start-over').data('url') || $('#start-over-active-file').data('url')
|
||||||
}).done(function(response) {
|
}).catch(this.ajaxError.bind(this));
|
||||||
this.hideSpinner();
|
|
||||||
App.synchronized_editor?.reset_content(response);
|
this.hideSpinner();
|
||||||
this.setEditorContent(response, onlyActiveFile);
|
|
||||||
}.bind(this));
|
if (!response) return;
|
||||||
|
App.synchronized_editor?.reset_content(response);
|
||||||
|
this.setEditorContent(response, onlyActiveFile);
|
||||||
},
|
},
|
||||||
|
|
||||||
setEditorContent: function(new_content, onlyActiveFile = false) {
|
setEditorContent: function(new_content, onlyActiveFile = false) {
|
||||||
@ -126,68 +138,73 @@ CodeOceanEditorSubmissions = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
renderCode: function(event) {
|
renderCode: function(event) {
|
||||||
|
event.preventDefault();
|
||||||
const cause = $('#render');
|
const cause = $('#render');
|
||||||
this.startSentryTransaction(cause);
|
this.startSentryTransaction(cause);
|
||||||
event.preventDefault();
|
if (!cause.is(':visible')) return;
|
||||||
if (cause.is(':visible')) {
|
|
||||||
this.createSubmission(cause, null, function (submission) {
|
|
||||||
if (submission.render_url === undefined) return;
|
|
||||||
|
|
||||||
const active_file = CodeOceanEditor.active_file.filename;
|
const submission = await this.createSubmission(cause, null).catch(this.ajaxError.bind(this));
|
||||||
const desired_file = submission.render_url.filter(hash => hash.filepath === active_file);
|
if (!submission) return;
|
||||||
const url = desired_file[0].url;
|
if (submission.render_url === undefined) return;
|
||||||
// Allow to open the new tab even in Safari.
|
|
||||||
// See: https://stackoverflow.com/a/70463940
|
const active_file = CodeOceanEditor.active_file.filename;
|
||||||
setTimeout(() => {
|
const desired_file = submission.render_url.filter(hash => hash.filepath === active_file);
|
||||||
var pop_up_window = window.open(url, '_blank');
|
const url = desired_file[0].url;
|
||||||
if (pop_up_window) {
|
|
||||||
pop_up_window.onerror = function (message) {
|
// Allow to open the new tab even in Safari.
|
||||||
this.clearOutput();
|
// See: https://stackoverflow.com/a/70463940
|
||||||
this.printOutput({
|
setTimeout(() => {
|
||||||
stderr: message
|
var pop_up_window = window.open(url, '_blank');
|
||||||
}, true, 0);
|
if (pop_up_window) {
|
||||||
this.sendError(message, submission.id);
|
pop_up_window.onerror = function (message) {
|
||||||
this.showOutputBar();
|
this.clearOutput();
|
||||||
};
|
this.printOutput({
|
||||||
}
|
stderr: message
|
||||||
})
|
}, true, 0);
|
||||||
});
|
this.sendError(message, submission.id);
|
||||||
}
|
this.showOutputBar();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execution-Logic
|
* Execution-Logic
|
||||||
*/
|
*/
|
||||||
runCode: function(event) {
|
runCode: function(event) {
|
||||||
|
event.preventDefault();
|
||||||
const cause = $('#run');
|
const cause = $('#run');
|
||||||
this.startSentryTransaction(cause);
|
this.startSentryTransaction(cause);
|
||||||
event.preventDefault();
|
|
||||||
this.stopCode(event);
|
this.stopCode(event);
|
||||||
if (cause.is(':visible')) {
|
if (!cause.is(':visible')) return;
|
||||||
this.createSubmission(cause, null, this.runSubmission.bind(this));
|
|
||||||
}
|
const submission = await this.createSubmission(cause, null).catch(this.ajaxError.bind(this));
|
||||||
|
if (!submission) return;
|
||||||
|
|
||||||
|
await this.runSubmission(submission);
|
||||||
},
|
},
|
||||||
|
|
||||||
runSubmission: function (submission) {
|
runSubmission: async function (submission) {
|
||||||
//Run part starts here
|
//Run part starts here
|
||||||
this.running = true;
|
this.running = true;
|
||||||
this.showSpinner($('#run'));
|
this.showSpinner($('#run'));
|
||||||
$('#score_div').addClass('d-none');
|
$('#score_div').addClass('d-none');
|
||||||
this.toggleButtonStates();
|
this.toggleButtonStates();
|
||||||
this.initializeSocketForRunning(submission.id, CodeOceanEditor.active_file.filename);
|
await this.socketRunCode(submission.id, CodeOceanEditor.active_file.filename);
|
||||||
},
|
},
|
||||||
|
|
||||||
testCode: function(event) {
|
testCode: function(event) {
|
||||||
|
event.preventDefault();
|
||||||
const cause = $('#test');
|
const cause = $('#test');
|
||||||
this.startSentryTransaction(cause);
|
this.startSentryTransaction(cause);
|
||||||
event.preventDefault();
|
if (!cause.is(':visible')) return;
|
||||||
if (cause.is(':visible')) {
|
|
||||||
this.createSubmission(cause, null, function(submission) {
|
const submission = await this.createSubmission(cause, null).catch(this.ajaxError.bind(this));
|
||||||
this.showSpinner($('#test'));
|
if (!submission) return;
|
||||||
$('#score_div').addClass('d-none');
|
|
||||||
this.initializeSocketForTesting(submission.id, CodeOceanEditor.active_file.filename);
|
this.showSpinner($('#test'));
|
||||||
}.bind(this));
|
$('#score_div').addClass('d-none');
|
||||||
}
|
await this.socketTestCode(submission.id, CodeOceanEditor.active_file.filename);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -216,6 +233,6 @@ CodeOceanEditorSubmissions = {
|
|||||||
autosave: function () {
|
autosave: function () {
|
||||||
clearTimeout(this.autosaveTimer);
|
clearTimeout(this.autosaveTimer);
|
||||||
this.autosaveTimer = null;
|
this.autosaveTimer = null;
|
||||||
this.createSubmission($('#autosave'), null);
|
this.createSubmission($('#autosave'), null).catch(this.ajaxError.bind(this));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user