diff --git a/frontend/src/js/component/wb-collection-listing.js b/frontend/src/js/component/wb-collection-listing.js index f0eaa27..6e01e6a 100644 --- a/frontend/src/js/component/wb-collection-listing.js +++ b/frontend/src/js/component/wb-collection-listing.js @@ -22,7 +22,7 @@ class WBCollectionListing extends Component { prepareRows(items, ownerLookup) { let { app, renderRenameLink, renderDeleteButton, - renderSelectionCell } = this.props; + renderSelectionCell, renderSharingButton } = this.props; return items.map(item => [ renderSelectionCell(item), @@ -59,6 +59,8 @@ class WBCollectionListing extends Component { { renderDeleteButton(item, () => this.fetchItems()) } + + { renderSharingButton(item) } ) ]); } diff --git a/frontend/src/js/component/wb-process-listing.js b/frontend/src/js/component/wb-process-listing.js index 7c1f3df..3228ed1 100644 --- a/frontend/src/js/component/wb-process-listing.js +++ b/frontend/src/js/component/wb-process-listing.js @@ -29,7 +29,7 @@ class WBProcessListing extends Component { prepareRows(requests, containerLookup, ownerLookup, outputLookup) { const { app, renderRenameLink, renderDeleteButton, - renderSelectionCell } = this.props; + renderSelectionCell, renderSharingButton } = this.props; return requests.map(item => { return ( [ renderSelectionCell(item), @@ -47,6 +47,7 @@ class WBProcessListing extends Component { ( ), (
{ renderDeleteButton(item, () => this.fetchItems()) } + { renderSharingButton(item) }
) ] ); }); diff --git a/frontend/src/js/component/wb-workflow-listing.js b/frontend/src/js/component/wb-workflow-listing.js index dbb7fcd..4dbea55 100644 --- a/frontend/src/js/component/wb-workflow-listing.js +++ b/frontend/src/js/component/wb-workflow-listing.js @@ -22,7 +22,7 @@ class WBWorkflowListing extends Component { prepareRows(items, ownerLookup) { const { renderRenameLink, renderDeleteButton, - renderSelectionCell } = this.props; + renderSelectionCell, renderSharingButton } = this.props; return items.map(item => [ renderSelectionCell(item), ( @@ -43,6 +43,7 @@ class WBWorkflowListing extends Component { href={ urlForObject(item, 'launch') }> { renderDeleteButton(item, () => this.fetchItems()) } + { renderSharingButton(item) } ) ]); } diff --git a/frontend/src/js/page/wb-browse.js b/frontend/src/js/page/wb-browse.js index aad22eb..eb83941 100644 --- a/frontend/src/js/page/wb-browse.js +++ b/frontend/src/js/page/wb-browse.js @@ -194,7 +194,8 @@ class WBBrowse extends Component { getPageUrl={ i => this.getUrl({ 'collectionPage': 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) } /> ) : (objTypeTab === 'process') ? ( this.route({ 'processPage': 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) } /> ) : (objTypeTab === 'workflow') ? ( this.getUrl({ 'workflowPage': 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) } /> ) : null } diff --git a/frontend/src/js/page/wb-sharing-page.js b/frontend/src/js/page/wb-sharing-page.js index 3ef7193..4a4562d 100644 --- a/frontend/src/js/page/wb-sharing-page.js +++ b/frontend/src/js/page/wb-sharing-page.js @@ -22,37 +22,116 @@ class WBSharingPage extends Component { const { app, uuid } = this.props; const { arvHost, arvToken } = app.state; let prom = makeArvadosRequest(arvHost, arvToken, - '/arvados/v1/permissions/' + encodeURIComponent(uuid)); + '/arvados/v1/permissions/' + encodeURIComponent(uuid) + + '?limit=100000'); prom = prom.then(xhr => this.setState({ + 'entries': xhr.response.items, 'rows': this.prepareRows(xhr.response.items) })); } - deletePermission(uuid) { - throw Error('Not implemented'); + deleteEntry(it) { + it._delete = true; + this.setState({ rows: this.prepareRows(this.state.entries) }); } prepareRows(items) { const { app } = this.props; - return items.map(it => [ + return items.filter(it => (!it._delete)).map(it => [ ( ), - ( ), + ( this.modifyEntry(it, e.target.value) } /> ), ( ) ]); } - addEntry(it) { - throw Error('Not implemented'); + modifyEntry(it, newPermissionName) { + it.name = newPermissionName; + it._dirty = true; + // this.setState({ rows: this.prepareRows(this.state.entries) }); + } + + addEntry(it, permissionName='can_read') { + // throw Error('Not implemented'); + const { uuid } = this.props; + let { entries } = this.state; + if (entries.filter(e => (e.tail_uuid === it.uuid)).length > 0) + return; // already in the list + const e = { + //_dirty: true, + link_class: 'permission', + head_uuid: uuid, + tail_uuid: it.uuid, + name: permissionName + }; + entries = entries.concat([e]); + this.setState({ + entries, + rows: this.prepareRows(entries) + }); + } + + disableControls() { + $('input, select, button').attr('disabled', 'disabled'); + $('a').each(function() { $(this).data('old_href', $(this).attr('href')); }); + $('a').attr('href', null); + } + + enableControls() { + $('input, select, button').attr('disabled', null); + $('a').each(function() { $(this).attr('href', $(this).data('old_href')); }); } save() { - throw Error('Not implemented'); + const { entries } = this.state; + const { arvHost, arvToken } = this.props.app.state; + let prom = new Promise(accept => accept()); + this.disableControls(); + this.setState({ working: true }); + for (let i = 0; i < entries.length; i++) { + const e = entries[i]; + + //if (!e._dirty && !e._delete) + //continue; + + if (!e.uuid) { + prom = prom.then(() => makeArvadosRequest(arvHost, arvToken, + '/arvados/v1/links', + { 'method': 'POST', + 'data': JSON.stringify({ + 'link_class': 'permission', + 'head_uuid': e.head_uuid, + 'tail_uuid': e.tail_uuid, + 'name': e.name + }) })); + + } else if (e._delete) { + prom = prom.then(() => makeArvadosRequest(arvHost, arvToken, + '/arvados/v1/links/' + e.uuid, + { 'method': 'DELETE' })); + + } else if (e._dirty) { + prom = prom.then(() => makeArvadosRequest(arvHost, arvToken, + '/arvados/v1/links/' + e.uuid, + { 'method': 'PUT', + 'data': JSON.stringify({ + 'name': e.name + }) })); + } + prom = prom.catch(() => {}); + } + prom = prom.then(() => { + this.enableControls(); + this.fetchData(); + this.setState({ working: false }); + }); } - render({ app, uuid }, { rows }) { + render({ app, uuid }, { rows, working }) { return (
@@ -70,6 +149,12 @@ class WBSharingPage extends Component { + { working ? (
+
+
) : null } +