Archived
1
0
This repository has been archived on 2026-01-19. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
arema-jobs/assets/main.js
T
2022-10-18 16:32:20 +02:00

292 lines
8.9 KiB
JavaScript
Executable File

class AremaRest
{
fetchPromise(url)
{
return fetch(url, {
method: 'GET',
headers: {'Accept': 'application/json'}
})
.catch(err => {
console.error('ERROR fetching data: %o', err);
})
.then(function (response) {
return response.json();
})
.catch(err => {
console.error('ERROR converting data to JSON: %o', err);
})
.then((data) => {
//console.log('JSON data: %o', data);
return this.fixXMLJSON(data);
})
.catch(err => {
console.error('ERROR fixing/enriching JSON: %o', err);
});
}
/**
* Arema converts XML to JSON, so:
* <param name="key1">value1</param>
* <param name="key2">value2</param>
* becomes
* "param": [
* { "@name": "key1", "$": "value1" },
* { "@name": "key2", "$": "value2" },
* ]
* This method tries to fix that (assuming all names/keys are unique).
*/
fixXMLJSON(data)
{
if (!Array.isArray(data) && typeof data !== 'object') {
return data;
}
for (var i in data) {
if (!data.hasOwnProperty(i)) {
continue;
}
if (Array.isArray(data[i])) {
// console.log('Found Array: %o', data[i]);
var key = false;
if (data[i][0]['@id']) {
key = '@id';
} else if (data[i][0]['@name']) {
key = '@name';
}
if (!key) {
// This doesn't seem to be the correct structure --> ignore
//console.log('Ignoring structure: %o', data[i]);
data[i] = this.fixXMLJSON(data[i]);
continue;
}
var new_assoc = {};
for (var j=0; j<data[i].length; j++) {
var record = data[i][j];
var thiskey = record[key];
delete record[key];
if (Object.keys(record).length == 1 && '$' in record) {
record = record['$'];
}
new_assoc[thiskey] = record;
}
// console.log('New Array: %o', new_assoc);
data[i] = this.fixXMLJSON(new_assoc);
} else {
data[i] = this.fixXMLJSON(data[i]);
}
}
return data;
}
getJoblist()
{
var url = 'aremaproxy.php?fetch=joblist';
return this.fetchPromise(url);
}
getJobDetails(jobId)
{
var url = 'aremaproxy.php?fetch=jobdetails&jobid=' + jobId;
return this.fetchPromise(url);
}
getJobProgress(jobId)
{
var url = 'aremaproxy.php?fetch=jobprogress&jobid=' + jobId;
return this.fetchPromise(url);
}
}
class JobRow extends React.Component
{
job_states = {
2: "Queued",
3: "Started",
4: "Dispatched",
5: "Running",
6: "Cancelling",
8: "Waiting for Resource",
9: "Waiting for Trigger",
10: "Finished",
11: "Finished with Problems",
12: "Finished with Errors",
13: "Finished but Dependency Error",
14: "Cancelled",
20: "Finished with Warnings",
30: "Skipped"
};
constructor(props)
{
super(props);
this.state = {
jobId: props.jobId,
name: '... fetching details ...',
state_numeric: -1,
state: '---',
percent: 0
};
}
updateDetails()
{
var req = new AremaRest();
req.getJobDetails(this.state.jobId)
.then((data) => {
console.log('updateDetails got data: %o', data);
var cur = this.state;
cur.name = data.job.param.title;
cur.state_numeric = data.job.state;
cur.state = this.job_states[data.job.state];
if (data.job.state == 10) {
cur.percent = 100;
}
this.setState(cur);
if (data.job.state < 10) {
// job still running, query progress in 1 second
setTimeout(() => { this.updateProgress(); }, 1000);
}
})
.catch(err => {
console.error('ERROR processing updateDetails(): %o', err);
setTimeout(() => { this.updateDetails(); }, 1000);
});
}
updateProgress()
{
var req = new AremaRest();
req.getJobProgress(this.state.jobId)
.then((data) => {
console.log('updateProgress got data: %o', data);
var cur = this.state;
cur.state_numeric = data.state;
cur.state = this.job_states[data.state];
// calculate percentage
var num_steps = 0;
var overall_percent = 0;
for (var step in data.job_steps.job_step) {
if (!data.job_steps.job_step.hasOwnProperty(step)) {
continue;
}
var this_step = data.job_steps.job_step[step];
//console.log('PCalc: Status: %o, Percent: %o', this_step.state, this_step.percent);
num_steps++;
if (this_step.state == 10) {
overall_percent += 100;
} else {
overall_percent += parseInt(this_step.percent);
}
}
cur.percent = Math.floor( overall_percent / num_steps );
console.log('calculated: %o', cur.percent);
this.setState(cur);
if (data.state < 10) {
// job still running, update progress in 5 seconds
setTimeout(() => { this.updateProgress(); }, 5000);
}
})
.catch(err => {
console.error('ERROR processing updateProgress(): %o', err);
setTimeout(() => { this.updateProgress(); }, 1000);
});
}
componentDidMount()
{
this.updateDetails();
}
render()
{
//console.log('Obj: %o', this);
return React.createElement('tr', { className: 'state'+this.state.state_numeric },
React.createElement('td', null, this.state.jobId),
React.createElement('td', null, this.state.name),
React.createElement('td', null,
React.createElement('span', { className: 'uk-label state'+this.state.state_numeric }, this.state.state)
),
React.createElement('td', { style: { verticalAlign: 'middle' } },
React.createElement('progress', { className: 'uk-progress uk-progress-striped uk-active', value: this.state.percent, max: 100 }, this.state.percent + '%' )
)
);
}
}
class JobList extends React.Component
{
constructor(props)
{
super(props);
this.state = {
jobIds: []
};
}
updateJobs()
{
var req = new AremaRest();
req.getJoblist()
.then((data) => {
console.log('updateJobs got data: %o', data);
this.setState({
jobIds: data.jobs.job
});
setTimeout(() => { this.updateJobs(); }, 11000);
})
.catch(err => {
console.error('ERROR processing updateJobs(): %o', err);
setTimeout(() => { this.updateJobs(); }, 2000);
});
}
componentDidMount()
{
this.updateJobs();
window.setJobList = (data) => {
this.setState(data);
}
window.appendJobList = (data) => {
var list = this.state;
console.log('Current state: %o', list);
for (var i=0; i<data.length; i++) {
list.jobIds.push(data[i]);
}
this.setState(list);
}
}
render()
{
var rows = this.state.jobIds.map(function(jobId) {
return React.createElement(JobRow, { key: jobId, jobId: jobId })
});
return React.createElement('div', {},
//React.createElement('button', { onClick: this.updateJobs.bind(this) }, 'Update'),
React.createElement('table', { className: 'uk-table uk-table-divider' },
React.createElement('thead', null,
React.createElement('tr', null,
React.createElement('th', null, 'ID'),
React.createElement('th', null, 'Name'),
React.createElement('th', null, 'Status'),
React.createElement('th', null, 'Progress')
)
),
React.createElement('tbody', null, rows)
)
);
}
}
document.addEventListener("DOMContentLoaded", function(event) {
ReactDOM.render(
React.createElement(JobList),
document.getElementById('joblist')
);
});