| @@ -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 ( | |||||
| <WBBreadcrumbs items={ items } | |||||
| onItemClicked={ item => app.breadcrumbClicked(item) } /> | |||||
| ); | |||||
| } | |||||
| } | |||||
| export default WBArvadosCrumbs; | |||||
| @@ -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 ( | |||||
| <WBNavbar items={ [ | |||||
| { 'name': 'Home', 'id': 'home' }, | |||||
| { 'name': 'All Projects', 'id': 'all-projects' }, | |||||
| { 'name': 'User', 'dropdown': [ { 'id': 'sign-out', 'name': 'Sign Out' } ]} | |||||
| ].concat(items) } rhs={ ( | |||||
| <WBInlineSearch /> | |||||
| ) } onItemClicked={ item => app.navbarItemClicked(item) } | |||||
| activeItem={ activeItem } /> | |||||
| ); | |||||
| } | |||||
| } | |||||
| WBNavbarCommon.defaultProps = { | |||||
| 'items': [] | |||||
| }; | |||||
| export default WBNavbarCommon; | |||||
| @@ -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; | |||||
| @@ -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; | |||||
| @@ -3,6 +3,8 @@ import { Router, route } from 'preact-router'; | |||||
| import WBBrowse from 'wb-browse'; | import WBBrowse from 'wb-browse'; | ||||
| import WBSignIn from 'wb-sign-in'; | import WBSignIn from 'wb-sign-in'; | ||||
| import WBLandingPage from 'wb-landing-page'; | import WBLandingPage from 'wb-landing-page'; | ||||
| import WBProcessView from 'wb-process-view'; | |||||
| import arvadosTypeName from 'arvados-type-name'; | |||||
| class WBApp extends Component { | class WBApp extends Component { | ||||
| constructor(...args) { | 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() { | render() { | ||||
| return ( | return ( | ||||
| <Router> | <Router> | ||||
| @@ -47,6 +59,8 @@ class WBApp extends Component { | |||||
| <WBBrowse path="/browse/:ownerUuid?/:activePage?/:objTypeTab?/:collectionPage?/:processPage?/:workflowPage?" | <WBBrowse path="/browse/:ownerUuid?/:activePage?/:objTypeTab?/:collectionPage?/:processPage?/:workflowPage?" | ||||
| appCallbacks={ this.appCallbacks } | appCallbacks={ this.appCallbacks } | ||||
| appState={ this.appState } /> | appState={ this.appState } /> | ||||
| <WBProcessView path="/process/:uuid" app={ this } /> | |||||
| </Router> | </Router> | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -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 ( | |||||
| <div> | |||||
| <WBNavbarCommon app={ app } /> | |||||
| <WBArvadosCrumbs app={ app } uuid={ uuid } /> | |||||
| <div class="my-2">This is the process view for { uuid }</div> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| } | |||||
| export default WBProcessView; | |||||
| @@ -1,7 +1,7 @@ | |||||
| import { h, Component } from 'preact'; | import { h, Component } from 'preact'; | ||||
| class WBNavbar extends Component { | class WBNavbar extends Component { | ||||
| render({ title, items, rhs, onItemClicked, onTitleClicked }) { | |||||
| render({ title, items, rhs, onItemClicked, onTitleClicked, activeItem }) { | |||||
| return ( | return ( | ||||
| <nav class="navbar navbar-expand-lg navbar-light bg-light"> | <nav class="navbar navbar-expand-lg navbar-light bg-light"> | ||||
| <a class="navbar-brand" href="#" onclick={ e => { e.preventDefault(); onTitleClicked(); } }>{ title }</a> | <a class="navbar-brand" href="#" onclick={ e => { e.preventDefault(); onTitleClicked(); } }>{ title }</a> | ||||
| @@ -23,7 +23,7 @@ class WBNavbar extends Component { | |||||
| else if (typeof(i) === 'object') | else if (typeof(i) === 'object') | ||||
| var li_cls = ['nav-item']; | var li_cls = ['nav-item']; | ||||
| if (i['active']) | |||||
| if (i['active'] || activeItem === i['id']) | |||||
| li_cls.push('active'); | li_cls.push('active'); | ||||
| var a_cls = ['nav-link']; | var a_cls = ['nav-link']; | ||||
| if (i['disabled']) | if (i['disabled']) | ||||
| @@ -87,7 +87,8 @@ WBNavbar.defaultProps = { | |||||
| 'items': [], | 'items': [], | ||||
| 'form': null, | 'form': null, | ||||
| 'onItemClicked': () => {}, | 'onItemClicked': () => {}, | ||||
| 'onTitleClicked': () => {} | |||||
| 'onTitleClicked': () => {}, | |||||
| 'activeItem': null | |||||
| } | } | ||||
| export default WBNavbar; | export default WBNavbar; | ||||