@salesforce/webapp-template-app-react-template-b2x-experimental 1.76.1 → 1.77.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.
Files changed (14) hide show
  1. package/dist/CHANGELOG.md +8 -0
  2. package/dist/force-app/main/default/webapplications/appreacttemplateb2x/package.json +3 -3
  3. package/dist/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/api/objectInfoGraphQLService.ts +108 -156
  4. package/dist/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/api/objectInfoService.ts +5 -10
  5. package/dist/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/detail/UiApiDetailForm.tsx +2 -2
  6. package/dist/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/hooks/useObjectInfoBatch.ts +1 -1
  7. package/dist/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/types/filters/picklist.ts +5 -31
  8. package/dist/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/types/objectInfo/objectInfo.ts +46 -163
  9. package/dist/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/types/schema.d.ts +200 -0
  10. package/dist/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/utils/graphQLObjectInfoAdapter.ts +37 -279
  11. package/dist/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/utils/recordUtils.ts +4 -4
  12. package/dist/force-app/main/default/webapplications/appreacttemplateb2x/src/index.ts +0 -5
  13. package/dist/package.json +1 -1
  14. package/package.json +1 -1
package/dist/CHANGELOG.md CHANGED
@@ -3,6 +3,14 @@
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
+ # [1.77.0](https://github.com/salesforce-experience-platform-emu/webapps/compare/v1.76.1...v1.77.0) (2026-03-06)
7
+
8
+ **Note:** Version bump only for package @salesforce/webapp-template-base-sfdx-project-experimental
9
+
10
+
11
+
12
+
13
+
6
14
  ## [1.76.1](https://github.com/salesforce-experience-platform-emu/webapps/compare/v1.76.0...v1.76.1) (2026-03-06)
7
15
 
8
16
  **Note:** Version bump only for package @salesforce/webapp-template-base-sfdx-project-experimental
@@ -15,8 +15,8 @@
15
15
  "graphql:schema": "node scripts/get-graphql-schema.mjs"
16
16
  },
