@wix/auto-patterns 1.15.0 → 1.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/dist/cjs/components/AutoPatternsCollectionPageContent/AutoPatternsCollectionPageContent.js +16 -4
  2. package/dist/cjs/components/AutoPatternsCollectionPageContent/AutoPatternsCollectionPageContent.js.map +1 -1
  3. package/dist/cjs/components/AutoPatternsCollectionPageContent/SkeletonCollection.js +34 -0
  4. package/dist/cjs/components/AutoPatternsCollectionPageContent/SkeletonCollection.js.map +1 -0
  5. package/dist/cjs/components/AutoPatternsEntityPage/AutoPatternsEntityPage.js +1 -0
  6. package/dist/cjs/components/AutoPatternsEntityPage/AutoPatternsEntityPage.js.map +1 -1
  7. package/dist/cjs/components/AutoPatternsEntityPage/SkeletonEntity.js +198 -0
  8. package/dist/cjs/components/AutoPatternsEntityPage/SkeletonEntity.js.map +1 -0
  9. package/dist/cjs/components/AutoPatternsRoute/AutoPatternsPage.js +13 -3
  10. package/dist/cjs/components/AutoPatternsRoute/AutoPatternsPage.js.map +1 -1
  11. package/dist/cjs/components/AutoPatternsRoute/AutoPatternsRoutes.js +4 -4
  12. package/dist/cjs/components/AutoPatternsRoute/AutoPatternsRoutes.js.map +1 -1
  13. package/dist/cjs/hooks/useBaseTableFeatures.js +7 -2
  14. package/dist/cjs/hooks/useBaseTableFeatures.js.map +1 -1
  15. package/dist/cjs/hooks/useCollectionPageOnRowClickActions.js +49 -0
  16. package/dist/cjs/hooks/useCollectionPageOnRowClickActions.js.map +1 -0
  17. package/dist/cjs/hooks/useNavigationUtils.js +2 -2
  18. package/dist/cjs/hooks/useNavigationUtils.js.map +1 -1
  19. package/dist/cjs/providers/PatternsWizardOverridesContext.js +1 -1
  20. package/dist/cjs/providers/PatternsWizardOverridesContext.js.map +1 -1
  21. package/dist/cjs/providers/SchemaContext.js +4 -3
  22. package/dist/cjs/providers/SchemaContext.js.map +1 -1
  23. package/dist/cjs/types/CollectionPageConfig.js.map +1 -1
  24. package/dist/cjs/types/actions/base.js.map +1 -1
  25. package/dist/cjs/types/actions/collectionPageActions.js.map +1 -1
  26. package/dist/cjs/utils/actions/resolveAction.js +2 -1
  27. package/dist/cjs/utils/actions/resolveAction.js.map +1 -1
  28. package/dist/cjs/utils/actions/types.js.map +1 -1
  29. package/dist/docs/action_cell.md +233 -0
  30. package/dist/docs/app_config_structure.md +356 -0
  31. package/dist/docs/auto-patterns-guide.md +2467 -0
  32. package/dist/docs/bulk_actions.md +266 -0
  33. package/dist/docs/collection_page.md +54 -0
  34. package/dist/docs/collection_page_actions.md +343 -0
  35. package/dist/docs/custom_overrides.md +511 -0
  36. package/dist/docs/entity_page.md +104 -0
  37. package/dist/docs/entity_page_actions.md +92 -0
  38. package/dist/docs/index.md +76 -0
  39. package/dist/docs/installation.md +55 -0
  40. package/dist/docs/introduction.md +74 -0
  41. package/dist/docs/pages_configuration.md +129 -0
  42. package/dist/docs/recipe-bulk-operations.md +1352 -0
  43. package/dist/docs/recipe-crud-operations.md +805 -0
  44. package/dist/docs/recipe-customization.md +1703 -0
  45. package/dist/docs/recipe-first-dashboard.md +795 -0
  46. package/dist/docs/sdk_and_schema.md +215 -0
  47. package/dist/esm/components/AutoPatternsCollectionPageContent/AutoPatternsCollectionPageContent.js +7 -1
  48. package/dist/esm/components/AutoPatternsCollectionPageContent/AutoPatternsCollectionPageContent.js.map +1 -1
  49. package/dist/esm/components/AutoPatternsCollectionPageContent/SkeletonCollection.js +21 -0
  50. package/dist/esm/components/AutoPatternsCollectionPageContent/SkeletonCollection.js.map +1 -0
  51. package/dist/esm/components/AutoPatternsEntityPage/AutoPatternsEntityPage.js +3 -1
  52. package/dist/esm/components/AutoPatternsEntityPage/AutoPatternsEntityPage.js.map +1 -1
  53. package/dist/esm/components/AutoPatternsEntityPage/SkeletonEntity.js +91 -0
  54. package/dist/esm/components/AutoPatternsEntityPage/SkeletonEntity.js.map +1 -0
  55. package/dist/esm/components/AutoPatternsRoute/AutoPatternsPage.js +5 -1
  56. package/dist/esm/components/AutoPatternsRoute/AutoPatternsPage.js.map +1 -1
  57. package/dist/esm/components/AutoPatternsRoute/AutoPatternsRoutes.js +1 -1
  58. package/dist/esm/components/AutoPatternsRoute/AutoPatternsRoutes.js.map +1 -1
  59. package/dist/esm/hooks/useBaseTableFeatures.js +6 -1
  60. package/dist/esm/hooks/useBaseTableFeatures.js.map +1 -1
  61. package/dist/esm/hooks/useCollectionPageOnRowClickActions.js +45 -0
  62. package/dist/esm/hooks/useCollectionPageOnRowClickActions.js.map +1 -0
  63. package/dist/esm/hooks/useNavigationUtils.js +1 -1
  64. package/dist/esm/hooks/useNavigationUtils.js.map +1 -1
  65. package/dist/esm/providers/PatternsWizardOverridesContext.js.map +1 -1
  66. package/dist/esm/providers/SchemaContext.js +3 -2
  67. package/dist/esm/providers/SchemaContext.js.map +1 -1
  68. package/dist/esm/types/CollectionPageConfig.js.map +1 -1
  69. package/dist/esm/types/actions/base.js.map +1 -1
  70. package/dist/esm/types/actions/collectionPageActions.js.map +1 -1
  71. package/dist/esm/utils/actions/resolveAction.js +2 -1
  72. package/dist/esm/utils/actions/resolveAction.js.map +1 -1
  73. package/dist/esm/utils/actions/types.js.map +1 -1
  74. package/dist/types/components/AutoPatternsCollectionPageContent/AutoPatternsCollectionPageContent.d.ts.map +1 -1
  75. package/dist/types/components/AutoPatternsCollectionPageContent/SkeletonCollection.d.ts +5 -0
  76. package/dist/types/components/AutoPatternsCollectionPageContent/SkeletonCollection.d.ts.map +1 -0
  77. package/dist/types/components/AutoPatternsEntityPage/SkeletonEntity.d.ts +7 -0
  78. package/dist/types/components/AutoPatternsEntityPage/SkeletonEntity.d.ts.map +1 -0
  79. package/dist/types/components/AutoPatternsRoute/AutoPatternsPage.d.ts.map +1 -1
  80. package/dist/types/hooks/useBaseTableFeatures.d.ts +1 -1
  81. package/dist/types/hooks/useBaseTableFeatures.d.ts.map +1 -1
  82. package/dist/types/hooks/useCollectionPageOnRowClickActions.d.ts +7 -0
  83. package/dist/types/hooks/useCollectionPageOnRowClickActions.d.ts.map +1 -0
  84. package/dist/types/hooks/useTableFeatures.d.ts +1 -1
  85. package/dist/types/hooks/useTableGridSwitchFeatures.d.ts +1 -1
  86. package/dist/types/providers/PatternsWizardOverridesContext.d.ts +2 -2
  87. package/dist/types/providers/PatternsWizardOverridesContext.d.ts.map +1 -1
  88. package/dist/types/providers/SchemaContext.d.ts +2 -1
  89. package/dist/types/providers/SchemaContext.d.ts.map +1 -1
  90. package/dist/types/types/CollectionPageConfig.d.ts +2 -1
  91. package/dist/types/types/CollectionPageConfig.d.ts.map +1 -1
  92. package/dist/types/types/actions/base.d.ts +1 -0
  93. package/dist/types/types/actions/base.d.ts.map +1 -1
  94. package/dist/types/types/actions/collectionPageActions.d.ts +8 -0
  95. package/dist/types/types/actions/collectionPageActions.d.ts.map +1 -1
  96. package/dist/types/utils/actions/resolveAction.d.ts +1 -0
  97. package/dist/types/utils/actions/resolveAction.d.ts.map +1 -1
  98. package/dist/types/utils/actions/types.d.ts +1 -0
  99. package/dist/types/utils/actions/types.d.ts.map +1 -1
  100. package/package.json +26 -20
