forked from enviPath/enviPy
Fixes Spinner and status message display on pathway page Reviewed-on: enviPath/enviPy#291 Co-authored-by: Tobias O <tobias.olenyi@envipath.com> Co-committed-by: Tobias O <tobias.olenyi@envipath.com>
135 lines
3.9 KiB
JavaScript
135 lines
3.9 KiB
JavaScript
/**
|
|
* Pathway Viewer Alpine.js Component
|
|
*
|
|
* Provides reactive status management and polling for pathway predictions.
|
|
* Handles status updates, change detection, and update notices.
|
|
*/
|
|
|
|
document.addEventListener('alpine:init', () => {
|
|
/**
|
|
* Pathway Viewer Component
|
|
*
|
|
* Usage:
|
|
* <div x-data="pathwayViewer({
|
|
* status: 'running',
|
|
* modified: '2024-01-01T00:00:00Z',
|
|
* statusUrl: '/pathway/123?status=true'
|
|
* })" x-init="init()">
|
|
* ...
|
|
* </div>
|
|
*/
|
|
Alpine.data('pathwayViewer', (config) => ({
|
|
status: config.status,
|
|
modified: config.modified,
|
|
modifiedDate: null,
|
|
statusUrl: config.statusUrl,
|
|
emptyDueToThreshold: config.emptyDueToThreshold === "True",
|
|
showUpdateNotice: false,
|
|
showEmptyDueToThresholdNotice: false,
|
|
emptyDueToThresholdMessage: 'The Pathway is empty due to the selected threshold. Please try a different threshold.',
|
|
updateMessage: '',
|
|
pollInterval: null,
|
|
|
|
get statusTooltip() {
|
|
const tooltips = {
|
|
'completed': 'Pathway prediction completed.',
|
|
'failed': 'Pathway prediction failed.',
|
|
'running': 'Pathway prediction running.'
|
|
};
|
|
return tooltips[this.status] || '';
|
|
},
|
|
|
|
init() {
|
|
this.modifiedDate = this.parseDate(this.modified);
|
|
|
|
if (this.status === 'running') {
|
|
this.startPolling();
|
|
}
|
|
|
|
if (this.emptyDueToThreshold) {
|
|
this.showEmptyDueToThresholdNotice = true;
|
|
}
|
|
|
|
},
|
|
|
|
startPolling() {
|
|
if (this.pollInterval) {
|
|
return;
|
|
}
|
|
this.pollInterval = setInterval(() => this.checkStatus(), 5000);
|
|
},
|
|
|
|
async checkStatus() {
|
|
try {
|
|
const response = await fetch(this.statusUrl);
|
|
const data = await response.json();
|
|
|
|
if (data.emptyDueToThreshold) {
|
|
this.emptyDueToThreshold = true;
|
|
this.showEmptyDueToThresholdNotice = true;
|
|
}
|
|
|
|
const nextModifiedDate = this.parseDate(data.modified);
|
|
const modifiedChanged = this.hasNewerTimestamp(nextModifiedDate, this.modifiedDate);
|
|
const statusChanged = data.status !== this.status;
|
|
|
|
if ((modifiedChanged || statusChanged) && !this.emptyDueToThreshold) {
|
|
this.showUpdateNotice = true;
|
|
this.updateMessage = this.getUpdateMessage(data.status, modifiedChanged, statusChanged);
|
|
}
|
|
|
|
this.modified = data.modified;
|
|
this.modifiedDate = nextModifiedDate;
|
|
this.status = data.status;
|
|
|
|
if (data.status !== 'running' && this.pollInterval) {
|
|
clearInterval(this.pollInterval);
|
|
this.pollInterval = null;
|
|
}
|
|
} catch (err) {
|
|
console.error('Polling error:', err);
|
|
}
|
|
},
|
|
|
|
getUpdateMessage(status, modifiedChanged, statusChanged) {
|
|
// Prefer explicit status change messaging, otherwise fall back to modified change copy
|
|
if (statusChanged) {
|
|
if (status === 'completed') {
|
|
return 'Prediction completed. Reload the page to see the updated Pathway.';
|
|
}
|
|
if (status === 'failed') {
|
|
return 'Prediction failed. Reload the page to see the latest status.';
|
|
}
|
|
}
|
|
|
|
let msg = 'Prediction ';
|
|
|
|
if (status === 'running') {
|
|
msg += 'is still running. But the Pathway was updated.';
|
|
} else if (status === 'completed') {
|
|
msg += 'is completed. Reload the page to see the updated Pathway.';
|
|
} else if (status === 'failed') {
|
|
msg += 'failed. Reload the page to see the current shape.';
|
|
}
|
|
|
|
return msg;
|
|
},
|
|
|
|
parseDate(dateString) {
|
|
// Normalize "YYYY-MM-DD HH:mm:ss" into an ISO-compatible string to avoid locale issues
|
|
if (!dateString) return null;
|
|
return new Date(dateString.replace(' ', 'T'));
|
|
},
|
|
|
|
hasNewerTimestamp(nextDate, currentDate) {
|
|
if (!nextDate) return false;
|
|
if (!currentDate) return true;
|
|
return nextDate.getTime() > currentDate.getTime();
|
|
},
|
|
|
|
reloadPage() {
|
|
location.reload();
|
|
}
|
|
}));
|
|
});
|