From e5bc77ee477d9cd5e261b16d2fb59c349bcd54b0 Mon Sep 17 00:00:00 2001 From: olivier Dufour Date: Wed, 18 Oct 2023 20:00:18 +0200 Subject: [PATCH] Automatically request SObject type when data export from an SObject record (#45) --- CHANGES.md | 1 + addon/data-import.js | 3 ++ addon/inspect.js | 4 +-- addon/popup.js | 68 +++++++++++++++++++++++++++++++++----------- 4 files changed, 58 insertions(+), 18 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 9511cad7a..8ebb9bbb4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -25,6 +25,7 @@ - Detect SObject on listview page [feature 121](https://github.com/tprouvot/Salesforce-Inspector-reloaded/issues/121) (idea by [Mehdi Cherfaoui](https://github.com/mehdisfdc)) - Automate test setup manual step of contact to multiple accounts [Aidan Majewski](https://github.com/aimaj) - In Data export, set input focus in SQOL query text area. [feature 183](https://github.com/tprouvot/Salesforce-Inspector-reloaded/issues/183) (contribution by [Sarath Addanki](https://github.com/asknet)) +- Automatically request SObject type when data export from an SObject record [feature 45](https://github.com/tprouvot/Salesforce-Inspector-reloaded/issues/45) ## Version 1.19 diff --git a/addon/data-import.js b/addon/data-import.js index 92b28c08f..31f800307 100644 --- a/addon/data-import.js +++ b/addon/data-import.js @@ -35,6 +35,9 @@ class Model { Succeeded: true, Failed: true }; + if (args.has("sobject")) { + this.importType = args.get("sobject"); + } if (localStorage.getItem(sfHost + "_isSandbox") != "true") { //change background color for production document.body.classList.add("prod"); diff --git a/addon/inspect.js b/addon/inspect.js index 72d184904..75725cea1 100644 --- a/addon/inspect.js +++ b/addon/inspect.js @@ -236,9 +236,9 @@ class Model { if (!objectName) { return undefined; } - let query = "select Id from " + objectName; + let query = "SELECT Id FROM " + objectName; if (this.recordData && this.recordData.Id) { - query += " where Id = '" + this.recordData.Id + "'"; + query += " WHERE Id = '" + this.recordData.Id + "'"; } return this.dataExportUrl(query); } diff --git a/addon/popup.js b/addon/popup.js index 372b6a2af..5e5a698ef 100644 --- a/addon/popup.js +++ b/addon/popup.js @@ -49,14 +49,43 @@ function initLinks({sfHost}){ class App extends React.PureComponent { constructor(props) { super(props); + let {sfHost} = this.props; + let hostArg = new URLSearchParams(); + hostArg.set("host", sfHost); this.state = { isInSetup: false, contextUrl: null, - apiVersionInput: apiVersion + apiVersionInput: apiVersion, + exportHref: "data-export.html?" + hostArg, + importHref: "data-import.html?" + hostArg, + limitsHref: "limits.html?" + hostArg }; this.onContextUrlMessage = this.onContextUrlMessage.bind(this); this.onShortcutKey = this.onShortcutKey.bind(this); this.onChangeApi = this.onChangeApi.bind(this); + this.onContextRecordChange = this.onContextRecordChange.bind(this); + } + onContextRecordChange(e) { + let {sfHost} = this.props; + let limitsArg = new URLSearchParams(); + let exportArg = new URLSearchParams(); + let importArg = new URLSearchParams(); + exportArg.set("host", sfHost); + importArg.set("host", sfHost); + limitsArg.set("host", sfHost); + if (e.contextSobject) { + let query = "SELECT Id FROM " + e.contextSobject; + if (e.contextRecordId && (e.contextRecordId.length == 15 || e.contextRecordId.length == 18)) { + query += " WHERE Id = '" + e.contextRecordId + "'"; + } + exportArg.set("query", query); + importArg.set('sobject', e.contextSobject) + } + this.setState({ + exportHref: "data-export.html?" + exportArg, + importHref: "data-import.html?" + importArg, + limitsHref: "limits.html?" + limitsArg + }) } onContextUrlMessage(e) { if (e.source == parent && e.data.insextUpdateRecordId) { @@ -66,6 +95,7 @@ class App extends React.PureComponent { contextUrl: locationHref }); } + } onShortcutKey(e) { @@ -151,7 +181,7 @@ class App extends React.PureComponent { inInspector, addonVersion } = this.props; - let {isInSetup, contextUrl, apiVersionInput} = this.state; + let {isInSetup, contextUrl, apiVersionInput, exportHref, importHref, limitsHref} = this.state; let clientId = localStorage.getItem(sfHost + "_clientId"); let orgInstance = this.getOrgInstance(sfHost); let hostArg = new URLSearchParams(); @@ -179,16 +209,16 @@ class App extends React.PureComponent { ) ), h("div", {className: "main"}, - h(AllDataBox, {ref: "showAllDataBox", sfHost, showDetailsSupported: !inLightning && !inInspector, linkTarget, contextUrl}), + h(AllDataBox, {ref: "showAllDataBox", sfHost, showDetailsSupported: !inLightning && !inInspector, linkTarget, contextUrl, onContextRecordChange: this.onContextRecordChange}), h("div", {className: "slds-p-vertical_x-small slds-p-horizontal_x-small slds-border_bottom"}, h("div", {className: "slds-m-bottom_xx-small"}, - h("a", {ref: "dataExportBtn", href: "data-export.html?" + hostArg, target: linkTarget, className: "page-button slds-button slds-button_neutral"}, h("span", {}, "Data ", h("u", {}, "E"), "xport")) + h("a", {ref: "dataExportBtn", href: exportHref, target: linkTarget, className: "page-button slds-button slds-button_neutral"}, h("span", {}, "Data ", h("u", {}, "E"), "xport")) ), h("div", {className: "slds-m-bottom_xx-small"}, - h("a", {ref: "dataImportBtn", href: "data-import.html?" + hostArg, target: linkTarget, className: "page-button slds-button slds-button_neutral"}, h("span", {}, "Data ", h("u", {}, "I"), "mport")) + h("a", {ref: "dataImportBtn", href: importHref, target: linkTarget, className: "page-button slds-button slds-button_neutral"}, h("span", {}, "Data ", h("u", {}, "I"), "mport")) ), h("div", {}, - h("a", {ref: "limitsBtn", href: "limits.html?" + hostArg, target: linkTarget, className: "page-button slds-button slds-button_neutral"}, h("span", {}, "Org ", h("u", {}, "L"), "imits")) + h("a", {ref: "limitsBtn", href: limitsHref, target: linkTarget, className: "page-button slds-button slds-button_neutral"}, h("span", {}, "Org ", h("u", {}, "L"), "imits")) ), ), h("div", {className: "slds-p-vertical_x-small slds-p-horizontal_x-small"}, @@ -268,7 +298,6 @@ class AllDataBox extends React.PureComponent { constructor(props) { super(props); this.SearchAspectTypes = Object.freeze({sobject: "sobject", users: "users", shortcuts: "shortcuts"}); //Enum. Supported aspects - this.state = { activeSearchAspect: this.SearchAspectTypes.sobject, sobjectsList: null, @@ -310,16 +339,18 @@ class AllDataBox extends React.PureComponent { } ensureKnownBrowserContext() { - let {contextUrl} = this.props; + let {contextUrl, onContextRecordChange} = this.props; if (contextUrl) { let recordId = getRecordId(contextUrl); let path = getSfPathFromUrl(contextUrl); let sobject = getSobject(contextUrl); - this.setState({ + let context = { contextRecordId: recordId, contextPath: path, contextSobject: sobject - }); + }; + this.setState(context); + onContextRecordChange(context); } } @@ -453,7 +484,7 @@ class AllDataBox extends React.PureComponent { render() { let {activeSearchAspect, sobjectsLoading, contextRecordId, contextSobject, contextUserId, contextOrgId, contextPath, sobjectsList} = this.state; - let {sfHost, showDetailsSupported, linkTarget} = this.props; + let {sfHost, showDetailsSupported, linkTarget, onContextRecordChange} = this.props; return ( h("div", {className: "slds-p-top_small slds-p-horizontal_x-small slds-p-bottom_x-small slds-border_bottom" + (this.isLoading() ? " loading " : "")}, @@ -464,7 +495,7 @@ class AllDataBox extends React.PureComponent { ), (activeSearchAspect == this.SearchAspectTypes.sobject) - ? h(AllDataBoxSObject, {ref: "showAllDataBoxSObject", sfHost, showDetailsSupported, sobjectsList, sobjectsLoading, contextRecordId, contextSobject, linkTarget}) + ? h(AllDataBoxSObject, {ref: "showAllDataBoxSObject", sfHost, showDetailsSupported, sobjectsList, sobjectsLoading, contextRecordId, contextSobject, linkTarget, onContextRecordChange}) : (activeSearchAspect == this.SearchAspectTypes.users) ? h(AllDataBoxUsers, {ref: "showAllDataBoxUsers", sfHost, linkTarget, contextUserId, contextOrgId, contextPath, setIsLoading: (value) => { this.setIsLoading("usersBox", value); }}, "Users") : "AllData aspect " + activeSearchAspect + " not implemented" @@ -760,8 +791,12 @@ class AllDataBoxSObject extends React.PureComponent { } onDataSelect(value) { + let {onContextRecordChange} = this.props; this.setState({selectedValue: value}, () => { this.loadRecordIdDetails(); + if (value) { + onContextRecordChange({contextSobject : value.sobject.name, contextRecordId : value.recordId}); + } }); } @@ -1613,10 +1648,11 @@ function getRecordId(href) { function getSobject(href) { let url = new URL(href); - if (url.pathname && url.pathname.endsWith("/list")){ - let sobject = url.pathname.substring(0, url.pathname.lastIndexOf("/list")); - sobject = sobject.substring(sobject.lastIndexOf("/") + 1); - return sobject; + if (url.pathname) { + let match = url.pathname.match(/\/lightning\/[r|o]\/([a-zA-Z0-9_]+)\/[a-zA-Z0-9]+/); + if (match) { + return match[1]; + } } return null; }