17
17
  "dependencies": {
18
- "@salesforce/sdk-data": "^1.76.1",
19
- "@salesforce/webapp-experimental": "^1.76.1",
18
+ "@salesforce/sdk-data": "^1.77.0",
19
+ "@salesforce/webapp-experimental": "^1.77.0",
20
20
  "@tailwindcss/vite": "^4.1.17",
21
21
  "@tanstack/react-form": "^1.28.4",
22
22
  "class-variance-authority": "^0.7.1",
@@ -40,7 +40,7 @@
40
40
  "@graphql-eslint/eslint-plugin": "^4.1.0",
41
41
  "@graphql-tools/utils": "^11.0.0",
42
42
  "@playwright/test": "^1.49.0",
43
- "@salesforce/vite-plugin-webapp-experimental": "^1.76.1",
43
+ "@salesforce/vite-plugin-webapp-experimental": "^1.77.0",
44
44
  "@testing-library/jest-dom": "^6.6.3",
45
45
  "@testing-library/react": "^16.1.0",
46
46
  "@testing-library/user-event": "^14.5.2",
@@ -7,179 +7,131 @@
7
7
  * @module api/objectInfoGraphQLService
8
8
  */
9
9
 
10
- import { getDataSDK } from "@salesforce/sdk-data";
11
-
12
- /** GraphQL objectInfoInputs for requesting picklist values (API v65.0+). Only apiName and fieldNames are sent; record type filtering is done from the response. */
13
- export interface ObjectInfoInput {
14
- apiName: string;
15
- fieldNames?: string[] | null;
16
- }
17
-
18
- /** Raw GraphQL response shape for uiapi.objectInfos (flexible for schema casing). */
19
- export interface ObjectInfosGraphQLResponse {
20
- uiapi?: {
21
- objectInfos?: Array<Record<string, unknown>>;
22
- };
23
- }
10
+ import { getDataSDK, gql } from "@salesforce/sdk-data";
11
+ import type {
12
+ GetObjectInfosQuery,
13
+ GetObjectInfosQueryVariables,
14
+ GetPicklistValuesQuery,
15
+ GetPicklistValuesQueryVariables,
16
+ ObjectInfoInput,
17
+ } from "../types/schema";
24
18
 
25
19
  /**
26
20
  * Builds objectInfos query (metadata only). Uses apiNames only — do not pass objectInfoInputs.
27
21
  */
28
- function buildObjectInfosQuery(): string {
29
- return `query GetObjectInfos($apiNames: [String!]!) {
30
- uiapi {
31
- objectInfos(apiNames: $apiNames) {
32
- ApiName
33
- label
34
- labelPlural
35
- nameFields
36
- defaultRecordTypeId
37
- keyPrefix
38
- layoutable
39
- queryable
40
- searchable
41
- updateable
42
- deletable
43
- createable
44
- custom
45
- mruEnabled
46
- feedEnabled
47
- fields {
48
- ApiName
49
- label
50
- dataType
51
- relationshipName
52
- reference
53
- compound
54
- compoundFieldName
55
- compoundComponentName
56
- controllingFields
57
- controllerName
58
- referenceToInfos {
59
- ApiName
60
- nameFields
61
- }
62
- }
63
- recordTypeInfos {
64
- recordTypeId
65
- name
66
- master
67
- available
68
- defaultRecordTypeMapping
69
- }
70
- themeInfo {
71
- color
72
- iconUrl
73
- }
74
- childRelationships {
75
- relationshipName
76
- fieldName
77
- childObjectApiName
78
- }
79
- dependentFields {
80
- controllingField
81
- }
82
- }
83
- }
84
- }`;
85
- }
22
+ const OBJECT_INFOS_QUERY = gql`
23
+ query GetObjectInfos($apiNames: [String!]!) {
24
+ uiapi {
25
+ objectInfos(apiNames: $apiNames) {
26
+ ApiName
27
+ label
28
+ labelPlural
29
+ nameFields
30
+ defaultRecordTypeId
31
+ keyPrefix
32
+ layoutable
33
+ queryable
34
+ searchable
35
+ updateable
36
+ deletable
37
+ createable
38
+ custom
39
+ mruEnabled
40
+ feedEnabled
41
+ fields {
42
+ ApiName
43
+ label
44
+ dataType
45
+ relationshipName
46
+ reference
47
+ compound
48
+ compoundFieldName
49
+ compoundComponentName
50
+ controllingFields
51
+ controllerName
52
+ referenceToInfos {
53
+ ApiName
54
+ nameFields
55
+ }
56
+ }
57
+ recordTypeInfos {
58
+ recordTypeId
59
+ name
60
+ master
61
+ available
62
+ defaultRecordTypeMapping
63
+ }
64
+ themeInfo {
65
+ color
66
+ iconUrl
67
+ }
68
+ childRelationships {
69
+ relationshipName
70
+ fieldName
71
+ childObjectApiName
72
+ }
73
+ dependentFields {
74
+ controllingField
75
+ }
76
+ }
77
+ }
78
+ }
79
+ `;
86
80
 
87
81
  /**
88
82
  * Builds objectInfos query with picklist values (API v65.0+).
89
83
  * Schema requires objectInfos to be called with either apiNames or objectInfoInputs, not both.
90
84
  * This query uses objectInfoInputs only.
85
+ * Optimized to only fetch fields used by extractPicklistValuesFromGraphQLObjectInfo.
91
86
  */
92
- function buildObjectInfosWithPicklistsQuery(): string {
93
- return `query GetPicklistValues($objectInfoInputs: [ObjectInfoInput!]!) {
94
- uiapi {
95
- objectInfos(objectInfoInputs: $objectInfoInputs) {
96
- ApiName
97
- label
98
- labelPlural
99
- nameFields
100
- defaultRecordTypeId
101
- keyPrefix
102
- layoutable
103
- queryable
104
- searchable
105
- updateable
106
- deletable
107
- createable
108
- custom
109
- mruEnabled
110
- feedEnabled
111
- fields {
112
- ApiName
113
- label
114
- dataType
115
- relationshipName
116
- reference
117
- compound
118
- compoundFieldName
119
- compoundComponentName
120
- controllingFields
121
- controllerName
122
- referenceToInfos {
123
- ApiName
124
- nameFields
125
- }
126
- ... on PicklistField {
127
- picklistValuesByRecordTypeIDs {
128
- recordTypeID
129
- defaultValue {
130
- value
131
- }
132
- picklistValues {
133
- label
134
- value
135
- validFor
136
- }
137
- }
138
- }
139
- }
140
- recordTypeInfos {
141
- recordTypeId
142
- name
143
- master
144
- available
145
- defaultRecordTypeMapping
146
- }
147
- themeInfo {
148
- color
149
- iconUrl
150
- }
151
- childRelationships {
152
- relationshipName
153
- fieldName
154
- childObjectApiName
155
- }
156
- dependentFields {
157
- controllingField
158
- }
159
- }
160
- }
161
- }`;
87
+ const PICKLIST_VALUES_QUERY = gql`
88
+ query GetPicklistValues($objectInfoInputs: [ObjectInfoInput!]!) {
89
+ uiapi {
90
+ objectInfos(objectInfoInputs: $objectInfoInputs) {
91
+ ApiName
92
+ fields {
93
+ ApiName
94
+ ... on PicklistField {
95
+ picklistValuesByRecordTypeIDs {
96
+ recordTypeID
97
+ defaultValue {
98
+ value
99
+ }
100
+ picklistValues {
101
+ label
102
+ value
103
+ validFor
104
+ }
105
+ }
106
+ }
107
+ }
108
+ }
109
+ }
110
+ }
111
+ `;
112
+
113
+ export async function queryForObjectInfos(apiNames: string[]): Promise<GetObjectInfosQuery> {
114
+ return runQuery<GetObjectInfosQuery, GetObjectInfosQueryVariables>(OBJECT_INFOS_QUERY, {
115
+ apiNames,
116
+ });
117
+ }
118
+
119
+ export async function queryForPicklistValues(
120
+ objectInfoInputs: ObjectInfoInput[],
121
+ ): Promise<GetPicklistValuesQuery> {
122
+ return runQuery<GetPicklistValuesQuery, GetPicklistValuesQueryVariables>(PICKLIST_VALUES_QUERY, {
123
+ objectInfoInputs,
124
+ });
162
125
  }
163
126
 
164
- export async function getObjectInfosGraphQL(
165
- apiNames: string[],
166
- options?: {
167
- objectInfoInputs?: ObjectInfoInput[] | null;
168
- },
169
- ): Promise<ObjectInfosGraphQLResponse> {
170
- const names = apiNames.length ? apiNames : [];
171
- const hasInputs = options?.objectInfoInputs != null && options.objectInfoInputs.length > 0;
172
- const query = hasInputs ? buildObjectInfosWithPicklistsQuery() : buildObjectInfosQuery();
173
- const variables: Record<string, unknown> = hasInputs
174
- ? { objectInfoInputs: options!.objectInfoInputs }
175
- : { apiNames: names };
127
+ async function runQuery<Q, V>(query: string, variables: V): Promise<Q> {
176
128
  const data = await getDataSDK();
177
- const response = await data.graphql?.<ObjectInfosGraphQLResponse>(query, variables);
129
+ const response = await data.graphql?.<Q, V>(query, variables);
178
130
 
179
131
  if (response?.errors?.length) {
180
132
  const errorMessages = response.errors.map((e) => e.message).join("; ");
181
133
  throw new Error(`GraphQL Error: ${errorMessages}`);
182
134
  }
183
135
 
184
- return response?.data ?? ({} as ObjectInfosGraphQLResponse);
136
+ return response?.data ?? ({} as Q);
185
137
  }
@@ -4,7 +4,7 @@ import { FilterArraySchema } from "../types/filters/filters";
4
4
  import type { PicklistValue } from "../types/filters/picklist";
5
5
  import type { ObjectInfoBatchResponse } from "../types/objectInfo/objectInfo";
6
6
  import { fetchAndValidate, safeEncodePath } from "../utils/apiUtils";
7
- import { getObjectInfosGraphQL } from "./objectInfoGraphQLService";
7
+ import { queryForObjectInfos, queryForPicklistValues } from "./objectInfoGraphQLService";
8
8
  import {
9
9
  graphQLObjectInfosToBatchResponse,
10
10
  extractPicklistValuesFromGraphQLObjectInfo,
@@ -47,7 +47,7 @@ export async function getObjectInfoBatch(objectApiNames: string): Promise<Object
47
47
  if (inFlight) return inFlight;
48
48
  const promise = (async () => {
49
49
  try {
50
- const response = await getObjectInfosGraphQL(names);
50
+ const response = await queryForObjectInfos(names);
51
51
  const nodes = response?.uiapi?.objectInfos ?? [];
52
52
  const result = graphQLObjectInfosToBatchResponse(nodes, names);
53
53
  objectInfoBatchCache.set(key, result);
@@ -79,14 +79,9 @@ export async function getPicklistValues(
79
79
  fieldName: string,
80
80
  recordTypeId: string = "012000000000000AAA",
81
81
  ): Promise<PicklistValue[]> {
82
- const response = await getObjectInfosGraphQL([objectApiName], {
83
- objectInfoInputs: [
84
- {
85
- apiName: objectApiName,
86
- fieldNames: [fieldName],
87
- },
88
- ],
89
- });
82
+ const response = await queryForPicklistValues([
83
+ { apiName: objectApiName, fieldNames: [fieldName] },
84
+ ]);
90
85
  const nodes = response?.uiapi?.objectInfos ?? [];
91
86
  const node = nodes[0];
92
87
  if (!node) return [];
@@ -75,7 +75,7 @@ export function UiApiDetailForm({
75
75
 
76
76
  const objectInfo: ObjectInfo | null = useMemo(() => {
77
77
  if (!metadata?.fields) return null;
78
- const apiName = typeof metadata.apiName === "string" ? metadata.apiName : undefined;
78
+ const apiName = metadata.ApiName;
79
79
  return {
80
80
  apiName,
81
81
  fields: Object.fromEntries(
@@ -83,7 +83,7 @@ export function UiApiDetailForm({
83
83
  name,
84
84
  {
85
85
  compoundFieldName: f.compoundFieldName ?? undefined,
86
- dataType: f.dataType,
86
+ dataType: f.dataType ?? "",
87
87
  },
88
88
  ]),
89
89
  ),
@@ -44,7 +44,7 @@ export function useObjectInfoBatch(objectApiNames: string[]): UseObjectInfoBatch
44
44
  .then((res) => {
45
45
  if (isCancelled.current) return;
46
46
  const objectInfos = names
47
- .map((apiName) => res.results?.find((r) => r.result?.apiName === apiName)?.result)
47
+ .map((apiName) => res.results?.find((r) => r.result?.ApiName === apiName)?.result)
48
48
  .filter((r) => r != null) as ObjectInfoResult[];
49
49
  setState({ objectInfos, loading: false, error: null });
50
50
  })
@@ -1,32 +1,6 @@
1
- import { z } from "zod";
1
+ import type { PicklistValue as GraphQLPicklistValue } from "../objectInfo/objectInfo";
2
2
 
3
- /**
4
- * Type definitions for picklist value structures
5
- */
6
-
7
- // Zod Schema for Picklist Value
8
- const PicklistValueSchema = z
9
- .object({
10
- // 1. Cleanup: Attributes are usually an object, not just 'unknown'
11
- attributes: z.record(z.string(), z.unknown()).nullish(),
12
- label: z.string(),
13
-
14
- // 2. Precise Typing: 'validFor' is an array of indices (numbers)
15
- // pointing to the controlling field's values.
16
- validFor: z.array(z.number()).nullish(),
17
- value: z.string(),
18
-
19
- // 3. Usability: Added common API fields that are useful for UI logic
20
- // (marked optional in case the specific API version omits them)
21
- defaultValue: z.boolean().nullish(),
22
- active: z.boolean().nullish(),
23
- })
24
- .passthrough();
25
-
26
- /**
27
- * Single picklist value from the API
28
- */
29
- export type PicklistValue = z.infer<typeof PicklistValueSchema>;
30
-
31
- // Export schema for validation
32
- export const PicklistValueArraySchema = z.array(PicklistValueSchema);
3
+ export type PicklistValue = GraphQLPicklistValue & {
4
+ value: NonNullable<GraphQLPicklistValue["value"]>;
5
+ label: NonNullable<GraphQLPicklistValue["label"]>;
6
+ };
@@ -1,166 +1,49 @@
1
- import { z } from "zod";
2
-
3
- /**
4
- * Type definitions and Zod schemas for Object Info Batch API response
5
- */
6
-
7
- // Zod Schema for Child Relationship
8
- const ChildRelationshipSchema = z.object({
9
- childObjectApiName: z.string(),
10
- fieldName: z.string(),
11
- junctionIdListNames: z.array(z.string()),
12
- junctionReferenceTo: z.array(z.string()),
13
- relationshipName: z.string(),
14
- });
15
-
16
- // Zod Schema for Reference To Info
17
- const ReferenceToInfoSchema = z.object({
18
- apiName: z.string(),
19
- nameFields: z.array(z.string()),
20
- });
21
-
22
- // Zod Schema for Filtered Lookup Info (can be null or object)
23
- const FilteredLookupInfoSchema = z.record(z.string(), z.unknown()).nullable();
24
-
25
- // Zod Schema for Field Definition
26
- // Using passthrough to allow extra fields that might be present in the API response
27
- const FieldSchema = z
28
- .object({
29
- apiName: z.string(),
30
- calculated: z.boolean(),
31
- compound: z.boolean(),
32
- compoundComponentName: z.string().nullable(),
33
- compoundFieldName: z.string().nullable(),
34
- controllerName: z.string().nullable(),
35
- controllingFields: z.array(z.string()),
36
- createable: z.boolean(),
37
- custom: z.boolean(),
38
- dataType: z.string(),
39
- defaultValue: z.unknown().nullable(),
40
- defaultedOnCreate: z.boolean(),
41
- digits: z.number(),
42
- externalId: z.boolean(),
43
- extraTypeInfo: z.string().nullable(),
44
- filterable: z.boolean(),
45
- filteredLookupInfo: FilteredLookupInfoSchema,
46
- highScaleNumber: z.boolean(),
47
- htmlFormatted: z.boolean(),
48
- inlineHelpText: z.string().nullable(),
49
- label: z.string(),
50
- length: z.number(),
51
- maskType: z.string().nullable(),
52
- nameField: z.boolean(),
53
- polymorphicForeignKey: z.boolean(),
54
- precision: z.number(),
55
- reference: z.boolean(),
56
- referenceTargetField: z.string().nullable(),
57
- referenceToInfos: z.array(ReferenceToInfoSchema),
58
- relationshipName: z.string().nullable(),
59
- required: z.boolean(),
60
- scale: z.number(),
61
- searchPrefilterable: z.boolean(),
62
- sortable: z.boolean(),
63
- unique: z.boolean(),
64
- updateable: z.boolean(),
65
- })
66
- .passthrough();
67
-
68
- // Zod Schema for Record Type Info
69
- // Using passthrough to allow extra fields that might be present in the API response
70
- const RecordTypeInfoSchema = z
71
- .object({
72
- available: z.boolean(),
73
- defaultRecordTypeMapping: z.boolean(),
74
- master: z.boolean(),
75
- name: z.string(),
76
- recordTypeId: z.string(),
77
- })
78
- .passthrough();
79
-
80
- // Zod Schema for Theme Info
81
- const ThemeInfoSchema = z.object({
82
- color: z.string(),
83
- iconUrl: z.string(),
84
- });
85
-
86
- // Zod Schema for Object Info Result
87
- // Using passthrough to allow extra fields and using FieldSchema/RecordTypeInfoSchema with passthrough
88
- const ObjectInfoResultSchema = z
89
- .object({
90
- apiName: z.string(),
91
- associateEntityType: z.string().nullable(),
92
- associateParentEntity: z.string().nullable(),
93
- childRelationships: z.array(ChildRelationshipSchema),
94
- compactLayoutable: z.boolean(),
95
- createable: z.boolean(),
96
- custom: z.boolean(),
97
- defaultRecordTypeId: z.string(),
98
- deletable: z.boolean(),
99
- dependentFields: z.record(z.string(), z.unknown()),
100
- eTag: z.string(),
101
- feedEnabled: z.boolean(),
102
- // Avoid using FieldSchema because of performance concerns with validating the high number of fields returned from the Salesforce API and causing the UI to freeze.
103
- fields: z.record(z.string(), z.any()),
104
- keyPrefix: z.string(),
105
- label: z.string(),
106
- labelPlural: z.string(),
107
- layoutable: z.boolean(),
108
- mruEnabled: z.boolean(),
109
- nameFields: z.array(z.string()),
110
- queryable: z.boolean(),
111
- // Avoid using RecordTypeInfoSchema because of performance concerns with validating the high number of fields returned from the Salesforce API and causing the UI to freeze.
112
- recordTypeInfos: z.record(z.string(), z.any()),
113
- searchLayoutable: z.boolean(),
114
- searchable: z.boolean(),
115
- themeInfo: ThemeInfoSchema,
116
- updateable: z.boolean(),
117
- })
118
- .passthrough();
119
-
120
- // Zod Schema for Object Info Batch Result Item
121
- const ObjectInfoBatchResultItemSchema = z.object({
122
- result: ObjectInfoResultSchema,
123
- statusCode: z.number(),
124
- });
125
-
126
- // Zod Schema for Object Info Batch Response (array of items)
127
- export const ObjectInfoBatchResponseSchema = z.object({
128
- results: z.array(ObjectInfoBatchResultItemSchema),
129
- });
130
-
131
- // TypeScript Types (inferred from Zod schemas)
132
- export type ChildRelationship = z.infer<typeof ChildRelationshipSchema>;
133
- export type ReferenceToInfo = z.infer<typeof ReferenceToInfoSchema>;
134
- export type FilteredLookupInfo = z.infer<typeof FilteredLookupInfoSchema>;
135
- export type Field = z.infer<typeof FieldSchema>;
136
- export type RecordTypeInfo = z.infer<typeof RecordTypeInfoSchema>;
137
- export type ThemeInfo = z.infer<typeof ThemeInfoSchema>;
138
- export type ObjectInfoBatchResponse = z.infer<typeof ObjectInfoBatchResponseSchema>;
139
- // Type Patching: Overwriting the "any" from the performance-optimized schema
140
- // with the strict types defined above. This ensures Developers get strict typing
141
- // even though the Runtime Validator skips the deep check.
142
- export type ObjectInfoResult = Omit<
143
- z.infer<typeof ObjectInfoResultSchema>,
144
- "fields" | "recordTypeInfos"
145
- > & {
146
- fields: Record<string, Field>;
147
- recordTypeInfos: Record<string, RecordTypeInfo>;
1
+ import type { GetObjectInfosQuery, GetPicklistValuesQuery } from "../schema";
2
+
3
+ // Generic utility types for extracting array item types
4
+ type ArrayItem<T> = T extends (infer Item)[] ? Item : never;
5
+ type NonNullableArrayItem<T> = NonNullable<ArrayItem<NonNullable<T>>>;
6
+
7
+ // ObjectInfos extraction
8
+ export type GetObjectInfosQueryObjectInfos = NonNullable<
9
+ GetObjectInfosQuery["uiapi"]["objectInfos"]
10
+ >;
11
+ export type GetObjectInfosQueryObjectInfo = NonNullableArrayItem<GetObjectInfosQueryObjectInfos>;
12
+ export type GetObjectInfosQueryField = NonNullableArrayItem<
13
+ GetObjectInfosQueryObjectInfo["fields"]
14
+ >;
15
+
16
+ // ObjectInfoResult types
17
+ export type ObjectInfoResult = Omit<GetObjectInfosQueryObjectInfo, "fields"> & {
18
+ fields: Record<string, GetObjectInfosQueryField>;
148
19
  };
149
- export type ObjectInfoBatchResultItem = Omit<
150
- z.infer<typeof ObjectInfoBatchResultItemSchema>,
151
- "result"
152
- > & {
153
- result: ObjectInfoResult;
20
+ export type ObjectInfoBatchResponse = {
21
+ results: { result: ObjectInfoResult; statusCode: number }[];
154
22
  };
155
23
 
156
- // Export schemas for validation
157
- export {
158
- ChildRelationshipSchema,
159
- ReferenceToInfoSchema,
160
- FilteredLookupInfoSchema,
161
- FieldSchema,
162
- RecordTypeInfoSchema,
163
- ThemeInfoSchema,
164
- ObjectInfoResultSchema,
165
- ObjectInfoBatchResultItemSchema,
166
- };
24
+ // Picklist values extraction
25
+ export type GetPicklistValuesQueryObjectInfos = GetPicklistValuesQuery["uiapi"]["objectInfos"];
26
+ export type GetPicklistValuesQueryObjectInfo =
27
+ NonNullableArrayItem<GetPicklistValuesQueryObjectInfos>;
28
+ export type GetPicklistValuesQueryField = NonNullableArrayItem<
29
+ GetPicklistValuesQueryObjectInfo["fields"]
30
+ >;
31
+
32
+ // Extract picklist-specific field type (the one with picklistValuesByRecordTypeIDs)
33
+ type GetPicklistValuesQueryPicklistField = Extract<
34
+ GetPicklistValuesQueryField,
35
+ { picklistValuesByRecordTypeIDs?: unknown }
36
+ >;
37
+
38
+ // Extract types from picklistValuesByRecordTypeIDs
39
+ type PicklistValuesByRecordTypeIDs =
40
+ GetPicklistValuesQueryPicklistField["picklistValuesByRecordTypeIDs"];
41
+ type PicklistValuesByRecordTypeID = NonNullable<
42
+ NonNullable<PicklistValuesByRecordTypeIDs> extends (infer Item)[] ? Item : null
43
+ >;
44
+
45
+ // Extract individual picklist value type
46
+ type PicklistValues = NonNullable<PicklistValuesByRecordTypeID>["picklistValues"];
47
+ export type PicklistValue = NonNullable<
48
+ NonNullable<PicklistValues> extends (infer Item)[] ? Item : null
49
+ >;
@@ -0,0 +1,200 @@
1
+ export type Maybe<T> = T | null;
2
+ export type InputMaybe<T> = Maybe<T>;
3
+ export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
4
+ export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> };
5
+ export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };
6
+ export type MakeEmpty<T extends { [key: string]: unknown }, K extends keyof T> = {
7
+ [_ in K]?: never;
8
+ };
9
+ export type Incremental<T> =
10
+ | T
11
+ | { [P in keyof T]?: P extends " $fragmentName" | "__typename" ? T[P] : never };
12
+ /** All built-in and custom scalars, mapped to their actual values */
13
+ export type Scalars = {
14
+ ID: { input: string; output: string };
15
+ String: { input: string; output: string };
16
+ Boolean: { input: boolean; output: boolean };
17
+ Int: { input: number; output: number };
18
+ Float: { input: number; output: number };
19
+ Base64: { input: string; output: string };
20
+ /** An arbitrary precision signed decimal */
21
+ BigDecimal: { input: number | string; output: number };
22
+ /** An arbitrary precision signed integer */
23
+ BigInteger: { input: number; output: number };
24
+ /** An 8-bit signed integer */
25
+ Byte: { input: number; output: number };
26
+ /** A UTF-16 code unit; a character on Unicode's BMP */
27
+ Char: { input: number; output: number };
28
+ Currency: { input: number | string; output: number };
29
+ Date: { input: string; output: string };
30
+ DateTime: { input: string; output: string };
31
+ Double: { input: number | string; output: number };
32
+ Email: { input: string; output: string };
33
+ EncryptedString: { input: string; output: string };
34
+ /** Can be set to an ID or a Reference to the result of another mutation operation. */
35
+ IdOrRef: { input: string; output: string };
36
+ JSON: { input: string; output: string };
37
+ Latitude: { input: number | string; output: number };
38
+ /** A 64-bit signed integer */
39
+ Long: { input: number; output: number };
40
+ LongTextArea: { input: string; output: string };
41
+ Longitude: { input: number | string; output: number };
42
+ MultiPicklist: { input: string; output: string };
43
+ Percent: { input: number | string; output: number };
44
+ PhoneNumber: { input: string; output: string };
45
+ Picklist: { input: string; output: string };
46
+ RichTextArea: { input: string; output: string };
47
+ /** A 16-bit signed integer */
48
+ Short: { input: number; output: number };
49
+ TextArea: { input: string; output: string };
50
+ Time: { input: string; output: string };
51
+ Url: { input: string; output: string };
52
+ };
53
+
54
+ export enum DataType {
55
+ Address = "ADDRESS",
56
+ Anytype = "ANYTYPE",
57
+ Base64 = "BASE64",
58
+ Boolean = "BOOLEAN",
59
+ Combobox = "COMBOBOX",
60
+ Complexvalue = "COMPLEXVALUE",
61
+ Currency = "CURRENCY",
62
+ Date = "DATE",
63
+ Datetime = "DATETIME",
64
+ Double = "DOUBLE",
65
+ Email = "EMAIL",
66
+ Encryptedstring = "ENCRYPTEDSTRING",
67
+ Int = "INT",
68
+ Json = "JSON",
69
+ Junctionidlist = "JUNCTIONIDLIST",
70
+ Location = "LOCATION",
71
+ Long = "LONG",
72
+ Multipicklist = "MULTIPICKLIST",
73
+ Percent = "PERCENT",
74
+ Phone = "PHONE",
75
+ Picklist = "PICKLIST",
76
+ Reference = "REFERENCE",
77
+ String = "STRING",
78
+ Textarea = "TEXTAREA",
79
+ Time = "TIME",
80
+ Url = "URL",
81
+ }
82
+
83
+ export enum FieldExtraTypeInfo {
84
+ ExternalLookup = "EXTERNAL_LOOKUP",
85
+ ImageUrl = "IMAGE_URL",
86
+ IndirectLookup = "INDIRECT_LOOKUP",
87
+ Personname = "PERSONNAME",
88
+ Plaintextarea = "PLAINTEXTAREA",
89
+ Richtextarea = "RICHTEXTAREA",
90
+ SwitchablePersonname = "SWITCHABLE_PERSONNAME",
91
+ }
92
+
93
+ /** Input for ObjectInfo and PickValues */
94
+ export type ObjectInfoInput = {
95
+ apiName: Scalars["String"]["input"];
96
+ fieldNames?: InputMaybe<Array<Scalars["String"]["input"]>>;
97
+ recordTypeIDs?: InputMaybe<Array<Scalars["ID"]["input"]>>;
98
+ };
99
+
100
+ export enum ResultOrder {
101
+ Asc = "ASC",
102
+ Desc = "DESC",
103
+ }
104
+
105
+ export type GetObjectInfosQueryVariables = Exact<{
106
+ apiNames: Array<Scalars["String"]["input"]> | Scalars["String"]["input"];
107
+ }>;
108
+
109
+ export type GetObjectInfosQuery = {
110
+ uiapi: {
111
+ objectInfos?: Array<{
112
+ ApiName: string;
113
+ label?: string | null;
114
+ labelPlural?: string | null;
115
+ nameFields: Array<string | null>;
116
+ defaultRecordTypeId?: string | null;
117
+ keyPrefix?: string | null;
118
+ layoutable: boolean;
119
+ queryable: boolean;
120
+ searchable: boolean;
121
+ updateable: boolean;
122
+ deletable: boolean;
123
+ createable: boolean;
124
+ custom: boolean;
125
+ mruEnabled: boolean;
126
+ feedEnabled: boolean;
127
+ fields: Array<
128
+ | {
129
+ ApiName: string;
130
+ label?: string | null;
131
+ dataType?: DataType | null;
132
+ relationshipName?: string | null;
133
+ reference: boolean;
134
+ compound: boolean;
135
+ compoundFieldName?: string | null;
136
+ compoundComponentName?: string | null;
137
+ controllingFields: Array<string | null>;
138
+ controllerName?: string | null;
139
+ referenceToInfos: Array<{ ApiName: string; nameFields: Array<string | null> } | null>;
140
+ }
141
+ | {
142
+ ApiName: string;
143
+ label?: string | null;
144
+ dataType?: DataType | null;
145
+ relationshipName?: string | null;
146
+ reference: boolean;
147
+ compound: boolean;
148
+ compoundFieldName?: string | null;
149
+ compoundComponentName?: string | null;
150
+ controllingFields: Array<string | null>;
151
+ controllerName?: string | null;
152
+ referenceToInfos: Array<{ ApiName: string; nameFields: Array<string | null> } | null>;
153
+ }
154
+ | null
155
+ >;
156
+ recordTypeInfos: Array<{
157
+ recordTypeId?: string | null;
158
+ name?: string | null;
159
+ master: boolean;
160
+ available: boolean;
161
+ defaultRecordTypeMapping: boolean;
162
+ } | null>;
163
+ themeInfo?: { color?: string | null; iconUrl?: string | null } | null;
164
+ childRelationships: Array<{
165
+ relationshipName?: string | null;
166
+ fieldName?: string | null;
167
+ childObjectApiName: string;
168
+ } | null>;
169
+ dependentFields: Array<{ controllingField: string } | null>;
170
+ } | null> | null;
171
+ };
172
+ };
173
+
174
+ export type GetPicklistValuesQueryVariables = Exact<{
175
+ objectInfoInputs: Array<ObjectInfoInput> | ObjectInfoInput;
176
+ }>;
177
+
178
+ export type GetPicklistValuesQuery = {
179
+ uiapi: {
180
+ objectInfos?: Array<{
181
+ ApiName: string;
182
+ fields: Array<
183
+ | {
184
+ ApiName: string;
185
+ picklistValuesByRecordTypeIDs?: Array<{
186
+ recordTypeID: string;
187
+ defaultValue?: { value?: string | null } | null;
188
+ picklistValues?: Array<{
189
+ label?: string | null;
190
+ value?: string | null;
191
+ validFor?: Array<number | null> | null;
192
+ }> | null;
193
+ } | null> | null;
194
+ }
195
+ | { ApiName: string }
196
+ | null
197
+ >;
198
+ } | null> | null;
199
+ };
200
+ };
@@ -10,259 +10,36 @@
10
10
 
11
11
  import type {
12
12
  ObjectInfoBatchResponse,
13
+ GetObjectInfosQueryObjectInfos,
14
+ GetPicklistValuesQueryObjectInfo,
15
+ GetPicklistValuesQueryField,
16
+ GetObjectInfosQueryObjectInfo,
13
17
  ObjectInfoResult,
14
- Field,
15
- RecordTypeInfo,
16
- ThemeInfo,
18
+ PicklistValue as GraphQLPicklistValue,
17
19
  } from "../types/objectInfo/objectInfo";
18
20
  import type { PicklistValue } from "../types/filters/picklist";
19
21
 
20
- type GraphQLNode = Record<string, unknown>;
21
-
22
- function getStr(node: GraphQLNode, key: string): string {
23
- const v = node[key] ?? node[key.charAt(0).toLowerCase() + key.slice(1)];
24
- return typeof v === "string" ? v : "";
25
- }
26
-
27
- function getNum(node: GraphQLNode, key: string): number {
28
- const v = node[key] ?? node[key.charAt(0).toLowerCase() + key.slice(1)];
29
- return typeof v === "number" ? v : 0;
30
- }
31
-
32
- function getBool(node: GraphQLNode, key: string): boolean {
33
- const v = node[key] ?? node[key.charAt(0).toLowerCase() + key.slice(1)];
34
- return typeof v === "boolean" ? v : false;
35
- }
36
-
37
- function getArr<T>(node: GraphQLNode, key: string, map: (item: unknown) => T): T[] {
38
- const v = node[key] ?? node[key.charAt(0).toLowerCase() + key.slice(1)];
39
- if (!Array.isArray(v)) return [];
40
- return v.map((item) => map(item));
41
- }
42
-
43
- function getObj(node: GraphQLNode, key: string): Record<string, unknown> {
44
- const v = node[key] ?? node[key.charAt(0).toLowerCase() + key.slice(1)];
45
- return v != null && typeof v === "object" && !Array.isArray(v)
46
- ? (v as Record<string, unknown>)
47
- : {};
48
- }
49
-
50
- /** GraphQL returns dependentFields as [DependentField]; REST expects Record. Normalize to object. */
51
- function toDependentFieldsRecord(v: unknown): Record<string, unknown> {
52
- if (v == null) return {};
53
- if (Array.isArray(v)) return {};
54
- return typeof v === "object" ? (v as Record<string, unknown>) : {};
55
- }
56
-
57
- /** Canonical dataType casing for formatters (Phone, FormattedAddress) and reference resolution (Reference). */
58
- const DATA_TYPE_CANONICAL: Record<string, string> = {
59
- phone: "Phone",
60
- email: "Email",
61
- url: "Url",
62
- address: "Address",
63
- reference: "Reference",
64
- };
65
-
66
- function normalizeDataType(raw: string): string {
67
- if (!raw) return raw;
68
- const lower = raw.toLowerCase();
69
- return DATA_TYPE_CANONICAL[lower] ?? raw;
70
- }
71
-
72
- /** Normalize GraphQL Field to our Field type (REST-compatible). */
73
- function mapField(fieldNode: unknown): [string, Field] {
74
- const n = (fieldNode != null && typeof fieldNode === "object" ? fieldNode : {}) as GraphQLNode;
75
- const apiName = getStr(n, "ApiName") || getStr(n, "apiName");
76
- const label = getStr(n, "label");
77
- const dataType = normalizeDataType(getStr(n, "dataType"));
78
- const relationshipName = getStr(n, "relationshipName") || null;
79
- const reference = getBool(n, "reference");
80
- const compound = getBool(n, "compound");
81
- const compoundFieldName = getStr(n, "compoundFieldName") || null;
82
- const compoundComponentName = getStr(n, "compoundComponentName") || null;
83
- const controllingFields = getArr(n, "controllingFields", String);
84
- const controllerName = getStr(n, "controllerName") || null;
85
- const referenceToInfos = getArr(n, "referenceToInfos", (item) => {
86
- const r = (item != null && typeof item === "object" ? item : {}) as GraphQLNode;
87
- return {
88
- apiName: getStr(r, "apiName") || getStr(r, "ApiName"),
89
- nameFields: getArr(r, "nameFields", String),
90
- };
91
- });
92
- return [
93
- apiName,
94
- {
95
- apiName,
96
- label,
97
- dataType,
98
- relationshipName,
99
- reference,
100
- compound,
101
- compoundFieldName,
102
- compoundComponentName,
103
- controllingFields,
104
- controllerName,
105
- referenceToInfos,
106
- calculated: getBool(n, "calculated"),
107
- createable: getBool(n, "createable"),
108
- custom: getBool(n, "custom"),
109
- defaultValue: n.defaultValue ?? null,
110
- defaultedOnCreate: getBool(n, "defaultedOnCreate"),
111
- digits: getNum(n, "digits"),
112
- externalId: getBool(n, "externalId"),
113
- extraTypeInfo: getStr(n, "extraTypeInfo") || null,
114
- filterable: getBool(n, "filterable"),
115
- filteredLookupInfo: null,
116
- highScaleNumber: getBool(n, "highScaleNumber"),
117
- htmlFormatted: getBool(n, "htmlFormatted"),
118
- inlineHelpText: getStr(n, "inlineHelpText") || null,
119
- length: getNum(n, "length"),
120
- maskType: getStr(n, "maskType") || null,
121
- nameField: getBool(n, "nameField"),
122
- polymorphicForeignKey: getBool(n, "polymorphicForeignKey"),
123
- precision: getNum(n, "precision"),
124
- required: getBool(n, "required"),
125
- scale: getNum(n, "scale"),
126
- searchPrefilterable: getBool(n, "searchPrefilterable"),
127
- sortable: getBool(n, "sortable"),
128
- unique: getBool(n, "unique"),
129
- updateable: getBool(n, "updateable"),
130
- referenceTargetField: getStr(n, "referenceTargetField") || null,
131
- } as Field,
132
- ];
133
- }
134
-
135
- /** Normalize GraphQL recordTypeInfo to RecordTypeInfo. */
136
- function mapRecordTypeInfo(rtNode: unknown): [string, RecordTypeInfo] {
137
- const n = (rtNode != null && typeof rtNode === "object" ? rtNode : {}) as GraphQLNode;
138
- const recordTypeId = getStr(n, "recordTypeId");
139
- return [
140
- recordTypeId,
141
- {
142
- recordTypeId,
143
- name: getStr(n, "name"),
144
- master: getBool(n, "master"),
145
- available: getBool(n, "available"),
146
- defaultRecordTypeMapping: getBool(n, "defaultRecordTypeMapping"),
147
- } as RecordTypeInfo,
148
- ];
149
- }
150
-
151
- function toFieldsMap(fieldsNode: unknown): Record<string, Field> {
152
- if (fieldsNode == null) return {};
153
- if (Array.isArray(fieldsNode)) {
154
- return Object.fromEntries((fieldsNode as unknown[]).map(mapField).filter(([k]) => k));
155
- }
156
- if (typeof fieldsNode === "object" && !Array.isArray(fieldsNode)) {
157
- const entries = Object.entries(fieldsNode as Record<string, unknown>).map(([, v]) =>
158
- mapField(v),
159
- );
160
- return Object.fromEntries(entries.filter(([k]) => k));
161
- }
162
- return {};
163
- }
164
-
165
- /**
166
- * Ensures compound parent fields (e.g. BillingAddress, ShippingAddress) exist in the fields map
167
- * with dataType "Address" so layout transform can set item.dataType for FormattedAddress.
168
- * GraphQL may only return component fields (BillingStreet, etc.) with compoundFieldName.
169
- */
170
- function ensureCompoundParentFields(fields: Record<string, Field>): Record<string, Field> {
171
- const result = { ...fields };
172
- for (const field of Object.values(fields)) {
173
- const compoundName = field.compoundFieldName;
174
- if (!compoundName || result[compoundName] != null) continue;
175
- const dataType =
176
- compoundName.endsWith("Address") || compoundName.endsWith("address") ? "Address" : "String";
177
- result[compoundName] = {
178
- ...field,
179
- apiName: compoundName,
180
- label: compoundName,
181
- dataType,
182
- compound: true,
183
- compoundFieldName: null,
184
- compoundComponentName: null,
185
- } as Field;
186
- }
187
- return result;
188
- }
189
-
190
- function toRecordTypeInfosMap(rtNode: unknown): Record<string, RecordTypeInfo> {
191
- if (rtNode == null) return {};
192
- if (Array.isArray(rtNode)) {
193
- return Object.fromEntries((rtNode as unknown[]).map(mapRecordTypeInfo).filter(([k]) => k));
194
- }
195
- if (typeof rtNode === "object" && !Array.isArray(rtNode)) {
196
- const entries = Object.entries(rtNode as Record<string, unknown>).map(([, v]) =>
197
- mapRecordTypeInfo(v),
198
- );
199
- return Object.fromEntries(entries.filter(([k]) => k));
200
- }
201
- return {};
202
- }
203
-
204
- /** Map a single GraphQL ObjectInfo node to ObjectInfoResult (REST-compatible). */
205
- export function graphQLObjectInfoToObjectInfoResult(node: GraphQLNode): ObjectInfoResult {
206
- const themeInfoNode = getObj(node, "themeInfo");
207
- const themeInfo: ThemeInfo = {
208
- color: getStr(themeInfoNode, "color"),
209
- iconUrl: getStr(themeInfoNode, "iconUrl"),
210
- };
211
-
212
- const childRelationships = getArr(node, "childRelationships", (item) => {
213
- const c = (item != null && typeof item === "object" ? item : {}) as GraphQLNode;
214
- return {
215
- childObjectApiName: getStr(c, "childObjectApiName"),
216
- fieldName: getStr(c, "fieldName"),
217
- junctionIdListNames: getArr(c, "junctionIdListNames", String),
218
- junctionReferenceTo: getArr(c, "junctionReferenceTo", String),
219
- relationshipName: getStr(c, "relationshipName"),
220
- };
221
- });
222
-
223
- const apiName = getStr(node, "ApiName") || getStr(node, "apiName");
224
- const fieldsNode = node.fields ?? node.Fields;
225
- const recordTypeInfosNode = node.recordTypeInfos ?? node.RecordTypeInfos;
226
-
22
+ export function graphQLObjectInfoToObjectInfoResult(
23
+ objectInfo: GetObjectInfosQueryObjectInfo,
24
+ ): ObjectInfoResult {
25
+ const { fields, ...rest } = objectInfo;
26
+ const fieldsRecord = Object.fromEntries((fields ?? []).map((field) => [field?.ApiName, field]));
227
27
  return {
228
- apiName,
229
- label: getStr(node, "label"),
230
- labelPlural: getStr(node, "labelPlural"),
231
- nameFields: getArr(node, "nameFields", String),
232
- defaultRecordTypeId: getStr(node, "defaultRecordTypeId") || "012000000000000AAA",
233
- keyPrefix: getStr(node, "keyPrefix"),
234
- layoutable: getBool(node, "layoutable"),
235
- queryable: getBool(node, "queryable"),
236
- searchable: getBool(node, "searchable"),
237
- updateable: getBool(node, "updateable"),
238
- deletable: getBool(node, "deletable"),
239
- createable: getBool(node, "createable"),
240
- custom: getBool(node, "custom"),
241
- mruEnabled: getBool(node, "mruEnabled"),
242
- feedEnabled: getBool(node, "feedEnabled"),
243
- fields: ensureCompoundParentFields(toFieldsMap(fieldsNode)),
244
- recordTypeInfos: toRecordTypeInfosMap(recordTypeInfosNode),
245
- themeInfo,
246
- childRelationships,
247
- associateEntityType: getStr(node, "associateEntityType") || null,
248
- associateParentEntity: getStr(node, "associateParentEntity") || null,
249
- compactLayoutable: getBool(node, "compactLayoutable"),
250
- searchLayoutable: getBool(node, "searchLayoutable"),
251
- dependentFields: toDependentFieldsRecord(node.dependentFields ?? node.DependentFields),
252
- eTag: getStr(node, "eTag"),
253
- } as ObjectInfoResult;
28
+ ...rest,
29
+ fields: fieldsRecord,
30
+ };
254
31
  }
255
32
 
256
33
  /** Convert GraphQL objectInfos array to ObjectInfoBatchResponse (REST shape). */
257
34
  export function graphQLObjectInfosToBatchResponse(
258
- nodes: GraphQLNode[],
35
+ objectInfos: GetObjectInfosQueryObjectInfos,
259
36
  _requestedApiNames: string[],
260
37
  ): ObjectInfoBatchResponse {
261
- const results = nodes.map((node) => ({
262
- result: graphQLObjectInfoToObjectInfoResult(node),
38
+ const results = objectInfos.map((objectInfo) => ({
39
+ result: graphQLObjectInfoToObjectInfoResult(objectInfo!),
263
40
  statusCode: 200,
264
41
  }));
265
- return { results } as ObjectInfoBatchResponse;
42
+ return { results };
266
43
  }
267
44
 
268
45
  /**
@@ -270,50 +47,31 @@ export function graphQLObjectInfosToBatchResponse(
270
47
  * Uses picklistValuesByRecordTypeIDs; prefers the given recordTypeId or first available.
271
48
  */
272
49
  export function extractPicklistValuesFromGraphQLObjectInfo(
273
- node: GraphQLNode,
50
+ objectInfo: NonNullable<GetPicklistValuesQueryObjectInfo>,
274
51
  fieldName: string,
275
52
  recordTypeId?: string,
276
53
  ): PicklistValue[] {
277
- const fieldsNode = node.fields ?? node.Fields;
278
- if (fieldsNode == null || typeof fieldsNode !== "object") return [];
279
- const fieldMap = Array.isArray(fieldsNode)
280
- ? Object.fromEntries(
281
- (fieldsNode as unknown[]).map((f: unknown) => {
282
- const n = (f != null && typeof f === "object" ? f : {}) as GraphQLNode;
283
- const k = getStr(n, "ApiName") || getStr(n, "apiName");
284
- return [k, n];
285
- }),
286
- )
287
- : (fieldsNode as Record<string, GraphQLNode>);
54
+ const fields = objectInfo.fields;
55
+ if (fields == null) return [];
56
+ const fieldMap: Record<string, GetPicklistValuesQueryField> = Object.fromEntries(
57
+ fields.map((field) => {
58
+ return [field?.ApiName, field];
59
+ }),
60
+ );
288
61
  const field = fieldMap[fieldName];
289
- if (!field || typeof field !== "object") return [];
290
- const picklistData = field.picklistValuesByRecordTypeIDs ?? field.PicklistValuesByRecordTypeIDs;
291
- if (!picklistData || !Array.isArray(picklistData)) return [];
62
+ if (!field) return [];
63
+ const picklistData =
64
+ "picklistValuesByRecordTypeIDs" in field ? field.picklistValuesByRecordTypeIDs : undefined;
65
+ if (!picklistData) return [];
292
66
  const rtId = recordTypeId ?? "012000000000000AAA";
293
- const arr = picklistData as Array<Record<string, unknown>>;
294
- const byRecordType = arr.find((p) => (p.recordTypeID ?? p.recordTypeId) === rtId);
295
- if (!byRecordType) {
296
- const first = arr[0];
297
- if (!first) return [];
298
- return mapPicklistValues(first);
299
- }
300
- return mapPicklistValues(byRecordType);
67
+ const byRecordType = picklistData.find((p) => p!.recordTypeID === rtId) ?? picklistData[0];
68
+ return mapPicklistValues(byRecordType?.picklistValues ?? []);
301
69
  }
302
70
 
303
- function mapPicklistValues(byRecordType: Record<string, unknown>): PicklistValue[] {
304
- const raw = byRecordType.picklistValues;
305
- if (!Array.isArray(raw)) return [];
306
- return raw.map((item: unknown) => {
307
- const n = (item != null && typeof item === "object" ? item : {}) as Record<string, unknown>;
308
- return {
309
- label: typeof n.label === "string" ? n.label : "",
310
- value: typeof n.value === "string" ? n.value : "",
311
- validFor: Array.isArray(n.validFor) ? n.validFor : undefined,
312
- attributes: (n.attributes != null && typeof n.attributes === "object"
313
- ? n.attributes
314
- : undefined) as Record<string, unknown> | undefined,
315
- defaultValue: typeof n.defaultValue === "boolean" ? n.defaultValue : undefined,
316
- active: typeof n.active === "boolean" ? n.active : undefined,
317
- } as PicklistValue;
318
- });
71
+ function mapPicklistValues(values: GraphQLPicklistValue[]): PicklistValue[] {
72
+ return values.map((item) => ({
73
+ ...item,
74
+ value: item.value ?? "",
75
+ label: item.label ?? "",
76
+ }));
319
77
  }
@@ -49,13 +49,13 @@ const getFetchableFieldsFromLayoutItem = function (
49
49
 
50
50
  // add field: fieldType
51
51
  const fieldMetadata = metadata.fields[comp.apiName];
52
- fields[comp.apiName] = fieldMetadata ? fieldMetadata.dataType : "";
52
+ fields[comp.apiName] = fieldMetadata?.dataType ?? "";
53
53
 
54
54
  // add relatedField if one exists (Id field -> add relationship name so we request Owner.Name)
55
55
  if (comp.apiName in metadata.fields) {
56
56
  const relationshipName = fieldMetadata?.relationshipName;
57
57
  if (relationshipName) {
58
- fields[relationshipName] = fieldMetadata.dataType;
58
+ fields[relationshipName] = fieldMetadata.dataType ?? "";
59
59
 
60
60
  relationFieldMap[comp.apiName] = relationshipName;
61
61
  }
@@ -65,7 +65,7 @@ const getFetchableFieldsFromLayoutItem = function (
65
65
  const idField = findIdFieldForRelationship(metadata, comp.apiName);
66
66
  if (idField) {
67
67
  const idMeta = metadata.fields[idField];
68
- fields[idField] = idMeta ? idMeta.dataType : "";
68
+ fields[idField] = idMeta?.dataType ?? "";
69
69
  relationFieldMap[idField] = comp.apiName;
70
70
  }
71
71
  }
@@ -137,7 +137,7 @@ export const calculateFieldsToFetch = function (
137
137
  const fields = getFetchableFieldsFromLayout(metadata, layout, relationFieldMap);
138
138
  let fieldsToFetch = Object.keys(fields);
139
139
  if (shouldPrefixedWithEntityName) {
140
- fieldsToFetch = fieldsToFetch.map((field) => `${metadata.apiName}.${field}`);
140
+ fieldsToFetch = fieldsToFetch.map((field) => `${metadata.ApiName}.${field}`);
141
141
  }
142
142
  // populate field types for o11y logging
143
143
  const fieldTypes = Object.values(fields).filter((fieldType) => fieldType !== "");
@@ -87,13 +87,8 @@ export type {
87
87
  FiltersResponse,
88
88
  } from "./features/global-search/types/filters/filters";
89
89
 
90
- export { PicklistValueArraySchema } from "./features/global-search/types/filters/picklist";
91
90
  export type { PicklistValue } from "./features/global-search/types/filters/picklist";
92
91
 
93
- export {
94
- ObjectInfoBatchResponseSchema,
95
- ObjectInfoResultSchema,
96
- } from "./features/global-search/types/objectInfo/objectInfo";
97
92
  export type {
98
93
  ObjectInfoBatchResponse,
99
94
  ObjectInfoResult,
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/webapp-template-base-sfdx-project-experimental",
3
- "version": "1.76.1",
3
+ "version": "1.77.0",
4
4
  "description": "Base SFDX project template",
5
5
  "private": true,
6
6
  "files": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/webapp-template-app-react-template-b2x-experimental",
3
- "version": "1.76.1",
3
+ "version": "1.77.0",
4
4
  "description": "Base reference app template",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "author": "",