diff --git a/frontend/src/js/component/wb-name-and-uuid.js b/frontend/src/js/component/wb-name-and-uuid.js
index fe0abad..9f8aefc 100644
--- a/frontend/src/js/component/wb-name-and-uuid.js
+++ b/frontend/src/js/component/wb-name-and-uuid.js
@@ -6,12 +6,18 @@ import arvadosTypeName from 'arvados-type-name';
class WBNameAndUuid extends Component {
componentDidMount() {
- let { uuid, app } = this.props;
- let { arvHost, arvToken } = app.state;
+ const { uuid, app, lookup } = this.props;
if (!uuid)
return;
+ if (uuid in lookup) {
+ this.setState({ 'item': lookup[uuid]});
+ return;
+ }
+
+ const { arvHost, arvToken } = app.state;
+
let prom = new Promise(accept => accept());
if (/[0-9a-f]{32}\+[0-9]+/g.exec(uuid)) {
diff --git a/frontend/src/js/component/wb-workflow-listing.js b/frontend/src/js/component/wb-workflow-listing.js
new file mode 100644
index 0000000..6329cd1
--- /dev/null
+++ b/frontend/src/js/component/wb-workflow-listing.js
@@ -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 => [
+ ( ),
+ item.description,
+ ( ),
+ wbFormatDate(item.created_at),
+ (
+
+
+
+
)
+ ]);
+ }
+
+ 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 (
+
+
+
+
+
+ );
+ }
+}
+
+WBWorkflowListing.defaultProps = {
+ 'itemsPerPage': 100,
+ 'ownerUuid': null
+};
+
+export default WBWorkflowListing;
diff --git a/frontend/src/js/misc/wb-fetch-objects.js b/frontend/src/js/misc/wb-fetch-objects.js
new file mode 100644
index 0000000..bcc47e2
--- /dev/null
+++ b/frontend/src/js/misc/wb-fetch-objects.js
@@ -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;
diff --git a/frontend/src/js/page/wb-browse.js b/frontend/src/js/page/wb-browse.js
index c67af04..a552abe 100644
--- a/frontend/src/js/page/wb-browse.js
+++ b/frontend/src/js/page/wb-browse.js
@@ -7,6 +7,7 @@ import WBProjectCrumbs from 'wb-project-crumbs';
import WBTabs from 'wb-tabs';
import WBProcessListing from 'wb-process-listing';
import WBCollectionListing from 'wb-collection-listing';
+import WBWorkflowListing from 'wb-workflow-listing';
class WBBrowse extends Component {
getUrl(params) {
@@ -67,7 +68,12 @@ class WBBrowse extends Component {
onPageChanged={ i => this.route({ 'processPage': i }) } />
) : (objTypeTab === 'workflow' ? (
- null
+ this.getUrl({ 'workflowPage': i }) } />
+
) : null))
}