| @@ -40,7 +40,7 @@ class WBCollectionFields extends Component { | |||||
| [ 'Description', wbFormatSpecialValue(item.description) ], | [ 'Description', wbFormatSpecialValue(item.description) ], | ||||
| [ 'Properties', ( | [ 'Properties', ( | ||||
| <WBAccordion names={ ['Properties'] } cardHeaderClass="card-header-sm"> | <WBAccordion names={ ['Properties'] } cardHeaderClass="card-header-sm"> | ||||
| <WBJsonViewer value={ item.properties } /> | |||||
| <WBJsonViewer app={ app } value={ item.properties } /> | |||||
| </WBAccordion> | </WBAccordion> | ||||
| ) ], | ) ], | ||||
| [ 'Portable Data Hash', item.portable_data_hash ], | [ 'Portable Data Hash', item.portable_data_hash ], | ||||
| @@ -39,38 +39,38 @@ class WBContainerFields extends Component { | |||||
| [ 'Environment', ( | [ 'Environment', ( | ||||
| <WBAccordion names={ ['Environment'] } | <WBAccordion names={ ['Environment'] } | ||||
| cardHeaderClass="card-header-sm"> | cardHeaderClass="card-header-sm"> | ||||
| <WBJsonViewer value={ item.environment } /> | |||||
| <WBJsonViewer app={ app } value={ item.environment } /> | |||||
| </WBAccordion> | </WBAccordion> | ||||
| ) ], | ) ], | ||||
| [ 'Working Directory', item.cwd ], | [ 'Working Directory', item.cwd ], | ||||
| [ 'Command', ( | [ 'Command', ( | ||||
| <WBJsonViewer value={ item.command } /> | |||||
| <WBJsonViewer app={ app } value={ item.command } /> | |||||
| ) ], | ) ], | ||||
| [ 'Output Path', item.output_path ], | [ 'Output Path', item.output_path ], | ||||
| [ 'Mounts', ( | [ 'Mounts', ( | ||||
| <WBAccordion names={ Object.keys(item.mounts) } | <WBAccordion names={ Object.keys(item.mounts) } | ||||
| cardHeaderClass="card-header-sm"> | cardHeaderClass="card-header-sm"> | ||||
| { Object.keys(item.mounts).map(k => ( | { Object.keys(item.mounts).map(k => ( | ||||
| <WBJsonViewer value={ item.mounts[k] } /> | |||||
| <WBJsonViewer app={ app } value={ item.mounts[k] } /> | |||||
| )) } | )) } | ||||
| </WBAccordion> | </WBAccordion> | ||||
| ) ], | ) ], | ||||
| [ 'Runtime Constraints', ( | [ 'Runtime Constraints', ( | ||||
| <WBAccordion names={ ['Runtime Constraints'] } | <WBAccordion names={ ['Runtime Constraints'] } | ||||
| cardHeaderClass="card-header-sm"> | cardHeaderClass="card-header-sm"> | ||||
| <WBJsonViewer value={ item.runtime_constraints } /> | |||||
| <WBJsonViewer app={ app } value={ item.runtime_constraints } /> | |||||
| </WBAccordion> | </WBAccordion> | ||||
| ) ], | ) ], | ||||
| [ 'Runtime Status', ( | [ 'Runtime Status', ( | ||||
| <WBAccordion names={ ['Runtime Status'] } | <WBAccordion names={ ['Runtime Status'] } | ||||
| cardHeaderClass="card-header-sm"> | cardHeaderClass="card-header-sm"> | ||||
| <WBJsonViewer value={ item.runtime_status } /> | |||||
| <WBJsonViewer app={ app } value={ item.runtime_status } /> | |||||
| </WBAccordion> | </WBAccordion> | ||||
| ) ], | ) ], | ||||
| [ 'Scheduling Parameters', ( | [ 'Scheduling Parameters', ( | ||||
| <WBAccordion names={ ['Scheduling Parameters'] } | <WBAccordion names={ ['Scheduling Parameters'] } | ||||
| cardHeaderClass="card-header-sm"> | cardHeaderClass="card-header-sm"> | ||||
| <WBJsonViewer value={ item.scheduling_parameters } /> | |||||
| <WBJsonViewer app={ app } value={ item.scheduling_parameters } /> | |||||
| </WBAccordion> | </WBAccordion> | ||||
| ) ], | ) ], | ||||
| [ 'Output', item.output ? ( | [ 'Output', item.output ? ( | ||||
| @@ -34,7 +34,7 @@ class WBContainerRequestFields extends Component { | |||||
| [ 'Description', item.description || (<i>{ String(item.description) }</i>) ], | [ 'Description', item.description || (<i>{ String(item.description) }</i>) ], | ||||
| [ 'Properties', ( | [ 'Properties', ( | ||||
| <WBAccordion names={ ['Properties'] } cardHeaderClass="card-header-sm"> | <WBAccordion names={ ['Properties'] } cardHeaderClass="card-header-sm"> | ||||
| <WBJsonViewer value={ item.properties } /> | |||||
| <WBJsonViewer app={ app } value={ item.properties } /> | |||||
| </WBAccordion> | </WBAccordion> | ||||
| ) ], | ) ], | ||||
| [ 'State', item.state ], | [ 'State', item.state ], | ||||
| @@ -49,20 +49,20 @@ class WBContainerRequestFields extends Component { | |||||
| <WBAccordion names={ Object.keys(item.mounts) } | <WBAccordion names={ Object.keys(item.mounts) } | ||||
| cardHeaderClass="card-header-sm"> | cardHeaderClass="card-header-sm"> | ||||
| { Object.keys(item.mounts).map(k => ( | { Object.keys(item.mounts).map(k => ( | ||||
| <WBJsonViewer value={ item.mounts[k] } /> | |||||
| <WBJsonViewer app={ app } value={ item.mounts[k] } /> | |||||
| )) } | )) } | ||||
| </WBAccordion> | </WBAccordion> | ||||
| ) ], | ) ], | ||||
| [ 'Runtime Constraints', ( | [ 'Runtime Constraints', ( | ||||
| <WBAccordion names={ ['Runtime Constraints'] } | <WBAccordion names={ ['Runtime Constraints'] } | ||||
| cardHeaderClass="card-header-sm"> | cardHeaderClass="card-header-sm"> | ||||
| <WBJsonViewer value={ item.runtime_constraints } /> | |||||
| <WBJsonViewer app={ app } value={ item.runtime_constraints } /> | |||||
| </WBAccordion> | </WBAccordion> | ||||
| ) ], | ) ], | ||||
| [ 'Scheduling Parameters', ( | [ 'Scheduling Parameters', ( | ||||
| <WBAccordion names={ ['Scheduling Parameters'] } | <WBAccordion names={ ['Scheduling Parameters'] } | ||||
| cardHeaderClass="card-header-sm"> | cardHeaderClass="card-header-sm"> | ||||
| <WBJsonViewer value={ item.scheduling_parameters } /> | |||||
| <WBJsonViewer app={ app } value={ item.scheduling_parameters } /> | |||||
| </WBAccordion> | </WBAccordion> | ||||
| ) ], | ) ], | ||||
| [ 'Container Image', ( | [ 'Container Image', ( | ||||
| @@ -71,12 +71,12 @@ class WBContainerRequestFields extends Component { | |||||
| [ 'Environment', ( | [ 'Environment', ( | ||||
| <WBAccordion names={ ['Environment'] } | <WBAccordion names={ ['Environment'] } | ||||
| cardHeaderClass="card-header-sm"> | cardHeaderClass="card-header-sm"> | ||||
| <WBJsonViewer value={ item.environment } /> | |||||
| <WBJsonViewer app={ app } value={ item.environment } /> | |||||
| </WBAccordion> | </WBAccordion> | ||||
| ) ], | ) ], | ||||
| [ 'Working Directory', item.cwd ], | [ 'Working Directory', item.cwd ], | ||||
| [ 'Command', ( | [ 'Command', ( | ||||
| <WBJsonViewer value={ item.command } /> | |||||
| <WBJsonViewer app={ app } value={ item.command } /> | |||||
| ) ], | ) ], | ||||
| [ 'Output Path', item.output_path ], | [ 'Output Path', item.output_path ], | ||||
| [ 'Output Name', item.output_name ], | [ 'Output Name', item.output_name ], | ||||
| @@ -91,7 +91,7 @@ class WBContainerRequestFields extends Component { | |||||
| <WBNameAndUuid app={ app } uuid={ item.output_uuid } /> | <WBNameAndUuid app={ app } uuid={ item.output_uuid } /> | ||||
| ) ], | ) ], | ||||
| [ 'Filters', ( | [ 'Filters', ( | ||||
| item.filters ? (<WBJsonViewer value={ item.filters } />) : (<i>{ String(item.filters) }</i>) | |||||
| item.filters ? (<WBJsonViewer app={ app } value={ item.filters } />) : (<i>{ String(item.filters) }</i>) | |||||
| ) ], | ) ], | ||||
| [ 'Runtime Token', item.runtime_token || (<i>{ String(item.runtime_token) }</i>) ], | [ 'Runtime Token', item.runtime_token || (<i>{ String(item.runtime_token) }</i>) ], | ||||
| [ 'Runtime User', ( | [ 'Runtime User', ( | ||||
| @@ -99,7 +99,7 @@ class WBContainerRequestFields extends Component { | |||||
| ) ], | ) ], | ||||
| [ 'Runtime Auth Scopes', ( | [ 'Runtime Auth Scopes', ( | ||||
| item.runtime_auth_scopes ? ( | item.runtime_auth_scopes ? ( | ||||
| <WBJsonViewer value={ item.runtime_auth_scopes } /> | |||||
| <WBJsonViewer app={ app } value={ item.runtime_auth_scopes } /> | |||||
| ) : ( | ) : ( | ||||
| <i>{ String(item.runtime_auth_scopes) }</i> | <i>{ String(item.runtime_auth_scopes) }</i> | ||||
| ) | ) | ||||
| @@ -1,8 +1,56 @@ | |||||
| import { h, Component } from 'preact'; | import { h, Component } from 'preact'; | ||||
| import WBIdTools from 'wb-id-tools'; | 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 arvadosObjectName from 'arvados-object-name'; | |||||
| function detectIds(value) { | |||||
| class WBLazyInlineName extends Component { | |||||
| 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> | |||||
| ); | |||||
| } | |||||
| } | |||||
| function detectIds(value, app) { | |||||
| const matches = WBIdTools.detectIdentifiers(value); | const matches = WBIdTools.detectIdentifiers(value); | ||||
| matches.sort((a, b) => (a.index - b.index)); | matches.sort((a, b) => (a.index - b.index)); | ||||
| const res = []; | const res = []; | ||||
| @@ -15,7 +63,7 @@ function detectIds(value) { | |||||
| typeName === 'collection' ? '/collection-browse/' + id : | typeName === 'collection' ? '/collection-browse/' + id : | ||||
| urlForObject({ uuid: id })); | urlForObject({ uuid: id })); | ||||
| res.push(value.substring(ofs, index)); | res.push(value.substring(ofs, index)); | ||||
| res.push(h('a', { href: url }, id)); | |||||
| res.push(h(WBLazyInlineName, { identifier: id, app }, id)); | |||||
| ofs = index + id.length; | ofs = index + id.length; | ||||
| } | } | ||||
| res.push(value.substring(ofs)); | res.push(value.substring(ofs)); | ||||
| @@ -23,11 +71,11 @@ function detectIds(value) { | |||||
| } | } | ||||
| class WBJsonViewer extends Component { | class WBJsonViewer extends Component { | ||||
| render({ value, stringify }) { | |||||
| render({ value, stringify, app }) { | |||||
| if (stringify) | if (stringify) | ||||
| value = JSON.stringify(value, null, 2); | value = JSON.stringify(value, null, 2); | ||||
| return ( | return ( | ||||
| <div class="wb-json-viewer">{ detectIds(value) }</div> | |||||
| <div class="wb-json-viewer">{ detectIds(value, app) }</div> | |||||
| ); | ); | ||||
| } | } | ||||
| } | } | ||||
| @@ -52,9 +52,9 @@ class WBWorkflowFields extends Component { | |||||
| <WBAccordion names={ [ 'Inputs', 'Outputs', 'Rest' ] } | <WBAccordion names={ [ 'Inputs', 'Outputs', 'Rest' ] } | ||||
| cardHeaderClass="card-header-sm"> | cardHeaderClass="card-header-sm"> | ||||
| <WBJsonViewer value={ it.inputs } /> | |||||
| <WBJsonViewer app={ app } value={ it.inputs } /> | |||||
| <WBJsonViewer value={ it.outputs } /> | |||||
| <WBJsonViewer app={ app } value={ it.outputs } /> | |||||
| { (() => { | { (() => { | ||||
| delete it['inputs']; | delete it['inputs']; | ||||
| @@ -64,7 +64,7 @@ class WBWorkflowFields extends Component { | |||||
| delete it['doc']; | delete it['doc']; | ||||
| delete it['id']; | delete it['id']; | ||||
| return ( | return ( | ||||
| <WBJsonViewer value={ it } /> | |||||
| <WBJsonViewer app={ app } value={ it } /> | |||||
| ); | ); | ||||
| })() } | })() } | ||||
| @@ -78,7 +78,7 @@ class WBWorkflowFields extends Component { | |||||
| cardHeaderClass="card-header-sm"> | cardHeaderClass="card-header-sm"> | ||||
| { graph.map(it => ( | { graph.map(it => ( | ||||
| <WBJsonViewer value={ it } /> | |||||
| <WBJsonViewer app={ app } value={ it } /> | |||||
| )) } | )) } | ||||
| </WBAccordion> | </WBAccordion> | ||||