@@ -18,7 +18,7 @@ class WBProjectListing extends Component { | |||||
prepareRows(items) { | prepareRows(items) { | ||||
const { app, renderRenameLink, renderDeleteButton, | const { app, renderRenameLink, renderDeleteButton, | ||||
renderSelectionCell } = this.props; | |||||
renderSelectionCell, renderSharingButton } = this.props; | |||||
return items.map(item => [ | return items.map(item => [ | ||||
renderSelectionCell(item), | renderSelectionCell(item), | ||||
@@ -39,6 +39,7 @@ class WBProjectListing extends Component { | |||||
<i class="fas fa-toolbox"></i> | <i class="fas fa-toolbox"></i> | ||||
</button> | </button> | ||||
{ renderDeleteButton(item, () => this.fetchItems()) } | { renderDeleteButton(item, () => this.fetchItems()) } | ||||
{ renderSharingButton(item) } | |||||
</div>) | </div>) | ||||
]); | ]); | ||||
} | } | ||||
@@ -42,6 +42,7 @@ class WBBrowseDialog extends Component { | |||||
this.state.bottomPage = 0; | this.state.bottomPage = 0; | ||||
this.state.collectionPath = ''; | this.state.collectionPath = ''; | ||||
this.state.textSearch = ''; | this.state.textSearch = ''; | ||||
this.state.id = ('id' in this.props) ? this.props.id : uuid.v4(); | |||||
} | } | ||||
navigateBack() { | navigateBack() { | ||||
@@ -134,10 +135,14 @@ class WBBrowseDialog extends Component { | |||||
); | ); | ||||
} | } | ||||
render({ app, id, selectMany, selectWhat }, | |||||
show(callback) { | |||||
$('#' + this.state.id).modal(); | |||||
} | |||||
render({ app, selectMany, selectWhat }, | |||||
{ history, currentUrl, mode, uuid, | { history, currentUrl, mode, uuid, | ||||
topPage, bottomPage, textSearch, | topPage, bottomPage, textSearch, | ||||
collectionPath }) { | |||||
collectionPath, id }) { | |||||
return ( | return ( | ||||
<div class="modal" id={ id } tabindex="-1" role="dialog"> | <div class="modal" id={ id } tabindex="-1" role="dialog"> | ||||
@@ -13,6 +13,7 @@ import WBWorkflowView from 'wb-workflow-view'; | |||||
import WBLaunchWorkflowPage from 'wb-launch-workflow-page'; | 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 arvadosTypeName from 'arvados-type-name'; | import arvadosTypeName from 'arvados-type-name'; | ||||
class WBApp extends Component { | class WBApp extends Component { | ||||
@@ -97,6 +98,8 @@ class WBApp extends Component { | |||||
<WBDownloadPage path="/download/:blocksBlobUrl/:inline?" app={ this } /> | <WBDownloadPage path="/download/:blocksBlobUrl/:inline?" app={ this } /> | ||||
<WBImageViewerPage path="/image-viewer/:blobUrl" app={ this } /> | <WBImageViewerPage path="/image-viewer/:blobUrl" app={ this } /> | ||||
<WBSharingPage path="/sharing/:uuid" app={ this } /> | |||||
</Router> | </Router> | ||||
); | ); | ||||
} | } | ||||
@@ -109,6 +109,15 @@ class WBBrowse extends Component { | |||||
); | ); | ||||
} | } | ||||
renderSharingButton(item) { | |||||
return ( | |||||
<a class="btn btn-outline-success m-1" title="Share" | |||||
href={ '/sharing/' + item.uuid }> | |||||
<i class="fas fa-share-alt"></i> | |||||
</a> | |||||
); | |||||
} | |||||
moveOrCopyOp(op) { | moveOrCopyOp(op) { | ||||
const { ownerUuid, app } = this.props; | const { ownerUuid, app } = this.props; | ||||
const { selected } = this.state; | const { selected } = this.state; | ||||
@@ -164,7 +173,8 @@ class WBBrowse extends Component { | |||||
getPageUrl={ i => this.getUrl({ 'activePage': i }) } | getPageUrl={ i => this.getUrl({ 'activePage': i }) } | ||||
renderRenameLink={ (it, cb) => this.renderRenameLink(it, cb) } | renderRenameLink={ (it, cb) => this.renderRenameLink(it, cb) } | ||||
renderDeleteButton={ (it, cb) => this.renderDeleteButton(it, cb) } | renderDeleteButton={ (it, cb) => this.renderDeleteButton(it, cb) } | ||||
renderSelectionCell={ it => this.renderSelectionCell(it) } /> | |||||
renderSelectionCell={ it => this.renderSelectionCell(it) } | |||||
renderSharingButton={ it => this.renderSharingButton(it) } /> | |||||
{ (mode !== 'browse') ? null : ( | { (mode !== 'browse') ? null : ( | ||||
<WBTabs tabs={ [ | <WBTabs tabs={ [ | ||||
@@ -0,0 +1,71 @@ | |||||
import { h, Component, createRef } from 'preact'; | |||||
import WBNavbarCommon from 'wb-navbar-common'; | |||||
import WBArvadosCrumbs from 'wb-arvados-crumbs'; | |||||
import WBNameAndUuid from 'wb-name-and-uuid'; | |||||
import WBSelect from 'wb-select'; | |||||
import WBTable from 'wb-table'; | |||||
import WBBrowseDialog from 'wb-browse-dialog'; | |||||
import makeArvadosRequest from 'make-arvados-request'; | |||||
class WBSharingPage extends Component { | |||||
constructor(...args) { | |||||
super(...args); | |||||
this.state.rows = []; | |||||
this.browseDialogRef = createRef(); | |||||
} | |||||
componentDidMount() { | |||||
this.fetchData(); | |||||
} | |||||
fetchData() { | |||||
const { app, uuid } = this.props; | |||||
const { arvHost, arvToken } = app.state; | |||||
let prom = makeArvadosRequest(arvHost, arvToken, | |||||
'/arvados/v1/permissions/' + encodeURIComponent(uuid)); | |||||
prom = prom.then(xhr => this.setState({ | |||||
'rows': this.prepareRows(xhr.response.items) | |||||
})); | |||||
} | |||||
deletePermission(uuid) { | |||||
throw Error('Not implemented'); | |||||
} | |||||
prepareRows(items) { | |||||
const { app } = this.props; | |||||
return items.map(it => [ | |||||
( <WBNameAndUuid app={ app } uuid={ it.tail_uuid } /> ), | |||||
( <WBSelect value={ it.name } options={ ['can_read', 'can_write', 'can_manage'] } /> ), | |||||
( <button class="btn btn-outline-danger m-1" title="Delete" | |||||
onclick={ () => this.deletePermission(it.uuid) }> | |||||
<i class="fas fa-trash"></i> | |||||
</button> ) | |||||
]); | |||||
} | |||||
render({ app, uuid }, { rows }) { | |||||
return ( | |||||
<div> | |||||
<WBNavbarCommon app={ app } /> | |||||
<WBArvadosCrumbs app={ app } uuid={ uuid } /> | |||||
<div class="my-2"> | |||||
This is the sharing management page for { uuid } | |||||
</div> | |||||
<WBTable columns={ [ 'Name', 'Permission', '' ] } | |||||
headerClasses={ [ null, null, 'w-1' ] } | |||||
rows={ rows } /> | |||||
<WBBrowseDialog app={ app } ref={ this.browseDialogRef } /> | |||||
<button class="btn btn-primary" | |||||
onclick={ () => this.browseDialogRef.current.show() }>Add</button> | |||||
</div> | |||||
); | |||||
} | |||||
} | |||||
export default WBSharingPage; |
@@ -0,0 +1,19 @@ | |||||
import { h, Component } from 'preact'; | |||||
class WBSelect extends Component { | |||||
render({ value, options, onChange }) { | |||||
return ( | |||||
<select class="form-control" onchange={ onChange }> | |||||
{ options.map(o => { | |||||
const name = (typeof(o) === 'string') ? o : o.name; | |||||
const id = (typeof(o) === 'object') ? o.id : name; | |||||
return ( | |||||
<option selected={ (value === id) } value={ id }>{ name }</option> | |||||
); | |||||
}) } | |||||
</select> | |||||
); | |||||
} | |||||
} | |||||
export default WBSelect; |