@@ -6,12 +6,18 @@ import arvadosTypeName from 'arvados-type-name'; | |||||
class WBNameAndUuid extends Component { | class WBNameAndUuid extends Component { | ||||
componentDidMount() { | componentDidMount() { | ||||
let { uuid, app } = this.props; | |||||
let { arvHost, arvToken } = app.state; | |||||
const { uuid, app, lookup } = this.props; | |||||
if (!uuid) | if (!uuid) | ||||
return; | return; | ||||
if (uuid in lookup) { | |||||
this.setState({ 'item': lookup[uuid]}); | |||||
return; | |||||
} | |||||
const { arvHost, arvToken } = app.state; | |||||
let prom = new Promise(accept => accept()); | let prom = new Promise(accept => accept()); | ||||
if (/[0-9a-f]{32}\+[0-9]+/g.exec(uuid)) { | if (/[0-9a-f]{32}\+[0-9]+/g.exec(uuid)) { | ||||
@@ -0,0 +1,84 @@ | |||||
import { h, Component } from 'preact'; | |||||
import makeArvadosRequest from 'make-arvados-request'; | |||||
import WBTable from 'wb-table'; | |||||
import WBPagination from 'wb-pagination'; | |||||
import WBNameAndUuid from 'wb-name-and-uuid'; | |||||
import wbFetchObjects from 'wb-fetch-objects'; | |||||
import wbFormatDate from 'wb-format-date'; | |||||
class WBWorkflowListing extends Component { | |||||
constructor(...args) { | |||||
super(...args); | |||||
this.state.rows = []; | |||||
this.state.numPages = 0; | |||||
} | |||||
componentDidMount() { | |||||
this.fetchItems(); | |||||
} | |||||
prepareRows(items, ownerLookup) { | |||||
return items.map(item => [ | |||||
( <WBNameAndUuid uuid={ item.uuid } lookup={ { [item.uuid]: item } } /> ), | |||||
item.description, | |||||
( <WBNameAndUuid uuid={ item.owner_uuid } lookup={ ownerLookup } /> ), | |||||
wbFormatDate(item.created_at), | |||||
(<div> | |||||
<button class="btn btn-outline-success mx-1 my-1" title="Run"><i class="fas fa-running"></i></button> | |||||
<button class="btn btn-outline-primary mx-1 my-1" title="View"><i class="far fa-eye"></i></button> | |||||
<button class="btn btn-outline-danger mx-1 my-1" title="Delete"><i class="fas fa-trash"></i></button> | |||||
</div>) | |||||
]); | |||||
} | |||||
fetchItems() { | |||||
const { arvHost, arvToken } = this.props.app.state; | |||||
const { page, itemsPerPage, ownerUuid } = this.props; | |||||
const filters = []; | |||||
if (ownerUuid) | |||||
filters.push([ 'owner_uuid', '=', ownerUuid ]); | |||||
const select = ['uuid', 'name', 'description', 'owner_uuid', 'created_at']; | |||||
let prom = makeArvadosRequest(arvHost, arvToken, | |||||
'/arvados/v1/workflows?filters=' + encodeURIComponent(JSON.stringify(filters)) + | |||||
'&select=' + encodeURIComponent(JSON.stringify(select)) + | |||||
'&limit=' + encodeURIComponent(itemsPerPage) + | |||||
'&offset=' + encodeURIComponent(itemsPerPage * page)); | |||||
let workflowResp; | |||||
prom = prom.then(xhr => (workflowResp = xhr.response)); | |||||
prom = prom.then(() => wbFetchObjects(arvHost, arvToken, | |||||
workflowResp.items.map(it => it.owner_uuid))); | |||||
let ownerLookup; | |||||
prom = prom.then(lookup => (ownerLookup = lookup)); | |||||
prom = prom.then(() => | |||||
this.setState({ | |||||
'numPages': Math.ceil(workflowResp['items_available'] / workflowResp['limit']), | |||||
'rows': this.prepareRows(workflowResp.items, ownerLookup) | |||||
})); | |||||
} | |||||
componentWillReceiveProps(nextProps, nextState) { | |||||
this.props = nextProps; | |||||
this.fetchItems(); | |||||
} | |||||
render({ app, ownerUuid, page, getPageUrl }, { rows, numPages }) { | |||||
return ( | |||||
<div> | |||||
<WBTable columns={ [ 'Name', 'Description', 'Owner', 'Created At', 'Actions' ] } | |||||
rows={ rows } /> | |||||
<WBPagination numPages={ numPages } | |||||
activePage={ page } | |||||
getPageUrl={ getPageUrl } /> | |||||
</div> | |||||
); | |||||
} | |||||
} | |||||
WBWorkflowListing.defaultProps = { | |||||
'itemsPerPage': 100, | |||||
'ownerUuid': null | |||||
}; | |||||
export default WBWorkflowListing; |
@@ -0,0 +1,33 @@ | |||||
import arvadosTypeName from 'arvados-type-name'; | |||||
import makeArvadosRequest from 'make-arvados-request'; | |||||
function wbFetchObjects(arvHost, arvToken, uuids) { | |||||
const unique = {}; | |||||
uuids.map(u => (unique[u] = true)); | |||||
uuids = {}; | |||||
Object.keys(unique).map(u => { | |||||
let typeName = arvadosTypeName(u); | |||||
if (!(typeName in uuids)) | |||||
uuids[typeName] = []; | |||||
uuids[typeName].push(u); | |||||
}); | |||||
const lookup = {}; | |||||
let prom = new Promise(accept => accept()); | |||||
for (let typeName in uuids) { | |||||
let filters = [ | |||||
['uuid', 'in', uuids[typeName]] | |||||
]; | |||||
prom = prom.then(() => makeArvadosRequest(arvHost, arvToken, | |||||
'/arvados/v1/' + typeName + 's?filters=' + | |||||
encodeURIComponent(JSON.stringify(filters)))); | |||||
prom = prom.then(xhr => xhr.response.items.map(it => ( | |||||
lookup[it.uuid] = it))); | |||||
} | |||||
prom = prom.then(() => lookup); | |||||
return prom; | |||||
} | |||||
export default wbFetchObjects; |
@@ -7,6 +7,7 @@ import WBProjectCrumbs from 'wb-project-crumbs'; | |||||
import WBTabs from 'wb-tabs'; | import WBTabs from 'wb-tabs'; | ||||
import WBProcessListing from 'wb-process-listing'; | import WBProcessListing from 'wb-process-listing'; | ||||
import WBCollectionListing from 'wb-collection-listing'; | import WBCollectionListing from 'wb-collection-listing'; | ||||
import WBWorkflowListing from 'wb-workflow-listing'; | |||||
class WBBrowse extends Component { | class WBBrowse extends Component { | ||||
getUrl(params) { | getUrl(params) { | ||||
@@ -67,7 +68,12 @@ class WBBrowse extends Component { | |||||
onPageChanged={ i => this.route({ 'processPage': i }) } /> | onPageChanged={ i => this.route({ 'processPage': i }) } /> | ||||
) : (objTypeTab === 'workflow' ? ( | ) : (objTypeTab === 'workflow' ? ( | ||||
null | |||||
<WBWorkflowListing app={ app } | |||||
ownerUuid={ ownerUuid } | |||||
itemsPerPage="20" | |||||
page={ Number(workflowPage || 0) } | |||||
getPageUrl={ i => this.getUrl({ 'workflowPage': i }) } /> | |||||
) : null)) | ) : null)) | ||||
} | } | ||||
</div> | </div> | ||||