diff --git a/frontend/src/js/component/wb-process-dashboard.js b/frontend/src/js/component/wb-process-dashboard.js index 561fa02..bc02f24 100644 --- a/frontend/src/js/component/wb-process-dashboard.js +++ b/frontend/src/js/component/wb-process-dashboard.js @@ -1,4 +1,5 @@ import { h, Component } from 'preact'; +import WBTable from 'wb-table'; import makeArvadosRequest from 'make-arvados-request'; function getAll(makeRequest) { @@ -19,38 +20,114 @@ function getAll(makeRequest) { return prom; } +function determineState(containerRequest) { + const cr = containerRequest; + const c = cr.container; + if (cr.state === 'Uncommitted' || !c || c.state === 'Queued' || c.state === 'Locked') + return 'Pending'; + if (c.state === 'Running') + return 'Running'; + if (c.state === 'Complete' && c.exit_code === 0) + return 'Complete'; + if (c.state === 'Complete' && c.exit_code !== 0) + return 'Failed'; + if (c.state === 'Cancelled') + return 'Cancelled'; +} + class WBProcessDashboard extends Component { + constructor(...args) { + super(...args); + this.state.rows = Array(5).fill(Array(6).fill('-')); + } + fetchData() { - const { app, uuid } = this.props; + const { app, parentProcessUuid } = this.props; const { arvHost, arvToken } = app.state; let prom = new Promise(accept => accept()); - if (uuid) { + if (parentProcessUuid) { prom = prom.then(() => { return makeArvadosRequest(arvHost, arvToken, - '/arvados/v1/container_requests/' + encodeURIComponent(uuid)); + '/arvados/v1/container_requests/' + encodeURIComponent(parentProcessUuid)); }); prom = prom.then(xhr => { const cr = xhr.response; - return makeArvadosRequest(arvHost, arvToken, - '/arvados/v1/containers/' + encodeURIComponent(cr.container_uuid)); - }); - prom = prom.then(xhr => { - const c = xhr.response; - const filters = [ [ 'requesting_container_uuid', '=', c.uuid ] ]; - return makeArvadosRequest(arvHost, arvToken, - '/arvados/v1/container_requests?filters=' + - encodeURIComponent(JSON.stringify(filters))); + if (!cr.container_uuid) + return []; + const filters = [ [ 'requesting_container_uuid', '=', cr.container_uuid ] ]; + return getAll(ofs => + makeArvadosRequest(arvHost, arvToken, + '/arvados/v1/container_requests?filters=' + + encodeURIComponent(JSON.stringify(filters)) + + '&order=' + encodeURIComponent(['uuid asc']) + + '&offset=' + ofs)); }); } else { prom = prom.then(() => { - return makeArvadosRequest(arvHost, arvToken, - '/arvados/v1/container_requests'); + return getAll(ofs => makeArvadosRequest(arvHost, arvToken, + '/arvados/v1/container_requests?order=' + + encodeURIComponent(['uuid asc']) + '&offset=' + ofs)); }); } + let crlist; + prom = prom.then(crl => { + crlist = crl; + const uuids = crlist.map(a => a.container_uuid); + // uuids = uuids.slice(0, 2); + // crlist.map(a => ( crdict[a.uuid] = a)); + const filters = [ [ 'uuid', 'in', uuids ] ]; + return getAll(ofs => makeArvadosRequest(arvHost, arvToken, + '/arvados/v1/containers?filters=' + encodeURIComponent(JSON.stringify(filters)) + + '&offset=' + ofs)); + }); + prom = prom.then(cl => { + cl.map(a => (crlist.find(b => (b.container_uuid === a.uuid)).container = a)); + crlist.map(a => (a.wb_state = determineState(a))); + const stats = {}; + for (let state in { 'Pending': 1, 'Running': 1, 'Complete': 1, 'Failed': 1, 'Cancelled': 1 }) { + const f = crlist.filter(a => (a.wb_state === state)); + stats[state] = { 'Count': f.length }; + if (state === 'Pending') + f.map(a => (a.wb_wait_time = (new Date() - new Date(a.created_at)) / 3.6e6)); + else + f.map(a => (a.wb_wait_time = (new Date(a.container.started_at) - new Date(a.created_at)) / 3.6e6)); + f.sort((a, b) => (a.wb_wait_time - b.wb_wait_time)); + stats[state]['Shortest Wait Time'] = f.length ? (f[0].wb_wait_time.toFixed(2) + ' hours') : '-'; + stats[state]['Longest Wait Time'] = f.length ? (f[f.length - 1].wb_wait_time.toFixed(2) + ' hours') : '-'; + if (state === 'Pending') + f.map(a => (a.wb_run_time = 0)); + else if (state === 'Running') + f.map(a => (a.wb_run_time = (new Date() - new Date(a.container.started_at)) / 3.6e6)); + else + f.map(a => (a.wb_run_time = Math.max(0, new Date(a.container.finished_at) - new Date(a.container.started_at)) / 3.6e6)); + f.sort((a, b) => (a.wb_run_time - b.wb_run_time)); + stats[state]['Shortest Run Time'] = f.length ? (f[0].wb_run_time.toFixed(2) + ' hours') : '-'; + stats[state]['Longest Run Time'] = f.length ? (f[f.length - 1].wb_run_time.toFixed(2) + ' hours') : '-'; + } + const rows = []; + for (let st in { 'Count': 1, 'Shortest Wait Time': 1, 'Longest Wait Time': 1, + 'Shortest Run Time': 1, 'Longest Run Time': 1}) { + rows.push([st].concat(['Pending', 'Running', 'Complete', 'Failed', 'Cancelled'].map(a => stats[a][st]))); + } + this.setState({ rows }); + }); + } + componentDidMount() { + this.fetchData(); } - render() { + /* componentWillReceiveProps(nextProps) { + this.props = nextProps; + fetchData(); + } */ + render({}, { rows }) { + return ( + + ); } } + +export default WBProcessDashboard; diff --git a/frontend/src/js/page/wb-process-view.js b/frontend/src/js/page/wb-process-view.js index 7c635b8..0ff4b3f 100644 --- a/frontend/src/js/page/wb-process-view.js +++ b/frontend/src/js/page/wb-process-view.js @@ -9,6 +9,7 @@ import detectHashes from 'detect-hashes'; import WBCommonFields from 'wb-common-fields'; import WBContainerRequestFields from 'wb-container-request-fields'; import WBProcessListing from 'wb-process-listing'; +import WBProcessDashboard from 'wb-process-dashboard'; import wbFetchObjects from 'wb-fetch-objects'; class WBProcessView extends Component { @@ -114,6 +115,9 @@ class WBProcessView extends Component { This is the process view for { uuid } +

Children Dashboard

+ +

Common Fields