@@ -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; |