@salesforce/webapp-template-feature-react-agentforce-conversation-client-experimental 1.61.2 → 1.61.4
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/.a4drules/{graphql.md → features/feature-graphql-graphql-data-access-rule.md} +127 -117
- package/dist/.a4drules/features/feature-react-agentforce-conversation-client-embedded-agent-rule.md +32 -0
- package/dist/.a4drules/features/feature-react-chart-analytics-charts-rule.md +27 -0
- package/dist/.a4drules/skills/feature-graphql-graphql-data-access/SKILL.md +155 -0
- package/dist/.a4drules/{graphql/tools/knowledge/lds-explore-graphql-schema.md → skills/feature-graphql-graphql-data-access/docs/explore-schema.md} +58 -29
- package/dist/.a4drules/{graphql/tools/knowledge/lds-generate-graphql-mutationquery.md → skills/feature-graphql-graphql-data-access/docs/generate-mutation-query.md} +52 -42
- package/dist/.a4drules/{graphql/tools/knowledge/lds-generate-graphql-readquery.md → skills/feature-graphql-graphql-data-access/docs/generate-read-query.md} +32 -22
- package/dist/.a4drules/{graphql/tools/schemas/shared.graphqls → skills/feature-graphql-graphql-data-access/docs/shared-schema.graphqls} +1 -1
- package/dist/.a4drules/skills/feature-micro-frontend-micro-frontend/SKILL.md +137 -0
- package/dist/.a4drules/skills/feature-react-agentforce-conversation-client-embedded-agent/SKILL.md +108 -0
- package/dist/.a4drules/skills/feature-react-agentforce-conversation-client-embedded-agent/docs/embed-examples.md +182 -0
- package/dist/.a4drules/skills/feature-react-chart-analytics-charts/SKILL.md +41 -0
- package/dist/.a4drules/skills/feature-react-chart-analytics-charts/docs/schema-mapping.md +4 -0
- package/dist/.a4drules/webapp-code-quality.md +136 -0
- package/dist/.a4drules/{images.md → webapp-images.md} +6 -4
- package/dist/.a4drules/webapp-no-node-e.md +3 -2
- package/dist/.a4drules/webapp-react.md +149 -0
- package/dist/.a4drules/{typescript.md → webapp-typescript.md} +9 -17
- package/dist/.a4drules/webapp.md +62 -45
- package/dist/CHANGELOG.md +16 -0
- package/dist/force-app/main/default/webapplications/feature-react-agentforce-conversation-client/package-lock.json +22 -22
- package/dist/force-app/main/default/webapplications/feature-react-agentforce-conversation-client/package.json +1 -1
- package/dist/force-app/main/default/webapplications/feature-react-agentforce-conversation-client/vite.config.ts +2 -2
- package/dist/package.json +1 -1
- package/package.json +3 -3
- package/dist/.a4drules/README.md +0 -35
- package/dist/.a4drules/a4d-webapp-generate.md +0 -27
- package/dist/.a4drules/build-validation.md +0 -78
- package/dist/.a4drules/code-quality.md +0 -136
- package/dist/.a4drules/graphql/tools/knowledge/lds-guide-graphql.md +0 -205
- package/dist/.a4drules/react.md +0 -388
- package/dist/.a4drules/react_image_processing.md +0 -45
- package/dist/.a4drules/ui-layout.md +0 -23
- package/dist/.a4drules/webapp-nav-and-placeholders.md +0 -33
- package/dist/.a4drules/webapp-ui-first.md +0 -32
- package/dist/force-app/main/default/webapplications/feature-react-agentforce-conversation-client/build/vite.config.d.ts +0 -2
- package/dist/force-app/main/default/webapplications/feature-react-agentforce-conversation-client/build/vite.config.js +0 -93
|
@@ -1,38 +1,45 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.ts"
|
|
4
|
+
- "**/*.tsx"
|
|
5
|
+
---
|
|
2
6
|
|
|
3
|
-
|
|
7
|
+
# GraphQL Data Access
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
- `force-app/main/default/webapplications/<appName>/**/*.ts`
|
|
7
|
-
- `force-app/main/default/webapplications/<appName>/**/*.tsx`
|
|
9
|
+
Instructs agents to use the established GraphQL utilities for Salesforce data access.
|
|
8
10
|
|
|
9
11
|
## TypeScript Types & Code Generation
|
|
10
12
|
|
|
11
13
|
### Generated Types File
|
|
12
|
-
|
|
14
|
+
|
|
15
|
+
Types are auto-generated at: `src/api/graphql-operations-types.ts`
|
|
13
16
|
|
|
14
17
|
### Generation Command
|
|
15
|
-
|
|
18
|
+
|
|
16
19
|
```bash
|
|
17
|
-
|
|
20
|
+
npm run graphql:codegen
|
|
18
21
|
```
|
|
19
22
|
|
|
20
|
-
The codegen configuration is
|
|
21
|
-
|
|
22
|
-
-
|
|
23
|
+
The codegen configuration is at `codegen.yml` and generates types from:
|
|
24
|
+
|
|
25
|
+
- Schema: `schema.graphql` (project root)
|
|
26
|
+
- Documents: `src/**/*.{graphql,ts,tsx}`
|
|
23
27
|
|
|
24
28
|
### Type Naming Convention
|
|
29
|
+
|
|
25
30
|
For a GraphQL operation named `GetHighRevenueAccounts`:
|
|
31
|
+
|
|
26
32
|
- **Query/Mutation Response Type**: `GetHighRevenueAccountsQuery` or `GetHighRevenueAccountsMutation`
|
|
27
33
|
- **Input Variables Type**: `GetHighRevenueAccountsQueryVariables` or `GetHighRevenueAccountsMutationVariables`
|
|
28
34
|
|
|
29
35
|
## Core Types & Function Signatures
|
|
30
36
|
|
|
31
37
|
### getDataSDK Function
|
|
38
|
+
|
|
32
39
|
Available from `@salesforce/sdk-data`:
|
|
33
40
|
|
|
34
41
|
```typescript
|
|
35
|
-
import { getDataSDK } from
|
|
42
|
+
import { getDataSDK } from "@salesforce/sdk-data";
|
|
36
43
|
|
|
37
44
|
const data = await getDataSDK();
|
|
38
45
|
const response = await data.graphql?.<ResponseType, VariablesType>(query, variables);
|
|
@@ -40,7 +47,26 @@ const response = await data.graphql?.<ResponseType, VariablesType>(query, variab
|
|
|
40
47
|
|
|
41
48
|
`getDataSDK()` returns a lazily-initialized `DataSDK` singleton. The `graphql` method uses optional chaining (`?.`) because not all surfaces support GraphQL.
|
|
42
49
|
|
|
50
|
+
### gql Template Tag
|
|
51
|
+
|
|
52
|
+
Also available from `@salesforce/sdk-data` for inline query definitions:
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { gql } from "@salesforce/sdk-data";
|
|
56
|
+
|
|
57
|
+
const MY_QUERY = gql`
|
|
58
|
+
query MyQuery {
|
|
59
|
+
uiapi {
|
|
60
|
+
...
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
`;
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The `gql` tag is a template literal that allows defining GraphQL queries inline while maintaining syntax highlighting in most editors.
|
|
67
|
+
|
|
43
68
|
### GraphQLResponse Shape
|
|
69
|
+
|
|
44
70
|
`data.graphql?.()` returns `GraphQLResponse<T>`. Callers destructure `{ data, errors }` and handle errors themselves:
|
|
45
71
|
|
|
46
72
|
```typescript
|
|
@@ -61,64 +87,48 @@ GraphQL can return **both `data` and `errors`** in the same response (partial su
|
|
|
61
87
|
```typescript
|
|
62
88
|
// Strategy A: Strict — treat any errors as failure (default for most queries)
|
|
63
89
|
if (response?.errors?.length) {
|
|
64
|
-
throw new Error(response.errors.map(e => e.message).join(
|
|
90
|
+
throw new Error(response.errors.map((e) => e.message).join("; "));
|
|
65
91
|
}
|
|
66
92
|
const result = response?.data;
|
|
67
93
|
|
|
68
94
|
// Strategy B: Tolerant — log errors but use partial data
|
|
69
95
|
if (response?.errors?.length) {
|
|
70
|
-
console.warn(
|
|
96
|
+
console.warn("GraphQL partial errors:", response.errors);
|
|
71
97
|
}
|
|
72
98
|
const result = response?.data;
|
|
73
99
|
|
|
74
100
|
// Strategy C: Discriminated — fail only when no data came back
|
|
75
101
|
if (response?.errors?.length && !response?.data) {
|
|
76
|
-
throw new Error(response.errors.map(e => e.message).join(
|
|
102
|
+
throw new Error(response.errors.map((e) => e.message).join("; "));
|
|
77
103
|
}
|
|
78
104
|
if (response?.errors?.length) {
|
|
79
|
-
console.warn(
|
|
105
|
+
console.warn("Partial success with errors:", response.errors);
|
|
80
106
|
}
|
|
81
107
|
const result = response?.data;
|
|
82
108
|
```
|
|
83
109
|
|
|
84
110
|
**When to use each:**
|
|
111
|
+
|
|
85
112
|
- **Strategy A** — Default. Use for queries where incomplete data would be misleading (e.g., financial summaries, approval workflows).
|
|
86
113
|
- **Strategy B** — Use when partial data is still useful and the UI can degrade gracefully (e.g., dashboard tiles, optional fields).
|
|
87
114
|
- **Strategy C** — Use for mutations where the operation may succeed but some return fields are inaccessible.
|
|
88
115
|
|
|
89
116
|
For mutation-specific partial responses, see `docs/generate-mutation-query.md` which covers `PARTIAL` and `FAILED` status handling workflows.
|
|
90
117
|
|
|
91
|
-
### gql Template Tag
|
|
92
|
-
Also available from `@salesforce/sdk-data` for inline query definitions:
|
|
93
|
-
|
|
94
|
-
```typescript
|
|
95
|
-
import { gql } from '@salesforce/sdk-data';
|
|
96
|
-
|
|
97
|
-
const MY_QUERY = gql`
|
|
98
|
-
query MyQuery {
|
|
99
|
-
uiapi {
|
|
100
|
-
...
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
`;
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
The `gql` tag is a template literal that allows defining GraphQL queries inline while maintaining syntax highlighting in most editors.
|
|
107
|
-
|
|
108
118
|
### NodeOfConnection Utility Type
|
|
119
|
+
|
|
109
120
|
Extract the node type from a connection (edges/node pattern):
|
|
110
121
|
|
|
111
122
|
```typescript
|
|
112
|
-
import { type NodeOfConnection } from
|
|
123
|
+
import { type NodeOfConnection } from "@salesforce/sdk-data";
|
|
113
124
|
|
|
114
125
|
// Extract Account node type from the query response
|
|
115
|
-
type AccountNode = NodeOfConnection<
|
|
116
|
-
GetHighRevenueAccountsQuery['uiapi']['query']['Account']
|
|
117
|
-
>;
|
|
126
|
+
type AccountNode = NodeOfConnection<GetHighRevenueAccountsQuery["uiapi"]["query"]["Account"]>;
|
|
118
127
|
```
|
|
119
128
|
|
|
120
129
|
### UIAPI Response Shape
|
|
121
|
-
|
|
130
|
+
|
|
131
|
+
All Salesforce GraphQL record queries follow this structure (https://developer.salesforce.com/docs/platform/graphql/guide/query-record-objects.html):
|
|
122
132
|
|
|
123
133
|
```typescript
|
|
124
134
|
interface UIAPIQueryResponse {
|
|
@@ -131,7 +141,7 @@ interface UIAPIQueryResponse {
|
|
|
131
141
|
[FieldName]?: { value?: FieldType | null } | null;
|
|
132
142
|
// Reference fields include the related record
|
|
133
143
|
[ReferenceField]?: {
|
|
134
|
-
value?: string | null;
|
|
144
|
+
value?: string | null; // The ID
|
|
135
145
|
[RelatedField]?: { value?: RelatedType | null } | null;
|
|
136
146
|
} | null;
|
|
137
147
|
} | null;
|
|
@@ -149,10 +159,11 @@ There are **two acceptable patterns** for defining GraphQL queries:
|
|
|
149
159
|
### Pattern 1: External .graphql File (Recommended for complex queries)
|
|
150
160
|
|
|
151
161
|
#### Step 1: Create .graphql File
|
|
162
|
+
|
|
152
163
|
Store queries in `.graphql` files for codegen to process:
|
|
153
164
|
|
|
154
165
|
```graphql
|
|
155
|
-
#
|
|
166
|
+
# src/api/utils/query/myQuery.graphql
|
|
156
167
|
query GetMyData($myVariable: String) {
|
|
157
168
|
uiapi {
|
|
158
169
|
query {
|
|
@@ -160,7 +171,9 @@ query GetMyData($myVariable: String) {
|
|
|
160
171
|
edges {
|
|
161
172
|
node {
|
|
162
173
|
Id
|
|
163
|
-
Name {
|
|
174
|
+
Name {
|
|
175
|
+
value
|
|
176
|
+
}
|
|
164
177
|
}
|
|
165
178
|
}
|
|
166
179
|
}
|
|
@@ -170,47 +183,50 @@ query GetMyData($myVariable: String) {
|
|
|
170
183
|
```
|
|
171
184
|
|
|
172
185
|
#### Step 2: Run Code Generation
|
|
186
|
+
|
|
173
187
|
```bash
|
|
174
|
-
|
|
188
|
+
npm run graphql:codegen
|
|
175
189
|
```
|
|
176
190
|
|
|
177
191
|
This generates types in `graphql-operations-types.ts`:
|
|
192
|
+
|
|
178
193
|
- `GetMyDataQuery` - response type
|
|
179
194
|
- `GetMyDataQueryVariables` - variables type
|
|
180
195
|
|
|
181
196
|
#### Step 3: Import and Use
|
|
197
|
+
|
|
182
198
|
```typescript
|
|
183
|
-
import { getDataSDK, type NodeOfConnection } from
|
|
184
|
-
import MY_QUERY from
|
|
185
|
-
import type {
|
|
186
|
-
GetMyDataQuery,
|
|
187
|
-
GetMyDataQueryVariables,
|
|
188
|
-
} from '../graphql-operations-types';
|
|
199
|
+
import { getDataSDK, type NodeOfConnection } from "@salesforce/sdk-data";
|
|
200
|
+
import MY_QUERY from "./query/myQuery.graphql?raw";
|
|
201
|
+
import type { GetMyDataQuery, GetMyDataQueryVariables } from "../graphql-operations-types";
|
|
189
202
|
|
|
190
|
-
type MyNode = NodeOfConnection<GetMyDataQuery[
|
|
203
|
+
type MyNode = NodeOfConnection<GetMyDataQuery["uiapi"]["query"]["MyObject"]>;
|
|
191
204
|
|
|
192
|
-
export async function getMyData(
|
|
193
|
-
variables: GetMyDataQueryVariables
|
|
194
|
-
): Promise<MyNode[]> {
|
|
205
|
+
export async function getMyData(variables: GetMyDataQueryVariables): Promise<MyNode[]> {
|
|
195
206
|
const data = await getDataSDK();
|
|
196
|
-
const response = await data.graphql?.<GetMyDataQuery, GetMyDataQueryVariables>(
|
|
207
|
+
const response = await data.graphql?.<GetMyDataQuery, GetMyDataQueryVariables>(
|
|
208
|
+
MY_QUERY,
|
|
209
|
+
variables,
|
|
210
|
+
);
|
|
197
211
|
|
|
198
212
|
if (response?.errors?.length) {
|
|
199
|
-
const errorMessages = response.errors.map(e => e.message).join(
|
|
213
|
+
const errorMessages = response.errors.map((e) => e.message).join("; ");
|
|
200
214
|
throw new Error(`GraphQL Error: ${errorMessages}`);
|
|
201
215
|
}
|
|
202
216
|
|
|
203
|
-
return response?.data?.uiapi?.query?.MyObject?.edges?.map(edge => edge?.node) || [];
|
|
217
|
+
return response?.data?.uiapi?.query?.MyObject?.edges?.map((edge) => edge?.node) || [];
|
|
204
218
|
}
|
|
205
219
|
```
|
|
206
220
|
|
|
207
221
|
**Key imports for Pattern 1:**
|
|
222
|
+
|
|
208
223
|
- `getDataSDK` - Get the DataSDK singleton
|
|
209
224
|
- `NodeOfConnection` - Extract node types from connection responses
|
|
210
225
|
- Query from `.graphql` file with `?raw` suffix
|
|
211
226
|
- Generated types from `graphql-operations-types.ts`
|
|
212
227
|
|
|
213
228
|
**Pattern 1 Benefits:**
|
|
229
|
+
|
|
214
230
|
- Full codegen support with automatic type generation
|
|
215
231
|
- Syntax highlighting and validation in `.graphql` files
|
|
216
232
|
- Easier to share queries across multiple files/components
|
|
@@ -220,6 +236,7 @@ export async function getMyData(
|
|
|
220
236
|
- Clear separation of concerns between query definition and usage
|
|
221
237
|
|
|
222
238
|
**Pattern 1 Limitations:**
|
|
239
|
+
|
|
223
240
|
- Requires separate file management
|
|
224
241
|
- Extra step to run codegen after query changes
|
|
225
242
|
- More boilerplate (file import with `?raw`, separate file to maintain)
|
|
@@ -232,8 +249,8 @@ export async function getMyData(
|
|
|
232
249
|
For simpler queries without variables or when colocation is preferred:
|
|
233
250
|
|
|
234
251
|
```typescript
|
|
235
|
-
import { getDataSDK, gql } from
|
|
236
|
-
import { type CurrentUserQuery } from
|
|
252
|
+
import { getDataSDK, gql } from "@salesforce/sdk-data";
|
|
253
|
+
import { type CurrentUserQuery } from "../graphql-operations-types";
|
|
237
254
|
|
|
238
255
|
const CURRENT_USER_QUERY = gql`
|
|
239
256
|
query CurrentUser {
|
|
@@ -249,8 +266,8 @@ const CURRENT_USER_QUERY = gql`
|
|
|
249
266
|
`;
|
|
250
267
|
|
|
251
268
|
interface User {
|
|
252
|
-
|
|
253
|
-
|
|
269
|
+
id: string;
|
|
270
|
+
name: string;
|
|
254
271
|
}
|
|
255
272
|
|
|
256
273
|
export async function getCurrentUser(): Promise<User | null> {
|
|
@@ -259,32 +276,34 @@ export async function getCurrentUser(): Promise<User | null> {
|
|
|
259
276
|
const response = await data.graphql?.<CurrentUserQuery>(CURRENT_USER_QUERY);
|
|
260
277
|
|
|
261
278
|
if (response?.errors?.length) {
|
|
262
|
-
throw new Error(response.errors.map(e => e.message).join(
|
|
279
|
+
throw new Error(response.errors.map((e) => e.message).join("; "));
|
|
263
280
|
}
|
|
264
281
|
|
|
265
282
|
const userData = response?.data?.uiapi.currentUser;
|
|
266
283
|
|
|
267
284
|
if (!userData) {
|
|
268
|
-
throw new Error(
|
|
285
|
+
throw new Error("No user data found");
|
|
269
286
|
}
|
|
270
287
|
|
|
271
288
|
return {
|
|
272
289
|
id: userData.Id,
|
|
273
|
-
name: userData.Name?.value ||
|
|
290
|
+
name: userData.Name?.value || "User",
|
|
274
291
|
};
|
|
275
292
|
} catch (error) {
|
|
276
|
-
console.error(
|
|
293
|
+
console.error("Error fetching user data:", error);
|
|
277
294
|
throw error;
|
|
278
295
|
}
|
|
279
296
|
}
|
|
280
297
|
```
|
|
281
298
|
|
|
282
299
|
**Key imports for Pattern 2:**
|
|
300
|
+
|
|
283
301
|
- `getDataSDK` - Get the DataSDK singleton
|
|
284
302
|
- `gql` - Template tag for inline query definition
|
|
285
303
|
- Generated types from `graphql-operations-types.ts`
|
|
286
304
|
|
|
287
305
|
**Pattern 2 Benefits:**
|
|
306
|
+
|
|
288
307
|
- Query is colocated with usage code
|
|
289
308
|
- Supports dynamic queries (e.g., the set of fields changes based on runtime conditions and cannot be predetermined)
|
|
290
309
|
- No separate file to maintain
|
|
@@ -292,51 +311,33 @@ export async function getCurrentUser(): Promise<User | null> {
|
|
|
292
311
|
- Simpler for straightforward queries
|
|
293
312
|
|
|
294
313
|
**Pattern 2 Limitations:**
|
|
314
|
+
|
|
295
315
|
- Inline queries without `gql` template tag are not processed by codegen
|
|
296
316
|
- Must manually ensure query name matches generated types
|
|
297
317
|
- Less suitable for complex queries with fragments
|
|
298
318
|
|
|
299
|
-
## Reference Examples
|
|
300
|
-
|
|
301
|
-
### Pattern 1 Example: accounts.ts
|
|
302
|
-
See `force-app/main/default/webapplications/<appName>/src/api/utils/accounts.ts` for Pattern 1:
|
|
303
|
-
1. Importing query from `.graphql` file with `?raw` suffix
|
|
304
|
-
2. Importing generated types from `graphql-operations-types.ts`
|
|
305
|
-
3. Using `NodeOfConnection` to extract node types
|
|
306
|
-
4. Proper typing with `data.graphql?.<ResponseType>(query, variables)`
|
|
307
|
-
5. Safe data extraction from the nested response
|
|
308
|
-
|
|
309
|
-
### Pattern 2 Example: user.ts
|
|
310
|
-
See `force-app/main/default/webapplications/<appName>/src/api/utils/user.ts` for Pattern 2:
|
|
311
|
-
1. Using `gql` template tag for inline query definition
|
|
312
|
-
2. Importing generated types from `graphql-operations-types.ts`
|
|
313
|
-
3. Simple query without variables
|
|
314
|
-
4. Error handling with try/catch
|
|
315
|
-
5. Direct access to `uiapi.currentUser` (non-connection response)
|
|
316
|
-
|
|
317
319
|
## Conditional Field Selection with Directives
|
|
318
320
|
|
|
319
321
|
For dynamic fieldsets with known fields that should be conditionally included, use GraphQL directives instead of building queries dynamically. This preserves type generation while allowing runtime control.
|
|
320
322
|
|
|
321
323
|
### Directives
|
|
324
|
+
|
|
322
325
|
- **`@include(if: $condition)`** - include field/fragment when `$condition` is `true`
|
|
323
326
|
- **`@skip(if: $condition)`** - skip field/fragment when `$condition` is `true`
|
|
324
327
|
|
|
325
328
|
### Example with Fragments
|
|
329
|
+
|
|
326
330
|
```graphql
|
|
327
|
-
|
|
328
|
-
query GetAccountDetails(
|
|
329
|
-
$id: ID!
|
|
330
|
-
$includeFinancials: Boolean!
|
|
331
|
-
$includeContacts: Boolean!
|
|
332
|
-
) {
|
|
331
|
+
query GetAccountDetails($id: ID!, $includeFinancials: Boolean!, $includeContacts: Boolean!) {
|
|
333
332
|
uiapi {
|
|
334
333
|
query {
|
|
335
334
|
Account(where: { Id: { eq: $id } }) {
|
|
336
335
|
edges {
|
|
337
336
|
node {
|
|
338
337
|
Id
|
|
339
|
-
Name {
|
|
338
|
+
Name {
|
|
339
|
+
value
|
|
340
|
+
}
|
|
340
341
|
...FinancialFields @include(if: $includeFinancials)
|
|
341
342
|
...ContactFields @include(if: $includeContacts)
|
|
342
343
|
}
|
|
@@ -347,46 +348,52 @@ query GetAccountDetails(
|
|
|
347
348
|
}
|
|
348
349
|
|
|
349
350
|
fragment FinancialFields on Account {
|
|
350
|
-
AnnualRevenue {
|
|
351
|
-
|
|
351
|
+
AnnualRevenue {
|
|
352
|
+
value
|
|
353
|
+
}
|
|
354
|
+
NumberOfEmployees {
|
|
355
|
+
value
|
|
356
|
+
}
|
|
352
357
|
}
|
|
353
358
|
|
|
354
359
|
fragment ContactFields on Account {
|
|
355
|
-
Phone {
|
|
356
|
-
|
|
360
|
+
Phone {
|
|
361
|
+
value
|
|
362
|
+
}
|
|
363
|
+
Website {
|
|
364
|
+
value
|
|
365
|
+
}
|
|
357
366
|
}
|
|
358
367
|
```
|
|
359
368
|
|
|
360
369
|
### Usage
|
|
370
|
+
|
|
361
371
|
```typescript
|
|
362
|
-
import { getDataSDK } from
|
|
363
|
-
import QUERY from
|
|
372
|
+
import { getDataSDK } from "@salesforce/sdk-data";
|
|
373
|
+
import QUERY from "./query/getAccountDetails.graphql?raw";
|
|
364
374
|
import type {
|
|
365
375
|
GetAccountDetailsQuery,
|
|
366
376
|
GetAccountDetailsQueryVariables,
|
|
367
|
-
} from
|
|
377
|
+
} from "../graphql-operations-types";
|
|
368
378
|
|
|
369
379
|
const data = await getDataSDK();
|
|
370
|
-
const response = await data.graphql?.<GetAccountDetailsQuery, GetAccountDetailsQueryVariables>(
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
380
|
+
const response = await data.graphql?.<GetAccountDetailsQuery, GetAccountDetailsQueryVariables>(
|
|
381
|
+
QUERY,
|
|
382
|
+
{
|
|
383
|
+
id: accountId,
|
|
384
|
+
includeFinancials: userWantsFinancials,
|
|
385
|
+
includeContacts: userWantsContacts,
|
|
386
|
+
},
|
|
387
|
+
);
|
|
375
388
|
```
|
|
376
389
|
|
|
377
|
-
### Benefits
|
|
378
|
-
- Query stays in `.graphql` file (codegen works)
|
|
379
|
-
- Generated types include all possible fields as optional
|
|
380
|
-
- Runtime control over which fields are fetched
|
|
381
|
-
- Better performance when fields aren't needed
|
|
382
|
-
- Type safety is preserved
|
|
383
|
-
|
|
384
390
|
## Anti-Patterns (Not Recommended)
|
|
385
391
|
|
|
386
392
|
### Direct API Calls
|
|
393
|
+
|
|
387
394
|
```typescript
|
|
388
395
|
// NOT RECOMMENDED: Direct axios/fetch calls for GraphQL
|
|
389
|
-
const response = await axios.post(
|
|
396
|
+
const response = await axios.post("/graphql", { query });
|
|
390
397
|
|
|
391
398
|
// PREFERRED: Use the DataSDK
|
|
392
399
|
const data = await getDataSDK();
|
|
@@ -394,6 +401,7 @@ const response = await data.graphql?.<ResponseType>(query, variables);
|
|
|
394
401
|
```
|
|
395
402
|
|
|
396
403
|
### Missing Type Definitions
|
|
404
|
+
|
|
397
405
|
```typescript
|
|
398
406
|
// NOT RECOMMENDED: Untyped GraphQL calls
|
|
399
407
|
const data = await getDataSDK();
|
|
@@ -405,6 +413,7 @@ const response = await data.graphql?.<GetMyDataQuery>(query);
|
|
|
405
413
|
```
|
|
406
414
|
|
|
407
415
|
### Plain String Queries (Without gql Tag)
|
|
416
|
+
|
|
408
417
|
```typescript
|
|
409
418
|
// NOT RECOMMENDED: Plain string queries without gql tag
|
|
410
419
|
const query = `query { ... }`;
|
|
@@ -417,36 +426,36 @@ const data = await getDataSDK();
|
|
|
417
426
|
const response = await data.graphql?.<ResponseType>(QUERY);
|
|
418
427
|
|
|
419
428
|
// OR: Use .graphql file for complex queries
|
|
420
|
-
import QUERY from
|
|
429
|
+
import QUERY from "./query/myQuery.graphql?raw";
|
|
421
430
|
const data = await getDataSDK();
|
|
422
431
|
const response = await data.graphql?.<ResponseType>(QUERY);
|
|
423
432
|
```
|
|
424
433
|
|
|
425
|
-
**Why avoid plain strings:**
|
|
426
|
-
- No syntax highlighting or validation
|
|
427
|
-
- Harder to maintain and refactor
|
|
428
|
-
- More error-prone
|
|
429
|
-
|
|
430
434
|
## Benefits of the DataSDK GraphQL API
|
|
435
|
+
|
|
431
436
|
- Uses the DataSDK with proper authentication and CSRF token handling
|
|
432
437
|
- Consistent typing with `GraphQLResponse<T>` interface
|
|
433
438
|
- Optional chaining (`?.`) safely handles surfaces where GraphQL is unavailable
|
|
434
439
|
- Callers get full `GraphQLResponse<T>` for flexible error handling
|
|
435
440
|
|
|
436
441
|
## Quality Checklist
|
|
442
|
+
|
|
437
443
|
Before completing GraphQL data access code:
|
|
438
444
|
|
|
439
445
|
### For Pattern 1 (.graphql files):
|
|
446
|
+
|
|
440
447
|
1. [ ] Create `.graphql` file for the query/mutation
|
|
441
448
|
2. [ ] Run `npm run graphql:codegen` to generate types
|
|
442
449
|
3. [ ] Import query with `?raw` suffix
|
|
443
450
|
4. [ ] Import generated types from `graphql-operations-types.ts`
|
|
444
451
|
5. [ ] Use `data.graphql?.<ResponseType>()` with proper generic
|
|
445
|
-
6. [ ]
|
|
446
|
-
7. [ ]
|
|
447
|
-
8. [ ]
|
|
452
|
+
6. [ ] Handle `response.errors` and destructure `response.data`
|
|
453
|
+
7. [ ] Use `NodeOfConnection` for cleaner node types when needed
|
|
454
|
+
8. [ ] Handle optional chaining for nested response data
|
|
455
|
+
9. [ ] Follow the pattern in `accounts.ts`
|
|
448
456
|
|
|
449
457
|
### For Pattern 2 (inline with gql):
|
|
458
|
+
|
|
450
459
|
1. [ ] Define query using `gql` template tag
|
|
451
460
|
2. [ ] Ensure query name matches generated types in `graphql-operations-types.ts`
|
|
452
461
|
3. [ ] Import generated types for the query
|
|
@@ -456,5 +465,6 @@ Before completing GraphQL data access code:
|
|
|
456
465
|
7. [ ] Follow the pattern in `user.ts`
|
|
457
466
|
|
|
458
467
|
### General:
|
|
468
|
+
|
|
459
469
|
- [ ] Choose Pattern 1 for complex queries with variables, fragments, or when shared
|
|
460
470
|
- [ ] Choose Pattern 2 for simple, colocated queries without complex requirements
|
package/dist/.a4drules/features/feature-react-agentforce-conversation-client-embedded-agent-rule.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.tsx"
|
|
4
|
+
- "**/components/**/*.ts"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Agentforce Conversation Client (standards)
|
|
8
|
+
|
|
9
|
+
When adding or editing the embedded Agentforce chat client in this project, follow these conventions.
|
|
10
|
+
|
|
11
|
+
## Component and library
|
|
12
|
+
|
|
13
|
+
- Use the shared **AgentforceConversationClient** React component from `@salesforce/webapp-template-feature-react-agentforce-conversation-client-experimental`. Do not call `embedAgentforceClient` directly in application code.
|
|
14
|
+
- Install with `npm install @salesforce/webapp-template-feature-react-agentforce-conversation-client-experimental`. The underlying SDK (`@salesforce/agentforce-conversation-client`) is included automatically as a dependency.
|
|
15
|
+
|
|
16
|
+
## Authentication
|
|
17
|
+
|
|
18
|
+
- The component resolves auth automatically: **localhost** fetches `frontdoorUrl` from `/__lo/frontdoor`; **production** uses `window.location.origin` as `salesforceOrigin`.
|
|
19
|
+
- Do not hard-code `salesforceOrigin` or `frontdoorUrl` unless the consumer explicitly provides them as props.
|
|
20
|
+
|
|
21
|
+
## Rendering mode
|
|
22
|
+
|
|
23
|
+
- Pass `agentforceClientConfig.renderingConfig.mode` to select **floating** (default) or **inline**. Do not apply custom positioning CSS to override the built-in layout.
|
|
24
|
+
- For inline mode, set `width` and `height` in `renderingConfig`. Do not override iframe dimensions with external CSS.
|
|
25
|
+
|
|
26
|
+
## Agent selection
|
|
27
|
+
|
|
28
|
+
- Use `agentforceClientConfig.agentId` to select a specific agent. Ask the user for the agent ID; if not provided, note that the org's default agent is used.
|
|
29
|
+
|
|
30
|
+
## Placement
|
|
31
|
+
|
|
32
|
+
- Render `<AgentforceConversationClient />` inside the existing app layout (e.g. alongside `<Outlet />`). Do not replace the entire page shell with the chat client.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.tsx"
|
|
4
|
+
- "**/components/**/*.ts"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Analytics charts (standards)
|
|
8
|
+
|
|
9
|
+
When adding or editing chart UI in this project, follow these conventions.
|
|
10
|
+
|
|
11
|
+
## Components and library
|
|
12
|
+
|
|
13
|
+
- Use the shared **AnalyticsChart** component (and **ChartContainer** when a framed block is needed). Do not use raw Recharts components for standard line or bar charts.
|
|
14
|
+
- The project must have **recharts** installed (`npm install recharts`).
|
|
15
|
+
|
|
16
|
+
## Data shape
|
|
17
|
+
|
|
18
|
+
- **Time-series** (line): data must be an array of `{ x: string, y: number }`. Map raw fields (e.g. `date`, `value`) to these keys before passing to the chart.
|
|
19
|
+
- **Categorical** (bar): data must be an array of `{ name: string, value: number }`. Map raw fields (e.g. `category`, `total`) accordingly.
|
|
20
|
+
|
|
21
|
+
## Theming
|
|
22
|
+
|
|
23
|
+
- Use only the **theme** prop on AnalyticsChart: `red` (decline/loss), `green` (growth/gain), `neutral` (default or mixed). Do not introduce ad-hoc color schemes for these semantics.
|
|
24
|
+
|
|
25
|
+
## Placement
|
|
26
|
+
|
|
27
|
+
- Render charts inside the existing application frame (e.g. main content or a route). Do not replace the full app shell with a single chart.
|