@wix/auto-patterns 1.38.0 → 1.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/AutoPatternsCollectionComponent/AutoPatternsCollectionComponent.js +72 -18
- package/dist/cjs/components/AutoPatternsCollectionComponent/AutoPatternsCollectionComponent.js.map +1 -1
- package/dist/cjs/components/AutoPatternsEntityPage/AutoPatternsEntityPage.js +41 -10
- package/dist/cjs/components/AutoPatternsEntityPage/AutoPatternsEntityPage.js.map +1 -1
- package/dist/cjs/components/AutoPatternsRoute/AutoPatternsPage.js +50 -14
- package/dist/cjs/components/AutoPatternsRoute/AutoPatternsPage.js.map +1 -1
- package/dist/cjs/hooks/useActionCell.js +14 -8
- package/dist/cjs/hooks/useActionCell.js.map +1 -1
- package/dist/cjs/types/actions/actionCell.js.map +1 -1
- package/dist/esm/components/AutoPatternsCollectionComponent/AutoPatternsCollectionComponent.js +28 -10
- package/dist/esm/components/AutoPatternsCollectionComponent/AutoPatternsCollectionComponent.js.map +1 -1
- package/dist/esm/components/AutoPatternsEntityPage/AutoPatternsEntityPage.js +18 -6
- package/dist/esm/components/AutoPatternsEntityPage/AutoPatternsEntityPage.js.map +1 -1
- package/dist/esm/components/AutoPatternsRoute/AutoPatternsPage.js +16 -6
- package/dist/esm/components/AutoPatternsRoute/AutoPatternsPage.js.map +1 -1
- package/dist/esm/hooks/useActionCell.js +14 -8
- package/dist/esm/hooks/useActionCell.js.map +1 -1
- package/dist/esm/types/actions/actionCell.js.map +1 -1
- package/dist/types/components/AutoPatternsCollectionComponent/AutoPatternsCollectionComponent.d.ts +1 -1
- package/dist/types/components/AutoPatternsCollectionComponent/AutoPatternsCollectionComponent.d.ts.map +1 -1
- package/dist/types/components/AutoPatternsEntityPage/AutoPatternsEntityPage.d.ts.map +1 -1
- package/dist/types/components/AutoPatternsRoute/AutoPatternsPage.d.ts.map +1 -1
- package/dist/types/hooks/useActionCell.d.ts.map +1 -1
- package/dist/types/types/actions/actionCell.d.ts +13 -1
- package/dist/types/types/actions/actionCell.d.ts.map +1 -1
- package/mcp-docs/action_cell.md +66 -8
- package/mcp-docs/app_config_structure.md +50 -43
- package/mcp-docs/auto-patterns-guide.md +116 -51
- package/mcp-docs/wix_fqdn_custom_data_source.md +360 -196
- package/package.json +12 -12
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
## Build a Custom Data Source from a Wix Business API FQDN (with Contacts v4 example)
|
|
2
2
|
|
|
3
3
|
**🛑 CRITICAL PREREQUISITE**: This guide explains a specialized feature that exists within the broader auto-patterns framework. You **CANNOT** implement this guide without first having the complete content of the WixAutoPatternsGuide.
|
|
4
4
|
|
|
@@ -8,13 +8,44 @@
|
|
|
8
8
|
2. **This document is NOT standalone** - it's an advanced feature guide that builds upon the core auto-patterns concepts
|
|
9
9
|
3. **Without the WixAutoPatternsGuide content**, you will not understand the basic concepts, component structure, or implementation patterns required for this FQDN implementation
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
This guide shows how to build an Auto-Patterns custom data source backed by a Wix Business API entity identified by its FQDN. You will:
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
- Discover schema and client library via the Business Schema MCP
|
|
14
|
+
- Map the FQDN schema to a `SchemaConfig` (see `schema_config.md` for the full interface)
|
|
15
|
+
- Implement actions (CRUD + find)
|
|
16
|
+
- Wire the custom data source into your Auto-Patterns page
|
|
17
|
+
|
|
18
|
+
> IMPORTANT: Always use the Business Schema MCP as the source of truth for your target FQDN.
|
|
19
|
+
> - Run `client_lib` to determine the exact SDK/ambassador package to install and import
|
|
20
|
+
> - Run `fqdn_info` to see available actions, pagination mode, and request/response structure
|
|
21
|
+
> - (Optional) Run `fqdn_schema` for precise field shapes
|
|
22
|
+
> Do not rely on this example without verifying all details for your specific FQDN via MCP.
|
|
14
23
|
|
|
15
24
|
**📝 MINIMAL IMPLEMENTATION APPROACH**: This guide focuses on creating a basic, functional dashboard page. Custom overrides (actions, columns, components, etc.) should only be implemented when explicitly requested by the user. A simple dashboard page requires only the core custom data source implementation without any additional overrides.
|
|
16
25
|
|
|
17
|
-
|
|
26
|
+
### Non‑negotiable requirements (LLM guardrails)
|
|
27
|
+
|
|
28
|
+
- You **MUST** derive the SDK package, action names, required fields, and pagination mode from Business Schema MCP.
|
|
29
|
+
- You **MUST** install the package returned by `client_lib` before importing/using it.
|
|
30
|
+
- You **MUST** map API snake_case field segments to camelCase segments in `SchemaConfig`, preserving dot paths.
|
|
31
|
+
- You **MUST** set `supportedQueryOperators: []` for all fields in custom data sources.
|
|
32
|
+
- You **MUST** return the correct pagination shape from `actions.find` based on the API’s paging mode.
|
|
33
|
+
- You **MUST** pass required concurrency/identity fields (e.g., `revision` on Contacts v4 updates) exactly as specified by MCP.
|
|
34
|
+
- You **MUST** fully implement `SchemaConfig` (fields and actions). Do not leave placeholders; do not use `as any` to bypass typing.
|
|
35
|
+
- You **MUST NOT** create new custom entity types. Use SDK-exported types (from the ambassador/SDK package) or rely on inference. Avoid `any` that suppresses type errors.
|
|
36
|
+
|
|
37
|
+
### LLM Quick‑Start Execution Plan (follow in order)
|
|
38
|
+
|
|
39
|
+
1. **MUST** run `client_lib` on your FQDN and note the exact package name.
|
|
40
|
+
2. **MUST** install that package (npm/yarn/pnpm) and import the correct client entry point.
|
|
41
|
+
3. **MUST** run `fqdn_info` to list actions, required fields, and pagination type; use it to draft your actions.
|
|
42
|
+
4. **MUST** run `fqdn_schema` if you need concrete field shapes; map fields to `SchemaConfig` with segment-wise snake_case→camelCase and preserved dot paths.
|
|
43
|
+
5. **MUST** implement `actions` using the exact method names and payloads from MCP; add robust error handling.
|
|
44
|
+
6. **MUST** implement `find` to return the correct pagination shape (cursor vs offset) per MCP.
|
|
45
|
+
7. **MUST** register the custom data source and set matching `custom.id` in AppConfig.
|
|
46
|
+
8. **MUST** keep `supportedQueryOperators: []` for all fields.
|
|
47
|
+
|
|
48
|
+
### Prerequisites: Required Tools and Knowledge
|
|
18
49
|
|
|
19
50
|
**🛑 ABSOLUTE REQUIREMENT - WixAutoPatternsGuide Content**:
|
|
20
51
|
|
|
@@ -26,6 +57,7 @@ When implementing a custom data source based on a Wix Business API FQDN, you'll
|
|
|
26
57
|
**🛑 CRITICAL**: Before proceeding with this guide, you must have the following tools available:
|
|
27
58
|
|
|
28
59
|
- `WixAutoPatternsGuide` tool for understanding auto-patterns fundamentals and implementation patterns (**MANDATORY FIRST STEP**)
|
|
60
|
+
- `fqdn_info` tool for extracting action information from FQDNs
|
|
29
61
|
- `fqdn_schema` tool for extracting schema information from FQDNs
|
|
30
62
|
- `client_lib` tool for determining the correct client library package
|
|
31
63
|
|
|
@@ -43,55 +75,65 @@ If you haven't already used the `WixAutoPatternsGuide` tool in this conversation
|
|
|
43
75
|
|
|
44
76
|
**Without this foundational knowledge, you cannot successfully implement FQDN-based custom data sources.**
|
|
45
77
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
1. Follow the setup instructions at: https://github.com/wix-private/mcp-servers/tree/master/packages/business-schema-mcp
|
|
51
|
-
2. Configure the MCP server according to the documentation
|
|
52
|
-
3. Restart your development environment to load the new tools
|
|
53
|
-
4. Return to this guide once the tools are available
|
|
78
|
+
**Tool Installation:**
|
|
79
|
+
- Business Schema MCP installed and available in your environment
|
|
80
|
+
- Tools used: `fqdn_info`, `fqdn_schema`, `client_lib`
|
|
81
|
+
- Installation: see the Business Schema MCP README (internal)
|
|
54
82
|
|
|
55
83
|
**Tool Verification:**
|
|
56
84
|
Before continuing, verify that you have access to:
|
|
57
85
|
|
|
86
|
+
- `fqdn_info` tool - for extracting action and pagination information from FQDNs
|
|
58
87
|
- `fqdn_schema` tool - for extracting entity schema from FQDNs
|
|
59
88
|
- `client_lib` tool - for determining the correct SDK package to use
|
|
60
89
|
|
|
61
|
-
|
|
90
|
+
### What you will build
|
|
62
91
|
|
|
63
|
-
|
|
92
|
+
We'll create a custom data source for Contacts using `wix.contacts.v4.contact` as an example. The same steps apply to any other FQDN.
|
|
64
93
|
|
|
65
|
-
|
|
66
|
-
Use fqdn_schema tool with your FQDN (e.g., "wix.bookings.v1.sessions")
|
|
67
|
-
```
|
|
94
|
+
---
|
|
68
95
|
|
|
69
|
-
|
|
96
|
+
## 1) Discover schema and SDK with Business Schema MCP
|
|
70
97
|
|
|
71
|
-
|
|
72
|
-
- Available actions/operations
|
|
73
|
-
- Field types and constraints
|
|
74
|
-
- Relationships and references
|
|
98
|
+
Use the MCP tools to examine the entity and determine which SDK package to use.
|
|
75
99
|
|
|
76
|
-
|
|
100
|
+
```text
|
|
101
|
+
Call client_lib with: "wix.contacts.v4.contact" -> returns: @wix/crm
|
|
77
102
|
|
|
78
|
-
|
|
103
|
+
Call fqdn_info with: "wix.contacts.v4.contact" -> see common methods like CreateContact, GetContact, UpdateContact, DeleteContact, QueryContacts (offset-based)
|
|
79
104
|
|
|
80
|
-
|
|
81
|
-
Use client_lib tool with your FQDN to get the appropriate SDK package
|
|
105
|
+
Optionally call fqdn_schema for message shapes (Contact, CreateContactRequest, etc.)
|
|
82
106
|
```
|
|
83
107
|
|
|
84
|
-
|
|
108
|
+
Notes for Contacts v4:
|
|
109
|
+
- Paging for `QueryContacts` is offset-based
|
|
110
|
+
- Identifier in routes is `id` or `contactId` depending on the action; the entity carries an `id` field
|
|
85
111
|
|
|
86
|
-
|
|
112
|
+
Using other FQDNs: always run `client_lib` to get the exact package. Some entities use an ambassador package (e.g., `@wix/ambassador-<product>-<version>-<resource>`); install and import accordingly.
|
|
87
113
|
|
|
88
|
-
|
|
114
|
+
LLM notes:
|
|
115
|
+
- You **MUST NOT** guess method names or shapes; copy them from `fqdn_info`.
|
|
116
|
+
- You **MUST NOT** assume pagination type; read it from `fqdn_info` and implement accordingly.
|
|
89
117
|
|
|
90
|
-
|
|
118
|
+
### Install the SDK package
|
|
91
119
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
120
|
+
For the Contacts v4 example:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
npm i @wix/crm
|
|
124
|
+
# or
|
|
125
|
+
yarn add @wix/crm
|
|
126
|
+
# or
|
|
127
|
+
pnpm add @wix/crm
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
For other FQDNs, install the package returned by `client_lib`.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## 2) Map FQDN fields to SchemaConfig
|
|
135
|
+
|
|
136
|
+
See `schema_config.md` for the interface. Derive your field list and types from Business Schema MCP (`fqdn_schema` / `fqdn_info`) for YOUR FQDN, then apply these **MUST** rules:
|
|
95
137
|
|
|
96
138
|
### ⚠️ CRITICAL: Field ID Conversion from snake_case to camelCase
|
|
97
139
|
|
|
@@ -107,6 +149,9 @@ Transform the FQDN schema from Step 1 into a AutoPatterns-compatible SchemaConfi
|
|
|
107
149
|
- `last_activity.activity_date` → `lastActivity.activityDate` (NOT `lastActivityDate`)
|
|
108
150
|
- `job_title` → `jobTitle`
|
|
109
151
|
- `created_date` → `createdDate`
|
|
152
|
+
- `info.job_title` → `info.jobTitle`
|
|
153
|
+
- `info.name.first` → `info.name.first` (already camelCase, no change needed)
|
|
154
|
+
- `info.name.last` → `info.name.last` (already camelCase, no change needed)
|
|
110
155
|
|
|
111
156
|
This conversion ensures:
|
|
112
157
|
|
|
@@ -115,170 +160,260 @@ This conversion ensures:
|
|
|
115
160
|
- **Proper field mapping** between configuration and data source
|
|
116
161
|
- **Seamless integration** with AutoPatterns components
|
|
117
162
|
|
|
118
|
-
|
|
163
|
+
**🛑 MANDATORY - Query Operators Must Be Empty Array**: When implementing a custom data source, you **MUST** set `supportedQueryOperators: []` (empty array) for all fields. This is required because:
|
|
164
|
+
|
|
165
|
+
- Custom data sources handle all query operations directly through your implementation
|
|
166
|
+
- You don't need to specify individual operators for each field
|
|
167
|
+
- The custom data source `find` action will receive all queries regardless of declared operators
|
|
168
|
+
|
|
169
|
+
**Additional Rules:**
|
|
170
|
+
- You **MUST** choose:
|
|
171
|
+
- `idField`: typically `id`
|
|
172
|
+
- `displayField`: a meaningful label, e.g., `displayName`, or build from name fields
|
|
173
|
+
|
|
174
|
+
Minimal example for a subset of Contacts fields:
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
import type { SchemaConfig } from "@wix/auto-patterns"; // refer to your local types
|
|
178
|
+
|
|
179
|
+
const fields: SchemaConfig["fields"] = {
|
|
180
|
+
id: {
|
|
181
|
+
id: "id",
|
|
182
|
+
displayName: "ID",
|
|
183
|
+
type: "SHORT_TEXT",
|
|
184
|
+
validation: { required: true },
|
|
185
|
+
capabilities: { supportedQueryOperators: [], sortable: true }
|
|
186
|
+
},
|
|
187
|
+
displayName: {
|
|
188
|
+
id: "displayName",
|
|
189
|
+
displayName: "Display Name",
|
|
190
|
+
type: "SHORT_TEXT",
|
|
191
|
+
validation: { required: false },
|
|
192
|
+
capabilities: { supportedQueryOperators: [], sortable: true }
|
|
193
|
+
},
|
|
194
|
+
createdDate: {
|
|
195
|
+
id: "createdDate", // from created_date
|
|
196
|
+
displayName: "Created Date",
|
|
197
|
+
type: "DATETIME",
|
|
198
|
+
validation: { required: false },
|
|
199
|
+
capabilities: { supportedQueryOperators: [], sortable: true }
|
|
200
|
+
},
|
|
201
|
+
updatedDate: {
|
|
202
|
+
id: "updatedDate", // from updated_date
|
|
203
|
+
displayName: "Updated Date",
|
|
204
|
+
type: "DATETIME",
|
|
205
|
+
validation: { required: false },
|
|
206
|
+
capabilities: { supportedQueryOperators: [], sortable: true }
|
|
207
|
+
},
|
|
208
|
+
"name.first": {
|
|
209
|
+
id: "name.first",
|
|
210
|
+
displayName: "First Name",
|
|
211
|
+
type: "SHORT_TEXT",
|
|
212
|
+
validation: { required: false },
|
|
213
|
+
capabilities: { supportedQueryOperators: [], sortable: true }
|
|
214
|
+
},
|
|
215
|
+
"name.last": {
|
|
216
|
+
id: "name.last",
|
|
217
|
+
displayName: "Last Name",
|
|
218
|
+
type: "SHORT_TEXT",
|
|
219
|
+
validation: { required: false },
|
|
220
|
+
capabilities: { supportedQueryOperators: [], sortable: true }
|
|
221
|
+
},
|
|
222
|
+
"email.email": {
|
|
223
|
+
id: "email.email",
|
|
224
|
+
displayName: "Email",
|
|
225
|
+
type: "SHORT_TEXT",
|
|
226
|
+
validation: { required: false },
|
|
227
|
+
capabilities: { supportedQueryOperators: [], sortable: true }
|
|
228
|
+
},
|
|
229
|
+
"phone.phone": {
|
|
230
|
+
id: "phone.phone",
|
|
231
|
+
displayName: "Phone",
|
|
232
|
+
type: "SHORT_TEXT",
|
|
233
|
+
validation: { required: false },
|
|
234
|
+
capabilities: { supportedQueryOperators: [], sortable: true }
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
// Field mapping example ends here.
|
|
239
|
+
// You MUST NOT ship a partial SchemaConfig. Implement the full SchemaConfig with actions (see section 3).
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## 3) Implement SchemaConfig actions
|
|
245
|
+
|
|
246
|
+
Actions **MUST** call the correct Wix client library returned by `client_lib`. For Contacts v4 use `@wix/crm`. For any other FQDN, use MCP (`client_lib`, `fqdn_info`) to get the exact package and method names, then adapt the calls accordingly.
|
|
247
|
+
|
|
248
|
+
**⚠️ IMPORTANT**: You have two implementation approaches available:
|
|
249
|
+
|
|
250
|
+
1. **Full Implementation** (recommended for production): Complete working implementation with actual API calls
|
|
251
|
+
2. **Foundation with Guidance** (recommended for scaffolding): Unimplemented actions with helpful comments and error throwing
|
|
252
|
+
|
|
253
|
+
### Implementation Approach 1: Full Implementation
|
|
254
|
+
|
|
255
|
+
Implementation **MUSTs**:
|
|
256
|
+
- You **MUST** wrap HTTP calls with consistent error handling (e.g., `errorHandler` from `@wix/essentials`).
|
|
257
|
+
- You **MUST** map outgoing payloads from camelCase (SchemaConfig/AppConfig) to API snake_case when required, and map responses back.
|
|
258
|
+
- You **MUST** respect pagination mode:
|
|
259
|
+
- Cursor-based APIs: return `{ items, cursor, total? }`
|
|
260
|
+
- Offset-based APIs (Contacts v4): return `{ items, hasNext, total? }`
|
|
261
|
+
- For Contacts v4 updates, you **MUST** pass both `contactId` and the latest `revision`.
|
|
262
|
+
|
|
263
|
+
#### Example implementation (Contacts v4, offset-based):
|
|
264
|
+
|
|
265
|
+
```ts
|
|
266
|
+
import { contacts } from "@wix/crm";
|
|
267
|
+
import type { SchemaConfig, Query } from "@wix/auto-patterns";
|
|
268
|
+
// import { errorHandler } from "@wix/essentials"; // if used in your app shell
|
|
269
|
+
|
|
270
|
+
// NOTE: Some SDKs expose methods directly off the named export (no client instantiation).
|
|
271
|
+
// Always verify import/method patterns in MCP `client_lib` docs/examples.
|
|
272
|
+
|
|
273
|
+
function toApiContact(input) {
|
|
274
|
+
// Map camelCase fields used in forms/UI back to API shapes as needed.
|
|
275
|
+
// Example only – adapt to your fields. Many v4 fields are snake_case.
|
|
276
|
+
return input;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function fromApiContact(api) {
|
|
280
|
+
// Map API response to the fields you exposed in SchemaConfig
|
|
281
|
+
return {
|
|
282
|
+
id: api.id ?? api._id,
|
|
283
|
+
displayName: api.display_name ?? api.displayName ?? api.info?.name?.first ?? api.info?.name?.last,
|
|
284
|
+
createdDate: api.created_date ?? api.createdDate,
|
|
285
|
+
updatedDate: api.updated_date ?? api.updatedDate,
|
|
286
|
+
primaryInfo: api.primary_info ?? api.primaryInfo,
|
|
287
|
+
info: api.info
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
export const contactsSchemaWithActions: SchemaConfig = {
|
|
292
|
+
id: "Contacts",
|
|
293
|
+
idField: "id",
|
|
294
|
+
displayField: "displayName",
|
|
295
|
+
// Provide the full fields object from section 2 in your implementation
|
|
296
|
+
fields,
|
|
297
|
+
actions: {
|
|
298
|
+
async get(entityId: string) {
|
|
299
|
+
const res = await contacts.getContact({ id: entityId });
|
|
300
|
+
// Some SDKs return the entity at the root (res) instead of res.contact — verify via MCP
|
|
301
|
+
return fromApiContact(res.contact ?? res);
|
|
302
|
+
},
|
|
303
|
+
|
|
304
|
+
async create(newEntity) {
|
|
305
|
+
const res = await contacts.createContact({ info: toApiContact(newEntity).info });
|
|
306
|
+
return fromApiContact(res.contact ?? res);
|
|
307
|
+
},
|
|
308
|
+
|
|
309
|
+
async update(updatedEntity) {
|
|
310
|
+
// v4 requires id and revision on updates
|
|
311
|
+
const { id, revision, info } = toApiContact(updatedEntity);
|
|
312
|
+
const res = await contacts.updateContact({ contactId: id, revision, info });
|
|
313
|
+
return fromApiContact(res.contact ?? res);
|
|
314
|
+
},
|
|
315
|
+
|
|
316
|
+
async delete(entityId: string) {
|
|
317
|
+
await contacts.deleteContact({ contactId: entityId });
|
|
318
|
+
return { id: entityId };
|
|
319
|
+
},
|
|
119
320
|
|
|
120
|
-
|
|
321
|
+
async bulkDelete(entityIds: string[]) {
|
|
322
|
+
// If bulk delete API is not available, fall back to per-entity updates as defined by MCP
|
|
323
|
+
await contacts.bulkDeleteContacts?.({ contactIds: entityIds })
|
|
324
|
+
?? Promise.all(entityIds.map((id) => contacts.deleteContact({ contactId: id })));
|
|
325
|
+
return { ids: entityIds };
|
|
326
|
+
},
|
|
121
327
|
|
|
122
|
-
|
|
328
|
+
async find(query: Query) {
|
|
329
|
+
// Use QueryContacts (offset-based). Map Auto-Patterns Query to API query
|
|
330
|
+
const limit = query.limit ?? 25;
|
|
331
|
+
const offset = query.offset ?? (query.page ? (query.page - 1) * limit : 0);
|
|
332
|
+
const res = await contacts.queryContacts({
|
|
333
|
+
query: {
|
|
334
|
+
paging: { limit, offset },
|
|
335
|
+
// Map filters/sort/search into the API query as needed
|
|
336
|
+
filter: /* build from query.filters */ undefined,
|
|
337
|
+
sort: /* build from query.sort */ undefined,
|
|
338
|
+
search: query.search ?? undefined
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
const items = (res.contacts ?? []).map(fromApiContact);
|
|
342
|
+
const hasNext = res.paging?.hasNext ?? (items.length === limit);
|
|
343
|
+
return { items, hasNext, total: null };
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
```
|
|
123
348
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
349
|
+
Notes:
|
|
350
|
+
- Update requires the latest `revision`. Make sure your UI carries it and you pass it when updating.
|
|
351
|
+
- If you target other FQDNs, import and call the methods from the package returned by `client_lib`, and adapt pagination (cursor vs offset) accordingly.
|
|
352
|
+
- **Validation warning**: You **MUST** verify that each method you plan to call exists in the SDK for your FQDN. Replace non-existent operations with the supported alternatives per MCP (for example, use `update*` to set an `archived` flag if no `archive*` exists).
|
|
353
|
+
- **⚠️ CRITICAL: Add Error Handling** - When implementing the actions, you MUST wrap all HTTP requests with proper error handling using `errorHandler` from `@wix/essentials`
|
|
128
354
|
|
|
129
|
-
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## 4) Set Up Custom Data Source Structure and Hook Pattern
|
|
130
358
|
|
|
131
359
|
### Custom Data Source Hook Implementation
|
|
132
360
|
|
|
133
|
-
Create your custom data source with the hook pattern:
|
|
361
|
+
Create your custom data source with the hook pattern for better React integration:
|
|
134
362
|
|
|
135
|
-
In `components/customDataSources/
|
|
363
|
+
In `components/customDataSources/contactsDataSource.ts`:
|
|
136
364
|
|
|
137
365
|
```typescript
|
|
138
366
|
import { SchemaConfig } from '@wix/auto-patterns/types';
|
|
367
|
+
import { contacts } from "@wix/crm";
|
|
368
|
+
// Choose your implementation approach from section 3 above
|
|
139
369
|
|
|
140
|
-
export const
|
|
370
|
+
export const contactsDataSource = async (
|
|
141
371
|
collectionId: string,
|
|
142
372
|
context: any,
|
|
143
373
|
): Promise<SchemaConfig> => {
|
|
144
|
-
return
|
|
145
|
-
id: 'myCustomCollection',
|
|
146
|
-
fields: {
|
|
147
|
-
// Field definitions based on your FQDN schema mapping
|
|
148
|
-
},
|
|
149
|
-
displayField: 'name',
|
|
150
|
-
idField: 'id',
|
|
151
|
-
actions: {
|
|
152
|
-
get: async (entityId: string) => {
|
|
153
|
-
// TODO: Implement using your FQDN client library
|
|
154
|
-
// Example:
|
|
155
|
-
// return errorHandler.withErrorHandler(
|
|
156
|
-
// async () => {
|
|
157
|
-
// return yourFQDNClient.getEntity(entityId);
|
|
158
|
-
// },
|
|
159
|
-
// {}
|
|
160
|
-
// );
|
|
161
|
-
// Remember to map the response fields from snake_case to camelCase
|
|
162
|
-
throw new Error(
|
|
163
|
-
'get action not implemented - user must implement this method',
|
|
164
|
-
);
|
|
165
|
-
},
|
|
166
|
-
create: async (newEntity: any) => {
|
|
167
|
-
// TODO: Implement using your FQDN client library
|
|
168
|
-
// Example:
|
|
169
|
-
// return errorHandler.withErrorHandler(
|
|
170
|
-
// async () => {
|
|
171
|
-
// return yourFQDNClient.createEntity(newEntity);
|
|
172
|
-
// },
|
|
173
|
-
// {}
|
|
174
|
-
// );
|
|
175
|
-
// Remember to map the request fields from camelCase to snake_case
|
|
176
|
-
throw new Error(
|
|
177
|
-
'create action not implemented - user must implement this method',
|
|
178
|
-
);
|
|
179
|
-
},
|
|
180
|
-
update: async (updatedEntity: any) => {
|
|
181
|
-
// TODO: Implement using your FQDN client library
|
|
182
|
-
// Example:
|
|
183
|
-
// return errorHandler.withErrorHandler(
|
|
184
|
-
// async () => {
|
|
185
|
-
// return yourFQDNClient.updateEntity(updatedEntity);
|
|
186
|
-
// },
|
|
187
|
-
// {}
|
|
188
|
-
// );
|
|
189
|
-
// Remember to map the request fields from camelCase to snake_case
|
|
190
|
-
throw new Error(
|
|
191
|
-
'update action not implemented - user must implement this method',
|
|
192
|
-
);
|
|
193
|
-
},
|
|
194
|
-
delete: async (entityId: string) => {
|
|
195
|
-
// TODO: Implement using your FQDN client library
|
|
196
|
-
// Example:
|
|
197
|
-
// return errorHandler.withErrorHandler(
|
|
198
|
-
// async () => {
|
|
199
|
-
// return yourFQDNClient.deleteEntity(entityId);
|
|
200
|
-
// },
|
|
201
|
-
// {}
|
|
202
|
-
// );
|
|
203
|
-
throw new Error(
|
|
204
|
-
'delete action not implemented - user must implement this method',
|
|
205
|
-
);
|
|
206
|
-
},
|
|
207
|
-
bulkDelete: async (entityIds: string[]) => {
|
|
208
|
-
// TODO: Implement using your FQDN client library
|
|
209
|
-
// Example:
|
|
210
|
-
// return errorHandler.withErrorHandler(
|
|
211
|
-
// async () => {
|
|
212
|
-
// return yourFQDNClient.bulkDeleteEntities(entityIds);
|
|
213
|
-
// },
|
|
214
|
-
// {}
|
|
215
|
-
// );
|
|
216
|
-
throw new Error(
|
|
217
|
-
'bulkDelete action not implemented - user must implement this method',
|
|
218
|
-
);
|
|
219
|
-
},
|
|
220
|
-
find: async (query: Query, options?: any) => {
|
|
221
|
-
// TODO: Implement using your FQDN client library
|
|
222
|
-
// Example:
|
|
223
|
-
// return errorHandler.withErrorHandler(
|
|
224
|
-
// async () => {
|
|
225
|
-
// return yourFQDNClient.queryEntities(query, options);
|
|
226
|
-
// },
|
|
227
|
-
// {}
|
|
228
|
-
// );
|
|
229
|
-
// Remember to map the response fields from snake_case to camelCase
|
|
230
|
-
// IMPORTANT: Return shape depends on pagination mode.
|
|
231
|
-
// Detect by presence of query.cursor (cursor mode) vs. query.offset/page (offset mode):
|
|
232
|
-
// - Cursor mode: return { items, cursor, total? }
|
|
233
|
-
// - Offset mode (default): return { items, hasNext, total? }
|
|
234
|
-
throw new Error(
|
|
235
|
-
'find action not implemented - user must implement this method',
|
|
236
|
-
);
|
|
237
|
-
},
|
|
238
|
-
move: async (
|
|
239
|
-
id,
|
|
240
|
-
{
|
|
241
|
-
moveAfterId,
|
|
242
|
-
}: {
|
|
243
|
-
moveAfterId: string | null | undefined;
|
|
244
|
-
},
|
|
245
|
-
) => {
|
|
246
|
-
// TODO: Implement using your FQDN client library if it supports ordering/moving entities
|
|
247
|
-
// Example:
|
|
248
|
-
// return errorHandler.withErrorHandler(
|
|
249
|
-
// async () => {
|
|
250
|
-
// return yourFQDNClient.mvoeEntity(id, {
|
|
251
|
-
// moveAfterCategoryId: moveAfterId,
|
|
252
|
-
// position: moveAfterId ? 'AFTER' : 'FIRST',
|
|
253
|
-
// })
|
|
254
|
-
// },
|
|
255
|
-
// {}
|
|
256
|
-
// );
|
|
257
|
-
throw new Error(
|
|
258
|
-
'move action not implemented - user must implement this method',
|
|
259
|
-
);
|
|
260
|
-
},
|
|
261
|
-
},
|
|
262
|
-
};
|
|
374
|
+
return contactsSchemaWithActions; // Your SchemaConfig from section 3
|
|
263
375
|
};
|
|
264
376
|
```
|
|
265
377
|
|
|
266
378
|
In `components/customDataSources/index.tsx`:
|
|
267
379
|
|
|
268
380
|
```typescript
|
|
269
|
-
import {
|
|
381
|
+
import { contactsDataSource } from './contactsDataSource';
|
|
270
382
|
|
|
271
383
|
export const useCustomDataSources = () => {
|
|
272
384
|
// You can access React context and other hooks here
|
|
273
385
|
return {
|
|
274
|
-
|
|
386
|
+
contactsFqdn: contactsDataSource,
|
|
275
387
|
};
|
|
276
388
|
};
|
|
277
389
|
```
|
|
278
390
|
|
|
279
391
|
For detailed implementation patterns, folder structure, and registration steps, refer to the **Custom Data Sources** section in "Custom Overrides".
|
|
280
392
|
|
|
281
|
-
##
|
|
393
|
+
## 5) Register the custom data source and wire AppConfig
|
|
394
|
+
|
|
395
|
+
You **MUST** register the custom data source and reference it from AppConfig.
|
|
396
|
+
|
|
397
|
+
### Register Custom Data Source
|
|
398
|
+
|
|
399
|
+
In your main page component, use the hook to register your custom data source:
|
|
400
|
+
|
|
401
|
+
```tsx
|
|
402
|
+
import { AutoPatternsApp, AutoPatternsOverridesProvider } from "@wix/auto-patterns"; // adjust import path in your monorepo
|
|
403
|
+
import { useCustomDataSources } from '../components/customDataSources';
|
|
404
|
+
|
|
405
|
+
export function Page() {
|
|
406
|
+
const customDataSources = useCustomDataSources();
|
|
407
|
+
|
|
408
|
+
return (
|
|
409
|
+
<AutoPatternsOverridesProvider value={{ customDataSources }}>
|
|
410
|
+
<AutoPatternsApp configuration={config} />
|
|
411
|
+
</AutoPatternsOverridesProvider>
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### Update AppConfig
|
|
282
417
|
|
|
283
418
|
Configure your AppConfig to use the custom data source by setting:
|
|
284
419
|
|
|
@@ -288,55 +423,73 @@ Configure your AppConfig to use the custom data source by setting:
|
|
|
288
423
|
**Key FQDN-specific configuration:**
|
|
289
424
|
|
|
290
425
|
```json
|
|
291
|
-
|
|
292
|
-
"
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
"id": "
|
|
426
|
+
{
|
|
427
|
+
"collection": {
|
|
428
|
+
"collectionId": "Contacts",
|
|
429
|
+
"entityTypeSource": "custom",
|
|
430
|
+
"custom": { "id": "contactsFqdn" },
|
|
431
|
+
"paginationMode": "offset" // v4 uses offset; use "cursor" for cursor-based APIs
|
|
296
432
|
}
|
|
297
433
|
}
|
|
298
434
|
```
|
|
299
435
|
|
|
300
436
|
For complete AppConfig structure, configuration rules, and advanced options, refer to the "App Config Structure" section.
|
|
301
437
|
|
|
302
|
-
|
|
438
|
+
---
|
|
303
439
|
|
|
304
|
-
|
|
440
|
+
## 6) Building queries, filters and sorts
|
|
305
441
|
|
|
306
|
-
|
|
307
|
-
|
|
442
|
+
- Keep `supportedQueryOperators: []` on fields. Build server-side WQL/search inside `actions.find`
|
|
443
|
+
- Map `Query.filters` to the API’s filter object
|
|
444
|
+
- Map `Query.sort` to API sorting
|
|
308
445
|
|
|
309
|
-
|
|
310
|
-
const customDataSources = useCustomDataSources();
|
|
446
|
+
For Contacts v4, you **MUST** use `QueryContacts` (WQL) and map your UI query object to the API query. For other entities, use their recommended query/search method per MCP and map accordingly.
|
|
311
447
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
448
|
+
---
|
|
449
|
+
|
|
450
|
+
## 7) Error handling and robustness
|
|
451
|
+
|
|
452
|
+
- Wrap all HTTP requests with a consistent error handler (e.g., `errorHandler` from `@wix/essentials`) in your app shell
|
|
453
|
+
- Surface meaningful messages using your `displayField`
|
|
454
|
+
- Handle retries or specific application codes (duplicate, permission, invalid argument) when appropriate
|
|
455
|
+
|
|
456
|
+
---
|
|
457
|
+
|
|
458
|
+
## 8) Contacts v4 field mapping reference (subset)
|
|
319
459
|
|
|
320
|
-
|
|
460
|
+
Examples derived from `fqdn_info` and query/search patterns:
|
|
321
461
|
|
|
322
|
-
|
|
462
|
+
- `id` → `id`
|
|
463
|
+
- `display_name` → `displayName`
|
|
464
|
+
- `created_date` → `createdDate`
|
|
465
|
+
- `updated_date` → `updatedDate`
|
|
466
|
+
- `info.name.first` → `info.name.first`
|
|
467
|
+
- `info.name.last` → `info.name.last`
|
|
468
|
+
- `primary_info.email` → `primaryInfo.email`
|
|
469
|
+
- `info.job_title` → `info.jobTitle`
|
|
470
|
+
- `last_activity.activity_date` → `lastActivity.activityDate`
|
|
471
|
+
|
|
472
|
+
Follow the snake_case-to-camelCase-per-segment rule and preserve dot paths. Use the original API field names when calling the SDK; use the camelCased paths in `SchemaConfig`/AppConfig.
|
|
323
473
|
|
|
324
|
-
|
|
474
|
+
---
|
|
325
475
|
|
|
326
|
-
## FQDN-Specific Implementation Checklist
|
|
476
|
+
## 9) FQDN-Specific Implementation Checklist
|
|
327
477
|
|
|
328
478
|
### Core Requirements (Always Required)
|
|
329
479
|
|
|
330
|
-
✅ **Schema Extraction**: Used fqdn_schema
|
|
480
|
+
✅ **Schema Extraction**: Used fqdn_info and/or fqdn_schema tools to understand entity structure
|
|
331
481
|
✅ **Client Library**: Used client_lib tool to identify correct SDK package
|
|
332
482
|
✅ **Field Mapping**: Mapped FQDN field types to AutoPatterns field types
|
|
333
|
-
✅ **Entity Info Mapping**: Mapped FQDN entity info to SchemaConfig properties (containsPii, extensible)
|
|
334
483
|
✅ **🛑 MANDATORY: Empty Query Operators**: Set `supportedQueryOperators: []` for ALL fields to avoid TypeScript errors
|
|
335
484
|
✅ **⚠️ CRITICAL: Field ID Conversion**: Converted individual field segments from snake_case to camelCase while preserving field path structure in SchemaConfig and AppConfig
|
|
485
|
+
✅ **Package Installation**: Installed the exact SDK package reported by `client_lib` (e.g., `@wix/crm` for Contacts v4)
|
|
486
|
+
✅ **Implementation Choice**: Chose either full implementation or foundation with guidance approach
|
|
487
|
+
✅ **Pagination Shape**: Return the correct pagination shape from `find` (cursor vs offset per MCP)
|
|
336
488
|
✅ **AppConfig Update**: Set `entityTypeSource: "custom"` and provided custom.id
|
|
337
|
-
✅ **Custom Data Source Structure**: Followed
|
|
489
|
+
✅ **Custom Data Source Structure**: Followed proper folder structure and registration
|
|
338
490
|
✅ **Hook Implementation**: Created useCustomDataSources hook for accessing React context
|
|
339
|
-
✅
|
|
491
|
+
✅ **Registration**: Registered the custom data source in `AutoPatternsOverridesProvider`
|
|
492
|
+
✅ **Matching IDs**: Used matching `custom.id` in AppConfig
|
|
340
493
|
|
|
341
494
|
### Optional Enhancements (Only When Explicitly Requested)
|
|
342
495
|
|
|
@@ -345,11 +498,10 @@ If the user specifically requests custom actions for your FQDN-based data source
|
|
|
345
498
|
⚠️ **Custom Components**: Only implement if user requests custom entity page components
|
|
346
499
|
⚠️ **Bulk Operations**: Only implement if user requests custom bulk actions beyond standard bulk delete
|
|
347
500
|
|
|
348
|
-
## Common FQDN-Specific Pitfalls to Avoid
|
|
501
|
+
## 10) Common FQDN-Specific Pitfalls to Avoid
|
|
349
502
|
|
|
350
503
|
- **⚠️ CRITICAL: Implementing Unnecessary Overrides**: Do NOT implement custom actions, column overrides, or custom components unless explicitly requested by the user - a basic dashboard page only needs the core custom data source
|
|
351
504
|
- **⚠️ CRITICAL: Inconsistent Field ID Casing**: Failing to convert individual field segments from snake_case to camelCase while preserving field path structure in SchemaConfig and AppConfig - this is the most common mistake and will cause field mapping failures
|
|
352
|
-
- **⚠️ CRITICAL: Implementing Actions**: DO NOT implement the schema actions - they should contain helpful comments and throw unimplemented exceptions for the user to complete
|
|
353
505
|
- **🛑 CRITICAL: Query Operators MUST Be Empty Array**: You **MUST** use `supportedQueryOperators: []` (empty array) for all fields - attempting to specify actual operators will cause TypeScript compilation errors and is not supported for custom data sources
|
|
354
506
|
- **Mismatched Field Types**: Ensure FQDN field types are correctly mapped to AutoPatterns types
|
|
355
507
|
- **Wrong Client Library**: Use the exact client library returned by the client_lib tool
|
|
@@ -357,10 +509,15 @@ If the user specifically requests custom actions for your FQDN-based data source
|
|
|
357
509
|
- **Display Field Selection**: Choose a display field that provides meaningful identification from your FQDN schema
|
|
358
510
|
- **Custom Data Source ID Mismatch**: Ensure the custom.id in AppConfig matches your custom data source identifier
|
|
359
511
|
- **Hook Registration**: Don't forget to register the custom data source through the useCustomDataSources hook
|
|
512
|
+
- **Mixing snake_case and camelCase**: In `SchemaConfig`/AppConfig field ids
|
|
513
|
+
- **Returning the wrong pagination shape**: From `find` action
|
|
514
|
+
- **Forgetting to pass `revision`**: On updates (especially v4/v5 APIs)
|
|
515
|
+
- **Using the wrong client library**: Always trust `client_lib` result
|
|
516
|
+
- **Missing error handling**: When implementing actions, wrap HTTP calls with proper error handling
|
|
360
517
|
|
|
361
|
-
|
|
518
|
+
---
|
|
362
519
|
|
|
363
|
-
## Advanced Customization (Only When Explicitly Requested)
|
|
520
|
+
## 11) Advanced Customization (Only When Explicitly Requested)
|
|
364
521
|
|
|
365
522
|
**⚠️ IMPORTANT**: The following customizations should only be implemented when the user explicitly requests them. A basic dashboard page does not require these advanced features.
|
|
366
523
|
|
|
@@ -373,3 +530,10 @@ For advanced customization options when specifically requested, refer to these s
|
|
|
373
530
|
- "Custom Overrides" - For column overrides and custom components
|
|
374
531
|
|
|
375
532
|
By following these steps, you'll successfully implement a custom data source that integrates seamlessly with AutoPatternsApp while leveraging Wix Business APIs through their FQDNs.
|
|
533
|
+
|
|
534
|
+
## 12) See also
|
|
535
|
+
|
|
536
|
+
- `schema_config.md` – Full `SchemaConfig` interface and field types
|
|
537
|
+
- `auto-patterns-guide.md` – End-to-end Auto-Patterns overview
|
|
538
|
+
|
|
539
|
+
|