@mohsinonxrm/pptb-fetchxml-studio 1.4.0 β 1.4.1
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 +598 -0
- package/README.md +89 -25
- package/dist/assets/index-BQgTOj7B.js +107 -0
- package/{icons β dist/icons}/icon.svg +1 -1
- package/dist/index.html +1 -1
- package/package.json +17 -13
- package/dist/assets/index-BoFrKby3.js +0 -107
- package/icons/icon-insider.svg +0 -16
- package/npm-shrinkwrap.json +0 -6362
package/README.md
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
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
|
+
[](https://www.npmjs.com/package/@mohsinonxrm/pptb-fetchxml-studio)
|
|
6
7
|

|
|
7
8
|

|
|
8
9
|

|
|
@@ -12,24 +13,56 @@ A powerful, modern FetchXML query builder and data explorer for [Power Platform
|
|
|
12
13
|
|
|
13
14
|
### π§ Visual Query Builder
|
|
14
15
|
- **Tree-based hierarchy** β Build FetchXML queries visually with entities, attributes, filters, orders, and link-entities
|
|
15
|
-
- **
|
|
16
|
+
- **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.
|
|
17
|
+
- **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
|
+
- **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
|
+
- **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
|
+
- **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.
|
|
16
21
|
- **Full FetchXML support** β Aggregate queries, grouping, distinct, top/count, paging, and advanced hints
|
|
17
22
|
- **Nested filters** β Create complex AND/OR filter groups with unlimited nesting
|
|
18
|
-
- **Link-entity relationships** β Browse and add 1:N, N:1, and N:N relationships with inner/outer joins
|
|
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
|
|
19
24
|
|
|
20
25
|
### π Results Grid
|
|
21
26
|
- **Virtualized DataGrid** β Handle large result sets with smooth scrolling (powered by react-window)
|
|
27
|
+
- **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**
|
|
22
28
|
- **Rich cell rendering** β Power Apps-style display for lookups, option sets, dates, currency, and more
|
|
23
|
-
- **Multi-column sorting** β Click headers to sort; Shift+click for multi-column sort
|
|
24
|
-
- **
|
|
29
|
+
- **Multi-column sorting** β Click headers to sort; Shift+click for multi-column sort. Each click writes a valid `<order>`: by alias in aggregate queries, with `entityname` for link-entity columns, and not at all for attribute types Dataverse can't sort (multi-select option sets)
|
|
30
|
+
- **Edit / Add columns** β Remove, reorder and add columns from the root entity or related entities (N:1 and 1:N); the tree and FetchXML change to match. Removing a column removes its attribute (aliased or not, root or link-entity), any sort on its alias, and an outer link-entity left empty. At least one column must remain (a query without attributes returns every attribute). Add columns isn't available in aggregate queries
|
|
31
|
+
- **Link-entities without an alias** β Their columns show in the grid: Dataverse names them `{name}{N}.attribute`, and the grid uses the same names
|
|
32
|
+
- **Row selection** β Select single or multiple records for bulk operations. Record actions use the table's primary key, which Dataverse returns automatically for regular queries; for aggregate and distinct queries (which return no record IDs) record actions are disabled with an explanation
|
|
25
33
|
- **Resizable & reorderable columns** β Customize your view with drag-and-drop columns
|
|
26
34
|
- **Formatted values** β Display OData formatted values or raw values (configurable)
|
|
35
|
+
- **Works with every entity** β Queries run against the entity set name from Dataverse metadata, so entities with irregular names (for example `feedback`, `msdyn_conversationdata`) run correctly. The Power Platform ToolBox host's own name guess is wrong for about 4% of entities.
|
|
27
36
|
|
|
28
37
|
### π FetchXML Editor
|
|
29
38
|
- **Monaco editor** β Full-featured XML editor with XML syntax highlighting and line numbers
|
|
30
39
|
- **Bi-directional editing** β Edit XML directly and parse back to the visual builder
|
|
40
|
+
- **Intellisense from the reference** β Element, attribute and value suggestions follow the FetchXML reference (every documented attribute, including `aggregatelimit`, `datasource`, `options`, `rowaggregate`, order `entityname` and the quick find overrides). Undocumented attributes are suggested only where Dataverse was verified to accept them, and say so. Value suggestions work for hyphenated attributes such as `link-type`
|
|
41
|
+
- **Power Automateβsafe values** β Apostrophes stay literal in the generated FetchXML (attribute values use double quotes), so expressions such as `@{body('x')}` paste into Power Automate unchanged; `"`, `&`, `<` and `>` are escaped everywhere, including names, aliases and `from` / `to`
|
|
42
|
+
- **Editor mode actions run what you see** β In editor mode, **Execute**, **Save** and **Send to Tool** first load your FetchXML into the tree, so results, saved views and sent queries always match the editor. Execute is available as soon as the editor has content, even before an entity is chosen. If the tree would change anything, a confirmation lists the changes first, and the editor then shows the cleaned FetchXML that ran. Invalid FetchXML is reported and nothing runs.
|
|
43
|
+
- **What you build is what runs** β The generated FetchXML contains exactly what is in the tree; nothing is injected, so what you copy, save as a view, or send to another tool matches what executes
|
|
31
44
|
- **Copy to clipboard** β One-click copy of generated FetchXML, available in both read-only and editor modes
|
|
32
|
-
- **Alias validation** β Invalid alias characters are sanitized in real time in the property editors;
|
|
45
|
+
- **Alias validation** β Invalid alias characters are sanitized in real time in the property editors; Parse to Tree corrects invalid aliases, lists each correction, and updates every reference to a corrected alias (condition and order `entityname`, `valueof`, aggregate order aliases) so the query keeps working
|
|
46
|
+
- **Accurate validation** β Everything in the FetchXML reference is supported, plus undocumented behaviour verified to work (e.g. `link-type="natural"`). Every rule is checked against a live Dataverse environment:
|
|
47
|
+
- **errors** block execution β only for FetchXML Dataverse is known to reject;
|
|
48
|
+
- **warnings** offer **Execute anyway** β only where it can't be determined in the client (e.g. a link-entity without `from`/`to`, which is valid only for system many-to-many relationships);
|
|
49
|
+
- **notes** never block (e.g. `xmlns:*` from other tools, which Dataverse ignores).
|
|
50
|
+
- **Query-level checks** β Validate and Execute catch the mistakes Dataverse rejects, each verified on a live environment:
|
|
51
|
+
- aggregate queries where an attribute has no Group by / aggregate or no alias;
|
|
52
|
+
- an aggregate order using an alias from another entity;
|
|
53
|
+
- `aggregatelimit` combined with an order;
|
|
54
|
+
- duplicate aliases;
|
|
55
|
+
- an invalid union hint;
|
|
56
|
+
- misuse of `rowaggregate`;
|
|
57
|
+
- `top` together with `count`, `page` or `returntotalrecordcount`, and `page` below 1;
|
|
58
|
+
- comparing to another attribute (`valueof`) with an operator other than eq, ne, gt, ge, lt or le, or through a link-entity without an alias;
|
|
59
|
+
- a link-entity inside a filter whose type isn't any / not any / all / not all;
|
|
60
|
+
- attributes, all-attributes or orders in an exists, in, any, not any, all or not all link-entity.
|
|
61
|
+
|
|
62
|
+
Settings Dataverse accepts but ignores (such as `aggregatelimit` on a non-aggregate query, `aggregate` on a condition, which FetchXML can't use to filter on aggregate values, or `visible` on a link-entity) are shown as notes only.
|
|
63
|
+
- **Boolean spellings** β `"1"`/`"0"` and other spellings Dataverse accepts are read correctly (e.g. `usertimezone="1"`, `descending="1"`, `enableprefiltering="1"`), so Parse to Tree never flips or drops them.
|
|
64
|
+
- **Lossless Parse to Tree** β Every attribute in the FetchXML reference is kept, including `datasource`, `aggregatelimit`, `useraworderby`, query hints (`options`), `latematerialize`, `<order alias>`, `distinct` counts, `rowaggregate` and quick find flags. So are unknown, namespaced and legacy attributes (e.g. `xmlns:generator` from SQL 4 CDS, `version`/`mapping` from Advanced Find, `uiname`/`uitype` from saved views). Every FetchXML example in the Microsoft Learn FetchXML articles round-trips without loss.
|
|
65
|
+
- **No silent changes** β If Parse to Tree must correct something Dataverse would reject (for example an invalid alias), a confirmation dialog lists every change first
|
|
33
66
|
- **LayoutXML preview** β See the column layout configuration
|
|
34
67
|
|
|
35
68
|
### π₯ Load & Save Views
|
|
@@ -49,7 +82,7 @@ A powerful, modern FetchXML query builder and data explorer for [Power Platform
|
|
|
49
82
|
- **Run workflows** β Execute on-demand workflows on selected records with batch execution and progress tracking
|
|
50
83
|
|
|
51
84
|
### π Bulk Attribute Selection
|
|
52
|
-
- **Select Attributes dialog** β Multi-select attributes from a
|
|
85
|
+
- **Select Attributes dialog** β Multi-select attributes from a sortable, resizable grid (display name, logical name, type). Long names end with an ellipsis and show in full on hover. Search by display or logical name, filter by type, show selected only, and see how many are selected. Opens from the entity and link-entity Add menus
|
|
53
86
|
- **Smart updates** β Adds new selections and removes deselected attributes while preserving existing order and properties
|
|
54
87
|
- **Search & filter** β Real-time filtering across logical name, display name, and data type columns
|
|
55
88
|
|
|
@@ -59,19 +92,19 @@ A powerful, modern FetchXML query builder and data explorer for [Power Platform
|
|
|
59
92
|
- **C# FetchExpression** β Simple `new FetchExpression(@"...")` wrapper using a verbatim string literal
|
|
60
93
|
- **JavaScript** β `Xrm.WebApi.retrieveMultipleRecords` call for model-driven apps and PCF components
|
|
61
94
|
- **pac CLI** β `pac org fetch --xml "..."` command for the Power Platform CLI
|
|
62
|
-
- **Power Automate** β Field-by-field form mirroring the Dataverse "List rows" connector UI; table name resolved from `EntityDefinitions` metadata (not a heuristic), each field individually copyable
|
|
63
|
-
- **Web API** β Full OData URL with request headers, cURL snippet
|
|
95
|
+
- **Power Automate** β Field-by-field form mirroring the Dataverse "List rows" connector UI; table name resolved from `EntityDefinitions` metadata (not a heuristic), each field individually copyable; Top Count is taken only from `top` (`count` is a page size)
|
|
96
|
+
- **Web API** β Full OData URL with request headers (including `Prefer: odata.include-annotations="*"` for formatted values and paging cookies), the documented paging-cookie steps, a cURL snippet and a PowerShell `Invoke-RestMethod` example; entity set name resolved from metadata
|
|
64
97
|
- **SQL** β Dataverse-generated T-SQL via `FetchXMLToSQL` (undocumented API, labelled Preview)
|
|
65
98
|
|
|
66
99
|
### π¨ User Experience
|
|
67
|
-
- **Dark/Light themes** β
|
|
100
|
+
- **Dark/Light themes** β Every surface (tree, properties, editors, results grid, panels and dialogs) uses the Fluent UI v9 light or dark theme and follows the Power Platform ToolBox theme live: changing it in ToolBox settings, including **System**, and changing the OS theme while ToolBox is on System, update the tool without a reload
|
|
68
101
|
- **Lazy metadata loading** β Loads only what's needed, when it's needed
|
|
69
102
|
- **Intelligent caching** β In-memory cache prevents duplicate API calls per session
|
|
70
103
|
- **Resizable panes** β Adjust split-pane layout to your preference
|
|
71
104
|
- **Keyboard shortcuts** β `Ctrl+Enter` to execute query, copy XML to clipboard
|
|
72
105
|
- **Display settings** β Toggle logical names vs display names in column headers; choose formatted, raw, or both value modes in the grid and exports
|
|
73
106
|
- **Query scope settings** β Control which entities appear in the entity picker: *Publisher + Solution* (full filter), *Solution Only*, or *All Entities* (no filter). Persisted across sessions.
|
|
74
|
-
- **Advanced Find Only toggle** β When on (default),
|
|
107
|
+
- **Advanced Find Only toggle** β When on (default), entities, attributes and relationships are limited to the ones Advanced Find shows (`IsValidForAdvancedFind`), in every entity scope. Turn it off to build queries Advanced Find can't: system and customization entities (saved views, forms, plug-in steps, solution components), intersect entities (team membership, user roles), and hidden attributes and relationships. Attributes that can't be read (`IsValidForRead = false`) are never listed. Hidden label attributes (such as `statuscodename`) can be filtered and sorted. Toggling is instant: metadata is fetched once and filtered locally. Attributes already in a query keep their operators and value inputs either way.
|
|
75
108
|
|
|
76
109
|
### π Tool-to-Tool (T2T) Integration
|
|
77
110
|
- **Send to Tool button** β Launch another PPTB tool directly from FetchXML Studio, pre-loading it with the current FetchXML query and active Dataverse connection (one-way handoff).
|
|
@@ -119,7 +152,7 @@ A powerful, modern FetchXML query builder and data explorer for [Power Platform
|
|
|
119
152
|
- Connection to a Dataverse environment
|
|
120
153
|
|
|
121
154
|
### Installation
|
|
122
|
-
FetchXML Studio is available as a tool in Power Platform ToolBox. Install it from the tool gallery or load as a custom tool.
|
|
155
|
+
FetchXML Studio is available as a tool in Power Platform ToolBox. Install it from the tool gallery or load as a custom tool. The package is published on npm as [`@mohsinonxrm/pptb-fetchxml-studio`](https://www.npmjs.com/package/@mohsinonxrm/pptb-fetchxml-studio).
|
|
123
156
|
|
|
124
157
|
## π οΈ Development
|
|
125
158
|
|
|
@@ -127,11 +160,11 @@ FetchXML Studio is available as a tool in Power Platform ToolBox. Install it fro
|
|
|
127
160
|
|
|
128
161
|
```bash
|
|
129
162
|
# Clone the repository
|
|
130
|
-
git clone https://github.com/mohsinonxrm/pptb-fetchxml-studio.git
|
|
131
|
-
cd pptb-fetchxml-studio
|
|
163
|
+
git clone https://github.com/mohsinonxrm/pptb-mxrm-fetchxml-studio.git
|
|
164
|
+
cd pptb-mxrm-fetchxml-studio
|
|
132
165
|
|
|
133
|
-
# Install
|
|
134
|
-
npm
|
|
166
|
+
# Install the exact dependency versions from package-lock.json
|
|
167
|
+
npm ci
|
|
135
168
|
|
|
136
169
|
# Start development server
|
|
137
170
|
npm run dev
|
|
@@ -149,10 +182,28 @@ npm run preview
|
|
|
149
182
|
# Validate package manifest against PPTB registry rules
|
|
150
183
|
npm run validate
|
|
151
184
|
|
|
152
|
-
# Finalize for publishing (
|
|
185
|
+
# Finalize for publishing (validate + build)
|
|
153
186
|
npm run finalize-package
|
|
154
187
|
```
|
|
155
188
|
|
|
189
|
+
**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.1-beta.8`, and `icons/icon.svg` for releases.
|
|
190
|
+
|
|
191
|
+
**Dependencies.** `package-lock.json` is committed and pins every dependency with an integrity hash. Use `npm ci` for a clean install. After changing dependencies, run `npm install` and commit the updated lockfile.
|
|
192
|
+
|
|
193
|
+
### Testing
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
# Unit tests (Vitest + jsdom): parser, serializer, rules, round-trip over the Microsoft Learn examples
|
|
197
|
+
npm test
|
|
198
|
+
|
|
199
|
+
# Watch mode / coverage
|
|
200
|
+
npm run test:watch
|
|
201
|
+
npm run coverage
|
|
202
|
+
|
|
203
|
+
# Lint
|
|
204
|
+
npm run lint
|
|
205
|
+
```
|
|
206
|
+
|
|
156
207
|
### Debug Logging
|
|
157
208
|
|
|
158
209
|
Enable debug logging in the browser console:
|
|
@@ -180,11 +231,12 @@ disableAllDebug();
|
|
|
180
231
|
| **React** | 18.3 | UI framework |
|
|
181
232
|
| **TypeScript** | 5.9 | Type-safe development |
|
|
182
233
|
| **Vite** | 7 | Build tooling and HMR |
|
|
183
|
-
| **Fluent UI v9** | 9.
|
|
234
|
+
| **Fluent UI v9** | 9.74 | Microsoft design system (Tree, DataGrid, Tabs, Drawer, etc.) |
|
|
184
235
|
| **Monaco Editor** | 0.54 | VS Code XML editor for FetchXML authoring |
|
|
185
236
|
| **react-window** | 2 | Virtualized list rendering for large datasets |
|
|
186
237
|
| **ExcelJS** | 4.4 | Native `.xlsx` generation with typed cells |
|
|
187
238
|
| **@pptb/types** | 1.2.3 | Power Platform ToolBox host API types (`window.dataverseAPI`, `window.toolboxAPI`) |
|
|
239
|
+
| **Vitest** | 5 | Unit tests (jsdom) |
|
|
188
240
|
|
|
189
241
|
## π Project Structure
|
|
190
242
|
|
|
@@ -202,12 +254,16 @@ src/
|
|
|
202
254
|
β βββ model/
|
|
203
255
|
β β βββ nodes.ts # FetchXML node TypeScript definitions
|
|
204
256
|
β β βββ fetchxml.ts # FetchXML XML generation
|
|
205
|
-
β β βββ fetchxmlParser.ts # FetchXML XML β node tree parser
|
|
257
|
+
β β βββ fetchxmlParser.ts # FetchXML XML β node tree parser (severity-classified findings)
|
|
258
|
+
β β βββ fetchxmlRules.ts # Query-level rules shared by the parser and editors
|
|
259
|
+
β β βββ attributeCapabilities.ts # What each attribute type supports (sort, group by, aggregates, valueof)
|
|
260
|
+
β β βββ aggregateToggle.ts # What turning off an aggregate query changes
|
|
206
261
|
β β βββ fetchxmlIntellisense.ts # Intellisense / autocomplete helpers
|
|
207
262
|
β β βββ layoutxml.ts # LayoutXML generation
|
|
208
263
|
β β βββ operators.ts # Operator definitions by attribute type
|
|
209
264
|
β β βββ displaySettings.ts # Display settings types and defaults
|
|
210
|
-
β β
|
|
265
|
+
β β βββ treeUtils.ts # Tree traversal utilities
|
|
266
|
+
β β βββ __fixtures__/ # FetchXML examples from Microsoft Learn (MIT) for round-trip tests
|
|
211
267
|
β βββ engine/
|
|
212
268
|
β β βββ queryExpressionTypes.ts # QE JSON schema interfaces (number | string enums)
|
|
213
269
|
β β βββ queryExpressionCodegen.ts # C# SDK code emitter (resolveEnum, unwrapODataValue)
|
|
@@ -218,7 +274,11 @@ src/
|
|
|
218
274
|
β βββ ui/
|
|
219
275
|
β βββ LeftPane/ # Tree view + context-aware properties panel
|
|
220
276
|
β β βββ PropertiesPanel/
|
|
221
|
-
β β
|
|
277
|
+
β β βββ editors/ # One editor per node type
|
|
278
|
+
β β βββ fields.tsx # InfoField, InfoCheckbox, NumberField, LeftoverSetting
|
|
279
|
+
β β βββ docLinks.ts # Microsoft Learn links used by the info popovers
|
|
280
|
+
β β βββ ruleFindings.ts # Rule findings β field validation
|
|
281
|
+
β β βββ useEditorMetadata.ts # Attribute / entity metadata hooks
|
|
222
282
|
β βββ RightPane/ # Monaco editor, LayoutXML viewer, results grid,
|
|
223
283
|
β β # code generation panel, Power Automate pane
|
|
224
284
|
β βββ Toolbar/ # Entity selector, load view picker, save button,
|
|
@@ -245,21 +305,26 @@ src/
|
|
|
245
305
|
| All-attributes | β
|
|
|
246
306
|
| Filters (and/or) | β
|
|
|
247
307
|
| Nested filters | β
|
|
|
248
|
-
| All condition operators | β
|
|
|
308
|
+
| All condition operators (offered per attribute from the documented data types and a live operator Γ attribute-type matrix; value inputs match each operator: whole numbers for "x" operators, period + year for fiscal period operators) | β
|
|
|
249
309
|
| Link-entity (joins) | β
|
|
|
250
310
|
| Inner/outer joins | β
|
|
|
251
|
-
| N:N relationships | β
|
|
|
311
|
+
| N:N relationships (through the intersect entity) | β
|
|
|
252
312
|
| Orders (sorting) | β
|
|
|
253
313
|
| Multi-column sort | β
|
|
|
254
314
|
| Aggregate queries | β
|
|
|
255
315
|
| Groupby | β
|
|
|
256
316
|
| Distinct | β
|
|
|
257
317
|
| Top/Count | β
|
|
|
258
|
-
| Paging with cookies | β
|
|
|
318
|
+
| Paging with cookies (`fetchxmlpagingcookie`), page-number paging when Dataverse returns no cookie, views via `@odata.nextLink` | β
|
|
|
259
319
|
| Value-of conditions | β
|
|
|
260
320
|
| Entity name on conditions | β
|
|
|
261
321
|
| Filter link-entity (any/all) | β
|
|
|
262
322
|
| Query hints | β
|
|
|
323
|
+
| Order by alias (aggregate) | β
|
|
|
324
|
+
| Quick find, union hint | β
|
|
|
325
|
+
| Row aggregate (hierarchy child count) | β
|
|
|
326
|
+
| Long-term retention (`datasource`) | β
|
|
|
327
|
+
| Validation against Dataverse rules | β
|
|
|
263
328
|
|
|
264
329
|
## π Callee Contract (`pptb.config.json`)
|
|
265
330
|
|
|
@@ -342,7 +407,6 @@ This project follows [Conventional Commits](https://www.conventionalcommits.org/
|
|
|
342
407
|
- [ ] Import/export query definitions (JSON)
|
|
343
408
|
- [ ] Quick query templates
|
|
344
409
|
- [ ] Query history
|
|
345
|
-
- [ ] Web API code generation
|
|
346
410
|
- [ ] Query performance insights
|
|
347
411
|
- [ ] Syntax validation in Monaco
|
|
348
412
|
|