@mohsinonxrm/pptb-fetchxml-studio 1.4.2 β 1.5.0-beta.12
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/CHANGELOG.md +245 -0
- package/README.md +37 -7
- package/dist/assets/codicon-DF1abBS2.ttf +0 -0
- package/dist/assets/index-CaYaZM-I.js +109 -0
- package/dist/assets/monaco-editor--wwQ80g0.css +1 -0
- package/dist/assets/monaco-editor-HrWgH4_j.js +988 -0
- package/dist/icons/icon.svg +6 -2
- package/dist/index.html +3 -3
- package/package.json +15 -9
- package/dist/assets/abap-CRCWOmpq.js +0 -1
- package/dist/assets/apex-DnsZk_dE.js +0 -1
- package/dist/assets/azcli-1IWB1ccx.js +0 -1
- package/dist/assets/bat-DPkNLes8.js +0 -1
- package/dist/assets/bicep-Corcdgou.js +0 -2
- package/dist/assets/cameligo-CGrWLZr3.js +0 -1
- package/dist/assets/clojure-D9WOWImG.js +0 -1
- package/dist/assets/codicon-B_Z2XQ3P.ttf +0 -0
- package/dist/assets/coffee-B7EJu28W.js +0 -1
- package/dist/assets/cpp-SEyurbux.js +0 -1
- package/dist/assets/csharp-BoL64M5l.js +0 -1
- package/dist/assets/csp-C46ZqvIl.js +0 -1
- package/dist/assets/css-DQU6DXDx.js +0 -3
- package/dist/assets/cssMode-lrJE5Iiz.js +0 -4
- package/dist/assets/cypher-D84EuPTj.js +0 -1
- package/dist/assets/dart-D8lhlL1r.js +0 -1
- package/dist/assets/dockerfile-DLk6rpji.js +0 -1
- package/dist/assets/ecl-BO6FnfXk.js +0 -1
- package/dist/assets/elixir-BRjLKONM.js +0 -1
- package/dist/assets/flow9-Cac8vKd7.js +0 -1
- package/dist/assets/freemarker2-DwmPKpl4.js +0 -3
- package/dist/assets/fsharp-fd1GTHhf.js +0 -1
- package/dist/assets/go-O9LJTZXk.js +0 -1
- package/dist/assets/graphql-LQdxqEYJ.js +0 -1
- package/dist/assets/handlebars-Cf8Yk1XH.js +0 -1
- package/dist/assets/hcl-DxDQ3s82.js +0 -1
- package/dist/assets/html-B8r17viV.js +0 -1
- package/dist/assets/htmlMode-Deu2Cnyl.js +0 -4
- package/dist/assets/index-DtvfGsXm.js +0 -109
- package/dist/assets/ini-BvajGCUy.js +0 -1
- package/dist/assets/java-SYsfObOQ.js +0 -1
- package/dist/assets/javascript-21fivyfm.js +0 -1
- package/dist/assets/jsonMode-C6fJmDrp.js +0 -10
- package/dist/assets/julia-DQXNmw_w.js +0 -1
- package/dist/assets/kotlin-qQ0MG-9I.js +0 -1
- package/dist/assets/less-GGFNNJHn.js +0 -2
- package/dist/assets/lexon-Canl7DCW.js +0 -1
- package/dist/assets/liquid-CBhIUaM_.js +0 -1
- package/dist/assets/lua-D28Ae8-K.js +0 -1
- package/dist/assets/m3-DPitgjJI.js +0 -1
- package/dist/assets/markdown-B811l8j2.js +0 -1
- package/dist/assets/mdx-DKh1a8vs.js +0 -1
- package/dist/assets/mips-CdjsipkG.js +0 -1
- package/dist/assets/monaco-editor-BhPcksyq.css +0 -1
- package/dist/assets/monaco-editor-CSKh0Kpy.js +0 -901
- package/dist/assets/msdax-CYqgjx_P.js +0 -1
- package/dist/assets/mysql-BHd6q0vd.js +0 -1
- package/dist/assets/objective-c-B1aVtJYH.js +0 -1
- package/dist/assets/pascal-BhNW15KB.js +0 -1
- package/dist/assets/pascaligo-5jv8CcQD.js +0 -1
- package/dist/assets/perl-DlYyT36c.js +0 -1
- package/dist/assets/pgsql-Dy0bjov7.js +0 -1
- package/dist/assets/php-120yhfDK.js +0 -1
- package/dist/assets/pla-CjnFlu4u.js +0 -1
- package/dist/assets/postiats-CQpG440k.js +0 -1
- package/dist/assets/powerquery-DdJtto1Z.js +0 -1
- package/dist/assets/powershell-Bu_VLpJB.js +0 -1
- package/dist/assets/protobuf-IBS6jZEB.js +0 -2
- package/dist/assets/pug-kFxLfcjb.js +0 -1
- package/dist/assets/python-C1DvjtTK.js +0 -1
- package/dist/assets/qsharp-q7JyzKFN.js +0 -1
- package/dist/assets/r-BIFz-_sK.js +0 -1
- package/dist/assets/razor-CxbdKBwV.js +0 -1
- package/dist/assets/redis-CHOsPHWR.js +0 -1
- package/dist/assets/redshift-CBifECDb.js +0 -1
- package/dist/assets/restructuredtext-CghPJEOS.js +0 -1
- package/dist/assets/ruby-CYWGW-b1.js +0 -1
- package/dist/assets/rust-DMDD0SHb.js +0 -1
- package/dist/assets/sb-BYAiYHFx.js +0 -1
- package/dist/assets/scala-Bqvq8jcR.js +0 -1
- package/dist/assets/scheme-Dhb-2j9p.js +0 -1
- package/dist/assets/scss-CTwUZ5N7.js +0 -3
- package/dist/assets/shell-CsDZo4DB.js +0 -1
- package/dist/assets/solidity-CME5AdoB.js +0 -1
- package/dist/assets/sophia-RYC1BQQz.js +0 -1
- package/dist/assets/sparql-KEyrF7De.js +0 -1
- package/dist/assets/sql-BdTr02Mf.js +0 -1
- package/dist/assets/st-C7iG7M4S.js +0 -1
- package/dist/assets/swift-D7IUmUK8.js +0 -1
- package/dist/assets/systemverilog-DgMryOEJ.js +0 -1
- package/dist/assets/tcl-PloMZuKG.js +0 -1
- package/dist/assets/tsMode-CoKGlBK3.js +0 -11
- package/dist/assets/twig-BfRIq3la.js +0 -1
- package/dist/assets/typescript-DE4VX4Fi.js +0 -1
- package/dist/assets/typespec-CzxlYoT_.js +0 -1
- package/dist/assets/vb-BwAE3J76.js +0 -1
- package/dist/assets/wgsl-B_1kOXbF.js +0 -298
- package/dist/assets/xml-D5FP6KmI.js +0 -1
- package/dist/assets/yaml-_F_B7Ufj.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,251 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.5.0-beta.12] - 2026-10-18
|
|
11
|
+
|
|
12
|
+
### β¨ Added
|
|
13
|
+
|
|
14
|
+
- **Saved views follow-ups (#142):**
|
|
15
|
+
- **Shared personal views:** Load view shows "Shared by {owner}" (or "Shared with you"). System views show their query type or "Default view" as a second line.
|
|
16
|
+
- **Write access:** before overwriting a personal view you don't own, Save view checks your access (`RetrievePrincipalAccess`). Without write access, it offers **Save a copyβ¦**; if access can't be determined, Dataverse decides.
|
|
17
|
+
- **Managed system views:** overwriting one shows a warning naming its solution. It's a warning only, not a block.
|
|
18
|
+
- **Quick find views:** enter a test value for `{0}`, with an optional trailing `%`, to execute them. The value is used only in the FetchXML that runs; the tree, the editor and saved views keep `{0}`. A loaded quick find view runs as FetchXML, not by ID, because by ID it matches nothing (verified live).
|
|
19
|
+
- **Set as default view** for public system views.
|
|
20
|
+
- **Description:** pre-filled when you overwrite a view, and clearing it clears the view's description.
|
|
21
|
+
- **Docs-driven helpers (#98):**
|
|
22
|
+
- **Wildcard helper** for `like` / `not-like` values: Contains (`%x%`), Begins with (`x%`), Ends with (`%x`) or a custom pattern. **Match literally** escapes `%` β `[%]`, `_` β `[_]` and `[` β `[[]`, per "Wildcard characters".
|
|
23
|
+
- begins-with and ends-with warn when a typed character would act as a wildcard.
|
|
24
|
+
- Stored values read back into the helper, and switching operators keeps the text.
|
|
25
|
+
- The Query Advisor's leading-wildcard advice ignores escaped characters, and now also appears in the results-grid column filter.
|
|
26
|
+
- **Total record count:** with *Return total record count*, the info bar shows "Rows: 50 of 1,234 total", or "5,000+ total" (500+ on elastic entities) when the limit is exceeded. **Count all {entity} records (unfiltered snapshot)** calls `RetrieveTotalRecordCount` and says plainly that it ignores the query's filters.
|
|
27
|
+
- **Hierarchy picker:** under / not-under / above / eq-or-under / eq-or-above on the primary key pick a record by name (`startswith` search, so no leading wildcard). The record's name is resolved back from its ID, and **Enter an ID instead** gives a GUID field with validation. The hint names the hierarchical relationship and the 100-level limit.
|
|
28
|
+
- **GUID values:** Lookup, Customer, Owner and Uniqueidentifier condition values that aren't GUIDs are flagged. Verified live: Dataverse rejects them with 0x80040203.
|
|
29
|
+
- **Undocumented settings:** "UTC offset (undocumented)" shows only when the query sets it, and the condition aggregate leftover reads "Aggregate (undocumented)".
|
|
30
|
+
|
|
31
|
+
### π§ Fixed
|
|
32
|
+
|
|
33
|
+
- **Record actions use the current selection after the results refresh (#158).** Previously, after a refresh (re-running the query, or the automatic refresh after Delete, Activate or Run workflow), the grid showed nothing selected, but the command bar kept the previous selection. Its actions stayed enabled and ran on the previously selected records. The command bar now clears its selection with the grid's.
|
|
34
|
+
|
|
35
|
+
### ποΈ Technical
|
|
36
|
+
|
|
37
|
+
- **Release process (`RELEASING.md`):** `main` holds the current stable release (npm `latest`); betas are tagged on `dev` (npm `beta`, GitHub pre-release); hotfixes branch from `main` and merge back into `dev`. PRs add CHANGELOG entries under `[Unreleased]` and don't change the version, which is set when a release is cut. The same process applies to Command Bar Studio and Dataverse Request Studio.
|
|
38
|
+
- **`release.yml` refuses a stable tag whose commit isn't on `main`,** so a stray tag on `dev` can't replace npm `latest`. Beta tags (`-beta.N`) are allowed from `dev`.
|
|
39
|
+
|
|
40
|
+
## [1.5.0-beta.11] - 2026-10-17
|
|
41
|
+
|
|
42
|
+
### β¨ Added
|
|
43
|
+
|
|
44
|
+
- **Activate and Deactivate work, driven by metadata (#143, verified live on temporary records).**
|
|
45
|
+
- **Simple entities** (Account, Contactβ¦): the state's default status reason is applied.
|
|
46
|
+
- **Multi-state entities** (Lead, activities, custom state models): you pick the status reason, grouped by state. When the entity enforces status-reason transitions, only targets allowed from every selected record's current status are offered.
|
|
47
|
+
- **Lead:** Deactivate defaults to Disqualified. Choosing Qualified warns that this doesn't run QualifyLead; Dataverse accepts the plain update.
|
|
48
|
+
- **Opportunity, Case, Quote, Order, Invoice and Contract** close through their own messages (WinOpportunity / LoseOpportunity, CloseIncident, WinQuote, FulfillSalesOrderβ¦). For these the buttons are disabled, with a tooltip naming the documented action. Proper dialogs are tracked in #149.
|
|
49
|
+
- **Also disabled, with a reason:** entities with no state, results with one-to-many joins, and missing Write privilege. The Write privilege name comes from metadata, e.g. `prvWriteActivity` for activities.
|
|
50
|
+
- **How it runs:** a PATCH of `statecode` + `statuscode`, sent through `$batch` in chunks of 25, with per-record errors, throttle retry, progress and the close warning. The query runs again afterwards.
|
|
51
|
+
- **Confirmations name the environment and the scope (#69, Marketplace policy).** Delete, Bulk delete, Run workflow, Save view and Activate/Deactivate show:
|
|
52
|
+
- the environment name, type and URL, with a warning for **Production**;
|
|
53
|
+
- the entity's display and logical name;
|
|
54
|
+
- the exact scope. A Bulk delete with no selection says "Every record the query matches" and never claims a total it doesn't know.
|
|
55
|
+
|
|
56
|
+
**Type-to-confirm:** on Production, for more than 100 records, or when the total is unknown, you type the entity's logical name before the action enables.
|
|
57
|
+
|
|
58
|
+
### π§ Fixed
|
|
59
|
+
|
|
60
|
+
- **Bulk delete no longer shows a stray horizontal scrollbar (#152).** The "Danger zone" warning was 1px wider than the dialog, a grid item's default `min-width`. Its title now reads "Bulk delete all matching {entity}" or "Bulk delete N records".
|
|
61
|
+
|
|
62
|
+
### π§ Changed
|
|
63
|
+
|
|
64
|
+
- **Sentence case** in the delete, bulk delete, workflow and save view dialogs and the results command bar, completing the sweep from beta.10: Delete record, Run workflow, Save and publish, Personal view, Bulk delete (job), Delete all, Retrieve all stopped.
|
|
65
|
+
|
|
66
|
+
### ποΈ Technical
|
|
67
|
+
|
|
68
|
+
- New `model/recordState.ts` (state planning from metadata, transition intersection, close-message entities) and `shared/components/TargetScope.tsx` with `targetScopeRules.ts`, all with tests.
|
|
69
|
+
- The `$batch` runner in `batchDelete.ts` is shared by delete and the state update.
|
|
70
|
+
|
|
71
|
+
## [1.5.0-beta.10] - 2026-10-17
|
|
72
|
+
|
|
73
|
+
### β¨ Added
|
|
74
|
+
|
|
75
|
+
- **Collapsible query scope section (#25).** It collapses to one line, "**Account** Β· View: Active accounts Β· Contoso Core", with **New** always visible. The collapsed state is remembered.
|
|
76
|
+
- **The publisher and solution selection is remembered per environment (#25),** keyed by environment URL in the ToolBox settings. It's restored once the lists load; publishers or solutions that no longer exist are dropped.
|
|
77
|
+
- **Right-click a tree row (#24).** Right-click, Shift+F10 or the context-menu key opens the row's Add items, a divider, then **Delete** in red. The root entity has no Delete.
|
|
78
|
+
|
|
79
|
+
### π§ Changed
|
|
80
|
+
|
|
81
|
+
- **Tree (#24, #25):**
|
|
82
|
+
- The Add menus are reordered, renamed and given the tree's icons: All attributes, **Select attributesβ¦** (now second), **Blank attribute**, Order by, Filter, Link-entity.
|
|
83
|
+
- Deleting a node with items inside asks first: "Delete filter (and)? This also deletes the 2 items inside it."
|
|
84
|
+
- Rows with nothing inside have no chevron.
|
|
85
|
+
- A link-entity that can return attributes but has none shows "(no attributes)".
|
|
86
|
+
- A link-entity without an alias is labelled by its lookup, e.g. "contact via primarycontactid (outer)". The lookup is `to` for N:1 and `from` for 1:N.
|
|
87
|
+
- **Relationship picker (#25):** each option has two lines, the related entity, then "via {lookup} ({logical}) Β· {schema name}". The groups are Many-to-one, One-to-many and Many-to-many, search matches any part, and the list is wide enough that options stay on two lines.
|
|
88
|
+
- **Publishers and solutions (#25)** show two lines: name, then `uniquename Β· vX` for solutions and `uniquename Β· prefix` for publishers. The empty states are worded consistently.
|
|
89
|
+
- **Sentence case and "β¦" across the UI,** matching Dataverse Request Studio and Command Bar Studio. For example: Load view, System views, Entity source, All entities, Advanced Find only, Use logical names, Editor mode, Parse to tree, Send to tool, Save asβ¦.
|
|
90
|
+
|
|
91
|
+
### ποΈ Technical
|
|
92
|
+
|
|
93
|
+
- New `model/scopeSelection.ts`, `model/treeLabels.ts` and `model/relationshipOptions.ts`, and the `useRememberedScope` hook, with tests.
|
|
94
|
+
|
|
95
|
+
## [1.5.0-beta.9] - 2026-10-17
|
|
96
|
+
|
|
97
|
+
### ποΈ Technical
|
|
98
|
+
|
|
99
|
+
- **monaco-editor 0.54 β 0.57 (#145)** clears the moderate `dompurify` advisories.
|
|
100
|
+
- `@monaco-editor/react` stays at 4.7.0, because 4.8 is still a prerelease. An ambient type declaration maps its `editor.api` import to Monaco 0.57's `monaco-editor/editor` entry.
|
|
101
|
+
- **Smaller bundle:** Monaco loads only the editor core, its features and the languages FXS shows (XML, C#, JavaScript, shell and SQL), using the tree-shakeable entry points added in Monaco 0.56. With the full 0.57 entry, the package would have exceeded its size budget. Now it's 13 files instead of 98, and slightly smaller overall.
|
|
102
|
+
- **No worker console errors:** the editor worker runs on the main thread from the start, as before (PPTB's CSP blocks `blob:` workers), without the errors Monaco 0.57 would log first.
|
|
103
|
+
- **Remaining audit findings:** two low `dompurify` advisories (fixed in 3.4.16). Monaco bundles its own copy and doesn't use the affected `IN_PLACE` mode.
|
|
104
|
+
- **`uuid` for exceljs pinned to 11.1.1 with an npm override (#145, GHSA-w5hq-g745-h8pq).** The browser build of exceljs bundles its own uuid and only calls `v4()`, so the advisory never applied to the tool.
|
|
105
|
+
- **A round-trip test for local Excel export:** headers, typed values, formats, dates, labels, the "both" (Raw) columns, the frozen header and auto-filter.
|
|
106
|
+
|
|
107
|
+
## [1.5.0-beta.8] - 2026-10-17
|
|
108
|
+
|
|
109
|
+
### β¨ Added
|
|
110
|
+
|
|
111
|
+
- **Query Advisor (#97).** Before you run a query, FetchXML Studio flags the performance anti-patterns Microsoft Learn documents, as notes in Validate, Parse to Tree and the property panel. **Advice never blocks Execute.** It covers:
|
|
112
|
+
- leading wildcards in `like` / `begins-with` values, and `ends-with`;
|
|
113
|
+
- `<all-attributes />` or no attributes selected;
|
|
114
|
+
- sorting by a link-entity's attributes, which is slower and can lose the paging cookie;
|
|
115
|
+
- `distinct` without an order;
|
|
116
|
+
- simple paging past 50,000 records;
|
|
117
|
+
- aggregate queries with no filter (the 50,000-record aggregate limit);
|
|
118
|
+
- the legacy `no-lock`.
|
|
119
|
+
- **Query limits, verified live (#97):**
|
|
120
|
+
- **More than 15 joined link-entities** blocks Execute (0x8004430D). Link-entities inside filters don't count.
|
|
121
|
+
- **More than 500 conditions** blocks Execute (0x8004430C). Microsoft Learn says conditions and link-entities count together, but live, only conditions count: 500 conditions plus a link-entity run.
|
|
122
|
+
- **URL-encoded FetchXML over 32,768 characters** gets a warning with "Execute anyway". Live, about 44,500 characters failed with HTTP 414, but the exact limit depends on the URL.
|
|
123
|
+
|
|
124
|
+
### ποΈ Technical
|
|
125
|
+
|
|
126
|
+
- New `model/queryAdvisor.ts`, called from `validateQueryRules`, with 91 table-driven tests. Every advice case is also checked to block nothing.
|
|
127
|
+
- The condition Operator and Value fields, the aggregate and distinct options and the order Attribute field now show their advice notes, through the existing `findingFor`.
|
|
128
|
+
|
|
129
|
+
## [1.5.0-beta.7] - 2026-10-17
|
|
130
|
+
|
|
131
|
+
### π§ Fixed
|
|
132
|
+
|
|
133
|
+
- **Load View labels querytype 2048 as "Other"** (`SavedQueryTypeOther`). It used to read "Template", a label that belongs to the template types (#144).
|
|
134
|
+
- **PPTB events no longer log their payloads to the console (#71).** Connection events carry environment details. Event names are logged only when debug logging is on.
|
|
135
|
+
|
|
136
|
+
### ποΈ Technical
|
|
137
|
+
|
|
138
|
+
- **Safe OData literals (#81).** Every value placed inside a single-quoted OData string literal now has its quotes doubled (`odataString`). That covers entity and attribute names in metadata queries, solution unique names, and the workflow and view filters. A value can no longer end the literal early.
|
|
139
|
+
- **The duplicate LayoutXML helpers are removed from `pptbClient.ts` (#81).** They were unused; `model/layoutxml.ts` is the only implementation.
|
|
140
|
+
|
|
141
|
+
## [1.5.0-beta.6] - 2026-10-17
|
|
142
|
+
|
|
143
|
+
### π§ Fixed
|
|
144
|
+
|
|
145
|
+
- **Column headers for one-to-many link-entities name the related entity (verified live).**
|
|
146
|
+
- A 1:N link-entity's column read "Full Name (Account)": the header used the parent's primary key, which is the link's `to` attribute.
|
|
147
|
+
- It now reads "Full Name (Contact)". The entity's display name comes from the cached entity lists, so it's there before the entity has been opened.
|
|
148
|
+
- N:1 columns are unchanged and still name the lookup ("Full Name (Primary Contact)").
|
|
149
|
+
|
|
150
|
+
## [1.5.0-beta.5] - 2026-10-17
|
|
151
|
+
|
|
152
|
+
### ποΈ Technical
|
|
153
|
+
|
|
154
|
+
- **Browser dev harness against a live org: `npm run dev:harness` (#78), modelled on Command Bar Studio #44.**
|
|
155
|
+
- **What it runs:** the real UI, in a browser, against the Dataverse org in `DATAVERSE_URL`.
|
|
156
|
+
- **How requests flow:**
|
|
157
|
+
- A stub of the PPTB host makes requests the same way PPTB 1.2.7 does: the same entity-set names, `execute()` encoding, Prefer headers and error text, plus optional `CallerObjectId` impersonation.
|
|
158
|
+
- A localhost-only Vite proxy attaches an Azure CLI token on the server side. The token is kept in memory only and is never logged or sent to the browser.
|
|
159
|
+
- The proxy only accepts requests from localhost with a harness header, and forwards only to the org's Web API over https.
|
|
160
|
+
- **Not shipped:** the harness is dev-only. The production build is byte-identical without it, and it isn't in the package. See `dev/README.md`.
|
|
161
|
+
- **Dev tooling updated, clearing every high npm audit finding (#77):**
|
|
162
|
+
- versions: vite 7.3.6, @vitejs/plugin-react 5.2.0, typescript-eslint 8.71.0, eslint 9.39.5, plus transitive fixes (rollup, postcss and others);
|
|
163
|
+
- audit: 25 findings (17 high) β 4 moderate, 0 high;
|
|
164
|
+
- every changed package was published at least two weeks ago;
|
|
165
|
+
- no runtime dependencies changed.
|
|
166
|
+
- **Not bumped:** monaco-editor 0.57. Its `exports` map breaks `@monaco-editor/react` 4.7's types, so it needs its own change.
|
|
167
|
+
|
|
168
|
+
## [1.5.0-beta.4] - 2026-10-17
|
|
169
|
+
|
|
170
|
+
### β οΈ Requires Power Platform ToolBox 1.2.7
|
|
171
|
+
|
|
172
|
+
- **PPTB 1.2.7 is now required (#82).**
|
|
173
|
+
- `@pptb/types` is 1.2.7.
|
|
174
|
+
- `features.connections: 1`, and `minAPI` is 1.2.7 (it was 1.2.2).
|
|
175
|
+
- Older hosts and `1.2.7-dev` Insider builds show the tool as unsupported.
|
|
176
|
+
|
|
177
|
+
### β¨ Added
|
|
178
|
+
|
|
179
|
+
- **Changing the tool's connection in place resets everything that came from the old environment (#66).**
|
|
180
|
+
- The metadata cache, entity lists, publishers and solutions, privileges, WhoAmI, results and the loaded view are all cleared, and the UI reloads for the new connection. The query is kept.
|
|
181
|
+
- A notification says what happened.
|
|
182
|
+
- Token refreshes and edits to other connections reset nothing. Deleting another connection no longer marks the tool as disconnected.
|
|
183
|
+
- Workflow runs and multi-record deletes stop if the connection changes partway through.
|
|
184
|
+
- **The ToolBox warns before closing while work is running (#70):** Retrieve All, deletes, workflow runs and Save view (`preventClose`).
|
|
185
|
+
- **Record links open in the connection's browser profile (#70).** This covers Open record and the bulk delete job link (`openInConnectionBrowser`).
|
|
186
|
+
|
|
187
|
+
### π§ Fixed
|
|
188
|
+
|
|
189
|
+
- **Deleting records uses the entity's metadata entity set name (#61).** This fixes entities whose entity set name the host guesses wrongly.
|
|
190
|
+
- Multi-record deletes are sent as real OData `$batch` requests of 25 (`executeBatch`).
|
|
191
|
+
- Errors are reported per record: a batch Dataverse rejects is retried one record at a time, so one failure doesn't fail the rest.
|
|
192
|
+
- **Clipboard writes try the ToolBox first (#70),** then the browser clipboard. That applies to copying results, record URLs, FetchXML and code.
|
|
193
|
+
|
|
194
|
+
### ποΈ Technical
|
|
195
|
+
|
|
196
|
+
- New `api/host.ts` adapter. Every host API is feature-detected, with a fallback.
|
|
197
|
+
- New `api/batchDelete.ts` and `shared/hooks/connectionIdentity.ts`.
|
|
198
|
+
- `metadataCache.clear()` now clears every cache, with a generation guard so requests still running for the old connection can't refill it.
|
|
199
|
+
|
|
200
|
+
## [1.5.0-beta.3] - 2026-10-17
|
|
201
|
+
|
|
202
|
+
### β¨ Added
|
|
203
|
+
|
|
204
|
+
- **Dataverse errors explain what to do (#96).** For documented error codes, the error bar, paging notices, export, delete, bulk delete, workflow and Save view messages start with what to do. Dataverse's own message follows after "Details:". Undocumented codes are shown unchanged. Covered:
|
|
205
|
+
- service protection limits (429, 0x80072322/21/26);
|
|
206
|
+
- the 50,000-record aggregate limit (0x8004E023);
|
|
207
|
+
- the quick find record limit;
|
|
208
|
+
- more than 500 conditions or 15 link-entities;
|
|
209
|
+
- query throttling and timeouts caused by leading wildcards, calculated attributes or other anti-patterns;
|
|
210
|
+
- aggregate mistakes;
|
|
211
|
+
- invalid condition values;
|
|
212
|
+
- missing attributes or entities;
|
|
213
|
+
- entity set names Web API doesn't recognise;
|
|
214
|
+
- records not found;
|
|
215
|
+
- missing privileges.
|
|
216
|
+
- **Throttling back-off (#96).** When Dataverse service protection limits are hit, deletes, workflow runs and page loads wait and retry: per `Retry-After` when it's given, otherwise 2, 4 and 8 seconds. Each wait is capped at 60 seconds, with at most 3 retries.
|
|
217
|
+
- **Pages over Power Platform ToolBox's 16 MB response limit (#68).**
|
|
218
|
+
- **Load more and Retrieve All:** the page is requested again at half the size, at most three times and never below 100 rows. The pages that follow keep the smaller size.
|
|
219
|
+
- **The first page and saved views:** the error explains how to make the response smaller (fewer attributes, or a smaller `count`), and nothing is retried.
|
|
220
|
+
|
|
221
|
+
### π§ Changed
|
|
222
|
+
|
|
223
|
+
- **Fewer startup calls and a quiet console (#71).**
|
|
224
|
+
- WhoAmI and each privilege check are sent once per connection, and concurrent callers share one request.
|
|
225
|
+
- Raw query results, privilege responses, payloads and routine status no longer go to the console. They're behind the debug flags (`src/shared/utils/debug.ts`), which are now all off by default.
|
|
226
|
+
- The Electron IPC prefix is removed from errors shown to users.
|
|
227
|
+
|
|
228
|
+
### ποΈ Technical
|
|
229
|
+
|
|
230
|
+
- New modules, each with tests:
|
|
231
|
+
- `api/dataverseErrors.ts`: reads the PPTB 1.2.7 host's error formats and maps documented codes to Microsoft Learn;
|
|
232
|
+
- `api/throttleRetry.ts`;
|
|
233
|
+
- `api/sessionCache.ts`: `resetDataverseSessionCache()`, to be called on a connection change (#66);
|
|
234
|
+
- `api/pageRecovery.ts`.
|
|
235
|
+
|
|
236
|
+
## [1.5.0-beta.2] - 2026-10-17
|
|
237
|
+
|
|
238
|
+
### π Documentation
|
|
239
|
+
|
|
240
|
+
- **README: "What this tool changes" (#69, Marketplace policy).** Lists every operation that writes to Dataverse: Delete, Bulk Delete, Run workflow, and saving personal and system views. For each it says when it runs, what it does and which privilege it needs. It also lists what doesn't write: both exports and the locally stored settings.
|
|
241
|
+
- It states plainly that Delete with no rows selected submits a Bulk Delete job for every record the query matches, not just the loaded rows.
|
|
242
|
+
|
|
243
|
+
## [1.5.0-beta.1] - 2026-10-17
|
|
244
|
+
|
|
245
|
+
### π§ Fixed
|
|
246
|
+
|
|
247
|
+
- **Cross-apply columns stay filled when they're filtered (#91 follow-up, verified live).**
|
|
248
|
+
- A `matchfirstrowusingcrossapply` link-entity normally returns its attributes by schema name (`FullName`).
|
|
249
|
+
- A condition with `entityname` targeting that link-entity, such as a column filter from the grid, makes Dataverse join it normally. It then returns `mc.fullname` instead.
|
|
250
|
+
- The grid now uses whichever key Dataverse returned, including for cross-apply `<all-attributes />`, so a filtered cross-apply column no longer shows as empty.
|
|
251
|
+
- **Two cross-apply queries Dataverse rejects are now flagged before they run (verified live 2026-10-17).**
|
|
252
|
+
- An order inside a `matchfirstrowusingcrossapply` link-entity (0x80041121). Order from the entity with `entityname` instead; that works.
|
|
253
|
+
- An aliased attribute in one, which fails with a generic SQL error (0x80044150) unless a condition with `entityname` targets the link-entity. With such a condition the alias works, so that case isn't flagged.
|
|
254
|
+
|
|
10
255
|
## [1.4.2] - 2026-10-17
|
|
11
256
|
|
|
12
257
|
The v1.4.2 milestone: the features other users asked for, a results grid that works from the query, saved views that behave as documented, operators that follow the docs, and the CI/CD and release setup shared with Command Bar Studio and Dataverse Request Studio. It was iterated through `1.4.2-beta.1` to `1.4.2-beta.7` (detailed below). Behaviour follows Microsoft Learn and the live operator matrix. Valid FetchXML is never refused, and a Dataverse error is shown as it is.
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
A powerful, modern FetchXML query builder and data explorer for [Power Platform ToolBox](https://github.com/PowerPlatformToolBox/desktop-app). Inspired by the XrmToolBox FetchXML Builder, reimagined with React 18, Fluent UI v9, and seamless Dataverse integration.
|
|
4
4
|
|
|
5
|
-

|
|
6
6
|
[](https://www.npmjs.com/package/@mohsinonxrm/pptb-fetchxml-studio)
|
|
7
7
|

|
|
8
8
|

|
|
@@ -13,18 +13,23 @@ A powerful, modern FetchXML query builder and data explorer for [Power Platform
|
|
|
13
13
|
|
|
14
14
|
### π§ Visual Query Builder
|
|
15
15
|
- **Tree-based hierarchy** β Build FetchXML queries visually with entities, attributes, filters, orders, and link-entities
|
|
16
|
+
- **Add menus and right-click** β Each row's + menu offers All attributes, Select attributesβ¦, Blank attribute, Order by, Filter and Link-entity, with the tree's icons. Right-click (or Shift+F10) a row for the same items plus **Delete**. Deleting a node with items inside asks first.
|
|
17
|
+
- **Readable rows** β Rows with nothing inside have no chevron. A link-entity that can return attributes but has none says "(no attributes)". A link-entity without an alias is labelled by its lookup, e.g. "contact via primarycontactid (outer)".
|
|
18
|
+
- **Query scope** β Publishers, Solutions, Entity and Load view sit in a section that collapses to one line (entity Β· view Β· solutions), with **New** always visible. Your publisher and solution selection is remembered for each environment. Solutions show their unique name and version, grouped Unmanaged / Managed.
|
|
16
19
|
- **Property panel for every node** β Fetch options, entity, attributes, all-attributes, sorts, filters, conditions and link-entities each have an editor covering the full FetchXML reference. Every field explains itself in an info popover with a link to Microsoft Learn.
|
|
20
|
+
- **Docs-driven helpers** β Like / begins-with / ends-with values have a wildcard helper: Contains, Begins with, Ends with or a custom pattern, plus "Match literally", which escapes `%`, `_` and `[`. Hierarchy operators (under, aboveβ¦) pick a record by name, with a Record ID fallback. Undocumented settings (UTC offset, condition aggregate) are labelled as such.
|
|
17
21
|
- **Metadata-driven** β Attribute pickers, operators, value pickers, aggregate functions, date grouping, sortable attributes and compare-to-attribute choices follow each attribute's metadata, so the panel only offers what Dataverse accepts.
|
|
18
22
|
- **Shows problems where they are** β Rule errors appear on the field they're about and as an **Error** badge in the tree; settings Dataverse ignores are listed with a **Remove** button.
|
|
19
23
|
- **Tree badges** β Aggregate, Distinct, Retained and Hints on the query; Group by, date grouping and aggregate functions on attributes; Union and Quick find on filters.
|
|
20
24
|
- **Safe mode changes** β Turning off aggregate, or switching a link-entity to a type that returns no attributes, lists what has to change and asks first.
|
|
21
25
|
- **Full FetchXML support** β Aggregate queries, grouping, distinct, top/count, paging, and advanced hints
|
|
22
26
|
- **Nested filters** β Create complex AND/OR filter groups with unlimited nesting
|
|
23
|
-
- **Link-entity relationships** β Browse and add 1:N, N:1, and N:N relationships with inner/outer joins; N:N relationships join through their intersect entity, as documented; intersect entities (such as `systemuserroles` or `teammembership`) can be joined to each side of their N:N relationship
|
|
27
|
+
- **Link-entity relationships** β Browse and add 1:N, N:1, and N:N relationships with inner/outer joins. Each option shows the related entity, then "via {lookup} Β· {schema name}", and search matches any part; N:N relationships join through their intersect entity, as documented; intersect entities (such as `systemuserroles` or `teammembership`) can be joined to each side of their N:N relationship
|
|
24
28
|
|
|
25
29
|
### π Results Grid
|
|
26
30
|
- **Virtualized DataGrid** β Handle large result sets with smooth scrolling (powered by react-window)
|
|
27
31
|
- **Copy results** β Right-click a cell to copy its value, its raw value (GUID, number, ISO date or option value), the row, the selected rows or the column. **Ctrl+C** copies the selected rows, or the focused cell. The command bar's **Copy** menu copies the selected or all loaded rows, as shown or as raw values. Rows copy as tab-separated values with a header row, so they paste into Excel as cells
|
|
32
|
+
- **Total record count** β With *Return total record count*, the info bar shows "Rows: 50 of 1,234 total", or "5,000+ total" when Dataverse caps the count. **Count all {entity} records** then gets the entity's unfiltered total (`RetrieveTotalRecordCount`, a snapshot that ignores the query's filters)
|
|
28
33
|
- **Paging and Retrieve All** β Scrolling to the end loads the next page; **Retrieve All** loads every page, with **Stop** to keep what's loaded so far. Pages use the documented paging cookie and the query's own `count` and starting `page`. Queries Dataverse returns no cookie for (sorted by a link-entity attribute, or distinct) page by page number, with a note. Views follow `@odata.nextLink`. A failed page shows how many rows loaded, with **Retry**
|
|
29
34
|
- **Rich cell rendering** β Power Apps-style display for lookups, option sets, dates, currency, and more
|
|
30
35
|
- **Column header menu** β Click a header for **Sort** (A to Z, smallest to largest or oldest to newest, by type), **Filter byβ¦** and **Clear filter**. Shift+click a header still adds it to a multi-column sort.
|
|
@@ -70,9 +75,13 @@ A powerful, modern FetchXML query builder and data explorer for [Power Platform
|
|
|
70
75
|
- **LayoutXML preview** β See the column layout configuration
|
|
71
76
|
|
|
72
77
|
### π₯ Load & Save Views
|
|
73
|
-
- **Load system/personal views** β Browse and load existing Dataverse views
|
|
74
|
-
- **Optimized view execution** β
|
|
75
|
-
- **Save to Dataverse** β Save your queries as new personal views or update existing ones
|
|
78
|
+
- **Load system/personal views** β Browse and load existing Dataverse views of every query type. Personal views shared with you show "Shared by {owner}", and system views show their type or "Default view"
|
|
79
|
+
- **Optimized view execution** β An unmodified loaded view runs by its ID (SavedQuery/UserQuery). Quick find views run as FetchXML with the test value you enter for `{0}`; the query keeps `{0}`
|
|
80
|
+
- **Save to Dataverse** β Save your queries as new personal or system views, or update existing ones.
|
|
81
|
+
- Before overwriting a shared personal view, your write access is checked; without it you get **Save a copyβ¦**.
|
|
82
|
+
- Overwriting a managed system view warns first.
|
|
83
|
+
- Public system views can be **set as the default view**.
|
|
84
|
+
- The description is pre-filled.
|
|
76
85
|
- **Solution-aware** β Add views to solutions during save
|
|
77
86
|
|
|
78
87
|
### π€ Export & Data Operations
|
|
@@ -123,6 +132,24 @@ A powerful, modern FetchXML query builder and data explorer for [Power Platform
|
|
|
123
132
|
- **Workflow privilege check** β Validates `prvReadWorkflow` + `prvWorkflowExecution` before showing workflow picker
|
|
124
133
|
- **View save privilege check** β Validates `prvWriteQuery` / `prvWriteCustomization` / `prvPublishCustomization` / `prvWriteUserQuery` before save operations
|
|
125
134
|
|
|
135
|
+
## βοΈ What this tool changes
|
|
136
|
+
|
|
137
|
+
FetchXML Studio only reads from Dataverse until you start one of the operations below. Each one asks for confirmation first, and the confirmation names the target: the environment (connection name, URL and type, with Production highlighted), the entity, and how many records (or which view). For the record operations, on a Production connection, for more than 100 records, or when the total isn't known (Bulk Delete with no rows selected), you type the entity logical name before the button enables. They all run as the connected user, or as the user PPTB is impersonating, so Dataverse applies that user's security roles.
|
|
138
|
+
|
|
139
|
+
| Operation | When | What it does in Dataverse |
|
|
140
|
+
|---|---|---|
|
|
141
|
+
| **Delete records** | Results β **Delete** with 1β100 rows selected | Deletes the selected records. 1β3 records are deleted one request each; 4β100 are deleted in a batch, with progress. Needs the entity's Delete privilege. |
|
|
142
|
+
| **Bulk Delete** | Results β **Delete** with more than 100 rows selected, or with **no rows selected**, or **Bulk Delete** | Submits an asynchronous Bulk Delete job (`BulkDelete`). It runs on the server, and you can track it under Settings β Data Management β Bulk Record Deletion. With no rows selected, the job deletes **every record the query matches**, not just the rows loaded in the grid. Needs the Bulk Delete privilege (`prvBulkDelete`). |
|
|
143
|
+
| **Activate / Deactivate** | Results β **Activate** or **Deactivate** with rows selected | Sets each selected record's Status and Status Reason with an update (`PATCH {EntitySetName}(id)` with `statecode` and `statuscode`), in batches with progress. The options come from the entity's metadata: entities with two states and one status reason each (such as account and contact) go to the state's default status reason; others let you pick the status reason, grouped by state, limited to the allowed transitions when the entity enforces status reason transitions. Off for entities whose states change through their own actions (opportunity, case, quote, order, invoice, contract) and for entities with no Status column. Needs the entity's Write privilege. |
|
|
144
|
+
| **Run workflow** | Results β **Run Workflow** on selected rows | Starts the chosen on-demand workflow (`ExecuteWorkflow`) once per selected record. What the workflow does is up to the workflow. |
|
|
145
|
+
| **Save view (personal)** | **Save As** / **Save**, Personal view | Creates or updates a `userquery` record (your personal view). |
|
|
146
|
+
| **Save view (system)** | **Save As** / **Save**, System view | Checks the query with `ValidateSavedQuery`, then creates or updates a `savedquery` record and publishes it (`PublishXml`). Optionally adds it to the unmanaged solution you choose (`AddSolutionComponent`). Overwriting a view that isn't customizable is blocked. |
|
|
147
|
+
|
|
148
|
+
Nothing else writes to Dataverse:
|
|
149
|
+
- **Export (Server)** asks Dataverse to build an Excel file (`ExportToExcel`) and changes no data.
|
|
150
|
+
- **Export (Local)** writes an `.xlsx` file to the location you choose.
|
|
151
|
+
- **Display settings** (logical names, value format, entity source, Advanced Find only) are stored by Power Platform ToolBox on your machine, not in Dataverse.
|
|
152
|
+
|
|
126
153
|
## πΌοΈ Interface Overview
|
|
127
154
|
|
|
128
155
|
```
|
|
@@ -152,7 +179,7 @@ A powerful, modern FetchXML query builder and data explorer for [Power Platform
|
|
|
152
179
|
## π Getting Started
|
|
153
180
|
|
|
154
181
|
### Prerequisites
|
|
155
|
-
- [Power Platform ToolBox](https://github.com/PowerPlatformToolBox/desktop-app) desktop application
|
|
182
|
+
- [Power Platform ToolBox](https://github.com/PowerPlatformToolBox/desktop-app) desktop application, **version 1.2.7 or later**. FetchXML Studio 1.5 targets PPTB 1.2.7 (`minAPI` 1.2.7); 1.4.x works with 1.2.2 or later
|
|
156
183
|
- Connection to a Dataverse environment
|
|
157
184
|
|
|
158
185
|
### Installation
|
|
@@ -172,6 +199,9 @@ npm ci
|
|
|
172
199
|
|
|
173
200
|
# Start development server
|
|
174
201
|
npm run dev
|
|
202
|
+
|
|
203
|
+
# Run the real UI in a browser against a live Dataverse org (needs `az login`; see dev/README.md)
|
|
204
|
+
npm run dev:harness
|
|
175
205
|
```
|
|
176
206
|
|
|
177
207
|
### Building
|
|
@@ -187,7 +217,7 @@ npm run preview
|
|
|
187
217
|
npm run validate
|
|
188
218
|
```
|
|
189
219
|
|
|
190
|
-
**Releases.** CI (`.github/workflows/ci.yml`) runs typecheck, lint, tests, PPTB validation, the build and a package-contents check on every pull request.
|
|
220
|
+
**Releases.** CI (`.github/workflows/ci.yml`) runs typecheck, lint, tests, PPTB validation, the build and a package-contents check on every pull request. `main` holds the current stable release and `dev` the next one. A `vX.Y.Z` tag on `main` publishes to npm `latest`, and a `vX.Y.Z-beta.N` tag on `dev` publishes to npm `beta` as a GitHub pre-release, both with provenance; see [RELEASING.md](RELEASING.md).
|
|
191
221
|
|
|
192
222
|
**Tool icon.** `package.json` points `icon` at `icons/icon.svg` under `dist/`, where Power Platform ToolBox looks for it. The build bundles `icons/icon-insider.svg` (gold stamp) for prerelease versions such as `1.4.2-beta.7`, and `icons/icon.svg` for releases.
|
|
193
223
|
|
|
Binary file
|