| @@ -4,9 +4,12 @@ function urlForObject(item, mode='primary') { | |||
| let objectType = arvadosTypeName(item.uuid.split('-')[1]); | |||
| if (objectType === 'user') | |||
| return ('/browse/' + item.uuid); | |||
| else if (objectType === 'group' && item.group_class === 'project') | |||
| return ('/browse/' + item.uuid); | |||
| else if (objectType === 'container_request') | |||
| else if (objectType === 'group' && item.group_class === 'project') { | |||
| if (mode === 'properties') | |||
| return ('/project/' + item.uuid); | |||
| else | |||
| return ('/browse/' + item.uuid); | |||
| } else if (objectType === 'container_request') | |||
| return ('/process/' + item.uuid); | |||
| else if (objectType === 'workflow') { | |||
| if (mode === 'launch') | |||
| @@ -3,58 +3,7 @@ import WBIdTools from 'wb-id-tools'; | |||
| import urlForObject from 'url-for-object'; | |||
| import makeArvadosRequest from 'make-arvados-request'; | |||
| import arvadosObjectName from 'arvados-object-name'; | |||
| class WBLazyInlineName extends Component { | |||
| componentWillReceiveProps(nextProps) { | |||
| if (nextProps.identifier === this.props.identifier) | |||
| return; | |||
| this.setState({ item: null }); | |||
| } | |||
| fetchData() { | |||
| const { app, identifier } = this.props; | |||
| const { arvHost, arvToken } = app.state; | |||
| const typeName = WBIdTools.typeName(identifier); | |||
| if (WBIdTools.isPDH(identifier)) { | |||
| const filters = [ | |||
| [ 'portable_data_hash', '=', identifier ] | |||
| ]; | |||
| let prom = makeArvadosRequest(arvHost, arvToken, | |||
| '/arvados/v1/collections?filters=' + encodeURIComponent(JSON.stringify(filters))); | |||
| prom = prom.then(xhr => this.setState({ item: { | |||
| uuid: xhr.response.items.length > 0 ? xhr.response.items[0].uuid : '', | |||
| name: xhr.response.items.length > 0 ? xhr.response.items[0].name : 'Not Found' + | |||
| ( xhr.response.items_available > 1 ? ' (+' + (xhr.response.items_available - 1) + ' others)' : '' ) | |||
| }})); | |||
| return; | |||
| } | |||
| let prom = makeArvadosRequest(arvHost, arvToken, | |||
| '/arvados/v1/' + typeName + 's/' + identifier); | |||
| prom = prom.then(xhr => this.setState({ item: xhr.response })); | |||
| prom = prom.catch(() => this.setState({ item: { name: 'Not Found' }})); | |||
| } | |||
| render({ identifier }, { item }) { | |||
| if (item) { | |||
| return ( | |||
| <a href={ urlForObject(item) }>{ arvadosObjectName(item) }</a> | |||
| ); | |||
| } | |||
| const typeName = WBIdTools.typeName(identifier); | |||
| const url = (typeName === 'group' ? '/browse/' + identifier : | |||
| typeName === 'collection' ? '/collection-browse/' + identifier : | |||
| urlForObject({ uuid: identifier })); | |||
| return ( | |||
| <span> | |||
| <a href={ url }>{ identifier }</a> <a href="#" title="Look up" | |||
| onclick={ e => { e.preventDefault(); this.fetchData(); } }> | |||
| <i class="fas fa-search"></i> | |||
| </a> | |||
| </span> | |||
| ); | |||
| } | |||
| } | |||
| import WBLazyInlineName from 'wb-lazy-inline-name'; | |||
| function detectIds(value, app) { | |||
| const matches = WBIdTools.detectIdentifiers(value); | |||
| @@ -0,0 +1,59 @@ | |||
| import { h, Component } from 'preact'; | |||
| import makeArvadosRequest from 'make-arvados-request'; | |||
| import WBIdTools from 'wb-id-tools'; | |||
| import urlForObject from 'url-for-object'; | |||
| import arvadosObjectName from 'arvados-object-name'; | |||
| class WBLazyInlineName extends Component { | |||
| componentWillReceiveProps(nextProps) { | |||
| if (nextProps.identifier === this.props.identifier) | |||
| return; | |||
| this.setState({ item: null }); | |||
| } | |||
| fetchData() { | |||
| const { app, identifier } = this.props; | |||
| const { arvHost, arvToken } = app.state; | |||
| const typeName = WBIdTools.typeName(identifier); | |||
| if (WBIdTools.isPDH(identifier)) { | |||
| const filters = [ | |||
| [ 'portable_data_hash', '=', identifier ] | |||
| ]; | |||
| let prom = makeArvadosRequest(arvHost, arvToken, | |||
| '/arvados/v1/collections?filters=' + encodeURIComponent(JSON.stringify(filters))); | |||
| prom = prom.then(xhr => this.setState({ item: { | |||
| uuid: xhr.response.items.length > 0 ? xhr.response.items[0].uuid : '', | |||
| name: xhr.response.items.length > 0 ? xhr.response.items[0].name : 'Not Found' + | |||
| ( xhr.response.items_available > 1 ? ' (+' + (xhr.response.items_available - 1) + ' others)' : '' ) | |||
| }})); | |||
| return; | |||
| } | |||
| let prom = makeArvadosRequest(arvHost, arvToken, | |||
| '/arvados/v1/' + typeName + 's/' + identifier); | |||
| prom = prom.then(xhr => this.setState({ item: xhr.response })); | |||
| prom = prom.catch(() => this.setState({ item: { name: 'Not Found' }})); | |||
| } | |||
| render({ identifier }, { item }) { | |||
| if (item) { | |||
| return ( | |||
| <a href={ urlForObject(item) }>{ arvadosObjectName(item) }</a> | |||
| ); | |||
| } | |||
| const typeName = WBIdTools.typeName(identifier); | |||
| const url = (typeName === 'group' ? '/browse/' + identifier : | |||
| typeName === 'collection' ? '/collection-browse/' + identifier : | |||
| urlForObject({ uuid: identifier })); | |||
| return ( | |||
| <span> | |||
| <a href={ url }>{ identifier }</a> <a href="#" title="Look up" | |||
| onclick={ e => { e.preventDefault(); this.fetchData(); } }> | |||
| <i class="fas fa-search"></i> | |||
| </a> | |||
| </span> | |||
| ); | |||
| } | |||
| } | |||
| export default WBLazyInlineName; | |||
| @@ -0,0 +1,65 @@ | |||
| import { h, Component } from 'preact'; | |||
| import WBTable from 'wb-table'; | |||
| import makeArvadosRequest from 'make-arvados-request'; | |||
| import WBAccordion from 'wb-accordion'; | |||
| import WBJsonViewer from 'wb-json-viewer'; | |||
| import wbFormatSpecialValue from 'wb-format-special-value'; | |||
| import WBLazyInlineName from 'wb-lazy-inline-name'; | |||
| import wbFormatDate from 'wb-format-date'; | |||
| class WBProjectFields extends Component { | |||
| componentDidMount() { | |||
| this.prepareRows(); | |||
| } | |||
| componentWillReceiveProps(nextProps) { | |||
| this.props = nextProps; | |||
| this.prepareRows(); | |||
| } | |||
| prepareRows() { | |||
| let { uuid, app } = this.props; | |||
| let { arvHost, arvToken } = app.state; | |||
| let prom = makeArvadosRequest(arvHost, arvToken, | |||
| '/arvados/v1/groups/' + uuid); | |||
| prom = prom.then(xhr => { | |||
| const item = xhr.response; | |||
| const rows = [ | |||
| [ 'Name', wbFormatSpecialValue(item.name) ], | |||
| [ 'Description', wbFormatSpecialValue(item.description) ], | |||
| [ 'Properties', ( | |||
| <WBAccordion names={[ 'Properties' ]} cardHeaderClass="card-header-sm"> | |||
| <WBJsonViewer app={ app } value={ item.properties } /> | |||
| </WBAccordion> | |||
| ) ], | |||
| [ 'Writable by', item.writable_by | |||
| .map(a => (<WBLazyInlineName app={ app } identifier={ a } />)) | |||
| .reduce((a, b) => [].concat(a).concat(', ').concat(b)) | |||
| ], | |||
| [ 'Trash At', wbFormatDate(item.trash_at) ], | |||
| [ 'Delete At', wbFormatDate(item.delete_at) ], | |||
| [ 'Is Trashed', wbFormatSpecialValue(item.is_trashed) ] | |||
| ]; | |||
| this.setState({ 'rows': rows }); | |||
| }); | |||
| } | |||
| render({}, { rows }) { | |||
| return ( | |||
| rows ? ( | |||
| <WBTable columns={ [ "Name", "Value" ] } | |||
| headerClasses={ [ "col-sm-2", "col-sm-4" ] } | |||
| rows={ rows } | |||
| verticalHeader={ true } /> | |||
| ) : ( | |||
| <div>Loading...</div> | |||
| ) | |||
| ); | |||
| } | |||
| } | |||
| export default WBProjectFields; | |||
| @@ -4,6 +4,7 @@ import makeArvadosRequest from 'make-arvados-request'; | |||
| import WBTable from 'wb-table'; | |||
| import WBPagination from 'wb-pagination'; | |||
| import WBNameAndUuid from 'wb-name-and-uuid'; | |||
| import urlForObject from 'url-for-object'; | |||
| class WBProjectListing extends Component { | |||
| @@ -37,6 +38,10 @@ class WBProjectListing extends Component { | |||
| </div>), | |||
| ( <WBNameAndUuid app={ app } uuid={ item['owner_uuid'] } lazy={ true } /> ), | |||
| (<div> | |||
| <a class="btn btn-outline-primary m-1" title="Properties" | |||
| href={ urlForObject(item, 'properties') }> | |||
| <i class="fas fa-list-ul"></i> | |||
| </a> | |||
| { renderDeleteButton(item, () => this.fetchItems()) } | |||
| { renderSharingButton(item) } | |||
| </div>) | |||
| @@ -14,6 +14,7 @@ import WBLaunchWorkflowPage from 'wb-launch-workflow-page'; | |||
| import WBDownloadPage from 'wb-download-page'; | |||
| import WBImageViewerPage from 'wb-image-viewer-page'; | |||
| import WBSharingPage from 'wb-sharing-page'; | |||
| import WBProjectView from 'wb-project-view'; | |||
| import arvadosTypeName from 'arvados-type-name'; | |||
| class WBApp extends Component { | |||
| @@ -100,6 +101,8 @@ class WBApp extends Component { | |||
| <WBImageViewerPage path="/image-viewer/:blobUrl" app={ this } /> | |||
| <WBSharingPage path="/sharing/:uuid" app={ this } /> | |||
| <WBProjectView path="/project/:uuid" app={ this } /> | |||
| </Router> | |||
| ); | |||
| } | |||
| @@ -0,0 +1,29 @@ | |||
| import { h, Component } from 'preact'; | |||
| import WBNavbarCommon from 'wb-navbar-common'; | |||
| import WBArvadosCrumbs from 'wb-arvados-crumbs'; | |||
| import WBCommonFields from 'wb-common-fields'; | |||
| import WBProjectFields from 'wb-project-fields'; | |||
| class WBProjectView extends Component { | |||
| render({ app, uuid }, {}) { | |||
| return ( | |||
| <div> | |||
| <WBNavbarCommon app={ app } /> | |||
| <WBArvadosCrumbs app={ app } uuid={ uuid } /> | |||
| <div class="my-2"> | |||
| This is the project view for { uuid } | |||
| </div> | |||
| <h2>Common Fields</h2> | |||
| <WBCommonFields app={ app } uuid={ uuid } /> | |||
| <h2>Project Fields</h2> | |||
| <WBProjectFields app={ app } uuid={ uuid } /> | |||
| </div> | |||
| ); | |||
| } | |||
| } | |||
| export default WBProjectView; | |||