Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[data-export] Add query plan to export data #315

Merged
merged 4 commits into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Version 1.23

- Add Query Plan to data export [feature 314](https://github.com/tprouvot/Salesforce-Inspector-reloaded/issues/314)
- Align show-all data 'Type' column with Salesforce's 'Data Type' field [issue 312](https://github.com/tprouvot/Salesforce-Inspector-reloaded/issues/312) by [efcdilascio](https://github.com/efcdilascio)
- Make data export suggestions scrollable [feature 301](https://github.com/tprouvot/Salesforce-Inspector-reloaded/issues/301) by [Vranisimo](https://github.com/vranisimo)
- Show the number of filtered records in data export [feature 300](https://github.com/tprouvot/Salesforce-Inspector-reloaded/issues/300) by [Vranisimo](https://github.com/vranisimo)
Expand Down Expand Up @@ -48,7 +49,6 @@
## Version 1.20.1

- Bugfix Delete Button not enabled when only one record is queried/filtered (contribution by [Oscar Gomez Balaguer](https://github.com/ogomezba))

- Bugfix User selection not displaying information (for orgs without community enabled) [issue 211](https://github.com/tprouvot/Salesforce-Inspector-reloaded/issues/211)

## Version 1.20
Expand Down
2 changes: 1 addition & 1 deletion addon/data-export-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ export async function dataExportTest(test) {
// Autocomplete object
setQuery("select Id from OpportunityLi", "", "");
assertEquals("Objects suggestions:", vm.autocompleteResults.title);
assertEquals(["OpportunityLineItem"], getValues(vm.autocompleteResults.results));
assertEquals(["OpportunityLineItem", "OpportunityLineItemChangeEvent"], getValues(vm.autocompleteResults.results));

// Autocomplete unknown object
setQuery("select Id from UnknownObj", "", "");
Expand Down
61 changes: 47 additions & 14 deletions addon/data-export.js
Original file line number Diff line number Diff line change
Expand Up @@ -360,19 +360,23 @@ class Model {
vm.autocompleteProgress.abort();
}

vm.autocompleteClick = ({value, suffix}) => {
vm.queryInput.focus();
//handle when selected field is the last one before "FROM" keyword, or if an existing comma is present after selection
let indexFrom = query.toLowerCase().indexOf("from");
if (suffix.trim() == "," && (query.substring(selEnd + 1, indexFrom).trim().length == 0 || query.substring(selEnd).trim().startsWith(",") || query.substring(selEnd).trim().toLowerCase().startsWith("from"))) {
suffix = "";
}
vm.queryInput.setRangeText(value + suffix, selStart, selEnd, "end");
//add query suffix if needed
if (value.startsWith("FIELDS") && !query.toLowerCase().includes("limit")) {
vm.queryInput.value += " LIMIT 200";
vm.autocompleteClick = ({value, suffix, link}) => {
if (link){
window.open(link, "_blank");
} else {
vm.queryInput.focus();
//handle when selected field is the last one before "FROM" keyword, or if an existing comma is present after selection
let indexFrom = query.toLowerCase().indexOf("from");
if (suffix.trim() == "," && (query.substring(selEnd + 1, indexFrom).trim().length == 0 || query.substring(selEnd).trim().startsWith(",") || query.substring(selEnd).trim().toLowerCase().startsWith("from"))) {
suffix = "";
}
vm.queryInput.setRangeText(value + suffix, selStart, selEnd, "end");
//add query suffix if needed
if (value.startsWith("FIELDS") && !query.toLowerCase().includes("limit")) {
vm.queryInput.value += " LIMIT 200";
}
vm.queryAutocompleteHandler();
}
vm.queryAutocompleteHandler();
};

// Find the token we want to autocomplete. This is the selected text, or the last word before the cursor.
Expand Down Expand Up @@ -905,6 +909,28 @@ class Model {
stopExport() {
this.exportProgress.abort();
}
doQueryPlan(){
let vm = this; // eslint-disable-line consistent-this
let exportedData = new RecordTable(vm);

vm.spinFor(sfConn.rest("/services/data/v" + apiVersion + "/query/?explain=" + encodeURIComponent(vm.queryInput.value)).then(res => {
exportedData.addToTable(res.plans);
vm.exportStatus = "";
vm.performancePoints = [];
vm.exportedData = exportedData;
vm.updatedExportedData();
vm.didUpdate();
}, () => {
vm.isWorking = false;
}));
vm.autocompleteResults = {
sobjectName: "",
title: "Query Plan Tool:",
results: [{value: "Developer Console Query Plan Tool FAQ", title: "Developer Console Query Plan Tool FAQ", rank: 1, autocompleteType: "fieldName", dataType: "", link: "https://help.salesforce.com/s/articleView?id=000386864&type=1"},
{value: "Get Feedback on Query Performance", title: "Get Feedback on Query Performance", suffix: " ", rank: 1, autocompleteType: "fieldName", dataType: "", link: "https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_query_explain.htm"},
]
};
}
}

function RecordTable(vm) {
Expand Down Expand Up @@ -1017,6 +1043,7 @@ class App extends React.Component {
this.onToggleSavedOptions = this.onToggleSavedOptions.bind(this);
this.onExport = this.onExport.bind(this);
this.onCopyQuery = this.onCopyQuery.bind(this);
this.onQueryPlan = this.onQueryPlan.bind(this);
this.onCopyAsExcel = this.onCopyAsExcel.bind(this);
this.onCopyAsCsv = this.onCopyAsCsv.bind(this);
this.onCopyAsJson = this.onCopyAsJson.bind(this);
Expand Down Expand Up @@ -1129,6 +1156,11 @@ class App extends React.Component {
navigator.clipboard.writeText(url.toString());
model.didUpdate();
}
onQueryPlan(){
let {model} = this.props;
model.doQueryPlan();
model.didUpdate();
}
onCopyAsExcel() {
let {model} = this.props;
model.copyAsExcel();
Expand Down Expand Up @@ -1313,8 +1345,9 @@ class App extends React.Component {
h("div", {className: "flex-right"},
h("button", {tabIndex: 1, disabled: model.isWorking, onClick: this.onExport, title: "Ctrl+Enter / F5", className: "highlighted"}, "Run Export"),
h("button", {tabIndex: 2, onClick: this.onCopyQuery, title: "Copy query url", className: "copy-id"}, "Export Query"),
h("a", {tabIndex: 3, className: "button", hidden: !model.autocompleteResults.sobjectName, href: model.showDescribeUrl(), target: "_blank", title: "Show field info for the " + model.autocompleteResults.sobjectName + " object"}, model.autocompleteResults.sobjectName + " Field Info"),
h("button", {tabIndex: 4, href: "#", className: model.expandAutocomplete ? "toggle contract" : "toggle expand", onClick: this.onToggleExpand, title: "Show all suggestions or only the first line"},
h("button", {tabIndex: 3, onClick: this.onQueryPlan, title: "Run Query Plan"}, "Query Plan"),
h("a", {tabIndex: 4, className: "button", hidden: !model.autocompleteResults.sobjectName, href: model.showDescribeUrl(), target: "_blank", title: "Show field info for the " + model.autocompleteResults.sobjectName + " object"}, model.autocompleteResults.sobjectName + " Field Info"),
h("button", {tabIndex: 5, href: "#", className: model.expandAutocomplete ? "toggle contract" : "toggle expand", onClick: this.onToggleExpand, title: "Show all suggestions or only the first line"},
h("div", {className: "button-icon"}),
h("div", {className: "button-toggle-icon"})
)
Expand Down
Loading