2021-07-28 02:15:48 +03:00

168 lines
6.9 KiB
JavaScript

class CeleryProgressBar {
constructor(progressUrl, options) {
this.progressUrl = progressUrl;
options = options || {};
let progressBarId = options.progressBarId || 'progress-bar';
let progressBarMessage = options.progressBarMessageId || 'progress-bar-message';
this.progressBarElement = options.progressBarElement || document.getElementById(progressBarId);
this.progressBarMessageElement = options.progressBarMessageElement || document.getElementById(progressBarMessage);
this.onProgress = options.onProgress || this.onProgressDefault;
this.onSuccess = options.onSuccess || this.onSuccessDefault;
this.onError = options.onError || this.onErrorDefault;
this.onTaskError = options.onTaskError || this.onTaskErrorDefault;
this.onDataError = options.onDataError || this.onError;
this.onRetry = options.onRetry || this.onRetryDefault;
this.onIgnored = options.onIgnored || this.onIgnoredDefault;
let resultElementId = options.resultElementId || 'celery-result';
this.resultElement = options.resultElement || document.getElementById(resultElementId);
this.onResult = options.onResult || this.onResultDefault;
// HTTP options
this.onNetworkError = options.onNetworkError || this.onError;
this.onHttpError = options.onHttpError || this.onError;
this.pollInterval = options.pollInterval || 500;
// Other options
let barColorsDefault = {
success: '#76ce60',
error: '#dc4f63',
progress: '#68a9ef',
ignored: '#7a7a7a'
}
this.barColors = Object.assign({}, barColorsDefault, options.barColors);
}
onSuccessDefault(progressBarElement, progressBarMessageElement, result) {
result = this.getMessageDetails(result);
progressBarElement.style.backgroundColor = this.barColors.success;
progressBarMessageElement.textContent = "Success! Please refresh page.";
}
onResultDefault(resultElement, result) {
if (resultElement) {
resultElement.textContent = result;
}
}
/**
* Default handler for all errors.
* @param data - A Response object for HTTP errors, undefined for other errors
*/
onErrorDefault(progressBarElement, progressBarMessageElement, excMessage, data) {
progressBarElement.style.backgroundColor = this.barColors.error;
excMessage = excMessage || '';
progressBarMessageElement.textContent = "Uh-Oh, something went wrong! " + excMessage;
}
onTaskErrorDefault(progressBarElement, progressBarMessageElement, excMessage) {
let message = this.getMessageDetails(excMessage);
this.onError(progressBarElement, progressBarMessageElement, message);
}
onRetryDefault(progressBarElement, progressBarMessageElement, excMessage, retryWhen) {
retryWhen = new Date(retryWhen);
let message = 'Retrying in ' + Math.round((retryWhen.getTime() - Date.now())/1000) + 's: ' + excMessage;
this.onError(progressBarElement, progressBarMessageElement, message);
}
onIgnoredDefault(progressBarElement, progressBarMessageElement, result) {
progressBarElement.style.backgroundColor = this.barColors.ignored;
progressBarMessageElement.textContent = result || 'Task result ignored!'
}
onProgressDefault(progressBarElement, progressBarMessageElement, progress) {
progressBarElement.style.backgroundColor = this.barColors.progress;
progressBarElement.style.width = progress.percent + "%";
var description = progress.description || "";
if (progress.current == 0) {
if (progress.pending === true) {
progressBarMessageElement.textContent = 'Waiting for task to start...';
} else {
progressBarMessageElement.textContent = 'Task started...';
}
} else {
progressBarMessageElement.textContent = progress.current + ' of ' + progress.total + ' processed. ' + description;
}
}
getMessageDetails(result) {
if (this.resultElement) {
return ''
} else {
return result || '';
}
}
/**
* Process update message data.
* @return true if the task is complete, false if it's not, undefined if `data` is invalid
*/
onData(data) {
let done = false;
if (data.progress) {
this.onProgress(this.progressBarElement, this.progressBarMessageElement, data.progress);
}
if (data.complete === true) {
done = true;
if (data.success === true) {
this.onSuccess(this.progressBarElement, this.progressBarMessageElement, data.result);
} else if (data.success === false) {
if (data.state === 'RETRY') {
this.onRetry(this.progressBarElement, this.progressBarMessageElement, data.result.message, data.result.when);
done = false;
delete data.result;
} else {
this.onTaskError(this.progressBarElement, this.progressBarMessageElement, data.result);
}
} else {
if (data.state === 'IGNORED') {
this.onIgnored(this.progressBarElement, this.progressBarMessageElement, data.result);
delete data.result;
} else {
done = undefined;
this.onDataError(this.progressBarElement, this.progressBarMessageElement, "Data Error");
}
}
if (data.hasOwnProperty('result')) {
this.onResult(this.resultElement, data.result);
}
} else if (data.complete === undefined) {
done = undefined;
this.onDataError(this.progressBarElement, this.progressBarMessageElement, "Data Error");
}
return done;
}
async connect() {
let response;
try {
response = await fetch(this.progressUrl);
} catch (networkError) {
this.onNetworkError(this.progressBarElement, this.progressBarMessageElement, "Network Error");
throw networkError;
}
if (response.status === 200) {
let data;
try {
data = await response.json();
} catch (parsingError) {
this.onDataError(this.progressBarElement, this.progressBarMessageElement, "Parsing Error")
throw parsingError;
}
const complete = this.onData(data);
if (complete === false) {
setTimeout(this.connect.bind(this), this.pollInterval);
}
} else {
this.onHttpError(this.progressBarElement, this.progressBarMessageElement, "HTTP Code " + response.status, response);
}
}
static initProgressBar(progressUrl, options) {
const bar = new this(progressUrl, options);
bar.connect();
}
}