@salesforce/ui-bundle-template-app-react-sample-b2e 12.3.6 → 12.3.8
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/dist/CHANGELOG.md +16 -0
- package/dist/force-app/main/default/uiBundles/propertymanagementapp/package.json +4 -4
- package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/hooks/__tests__/useSearch.test.ts +36 -0
- package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/hooks/useSearch.ts +4 -3
- package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/utils/__tests__/filterUtils.test.ts +40 -0
- package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/utils/filterUtils.ts +7 -2
- package/dist/package-lock.json +2 -2
- package/dist/package.json +1 -1
- package/package.json +2 -2
package/dist/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,22 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [12.3.8](https://github.com/salesforce-experience-platform-emu/webapps/compare/v12.3.7...v12.3.8) (2026-09-01)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @salesforce/ui-bundle-template-base-sfdx-project
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [12.3.7](https://github.com/salesforce-experience-platform-emu/webapps/compare/v12.3.6...v12.3.7) (2026-09-01)
|
|
15
|
+
|
|
16
|
+
**Note:** Version bump only for package @salesforce/ui-bundle-template-base-sfdx-project
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
6
22
|
## [12.3.6](https://github.com/salesforce-experience-platform-emu/webapps/compare/v12.3.5...v12.3.6) (2026-09-01)
|
|
7
23
|
|
|
8
24
|
**Note:** Version bump only for package @salesforce/ui-bundle-template-base-sfdx-project
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"graphql:schema": "node scripts/get-graphql-schema.mjs"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@salesforce/platform-sdk": "^12.3.
|
|
23
|
-
"@salesforce/ui-bundle": "^12.3.
|
|
22
|
+
"@salesforce/platform-sdk": "^12.3.8",
|
|
23
|
+
"@salesforce/ui-bundle": "^12.3.8",
|
|
24
24
|
"@tailwindcss/vite": "^4.1.17",
|
|
25
25
|
"class-variance-authority": "^0.7.1",
|
|
26
26
|
"clsx": "^2.1.1",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"@graphql-eslint/eslint-plugin": "^4.1.0",
|
|
48
48
|
"@graphql-tools/utils": "^11.0.0",
|
|
49
49
|
"@playwright/test": "^1.49.0",
|
|
50
|
-
"@salesforce/graphiti": "^12.3.
|
|
51
|
-
"@salesforce/vite-plugin-ui-bundle": "^12.3.
|
|
50
|
+
"@salesforce/graphiti": "^12.3.8",
|
|
51
|
+
"@salesforce/vite-plugin-ui-bundle": "^12.3.8",
|
|
52
52
|
"@testing-library/jest-dom": "^6.6.3",
|
|
53
53
|
"@testing-library/react": "^16.1.0",
|
|
54
54
|
"@testing-library/user-event": "^14.5.2",
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Cursors aren't persisted to the URL, so initSourceState ignores the page param and seeds page 0.
|
|
8
|
+
import { describe, it, expect } from "vitest";
|
|
9
|
+
import { initSourceState, resolvePagination } from "../useSearch";
|
|
10
|
+
import type { SearchConfig, SObjectSourceConfig } from "../../types";
|
|
11
|
+
|
|
12
|
+
describe("initSourceState pagination seed", () => {
|
|
13
|
+
const source: SObjectSourceConfig = {
|
|
14
|
+
kind: "sobject",
|
|
15
|
+
key: "accounts",
|
|
16
|
+
objectName: "Account",
|
|
17
|
+
label: "Accounts",
|
|
18
|
+
searchableFields: ["Name"],
|
|
19
|
+
displayFields: ["Name"],
|
|
20
|
+
};
|
|
21
|
+
const config: SearchConfig = { sources: [source] };
|
|
22
|
+
|
|
23
|
+
it("ignores the URL page param and always seeds the first page", () => {
|
|
24
|
+
const pagination = resolvePagination(config);
|
|
25
|
+
const params = new URLSearchParams("s.accounts.page=3");
|
|
26
|
+
const state = initSourceState(source, params, pagination);
|
|
27
|
+
expect(state.pageIndex).toBe(0);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("still reads a valid page size from the URL", () => {
|
|
31
|
+
const pagination = resolvePagination(config);
|
|
32
|
+
const params = new URLSearchParams("s.accounts.ps=25");
|
|
33
|
+
const state = initSourceState(source, params, pagination);
|
|
34
|
+
expect(state.pageSize).toBe(25);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
@@ -102,7 +102,7 @@ interface ResolvedPagination {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
/** Resolves the single global pagination config, filling in defaults. */
|
|
105
|
-
function resolvePagination(config: SearchConfig): ResolvedPagination {
|
|
105
|
+
export function resolvePagination(config: SearchConfig): ResolvedPagination {
|
|
106
106
|
const p = config.pagination;
|
|
107
107
|
const pageSizeOptions =
|
|
108
108
|
p?.pageSizeOptions && p.pageSizeOptions.length > 0
|
|
@@ -123,7 +123,7 @@ function validatePageSize(pagination: ResolvedPagination, size: number): number
|
|
|
123
123
|
return valid.includes(size) ? size : pagination.pageSize;
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
function initSourceState(
|
|
126
|
+
export function initSourceState(
|
|
127
127
|
source: SourceConfig,
|
|
128
128
|
params: URLSearchParams,
|
|
129
129
|
pagination: ResolvedPagination,
|
|
@@ -139,7 +139,8 @@ function initSourceState(
|
|
|
139
139
|
filters: read.filters,
|
|
140
140
|
sort,
|
|
141
141
|
pageSize,
|
|
142
|
-
|
|
142
|
+
// Cursors aren't persisted to the URL, so always seed the first page (page param ignored on read).
|
|
143
|
+
pageIndex: 0,
|
|
143
144
|
afterCursor: undefined,
|
|
144
145
|
cursorStack: [],
|
|
145
146
|
};
|
|
@@ -71,3 +71,43 @@ describe("LIKE pattern escaping", () => {
|
|
|
71
71
|
});
|
|
72
72
|
});
|
|
73
73
|
});
|
|
74
|
+
|
|
75
|
+
// A non-numeric or non-finite URL bound must be dropped, never emitted as NaN/Infinity.
|
|
76
|
+
describe("buildFilter numeric guard against invalid bounds", () => {
|
|
77
|
+
const configs: FilterFieldConfig[] = [{ field: "Amount", label: "Amount", type: "numeric" }];
|
|
78
|
+
|
|
79
|
+
it("drops a non-numeric min when there is no valid max, emitting no clause", () => {
|
|
80
|
+
const filters: ActiveFilterValue[] = [
|
|
81
|
+
{ field: "Amount", label: "Amount", type: "numeric", min: "abc" },
|
|
82
|
+
];
|
|
83
|
+
expect(buildFilter(filters, configs)).toBeUndefined();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("drops a non-numeric min but keeps a valid max", () => {
|
|
87
|
+
const filters: ActiveFilterValue[] = [
|
|
88
|
+
{ field: "Amount", label: "Amount", type: "numeric", min: "abc", max: "200" },
|
|
89
|
+
];
|
|
90
|
+
expect(buildFilter(filters, configs)).toEqual({ Amount: { lte: 200 } });
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("keeps both bounds when min and max are valid numbers", () => {
|
|
94
|
+
const filters: ActiveFilterValue[] = [
|
|
95
|
+
{ field: "Amount", label: "Amount", type: "numeric", min: "100", max: "200" },
|
|
96
|
+
];
|
|
97
|
+
expect(buildFilter(filters, configs)).toEqual({ Amount: { gte: 100, lte: 200 } });
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("keeps a numeric zero bound (a non-empty string is truthy)", () => {
|
|
101
|
+
const filters: ActiveFilterValue[] = [
|
|
102
|
+
{ field: "Amount", label: "Amount", type: "numeric", min: "0" },
|
|
103
|
+
];
|
|
104
|
+
expect(buildFilter(filters, configs)).toEqual({ Amount: { gte: 0 } });
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('drops a non-finite bound like Infinity (Number("1e999"))', () => {
|
|
108
|
+
const filters: ActiveFilterValue[] = [
|
|
109
|
+
{ field: "Amount", label: "Amount", type: "numeric", min: "1e999" },
|
|
110
|
+
];
|
|
111
|
+
expect(buildFilter(filters, configs)).toBeUndefined();
|
|
112
|
+
});
|
|
113
|
+
});
|
|
@@ -233,8 +233,13 @@ function buildSingleFilter(filter: ActiveFilterValue, config?: FilterFieldConfig
|
|
|
233
233
|
if (config?.max != null) n = Math.min(n, config.max);
|
|
234
234
|
return n;
|
|
235
235
|
};
|
|
236
|
-
|
|
237
|
-
|
|
236
|
+
// Drop any endpoint that isn't finite — NaN/Infinity serialize to null on the wire.
|
|
237
|
+
const lo = Number(min);
|
|
238
|
+
if (min && Number.isFinite(lo)) ops.gte = clamp(lo);
|
|
239
|
+
const hi = Number(max);
|
|
240
|
+
if (max && Number.isFinite(hi)) ops.lte = clamp(hi);
|
|
241
|
+
// If both endpoints were dropped as invalid, emit no clause at all.
|
|
242
|
+
if (Object.keys(ops).length === 0) return null;
|
|
238
243
|
return { [field]: ops };
|
|
239
244
|
}
|
|
240
245
|
case "boolean": {
|
package/dist/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/ui-bundle-template-base-sfdx-project",
|
|
3
|
-
"version": "12.3.
|
|
3
|
+
"version": "12.3.8",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@salesforce/ui-bundle-template-base-sfdx-project",
|
|
9
|
-
"version": "12.3.
|
|
9
|
+
"version": "12.3.8",
|
|
10
10
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"fast-xml-parser": "^5.9.3",
|
package/dist/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/ui-bundle-template-app-react-sample-b2e",
|
|
3
|
-
"version": "12.3.
|
|
3
|
+
"version": "12.3.8",
|
|
4
4
|
"description": "Salesforce sample property rental React app",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"author": "",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"clean": "rm -rf dist"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@salesforce/ui-bundle": "^12.3.
|
|
19
|
+
"@salesforce/ui-bundle": "^12.3.8",
|
|
20
20
|
"sonner": "^1.7.0"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|