@@ -0,0 +1,1703 @@
1
+ # Recipe: Complete Customization Guide
2
+
3
+ **Use Case**: "I want to customize my dashboard - from basic styling to complex custom behavior and integrations"
4
+
5
+ This comprehensive guide covers customization from basic visual changes to advanced programmatic control.
6
+
7
+ ---
8
+
9
+ # AppConfig Structure
10
+
11
+ ## ⚠️ Configuration Rules
12
+
13
+ - **Configuration must come only from a JSON file** - never inline or from other sources
14
+ - **DO NOT fill optional fields unless explicitly requested** - leave optional properties undefined to avoid unnecessary complexity
15
+ - **After each configuration change, verify that the configuration strictly aligns with the structure described below** - any configuration entries not defined in this structure must be removed
16
+ - **When generating config for the first time, select up to 3 columns from the schema that best represent the entity**
17
+
18
+ ## ⚠️ Common Configuration Mistakes to Avoid
19
+
20
+ - Adding more than two pages
21
+ - Mixing page types in a single configuration
22
+ - Including undefined optional fields
23
+ - Selecting too many initial columns
24
+ - Not designating exactly one page as `appMainPage: true`
25
+ - Missing or inconsistent page relationships (parentPageId/entityPageId)
26
+ - Setting `stickyColumns` to invalid values (negative, zero, or exceeding column count)
27
+
28
+ ```ts
29
+ export interface AppConfig {
30
+ pages: {
31
+ id: string; // Page unique identifier (must be unique across the app)
32
+ type: 'collectionPage' | 'entityPage'; // Defines page type
33
+ appMainPage?: boolean; // Designates this page as the main page (exactly one page must have this set to true)
34
+ collectionPage?: {
35
+ route: {
36
+ path: string; // Route path for the collection page (e.g., '/')
37
+ };
38
+ title: {
39
+ text: string; // Main page title
40
+ hideTotal?: boolean; // Hide total items in header. Default: true
41
+ };
42
+ subtitle?: {
43
+ text: string; // Optional page subtitle
44
+ };
45
+ actions?: { // Defines page-level actions for the collection page
46
+ primaryActions?: {
47
+ type: 'action' | 'menu'; // Type of primary actions layout
48
+ action?: { // Required when type is 'action'
49
+ item: {
50
+ id: string; // Unique identifier for the action
51
+ type: 'create' | 'custom'; // Action type
52
+ label?: string; // Text displayed for the action
53
+ collection: {
54
+ collectionId: string; // ID of the Wix Data collection
55
+ entityTypeSource: 'cms'; // Data source type. Always 'cms'
56
+ };
57
+ create?: { // Required when type is 'create'
58
+ mode: 'page'; // Create mode
59
+ page: {
60
+ id: string; // Entity page ID to navigate to for creation
61
+ };
62
+ };
63
+ };
64
+ };
65
+ menu?: { // Required when type is 'menu'
66
+ label: string; // Label for the group
67
+ items: {}[]; // Array of action configurations, same structure as action.item, can include dividers
68
+ };
69
+ };
70
+ secondaryActions?: {
71
+ type: 'action' | 'menu'; // Type of secondary actions layout, same structure as primaryActions
72
+ action?: {}; // Same structure as primaryActions.action
73
+ menu?: {}; // Same structure as primaryActions.menu
74
+ };
75
+ };
76
+ components: [
77
+ {
78
+ entityPageId?: string; // ID of the entity page to navigate to when clicking a row
79
+ collection: {
80
+ collectionId: string; // ID of the Wix Data collection
81
+ entityTypeSource: 'cms'; // Data source type. Always 'cms'
82
+ reflectQueryInUrl?: boolean; // Reflects query state (search, filters, sorting) in the browser URL. Default: false
83
+ selectAllScope?: 'page' | 'all'; // Controls "Select All" scope. 'all' selects entire collection, 'page' selects only visible items. Default: 'all'
84
+ selectionUpdateMode?: 'preserve' | 'clear'; // Controls selection behavior when data changes. 'preserve' maintains selections, 'clear' clears them. Default: 'clear'
85
+ };
86
+ filters?: {
87
+ panelTitle?: string; // Title of the filters panel
88
+ items: {
89
+ id: string; // Unique identifier for the filter item
90
+ fieldId: string; // ID of the field to filter by (must be a valid type: NUMBER, DATETIME, BOOLEAN, ARRAY, ARRAY_STRING)
91
+ displayName?: string; // Display name of the filter item
92
+ openByDefault?: boolean; // Whether the filter item is open by default in the panel (accordion is open)
93
+ sectionTitle?: string; // Title of the filter section. Required if more than one section exists to prevent confusion
94
+ tagLabel?: string; // Label shown in Tag component in the table/grid when the filter is applied (e.g., "Age: 7")
95
+ numberConfig?: {
96
+ min?: number; // Minimum value
97
+ max?: number; // Maximum value
98
+ allowedDecimals?: true; // Decimal precision allowed
99
+ };
100
+ dateConfig?: {
101
+ mode?: 'ONLY_PREDEFINED' | 'ONLY_CUSTOM' | 'COMBINE'; // Determines filter behavior
102
+ presets?: (
103
+ | 'SEVEN_DAYS'
104
+ | 'FOURTEEN_DAYS'
105
+ | 'MONTH'
106
+ | 'TODAY'
107
+ | 'TOMORROW'
108
+ | 'NEXT_THREE_DAYS'
109
+ | 'NEXT_SEVEN_DAYS'
110
+ | 'NEXT_THIRTY_DAYS'
111
+ )[]; // Shown only if mode includes predefined presets (COMBINE or ONLY_PREDEFINED)
112
+ includeTime?: boolean; // Whether to allow time selection. Default is true
113
+ };
114
+ booleanConfig?: {
115
+ trueLabel?: string; // Label shown for the true value
116
+ falseLabel?: string; // Label shown for the false value
117
+ };
118
+ enumConfig?: {
119
+ options: {
120
+ value: string; // Enum option value
121
+ label: string; // Enum option label
122
+ }[];
123
+ selectionMode: 'single' | 'multiple'; // Selection behavior
124
+ optionType?:
125
+ | 'checkbox'
126
+ | 'inlineCheckbox'
127
+ | 'radio'
128
+ | 'select'; // Option rendering style
129
+ };
130
+ }[];
131
+ };
132
+ actionCell?: {
133
+ primaryAction?: {
134
+ item: {
135
+ id: string; // Unique identifier for the action
136
+ type: 'update' | 'delete' | 'custom'; // Action type
137
+ label?: string; // Text displayed for the action
138
+ skin?: string; // Visual appearance of the action button (see Action Button Skin Values section)
139
+ disabled?: boolean; // Whether the action is disabled
140
+ tooltip?: string; // Tooltip text shown on hover
141
+ update?: { // Required when type is 'update'
142
+ mode: 'page'; // Update mode
143
+ page?: { // Required when mode is 'page'
144
+ id: string; // Entity page ID to navigate to
145
+ };
146
+ };
147
+ delete?: { // Required when type is 'delete'
148
+ mode: 'modal'; // Currently only 'modal' is supported
149
+ modal: {
150
+ title?: {
151
+ text: string; // Modal title
152
+ };
153
+ description?: {
154
+ text: string; // Modal description
155
+ };
156
+ actions?: {
157
+ submit?: {
158
+ text: string; // Submit button text
159
+ };
160
+ cancel?: {
161
+ text: string; // Cancel button text
162
+ };
163
+ };
164
+ feedback?: {
165
+ successToast?: {
166
+ text: string; // Success message
167
+ };
168
+ errorToast?: {
169
+ text: string; // Error message
170
+ };
171
+ };
172
+ };
173
+ };
174
+ };
175
+ };
176
+ secondaryActions?: {
177
+ items: {}[]; // Array of action configurations, same structure as primaryAction.item, can include dividers
178
+ inlineCount?: number; // How many secondary actions to show inline before showing popover
179
+ inlineAlwaysVisible?: boolean; // Whether to always show inline actions (not just on hover)
180
+ };
181
+ };
182
+ bulkActionToolbar?: {
183
+ primaryActions?: ({
184
+ type: 'action' | 'menu'; // Type of bulk action item
185
+ action?: { // Required when type is 'action'
186
+ item: {
187
+ id: string; // Unique identifier for the bulk action
188
+ type: 'bulkDelete' | 'custom'; // Bulk action type
189
+ label?: string; // Text displayed for the action
190
+ bulkDelete?: { // Required when type is 'bulkDelete'
191
+ mode: 'modal'; // Currently only 'modal' is supported
192
+ modal: {
193
+ title?: {
194
+ text: string; // Modal title
195
+ };
196
+ description?: {
197
+ text: string; // Modal description
198
+ };
199
+ actions?: {
200
+ submit?: {
201
+ text: string; // Submit button text
202
+ };
203
+ cancel?: {
204
+ text: string; // Cancel button text
205
+ };
206
+ };
207
+ feedback?: {
208
+ successToast?: {
209
+ text: string; // Success message
210
+ };
211
+ errorToast?: {
212
+ text: string; // Error message
213
+ };
214
+ };
215
+ };
216
+ };
217
+ };
218
+ };
219
+ menu?: { // Required when type is 'menu'
220
+ label: string; // Label for the dropdown group
221
+ items: {}[] // Array of bulk actions configurations, same structure as action.item, can include dividers
222
+ };
223
+ })[];
224
+ secondaryActions?: {}[]; // Array of bulk actions configurations, same structure as primaryActions[].menu.items, can include dividers
225
+ };
226
+ toolbarTitle?: {
227
+ title: string; // Toolbar title above the table/grid
228
+ subtitle?: {
229
+ text: string; // Toolbar subtitle
230
+ };
231
+ showTotal?: boolean; // Show total items on toolbar. Default: false
232
+ };
233
+ search?: {
234
+ shown?: boolean; // Show/hide the search
235
+ };
236
+ emptyState?: {
237
+ title?: string; // Empty state title
238
+ subtitle?: string; // Empty state subtitle
239
+ image?: {
240
+ id: string; // Image ID for empty state
241
+ };
242
+ addNewCta?: {
243
+ id?: string; // Add New CTA ID
244
+ text?: string; // Add New CTA text
245
+ };
246
+ customCta?: {
247
+ id?: string; // Custom CTA ID
248
+ };
249
+ };
250
+ layout: [ // Array of layout items that define what components to render
251
+ {
252
+ type: 'Table'; // Layout item type for table rendering
253
+ table?: {
254
+ columns: {
255
+ id: string; // Field ID from the collection
256
+ name: string; // Column title displayed
257
+ width: string; // The width of the column (required in types)
258
+ sortable?: boolean; // If the column is sortable
259
+ defaultSortOrder?: 'asc' | 'desc'; // Optional default sort order
260
+ sortMode?: 'asc' | 'desc'; // Optional sorting mode
261
+ reorderDisabled?: boolean; // Whether column reordering is disabled
262
+ hideable?: boolean; // Whether column can be hidden
263
+ defaultHidden?: boolean; // Whether column is hidden by default
264
+ hiddenFromCustomColumnsSelection?: boolean; // Whether column is hidden from custom columns selection
265
+ }[];
266
+ customColumns?: {
267
+ enabled: boolean; // Enable user customization (hide/reorder columns)
268
+ };
269
+ stickyColumns?: number; // Number of columns to make sticky from the start. Sticky columns remain visible when horizontally scrolling.
270
+ };
271
+ },
272
+ {
273
+ type: 'Grid'; // Layout item type for grid rendering
274
+ grid?: {
275
+ item: {
276
+ titleFieldId: string; // Field ID to display as the item title
277
+ subtitleFieldId?: string; // Field ID for the item subtitle
278
+ imageFieldId?: string; // Field ID for the item image
279
+ /**
280
+ * Controls which content is shown in the card (preset):
281
+ * - 'full': Shows both title and subtitle.
282
+ * - 'title': Shows only the title.
283
+ * - 'empty': Hides both title and subtitle (card appears visually empty except for image or other content).
284
+ */
285
+ cardContentMode?: 'full' | 'title' | 'empty';
286
+ imagePlacement?: 'top' | 'side';
287
+ };
288
+ };
289
+ }
290
+ ]; // End of layout array
291
+ }
292
+ ]; // End of components array
293
+ };
294
+ entityPage?: {
295
+ route: {
296
+ path: string; // Route path for the entity page (e.g., '/product/:entityId')
297
+ params: {
298
+ id: string; // Maps dynamic parameter in path to its identifier
299
+ };
300
+ };
301
+ title?: {
302
+ text: string; // Entity page title
303
+ };
304
+ subtitle?: {
305
+ text: string; // Entity page subtitle
306
+ };
307
+ parentPageId?: string; // ID of the parent collection page
308
+ layout?: {
309
+ // Main layout section
310
+ main: {
311
+ type: 'card'; // Type of the card
312
+ card: {
313
+ title: {
314
+ text: string; // Title of the card
315
+ };
316
+ subtitle?: {
317
+ text: string; // Subtitle of the card
318
+ };
319
+ children: LayoutContent[]; // Array of content items that can be fields, nested containers, or components
320
+ };
321
+ }[];
322
+ // Sidebar layout section
323
+ sidebar?: {
324
+ type: 'card';
325
+ card: {
326
+ title: {
327
+ text: string; // Title of the card
328
+ };
329
+ subtitle?: {
330
+ text: string; // Subtitle of the card
331
+ };
332
+ children: LayoutContent[]; // Array of content items that can be fields, nested containers, or components
333
+ };
334
+ }[];
335
+ };
336
+ collectionId: string; // Related collection ID
337
+ entityTypeSource: 'cms'; // Data source type. Always 'cms'
338
+ };
339
+ }[];
340
+ }
341
+
342
+ type LayoutContent =
343
+ | {
344
+ type: 'field';
345
+ field: {
346
+ span?: number;
347
+ fieldId: string;
348
+ };
349
+ }
350
+ | {
351
+ type: 'container';
352
+ container: {
353
+ span?: number;
354
+ children: LayoutContent[];
355
+ };
356
+ }
357
+ | {
358
+ type: 'component';
359
+ component: {
360
+ span?: number;
361
+ componentId: string;
362
+ };
363
+ };
364
+ ```
365
+
366
+ ---
367
+
368
+ # Custom Overrides
369
+
370
+ ## ⚠️ Override Rules
371
+
372
+ - **Custom overrides are restricted to the defined areas only** - attempting to override or modify any other aspect of `AutoPatternsApp` is prohibited and can cause unexpected behavior
373
+ - **Always verify override implementation** - when implementing custom overrides, you MUST ensure they are correctly imported and passed to the `PatternsWizardOverridesProvider`
374
+
375
+ The `PatternsWizardOverridesProvider` allows you to inject custom code to override default behaviors or add additional functionality. Below are the areas where overrides can be applied:
376
+
377
+ > **Note:** These are the only areas where overrides are supported. Avoid attempting to override or modify other parts of the system, as this is not supported and may lead to unexpected behavior.
378
+
379
+ ## Folder Structure Organization
380
+
381
+ All custom overrides (components, modals, actions, columns, and other customizations) should be created in a `components` folder inside your page directory, not in a global `/src/components` folder. This keeps page-specific customizations organized alongside their respective pages.
382
+
383
+ ### Recommended Structure:
384
+
385
+ ```
386
+ your-page/
387
+ ├── page.tsx // Your main page component
388
+ ├── MyCollectionConfig.patterns.json // Configuration file
389
+ └── components/ // Page-specific components folder
390
+ ├── index.tsx // Exports all overrides for easy importing
391
+ ├── actions/ // Custom actions
392
+ │ ├── index.tsx
393
+ │ └── myCustomAction.tsx
394
+ ├── columns/ // Column overrides
395
+ │ ├── index.tsx
396
+ │ ├── name.ts
397
+ │ └── date.ts
398
+ └── customComponents/ // Custom entity page components
399
+ ├── index.tsx
400
+ ├── CustomNameField.tsx
401
+ └── InfoCard.tsx
402
+ ```
403
+
404
+ ### Importing Overrides in Your Page
405
+
406
+ In your page component, import from the local components folder:
407
+
408
+ ```tsx
409
+ import * as modals from './components/modals';
410
+ import * as actions from './components/actions';
411
+ import * as columns from './components/columns';
412
+ import * as components from './components/customComponents';
413
+
414
+ <PatternsWizardOverridesProvider value={{ modals, actions, columns, components }}>
415
+ <AutoPatternsApp configuration={config as AppConfig} />
416
+ </PatternsWizardOverridesProvider>
417
+ ```
418
+
419
+ ### Important: Updating Index Files
420
+
421
+ **When adding any new implementation (action, modal, column, or component), you MUST update the corresponding `index.tsx` file to export your new implementation.** The main page component imports from these index files, so they serve as the central export point for each type of override.
422
+
423
+ For example:
424
+ - Adding a new action → Update `./components/actions/index.tsx`
425
+ - Adding a new modal → Update `./components/modals/index.tsx`
426
+ - Adding a new column override → Update `./components/columns/index.tsx`
427
+ - Adding a new custom component → Update `./components/customComponents/index.tsx`
428
+
429
+ Without updating the index files, your implementations won't be available to the `PatternsWizardOverridesProvider`.
430
+
431
+ ## ⚠️ Common Override Mistakes to Avoid
432
+
433
+ - Attempting to override unsupported areas
434
+ - Invalid column rendering functions
435
+ - Missing index file exports for new implementations
436
+ - Incorrect import paths or naming mismatches
437
+
438
+ ## Columns
439
+
440
+ Each column in the table has a default rendering based on its field type. You can override this rendering by providing a custom function for the `column.id`. This allows you to customize how specific columns are displayed.
441
+
442
+ **Enhanced Column Overrides**: Column override can receive both the individual column `value` and the entire `row` data, enabling you to create complex columns that combine multiple field values from the same row.
443
+
444
+ ### Function Signature
445
+
446
+ ```typescript
447
+ function columnOverride({ value, row }) {
448
+ // value: The individual column value
449
+ // row: The entire row object containing all field values
450
+ return <YourCustomRendering />;
451
+ }
452
+ ```
453
+
454
+ ### Understanding Row Data
455
+
456
+ **Important**: The `row` object contains all field values from the entity, where each property corresponds to a **field ID** from the collection schema. To access specific field values, use the exact field ID as defined in your collection schema.
457
+
458
+ For example, if your collection schema has these fields:
459
+ ```json
460
+ {
461
+ "fields": [
462
+ { "key": "name", "displayName": "Pet Name", "type": "TEXT" },
463
+ { "key": "age", "displayName": "Age", "type": "NUMBER" },
464
+ { "key": "isVaccinated", "displayName": "Vaccinated", "type": "BOOLEAN" },
465
+ { "key": "lastActivity", "displayName": "Last Activity", "type": "DATETIME" }
466
+ ]
467
+ }
468
+ ```
469
+
470
+ Then in your column override, you access these values using the field IDs:
471
+ ```typescript
472
+ export function myColumn({ value, row }) {
473
+ // Access field values using their schema field IDs
474
+ const petName = row.name; // "name" field ID
475
+ const petAge = row.age; // "age" field ID
476
+ const isVaccinated = row.isVaccinated; // "isVaccinated" field ID
477
+ const lastActivity = row.lastActivity; // "lastActivity" field ID
478
+
479
+ return <YourCustomRendering />;
480
+ }
481
+ ```
482
+
483
+ ### Use Cases for Row Data Access
484
+
485
+ 1. **Complex Display Columns**: Combine multiple fields into a single display (e.g., "Name (Age)" combining name and age fields)
486
+ 2. **Conditional Rendering**: Show different content based on other field values in the same row
487
+ 3. **Calculated Columns**: Create computed values using multiple row fields
488
+ 4. **Cross-Field Validation Display**: Show validation status based on relationships between fields
489
+
490
+ ### Example: Defining and Using Column Overrides
491
+
492
+ In `components/columns/name.tsx`:
493
+
494
+ ```ts
495
+ import React from 'react';
496
+
497
+ export function name({ value, row }) {
498
+ // Simple value formatting
499
+ return <strong>{value}</strong>;
500
+ }
501
+ ```
502
+
503
+ In `components/columns/petInfo.tsx`:
504
+
505
+ ```ts
506
+ import React from 'react';
507
+ import { Box, Text } from '@wix/design-system';
508
+
509
+ export function petInfo({ value, row }) {
510
+ // Complex column combining multiple row values
511
+ return (
512
+ <Box direction="vertical" gap={1}>
513
+ <Text weight="bold">{row.name}</Text>
514
+ <Text size="small" skin="disabled">
515
+ {row.age} years old • {row.type}
516
+ </Text>
517
+ {row.isVaccinated && (
518
+ <Text size="tiny" skin="success">✓ Vaccinated</Text>
519
+ )}
520
+ </Box>
521
+ );
522
+ }
523
+ ```
524
+
525
+ In `components/columns/status.tsx`:
526
+
527
+ ```ts
528
+ import React from 'react';
529
+ import { Badge } from '@wix/design-system';
530
+
531
+ export function status({ value, row }) {
532
+ // Conditional rendering based on multiple row fields
533
+ if (row.isVaccinated && row.age > 1) {
534
+ return <Badge skin="success">Ready for Adoption</Badge>;
535
+ } else if (!row.isVaccinated) {
536
+ return <Badge skin="warning">Needs Vaccination</Badge>;
537
+ } else {
538
+ return <Badge skin="neutral">Too Young</Badge>;
539
+ }
540
+ }
541
+ ```
542
+
543
+ In `components/columns/fullName.tsx`:
544
+
545
+ ```ts
546
+ import React from 'react';
547
+
548
+ export function fullName({ value, row }) {
549
+ // Calculated column using multiple fields
550
+ return `${row.name} (owned by ${row.owner})`;
551
+ }
552
+ ```
553
+
554
+ In `components/columns/date.tsx`:
555
+
556
+ ```ts
557
+ import React from 'react';
558
+
559
+ export function date({ value, row }) {
560
+ // Access to other row data for enhanced date formatting
561
+ const isRecent = row.lastActivity && new Date(row.lastActivity) > new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
562
+
563
+ return (
564
+ <span style={{ color: isRecent ? 'green' : 'inherit' }}>
565
+ <em>{new Date(value).toLocaleDateString()}</em>
566
+ {isRecent && ' (Recent)'}
567
+ </span>
568
+ );
569
+ }
570
+ ```
571
+
572
+ In `components/columns/index.tsx`:
573
+
574
+ ```ts
575
+ export * from './name';
576
+ export * from './petInfo';
577
+ export * from './status';
578
+ export * from './fullName';
579
+ export * from './date';
580
+ ```
581
+
582
+ **Important:** Every time you add a new column override file, you must add a corresponding export line to this `index.tsx` file. For example, if you create `price.tsx`, you must add `export * from './price';` to the index file.
583
+
584
+ In the `PatternsWizardOverridesProvider`:
585
+
586
+ ```tsx
587
+ import * as columns from './components/columns';
588
+
589
+ <PatternsWizardOverridesProvider value={{ columns }}>
590
+ <AutoPatternsApp configuration={config as AppConfig} />
591
+ </PatternsWizardOverridesProvider>
592
+ ```
593
+
594
+ ### Visual Representation
595
+
596
+ ```
597
+ your-page/
598
+ └── components/
599
+ └── columns/
600
+ ├── index.tsx // Exports all column overrides
601
+ ├── name.tsx // Simple value formatting
602
+ ├── petInfo.tsx // Complex multi-field column
603
+ ├── status.tsx // Conditional rendering column
604
+ ├── fullName.tsx // Calculated column
605
+ └── date.tsx // Enhanced formatting with row context
606
+
607
+ PatternsWizardOverridesProvider
608
+ └── value.columns
609
+ ├── name
610
+ ├── petInfo
611
+ ├── status
612
+ ├── fullName
613
+ └── date
614
+ ```
615
+
616
+ ### Key Benefits of Row Data Access
617
+
618
+ 1. **Reduced Configuration Complexity**: Instead of adding multiple columns, create one complex column that shows related information
619
+ 2. **Better User Experience**: Present related data together in a logical, readable format
620
+ 3. **Dynamic Content**: Show different content based on the state of other fields
621
+ 4. **Data Relationships**: Highlight relationships between different field values in the same entity
622
+
623
+ ### Important Guidelines
624
+
625
+ - **Performance**: Remember that column functions are called for every row, so keep calculations lightweight
626
+ - **Consistency**: When using row data, ensure the column header accurately represents what's displayed
627
+ - **Accessibility**: Maintain proper semantic structure when combining multiple values
628
+
629
+ ## Components
630
+
631
+ Components allow you to create custom rendering for specific elements in the entity page. Each component has a unique `componentId` that corresponds to the ID specified in the layout configuration.
632
+
633
+ The custom components receive two essential props:
634
+
635
+ 1. **form**: An instance of `UseFormReturn` from react-hook-form (re-exported through `@wix/auto-patterns/form`), giving you access to the form control, methods, and state.
636
+ 2. **entity**: A key-value object where keys are field IDs from the collection schema and values are the current field values, providing access to the entity's data.
637
+
638
+ Custom components can serve two main purposes:
639
+
640
+ ### 1. Standalone Custom Components
641
+
642
+ These components can display custom UI elements like notifications, information cards, or any other custom content that isn't directly tied to specific fields. These are useful for adding unique UI elements that enhance the entity page experience.
643
+
644
+ ### 2. Field Rendering Overrides
645
+
646
+ You can use custom components to override the default rendering of one or more fields. This allows you to:
647
+ - Apply custom validation logic
648
+ - Create custom input components
649
+ - Combine multiple fields into a single UI component
650
+ - Add field-specific functionality not available in the default renderers
651
+
652
+ ### Using the useController Hook for Field Overrides
653
+
654
+ When creating field overrides, use the `useController` hook from `@wix/auto-patterns/form` (a re-export of react-hook-form's hook) to connect your custom component to the form state:
655
+
656
+ ```tsx
657
+ import { useController } from '@wix/auto-patterns/form'; // Always import from this path, not react-hook-form
658
+ ```
659
+
660
+ The hook requires:
661
+ - **name**: The field name you want to edit (should match the schema field ID)
662
+ - **control**: Retrieved from `form.control`
663
+ - **defaultValue**: Set from `entity?.[fieldId]` when it exists
664
+
665
+ ### Example: Defining a Custom Component
666
+
667
+ Here's an example of a custom component that overrides the rendering of the "name" field:
668
+
669
+ ```tsx
670
+ import React, { FC } from 'react';
671
+ import { Box, Card, FormField, Input, Text } from '@wix/design-system';
672
+ import { useController } from '@wix/auto-patterns/form';
673
+ import { CustomComponentProps } from '@wix/auto-patterns/types';
674
+
675
+ export const customNameField: FC<CustomComponentProps> = ({ form, entity }) => {
676
+ // Create a controller for the name field
677
+ const controller = useController({
678
+ name: 'name', // Field ID from the schema
679
+ control: form.control, // Form control
680
+ defaultValue: entity?.name, // Default value from entity
681
+ });
682
+
683
+ return (
684
+ <FormField
685
+ label="Name"
686
+ required={true}
687
+ charCount={100}
688
+ // Connect field state to UI
689
+ status={controller.fieldState.invalid ? 'error' : undefined}
690
+ statusMessage={controller.fieldState.error?.message}
691
+ dataHook={`short-text-${controller.field.name}`}
692
+ >
693
+ <Input
694
+ // Connect field value and onChange
695
+ value={controller.field.value}
696
+ onChange={(e) => controller.field.onChange(e.target.value)}
697
+ dataHook={`short-text-${controller.field.name}`}
698
+ />
699
+ </FormField>
700
+ );
701
+ };
702
+ ```
703
+
704
+
705
+ ### Example: Standalone Component (Not Field-Specific)
706
+
707
+ Custom components can also be used to add UI elements not tied to specific fields:
708
+
709
+ ```tsx
710
+ import React, { FC } from 'react';
711
+ import { Box, Card, Text, Button } from '@wix/design-system';
712
+ import { CustomComponentProps } from '@wix/auto-patterns/types';
713
+
714
+ export const infoCard: FC<CustomComponentProps> = ({ entity }) => {
715
+ return (
716
+ <Card>
717
+ <Card.Content>
718
+ <Box direction="vertical" gap={2}>
719
+ <Text weight="bold">Important Information</Text>
720
+ <Text>
721
+ This custom component can display additional information or functionality
722
+ that isn't directly tied to a specific field.
723
+ </Text>
724
+ {entity?.isVaccinated ? (
725
+ <Text skin="success">This pet is vaccinated</Text>
726
+ ) : (
727
+ <Text skin="warning">This pet needs vaccination</Text>
728
+ )}
729
+ </Box>
730
+ </Card.Content>
731
+ </Card>
732
+ );
733
+ };
734
+ ```
735
+
736
+ ### Connecting Components in the Provider
737
+
738
+ In your main page file, import and provide these components via the `PatternsWizardOverridesProvider`:
739
+
740
+ ```tsx
741
+ import * as components from './components';
742
+
743
+ <PatternsWizardOverridesProvider value={{ components }}>
744
+ <AutoPatternsApp configuration={config as AppConfig} />
745
+ </PatternsWizardOverridesProvider>
746
+ ```
747
+
748
+ ### Important Guidelines for Custom Components
749
+
750
+ 1. **Always import from `@wix/auto-patterns/form`** instead of directly from `react-hook-form`
751
+ 2. **Follow react-hook-form best practices** - the underlying infrastructure is built on react-hook-form
752
+ 3. **Handle form state properly**:
753
+ - Use `controller.fieldState.invalid` for error state
754
+ - Use `controller.fieldState.error?.message` for error messages
755
+ - Connect `controller.field.value` to input values
756
+ - Use `controller.field.onChange` for change handlers
757
+ 4. **Component rendering**:
758
+ - Choose appropriate design-system components based on the field type
759
+ - For text fields: `Input`
760
+ - For multi-line text: `InputArea`
761
+ - For checkboxes: `Checkbox`
762
+ - For dates: `DatePicker`
763
+ - For dropdowns: `Dropdown`
764
+
765
+ **Important:** Every time you create a new custom component, you must add a corresponding export line to the `./components/customComponents/index.tsx` file. For example, if you create `StatusIndicator.tsx`, you must add `export * from './StatusIndicator';` to the index file.
766
+
767
+ ### Understanding Reactivity in Custom Components
768
+
769
+ 5. **Reactivity and field value changes (IMPORTANT)**:
770
+ - **NEVER rely on the `entity` object for reactive UI** - it is not reactive to form changes
771
+ - For any reactive UI that needs to respond to field value changes in real-time:
772
+ - Use `form.watch('fieldName')` to observe field changes reactively
773
+ - Use `useController` hook when you need both read and write access to a field
774
+
775
+ #### Common Reactivity Issues and Solutions
776
+
777
+ ##### Example: Conditional Display Based on Field Value
778
+
779
+ ```tsx
780
+ // ❌ INCORRECT APPROACH (Non-reactive)
781
+ const CustomComponent: FC<CustomComponentProps> = ({ form, entity }) => {
782
+ // This won't update when the user changes the name in the form
783
+ const showSpecialMessage = entity?.name === 'special';
784
+
785
+ return (
786
+ <Box>
787
+ <Input
788
+ value={form.getValues('name')}
789
+ onChange={(e) => form.setValue('name', e.target.value)}
790
+ />
791
+
792
+ {showSpecialMessage && (
793
+ <Text>Special message for special name!</Text>
794
+ )}
795
+ </Box>
796
+ );
797
+ };
798
+ ```
799
+
800
+ ```tsx
801
+ // ✅ CORRECT APPROACH (Reactive)
802
+ const CustomComponent: FC<CustomComponentProps> = ({ form, entity }) => {
803
+ // This WILL update whenever the name field changes
804
+ const nameValue = form.watch('name');
805
+ const showSpecialMessage = nameValue === 'special';
806
+
807
+ return (
808
+ <Box>
809
+ <Input
810
+ value={nameValue}
811
+ onChange={(e) => form.setValue('name', e.target.value)}
812
+ />
813
+
814
+ {showSpecialMessage && (
815
+ <Text>Special message for special name!</Text>
816
+ )}
817
+ </Box>
818
+ );
819
+ };
820
+ ```
821
+
822
+
823
+ ##### When to Use the Entity Object
824
+
825
+ The `entity` object is useful for:
826
+ - Setting initial values
827
+ - Accessing read-only data that doesn't change
828
+ - Comparing form state with original values (e.g., detecting if changes were made)
829
+ - Initializing form fields with useController's defaultValue parameter
830
+
831
+ ```tsx
832
+ // Example: Proper use of entity object with useController
833
+ const CustomComponent: FC<CustomComponentProps> = ({ form, entity }) => {
834
+ // Use entity for initialization via defaultValue
835
+ const controller = useController({
836
+ name: 'name', // Field ID from the schema
837
+ control: form.control,
838
+ defaultValue: entity?.name // Initialize from entity
839
+ });
840
+
841
+ // Use watch for reactive updates
842
+ const currentName = controller.field.value;
843
+ const hasChanges = entity?.name !== currentName;
844
+
845
+ return (
846
+ <Box>
847
+ <FormField label="Name">
848
+ <Input
849
+ value={currentName}
850
+ onChange={(e) => controller.field.onChange(e.target.value)}
851
+ />
852
+ </FormField>
853
+ {hasChanges && (
854
+ <Text size="small">Original value: {entity?.name}</Text>
855
+ )}
856
+ </Box>
857
+ );
858
+ };
859
+ ```
860
+
861
+ ### Visual Representation
862
+
863
+ ```
864
+ your-page/
865
+ └── components/
866
+ ├── index.tsx // Exports all component overrides
867
+ ├── customNameField.tsx // Field override component
868
+ ├── combinedNameFields.tsx // Multiple fields override
869
+ └── infoCard.tsx // Standalone component
870
+
871
+ PatternsWizardOverridesProvider
872
+ └── value.components
873
+ ├── customNameField
874
+ ├── combinedNameFields
875
+ └── infoCard
876
+ ```
877
+
878
+ By using these component overrides, you can tailor the behavior and appearance of your `AutoPatternsApp` to meet specific requirements beyond what the default rendering provides.
879
+
880
+ ---
881
+
882
+ # Collection Page Configuration
883
+
884
+ ## ⚠️ Collection Page Rules
885
+
886
+ - **Components array inside collectionPage must contain exactly one component with a layout array**
887
+ - **All collection pages with tables/grids must reference their corresponding entity page via `entityPageId`** in the collection configuration
888
+ - **Enable `customColumns` only based on strict logic** - enable if more than 5 columns are defined OR user explicitly requests it, otherwise disable
889
+ - **Row click behavior**: By default, clicking a table row navigates to the entity page. Use `onRowClick` configuration only when custom row click behavior is explicitly required
890
+ - **When generating config for first time, select up to 3 columns from the schema that best represent the entity**
891
+
892
+ ## Components Array
893
+
894
+ * Must include **exactly one item**.
895
+ * Each component must have:
896
+ * `collection`: Collection configuration with `collectionId` and `entityTypeSource: 'cms'`
897
+ * `layout`: Array of layout items that determine what components to render
898
+
899
+ ## Layout Array
900
+
901
+ The `layout` array contains the rendering components for the collection. Each layout item has:
902
+ * `type`: Either 'Table' or 'Grid'
903
+ * Component-specific configuration (`table` or `grid` object)
904
+
905
+ ### Layout Item Types:
906
+
907
+ 1. **Table Layout Item** (`type: 'Table'`):
908
+ * `table` field contains table-specific configuration
909
+ * Used for displaying collection in a **table view**
910
+ * Includes columns, actionCell, bulkActionToolbar, etc.
911
+
912
+ 2. **Grid Layout Item** (`type: 'Grid'`):
913
+ * `grid` field contains grid-specific configuration
914
+ * Used for **grid (card) view** of collection
915
+ * Includes item configuration for title/subtitle/image fields
916
+
917
+ ### Table/Grid View Switch Behavior:
918
+ * When **both** Table and Grid layout items are present in the layout array, AutoPatterns automatically adds a Table/Grid view switch control so users can toggle between the two views
919
+ * Users can toggle between table and grid views
920
+
921
+ ## Table Configuration
922
+
923
+ * Used for displaying collection in a **table view**.
924
+ * **customColumns.enabled** logic:
925
+ * Enable if:
926
+ * More than **5 columns** are defined
927
+ * OR user **explicitly** requests it
928
+ * Otherwise, **disable** (false)
929
+
930
+ ## Grid Configuration
931
+
932
+ * Used for **grid (card) view** of collection.
933
+ * `item.title`, `item.subtitle`, `item.image` fields are **Field IDs** from the schema.
934
+ * If the user does not specify, **select the most relevant fields automatically**.
935
+ * For grid components, it is strongly recommended to implement a primary action cell with an `update` action that navigates to the entity page. This provides users with an intuitive way to access detailed information and edit individual entities directly from the grid view.
936
+
937
+ ---
938
+
939
+ # Collection Page Actions
940
+
941
+ ## ⚠️ Required Actions
942
+
943
+ - **Every collection page must include a create action that navigates to the entity page for adding new entities** - this is essential for user workflow
944
+
945
+ The `actions` property is an optional object within the `collectionPage` configuration, but it is strongly recommended to always include primaryActions with a create action for better user experience.
946
+
947
+ ## `primaryActions` and `secondaryActions` Structure
948
+
949
+ Both `primaryActions` and `secondaryActions` are optional and share the same underlying structure for defining how actions are displayed. They can be configured in one of two ways:
950
+
951
+ ### A. Action Layout (`type: "action"`)
952
+ * **Description**: This layout is used to display a single, prominent page-level action. For example, a "Create New Item" button.
953
+ * **`action.item`**: Contains the configuration for the single action.
954
+
955
+ ### B. Action Menu Layout (`type: "menu"`)
956
+ * **Description**: This layout groups several page-level actions, often rendered as a dropdown menu or a set of related buttons under a common label.
957
+ * **`menu.label`**: A string that serves as the title or accessible label for the group of actions.
958
+ * **`menu.items`**: A flat array of action configurations, which can include divider objects for visual separation.
959
+
960
+ ## Individual Action Configuration
961
+
962
+ Each individual action, whether standalone in an `action` layout or part of an `items` array in a `menu` layout, is defined by the action item structure (see `AppConfig Structure`).
963
+
964
+ In addition to these common properties, each action item must specify a `type` which determines the action's behavior and additional required configuration.
965
+
966
+ ### 1. `type: "create"`
967
+ * **Purpose**: Navigates to an entity page, allowing the user to create a new item in the specified collection.
968
+ * **Details**:
969
+ * `create.mode`: Must be `'page'`.
970
+ * `create.page.id`: Must be the `id` of an existing `entityPage` in your `AppConfig`. This entity page should be set up to handle the creation of new entities for the `collection.collectionId`.
971
+
972
+ ### 2. `type: "custom"`
973
+ * **Purpose**: Executes custom JavaScript logic defined in your application's overrides.
974
+ * **Details**:
975
+ * The `custom` object in the configuration is typically empty. The functionality is determined by a custom action resolver function that you implement and register in the `actions` section of your `PatternsWizardOverridesProvider`. The `id` of this action item must exactly match the name (key) of the registered custom action resolver. The resolver will receive parameters including `collectionId`.
976
+
977
+ ### 3. `type: "divider"`
978
+ * **Purpose**: Creates a visual separator between action groups in menus and lists.
979
+ * **Details**:
980
+ * Divider actions require no additional configuration beyond `{ "type": "divider" }`.
981
+ * Used within flat arrays to create logical groupings.
982
+
983
+ ## Note on `secondaryActions`
984
+
985
+ `secondaryActions` follow the exact same structural rules (`type: "action"` or `type: "menu"`) and use the same action item options as `primaryActions`. They are typically used for less prominent or less frequently used page-level actions, often rendered in a secondary position or within a "more options" style menu.
986
+
987
+ ## Custom Collection Page Action Configuration
988
+
989
+ Custom collection page actions execute JavaScript code that you define for collection-level operations. These actions receive parameters that give them access to collection context and utilities. Here's how to implement a custom collection page action:
990
+
991
+ 1. First, create the actions folder structure in your page folder:
992
+ ```
993
+ your-page/
994
+ ├── page.tsx
995
+ └── components/
996
+ └── actions/
997
+ ├── index.tsx // Exports all actions
998
+ └── exportCollection.tsx // Your custom collection action
999
+ ```
1000
+
1001
+ 2. Create your collection action handler in `exportCollection.tsx`:
1002
+ ```typescript
1003
+ import { CustomActionCollectionPageActionResolver } from '@wix/auto-patterns';
1004
+ import React from 'react';
1005
+ import { Download } from '@wix/ui-icons-common';
1006
+
1007
+ // IMPORTANT: Function name MUST match the action id in your configuration
1008
+ export const exportCollection: CustomActionCollectionPageActionResolver = (params) => {
1009
+ const { actionParams, sdk } = params;
1010
+ const { collectionId } = actionParams;
1011
+
1012
+ return {
1013
+ label: 'Export Collection',
1014
+ icon: <Download />,
1015
+ onClick: () => {
1016
+ // sdk is provided to custom action resolvers (see SDK Utilities section)
1017
+ const optimisticActions = sdk.getOptimisticActions(collectionId);
1018
+ const schema = sdk.getSchema(collectionId);
1019
+
1020
+ // Example: Mark entire collection as exported
1021
+ optimisticActions.updateAll(
1022
+ (item) => ({ lastExported: new Date() }),
1023
+ {
1024
+ submit: async () => {
1025
+ // Your collection export logic here
1026
+ console.log(`Exporting collection: ${collectionId}`);
1027
+ // Export and update all items on server
1028
+ return await schema.actions.bulkUpdate({ lastExported: new Date() });
1029
+ },
1030
+ successToast: 'Collection exported successfully',
1031
+ errorToast: (err, {retry}) => ({
1032
+ text: 'Export failed',
1033
+ action: { text: 'Retry', onClick: retry }
1034
+ })
1035
+ }
1036
+ );
1037
+ },
1038
+ };
1039
+ };
1040
+ ```
1041
+
1042
+ 3. Export your action in `actions/index.tsx`:
1043
+ ```typescript
1044
+ export * from './exportCollection';
1045
+ ```
1046
+
1047
+ 4. Configure the action in your JSON configuration:
1048
+ ```json
1049
+ {
1050
+ "id": "exportCollection", // MUST match the function name exactly
1051
+ "type": "custom", // REQUIRED: Must be exactly "custom"
1052
+ "label": "Export Collection", // Optional: Displayed text
1053
+ "collection": {
1054
+ "collectionId": "WixPets",
1055
+ "entityTypeSource": "cms"
1056
+ }
1057
+ }
1058
+ ```
1059
+
1060
+ 5. Register your action in the `PatternsWizardOverridesProvider`:
1061
+ ```typescript
1062
+ import * as actions from './components/actions';
1063
+
1064
+ <PatternsWizardOverridesProvider value={{ actions }}>
1065
+ <AutoPatternsApp configuration={config as AppConfig} />
1066
+ </PatternsWizardOverridesProvider>
1067
+ ```
1068
+
1069
+ ## Key Points for Custom Collection Page Actions:
1070
+ - The action `id` in the configuration MUST exactly match the function name exported from your actions folder
1071
+ - The function name and file name should follow a consistent naming convention (e.g., camelCase)
1072
+ - The implementation must be exported as a named export (not default export)
1073
+ - The implementation must use the `CustomActionCollectionPageActionResolver` type
1074
+ - Access collection context through `actionParams.collectionId`
1075
+
1076
+ ---
1077
+
1078
+ ## Custom Row Click Actions
1079
+
1080
+ In addition to page-level actions, you can also customize what happens when users click on individual rows in your collection table. By default, clicking a row navigates to the entity page, but you can override this behavior with custom logic.
1081
+
1082
+ **Before You Start:**
1083
+ - Only configure `onRowClick` if you need custom behavior (e.g., opening modals, side panels, custom actions)
1084
+ - If you just want navigation to entity page, don't configure `onRowClick` - it's the default behavior
1085
+ - Once you configure `onRowClick`, you must provide a complete working implementation
1086
+
1087
+ ### Configuration
1088
+
1089
+ Row click actions are configured at the table level using the `onRowClick` property:
1090
+
1091
+ ```json
1092
+ {
1093
+ "type": "Table",
1094
+ "table": {
1095
+ "columns": [...],
1096
+ "onRowClick": {
1097
+ "id": "handleRowClick", // MUST match the function name exactly
1098
+ "type": "custom", // REQUIRED: Must be exactly "custom"
1099
+ }
1100
+ }
1101
+ }
1102
+ ```
1103
+
1104
+ ### Implementation Requirements
1105
+
1106
+ ⚠️ **CRITICAL**: When you configure `onRowClick` in your JSON, you MUST provide a complete working implementation. The Auto Patterns framework cannot function without it.
1107
+
1108
+ Custom row click actions use the `CustomActionCollectionPageActionOnRowClickResolver` type and MUST return a `ResolvedAction` object with all required properties:
1109
+
1110
+ #### Required Return Object Structure:
1111
+ ```typescript
1112
+ return {
1113
+ label: string, // REQUIRED: Action label
1114
+ icon: ReactElement, // REQUIRED: Icon component
1115
+ onClick: () => void // REQUIRED: Click handler function
1116
+ };
1117
+ ```
1118
+
1119
+ #### Complete Implementation Example:
1120
+
1121
+ ```typescript
1122
+ import { CustomActionCollectionPageActionOnRowClickResolver } from '@wix/auto-patterns';
1123
+ import React from 'react';
1124
+ import { More } from '@wix/wix-ui-icons-common';
1125
+
1126
+ // IMPORTANT: Function name MUST match the action id in your configuration
1127
+ export const handleRowClick: CustomActionCollectionPageActionOnRowClickResolver = (params) => {
1128
+ const { actionParams, sdk } = params;
1129
+ const { item } = actionParams; // The clicked row's data
1130
+
1131
+ return {
1132
+ label: 'View Details', // REQUIRED
1133
+ icon: <More />, // REQUIRED
1134
+ onClick: () => { // REQUIRED
1135
+ // Your custom row click logic here
1136
+ console.log('Row clicked:', item);
1137
+
1138
+ // Example: Show a custom modal, perform an action, etc.
1139
+ // You can access all SDK utilities here (see SDK Utilities section)
1140
+ const optimisticActions = sdk.getOptimisticActions(sdk.collectionId);
1141
+ const schema = sdk.getSchema(sdk.collectionId);
1142
+
1143
+ // Your custom logic...
1144
+ },
1145
+ };
1146
+ };
1147
+ ```
1148
+
1149
+ ### Common Use Cases and Complete Examples
1150
+
1151
+ #### 1. Opening a Side Panel Modal
1152
+
1153
+ This is a complete working example for opening a side panel when clicking a row:
1154
+
1155
+ **Step 1: Create the row click action** (`components/actions/openSidePanel.tsx`):
1156
+ ```typescript
1157
+ import { CustomActionCollectionPageActionOnRowClickResolver } from '@wix/auto-patterns';
1158
+ import React from 'react';
1159
+ import { More } from '@wix/wix-ui-icons-common';
1160
+
1161
+ export const openSidePanel: CustomActionCollectionPageActionOnRowClickResolver = (params) => {
1162
+ const { actionParams, sdk } = params;
1163
+ const { item } = actionParams;
1164
+
1165
+ return {
1166
+ label: 'View Details',
1167
+ icon: <More />,
1168
+ onClick: () => {
1169
+ // Open a custom modal with the item data
1170
+ // You need to implement the modal opening mechanism
1171
+ // This could be through a modal context, state management, etc.
1172
+ console.log('Opening side panel for:', item);
1173
+
1174
+ // Example: Using a global modal state (you need to implement this)
1175
+ // window.dispatchEvent(new CustomEvent('openSidePanel', { detail: item }));
1176
+
1177
+ // Or use a modal service/context that you've set up
1178
+ // modalService.openSidePanel(item);
1179
+ },
1180
+ };
1181
+ };
1182
+ ```
1183
+
1184
+ **Step 2: Configure in JSON**:
1185
+ ```json
1186
+ {
1187
+ "type": "Table",
1188
+ "table": {
1189
+ "onRowClick": {
1190
+ "id": "openSidePanel",
1191
+ "type": "custom"
1192
+ },
1193
+ "columns": [...]
1194
+ }
1195
+ }
1196
+ ```
1197
+
1198
+ **Step 3: Export and Register**:
1199
+ ```typescript
1200
+ // components/actions/index.tsx
1201
+ export * from './openSidePanel';
1202
+
1203
+ // page.tsx
1204
+ import * as actions from './components/actions';
1205
+
1206
+ <PatternsWizardOverridesProvider value={{ actions }}>
1207
+ <AutoPatternsApp configuration={config as AppConfig} />
1208
+ </PatternsWizardOverridesProvider>
1209
+ ```
1210
+
1211
+ #### 2. Direct Data Manipulation
1212
+
1213
+ ```typescript
1214
+ export const quickToggle: CustomActionCollectionPageActionOnRowClickResolver = (params) => {
1215
+ const { actionParams, sdk } = params;
1216
+ const { item } = actionParams;
1217
+
1218
+ return {
1219
+ label: 'Quick Toggle',
1220
+ icon: <Toggle />,
1221
+ onClick: () => {
1222
+ const optimisticActions = sdk.getOptimisticActions(sdk.collectionId);
1223
+ const schema = sdk.getSchema(sdk.collectionId);
1224
+
1225
+ // Example: Toggle a boolean field
1226
+ const updatedItem = { ...item, isActive: !item.isActive };
1227
+
1228
+ optimisticActions.updateOne(updatedItem, {
1229
+ submit: async (items) => schema.actions.update(items[0]),
1230
+ successToast: `${item.name} toggled successfully`,
1231
+ errorToast: (err, {retry}) => ({
1232
+ text: 'Toggle failed',
1233
+ action: { text: 'Retry', onClick: retry }
1234
+ })
1235
+ });
1236
+ },
1237
+ };
1238
+ };
1239
+ ```
1240
+
1241
+ ### Default vs Custom Behavior
1242
+
1243
+ **Default Behavior (when `onRowClick` is not configured):**
1244
+ - Clicking a row automatically navigates to the entity page
1245
+ - Uses the `entityPageId` configuration to determine the target page
1246
+ - Passes the selected item's data to the entity page
1247
+
1248
+ **Custom Behavior (when `onRowClick` is configured):**
1249
+ - Default navigation is **disabled**
1250
+ - Your custom action function is executed instead
1251
+ - You have complete control over the row click behavior
1252
+ - You can still navigate to the entity page programmatically if needed using the SDK navigation utilities
1253
+
1254
+ ### Key Points for Custom Row Click Actions:
1255
+ - **MANDATORY IMPLEMENTATION**: If you configure `onRowClick` in JSON, you MUST provide a complete working implementation - the framework cannot function without it
1256
+ - The action `id` in the configuration MUST exactly match the function name exported from your actions folder
1257
+ - The implementation must use the `CustomActionCollectionPageActionOnRowClickResolver` type
1258
+ - **Required Return Object**: Must return an object with `label`, `icon`, and `onClick` properties - all are required
1259
+ - Access the clicked item's data through `actionParams.item`
1260
+ - The implementation must be exported as a named export and registered in your `PatternsWizardOverridesProvider`
1261
+ - When `onRowClick` is configured, the default navigation to entity page is completely disabled
1262
+ - **Complete Setup Required**: You need to create the action file, export it in the index, and register it in the provider - missing any step will cause errors
1263
+
1264
+ ## Validation Checklist for Collection Page Actions
1265
+
1266
+ ✓ Every collection page must include a create action.
1267
+ ✓ `actions` is an optional property of `collectionPage`.
1268
+ ✓ `primaryActions` and `secondaryActions` (if defined) have a valid `type` ("action" or "menu").
1269
+ ✓ If `type: "action"`, `action.item` is a valid action item configuration.
1270
+ ✓ If `type: "menu"`, `menu.items` is an array of valid action item configurations that can include dividers.
1271
+ ✓ Each action item contains a unique `id`, and the full `collection` object (`collectionId`, `entityTypeSource: 'cms'`).
1272
+ ✓ Each action item has a supported `type` (`create`, `custom`) and its corresponding configuration block (e.g., `create` block for `type: "create"`).
1273
+ ✓ `create` actions specify a `create.page.id` that matches an existing `entityPage` ID in the configuration.
1274
+ ✓ `custom` actions (identified by their main `id`) correspond to an action resolver function name registered in the `actions` override.
1275
+ ✓ Divider actions use `{ "type": "divider" }` format and require no additional properties.
1276
+ ✓ If `onRowClick` is configured in table layout, it must have a valid `id` and `type: "custom"`.
1277
+ ✓ **CRITICAL**: Custom row click actions must have corresponding implementations registered in the `actions` override - configuration without implementation will cause errors.
1278
+ ✓ Custom row click action implementations must return an object with `label`, `icon`, and `onClick` properties - all are required.
1279
+ ✓ Custom row click action implementations must be exported as named exports and included in the actions index file.
1280
+ ✓ `onRowClick` is optional - when not configured, rows navigate to entity page by default.
1281
+ ✓ **IMPORTANT**: Configuring `onRowClick` completely disables default navigation - you must handle all row click logic in your custom implementation.
1282
+
1283
+ ---
1284
+
1285
+ ## SDK Utilities
1286
+
1287
+ The `sdk` parameter provides access to Auto Patterns utilities and context. Available in custom actions across all action types (ActionCell, BulkActions, CollectionPage actions, and EntityPage Actions).
1288
+
1289
+ ### Key SDK Utilities
1290
+ The only functions exist in sdk are:
1291
+
1292
+ • **closeModal** - `closeModal(): void`
1293
+ - Closes the currently open modal
1294
+ - Example: `sdk.closeModal()` after saving or canceling
1295
+
1296
+ • **getOptimisticActions** - `getOptimisticActions(collectionId): OptimisticActions`
1297
+ - Provides optimistic UI updates for immediate user feedback
1298
+ - Supports create, update, delete operations with automatic rollback on failure
1299
+ - Example: `sdk.getOptimisticActions(sdk.collectionId).updateOne(item, { ... })`
1300
+
1301
+ • **getSchema** - `getSchema(collectionId): SchemaConfig | undefined`
1302
+ - Access to collection schema information (fields, types, validation)
1303
+ - Useful for dynamic operations based on collection structure
1304
+ - Example: `const schema = sdk.getSchema(sdk.collectionId)`
1305
+
1306
+ • **collectionId** - `string`
1307
+ - Current collection context identifier
1308
+ - Available in all action contexts for referencing the active collection
1309
+ - Example: `sdk.collectionId` to get the current collection ID
1310
+
1311
+ ---
1312
+
1313
+ ## OptimisticActions
1314
+
1315
+ Provides immediate UI updates with automatic server synchronization and error recovery.
1316
+
1317
+ ### Usage Rules
1318
+
1319
+ **Use OptimisticActions for:**
1320
+ - Data modification operations (create, update, delete)
1321
+ - Operations requiring immediate visual feedback
1322
+
1323
+ **Do NOT use for:**
1324
+ - Read-only operations
1325
+ - Operations requiring server confirmation first
1326
+
1327
+ ### Core Pattern
1328
+
1329
+ ```typescript
1330
+ // Get instances from SDK (see SDK Utilities section)
1331
+ const optimisticActions = sdk.getOptimisticActions(sdk.collectionId);
1332
+ const schema = sdk.getSchema(sdk.collectionId);
1333
+
1334
+ optimisticActions.operation(items, {
1335
+ submit: async (items) => schema.actions.serverMethod(items),
1336
+ successToast: 'Success message',
1337
+ errorToast: (err, {retry}) => ({ text: 'Error message', action: { text: 'Retry', onClick: retry }})
1338
+ });
1339
+ ```
1340
+
1341
+ ### Available Operations
1342
+
1343
+ #### Create Operations
1344
+ - `createOne(item: T, params: OptimisticParams<T>): void`
1345
+ - `createMany(items: T[], params: OptimisticParams<T>): void`
1346
+
1347
+ #### Update Operations
1348
+ - `updateOne(item: T, params: OptimisticParams<T>): void`
1349
+ - `updateMany(items: T[], params: OptimisticParams<T>): void`
1350
+ - `updateAll(transformFn: (item: T) => Partial<T>, params: OptimisticParams<T>): void`
1351
+
1352
+ #### Delete Operations
1353
+ - `deleteOne(item: T, params: OptimisticParams<T> & { showUndoToast: true }): void`
1354
+ - `deleteMany(items: T[], params: OptimisticParams<T> & { showUndoToast: true }): void`
1355
+ - `deleteAll(params: OptimisticParams<T> & { showUndoToast: true }): void`
1356
+
1357
+ ### Type Definitions
1358
+
1359
+ ```typescript
1360
+ interface OptimisticParams<T> {
1361
+ submit: (items: T[]) => Promise<any>;
1362
+ successToast: string | ToastConfig;
1363
+ errorToast: (error: Error, actions: { retry: () => void }) => ToastConfig | string;
1364
+ showUndoToast?: boolean; // Required: true for delete operations
1365
+ }
1366
+
1367
+ interface ToastConfig {
1368
+ text: string;
1369
+ action?: { text: string; onClick: () => void };
1370
+ }
1371
+ ```
1372
+
1373
+ ### Validation Requirements
1374
+
1375
+ **Before using optimistic actions:**
1376
+ - Verify `sdk.getOptimisticActions(collectionId)` returns valid instance
1377
+ - Verify `sdk.getSchema(collectionId)` returns valid schema
1378
+ - For delete operations: `showUndoToast: true` is mandatory
1379
+ - All `submit` functions must return a Promise
1380
+
1381
+ **SDK Parameter:** Available in custom actions and modals. See SDK Utilities section for complete interface.
1382
+
1383
+ ---
1384
+
1385
+ ## SchemaConfig Usage
1386
+
1387
+ SchemaConfig provides complete collection metadata and server actions. Essential for dynamic operations and accessing collection structure information.
1388
+
1389
+ ### Key Properties
1390
+
1391
+ • **id** - `string`
1392
+ - Collection identifier (e.g., "WixPets")
1393
+ - Example: `schema.id === "WixPets"`
1394
+
1395
+ • **idField** - `string`
1396
+ - Primary key field name (usually "_id")
1397
+ - Required for all update/delete operations
1398
+ - Example: `const id = item[schema.idField]`
1399
+
1400
+ • **displayField** - `string`
1401
+ - Main field for displaying items (name, title, etc.)
1402
+ - Used in UI components for item identification
1403
+ - Example: `const label = item[schema.displayField]`
1404
+
1405
+ • **fields** - `Record<string, Field | undefined>`
1406
+ - Complete field definitions with types and metadata
1407
+ - Useful for dynamic form generation or validation
1408
+ - Example: `schema.fields.name.type === 'TEXT'`
1409
+
1410
+ • **actions** - Server operation functions
1411
+ - Pre-configured API calls for CRUD operations
1412
+ - Use with optimistic actions for best UX
1413
+ - Example: `await schema.actions.update(item)`
1414
+
1415
+ ### Available Schema Actions
1416
+
1417
+ - schema.actions.create(item) // Create single item
1418
+ - schema.actions.update(item) // Update single item
1419
+ - schema.actions.delete(itemId) // Delete by ID
1420
+ - schema.actions.bulkUpdate(updates) // Update multiple items
1421
+ - schema.actions.bulkDelete(itemIds) // Delete multiple items
1422
+
1423
+ ### Schema Validation Checklist
1424
+
1425
+ Before using schema in operations:
1426
+
1427
+ ✓ Check if schema exists: `if (!schema) return;`
1428
+ ✓ Verify required fields exist on items
1429
+ ✓ Use `schema.idField` for ID operations
1430
+ ✓ Use `schema.displayField` for UI display
1431
+ ✓ Use `schema.actions` for server operations
1432
+
1433
+ ### Common Usage Patterns
1434
+
1435
+ - **ActionCell**: Use `schema.actions.update()` or `schema.actions.delete()` for single item operations
1436
+ - **BulkActions**: Use `schema.actions.bulkUpdate()` or `schema.actions.bulkDelete()` for multiple items
1437
+ - **Dynamic UI**: Use `schema.fields` to build forms or validate data
1438
+ - **Error Messages**: Use `schema.displayField` to create meaningful user feedback
1439
+
1440
+ ---
1441
+
1442
+ ## Filters Configuration Notes
1443
+
1444
+ To configure filters in a `collectionPage`, add a `filters` property inside the page's component configuration object. Each filter must reference a valid field by its `fieldId`, and the supported types are:
1445
+
1446
+ * `numberConfig`: used with fields of type `NUMBER`
1447
+ * `dateConfig`: used with fields of type `DATETIME`
1448
+ * `booleanConfig`: used with fields of type `BOOLEAN`
1449
+ * `enumConfig`: used with fields of type `ARRAY` or `ARRAY_STRING`
1450
+
1451
+ ### Enum Configuration Implementation
1452
+
1453
+ When implementing enum filters, you must ask the user to provide the possible option values. Never invent or assume enum values. Here's how to properly handle enumConfig:
1454
+
1455
+ #### Example: User-Provided Enum Implementation
1456
+
1457
+ 1. First, collect the possible values from the user:
1458
+ ```
1459
+ User requests: "I need a filter for pet types."
1460
+ You ask: "What are the possible values for pet types that should be available in the filter?"
1461
+ User responds: "dog, cat, bird, rabbit, fish"
1462
+ ```
1463
+
1464
+ 2. Then, create the `enumConfig` structure:
1465
+ ```json
1466
+ "enumConfig": {
1467
+ "options": [
1468
+ { "value": "dog", "label": "Dog" },
1469
+ { "value": "cat", "label": "Cat" },
1470
+ { "value": "bird", "label": "Bird" },
1471
+ { "value": "rabbit", "label": "Rabbit" },
1472
+ { "value": "fish", "label": "Fish" }
1473
+ ],
1474
+ "selectionMode": "multiple",
1475
+ "optionType": "checkbox"
1476
+ }
1477
+ ```
1478
+
1479
+ Notice how the `label` is derived from the `value` by capitalizing the first letter. The user's exact values become the `value` property.
1480
+
1481
+ ### Grouping Filters with Section Title
1482
+
1483
+ * Filters can be grouped by sections using the `sectionTitle` property.
1484
+ * If multiple filter items share the same `sectionTitle`, they will be displayed together in a grouped section in the UI.
1485
+ * Filters without a `sectionTitle` will appear in a default section or be displayed individually.
1486
+ * Grouping helps maintain clarity, especially when dealing with multiple filter options.
1487
+
1488
+ ### Key Guidelines
1489
+
1490
+ * **openByDefault**: Automatically expands the filter accordion when the filters panel is opened.
1491
+ * **tagLabel**: Specifies the label displayed in a Tag component on the table or grid once the filter is active. For example, if the tagLabel is "Age", the filter display might show: `Age: 7`.
1492
+ * **maxInlineFilters**: Limits the number of filters shown inline in the table toolbar. Others are accessible via the panel. Default is 0.
1493
+ * **dateConfig.mode**:
1494
+
1495
+ * `ONLY_PREDEFINED`: user can select only from preset options
1496
+ * `ONLY_CUSTOM`: user must select a custom date range manually (no presets)
1497
+ * `COMBINE`: both options available
1498
+ * **dateConfig.presets** must be omitted if mode is `ONLY_CUSTOM`.
1499
+ * **dateConfig.includeTime**: Controls whether time selection is also enabled alongside date (default is `true`).
1500
+
1501
+ ---
1502
+
1503
+ # Entity Page Configuration
1504
+
1505
+ ## ⚠️ Entity Page Requirements
1506
+
1507
+ All entity pages must have:
1508
+ - **A route path with descriptive segment and dynamic parameter** (e.g., `/product/:entityId`, `/pet/:entityId`) - **never just `/:entityId`** as this conflicts with collection page routing
1509
+ - **A matching `route.params` configuration** that maps the dynamic parameter
1510
+ - **A reference to their parent collection page via `parentPageId`**
1511
+
1512
+ ## Overview
1513
+
1514
+ * Displays details for a **single entity**.
1515
+ * Always tied to a single Wix collection.
1516
+ * `entityTypeSource` is always `'cms'`.
1517
+
1518
+ > The custom actions must be defined inside the `moreActions` array.
1519
+
1520
+ > Note: You do not need to define a custom action to navigate to the entity page. This behavior is built-in — clicking on a row in the collection table automatically navigates to the corresponding entity page.
1521
+
1522
+ ## Entity Page Layout Configuration
1523
+
1524
+ ### Grid System
1525
+
1526
+ - **12-Column Grid**: The layout uses a 12-column grid system.
1527
+ - The `span` property controls how many columns an item occupies (1-12).
1528
+ - When items in a row exceed 12 columns total, the next item wraps to a new line.
1529
+ - Example: If an item has `span: 8` and the next has `span: 5`, the second item will start a new line.
1530
+
1531
+ ### Layout Structure
1532
+
1533
+ - **Main Section**: Contains primary entity information and most important fields.
1534
+ - **Sidebar Section**: Contains secondary information, metadata, or supporting content.
1535
+ - Both sections support cards that can contain fields, containers, and components.
1536
+
1537
+ ### Detailed Layout Content Types
1538
+
1539
+ 1. **Field Type**:
1540
+ ```typescript
1541
+ {
1542
+ type: 'field';
1543
+ field: {
1544
+ span?: number; // How many columns this field occupies (1-12)
1545
+ fieldId: string; // Must match a valid field ID from the collection schema
1546
+ };
1547
+ }
1548
+ ```
1549
+
1550
+ 2. **Container Type** (for grouping related fields):
1551
+ ```typescript
1552
+ {
1553
+ type: 'container';
1554
+ container: {
1555
+ span?: number; // How many columns this container occupies (1-12)
1556
+ children: LayoutContent[]; // Can nest fields, other containers, or components
1557
+ };
1558
+ }
1559
+ ```
1560
+
1561
+ 3. **Component Type** (for custom rendering):
1562
+ ```typescript
1563
+ {
1564
+ type: 'component';
1565
+ component: {
1566
+ span?: number; // How many columns this component occupies (1-12)
1567
+ componentId: string; // ID matching a component override implementation
1568
+ };
1569
+ }
1570
+ ```
1571
+
1572
+ ### Layout Best Practices
1573
+
1574
+ 1. **Field Grouping**:
1575
+ - Group related fields using containers
1576
+ - Place frequently used fields at the top
1577
+ - Consider the natural flow of data entry
1578
+
1579
+ 2. **Main vs. Sidebar Usage**:
1580
+ - Main section: Put primary entity information
1581
+ - Sidebar: Place secondary information and metadata
1582
+
1583
+ 3. **Responsive Considerations**:
1584
+ - Use appropriate spans for different field types
1585
+ - Text fields often benefit from larger spans
1586
+ - Boolean fields can use smaller spans
1587
+
1588
+ 4. **Nested Containers**:
1589
+ - Use containers to create logical groupings
1590
+ - Don't nest containers too deeply for clarity
1591
+ - Consider using cards for major sections instead of deeply nested containers
1592
+
1593
+ 5. **Image Handling**:
1594
+ - For image fields, consider providing more space (larger span)
1595
+ - Images are automatically rendered with proper controls when using the field type
1596
+
1597
+ ## ⚠️ Common Entity Page Layout Mistakes to Avoid
1598
+
1599
+ - Using incorrect span values causing unexpected layout breaks
1600
+ - Referencing non-existent field IDs in the layout
1601
+ - Creating overly complex nested container structures
1602
+ - Failing to properly register component overrides
1603
+ - Confusing main and sidebar section usage (putting main content in sidebar)
1604
+ - Exceeding 12 total columns in a row without realizing content will wrap
1605
+ - Forgetting to specify the `collectionPagePath` value
1606
+ - Missing required `type: 'card'` structure in layout sections
1607
+
1608
+ ---
1609
+
1610
+ ## Entity Page Actions: `moreActions` Support
1611
+
1612
+ Entity pages in AutoPatternsApp support not only a primary action (such as "Save" or "Delete") but also a flexible set of **more actions** (sometimes called "secondary actions" or `moreActions`). These allow you to provide additional contextual actions for the entity, such as custom logic, or grouped actions.
1613
+
1614
+ > **Note:** All custom actions for entity pages must be placed in the `moreActions` array. Do not place custom actions as primary actions on entity pages. The `moreActions` array is the only supported location for custom actions on entity pages.
1615
+
1616
+ ### Configuration Structure
1617
+
1618
+ - The `moreActions` property on the entity page is an **array** of action configurations that can include divider objects for visual separation.
1619
+ - Each action in `moreActions` is a Custom Action (type: "custom") or a Divider (type: "divider")
1620
+
1621
+ #### Example: Adding custom actions with dividers to an entity page
1622
+ ```json
1623
+ {
1624
+ "type": "entityPage",
1625
+ "entityPage": {
1626
+ // ... other config ...
1627
+ "moreActions": [
1628
+ {
1629
+ "id": "sendEmail",
1630
+ "type": "custom",
1631
+ "label": "Send Email"
1632
+ },
1633
+ {
1634
+ "id": "exportData",
1635
+ "type": "custom",
1636
+ "label": "Export Data"
1637
+ },
1638
+ { "type": "divider" },
1639
+ {
1640
+ "id": "archiveEntity",
1641
+ "type": "custom",
1642
+ "label": "Archive"
1643
+ }
1644
+ ]
1645
+ }
1646
+ }
1647
+ ```
1648
+
1649
+ ---
1650
+
1651
+ ### CustomEntityPageMoreActionsActionResolver
1652
+
1653
+ The `CustomEntityPageMoreActionsActionResolver` type is used to implement custom actions for the `moreActions` menu on entity pages in AutoPatternsApp. Each action in the `moreActions` array must have a corresponding resolver function registered in your overrides.
1654
+
1655
+ #### Function Signature
1656
+
1657
+ ```typescript
1658
+ import { CustomEntityPageMoreActionsActionResolver } from '@wix/auto-patterns/types';
1659
+
1660
+ export const myMoreAction: CustomEntityPageMoreActionsActionResolver = (params) => {
1661
+ const { actionParams: { entity, form } , sdk } = params;
1662
+
1663
+ return {
1664
+ label: 'My More Action',
1665
+ icon: <MyIcon />, // optional
1666
+ onClick: () => {
1667
+ // Your custom logic here
1668
+ },
1669
+ };
1670
+ };
1671
+ ```
1672
+
1673
+ - **entity**: The current entity data (all field values). In actionParams.
1674
+ - **form**: The react-hook-form instance for the entity page. In actionParams.
1675
+ - **sdk**: The AutoPatterns SDK (see SDK Utilities section).
1676
+
1677
+ ---
1678
+
1679
+ #### Key Points for CustomEntityPageMoreActionsActionResolver
1680
+
1681
+ - The action `id` in the configuration MUST exactly match the function name exported from your actions folder.
1682
+ - The implementation must use the `CustomEntityPageMoreActionsActionResolver` type.
1683
+ - The implementation must be exported as a named export (not default export).
1684
+ - The function receives `{ actionParams, sdk }` as parameters.
1685
+ - The returned object must include at least a `label` and an `onClick` handler (optionally an `icon`).
1686
+
1687
+ ---
1688
+
1689
+ #### Validation Checklist for More Actions
1690
+
1691
+ ✓ Each action in `moreActions` has a unique `id` and correct `type` value
1692
+ ✓ Each action type only includes its required field(s)
1693
+ ✓ Custom actions match implementations in overrides
1694
+ ✓ The resolver is exported and registered in the `actions` property of your `PatternsWizardOverridesProvider`
1695
+ ✓ The function signature matches `CustomEntityPageMoreActionsActionResolver`
1696
+ ✓ The returned object includes `label`, `onClick`, and optionally `icon`
1697
+
1698
+ ---
1699
+
1700
+ **Summary:**
1701
+ The `CustomEntityPageMoreActionsActionResolver` enables you to add custom, contextual actions to the "More Actions" menu on your entity pages. Implement the resolver, export it, and reference it by `id` in your config for seamless integration.
1702
+
1703
+ ---