fluentui-extended 2026.2.6 → 2026.2.7
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 +2 -2
- package/dist/index.d.mts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +157 -122
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +157 -122
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -349,7 +349,7 @@ The Validate button checks query structure and optionally tests against the Dyna
|
|
|
349
349
|
```
|
|
350
350
|
|
|
351
351
|
When running inside Dynamics 365:
|
|
352
|
-
-
|
|
352
|
+
- Uses native fetch to `/api/data/v9.2/` endpoints
|
|
353
353
|
- Executes a test query with `$top=1&$count=true`
|
|
354
354
|
- Shows record count or API error message
|
|
355
355
|
|
|
@@ -405,7 +405,7 @@ const fields: QueryBuilderField[] = [
|
|
|
405
405
|
|------|------|---------|-------------|
|
|
406
406
|
| `entityName` | `string` | - | Logical name of the entity (required) |
|
|
407
407
|
| `entityDisplayName` | `string` | - | Display name shown in header |
|
|
408
|
-
| `fields` | `QueryBuilderField[]` | - | Fields for filtering (auto-loaded
|
|
408
|
+
| `fields` | `QueryBuilderField[]` | - | Fields for filtering (auto-loaded via Web API if omitted) |
|
|
409
409
|
| `initialFetchXml` | `string` | - | FetchXML to pre-populate the query builder |
|
|
410
410
|
| `initialState` | `QueryBuilderState` | - | Initial query state object |
|
|
411
411
|
| `onSerializedChange` | `(result: QueryBuilderApplyResult) => void` | - | Called when query changes |
|
package/dist/index.d.mts
CHANGED
|
@@ -156,7 +156,7 @@ interface QueryBuilderLookupOption {
|
|
|
156
156
|
}
|
|
157
157
|
interface QueryBuilderProps {
|
|
158
158
|
entityName: string;
|
|
159
|
-
/** Entity set name for OData queries (e.g., "accounts"). If not provided, will be fetched from
|
|
159
|
+
/** Entity set name for OData queries (e.g., "accounts"). If not provided, will be fetched from the Web API. */
|
|
160
160
|
entitySetName?: string;
|
|
161
161
|
entityDisplayName?: string;
|
|
162
162
|
fields?: QueryBuilderField[];
|
|
@@ -189,6 +189,8 @@ interface QueryBuilderProps {
|
|
|
189
189
|
onSerializedChange?: (result: QueryBuilderApplyResult) => void;
|
|
190
190
|
/** Callback for lookup field search - returns options for the lookup dropdown */
|
|
191
191
|
onLookupSearch?: (fieldId: string, searchText: string) => Promise<QueryBuilderLookupOption[]> | QueryBuilderLookupOption[];
|
|
192
|
+
/** Callback to fetch fields for a related entity. If provided, this is used instead of the native Web API. */
|
|
193
|
+
onFetchEntityFields?: (entityLogicalName: string) => Promise<QueryBuilderField[]>;
|
|
192
194
|
}
|
|
193
195
|
|
|
194
196
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -156,7 +156,7 @@ interface QueryBuilderLookupOption {
|
|
|
156
156
|
}
|
|
157
157
|
interface QueryBuilderProps {
|
|
158
158
|
entityName: string;
|
|
159
|
-
/** Entity set name for OData queries (e.g., "accounts"). If not provided, will be fetched from
|
|
159
|
+
/** Entity set name for OData queries (e.g., "accounts"). If not provided, will be fetched from the Web API. */
|
|
160
160
|
entitySetName?: string;
|
|
161
161
|
entityDisplayName?: string;
|
|
162
162
|
fields?: QueryBuilderField[];
|
|
@@ -189,6 +189,8 @@ interface QueryBuilderProps {
|
|
|
189
189
|
onSerializedChange?: (result: QueryBuilderApplyResult) => void;
|
|
190
190
|
/** Callback for lookup field search - returns options for the lookup dropdown */
|
|
191
191
|
onLookupSearch?: (fieldId: string, searchText: string) => Promise<QueryBuilderLookupOption[]> | QueryBuilderLookupOption[];
|
|
192
|
+
/** Callback to fetch fields for a related entity. If provided, this is used instead of the native Web API. */
|
|
193
|
+
onFetchEntityFields?: (entityLogicalName: string) => Promise<QueryBuilderField[]>;
|
|
192
194
|
}
|
|
193
195
|
|
|
194
196
|
/**
|
package/dist/index.js
CHANGED
|
@@ -2532,9 +2532,8 @@ var LookupValueInput = ({
|
|
|
2532
2532
|
const [lookupLoading, setLookupLoading] = React3__namespace.useState(false);
|
|
2533
2533
|
const [resultCount, setResultCount] = React3__namespace.useState(0);
|
|
2534
2534
|
const [headerText, setHeaderText] = React3__namespace.useState("");
|
|
2535
|
-
const
|
|
2536
|
-
|
|
2537
|
-
if (!xrm?.WebApi?.retrieveMultipleRecords || !targets || targets.length === 0) {
|
|
2535
|
+
const searchUsingWebApi = React3__namespace.useCallback(async (searchText, limit = 15) => {
|
|
2536
|
+
if (!targets || targets.length === 0) {
|
|
2538
2537
|
return { results: [], entityDisplayName: "" };
|
|
2539
2538
|
}
|
|
2540
2539
|
const results = [];
|
|
@@ -2546,12 +2545,20 @@ var LookupValueInput = ({
|
|
|
2546
2545
|
}
|
|
2547
2546
|
try {
|
|
2548
2547
|
const nameAttr = target.primaryNameAttribute;
|
|
2549
|
-
let
|
|
2548
|
+
let queryOptions = `$select=${nameAttr}&$top=${limit}`;
|
|
2550
2549
|
if (searchText) {
|
|
2551
|
-
|
|
2550
|
+
queryOptions += `&$filter=contains(${nameAttr},'${searchText.replace(/'/g, "''")}')`;
|
|
2552
2551
|
}
|
|
2553
|
-
const response = await
|
|
2554
|
-
|
|
2552
|
+
const response = await fetch(`/api/data/v9.2/${target.entitySetName}?${queryOptions}`, {
|
|
2553
|
+
headers: {
|
|
2554
|
+
"OData-MaxVersion": "4.0",
|
|
2555
|
+
"OData-Version": "4.0",
|
|
2556
|
+
"Accept": "application/json"
|
|
2557
|
+
}
|
|
2558
|
+
});
|
|
2559
|
+
if (!response.ok) continue;
|
|
2560
|
+
const data = await response.json();
|
|
2561
|
+
const records = data.value || [];
|
|
2555
2562
|
for (const record of records) {
|
|
2556
2563
|
const idField = `${target.entityLogicalName}id`;
|
|
2557
2564
|
const id = record[idField] || record.id || "";
|
|
@@ -2570,12 +2577,11 @@ var LookupValueInput = ({
|
|
|
2570
2577
|
}, [targets]);
|
|
2571
2578
|
React3__namespace.useEffect(() => {
|
|
2572
2579
|
const loadInitialRecords = async () => {
|
|
2573
|
-
const xrm = window.Xrm;
|
|
2574
2580
|
const hasValidTargets2 = targets && targets.length > 0 && targets.some((t) => t.entitySetName && t.primaryNameAttribute);
|
|
2575
|
-
if (!disabled && hasValidTargets2 &&
|
|
2581
|
+
if (!disabled && hasValidTargets2 && !onLookupSearch) {
|
|
2576
2582
|
setLookupLoading(true);
|
|
2577
2583
|
try {
|
|
2578
|
-
const searchResult = await
|
|
2584
|
+
const searchResult = await searchUsingWebApi("", 5);
|
|
2579
2585
|
setLookupOptions(searchResult.results);
|
|
2580
2586
|
setResultCount(searchResult.results.length);
|
|
2581
2587
|
setHeaderText(searchResult.entityDisplayName);
|
|
@@ -2585,7 +2591,7 @@ var LookupValueInput = ({
|
|
|
2585
2591
|
}
|
|
2586
2592
|
};
|
|
2587
2593
|
loadInitialRecords();
|
|
2588
|
-
}, [targets, disabled, onLookupSearch,
|
|
2594
|
+
}, [targets, disabled, onLookupSearch, searchUsingWebApi]);
|
|
2589
2595
|
const handleSearchChange = React3__namespace.useCallback(
|
|
2590
2596
|
async (searchText) => {
|
|
2591
2597
|
setLookupLoading(true);
|
|
@@ -2601,7 +2607,7 @@ var LookupValueInput = ({
|
|
|
2601
2607
|
}));
|
|
2602
2608
|
entityName = targets?.[0]?.displayName || "";
|
|
2603
2609
|
} else {
|
|
2604
|
-
const searchResult = await
|
|
2610
|
+
const searchResult = await searchUsingWebApi(searchText);
|
|
2605
2611
|
results = searchResult.results;
|
|
2606
2612
|
entityName = searchResult.entityDisplayName;
|
|
2607
2613
|
}
|
|
@@ -2612,7 +2618,7 @@ var LookupValueInput = ({
|
|
|
2612
2618
|
setLookupLoading(false);
|
|
2613
2619
|
}
|
|
2614
2620
|
},
|
|
2615
|
-
[fieldId, onLookupSearch,
|
|
2621
|
+
[fieldId, onLookupSearch, searchUsingWebApi, targets]
|
|
2616
2622
|
);
|
|
2617
2623
|
const handleOptionSelect = React3__namespace.useCallback(
|
|
2618
2624
|
(option) => {
|
|
@@ -2727,67 +2733,98 @@ var QueryBuilder = (props) => {
|
|
|
2727
2733
|
}
|
|
2728
2734
|
setLoading(true);
|
|
2729
2735
|
try {
|
|
2730
|
-
const
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2736
|
+
const entityResponse = await fetch(
|
|
2737
|
+
`/api/data/v9.2/EntityDefinitions(LogicalName='${props.entityName}')?$select=EntitySetName,DisplayName,PrimaryNameAttribute`,
|
|
2738
|
+
{
|
|
2739
|
+
headers: {
|
|
2740
|
+
"OData-MaxVersion": "4.0",
|
|
2741
|
+
"OData-Version": "4.0",
|
|
2742
|
+
"Accept": "application/json"
|
|
2743
|
+
}
|
|
2735
2744
|
}
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
+
);
|
|
2746
|
+
if (!entityResponse.ok) {
|
|
2747
|
+
console.warn("[QueryBuilder] Failed to fetch entity metadata");
|
|
2748
|
+
return;
|
|
2749
|
+
}
|
|
2750
|
+
const entityMetadata = await entityResponse.json();
|
|
2751
|
+
if (entityMetadata?.EntitySetName && !disposed) {
|
|
2752
|
+
setEntitySetName(entityMetadata.EntitySetName);
|
|
2753
|
+
}
|
|
2754
|
+
const attributesResponse = await fetch(
|
|
2755
|
+
`/api/data/v9.2/EntityDefinitions(LogicalName='${props.entityName}')/Attributes?$select=LogicalName,SchemaName,DisplayName,AttributeType,AttributeTypeName`,
|
|
2756
|
+
{
|
|
2757
|
+
headers: {
|
|
2758
|
+
"OData-MaxVersion": "4.0",
|
|
2759
|
+
"OData-Version": "4.0",
|
|
2760
|
+
"Accept": "application/json"
|
|
2761
|
+
}
|
|
2762
|
+
}
|
|
2763
|
+
);
|
|
2764
|
+
if (!attributesResponse.ok) {
|
|
2765
|
+
console.warn("[QueryBuilder] Failed to fetch entity attributes");
|
|
2766
|
+
return;
|
|
2767
|
+
}
|
|
2768
|
+
const attributesData = await attributesResponse.json();
|
|
2769
|
+
const attributesArray = attributesData.value || [];
|
|
2770
|
+
const targetEntityNames = /* @__PURE__ */ new Set();
|
|
2771
|
+
for (const attribute of attributesArray) {
|
|
2772
|
+
if (Array.isArray(attribute?.Targets)) {
|
|
2773
|
+
for (const target of attribute.Targets) {
|
|
2774
|
+
const entityName = typeof target === "string" ? target : target?.entityLogicalName;
|
|
2775
|
+
if (entityName) targetEntityNames.add(entityName);
|
|
2745
2776
|
}
|
|
2746
2777
|
}
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2778
|
+
}
|
|
2779
|
+
const targetMetadataCache = {};
|
|
2780
|
+
for (const targetEntityName of targetEntityNames) {
|
|
2781
|
+
try {
|
|
2782
|
+
const targetResponse = await fetch(
|
|
2783
|
+
`/api/data/v9.2/EntityDefinitions(LogicalName='${targetEntityName}')?$select=EntitySetName,DisplayName,PrimaryNameAttribute`,
|
|
2784
|
+
{
|
|
2785
|
+
headers: {
|
|
2786
|
+
"OData-MaxVersion": "4.0",
|
|
2787
|
+
"OData-Version": "4.0",
|
|
2788
|
+
"Accept": "application/json"
|
|
2789
|
+
}
|
|
2790
|
+
}
|
|
2791
|
+
);
|
|
2792
|
+
if (targetResponse.ok) {
|
|
2793
|
+
const targetMeta = await targetResponse.json();
|
|
2751
2794
|
targetMetadataCache[targetEntityName] = {
|
|
2752
2795
|
entitySetName: targetMeta?.EntitySetName,
|
|
2753
2796
|
displayName: targetMeta?.DisplayName?.UserLocalizedLabel?.Label || targetMeta?.LogicalName,
|
|
2754
2797
|
primaryNameAttribute: targetMeta?.PrimaryNameAttribute
|
|
2755
2798
|
};
|
|
2756
|
-
} catch (targetErr) {
|
|
2757
|
-
console.warn(`[QueryBuilder] Could not fetch metadata for target entity "${targetEntityName}":`, targetErr);
|
|
2758
2799
|
}
|
|
2800
|
+
} catch (targetErr) {
|
|
2801
|
+
console.warn(`[QueryBuilder] Could not fetch metadata for target entity "${targetEntityName}":`, targetErr);
|
|
2759
2802
|
}
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
})).filter((option) => option.value !== void 0 && option.value !== null) : void 0;
|
|
2767
|
-
const targets = dataType === "lookup" && Array.isArray(attribute.Targets) ? attribute.Targets.map((target) => {
|
|
2768
|
-
const entityLogicalName = typeof target === "string" ? target : target?.entityLogicalName || target;
|
|
2769
|
-
const cached = targetMetadataCache[entityLogicalName] || {};
|
|
2770
|
-
return {
|
|
2771
|
-
entityLogicalName,
|
|
2772
|
-
entitySetName: target?.entitySetName || cached.entitySetName,
|
|
2773
|
-
displayName: target?.displayName || cached.displayName,
|
|
2774
|
-
primaryNameAttribute: target?.primaryNameAttribute || cached.primaryNameAttribute
|
|
2775
|
-
};
|
|
2776
|
-
}) : void 0;
|
|
2777
|
-
const displayName = attribute.DisplayName;
|
|
2778
|
-
const label = typeof displayName === "string" ? displayName : displayName?.UserLocalizedLabel?.Label || attribute.SchemaName || attribute.LogicalName;
|
|
2803
|
+
}
|
|
2804
|
+
const resolvedFields = attributesArray.filter((attribute) => attribute?.LogicalName && attribute?.IsValidForAdvancedFind !== false).map((attribute) => {
|
|
2805
|
+
const dataType = dataTypeFromAttribute(attribute);
|
|
2806
|
+
const targets = dataType === "lookup" && Array.isArray(attribute.Targets) ? attribute.Targets.map((target) => {
|
|
2807
|
+
const entityLogicalName = typeof target === "string" ? target : target?.entityLogicalName || target;
|
|
2808
|
+
const cached = targetMetadataCache[entityLogicalName] || {};
|
|
2779
2809
|
return {
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
options,
|
|
2785
|
-
targets
|
|
2810
|
+
entityLogicalName,
|
|
2811
|
+
entitySetName: target?.entitySetName || cached.entitySetName,
|
|
2812
|
+
displayName: target?.displayName || cached.displayName,
|
|
2813
|
+
primaryNameAttribute: target?.primaryNameAttribute || cached.primaryNameAttribute
|
|
2786
2814
|
};
|
|
2787
|
-
})
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2815
|
+
}) : void 0;
|
|
2816
|
+
const displayName = attribute.DisplayName;
|
|
2817
|
+
const label = typeof displayName === "string" ? displayName : displayName?.UserLocalizedLabel?.Label || attribute.SchemaName || attribute.LogicalName;
|
|
2818
|
+
return {
|
|
2819
|
+
id: attribute.LogicalName,
|
|
2820
|
+
label,
|
|
2821
|
+
schemaName: attribute.SchemaName,
|
|
2822
|
+
dataType,
|
|
2823
|
+
targets
|
|
2824
|
+
};
|
|
2825
|
+
}).sort((left, right) => String(left.label).localeCompare(String(right.label), void 0, { sensitivity: "base" }));
|
|
2826
|
+
if (!disposed && resolvedFields.length > 0) {
|
|
2827
|
+
setAvailableFields(resolvedFields);
|
|
2791
2828
|
}
|
|
2792
2829
|
} catch (error) {
|
|
2793
2830
|
console.error("[QueryBuilder] Error loading fields:", error);
|
|
@@ -2873,45 +2910,48 @@ var QueryBuilder = (props) => {
|
|
|
2873
2910
|
const loadRelatedEntityFields = React3__namespace.useCallback(
|
|
2874
2911
|
async (groupId, conditionId, targetEntity) => {
|
|
2875
2912
|
try {
|
|
2876
|
-
|
|
2877
|
-
if (
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2913
|
+
let resolvedFields = [];
|
|
2914
|
+
if (props.onFetchEntityFields) {
|
|
2915
|
+
resolvedFields = await props.onFetchEntityFields(targetEntity);
|
|
2916
|
+
} else {
|
|
2917
|
+
const response = await fetch(
|
|
2918
|
+
`/api/data/v9.2/EntityDefinitions(LogicalName='${targetEntity}')/Attributes?$select=LogicalName,SchemaName,DisplayName,AttributeType,AttributeTypeName`,
|
|
2919
|
+
{
|
|
2920
|
+
headers: {
|
|
2921
|
+
"OData-MaxVersion": "4.0",
|
|
2922
|
+
"OData-Version": "4.0",
|
|
2923
|
+
"Accept": "application/json"
|
|
2924
|
+
}
|
|
2925
|
+
}
|
|
2926
|
+
);
|
|
2927
|
+
if (!response.ok) {
|
|
2928
|
+
console.warn("[QueryBuilder] Failed to fetch entity metadata:", response.status, response.statusText);
|
|
2929
|
+
return;
|
|
2930
|
+
}
|
|
2931
|
+
const data = await response.json();
|
|
2932
|
+
const attributesArray = data.value || [];
|
|
2933
|
+
if (attributesArray.length === 0) {
|
|
2934
|
+
console.warn("[QueryBuilder] No attributes found for entity:", targetEntity);
|
|
2935
|
+
return;
|
|
2936
|
+
}
|
|
2937
|
+
resolvedFields = attributesArray.filter((attr) => {
|
|
2938
|
+
if (!attr?.LogicalName) return false;
|
|
2939
|
+
const attrType = attr.AttributeType || attr.AttributeTypeName?.Value;
|
|
2940
|
+
if (attrType === "Virtual" || attrType === "CalendarRules") return false;
|
|
2941
|
+
if (attrType === "Uniqueidentifier" && !attr.LogicalName.endsWith("id")) return false;
|
|
2942
|
+
return true;
|
|
2943
|
+
}).map((attr) => {
|
|
2944
|
+
const dataType = dataTypeFromAttribute(attr);
|
|
2945
|
+
const displayName = attr.DisplayName;
|
|
2946
|
+
const label = typeof displayName === "string" ? displayName : displayName?.UserLocalizedLabel?.Label || attr.SchemaName || attr.LogicalName;
|
|
2947
|
+
return {
|
|
2948
|
+
id: attr.LogicalName,
|
|
2949
|
+
label,
|
|
2950
|
+
schemaName: attr.SchemaName,
|
|
2951
|
+
dataType
|
|
2952
|
+
};
|
|
2953
|
+
}).sort((a, b) => String(a.label).localeCompare(String(b.label), void 0, { sensitivity: "base" }));
|
|
2891
2954
|
}
|
|
2892
|
-
const resolvedFields = attributesArray.filter((attr) => {
|
|
2893
|
-
if (!attr?.LogicalName) return false;
|
|
2894
|
-
const attrType = attr.AttributeType || attr.AttributeTypeName?.Value;
|
|
2895
|
-
if (attrType === "Virtual" || attrType === "CalendarRules") return false;
|
|
2896
|
-
if (attrType === "Uniqueidentifier" && !attr.LogicalName.endsWith("id")) return false;
|
|
2897
|
-
return true;
|
|
2898
|
-
}).map((attr) => {
|
|
2899
|
-
const dataType = dataTypeFromAttribute(attr);
|
|
2900
|
-
const optionSet = attr?.OptionSet?.Options;
|
|
2901
|
-
const options = dataType === "optionset" && Array.isArray(optionSet) ? optionSet.map((opt) => ({
|
|
2902
|
-
label: opt?.Label?.UserLocalizedLabel?.Label || opt?.Label || String(opt?.Value),
|
|
2903
|
-
value: opt?.Value
|
|
2904
|
-
})).filter((opt) => opt.value !== void 0 && opt.value !== null) : void 0;
|
|
2905
|
-
const displayName = attr.DisplayName;
|
|
2906
|
-
const label = typeof displayName === "string" ? displayName : displayName?.UserLocalizedLabel?.Label || attr.SchemaName || attr.LogicalName;
|
|
2907
|
-
return {
|
|
2908
|
-
id: attr.LogicalName,
|
|
2909
|
-
label,
|
|
2910
|
-
schemaName: attr.SchemaName,
|
|
2911
|
-
dataType,
|
|
2912
|
-
options
|
|
2913
|
-
};
|
|
2914
|
-
}).sort((a, b) => String(a.label).localeCompare(String(b.label), void 0, { sensitivity: "base" }));
|
|
2915
2955
|
if (resolvedFields.length > 0) {
|
|
2916
2956
|
const defaultCondition = createCondition(resolvedFields[0]);
|
|
2917
2957
|
updateGroup(groupId, (group) => ({
|
|
@@ -2931,7 +2971,7 @@ var QueryBuilder = (props) => {
|
|
|
2931
2971
|
console.error("[QueryBuilder] Error loading related entity fields:", error);
|
|
2932
2972
|
}
|
|
2933
2973
|
},
|
|
2934
|
-
[updateGroup]
|
|
2974
|
+
[props.onFetchEntityFields, updateGroup]
|
|
2935
2975
|
);
|
|
2936
2976
|
const addNestedCondition = React3__namespace.useCallback(
|
|
2937
2977
|
(groupId, conditionId, nestedFields) => {
|
|
@@ -3054,24 +3094,8 @@ var QueryBuilder = (props) => {
|
|
|
3054
3094
|
if (!validationResult) return /* @__PURE__ */ new Set();
|
|
3055
3095
|
return new Set(validationResult.errors.map((e) => e.conditionId).filter(Boolean));
|
|
3056
3096
|
}, [validationResult]);
|
|
3057
|
-
const isXrmAvailable = React3__namespace.useMemo(() => {
|
|
3058
|
-
try {
|
|
3059
|
-
return typeof window.Xrm?.WebApi?.retrieveMultipleRecords === "function";
|
|
3060
|
-
} catch {
|
|
3061
|
-
return false;
|
|
3062
|
-
}
|
|
3063
|
-
}, []);
|
|
3064
3097
|
const onValidate = React3__namespace.useCallback(async () => {
|
|
3065
3098
|
const result = validateQueryBuilderState(builderState, availableFields);
|
|
3066
|
-
if (!isXrmAvailable) {
|
|
3067
|
-
result.apiValidation = {
|
|
3068
|
-
available: false,
|
|
3069
|
-
tested: false
|
|
3070
|
-
};
|
|
3071
|
-
setValidationResult(result);
|
|
3072
|
-
setValidationDialogOpen(true);
|
|
3073
|
-
return;
|
|
3074
|
-
}
|
|
3075
3099
|
if (!result.isValid) {
|
|
3076
3100
|
result.apiValidation = {
|
|
3077
3101
|
available: true,
|
|
@@ -3085,18 +3109,29 @@ var QueryBuilder = (props) => {
|
|
|
3085
3109
|
setValidationResult(result);
|
|
3086
3110
|
setValidationDialogOpen(true);
|
|
3087
3111
|
try {
|
|
3088
|
-
const Xrm = window.Xrm;
|
|
3089
3112
|
const { odataFilter } = serializeQueryBuilderState(builderState, availableFields, props.entityName, entitySetName);
|
|
3090
|
-
const options = odataFilter ? `?$filter=${odataFilter}&$top=1&$count=true` : "?$top=1&$count=true";
|
|
3091
3113
|
const entitySetForApi = entitySetName || props.entityName;
|
|
3092
|
-
const
|
|
3114
|
+
const queryOptions = odataFilter ? `$filter=${odataFilter}&$top=1&$count=true` : "$top=1&$count=true";
|
|
3115
|
+
const response = await fetch(`/api/data/v9.2/${entitySetForApi}?${queryOptions}`, {
|
|
3116
|
+
headers: {
|
|
3117
|
+
"OData-MaxVersion": "4.0",
|
|
3118
|
+
"OData-Version": "4.0",
|
|
3119
|
+
"Accept": "application/json",
|
|
3120
|
+
"Prefer": 'odata.include-annotations="*"'
|
|
3121
|
+
}
|
|
3122
|
+
});
|
|
3123
|
+
if (!response.ok) {
|
|
3124
|
+
const errorText = await response.text();
|
|
3125
|
+
throw new Error(errorText || `HTTP ${response.status}`);
|
|
3126
|
+
}
|
|
3127
|
+
const data = await response.json();
|
|
3093
3128
|
setValidationResult({
|
|
3094
3129
|
...result,
|
|
3095
3130
|
apiValidation: {
|
|
3096
3131
|
available: true,
|
|
3097
3132
|
tested: true,
|
|
3098
3133
|
success: true,
|
|
3099
|
-
recordCount:
|
|
3134
|
+
recordCount: data["@odata.count"] ?? data.value?.length ?? 0
|
|
3100
3135
|
}
|
|
3101
3136
|
});
|
|
3102
3137
|
} catch (err) {
|
|
@@ -3112,7 +3147,7 @@ var QueryBuilder = (props) => {
|
|
|
3112
3147
|
} finally {
|
|
3113
3148
|
setApiValidating(false);
|
|
3114
3149
|
}
|
|
3115
|
-
}, [builderState, availableFields, entitySetName,
|
|
3150
|
+
}, [builderState, availableFields, entitySetName, props.entityName]);
|
|
3116
3151
|
const onOpenUploadDialog = React3__namespace.useCallback(() => {
|
|
3117
3152
|
setUploadXmlText("");
|
|
3118
3153
|
setUploadError(null);
|