pptb-standard-sample-tool 1.5.2 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/app.js +179 -1
- package/dist/index.html +41 -0
- package/npm-shrinkwrap.json +11 -11
- package/package.json +7 -5
package/README.md
CHANGED
|
@@ -120,7 +120,7 @@ html-sample/
|
|
|
120
120
|
- FetchXML query to retrieve top 10 accounts
|
|
121
121
|
- Display results with formatting
|
|
122
122
|
- If a FetchXML is saved in Tool Settings, the Query button will use that instead of the default
|
|
123
|
-
- This sample supports
|
|
123
|
+
- This sample supports up to three connections: use the Primary, Secondary, and Third query buttons to test slots 0, 1, and 2
|
|
124
124
|
|
|
125
125
|
**CRUD Operations:**
|
|
126
126
|
|
package/dist/app.js
CHANGED
|
@@ -19,6 +19,7 @@ const powerplatform = window.powerplatformAPI;
|
|
|
19
19
|
// Application state
|
|
20
20
|
let currentConnection = null;
|
|
21
21
|
let secondaryConnection = null;
|
|
22
|
+
let thirdConnection = null;
|
|
22
23
|
let currentTerminal = null;
|
|
23
24
|
let createdId = null;
|
|
24
25
|
let currentLaunchContext = null;
|
|
@@ -137,7 +138,8 @@ async function identifyLaunchContext() {
|
|
|
137
138
|
async function refreshConnection() {
|
|
138
139
|
try {
|
|
139
140
|
currentConnection = await toolbox.connections.getActiveConnection();
|
|
140
|
-
secondaryConnection = await toolbox.connections.
|
|
141
|
+
secondaryConnection = await toolbox.connections.getConnection("secondary");
|
|
142
|
+
thirdConnection = await toolbox.connections.getConnection(2);
|
|
141
143
|
const connectionInfo = document.getElementById("connection-info");
|
|
142
144
|
if (!connectionInfo)
|
|
143
145
|
return;
|
|
@@ -207,6 +209,39 @@ async function refreshConnection() {
|
|
|
207
209
|
secondaryInfo.innerHTML = "<p><strong>⚠️ No secondary connection</strong><br>Please connect to a secondary Dataverse environment to use this tool.</p>";
|
|
208
210
|
log("No secondary connection found", "warning");
|
|
209
211
|
}
|
|
212
|
+
const thirdInfo = document.getElementById("third-connection-info");
|
|
213
|
+
if (!thirdInfo)
|
|
214
|
+
return;
|
|
215
|
+
if (thirdConnection) {
|
|
216
|
+
const envClass = thirdConnection.environment.toLowerCase();
|
|
217
|
+
thirdInfo.className = "info-box success";
|
|
218
|
+
thirdInfo.innerHTML = `
|
|
219
|
+
<div class="connection-details">
|
|
220
|
+
<div class="connection-item">
|
|
221
|
+
<strong>Name:</strong>
|
|
222
|
+
<span>${thirdConnection.name}</span>
|
|
223
|
+
</div>
|
|
224
|
+
<div class="connection-item">
|
|
225
|
+
<strong>URL:</strong>
|
|
226
|
+
<span>${thirdConnection.url}</span>
|
|
227
|
+
</div>
|
|
228
|
+
<div class="connection-item">
|
|
229
|
+
<strong>Environment:</strong>
|
|
230
|
+
<span class="env-badge ${envClass}">${thirdConnection.environment}</span>
|
|
231
|
+
</div>
|
|
232
|
+
<div class="connection-item">
|
|
233
|
+
<strong>ID:</strong>
|
|
234
|
+
<span>${thirdConnection.id}</span>
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
`;
|
|
238
|
+
log(`Third connection: ${thirdConnection.name}`, "success");
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
thirdInfo.className = "info-box warning";
|
|
242
|
+
thirdInfo.innerHTML = "<p><strong>⚠️ No third connection</strong><br>Please connect a third Dataverse environment to use this tool.</p>";
|
|
243
|
+
log("No third connection found", "warning");
|
|
244
|
+
}
|
|
210
245
|
}
|
|
211
246
|
catch (error) {
|
|
212
247
|
log(`Error refreshing connection: ${error.message}`, "error");
|
|
@@ -273,6 +308,7 @@ function setupEventHandlers() {
|
|
|
273
308
|
// Dataverse query button
|
|
274
309
|
document.getElementById("query-accounts-btn")?.addEventListener("click", queryAccounts);
|
|
275
310
|
document.getElementById("query-accounts-secondary-btn")?.addEventListener("click", queryAccountsSecondary);
|
|
311
|
+
document.getElementById("query-accounts-third-btn")?.addEventListener("click", queryAccountsThird);
|
|
276
312
|
document.getElementById("query-contacts-querydata-btn")?.addEventListener("click", queryContactQueryData);
|
|
277
313
|
// CRUD buttons
|
|
278
314
|
document.getElementById("create-contact-btn")?.addEventListener("click", createContact);
|
|
@@ -284,6 +320,9 @@ function setupEventHandlers() {
|
|
|
284
320
|
document.getElementById("get-metadata-allentities")?.addEventListener("click", getAllEntities);
|
|
285
321
|
//Execute buttons
|
|
286
322
|
document.getElementById("whoami-btn")?.addEventListener("click", executeWhoAmI);
|
|
323
|
+
document.getElementById("query-with-headers-btn")?.addEventListener("click", queryAccountsWithHeaders);
|
|
324
|
+
document.getElementById("execute-batch-btn")?.addEventListener("click", executeReadBatch);
|
|
325
|
+
document.getElementById("execute-transaction-btn")?.addEventListener("click", executeAtomicTransaction);
|
|
287
326
|
// Power Platform API buttons
|
|
288
327
|
document.getElementById("list-apps-btn")?.addEventListener("click", listPowerApps);
|
|
289
328
|
document.getElementById("list-flows-btn")?.addEventListener("click", listPowerAutomateFlows);
|
|
@@ -642,6 +681,53 @@ async function queryAccountsSecondary() {
|
|
|
642
681
|
log(`Error querying accounts (secondary): ${error.message}`, "error");
|
|
643
682
|
}
|
|
644
683
|
}
|
|
684
|
+
/**
|
|
685
|
+
* Query accounts from Dataverse using the third connection slot (FetchXML)
|
|
686
|
+
*/
|
|
687
|
+
async function queryAccountsThird() {
|
|
688
|
+
if (!thirdConnection) {
|
|
689
|
+
await showNotification("No Third Connection", "Please configure a third Dataverse connection", "warning");
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
const output = document.getElementById("query-output-third");
|
|
693
|
+
try {
|
|
694
|
+
if (output)
|
|
695
|
+
output.textContent = "Querying accounts using third connection...\n";
|
|
696
|
+
const saved = await getSetting("demo.fetchxml");
|
|
697
|
+
const fetchXml = saved && saved.trim().length > 0
|
|
698
|
+
? saved
|
|
699
|
+
: `
|
|
700
|
+
<fetch top="10">
|
|
701
|
+
<entity name="account">
|
|
702
|
+
<attribute name="name" />
|
|
703
|
+
<attribute name="accountid" />
|
|
704
|
+
<attribute name="emailaddress1" />
|
|
705
|
+
<attribute name="telephone1" />
|
|
706
|
+
<order attribute="name" />
|
|
707
|
+
</entity>
|
|
708
|
+
</fetch>
|
|
709
|
+
`.trim();
|
|
710
|
+
const result = await dataverse.fetchXmlQuery(fetchXml, 2);
|
|
711
|
+
if (output) {
|
|
712
|
+
output.textContent = `Found ${result.value.length} account(s) on third connection:\n\n`;
|
|
713
|
+
result.value.forEach((account, index) => {
|
|
714
|
+
output.textContent += `${index + 1}. ${account.name}\n`;
|
|
715
|
+
output.textContent += ` ID: ${account.accountid}\n`;
|
|
716
|
+
if (account.emailaddress1)
|
|
717
|
+
output.textContent += ` Email: ${account.emailaddress1}\n`;
|
|
718
|
+
if (account.telephone1)
|
|
719
|
+
output.textContent += ` Phone: ${account.telephone1}\n`;
|
|
720
|
+
output.textContent += "\n";
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
log(`Queried ${result.value.length} accounts on third connection`, "success");
|
|
724
|
+
}
|
|
725
|
+
catch (error) {
|
|
726
|
+
if (output)
|
|
727
|
+
output.textContent = `Error (third connection): ${error.message}`;
|
|
728
|
+
log(`Error querying accounts (third connection): ${error.message}`, "error");
|
|
729
|
+
}
|
|
730
|
+
}
|
|
645
731
|
/**
|
|
646
732
|
* Create a new account
|
|
647
733
|
*/
|
|
@@ -854,6 +940,98 @@ async function executeWhoAmI() {
|
|
|
854
940
|
log(`Error executing WhoAmI: ${error.message}`, "error");
|
|
855
941
|
}
|
|
856
942
|
}
|
|
943
|
+
function getAdditionalHeaders() {
|
|
944
|
+
const input = document.getElementById("dataverse-headers");
|
|
945
|
+
const parsed = JSON.parse(input?.value || "{}");
|
|
946
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
947
|
+
throw new Error("Additional headers must be a JSON object");
|
|
948
|
+
}
|
|
949
|
+
const headers = {};
|
|
950
|
+
for (const [name, value] of Object.entries(parsed)) {
|
|
951
|
+
if (typeof value !== "string") {
|
|
952
|
+
throw new Error(`Header value for '${name}' must be a string`);
|
|
953
|
+
}
|
|
954
|
+
headers[name] = value;
|
|
955
|
+
}
|
|
956
|
+
return headers;
|
|
957
|
+
}
|
|
958
|
+
async function queryAccountsWithHeaders() {
|
|
959
|
+
if (!currentConnection) {
|
|
960
|
+
await showNotification("No Connection", "Please connect to a Dataverse environment", "warning");
|
|
961
|
+
return;
|
|
962
|
+
}
|
|
963
|
+
const output = document.getElementById("headers-output");
|
|
964
|
+
try {
|
|
965
|
+
const headers = getAdditionalHeaders();
|
|
966
|
+
if (output)
|
|
967
|
+
output.textContent = "Querying accounts with additional headers...\n";
|
|
968
|
+
const result = await dataverse.queryData("accounts?$select=name,accountid&$top=5", "primary", headers);
|
|
969
|
+
if (output) {
|
|
970
|
+
output.textContent = `Found ${result.value.length} account(s):\n\n`;
|
|
971
|
+
output.textContent += JSON.stringify(result.value, null, 2);
|
|
972
|
+
}
|
|
973
|
+
log(`Queried ${result.value.length} accounts with additional headers`, "success");
|
|
974
|
+
}
|
|
975
|
+
catch (error) {
|
|
976
|
+
if (output)
|
|
977
|
+
output.textContent = `Error: ${error.message}`;
|
|
978
|
+
log(`Error querying accounts with headers: ${error.message}`, "error");
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
async function executeReadBatch() {
|
|
982
|
+
if (!currentConnection) {
|
|
983
|
+
await showNotification("No Connection", "Please connect to a Dataverse environment", "warning");
|
|
984
|
+
return;
|
|
985
|
+
}
|
|
986
|
+
const output = document.getElementById("batch-output");
|
|
987
|
+
try {
|
|
988
|
+
const headers = getAdditionalHeaders();
|
|
989
|
+
if (output)
|
|
990
|
+
output.textContent = "Executing read batch...\n";
|
|
991
|
+
const results = await dataverse.executeBatch([
|
|
992
|
+
{ method: "GET", url: "accounts?$select=name,accountid&$top=3" },
|
|
993
|
+
{ method: "GET", url: "contacts?$select=fullname,contactid&$top=3" },
|
|
994
|
+
], "primary", headers);
|
|
995
|
+
if (output)
|
|
996
|
+
output.textContent = `Batch returned ${results.length} result(s):\n\n${JSON.stringify(results, null, 2)}`;
|
|
997
|
+
log(`Read batch completed with ${results.length} result(s)`, "success");
|
|
998
|
+
}
|
|
999
|
+
catch (error) {
|
|
1000
|
+
if (output)
|
|
1001
|
+
output.textContent = `Error: ${error.message}`;
|
|
1002
|
+
log(`Error executing read batch: ${error.message}`, "error");
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
async function executeAtomicTransaction() {
|
|
1006
|
+
if (!currentConnection) {
|
|
1007
|
+
await showNotification("No Connection", "Please connect to a Dataverse environment", "warning");
|
|
1008
|
+
return;
|
|
1009
|
+
}
|
|
1010
|
+
const output = document.getElementById("batch-output");
|
|
1011
|
+
try {
|
|
1012
|
+
const headers = getAdditionalHeaders();
|
|
1013
|
+
const suffix = new Date().toISOString();
|
|
1014
|
+
if (output)
|
|
1015
|
+
output.textContent = `Executing atomic transaction (creating an account and contact - ${`HTML Sample ${suffix}`} )...\n`;
|
|
1016
|
+
const results = await dataverse.executeTransaction([
|
|
1017
|
+
{ method: "POST", url: "accounts", contentId: "account", body: { name: `HTML Sample ${suffix}` } },
|
|
1018
|
+
{
|
|
1019
|
+
method: "POST",
|
|
1020
|
+
url: "contacts",
|
|
1021
|
+
contentId: "contact",
|
|
1022
|
+
body: { firstname: "HTML", lastname: `Sample ${suffix}` },
|
|
1023
|
+
},
|
|
1024
|
+
], "primary", headers);
|
|
1025
|
+
if (output)
|
|
1026
|
+
output.textContent = `Transaction returned ${results.length} result(s):\n\n${JSON.stringify(results, null, 2)}`;
|
|
1027
|
+
log(`Atomic transaction completed with ${results.length} result(s)`, "success");
|
|
1028
|
+
}
|
|
1029
|
+
catch (error) {
|
|
1030
|
+
if (output)
|
|
1031
|
+
output.textContent = `Error: ${error.message}`;
|
|
1032
|
+
log(`Error executing atomic transaction: ${error.message}`, "error");
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
857
1035
|
/**
|
|
858
1036
|
* Apply current theme
|
|
859
1037
|
*/
|
package/dist/index.html
CHANGED
|
@@ -29,6 +29,13 @@
|
|
|
29
29
|
</div>
|
|
30
30
|
</section>
|
|
31
31
|
|
|
32
|
+
<section class="card">
|
|
33
|
+
<h2>🔗 Third Connection Status</h2>
|
|
34
|
+
<div id="third-connection-info" class="info-box">
|
|
35
|
+
<div class="loading">Checking connection...</div>
|
|
36
|
+
</div>
|
|
37
|
+
</section>
|
|
38
|
+
|
|
32
39
|
<!-- ToolBox API Examples -->
|
|
33
40
|
<section class="card">
|
|
34
41
|
<h2>🛠️ ToolBox API Examples</h2>
|
|
@@ -146,10 +153,12 @@
|
|
|
146
153
|
<div class="button-group">
|
|
147
154
|
<button id="query-accounts-btn" class="btn btn-primary">Query Top 10 Accounts (Primary)</button>
|
|
148
155
|
<button id="query-accounts-secondary-btn" class="btn">Query Top 10 Accounts (Secondary)</button>
|
|
156
|
+
<button id="query-accounts-third-btn" class="btn">Query Top 10 Accounts (Third)</button>
|
|
149
157
|
<button id="query-contacts-querydata-btn" class="btn">Query Top 10 Contacts (Primary)</button>
|
|
150
158
|
</div>
|
|
151
159
|
<div id="query-output" class="output"></div>
|
|
152
160
|
<div id="query-output-secondary" class="output"></div>
|
|
161
|
+
<div id="query-output-third" class="output"></div>
|
|
153
162
|
</div>
|
|
154
163
|
|
|
155
164
|
<div class="example-group">
|
|
@@ -183,6 +192,38 @@
|
|
|
183
192
|
<button id="whoami-btn" class="btn">Execute WhoAmI</button>
|
|
184
193
|
<div id="execute-output" class="output"></div>
|
|
185
194
|
</div>
|
|
195
|
+
|
|
196
|
+
<div class="example-group">
|
|
197
|
+
<h3>Additional Headers</h3>
|
|
198
|
+
<p style="margin: 4px 0 10px; font-size: 12px; opacity: 0.85">
|
|
199
|
+
Headers are shown for consent before the request is sent. Use valid Dataverse header names and string values.
|
|
200
|
+
</p>
|
|
201
|
+
<div class="input-group">
|
|
202
|
+
<label for="dataverse-headers">Additional Headers (JSON):</label>
|
|
203
|
+
<textarea
|
|
204
|
+
id="dataverse-headers"
|
|
205
|
+
style="width: 100%; min-height: 90px; padding: 10px; border: 2px solid #e0e0e0; border-radius: 6px; font-family: monospace; font-size: 12px; line-height: 1.4"
|
|
206
|
+
>{
|
|
207
|
+
"Prefer": "odata.include-annotations=\"*\""
|
|
208
|
+
}</textarea>
|
|
209
|
+
</div>
|
|
210
|
+
<div class="button-group">
|
|
211
|
+
<button id="query-with-headers-btn" class="btn btn-primary">Query Accounts with Headers</button>
|
|
212
|
+
</div>
|
|
213
|
+
<div id="headers-output" class="output"></div>
|
|
214
|
+
</div>
|
|
215
|
+
|
|
216
|
+
<div class="example-group">
|
|
217
|
+
<h3>Batch Operations</h3>
|
|
218
|
+
<p style="margin: 4px 0 10px; font-size: 12px; opacity: 0.85">
|
|
219
|
+
Runs independent reads in one <code>$batch</code> request or creates an account and contact in one atomic transaction.
|
|
220
|
+
</p>
|
|
221
|
+
<div class="button-group">
|
|
222
|
+
<button id="execute-batch-btn" class="btn btn-primary">Execute Read Batch</button>
|
|
223
|
+
<button id="execute-transaction-btn" class="btn btn-warning">Execute Atomic Transaction</button>
|
|
224
|
+
</div>
|
|
225
|
+
<div id="batch-output" class="output"></div>
|
|
226
|
+
</div>
|
|
186
227
|
</section>
|
|
187
228
|
|
|
188
229
|
<!-- Power Platform API Examples -->
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pptb-standard-sample-tool",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "pptb-standard-sample-tool",
|
|
9
|
-
"version": "1.
|
|
9
|
+
"version": "1.7.0",
|
|
10
10
|
"license": "GPL-3.0",
|
|
11
11
|
"devDependencies": {
|
|
12
|
-
"@pptb/types": "^1.2.
|
|
12
|
+
"@pptb/types": "^1.2.7-beta.4",
|
|
13
13
|
"shx": "^0.4.0",
|
|
14
14
|
"typescript": "^5.0.0"
|
|
15
15
|
},
|
|
@@ -69,26 +69,26 @@
|
|
|
69
69
|
}
|
|
70
70
|
},
|
|
71
71
|
"node_modules/@pptb/types": {
|
|
72
|
-
"version": "1.2.
|
|
73
|
-
"resolved": "https://registry.npmjs.org/@pptb/types/-/types-1.2.
|
|
74
|
-
"integrity": "sha512-
|
|
72
|
+
"version": "1.2.7-beta.4",
|
|
73
|
+
"resolved": "https://registry.npmjs.org/@pptb/types/-/types-1.2.7-beta.4.tgz",
|
|
74
|
+
"integrity": "sha512-i/bkvXuplSbOHgekfQglmuGDc2PrBs+3uX/rFdNOl1RhyAf1st4SbseA/YeA2eWQN2Mm32YAXhuGqB7BS0yxdw==",
|
|
75
75
|
"dev": true,
|
|
76
76
|
"license": "GPL-3.0",
|
|
77
77
|
"dependencies": {
|
|
78
|
-
"@pptb/validate": "1.0.
|
|
78
|
+
"@pptb/validate": "1.0.4"
|
|
79
79
|
},
|
|
80
80
|
"bin": {
|
|
81
81
|
"pptb-validate": "bin/pptb-validate.js"
|
|
82
82
|
}
|
|
83
83
|
},
|
|
84
84
|
"node_modules/@pptb/validate": {
|
|
85
|
-
"version": "1.0.
|
|
86
|
-
"resolved": "https://registry.npmjs.org/@pptb/validate/-/validate-1.0.
|
|
87
|
-
"integrity": "sha512-
|
|
85
|
+
"version": "1.0.4",
|
|
86
|
+
"resolved": "https://registry.npmjs.org/@pptb/validate/-/validate-1.0.4.tgz",
|
|
87
|
+
"integrity": "sha512-Xew21gUgwrdstVpu6EB8b8vDaWNE4OOiPqr1Xk61Ao2EKN4ioCVg/cG6uFRFBhLaLqSjublVYczJ01KAUbBsvw==",
|
|
88
88
|
"dev": true,
|
|
89
89
|
"license": "GPL-3.0",
|
|
90
90
|
"dependencies": {
|
|
91
|
-
"tar": "^7.5.
|
|
91
|
+
"tar": "^7.5.21"
|
|
92
92
|
},
|
|
93
93
|
"bin": {
|
|
94
94
|
"pptb-validate": "dist/cli.js"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pptb-standard-sample-tool",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"displayName": "HTML Sample Tool",
|
|
5
5
|
"description": "A sample Power Platform ToolBox tool built with HTML, CSS, and TypeScript",
|
|
6
6
|
"main": "index.html",
|
|
@@ -27,10 +27,12 @@
|
|
|
27
27
|
"readmeUrl": "https://raw.githubusercontent.com/PowerPlatformToolBox/sample-tools/refs/heads/main/new/html-sample/README.md"
|
|
28
28
|
},
|
|
29
29
|
"features": {
|
|
30
|
-
"minAPI": "1.2.
|
|
31
|
-
"multiConnection": "optional",
|
|
30
|
+
"minAPI": "1.2.7",
|
|
32
31
|
"enabledForPowerPlatformAPI": true,
|
|
33
|
-
"
|
|
32
|
+
"connections": {
|
|
33
|
+
"min": 0,
|
|
34
|
+
"max": 3
|
|
35
|
+
}
|
|
34
36
|
},
|
|
35
37
|
"cspExceptions": {
|
|
36
38
|
"style-src": [
|
|
@@ -79,7 +81,7 @@
|
|
|
79
81
|
"validate": "pptb-validate"
|
|
80
82
|
},
|
|
81
83
|
"devDependencies": {
|
|
82
|
-
"@pptb/types": "^1.2.
|
|
84
|
+
"@pptb/types": "^1.2.7-beta.4",
|
|
83
85
|
"shx": "^0.4.0",
|
|
84
86
|
"typescript": "^5.0.0"
|
|
85
87
|
},
|