| @@ -4,9 +4,12 @@ function urlForObject(item, mode='primary') { | |||||
| let objectType = arvadosTypeName(item.uuid.split('-')[1]); | let objectType = arvadosTypeName(item.uuid.split('-')[1]); | ||||
| if (objectType === 'user') | if (objectType === 'user') | ||||
| return ('/browse/' + item.uuid); | 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); | return ('/process/' + item.uuid); | ||||
| else if (objectType === 'workflow') { | else if (objectType === 'workflow') { | ||||
| if (mode === 'launch') | if (mode === 'launch') | ||||
| @@ -3,58 +3,7 @@ import WBIdTools from 'wb-id-tools'; | |||||
| import urlForObject from 'url-for-object'; | import urlForObject from 'url-for-object'; | ||||
| import makeArvadosRequest from 'make-arvados-request'; | import makeArvadosRequest from 'make-arvados-request'; | ||||
| import arvadosObjectName from 'arvados-object-name'; | 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) { | function detectIds(value, app) { | ||||
| const matches = WBIdTools.detectIdentifiers(value); | 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 WBTable from 'wb-table'; | ||||
| import WBPagination from 'wb-pagination'; | import WBPagination from 'wb-pagination'; | ||||
| import WBNameAndUuid from 'wb-name-and-uuid'; | import WBNameAndUuid from 'wb-name-and-uuid'; | ||||
| import urlForObject from 'url-for-object'; | |||||
| class WBProjectListing extends Component { | class WBProjectListing extends Component { | ||||
| @@ -37,6 +38,10 @@ class WBProjectListing extends Component { | |||||
| </div>), | </div>), | ||||
| ( <WBNameAndUuid app={ app } uuid={ item['owner_uuid'] } lazy={ true } /> ), | ( <WBNameAndUuid app={ app } uuid={ item['owner_uuid'] } lazy={ true } /> ), | ||||
| (<div> | (<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()) } | { renderDeleteButton(item, () => this.fetchItems()) } | ||||
| { renderSharingButton(item) } | { renderSharingButton(item) } | ||||
| </div>) | </div>) | ||||
| @@ -14,6 +14,7 @@ import WBLaunchWorkflowPage from 'wb-launch-workflow-page'; | |||||
| import WBDownloadPage from 'wb-download-page'; | import WBDownloadPage from 'wb-download-page'; | ||||
| import WBImageViewerPage from 'wb-image-viewer-page'; | import WBImageViewerPage from 'wb-image-viewer-page'; | ||||
| import WBSharingPage from 'wb-sharing-page'; | import WBSharingPage from 'wb-sharing-page'; | ||||
| import WBProjectView from 'wb-project-view'; | |||||
| import arvadosTypeName from 'arvados-type-name'; | import arvadosTypeName from 'arvados-type-name'; | ||||
| class WBApp extends Component { | class WBApp extends Component { | ||||
| @@ -100,6 +101,8 @@ class WBApp extends Component { | |||||
| <WBImageViewerPage path="/image-viewer/:blobUrl" app={ this } /> | <WBImageViewerPage path="/image-viewer/:blobUrl" app={ this } /> | ||||
| <WBSharingPage path="/sharing/:uuid" app={ this } /> | <WBSharingPage path="/sharing/:uuid" app={ this } /> | ||||
| <WBProjectView path="/project/:uuid" app={ this } /> | |||||
| </Router> | </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; | |||||