| @@ -21,7 +21,7 @@ class WBCollectionListing extends Component { | |||||
| } | } | ||||
| prepareRows(items, ownerLookup) { | prepareRows(items, ownerLookup) { | ||||
| let { app, renderRenameLink } = this.props; | |||||
| let { app, renderRenameLink, renderDeleteButton } = this.props; | |||||
| return items.map(item => [ | return items.map(item => [ | ||||
| (<div> | (<div> | ||||
| @@ -56,9 +56,7 @@ class WBCollectionListing extends Component { | |||||
| <i class="fas fa-list-ul"></i> | <i class="fas fa-list-ul"></i> | ||||
| </a> | </a> | ||||
| <button class="btn btn-outline-danger m-1" title="Delete"> | |||||
| <i class="fas fa-trash"></i> | |||||
| </button> | |||||
| { renderDeleteButton(item, () => this.fetchItems()) } | |||||
| </div>) | </div>) | ||||
| ]); | ]); | ||||
| } | } | ||||
| @@ -22,7 +22,7 @@ class WBProcessListing extends Component { | |||||
| } | } | ||||
| prepareRows(items) { | prepareRows(items) { | ||||
| const { renderRenameLink } = this.props; | |||||
| const { renderRenameLink, renderDeleteButton } = this.props; | |||||
| return items.map(item => [ | return items.map(item => [ | ||||
| (<div> | (<div> | ||||
| <div> | <div> | ||||
| @@ -38,7 +38,7 @@ class WBProcessListing extends Component { | |||||
| item['created_at'].replace('T', ' ').substr(0, item['created_at'].length - 11) + '', | item['created_at'].replace('T', ' ').substr(0, item['created_at'].length - 11) + '', | ||||
| item['output_uuid'], | item['output_uuid'], | ||||
| (<div> | (<div> | ||||
| <button class="btn btn-outline-danger"><i class="fas fa-trash"></i></button> | |||||
| { renderDeleteButton(item, () => this.fetchItems()) } | |||||
| </div>) | </div>) | ||||
| ]); | ]); | ||||
| } | } | ||||
| @@ -17,7 +17,7 @@ class WBProjectListing extends Component { | |||||
| } | } | ||||
| prepareRows(items) { | prepareRows(items) { | ||||
| let { app, renderRenameLink } = this.props; | |||||
| let { app, renderRenameLink, renderDeleteButton } = this.props; | |||||
| return items.map(item => [ | return items.map(item => [ | ||||
| (<div> | (<div> | ||||
| @@ -36,6 +36,7 @@ class WBProjectListing extends Component { | |||||
| onclick={ () => (app.addToToolbox(item.uuid)) }> | onclick={ () => (app.addToToolbox(item.uuid)) }> | ||||
| <i class="fas fa-toolbox"></i> | <i class="fas fa-toolbox"></i> | ||||
| </button> | </button> | ||||
| { renderDeleteButton(item, () => this.fetchItems()) } | |||||
| </div>) | </div>) | ||||
| ]); | ]); | ||||
| } | } | ||||
| @@ -21,7 +21,7 @@ class WBWorkflowListing extends Component { | |||||
| } | } | ||||
| prepareRows(items, ownerLookup) { | prepareRows(items, ownerLookup) { | ||||
| const { renderRenameLink } = this.props; | |||||
| const { renderRenameLink, renderDeleteButton } = this.props; | |||||
| return items.map(item => [ | return items.map(item => [ | ||||
| ( | ( | ||||
| <div> | <div> | ||||
| @@ -40,7 +40,7 @@ class WBWorkflowListing extends Component { | |||||
| <a class="btn btn-outline-success mx-1 my-1" title="Launch" | <a class="btn btn-outline-success mx-1 my-1" title="Launch" | ||||
| href={ urlForObject(item, 'launch') }><i class="fas fa-running"></i></a> | href={ urlForObject(item, 'launch') }><i class="fas fa-running"></i></a> | ||||
| <button class="btn btn-outline-primary mx-1 my-1" title="View"><i class="far fa-eye"></i></button> | <button class="btn btn-outline-primary mx-1 my-1" title="View"><i class="far fa-eye"></i></button> | ||||
| <button class="btn btn-outline-danger mx-1 my-1" title="Delete"><i class="fas fa-trash"></i></button> | |||||
| { renderDeleteButton(item, () => this.fetchItems()) } | |||||
| </div>) | </div>) | ||||
| ]); | ]); | ||||
| } | } | ||||
| @@ -0,0 +1,53 @@ | |||||
| import { h, Component, createRef } from 'preact'; | |||||
| import WBDialog from 'wb-dialog'; | |||||
| import WBArvadosCrumbs from 'wb-arvados-crumbs'; | |||||
| import linkState from 'linkstate'; | |||||
| import wbDeleteObject from 'wb-delete-object'; | |||||
| import arvadosTypeName from 'arvados-type-name'; | |||||
| class WBDeleteDialog extends Component { | |||||
| constructor(...args) { | |||||
| super(...args); | |||||
| this.dialogRef = createRef(); | |||||
| } | |||||
| show(item, callback) { | |||||
| this.setState({ | |||||
| 'item': item, | |||||
| 'callback': callback || (() => {}) | |||||
| }); | |||||
| this.dialogRef.current.show(); | |||||
| } | |||||
| hide() { | |||||
| this.dialogRef.current.hide(); | |||||
| } | |||||
| render({ app }, { item, callback }) { | |||||
| const { arvHost, arvToken } = app.state; | |||||
| return ( | |||||
| <WBDialog title="Delete" ref={ this.dialogRef }> | |||||
| <div> | |||||
| <div class="mb-3"> | |||||
| Are you sure you want to delete the following { item ? arvadosTypeName(item.uuid) : null }: | |||||
| </div> | |||||
| { item ? <WBArvadosCrumbs app={ app } uuid={ item.uuid } /> : null } | |||||
| <div>???</div> | |||||
| </div> | |||||
| <div> | |||||
| <input type="submit" class="btn btn-danger mr-2" value="Delete" | |||||
| onclick={ e => { e.preventDefault(); | |||||
| wbDeleteObject(arvHost, arvToken, item.uuid).then(callback); } } /> | |||||
| <button class="btn btn-secondary mr-2" onclick={ e => { e.preventDefault(); | |||||
| this.hide(); } }> | |||||
| Cancel | |||||
| </button> | |||||
| </div> | |||||
| </WBDialog> | |||||
| ); | |||||
| } | |||||
| } | |||||
| export default WBDeleteDialog; | |||||
| @@ -0,0 +1,11 @@ | |||||
| import makeArvadosRequest from 'make-arvados-request'; | |||||
| import arvadosTypeName from 'arvados-type-name'; | |||||
| function wbDeleteObject(arvHost, arvToken, uuid) { | |||||
| const typeName = arvadosTypeName(uuid); | |||||
| return makeArvadosRequest(arvHost, arvToken, | |||||
| '/arvados/v1/' + typeName + 's/' + | |||||
| uuid, { 'method': 'DELETE' }); | |||||
| } | |||||
| export default wbDeleteObject; | |||||
| @@ -9,11 +9,13 @@ import WBProcessListing from 'wb-process-listing'; | |||||
| import WBCollectionListing from 'wb-collection-listing'; | import WBCollectionListing from 'wb-collection-listing'; | ||||
| import WBWorkflowListing from 'wb-workflow-listing'; | import WBWorkflowListing from 'wb-workflow-listing'; | ||||
| import WBRenameDialog from 'wb-rename-dialog'; | import WBRenameDialog from 'wb-rename-dialog'; | ||||
| import WBDeleteDialog from 'wb-delete-dialog'; | |||||
| class WBBrowse extends Component { | class WBBrowse extends Component { | ||||
| constructor(...args) { | constructor(...args) { | ||||
| super(...args); | super(...args); | ||||
| this.renameDialogRef = createRef(); | this.renameDialogRef = createRef(); | ||||
| this.deleteDialogRef = createRef(); | |||||
| } | } | ||||
| getUrl(params) { | getUrl(params) { | ||||
| @@ -45,6 +47,15 @@ class WBBrowse extends Component { | |||||
| ); | ); | ||||
| } | } | ||||
| renderDeleteButton(item, callback) { | |||||
| return ( | |||||
| <button class="btn btn-outline-danger m-1" title="Delete" | |||||
| onclick={ () => this.deleteDialogRef.current.show(item, callback) }> | |||||
| <i class="fas fa-trash"></i> | |||||
| </button> | |||||
| ); | |||||
| } | |||||
| render({ ownerUuid, activePage, appState, app, | render({ ownerUuid, activePage, appState, app, | ||||
| objTypeTab, collectionPage, processPage, workflowPage }) { | objTypeTab, collectionPage, processPage, workflowPage }) { | ||||
| @@ -52,6 +63,8 @@ class WBBrowse extends Component { | |||||
| <div> | <div> | ||||
| <WBRenameDialog app={ app } ref={ this.renameDialogRef } /> | <WBRenameDialog app={ app } ref={ this.renameDialogRef } /> | ||||
| <WBDeleteDialog app={ app } ref={ this.deleteDialogRef } /> | |||||
| <WBNavbarCommon app={ app } activeItem={ !ownerUuid ? 'all-projects' : | <WBNavbarCommon app={ app } activeItem={ !ownerUuid ? 'all-projects' : | ||||
| (ownerUuid === app.state.currentUser.uuid ? 'home' : null) } /> | (ownerUuid === app.state.currentUser.uuid ? 'home' : null) } /> | ||||
| @@ -66,7 +79,8 @@ class WBBrowse extends Component { | |||||
| itemsPerPage="5" | itemsPerPage="5" | ||||
| activePage={ Number(activePage || 0) } | activePage={ Number(activePage || 0) } | ||||
| onPageChanged={ i => route('/browse/' + (ownerUuid || '') + '/' + i) } | onPageChanged={ i => route('/browse/' + (ownerUuid || '') + '/' + i) } | ||||
| renderRenameLink={ (it, cb) => this.renderRenameLink(it, cb) } /> | |||||
| renderRenameLink={ (it, cb) => this.renderRenameLink(it, cb) } | |||||
| renderDeleteButton={ (it, cb) => this.renderDeleteButton(it, cb) } /> | |||||
| <WBTabs tabs={ [ | <WBTabs tabs={ [ | ||||
| { 'id': 'collection', 'name': 'Collections', 'isActive': (!objTypeTab || objTypeTab === 'collection') }, | { 'id': 'collection', 'name': 'Collections', 'isActive': (!objTypeTab || objTypeTab === 'collection') }, | ||||
| @@ -81,7 +95,8 @@ class WBBrowse extends Component { | |||||
| itemsPerPage="20" | itemsPerPage="20" | ||||
| activePage={ Number(collectionPage || 0) } | activePage={ Number(collectionPage || 0) } | ||||
| getPageUrl={ i => this.getUrl({ 'collectionPage': i }) } | getPageUrl={ i => this.getUrl({ 'collectionPage': i }) } | ||||
| renderRenameLink={ (it, cb) => this.renderRenameLink(it, cb) } /> | |||||
| renderRenameLink={ (it, cb) => this.renderRenameLink(it, cb) } | |||||
| renderDeleteButton={ (it, cb) => this.renderDeleteButton(it, cb) } /> | |||||
| ) : (objTypeTab === 'process' ? ( | ) : (objTypeTab === 'process' ? ( | ||||
| <WBProcessListing appState={ appState } | <WBProcessListing appState={ appState } | ||||
| @@ -89,7 +104,8 @@ class WBBrowse extends Component { | |||||
| itemsPerPage="20" | itemsPerPage="20" | ||||
| activePage={ Number(processPage || 0) } | activePage={ Number(processPage || 0) } | ||||
| onPageChanged={ i => this.route({ 'processPage': i }) } | onPageChanged={ i => this.route({ 'processPage': i }) } | ||||
| renderRenameLink={ (it, cb) => this.renderRenameLink(it, cb) } /> | |||||
| renderRenameLink={ (it, cb) => this.renderRenameLink(it, cb) } | |||||
| renderDeleteButton={ (it, cb) => this.renderDeleteButton(it, cb) } /> | |||||
| ) : (objTypeTab === 'workflow' ? ( | ) : (objTypeTab === 'workflow' ? ( | ||||
| <WBWorkflowListing app={ app } | <WBWorkflowListing app={ app } | ||||
| @@ -97,7 +113,8 @@ class WBBrowse extends Component { | |||||
| itemsPerPage="20" | itemsPerPage="20" | ||||
| page={ Number(workflowPage || 0) } | page={ Number(workflowPage || 0) } | ||||
| getPageUrl={ i => this.getUrl({ 'workflowPage': i }) } | getPageUrl={ i => this.getUrl({ 'workflowPage': i }) } | ||||
| renderRenameLink={ (it, cb) => this.renderRenameLink(it, cb) } /> | |||||
| renderRenameLink={ (it, cb) => this.renderRenameLink(it, cb) } | |||||
| renderDeleteButton={ (it, cb) => this.renderDeleteButton(it, cb) } /> | |||||
| ) : null)) | ) : null)) | ||||
| } | } | ||||
| @@ -34,10 +34,13 @@ class WBDialog extends Component { | |||||
| </div> | </div> | ||||
| <div class="modal-footer"> | <div class="modal-footer"> | ||||
| <input type="submit" class="btn btn-primary" value="Accept" | |||||
| onclick={ e => { e.preventDefault(); this.hide(); accept(); } } /> | |||||
| <button type="button" class="btn btn-secondary" | |||||
| onclick={ () => { this.hide(); reject(); } }>Cancel</button> | |||||
| { children[1] ? children[1] : [ | |||||
| <input type="submit" class="btn btn-primary" value="Accept" | |||||
| onclick={ e => { e.preventDefault(); this.hide(); accept(); } } />, | |||||
| <button type="button" class="btn btn-secondary" | |||||
| onclick={ () => { this.hide(); reject(); } }>Cancel</button> | |||||
| ] } | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||