| @@ -18,7 +18,7 @@ class WBProjectListing extends Component { | |||
| prepareRows(items) { | |||
| const { app, renderRenameLink, renderDeleteButton, | |||
| renderSelectionCell } = this.props; | |||
| renderSelectionCell, renderSharingButton } = this.props; | |||
| return items.map(item => [ | |||
| renderSelectionCell(item), | |||
| @@ -39,6 +39,7 @@ class WBProjectListing extends Component { | |||
| <i class="fas fa-toolbox"></i> | |||
| </button> | |||
| { renderDeleteButton(item, () => this.fetchItems()) } | |||
| { renderSharingButton(item) } | |||
| </div>) | |||
| ]); | |||
| } | |||
| @@ -42,6 +42,7 @@ class WBBrowseDialog extends Component { | |||
| this.state.bottomPage = 0; | |||
| this.state.collectionPath = ''; | |||
| this.state.textSearch = ''; | |||
| this.state.id = ('id' in this.props) ? this.props.id : uuid.v4(); | |||
| } | |||
| 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, | |||
| topPage, bottomPage, textSearch, | |||
| collectionPath }) { | |||
| collectionPath, id }) { | |||
| return ( | |||
| <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 WBDownloadPage from 'wb-download-page'; | |||
| import WBImageViewerPage from 'wb-image-viewer-page'; | |||
| import WBSharingPage from 'wb-sharing-page'; | |||
| import arvadosTypeName from 'arvados-type-name'; | |||
| class WBApp extends Component { | |||
| @@ -97,6 +98,8 @@ class WBApp extends Component { | |||
| <WBDownloadPage path="/download/:blocksBlobUrl/:inline?" app={ this } /> | |||
| <WBImageViewerPage path="/image-viewer/:blobUrl" app={ this } /> | |||
| <WBSharingPage path="/sharing/:uuid" app={ this } /> | |||
| </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) { | |||
| const { ownerUuid, app } = this.props; | |||
| const { selected } = this.state; | |||
| @@ -164,7 +173,8 @@ class WBBrowse extends Component { | |||
| getPageUrl={ i => this.getUrl({ 'activePage': i }) } | |||
| renderRenameLink={ (it, cb) => this.renderRenameLink(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 : ( | |||
| <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; | |||