@salesforce/ui-bundle-template-app-angular-template-b2x 11.35.6 → 11.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/CHANGELOG.md +8 -0
- package/dist/force-app/main/default/uiBundles/angularextapp/.graphqlrc.yml +2 -0
- package/dist/force-app/main/default/uiBundles/angularextapp/angular.json +3 -1
- package/dist/force-app/main/default/uiBundles/angularextapp/codegen.yml +95 -0
- package/dist/force-app/main/default/uiBundles/angularextapp/esbuild/graphql-codegen.mjs +13 -0
- package/dist/force-app/main/default/uiBundles/angularextapp/package.json +9 -2
- package/dist/force-app/main/default/uiBundles/angularextapp/scripts/get-graphql-schema.mjs +69 -0
- package/dist/force-app/main/default/uiBundles/angularextapp/src/app/api/account/account-search.service.ts +52 -140
- package/dist/force-app/main/default/uiBundles/angularextapp/src/app/api/graphql-operations-types.ts +29389 -0
- package/dist/force-app/main/default/uiBundles/angularextapp/src/app/features/object-search/api/object-search.service.ts +94 -0
- package/dist/force-app/main/default/uiBundles/angularextapp/src/app/features/object-search/utils/sort-utils.ts +3 -10
- package/dist/force-app/main/default/uiBundles/angularextapp/src/app/pages/account-search/account-search-page.ts +15 -8
- package/dist/package-lock.json +2 -2
- package/dist/package.json +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
import { Injectable, inject } from "@angular/core";
|
|
7
|
+
import { DataClient } from "../../../api/data-client.service";
|
|
8
|
+
|
|
9
|
+
/** Search args */
|
|
10
|
+
export interface ObjectSearchOptions<TWhere, TOrderBy> {
|
|
11
|
+
where?: TWhere;
|
|
12
|
+
orderBy?: TOrderBy;
|
|
13
|
+
first?: number;
|
|
14
|
+
after?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Picklist option shape shared with filter components. */
|
|
18
|
+
export type PicklistOption = { value: string; label: string };
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Generic object-search data service
|
|
22
|
+
*
|
|
23
|
+
* Provides reusable, object-agnostic methods for:
|
|
24
|
+
* - Searching objects via GraphQL `uiapi.query.<ObjectName>`
|
|
25
|
+
* - Fetching distinct picklist values via `uiapi.aggregate.<ObjectName>`
|
|
26
|
+
*
|
|
27
|
+
* Domain-specific services (e.g. `AccountSearchService`) delegate here with
|
|
28
|
+
* typed parameters rather than reimplementing the query/extraction logic.
|
|
29
|
+
*/
|
|
30
|
+
@Injectable({ providedIn: "root" })
|
|
31
|
+
export class ObjectSearchService {
|
|
32
|
+
private readonly client = inject(DataClient);
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Executes a GraphQL search query and extracts the result for the given
|
|
36
|
+
* object name from the standard `uiapi.query.<ObjectName>` response shape.
|
|
37
|
+
*/
|
|
38
|
+
async searchObjects<TResult, TQuery, TVariables>(
|
|
39
|
+
query: string,
|
|
40
|
+
objectName: string,
|
|
41
|
+
options: ObjectSearchOptions<unknown, unknown> = {},
|
|
42
|
+
): Promise<TResult> {
|
|
43
|
+
const { where, orderBy, first = 20, after } = options;
|
|
44
|
+
const data = await this.client.execute<TQuery, TVariables>(query, {
|
|
45
|
+
first,
|
|
46
|
+
after,
|
|
47
|
+
where,
|
|
48
|
+
orderBy,
|
|
49
|
+
} as TVariables);
|
|
50
|
+
|
|
51
|
+
const uiapi = (data as Record<string, unknown>)?.["uiapi"] as
|
|
52
|
+
| Record<string, unknown>
|
|
53
|
+
| undefined;
|
|
54
|
+
const queryResult = (uiapi?.["query"] as Record<string, unknown> | undefined)?.[objectName] as
|
|
55
|
+
| TResult
|
|
56
|
+
| undefined;
|
|
57
|
+
|
|
58
|
+
if (!queryResult) {
|
|
59
|
+
throw new Error(`No ${objectName} data returned`);
|
|
60
|
+
}
|
|
61
|
+
return queryResult;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Executes a GraphQL aggregate/groupBy query and extracts picklist options
|
|
66
|
+
* from the standard `uiapi.aggregate.<ObjectName>` response shape.
|
|
67
|
+
*/
|
|
68
|
+
async fetchDistinctValues<TQuery>(
|
|
69
|
+
query: string,
|
|
70
|
+
objectName: string,
|
|
71
|
+
fieldName: string,
|
|
72
|
+
): Promise<PicklistOption[]> {
|
|
73
|
+
const data = await this.client.execute<TQuery>(query);
|
|
74
|
+
|
|
75
|
+
const uiapi = (data as Record<string, unknown>)?.["uiapi"] as
|
|
76
|
+
| Record<string, unknown>
|
|
77
|
+
| undefined;
|
|
78
|
+
const aggregate = (uiapi?.["aggregate"] as Record<string, unknown> | undefined)?.[
|
|
79
|
+
objectName
|
|
80
|
+
] as { edges?: Array<{ node?: { aggregate?: Record<string, unknown> } }> } | undefined;
|
|
81
|
+
|
|
82
|
+
const edges = aggregate?.edges ?? [];
|
|
83
|
+
return edges
|
|
84
|
+
.map((edge) => {
|
|
85
|
+
const field = edge?.node?.aggregate?.[fieldName] as
|
|
86
|
+
| { value?: string | null; displayValue?: string | null; label?: string | null }
|
|
87
|
+
| undefined;
|
|
88
|
+
const value = field?.value;
|
|
89
|
+
if (!value) return null;
|
|
90
|
+
return { value, label: field.label ?? field.displayValue ?? value };
|
|
91
|
+
})
|
|
92
|
+
.filter((opt): opt is PicklistOption => opt !== null);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -4,14 +4,7 @@
|
|
|
4
4
|
* For full license text, see the LICENSE.txt file
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
// GraphQL types (graphql-operations-types.ts). Codegen is parked for the
|
|
9
|
-
// Angular port, so the enum string values are inlined here. When codegen lands,
|
|
10
|
-
// swap these constants for the generated enums.
|
|
11
|
-
/** GraphQL `ResultOrder` values. */
|
|
12
|
-
const RESULT_ORDER = { asc: "ASC", desc: "DESC" } as const;
|
|
13
|
-
/** GraphQL `NullOrder` values. */
|
|
14
|
-
const NULL_ORDER = { first: "FIRST", last: "LAST" } as const;
|
|
7
|
+
import { ResultOrder, NullOrder } from "../../../api/graphql-operations-types";
|
|
15
8
|
|
|
16
9
|
export interface SortFieldConfig<TFieldName extends string = string> {
|
|
17
10
|
field: TFieldName;
|
|
@@ -39,8 +32,8 @@ export function buildOrderBy<TOrderBy>(sort: SortState | null): TOrderBy | undef
|
|
|
39
32
|
if (!sort) return undefined;
|
|
40
33
|
return {
|
|
41
34
|
[sort.field]: {
|
|
42
|
-
order: sort.direction === "ASC" ?
|
|
43
|
-
nulls:
|
|
35
|
+
order: sort.direction === "ASC" ? ResultOrder.Asc : ResultOrder.Desc,
|
|
36
|
+
nulls: NullOrder.Last,
|
|
44
37
|
},
|
|
45
38
|
} as TOrderBy;
|
|
46
39
|
}
|
|
@@ -31,7 +31,11 @@ import { createAsyncData } from "../../utils/async-data";
|
|
|
31
31
|
import { fieldValue } from "../../features/object-search/utils/field-utils";
|
|
32
32
|
import type { FilterFieldConfig } from "../../features/object-search/utils/filter-utils";
|
|
33
33
|
import type { SortFieldConfig } from "../../features/object-search/utils/sort-utils";
|
|
34
|
-
import {
|
|
34
|
+
import {
|
|
35
|
+
AccountSearchService,
|
|
36
|
+
type AccountSearchNode,
|
|
37
|
+
type AccountSearchOptions,
|
|
38
|
+
} from "../../api/account/account-search.service";
|
|
35
39
|
|
|
36
40
|
/** Cursor-pagination config for the account search (mirrors the React reference). */
|
|
37
41
|
const PAGINATION_CONFIG: PaginationConfig = {
|
|
@@ -124,7 +128,10 @@ export class AccountSearchPageComponent {
|
|
|
124
128
|
protected readonly filtersOpen = signal<boolean>(true);
|
|
125
129
|
|
|
126
130
|
/** Derived, API-ready `where` / `orderBy` signals from the shared state. */
|
|
127
|
-
private readonly query = this.state.init<
|
|
131
|
+
private readonly query = this.state.init<
|
|
132
|
+
AccountSearchOptions["where"],
|
|
133
|
+
AccountSearchOptions["orderBy"]
|
|
134
|
+
>(FILTER_CONFIGS, PAGINATION_CONFIG);
|
|
128
135
|
|
|
129
136
|
/** Live page-size / cursor signals from the shared state. */
|
|
130
137
|
protected readonly pageSize = this.state.pageSize;
|
|
@@ -171,9 +178,9 @@ export class AccountSearchPageComponent {
|
|
|
171
178
|
protected readonly endCursor = computed(() => this.pageInfo()?.endCursor ?? undefined);
|
|
172
179
|
|
|
173
180
|
/** Non-null account nodes from the current page's edges. */
|
|
174
|
-
protected readonly nodes = computed<
|
|
181
|
+
protected readonly nodes = computed<AccountSearchNode[]>(() => {
|
|
175
182
|
const edges = this.result.data()?.edges ?? [];
|
|
176
|
-
const out:
|
|
183
|
+
const out: AccountSearchNode[] = [];
|
|
177
184
|
for (const edge of edges) {
|
|
178
185
|
if (edge?.node) out.push(edge.node);
|
|
179
186
|
}
|
|
@@ -199,19 +206,19 @@ export class AccountSearchPageComponent {
|
|
|
199
206
|
});
|
|
200
207
|
|
|
201
208
|
/** Display helpers for the results list (mirrors `fieldValue` in the template). */
|
|
202
|
-
protected name(node:
|
|
209
|
+
protected name(node: AccountSearchNode): string {
|
|
203
210
|
return fieldValue(node.Name) ?? "—";
|
|
204
211
|
}
|
|
205
212
|
|
|
206
|
-
protected secondaryLine(node:
|
|
213
|
+
protected secondaryLine(node: AccountSearchNode): string {
|
|
207
214
|
return [fieldValue(node.Industry), fieldValue(node.Type)].filter(Boolean).join(" · ") || "—";
|
|
208
215
|
}
|
|
209
216
|
|
|
210
|
-
protected phone(node:
|
|
217
|
+
protected phone(node: AccountSearchNode): string {
|
|
211
218
|
return fieldValue(node.Phone) ?? "";
|
|
212
219
|
}
|
|
213
220
|
|
|
214
|
-
protected ownerName(node:
|
|
221
|
+
protected ownerName(node: AccountSearchNode): string {
|
|
215
222
|
return fieldValue(node.Owner?.Name) ?? "";
|
|
216
223
|
}
|
|
217
224
|
}
|
package/dist/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/ui-bundle-template-base-sfdx-project",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.36.0",
|
|
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": "11.
|
|
9
|
+
"version": "11.36.0",
|
|
10
10
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"fast-xml-parser": "^5.9.3",
|
package/dist/package.json
CHANGED