@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.
Files changed (37) hide show
  1. package/dist/.a4drules/{graphql.md → features/feature-graphql-graphql-data-access-rule.md} +127 -117
  2. package/dist/.a4drules/features/feature-react-agentforce-conversation-client-embedded-agent-rule.md +32 -0
  3. package/dist/.a4drules/features/feature-react-chart-analytics-charts-rule.md +27 -0
  4. package/dist/.a4drules/skills/feature-graphql-graphql-data-access/SKILL.md +155 -0
  5. package/dist/.a4drules/{graphql/tools/knowledge/lds-explore-graphql-schema.md → skills/feature-graphql-graphql-data-access/docs/explore-schema.md} +58 -29
  6. package/dist/.a4drules/{graphql/tools/knowledge/lds-generate-graphql-mutationquery.md → skills/feature-graphql-graphql-data-access/docs/generate-mutation-query.md} +52 -42
  7. package/dist/.a4drules/{graphql/tools/knowledge/lds-generate-graphql-readquery.md → skills/feature-graphql-graphql-data-access/docs/generate-read-query.md} +32 -22
  8. package/dist/.a4drules/{graphql/tools/schemas/shared.graphqls → skills/feature-graphql-graphql-data-access/docs/shared-schema.graphqls} +1 -1
  9. package/dist/.a4drules/skills/feature-micro-frontend-micro-frontend/SKILL.md +137 -0
  10. package/dist/.a4drules/skills/feature-react-agentforce-conversation-client-embedded-agent/SKILL.md +108 -0
  11. package/dist/.a4drules/skills/feature-react-agentforce-conversation-client-embedded-agent/docs/embed-examples.md +182 -0
  12. package/dist/.a4drules/skills/feature-react-chart-analytics-charts/SKILL.md +41 -0
  13. package/dist/.a4drules/skills/feature-react-chart-analytics-charts/docs/schema-mapping.md +4 -0
  14. package/dist/.a4drules/webapp-code-quality.md +136 -0
  15. package/dist/.a4drules/{images.md → webapp-images.md} +6 -4
  16. package/dist/.a4drules/webapp-no-node-e.md +3 -2
  17. package/dist/.a4drules/webapp-react.md +149 -0
  18. package/dist/.a4drules/{typescript.md → webapp-typescript.md} +9 -17
  19. package/dist/.a4drules/webapp.md +62 -45
  20. package/dist/CHANGELOG.md +16 -0
  21. package/dist/force-app/main/default/webapplications/feature-react-agentforce-conversation-client/package-lock.json +22 -22
  22. package/dist/force-app/main/default/webapplications/feature-react-agentforce-conversation-client/package.json +1 -1
  23. package/dist/force-app/main/default/webapplications/feature-react-agentforce-conversation-client/vite.config.ts +2 -2
  24. package/dist/package.json +1 -1
  25. package/package.json +3 -3
  26. package/dist/.a4drules/README.md +0 -35
  27. package/dist/.a4drules/a4d-webapp-generate.md +0 -27
  28. package/dist/.a4drules/build-validation.md +0 -78
  29. package/dist/.a4drules/code-quality.md +0 -136
  30. package/dist/.a4drules/graphql/tools/knowledge/lds-guide-graphql.md +0 -205
  31. package/dist/.a4drules/react.md +0 -388
  32. package/dist/.a4drules/react_image_processing.md +0 -45
  33. package/dist/.a4drules/ui-layout.md +0 -23
  34. package/dist/.a4drules/webapp-nav-and-placeholders.md +0 -33
  35. package/dist/.a4drules/webapp-ui-first.md +0 -32
  36. package/dist/force-app/main/default/webapplications/feature-react-agentforce-conversation-client/build/vite.config.d.ts +0 -2
  37. package/dist/force-app/main/default/webapplications/feature-react-agentforce-conversation-client/build/vite.config.js +0 -93
@@ -1,38 +1,45 @@
1
- # AI Rule: GraphQL Data Access
1
+ ---
2
+ paths:
3
+ - "**/*.ts"
4
+ - "**/*.tsx"
5
+ ---
2
6
 
3
- Instructs agents to use the established GraphQL utilities for Salesforce data access.
7
+ # GraphQL Data Access
4
8
 
5
- ## Targets
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
- Types are auto-generated at: `force-app/main/default/webapplications/<appName>/src/api/graphql-operations-types.ts`
14
+
15
+ Types are auto-generated at: `src/api/graphql-operations-types.ts`
13
16
 
14
17
  ### Generation Command
15
- Run from the web app directory (replace `<appName>` with your app folder name, e.g. `base-react-app`):
18
+
16
19
  ```bash
17
- cd force-app/main/default/webapplications/<appName> && npm run graphql:codegen
20
+ npm run graphql:codegen
18
21
  ```
19
22
 
20
- The codegen configuration is located at `scripts/graphql/codegen.js` (or the package's codegen config) and generates types from:
21
- - Schema: `schema.graphql` (root level of the web app or as configured)
22
- - Documents: `force-app/main/default/webapplications/<appName>/src/**/*.{graphql,ts,tsx}`
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 '@salesforce/sdk-data';
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('GraphQL partial errors:', response.errors);
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('Partial success with errors:', response.errors);
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 '@salesforce/sdk-data';
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
- All Salesforce GraphQL queries follow this structure:
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; // The ID
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
- # force-app/main/default/webapplications/<appName>/src/api/utils/query/myQuery.graphql
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 { value }
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
- cd force-app/main/default/webapplications/<appName> && npm run graphql:codegen
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 '@salesforce/sdk-data';
184
- import MY_QUERY from './query/myQuery.graphql?raw';
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['uiapi']['query']['MyObject']>;
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>(MY_QUERY, variables);
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 '@salesforce/sdk-data';
236
- import { type CurrentUserQuery } from '../graphql-operations-types';
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
- id: string;
253
- name: string;
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('No user data found');
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 || 'User',
290
+ name: userData.Name?.value || "User",
274
291
  };
275
292
  } catch (error) {
276
- console.error('Error fetching user data:', 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
- # <appName>/src/api/utils/query/getAccountDetails.graphql
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 { value }
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 { value }
351
- NumberOfEmployees { value }
351
+ AnnualRevenue {
352
+ value
353
+ }
354
+ NumberOfEmployees {
355
+ value
356
+ }
352
357
  }
353
358
 
354
359
  fragment ContactFields on Account {
355
- Phone { value }
356
- Website { value }
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 '@salesforce/sdk-data';
363
- import QUERY from './query/getAccountDetails.graphql?raw';
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 '../graphql-operations-types';
377
+ } from "../graphql-operations-types";
368
378
 
369
379
  const data = await getDataSDK();
370
- const response = await data.graphql?.<GetAccountDetailsQuery, GetAccountDetailsQueryVariables>(QUERY, {
371
- id: accountId,
372
- includeFinancials: userWantsFinancials,
373
- includeContacts: userWantsContacts,
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('/graphql', { query });
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 './query/myQuery.graphql?raw';
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. [ ] Use `NodeOfConnection` for cleaner node types when needed
446
- 7. [ ] Handle optional chaining for nested response data
447
- 8. [ ] Follow the pattern in `accounts.ts`
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
@@ -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.