From 3f2c748f834b090588545112abf9cb22b2929463 Mon Sep 17 00:00:00 2001 From: Milan Patel Date: Fri, 10 Nov 2023 23:28:43 +0530 Subject: [PATCH 1/4] feat: Execute script for selected rows --- src/dashboard/Data/Browser/Browser.react.js | 60 ++++++++++++++ .../Data/Browser/BrowserToolbar.react.js | 8 ++ .../Browser/ExecuteScriptRowsDialog.react.js | 78 +++++++++++++++++++ 3 files changed, 146 insertions(+) create mode 100644 src/dashboard/Data/Browser/ExecuteScriptRowsDialog.react.js diff --git a/src/dashboard/Data/Browser/Browser.react.js b/src/dashboard/Data/Browser/Browser.react.js index ec4897117c..fbf6a31df5 100644 --- a/src/dashboard/Data/Browser/Browser.react.js +++ b/src/dashboard/Data/Browser/Browser.react.js @@ -18,6 +18,7 @@ import EmptyState from 'components/EmptyState/EmptyState.react'; import ExportDialog from 'dashboard/Data/Browser/ExportDialog.react'; import AttachRowsDialog from 'dashboard/Data/Browser/AttachRowsDialog.react'; import AttachSelectedRowsDialog from 'dashboard/Data/Browser/AttachSelectedRowsDialog.react'; +import ExecuteScriptRowsDialog from 'dashboard/Data/Browser/ExecuteScriptRowsDialog.react'; import CloneSelectedRowsDialog from 'dashboard/Data/Browser/CloneSelectedRowsDialog.react'; import EditRowDialog from 'dashboard/Data/Browser/EditRowDialog.react'; import ExportSelectedRowsDialog from 'dashboard/Data/Browser/ExportSelectedRowsDialog.react'; @@ -95,6 +96,8 @@ class Browser extends DashboardView { useMasterKey: true, currentUser: Parse.User.current(), + + processedScripts: 0, }; this.prefetchData = this.prefetchData.bind(this); @@ -114,6 +117,9 @@ class Browser extends DashboardView { this.cancelAttachRows = this.cancelAttachRows.bind(this); this.confirmAttachRows = this.confirmAttachRows.bind(this); this.showAttachSelectedRowsDialog = this.showAttachSelectedRowsDialog.bind(this); + this.showExecuteScriptRowsDialog = this.showExecuteScriptRowsDialog.bind(this); + this.confirmExecuteScriptRows = this.confirmExecuteScriptRows.bind(this); + this.cancelExecuteScriptRowsDialog = this.cancelExecuteScriptRowsDialog.bind(this); this.confirmAttachSelectedRows = this.confirmAttachSelectedRows.bind(this); this.cancelAttachSelectedRows = this.cancelAttachSelectedRows.bind(this); this.showCloneSelectedRowsDialog = this.showCloneSelectedRowsDialog.bind(this); @@ -1326,6 +1332,18 @@ class Browser extends DashboardView { }); } + showExecuteScriptRowsDialog() { + this.setState({ + showExecuteScriptRowsDialog: true, + }); + } + + cancelExecuteScriptRowsDialog() { + this.setState({ + showExecuteScriptRowsDialog: false, + }); + } + async confirmAttachSelectedRows( className, targetObjectId, @@ -1346,6 +1364,37 @@ class Browser extends DashboardView { }); } + async confirmExecuteScriptRows(script) { + try { + const objects = []; + Object.keys(this.state.selection).forEach(key => + objects.push(Parse.Object.extend(this.props.params.className).createWithoutData(key)) + ); + for (const object of objects) { + const response = await Parse.Cloud.run( + script.cloudCodeFunction, + { object: object.toPointer() }, + { useMasterKey: true } + ); + this.setState(prevState => ({ + processedScripts: prevState.processedScripts + 1, + })); + this.showNote( + response || + `Ran script "${script.title}" on "${this.props.className}" object "${object.id}".` + ); + } + this.refresh(); + } catch (e) { + this.showNote(e.message, true); + console.log(`Could not run ${script.title}: ${e}`); + } finally{ + this.setState(({ + processedScripts: 0, + })); + } + } + showCloneSelectedRowsDialog() { this.setState({ showCloneSelectedRowsDialog: true, @@ -1790,6 +1839,7 @@ class Browser extends DashboardView { onRefresh={this.refresh} onAttachRows={this.showAttachRowsDialog} onAttachSelectedRows={this.showAttachSelectedRowsDialog} + onExecuteScriptRows={this.showExecuteScriptRowsDialog} onCloneSelectedRows={this.showCloneSelectedRowsDialog} onEditSelectedRow={this.showEditRowDialog} onEditPermissions={this.onDialogToggle} @@ -1943,6 +1993,16 @@ class Browser extends DashboardView { onConfirm={this.confirmAttachSelectedRows} /> ); + } else if (this.state.showExecuteScriptRowsDialog) { + extras = ( + + ); } else if (this.state.showCloneSelectedRowsDialog) { extras = ( onDeleteRows(selection)} /> + + onExecuteScriptRows(selection)} + /> + {enableColumnManipulation ? ( ) : ( diff --git a/src/dashboard/Data/Browser/ExecuteScriptRowsDialog.react.js b/src/dashboard/Data/Browser/ExecuteScriptRowsDialog.react.js new file mode 100644 index 0000000000..2abdbff1c5 --- /dev/null +++ b/src/dashboard/Data/Browser/ExecuteScriptRowsDialog.react.js @@ -0,0 +1,78 @@ +import React from 'react'; +import FormModal from 'components/FormModal/FormModal.react'; +import Field from 'components/Field/Field.react'; +import Label from 'components/Label/Label.react'; +import Dropdown from 'components/Dropdown/Dropdown.react'; +import Option from 'components/Dropdown/Option.react'; +import { CurrentApp } from 'context/currentApp'; + +export default class ExecuteScriptRowsDialog extends React.Component { + static contextType = CurrentApp; + constructor(props) { + super(props); + + this.state = { + currentScript: null, + validScripts: [], + }; + + this.handleConfirm = this.handleConfirm.bind(this); + this.handleScriptChange = this.handleScriptChange.bind(this); + } + + componentWillMount() { + const { selection, currentClass } = this.props; + + const validScripts = (this.context.scripts || []).filter(script => + script.classes?.includes(currentClass) + ); + + if (selection && validScripts.length > 0) { + this.setState({ + currentScript: validScripts[0], + validScripts: validScripts, + }); + } + } + + handleConfirm() { + return this.props.onConfirm(this.state.currentScript); + } + + handleScriptChange(scriptName) { + this.setState({ + currentScript: validScripts.find(script => script.name === scriptName), + }); + } + + render() { + const { validScripts } = this.state; + const { selection, processedScripts } = this.props; + + return ( + + } + input={ + + {validScripts.map(script => ( + + ))} + + } + /> + + ); + } +} From 95f8c97159008486f30545d6cc33796405d4d1e0 Mon Sep 17 00:00:00 2001 From: Milan Patel Date: Sat, 11 Nov 2023 11:51:44 +0530 Subject: [PATCH 2/4] fix: validscript scope error --- src/dashboard/Data/Browser/ExecuteScriptRowsDialog.react.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dashboard/Data/Browser/ExecuteScriptRowsDialog.react.js b/src/dashboard/Data/Browser/ExecuteScriptRowsDialog.react.js index 2abdbff1c5..c78241b252 100644 --- a/src/dashboard/Data/Browser/ExecuteScriptRowsDialog.react.js +++ b/src/dashboard/Data/Browser/ExecuteScriptRowsDialog.react.js @@ -41,7 +41,7 @@ export default class ExecuteScriptRowsDialog extends React.Component { handleScriptChange(scriptName) { this.setState({ - currentScript: validScripts.find(script => script.name === scriptName), + currentScript: this.state.validScripts.find(script => script.title === scriptName), }); } From e5dab9fda35e859c82b2b4f66deb2aca192e5917 Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Sat, 16 Dec 2023 20:06:54 +0100 Subject: [PATCH 3/4] move to new menu item --- .../Data/Browser/BrowserToolbar.react.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/dashboard/Data/Browser/BrowserToolbar.react.js b/src/dashboard/Data/Browser/BrowserToolbar.react.js index 5e51bdd86e..5155b94486 100644 --- a/src/dashboard/Data/Browser/BrowserToolbar.react.js +++ b/src/dashboard/Data/Browser/BrowserToolbar.react.js @@ -163,12 +163,6 @@ const BrowserToolbar = ({ onClick={() => onDeleteRows(selection)} /> - onExecuteScriptRows(selection)} - /> - {enableColumnManipulation ? ( ) : ( @@ -386,6 +380,18 @@ const BrowserToolbar = ({