diff --git a/frontend/src/js/component/wb-arvados-crumbs.js b/frontend/src/js/component/wb-arvados-crumbs.js new file mode 100644 index 0000000..f4612f1 --- /dev/null +++ b/frontend/src/js/component/wb-arvados-crumbs.js @@ -0,0 +1,39 @@ +import { h, Component } from 'preact'; +import WBBreadcrumbs from 'wb-breadcrumbs'; +import fetchObjectParents from 'fetch-object-parents'; + +class WBArvadosCrumbs extends Component { + constructor(...args) { + super(...args); + this.state.items = [ { 'name': 'All Projects' } ]; + } + + fetchCrumbs() { + if (!this.props.uuid) { + this.setState({ 'items': [ { 'name': 'All Projects' } ] }); + return; + } + + let { arvHost, arvToken } = this.props.app.state; + let prom = fetchObjectParents(arvHost, arvToken, this.props.uuid); + prom = prom.then(parents => this.setState({ 'items': parents })); + } + + componentDidMount() { + this.fetchCrumbs(); + } + + componentWillReceiveProps(nextProps) { + this.props = nextProps; + this.fetchCrumbs(); + } + + render({ app }, { items }) { + return ( + app.breadcrumbClicked(item) } /> + ); + } +} + +export default WBArvadosCrumbs; diff --git a/frontend/src/js/component/wb-navbar-common.js b/frontend/src/js/component/wb-navbar-common.js new file mode 100644 index 0000000..f07610d --- /dev/null +++ b/frontend/src/js/component/wb-navbar-common.js @@ -0,0 +1,24 @@ +import { h, Component } from 'preact'; +import WBNavbar from 'wb-navbar'; +import WBInlineSearch from 'wb-inline-search'; + +class WBNavbarCommon extends Component { + render({ app, items, activeItem }) { + return ( + + ) } onItemClicked={ item => app.navbarItemClicked(item) } + activeItem={ activeItem } /> + ); + } +} + +WBNavbarCommon.defaultProps = { + 'items': [] +}; + +export default WBNavbarCommon; diff --git a/frontend/src/js/misc/arvados-type-name.js b/frontend/src/js/misc/arvados-type-name.js new file mode 100644 index 0000000..59c486c --- /dev/null +++ b/frontend/src/js/misc/arvados-type-name.js @@ -0,0 +1,13 @@ +const typeIdToName = { + 'tpzed': 'user', + 'j7d0g': 'group', + 'xvhdp': 'container_request', + 'dz642': 'container', + '7fd4e': 'workflow' +}; + +function arvadosTypeName(id) { + return typeIdToName[id]; +} + +export default arvadosTypeName; diff --git a/frontend/src/js/misc/fetch-object-parents.js b/frontend/src/js/misc/fetch-object-parents.js new file mode 100644 index 0000000..65a06fe --- /dev/null +++ b/frontend/src/js/misc/fetch-object-parents.js @@ -0,0 +1,49 @@ +import makeArvadosRequest from 'make-arvados-request'; +import arvadosTypeName from 'arvados-type-name'; + +function fetchObjectParents(arvHost, arvToken, uuid) { + let parents = []; + + let cb = xhr => { + let objectType = arvadosTypeName(xhr.response['uuid'].split('-')[1]); + + let item = { + 'uuid': xhr.response['uuid'] + }; + + if (objectType === 'user') { + item['name'] = xhr.response['first_name'] + ' ' + xhr.response['last_name']; + + } else { + item['name'] = xhr.response['name']; + } + + if (objectType === 'group') { + item['group_class'] = xhr.response['group_class']; + } + + parents.push(item); + + if (!xhr.response['owner_uuid'] || + xhr.response['owner_uuid'].endsWith('-tpzed-000000000000000')) { + + return parents.reverse(); + } + + objectType = arvadosTypeName(xhr.response['owner_uuid'].split('-')[1]); + + return makeArvadosRequest(arvHost, arvToken, + '/arvados/v1/' + objectType + 's' + + '/' + xhr.response['owner_uuid']).then(cb); + }; + + let objectType = arvadosTypeName(uuid.split('-')[1]); + let prom = makeArvadosRequest(arvHost, arvToken, + '/arvados/v1/' + objectType + 's' + + '/' + uuid); + prom = prom.then(cb); + + return prom; +} + +export default fetchObjectParents; diff --git a/frontend/src/js/page/wb-app.js b/frontend/src/js/page/wb-app.js index 6ebb0b6..e4a71e7 100644 --- a/frontend/src/js/page/wb-app.js +++ b/frontend/src/js/page/wb-app.js @@ -3,6 +3,8 @@ import { Router, route } from 'preact-router'; import WBBrowse from 'wb-browse'; import WBSignIn from 'wb-sign-in'; import WBLandingPage from 'wb-landing-page'; +import WBProcessView from 'wb-process-view'; +import arvadosTypeName from 'arvados-type-name'; class WBApp extends Component { constructor(...args) { @@ -37,6 +39,16 @@ class WBApp extends Component { } } + breadcrumbClicked(item) { + let objectType = arvadosTypeName(item.uuid.split('-')[1]); + if (objectType === 'user') + route('/browse/' + item.uuid) + else if (objectType === 'group' && item.group_class === 'project') + route('/browse/' + item.uuid); + else if (objectType === 'container_request') + route('/process/' + item.uuid) + } + render() { return ( @@ -47,6 +59,8 @@ class WBApp extends Component { + + ); } diff --git a/frontend/src/js/page/wb-process-view.js b/frontend/src/js/page/wb-process-view.js new file mode 100644 index 0000000..655b11e --- /dev/null +++ b/frontend/src/js/page/wb-process-view.js @@ -0,0 +1,19 @@ +import { h, Component } from 'preact'; +import WBNavbarCommon from 'wb-navbar-common'; +import WBArvadosCrumbs from 'wb-arvados-crumbs'; + +class WBProcessView extends Component { + render({ app, uuid }) { + return ( +
+ + + + +
This is the process view for { uuid }
+
+ ); + } +} + +export default WBProcessView; diff --git a/frontend/src/js/widget/wb-navbar.js b/frontend/src/js/widget/wb-navbar.js index c5bbef5..b44686f 100644 --- a/frontend/src/js/widget/wb-navbar.js +++ b/frontend/src/js/widget/wb-navbar.js @@ -1,7 +1,7 @@ import { h, Component } from 'preact'; class WBNavbar extends Component { - render({ title, items, rhs, onItemClicked, onTitleClicked }) { + render({ title, items, rhs, onItemClicked, onTitleClicked, activeItem }) { return (