From 220ad9dd27068a1ec235e7387783621141c497fd Mon Sep 17 00:00:00 2001 From: Stanislaw Adaszewski Date: Wed, 12 Feb 2020 18:58:39 +0100 Subject: [PATCH] Added renaming functionality. --- .../src/js/component/wb-collection-listing.js | 8 ++- .../src/js/component/wb-process-listing.js | 5 +- .../src/js/component/wb-project-listing.js | 11 ++-- .../src/js/component/wb-workflow-listing.js | 13 ++++- frontend/src/js/dialog/wb-rename-dialog.js | 45 +++++++++++++++ frontend/src/js/misc/wb-rename-object.js | 16 ++++++ frontend/src/js/page/wb-browse.js | 35 ++++++++++-- frontend/src/js/widget/wb-dialog.js | 56 +++++++++++++++++++ 8 files changed, 175 insertions(+), 14 deletions(-) create mode 100644 frontend/src/js/dialog/wb-rename-dialog.js create mode 100644 frontend/src/js/misc/wb-rename-object.js create mode 100644 frontend/src/js/widget/wb-dialog.js diff --git a/frontend/src/js/component/wb-collection-listing.js b/frontend/src/js/component/wb-collection-listing.js index 9523399..9e84eaf 100644 --- a/frontend/src/js/component/wb-collection-listing.js +++ b/frontend/src/js/component/wb-collection-listing.js @@ -21,12 +21,14 @@ class WBCollectionListing extends Component { } prepareRows(items, ownerLookup) { - let { app } = this.props; - + let { app, renderRenameLink } = this.props; + return items.map(item => [ (
- { item['name'] } + + { item['name'] } + { renderRenameLink(item, () => this.fetchItems()) }
{ item['uuid'] }
), diff --git a/frontend/src/js/component/wb-process-listing.js b/frontend/src/js/component/wb-process-listing.js index 2d1021c..2c2bb27 100644 --- a/frontend/src/js/component/wb-process-listing.js +++ b/frontend/src/js/component/wb-process-listing.js @@ -22,11 +22,14 @@ class WBProcessListing extends Component { } prepareRows(items) { + const { renderRenameLink } = this.props; return items.map(item => [ (
{ e.preventDefault(); route('/process/' + item['uuid']) }}>{ item['name'] } + onclick={ e => { e.preventDefault(); route('/process/' + item['uuid']) }}> + { item['name'] } + { renderRenameLink(item, () => this.fetchItems()) }
{ item['uuid'] }
), diff --git a/frontend/src/js/component/wb-project-listing.js b/frontend/src/js/component/wb-project-listing.js index 9d37885..8a40e53 100644 --- a/frontend/src/js/component/wb-project-listing.js +++ b/frontend/src/js/component/wb-project-listing.js @@ -17,13 +17,15 @@ class WBProjectListing extends Component { } prepareRows(items) { - let { app } = this.props; - + let { app, renderRenameLink } = this.props; + return items.map(item => [ (
{ e.preventDefault(); route('/browse/' + item['uuid']) }}>{ item['name'] } + onclick={ e => { e.preventDefault(); route('/browse/' + item['uuid']) }}> + { item['name'] } + { renderRenameLink(item, () => this.fetchItems()) }
{ item['uuid'] }
), @@ -78,7 +80,8 @@ class WBProjectListing extends Component { WBProjectListing.defaultProps = { 'itemsPerPage': 100, - 'ownerUuid': null + 'ownerUuid': null, + 'renderRenameLink': () => null }; export default WBProjectListing; diff --git a/frontend/src/js/component/wb-workflow-listing.js b/frontend/src/js/component/wb-workflow-listing.js index f7bb05b..95cd285 100644 --- a/frontend/src/js/component/wb-workflow-listing.js +++ b/frontend/src/js/component/wb-workflow-listing.js @@ -6,6 +6,7 @@ import WBNameAndUuid from 'wb-name-and-uuid'; import wbFetchObjects from 'wb-fetch-objects'; import wbFormatDate from 'wb-format-date'; import urlForObject from 'url-for-object'; +import arvadosObjectName from 'arvados-object-name'; class WBWorkflowListing extends Component { @@ -20,8 +21,18 @@ class WBWorkflowListing extends Component { } prepareRows(items, ownerLookup) { + const { renderRenameLink } = this.props; return items.map(item => [ - ( ), + ( +
+
+ + { arvadosObjectName(item) } + { renderRenameLink(item, () => this.fetchItems()) } +
+
{ item.uuid }
+
+ ), item.description, ( ), wbFormatDate(item.created_at), diff --git a/frontend/src/js/dialog/wb-rename-dialog.js b/frontend/src/js/dialog/wb-rename-dialog.js new file mode 100644 index 0000000..af31897 --- /dev/null +++ b/frontend/src/js/dialog/wb-rename-dialog.js @@ -0,0 +1,45 @@ +import { h, Component, createRef } from 'preact'; +import WBDialog from 'wb-dialog'; +import linkState from 'linkstate'; +import wbRenameObject from 'wb-rename-object'; + +class WBRenameDialog extends Component { + constructor(...args) { + super(...args); + this.dialogRef = createRef(); + this.state.inputId = uuid.v4(); + } + + show(item, callback) { + const { inputId } = this.state; + this.setState({ + 'item': item, + 'newName': null, + 'callback': callback || (() => {}) + }); + this.dialogRef.current.show(); + $('#' + inputId).focus(); + } + + hide() { + this.dialogRef.current.hide(); + } + + render({ app }, { item, newName, callback, inputId }) { + const { arvHost, arvToken } = app.state; + return ( + { + if (newName) + wbRenameObject(arvHost, arvToken, item.uuid, newName).then(callback); + } }> +
+ +
+
+ ); + } +} + +export default WBRenameDialog; diff --git a/frontend/src/js/misc/wb-rename-object.js b/frontend/src/js/misc/wb-rename-object.js new file mode 100644 index 0000000..bbd5a8a --- /dev/null +++ b/frontend/src/js/misc/wb-rename-object.js @@ -0,0 +1,16 @@ +import makeArvadosRequest from 'make-arvados-request'; +import arvadosTypeName from 'arvados-type-name'; + +function wbRenameObject(arvHost, arvToken, uuid, newName) { + const update = { + 'name': newName + }; + const typeName = arvadosTypeName(uuid); + return makeArvadosRequest(arvHost, arvToken, + '/arvados/v1/' + typeName + 's/' + + uuid + '?' + typeName + '=' + + encodeURIComponent(JSON.stringify(update)), + { 'method': 'PUT' }); +} + +export default wbRenameObject; diff --git a/frontend/src/js/page/wb-browse.js b/frontend/src/js/page/wb-browse.js index c61bc83..7b170b1 100644 --- a/frontend/src/js/page/wb-browse.js +++ b/frontend/src/js/page/wb-browse.js @@ -1,4 +1,4 @@ -import { h, Component } from 'preact'; +import { h, Component, createRef } from 'preact'; import { route } from 'preact-router'; import WBNavbarCommon from 'wb-navbar-common'; import WBProjectListing from 'wb-project-listing'; @@ -8,8 +8,14 @@ import WBTabs from 'wb-tabs'; import WBProcessListing from 'wb-process-listing'; import WBCollectionListing from 'wb-collection-listing'; import WBWorkflowListing from 'wb-workflow-listing'; +import WBRenameDialog from 'wb-rename-dialog'; class WBBrowse extends Component { + constructor(...args) { + super(...args); + this.renameDialogRef = createRef(); + } + getUrl(params) { let res = '/browse/' + ('ownerUuid' in params ? params.ownerUuid : (this.props.ownerUuid || '')) + '/' + @@ -26,11 +32,26 @@ class WBBrowse extends Component { route(this.getUrl(params)); } + renameDialog(item, callback) { + // throw Error('Not implemented'); + this.renameDialogRef.current.show(item, callback); + } + + renderRenameLink(item, callback) { + return ( + { e.preventDefault(); this.renameDialog(item, callback); } }> + + + ); + } + render({ ownerUuid, activePage, appState, app, objTypeTab, collectionPage, processPage, workflowPage }) { return (
+ + @@ -44,7 +65,8 @@ class WBBrowse extends Component { ownerUuid={ ownerUuid } itemsPerPage="5" activePage={ Number(activePage || 0) } - onPageChanged={ i => route('/browse/' + (ownerUuid || '') + '/' + i)} /> + onPageChanged={ i => route('/browse/' + (ownerUuid || '') + '/' + i) } + renderRenameLink={ (it, cb) => this.renderRenameLink(it, cb) } /> this.getUrl({ 'collectionPage': i }) } /> + getPageUrl={ i => this.getUrl({ 'collectionPage': i }) } + renderRenameLink={ (it, cb) => this.renderRenameLink(it, cb) } /> ) : (objTypeTab === 'process' ? ( this.route({ 'processPage': i }) } /> + onPageChanged={ i => this.route({ 'processPage': i }) } + renderRenameLink={ (it, cb) => this.renderRenameLink(it, cb) } /> ) : (objTypeTab === 'workflow' ? ( this.getUrl({ 'workflowPage': i }) } /> + getPageUrl={ i => this.getUrl({ 'workflowPage': i }) } + renderRenameLink={ (it, cb) => this.renderRenameLink(it, cb) } /> ) : null)) } diff --git a/frontend/src/js/widget/wb-dialog.js b/frontend/src/js/widget/wb-dialog.js new file mode 100644 index 0000000..570a625 --- /dev/null +++ b/frontend/src/js/widget/wb-dialog.js @@ -0,0 +1,56 @@ +import { h, Component } from 'preact'; + +class WBDialog extends Component { + constructor(...args) { + super(...args); + this.state.id = uuid.v4(); + } + + show() { + const { id } = this.state; + $('#' + id).modal(); + } + + hide() { + const { id } = this.state; + $('#' + id).modal('hide'); + } + + render({ title, children, accept, reject }, { id }) { + return ( +
+ +
+ ); + } +} + +WBDialog.defaultProps = { + 'title': 'Dialog', + 'accept': () => {}, + 'reject': () => {} +}; + +export default WBDialog;