@wix/auto-patterns 1.14.0 → 1.16.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 (203) hide show
  1. package/dist/cjs/components/AutoPatternsCollectionPageContent/AutoPatternsCollectionPageContent.js +17 -6
  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 +14 -5
  10. package/dist/cjs/components/AutoPatternsRoute/AutoPatternsPage.js.map +1 -1
  11. package/dist/cjs/components/filters/DynamicCollectionFilter.js +5 -11
  12. package/dist/cjs/components/filters/DynamicCollectionFilter.js.map +1 -1
  13. package/dist/cjs/dataSourceAdapters/cms/cmsAdapter.js +51 -88
  14. package/dist/cjs/dataSourceAdapters/cms/cmsAdapter.js.map +1 -1
  15. package/dist/cjs/dataSourceAdapters/cms/fetchCmsData.js +43 -0
  16. package/dist/cjs/dataSourceAdapters/cms/fetchCmsData.js.map +1 -0
  17. package/dist/cjs/dataSourceAdapters/cms/filterUtils.js +15 -15
  18. package/dist/cjs/dataSourceAdapters/cms/filterUtils.js.map +1 -1
  19. package/dist/cjs/dataSourceAdapters/cms/sortUtils.js +2 -2
  20. package/dist/cjs/dataSourceAdapters/cms/sortUtils.js.map +1 -1
  21. package/dist/cjs/dataSourceAdapters/factory.js +0 -20
  22. package/dist/cjs/dataSourceAdapters/factory.js.map +1 -1
  23. package/dist/cjs/hooks/useActionCell.js +0 -6
  24. package/dist/cjs/hooks/useActionCell.js.map +1 -1
  25. package/dist/cjs/hooks/useBaseTableFeatures.js +7 -2
  26. package/dist/cjs/hooks/useBaseTableFeatures.js.map +1 -1
  27. package/dist/cjs/hooks/useBulkActionToolbar.js +1 -7
  28. package/dist/cjs/hooks/useBulkActionToolbar.js.map +1 -1
  29. package/dist/cjs/hooks/useCollectionPageActions.js +2 -8
  30. package/dist/cjs/hooks/useCollectionPageActions.js.map +1 -1
  31. package/dist/cjs/hooks/useCollectionPageOnRowClickActions.js +49 -0
  32. package/dist/cjs/hooks/useCollectionPageOnRowClickActions.js.map +1 -0
  33. package/dist/cjs/hooks/useFetchData.js +9 -29
  34. package/dist/cjs/hooks/useFetchData.js.map +1 -1
  35. package/dist/cjs/hooks/useFilters.js +2 -2
  36. package/dist/cjs/hooks/useFilters.js.map +1 -1
  37. package/dist/cjs/hooks/useGridFeatures.js +3 -4
  38. package/dist/cjs/hooks/useGridFeatures.js.map +1 -1
  39. package/dist/cjs/hooks/useTableFeatures.js +3 -4
  40. package/dist/cjs/hooks/useTableFeatures.js.map +1 -1
  41. package/dist/cjs/hooks/useTableGridSwitchFeatures.js +3 -4
  42. package/dist/cjs/hooks/useTableGridSwitchFeatures.js.map +1 -1
  43. package/dist/cjs/providers/PatternsWizardOverridesContext.js +1 -1
  44. package/dist/cjs/providers/PatternsWizardOverridesContext.js.map +1 -1
  45. package/dist/cjs/providers/SchemaContext.js +32 -8
  46. package/dist/cjs/providers/SchemaContext.js.map +1 -1
  47. package/dist/cjs/types/CollectionPageConfig.js.map +1 -1
  48. package/dist/cjs/types/EntityPageConfig.js.map +1 -1
  49. package/dist/cjs/types/actions/actionCell.js.map +1 -1
  50. package/dist/cjs/types/actions/base.js.map +1 -1
  51. package/dist/cjs/types/actions/bulkActions.js.map +1 -1
  52. package/dist/cjs/types/actions/collectionPageActions.js.map +1 -1
  53. package/dist/cjs/types/index.js +6 -0
  54. package/dist/cjs/types/index.js.map +1 -1
  55. package/dist/cjs/types/providers.js +4 -0
  56. package/dist/cjs/types/providers.js.map +1 -0
  57. package/dist/cjs/types/types.js.map +1 -1
  58. package/dist/cjs/utils/actions/index.js +0 -6
  59. package/dist/cjs/utils/actions/index.js.map +1 -1
  60. package/dist/cjs/utils/actions/types.js.map +1 -1
  61. package/dist/docs/action_cell.md +214 -0
  62. package/dist/docs/app_config_structure.md +355 -0
  63. package/dist/docs/auto-patterns-guide.md +2447 -0
  64. package/dist/docs/bulk_actions.md +266 -0
  65. package/dist/docs/collection_page.md +54 -0
  66. package/dist/docs/collection_page_actions.md +343 -0
  67. package/dist/docs/custom_overrides.md +511 -0
  68. package/dist/docs/entity_page.md +104 -0
  69. package/dist/docs/entity_page_actions.md +92 -0
  70. package/dist/docs/index.md +76 -0
  71. package/dist/docs/installation.md +55 -0
  72. package/dist/docs/introduction.md +74 -0
  73. package/dist/docs/pages_configuration.md +129 -0
  74. package/dist/docs/recipe-bulk-operations.md +1352 -0
  75. package/dist/docs/recipe-crud-operations.md +786 -0
  76. package/dist/docs/recipe-customization.md +1702 -0
  77. package/dist/docs/recipe-first-dashboard.md +794 -0
  78. package/dist/docs/sdk_and_schema.md +215 -0
  79. package/dist/esm/components/AutoPatternsCollectionPageContent/AutoPatternsCollectionPageContent.js +7 -2
  80. package/dist/esm/components/AutoPatternsCollectionPageContent/AutoPatternsCollectionPageContent.js.map +1 -1
  81. package/dist/esm/components/AutoPatternsCollectionPageContent/SkeletonCollection.js +21 -0
  82. package/dist/esm/components/AutoPatternsCollectionPageContent/SkeletonCollection.js.map +1 -0
  83. package/dist/esm/components/AutoPatternsEntityPage/AutoPatternsEntityPage.js +3 -1
  84. package/dist/esm/components/AutoPatternsEntityPage/AutoPatternsEntityPage.js.map +1 -1
  85. package/dist/esm/components/AutoPatternsEntityPage/SkeletonEntity.js +91 -0
  86. package/dist/esm/components/AutoPatternsEntityPage/SkeletonEntity.js.map +1 -0
  87. package/dist/esm/components/AutoPatternsRoute/AutoPatternsPage.js +5 -2
  88. package/dist/esm/components/AutoPatternsRoute/AutoPatternsPage.js.map +1 -1
  89. package/dist/esm/components/filters/DynamicCollectionFilter.js +4 -10
  90. package/dist/esm/components/filters/DynamicCollectionFilter.js.map +1 -1
  91. package/dist/esm/dataSourceAdapters/cms/cmsAdapter.js +54 -88
  92. package/dist/esm/dataSourceAdapters/cms/cmsAdapter.js.map +1 -1
  93. package/dist/esm/dataSourceAdapters/cms/fetchCmsData.js +42 -0
  94. package/dist/esm/dataSourceAdapters/cms/fetchCmsData.js.map +1 -0
  95. package/dist/esm/dataSourceAdapters/cms/filterUtils.js +15 -15
  96. package/dist/esm/dataSourceAdapters/cms/filterUtils.js.map +1 -1
  97. package/dist/esm/dataSourceAdapters/cms/sortUtils.js +2 -2
  98. package/dist/esm/dataSourceAdapters/cms/sortUtils.js.map +1 -1
  99. package/dist/esm/dataSourceAdapters/factory.js +1 -21
  100. package/dist/esm/dataSourceAdapters/factory.js.map +1 -1
  101. package/dist/esm/hooks/useActionCell.js +1 -7
  102. package/dist/esm/hooks/useActionCell.js.map +1 -1
  103. package/dist/esm/hooks/useBaseTableFeatures.js +6 -1
  104. package/dist/esm/hooks/useBaseTableFeatures.js.map +1 -1
  105. package/dist/esm/hooks/useBulkActionToolbar.js +1 -7
  106. package/dist/esm/hooks/useBulkActionToolbar.js.map +1 -1
  107. package/dist/esm/hooks/useCollectionPageActions.js +1 -7
  108. package/dist/esm/hooks/useCollectionPageActions.js.map +1 -1
  109. package/dist/esm/hooks/useCollectionPageOnRowClickActions.js +45 -0
  110. package/dist/esm/hooks/useCollectionPageOnRowClickActions.js.map +1 -0
  111. package/dist/esm/hooks/useFetchData.js +9 -29
  112. package/dist/esm/hooks/useFetchData.js.map +1 -1
  113. package/dist/esm/hooks/useFilters.js +2 -2
  114. package/dist/esm/hooks/useFilters.js.map +1 -1
  115. package/dist/esm/hooks/useGridFeatures.js +3 -4
  116. package/dist/esm/hooks/useGridFeatures.js.map +1 -1
  117. package/dist/esm/hooks/useTableFeatures.js +3 -4
  118. package/dist/esm/hooks/useTableFeatures.js.map +1 -1
  119. package/dist/esm/hooks/useTableGridSwitchFeatures.js +3 -4
  120. package/dist/esm/hooks/useTableGridSwitchFeatures.js.map +1 -1
  121. package/dist/esm/providers/PatternsWizardOverridesContext.js.map +1 -1
  122. package/dist/esm/providers/SchemaContext.js +31 -7
  123. package/dist/esm/providers/SchemaContext.js.map +1 -1
  124. package/dist/esm/types/CollectionPageConfig.js.map +1 -1
  125. package/dist/esm/types/EntityPageConfig.js.map +1 -1
  126. package/dist/esm/types/actions/actionCell.js.map +1 -1
  127. package/dist/esm/types/actions/base.js.map +1 -1
  128. package/dist/esm/types/actions/bulkActions.js.map +1 -1
  129. package/dist/esm/types/actions/collectionPageActions.js.map +1 -1
  130. package/dist/esm/types/index.js +1 -0
  131. package/dist/esm/types/index.js.map +1 -1
  132. package/dist/esm/types/providers.js +2 -0
  133. package/dist/esm/types/providers.js.map +1 -0
  134. package/dist/esm/types/types.js.map +1 -1
  135. package/dist/esm/utils/actions/index.js +0 -2
  136. package/dist/esm/utils/actions/index.js.map +1 -1
  137. package/dist/esm/utils/actions/types.js.map +1 -1
  138. package/dist/types/components/AutoPatternsCollectionPageContent/AutoPatternsCollectionPageContent.d.ts.map +1 -1
  139. package/dist/types/components/AutoPatternsCollectionPageContent/SkeletonCollection.d.ts +5 -0
  140. package/dist/types/components/AutoPatternsCollectionPageContent/SkeletonCollection.d.ts.map +1 -0
  141. package/dist/types/components/AutoPatternsEntityPage/SkeletonEntity.d.ts +7 -0
  142. package/dist/types/components/AutoPatternsEntityPage/SkeletonEntity.d.ts.map +1 -0
  143. package/dist/types/components/AutoPatternsRoute/AutoPatternsPage.d.ts.map +1 -1
  144. package/dist/types/components/filters/DynamicCollectionFilter.d.ts.map +1 -1
  145. package/dist/types/dataSourceAdapters/cms/cmsAdapter.d.ts +1 -10
  146. package/dist/types/dataSourceAdapters/cms/cmsAdapter.d.ts.map +1 -1
  147. package/dist/types/dataSourceAdapters/cms/fetchCmsData.d.ts +13 -0
  148. package/dist/types/dataSourceAdapters/cms/fetchCmsData.d.ts.map +1 -0
  149. package/dist/types/dataSourceAdapters/cms/filterUtils.d.ts +9 -7
  150. package/dist/types/dataSourceAdapters/cms/filterUtils.d.ts.map +1 -1
  151. package/dist/types/dataSourceAdapters/cms/sortUtils.d.ts +2 -2
  152. package/dist/types/dataSourceAdapters/cms/sortUtils.d.ts.map +1 -1
  153. package/dist/types/dataSourceAdapters/factory.d.ts +1 -11
  154. package/dist/types/dataSourceAdapters/factory.d.ts.map +1 -1
  155. package/dist/types/hooks/useActionCell.d.ts.map +1 -1
  156. package/dist/types/hooks/useBaseTableFeatures.d.ts +1 -1
  157. package/dist/types/hooks/useBaseTableFeatures.d.ts.map +1 -1
  158. package/dist/types/hooks/useBulkActionToolbar.d.ts.map +1 -1
  159. package/dist/types/hooks/useCollectionPageActions.d.ts.map +1 -1
  160. package/dist/types/hooks/useCollectionPageOnRowClickActions.d.ts +7 -0
  161. package/dist/types/hooks/useCollectionPageOnRowClickActions.d.ts.map +1 -0
  162. package/dist/types/hooks/useEntityPageHeaderTexts.d.ts.map +1 -1
  163. package/dist/types/hooks/useFetchData.d.ts +13 -7
  164. package/dist/types/hooks/useFetchData.d.ts.map +1 -1
  165. package/dist/types/hooks/useFilters.d.ts +1 -1
  166. package/dist/types/hooks/useGridFeatures.d.ts.map +1 -1
  167. package/dist/types/hooks/useTableFeatures.d.ts +1 -1
  168. package/dist/types/hooks/useTableFeatures.d.ts.map +1 -1
  169. package/dist/types/hooks/useTableGridSwitchFeatures.d.ts +1 -1
  170. package/dist/types/hooks/useTableGridSwitchFeatures.d.ts.map +1 -1
  171. package/dist/types/providers/PatternsWizardOverridesContext.d.ts +4 -5
  172. package/dist/types/providers/PatternsWizardOverridesContext.d.ts.map +1 -1
  173. package/dist/types/providers/SchemaContext.d.ts +4 -4
  174. package/dist/types/providers/SchemaContext.d.ts.map +1 -1
  175. package/dist/types/types/CollectionPageConfig.d.ts +4 -8
  176. package/dist/types/types/CollectionPageConfig.d.ts.map +1 -1
  177. package/dist/types/types/EntityPageConfig.d.ts +3 -4
  178. package/dist/types/types/EntityPageConfig.d.ts.map +1 -1
  179. package/dist/types/types/actions/actionCell.d.ts +2 -2
  180. package/dist/types/types/actions/actionCell.d.ts.map +1 -1
  181. package/dist/types/types/actions/base.d.ts +0 -7
  182. package/dist/types/types/actions/base.d.ts.map +1 -1
  183. package/dist/types/types/actions/bulkActions.d.ts +2 -2
  184. package/dist/types/types/actions/bulkActions.d.ts.map +1 -1
  185. package/dist/types/types/actions/collectionPageActions.d.ts +10 -2
  186. package/dist/types/types/actions/collectionPageActions.d.ts.map +1 -1
  187. package/dist/types/types/index.d.ts +1 -0
  188. package/dist/types/types/index.d.ts.map +1 -1
  189. package/dist/types/types/providers.d.ts +11 -0
  190. package/dist/types/types/providers.d.ts.map +1 -0
  191. package/dist/types/types/types.d.ts +25 -1
  192. package/dist/types/types/types.d.ts.map +1 -1
  193. package/dist/types/utils/actions/index.d.ts +0 -2
  194. package/dist/types/utils/actions/index.d.ts.map +1 -1
  195. package/dist/types/utils/actions/types.d.ts +1 -4
  196. package/dist/types/utils/actions/types.d.ts.map +1 -1
  197. package/package.json +21 -16
  198. package/dist/cjs/utils/actions/customModalAction.js +0 -22
  199. package/dist/cjs/utils/actions/customModalAction.js.map +0 -1
  200. package/dist/esm/utils/actions/customModalAction.js +0 -17
  201. package/dist/esm/utils/actions/customModalAction.js.map +0 -1
  202. package/dist/types/utils/actions/customModalAction.d.ts +0 -5
  203. package/dist/types/utils/actions/customModalAction.d.ts.map +0 -1
@@ -0,0 +1,2447 @@
1
+ # AI Agent Instructions for AutoPatternsApp
2
+
3
+ This document serves as a comprehensive guide for AI agents to correctly generate and validate configurations for the `AutoPatternsApp` component. Follow these instructions sequentially to ensure proper implementation.
4
+
5
+ ## AI Usage Guidelines
6
+
7
+ 1. **Configuration Generation Process**:
8
+
9
+ * First, analyze the schema requirements.
10
+ * Then, select appropriate fields based on data types.
11
+ * Finally, validate against the rules before output.
12
+
13
+ 2. **Required Validation Steps**:
14
+
15
+ * Verify exact page count (must be 2).
16
+ * Confirm proper field selection (max 3 columns initially).
17
+ * Check all mandatory fields are present.
18
+ * Ensure no unsupported fields are included.
19
+ * Verify that every collection page has a create action that navigates to the entity page.
20
+
21
+ 3. **Decision-Making Priority**:
22
+
23
+ * User explicit requirements override defaults.
24
+ * Schema structure guides field selection.
25
+ * Best practices determine presentation.
26
+
27
+ 4. **Enum Configuration Rule (CRITICAL)**:
28
+
29
+ * When generating `enumConfig` (whether implicitly as part of another rule or explicitly upon user request), the AI **must always ask the user to provide the possible option values** for the enum field.
30
+ * The `value` of each option can be **any string specified by the user**, and the `label` should be derived from the `value` (e.g., if `value` is "dog", the `label` can be "Dog").
31
+ * The AI is strictly prohibited from guessing, inventing, or assuming the enum values or their labels.
32
+
33
+ ---
34
+
35
+ # Core Rules
36
+
37
+ ## Configuration Rules
38
+
39
+ * Pages array MUST contain exactly two pages.
40
+ * Components array inside collectionPage MUST contain exactly one component with a layout array.
41
+ * Configuration MUST come only from a JSON file.
42
+ * DO NOT fill optional fields unless explicitly requested.
43
+ * Select up to 3 columns initially that best represent the entity.
44
+ * Every collection page MUST include a create action that allows users to create new entities by navigating to the entity page.
45
+
46
+ ## Type Binding Rules
47
+
48
+ * If `type: 'collectionPage'`, only `collectionPage` field should exist.
49
+ * If `type: 'entityPage'`, only `entityPage` field should exist.
50
+ * No cross-mixing of types is allowed.
51
+
52
+ ## Override Rules
53
+
54
+ * Custom overrides are restricted to documented areas only.
55
+ * Only override columns when specific rendering is required.
56
+
57
+ ## Validation Rules
58
+
59
+ * All configurations must align with AppConfig Structure.
60
+ * Remove any configuration entries not in the structure.
61
+ * Verify customColumns.enabled logic (>5 columns or explicit request).
62
+
63
+ ---
64
+
65
+ # Instruction Guide & Best Practices
66
+
67
+ This guide instructs on how to correctly integrate the `AutoPatternsApp` component from `@wix/auto-patterns` package into a Wix-based admin page.
68
+
69
+ ---
70
+
71
+ # Component Purpose
72
+
73
+ The `AutoPatternsApp` is a page-level component used to display a data collection either as a Table or Grid.
74
+ It is configured using a JSON file conforming to the `AppConfig` interface and supports overrides for advanced use-cases.
75
+
76
+ ---
77
+
78
+ # AppConfig Structure
79
+
80
+ ## ⚠️ Configuration Rules
81
+
82
+ - **Configuration must come only from a JSON file** - never inline or from other sources
83
+ - **DO NOT fill optional fields unless explicitly requested** - leave optional properties undefined to avoid unnecessary complexity
84
+ - **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
85
+ - **When generating config for the first time, select up to 3 columns from the schema that best represent the entity**
86
+
87
+ ## ⚠️ Common Configuration Mistakes to Avoid
88
+
89
+ - Adding more than two pages
90
+ - Mixing page types in a single configuration
91
+ - Including undefined optional fields
92
+ - Selecting too many initial columns
93
+ - Not designating exactly one page as `appMainPage: true`
94
+ - Missing or inconsistent page relationships (parentPageId/entityPageId)
95
+ - Setting `stickyColumns` to invalid values (negative, zero, or exceeding column count)
96
+
97
+ ```ts
98
+ export interface AppConfig {
99
+ pages: {
100
+ id: string; // Page unique identifier (must be unique across the app)
101
+ type: 'collectionPage' | 'entityPage'; // Defines page type
102
+ appMainPage?: boolean; // Designates this page as the main page (exactly one page must have this set to true)
103
+ collectionPage?: {
104
+ route: {
105
+ path: string; // Route path for the collection page (e.g., '/')
106
+ };
107
+ title: {
108
+ text: string; // Main page title
109
+ hideTotal?: boolean; // Hide total items in header. Default: true
110
+ };
111
+ subtitle?: {
112
+ text: string; // Optional page subtitle
113
+ };
114
+ actions?: { // Defines page-level actions for the collection page
115
+ primaryActions?: {
116
+ type: 'action' | 'menu'; // Type of primary actions layout
117
+ action?: { // Required when type is 'action'
118
+ item: {
119
+ id: string; // Unique identifier for the action
120
+ type: 'create' | 'custom'; // Action type
121
+ label?: string; // Text displayed for the action
122
+ collection: {
123
+ collectionId: string; // ID of the Wix Data collection
124
+ entityTypeSource: 'cms'; // Data source type. Always 'cms'
125
+ };
126
+ create?: { // Required when type is 'create'
127
+ mode: 'page'; // Create mode
128
+ page: {
129
+ id: string; // Entity page ID to navigate to for creation
130
+ };
131
+ };
132
+ };
133
+ };
134
+ menu?: { // Required when type is 'menu'
135
+ label: string; // Label for the group
136
+ items: {}[]; // Array of action configurations, same structure as action.item, can include dividers
137
+ };
138
+ };
139
+ secondaryActions?: {
140
+ type: 'action' | 'menu'; // Type of secondary actions layout, same structure as primaryActions
141
+ action?: {}; // Same structure as primaryActions.action
142
+ menu?: {}; // Same structure as primaryActions.menu
143
+ };
144
+ };
145
+ components: [
146
+ {
147
+ entityPageId?: string; // ID of the entity page to navigate to when clicking a row
148
+ collection: {
149
+ collectionId: string; // ID of the Wix Data collection
150
+ entityTypeSource: 'cms'; // Data source type. Always 'cms'
151
+ reflectQueryInUrl?: boolean; // Reflects query state (search, filters, sorting) in the browser URL. Default: false
152
+ selectAllScope?: 'page' | 'all'; // Controls "Select All" scope. 'all' selects entire collection, 'page' selects only visible items. Default: 'all'
153
+ selectionUpdateMode?: 'preserve' | 'clear'; // Controls selection behavior when data changes. 'preserve' maintains selections, 'clear' clears them. Default: 'clear'
154
+ };
155
+ filters?: {
156
+ panelTitle?: string; // Title of the filters panel
157
+ items: {
158
+ id: string; // Unique identifier for the filter item
159
+ fieldId: string; // ID of the field to filter by (must be a valid type: NUMBER, DATETIME, BOOLEAN, ARRAY, ARRAY_STRING)
160
+ displayName?: string; // Display name of the filter item
161
+ openByDefault?: boolean; // Whether the filter item is open by default in the panel (accordion is open)
162
+ sectionTitle?: string; // Title of the filter section. Required if more than one section exists to prevent confusion
163
+ tagLabel?: string; // Label shown in Tag component in the table/grid when the filter is applied (e.g., "Age: 7")
164
+ numberConfig?: {
165
+ min?: number; // Minimum value
166
+ max?: number; // Maximum value
167
+ allowedDecimals?: true; // Decimal precision allowed
168
+ };
169
+ dateConfig?: {
170
+ mode?: 'ONLY_PREDEFINED' | 'ONLY_CUSTOM' | 'COMBINE'; // Determines filter behavior
171
+ presets?: (
172
+ | 'SEVEN_DAYS'
173
+ | 'FOURTEEN_DAYS'
174
+ | 'MONTH'
175
+ | 'TODAY'
176
+ | 'TOMORROW'
177
+ | 'NEXT_THREE_DAYS'
178
+ | 'NEXT_SEVEN_DAYS'
179
+ | 'NEXT_THIRTY_DAYS'
180
+ )[]; // Shown only if mode includes predefined presets (COMBINE or ONLY_PREDEFINED)
181
+ includeTime?: boolean; // Whether to allow time selection. Default is true
182
+ };
183
+ booleanConfig?: {
184
+ trueLabel?: string; // Label shown for the true value
185
+ falseLabel?: string; // Label shown for the false value
186
+ };
187
+ enumConfig?: {
188
+ options: {
189
+ value: string; // Enum option value
190
+ label: string; // Enum option label
191
+ }[];
192
+ selectionMode: 'single' | 'multiple'; // Selection behavior
193
+ optionType?:
194
+ | 'checkbox'
195
+ | 'inlineCheckbox'
196
+ | 'radio'
197
+ | 'select'; // Option rendering style
198
+ };
199
+ }[];
200
+ };
201
+ actionCell?: {
202
+ primaryAction?: {
203
+ item: {
204
+ id: string; // Unique identifier for the action
205
+ type: 'update' | 'delete' | 'custom'; // Action type
206
+ label?: string; // Text displayed for the action
207
+ disabled?: boolean; // Whether the action is disabled
208
+ tooltip?: string; // Tooltip text shown on hover
209
+ update?: { // Required when type is 'update'
210
+ mode: 'page'; // Update mode
211
+ page?: { // Required when mode is 'page'
212
+ id: string; // Entity page ID to navigate to
213
+ };
214
+ };
215
+ delete?: { // Required when type is 'delete'
216
+ mode: 'modal'; // Currently only 'modal' is supported
217
+ modal: {
218
+ title?: {
219
+ text: string; // Modal title
220
+ };
221
+ description?: {
222
+ text: string; // Modal description
223
+ };
224
+ actions?: {
225
+ submit?: {
226
+ text: string; // Submit button text
227
+ };
228
+ cancel?: {
229
+ text: string; // Cancel button text
230
+ };
231
+ };
232
+ feedback?: {
233
+ successToast?: {
234
+ text: string; // Success message
235
+ };
236
+ errorToast?: {
237
+ text: string; // Error message
238
+ };
239
+ };
240
+ };
241
+ };
242
+ };
243
+ };
244
+ secondaryActions?: {
245
+ items: {}[]; // Array of action configurations, same structure as primaryAction.item, can include dividers
246
+ inlineCount?: number; // How many secondary actions to show inline before showing popover
247
+ inlineAlwaysVisible?: boolean; // Whether to always show inline actions (not just on hover)
248
+ };
249
+ };
250
+ bulkActionToolbar?: {
251
+ primaryActions?: ({
252
+ type: 'action' | 'menu'; // Type of bulk action item
253
+ action?: { // Required when type is 'action'
254
+ item: {
255
+ id: string; // Unique identifier for the bulk action
256
+ type: 'bulkDelete' | 'custom'; // Bulk action type
257
+ label?: string; // Text displayed for the action
258
+ bulkDelete?: { // Required when type is 'bulkDelete'
259
+ mode: 'modal'; // Currently only 'modal' is supported
260
+ modal: {
261
+ title?: {
262
+ text: string; // Modal title
263
+ };
264
+ description?: {
265
+ text: string; // Modal description
266
+ };
267
+ actions?: {
268
+ submit?: {
269
+ text: string; // Submit button text
270
+ };
271
+ cancel?: {
272
+ text: string; // Cancel button text
273
+ };
274
+ };
275
+ feedback?: {
276
+ successToast?: {
277
+ text: string; // Success message
278
+ };
279
+ errorToast?: {
280
+ text: string; // Error message
281
+ };
282
+ };
283
+ };
284
+ };
285
+ };
286
+ };
287
+ menu?: { // Required when type is 'menu'
288
+ label: string; // Label for the dropdown group
289
+ items: {}[] // Array of bulk actions configurations, same structure as action.item, can include dividers
290
+ };
291
+ })[];
292
+ secondaryActions?: {}[]; // Array of bulk actions configurations, same structure as primaryActions[].menu.items, can include dividers
293
+ };
294
+ toolbarTitle?: {
295
+ title: string; // Toolbar title above the table/grid
296
+ subtitle?: {
297
+ text: string; // Toolbar subtitle
298
+ };
299
+ showTotal?: boolean; // Show total items on toolbar. Default: false
300
+ };
301
+ search?: {
302
+ shown?: boolean; // Show/hide the search
303
+ };
304
+ emptyState?: {
305
+ title?: string; // Empty state title
306
+ subtitle?: string; // Empty state subtitle
307
+ image?: {
308
+ id: string; // Image ID for empty state
309
+ };
310
+ addNewCta?: {
311
+ id?: string; // Add New CTA ID
312
+ text?: string; // Add New CTA text
313
+ };
314
+ customCta?: {
315
+ id?: string; // Custom CTA ID
316
+ };
317
+ };
318
+ layout: [ // Array of layout items that define what components to render
319
+ {
320
+ type: 'Table'; // Layout item type for table rendering
321
+ table?: {
322
+ columns: {
323
+ id: string; // Field ID from the collection
324
+ name: string; // Column title displayed
325
+ width: string; // The width of the column (required in types)
326
+ sortable?: boolean; // If the column is sortable
327
+ defaultSortOrder?: 'asc' | 'desc'; // Optional default sort order
328
+ sortMode?: 'asc' | 'desc'; // Optional sorting mode
329
+ reorderDisabled?: boolean; // Whether column reordering is disabled
330
+ hideable?: boolean; // Whether column can be hidden
331
+ defaultHidden?: boolean; // Whether column is hidden by default
332
+ hiddenFromCustomColumnsSelection?: boolean; // Whether column is hidden from custom columns selection
333
+ }[];
334
+ customColumns?: {
335
+ enabled: boolean; // Enable user customization (hide/reorder columns)
336
+ };
337
+ stickyColumns?: number; // Number of columns to make sticky from the start. Sticky columns remain visible when horizontally scrolling.
338
+ };
339
+ },
340
+ {
341
+ type: 'Grid'; // Layout item type for grid rendering
342
+ grid?: {
343
+ item: {
344
+ titleFieldId: string; // Field ID to display as the item title
345
+ subtitleFieldId?: string; // Field ID for the item subtitle
346
+ imageFieldId?: string; // Field ID for the item image
347
+ /**
348
+ * Controls which content is shown in the card (preset):
349
+ * - 'full': Shows both title and subtitle.
350
+ * - 'title': Shows only the title.
351
+ * - 'empty': Hides both title and subtitle (card appears visually empty except for image or other content).
352
+ */
353
+ cardContentMode?: 'full' | 'title' | 'empty';
354
+ imagePlacement?: 'top' | 'side';
355
+ };
356
+ };
357
+ }
358
+ ]; // End of layout array
359
+ }
360
+ ]; // End of components array
361
+ };
362
+ entityPage?: {
363
+ route: {
364
+ path: string; // Route path for the entity page (e.g., '/product/:entityId')
365
+ params: {
366
+ id: string; // Maps dynamic parameter in path to its identifier
367
+ };
368
+ };
369
+ title?: {
370
+ text: string; // Entity page title
371
+ };
372
+ subtitle?: {
373
+ text: string; // Entity page subtitle
374
+ };
375
+ parentPageId?: string; // ID of the parent collection page
376
+ layout?: {
377
+ // Main layout section
378
+ main: {
379
+ type: 'card'; // Type of the card
380
+ card: {
381
+ title: {
382
+ text: string; // Title of the card
383
+ };
384
+ subtitle?: {
385
+ text: string; // Subtitle of the card
386
+ };
387
+ children: LayoutContent[]; // Array of content items that can be fields, nested containers, or components
388
+ };
389
+ }[];
390
+ // Sidebar layout section
391
+ sidebar?: {
392
+ type: 'card';
393
+ card: {
394
+ title: {
395
+ text: string; // Title of the card
396
+ };
397
+ subtitle?: {
398
+ text: string; // Subtitle of the card
399
+ };
400
+ children: LayoutContent[]; // Array of content items that can be fields, nested containers, or components
401
+ };
402
+ }[];
403
+ };
404
+ collectionId: string; // Related collection ID
405
+ entityTypeSource: 'cms'; // Data source type. Always 'cms'
406
+ };
407
+ }[];
408
+ }
409
+
410
+ type LayoutContent =
411
+ | {
412
+ type: 'field';
413
+ field: {
414
+ span?: number;
415
+ fieldId: string;
416
+ };
417
+ }
418
+ | {
419
+ type: 'container';
420
+ container: {
421
+ span?: number;
422
+ children: LayoutContent[];
423
+ };
424
+ }
425
+ | {
426
+ type: 'component';
427
+ component: {
428
+ span?: number;
429
+ componentId: string;
430
+ };
431
+ };
432
+ ```
433
+
434
+ ---
435
+
436
+ # Pages Configuration
437
+
438
+ ## ⚠️ Critical Page Rules
439
+
440
+ - **Pages array must contain exactly two pages** - one collectionPage and one entityPage
441
+ - **Exactly one page must have `appMainPage: true`** to designate it as the main page
442
+ - **All page IDs referenced in relationships must exist in the configuration** - validate all `parentPageId` and `entityPageId` references
443
+ - **Bind `type` strictly to matching fields** - if `type: 'collectionPage'`, only `collectionPage` field exists (no `entityPage` field), and vice versa
444
+
445
+ ## Default Generation
446
+
447
+ * **Always generate two pages**:
448
+
449
+ * One **collectionPage** (routePath: `/`)
450
+ * One **entityPage** (routePath: `/[segment]/:entityId`)
451
+
452
+ * Always use `entityId` as the dynamic URL parameter, not `id`.
453
+ * The route path **must** include a descriptive segment (e.g., `/product/:entityId`, `/pet/:entityId`)
454
+ * **Never use just `/:entityId`** - this conflicts with the collection page route and breaks routing
455
+
456
+ ## Type and Structure Binding
457
+
458
+ * If `type: 'collectionPage'`, then **only** `collectionPage` field exists (no `entityPage` field).
459
+ * If `type: 'entityPage'`, then **only** `entityPage` field exists (no `collectionPage` field).
460
+ * **No cross-mixing** allowed.
461
+
462
+ ## Page Connection Configuration
463
+
464
+ ### Main Page Designation
465
+
466
+ * One page must be designated as the main page using the `appMainPage` property:
467
+ * **Exactly one page** must have `appMainPage: true`
468
+ * When users navigate to the root path (`/`), they will be automatically redirected to this page
469
+ * This is typically set on the collection page, but can be any page based on your application's requirements
470
+
471
+ ### Collection-Entity Page Relationships
472
+
473
+ A two-way connection must be established between collection pages and entity pages:
474
+
475
+ 1. **From EntityPage to CollectionPage**:
476
+ * Each entity page must specify its parent collection page using `parentPageId`
477
+ * This property on the entity page references the `id` of its parent collection page
478
+
479
+ 2. **From CollectionPage to EntityPage**:
480
+ * Each collection page's component must reference its corresponding entity page:
481
+ * Inside the table or grid configuration (not directly in the collectionPage), specify `entityPageId` pointing to the entity page's `id`:
482
+ ```json
483
+ "components": [
484
+ {
485
+ "type": "Table", // or "Grid"
486
+ "table": { // or "grid"
487
+ "entityPageId": "my-entity-page-id",
488
+ // other table/grid configuration
489
+ }
490
+ }
491
+ ]
492
+ ```
493
+ * ⚠️ **IMPORTANT**: The `entityPageId` field is located within the specific component configuration (table or grid), not at the collection page level
494
+
495
+ ### Entity Page URL Configuration
496
+
497
+ * For entity pages (`type: "entityPage"`), the following URL configuration is **mandatory**:
498
+
499
+ 1. **Route Path Structure**:
500
+ * The `route.path` **must** include a relative path segment followed by a dynamic parameter (e.g., `/product/:entityId` or `/pets/:entityId`)
501
+ * **Never use just `/:entityId`** - this conflicts with the collection page route `/` and breaks routing
502
+ * The relative path segment should be descriptive of the entity type (e.g., `/product/`, `/pet/`, `/user/`)
503
+ * This parameter is typically named `:entityId` by convention, but any parameter name prefixed with `:` is valid
504
+
505
+ 2. **Route Parameters Mapping**:
506
+ * The `route.params` property is required and must map the dynamic parameter:
507
+ ```json
508
+ "route": {
509
+ "path": "/product/:entityId",
510
+ "params": {
511
+ "id": "entityId"
512
+ }
513
+ }
514
+ ```
515
+ * The `id` field in `route.params` must match the parameter name used in `route.path` (without the colon)
516
+
517
+
518
+ ### Key Rules for Page Connections
519
+
520
+ * **Main Page Requirement**: Exactly one page must have `appMainPage: true`
521
+ * **Reference Validity**: All page IDs referenced in `parentPageId` and `entityPageId` must exist in the configuration
522
+ * **Relationship Consistency**: The two-way connection must be consistent - if entity page A points to collection page B, then collection page B must point to entity page A
523
+ * **Route Structure**: Entity pages must use `/[segment]/:entityId` format (e.g., `/product/:entityId` or `/pets/:entityId`), never just `/:entityId`
524
+ * **Route Parameters Configuration**: All entity pages must have both a dynamic parameter in `route.path` and a matching configuration in `route.params`
525
+
526
+ ## ⚠️ Common Type and Route Mistakes to Avoid
527
+
528
+ - Using incorrect field types
529
+ - Missing required fields
530
+ - Including fields from wrong page type
531
+ - Missing route.params for entity pages
532
+ - Using `/:entityId` instead of `/segment/:entityId` for entity page routes (causes routing conflicts)
533
+
534
+ # Sticky Columns Configuration
535
+
536
+ ## Overview
537
+
538
+ Sticky columns allow you to keep specific columns visible while users scroll horizontally through wide tables. This feature improves usability by ensuring important information (like names or IDs) remains accessible during scrolling.
539
+
540
+ ## Configuration Properties
541
+
542
+ ### stickyColumns
543
+
544
+ - **Type**: `number` (optional)
545
+ - **Description**: Number of columns to make sticky from the start of the table
546
+ - **Behavior**: Sticky columns are always the **first N columns** in the `columns` array
547
+ - **Default**: `undefined` (no sticky columns)
548
+
549
+ ## Key Behavior Rules
550
+
551
+ ### 🔑 **Critical Rule: Position-Based Stickiness**
552
+ - `stickyColumns: 2` means "make the **first 2 columns** sticky" (positions 0 and 1 in the `columns` array)
553
+ - The sticky columns are determined by **array position**, not by column content
554
+ - If columns are reordered, the sticky behavior follows the new order
555
+
556
+ ### 🔒 **Important: Reorder Protection**
557
+ - To protect specific columns from being reordered away from their sticky positions, set `reorderDisabled: true` on those columns
558
+ - This allows `customColumns.enabled: true` while protecting sticky columns from being moved
559
+ - Without reorder protection, users can accidentally move intended sticky columns away from the beginning
560
+
561
+ ### ⚠️ **Validation Rules**
562
+ - `stickyColumns` must be a positive number
563
+ - `stickyColumns` should not exceed the total number of columns
564
+ - Invalid values are ignored (treated as `undefined`)
565
+
566
+ ---
567
+
568
+ # Collection Page Configuration
569
+
570
+ ## ⚠️ Collection Page Rules
571
+
572
+ - **Components array inside collectionPage must contain exactly one component with a layout array**
573
+ - **All collection pages with tables/grids must reference their corresponding entity page via `entityPageId`** in the collection configuration
574
+ - **Enable `customColumns` only based on strict logic** - enable if more than 5 columns are defined OR user explicitly requests it, otherwise disable
575
+ - **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
576
+ - **When generating config for first time, select up to 3 columns from the schema that best represent the entity**
577
+
578
+ ## Components Array
579
+
580
+ * Must include **exactly one item**.
581
+ * Each component must have:
582
+ * `collection`: Collection configuration with `collectionId` and `entityTypeSource: 'cms'`
583
+ * `layout`: Array of layout items that determine what components to render
584
+
585
+ ## Layout Array
586
+
587
+ The `layout` array contains the rendering components for the collection. Each layout item has:
588
+ * `type`: Either 'Table' or 'Grid'
589
+ * Component-specific configuration (`table` or `grid` object)
590
+
591
+ ### Layout Item Types:
592
+
593
+ 1. **Table Layout Item** (`type: 'Table'`):
594
+ * `table` field contains table-specific configuration
595
+ * Used for displaying collection in a **table view**
596
+ * Includes columns, actionCell, bulkActionToolbar, etc.
597
+
598
+ 2. **Grid Layout Item** (`type: 'Grid'`):
599
+ * `grid` field contains grid-specific configuration
600
+ * Used for **grid (card) view** of collection
601
+ * Includes item configuration for title/subtitle/image fields
602
+
603
+ ### Table/Grid View Switch Behavior:
604
+ * 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
605
+ * Users can toggle between table and grid views
606
+
607
+ ## Table Configuration
608
+
609
+ * Used for displaying collection in a **table view**.
610
+ * **customColumns.enabled** logic:
611
+ * Enable if:
612
+ * More than **5 columns** are defined
613
+ * OR user **explicitly** requests it
614
+ * Otherwise, **disable** (false)
615
+
616
+ ## Grid Configuration
617
+
618
+ * Used for **grid (card) view** of collection.
619
+ * `item.title`, `item.subtitle`, `item.image` fields are **Field IDs** from the schema.
620
+ * If the user does not specify, **select the most relevant fields automatically**.
621
+ * 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.
622
+
623
+ ---
624
+
625
+ # Collection Page Actions
626
+
627
+ ## ⚠️ Required Actions
628
+
629
+ - **Every collection page must include a create action that navigates to the entity page for adding new entities** - this is essential for user workflow
630
+
631
+ 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.
632
+
633
+ ## `primaryActions` and `secondaryActions` Structure
634
+
635
+ 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:
636
+
637
+ ### A. Action Layout (`type: "action"`)
638
+ * **Description**: This layout is used to display a single, prominent page-level action. For example, a "Create New Item" button.
639
+ * **`action.item`**: Contains the configuration for the single action.
640
+
641
+ ### B. Action Menu Layout (`type: "menu"`)
642
+ * **Description**: This layout groups several page-level actions, often rendered as a dropdown menu or a set of related buttons under a common label.
643
+ * **`menu.label`**: A string that serves as the title or accessible label for the group of actions.
644
+ * **`menu.items`**: A flat array of action configurations, which can include divider objects for visual separation.
645
+
646
+ ## Individual Action Configuration
647
+
648
+ 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`).
649
+
650
+ In addition to these common properties, each action item must specify a `type` which determines the action's behavior and additional required configuration.
651
+
652
+ ### 1. `type: "create"`
653
+ * **Purpose**: Navigates to an entity page, allowing the user to create a new item in the specified collection.
654
+ * **Details**:
655
+ * `create.mode`: Must be `'page'`.
656
+ * `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`.
657
+
658
+ ### 2. `type: "custom"`
659
+ * **Purpose**: Executes custom JavaScript logic defined in your application's overrides.
660
+ * **Details**:
661
+ * 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`.
662
+
663
+ ### 3. `type: "divider"`
664
+ * **Purpose**: Creates a visual separator between action groups in menus and lists.
665
+ * **Details**:
666
+ * Divider actions require no additional configuration beyond `{ "type": "divider" }`.
667
+ * Used within flat arrays to create logical groupings.
668
+
669
+ ## Note on `secondaryActions`
670
+
671
+ `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.
672
+
673
+ ## Custom Collection Page Action Configuration
674
+
675
+ 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:
676
+
677
+ 1. First, create the actions folder structure in your page folder:
678
+ ```
679
+ your-page/
680
+ ├── page.tsx
681
+ └── components/
682
+ └── actions/
683
+ ├── index.tsx // Exports all actions
684
+ └── exportCollection.tsx // Your custom collection action
685
+ ```
686
+
687
+ 2. Create your collection action handler in `exportCollection.tsx`:
688
+ ```typescript
689
+ import { CustomActionCollectionPageActionResolver } from '@wix/auto-patterns';
690
+ import React from 'react';
691
+ import { Download } from '@wix/ui-icons-common';
692
+
693
+ // IMPORTANT: Function name MUST match the action id in your configuration
694
+ export const exportCollection: CustomActionCollectionPageActionResolver = (params) => {
695
+ const { actionParams, sdk } = params;
696
+ const { collectionId } = actionParams;
697
+
698
+ return {
699
+ label: 'Export Collection',
700
+ icon: <Download />,
701
+ onClick: () => {
702
+ // sdk is provided to custom action resolvers (see SDK Utilities section)
703
+ const optimisticActions = sdk.getOptimisticActions(collectionId);
704
+ const schema = sdk.getSchema(collectionId);
705
+
706
+ // Example: Mark entire collection as exported
707
+ optimisticActions.updateAll(
708
+ (item) => ({ lastExported: new Date() }),
709
+ {
710
+ submit: async () => {
711
+ // Your collection export logic here
712
+ console.log(`Exporting collection: ${collectionId}`);
713
+ // Export and update all items on server
714
+ return await schema.actions.bulkUpdate({ lastExported: new Date() });
715
+ },
716
+ successToast: 'Collection exported successfully',
717
+ errorToast: (err, {retry}) => ({
718
+ text: 'Export failed',
719
+ action: { text: 'Retry', onClick: retry }
720
+ })
721
+ }
722
+ );
723
+ },
724
+ };
725
+ };
726
+ ```
727
+
728
+ 3. Export your action in `actions/index.tsx`:
729
+ ```typescript
730
+ export * from './exportCollection';
731
+ ```
732
+
733
+ 4. Configure the action in your JSON configuration:
734
+ ```json
735
+ {
736
+ "id": "exportCollection", // MUST match the function name exactly
737
+ "type": "custom", // REQUIRED: Must be exactly "custom"
738
+ "label": "Export Collection", // Optional: Displayed text
739
+ "collection": {
740
+ "collectionId": "WixPets",
741
+ "entityTypeSource": "cms"
742
+ }
743
+ }
744
+ ```
745
+
746
+ 5. Register your action in the `PatternsWizardOverridesProvider`:
747
+ ```typescript
748
+ import * as actions from './components/actions';
749
+
750
+ <PatternsWizardOverridesProvider value={{ actions }}>
751
+ <AutoPatternsApp configuration={config as AppConfig} />
752
+ </PatternsWizardOverridesProvider>
753
+ ```
754
+
755
+ ## Key Points for Custom Collection Page Actions:
756
+ - The action `id` in the configuration MUST exactly match the function name exported from your actions folder
757
+ - The function name and file name should follow a consistent naming convention (e.g., camelCase)
758
+ - The implementation must be exported as a named export (not default export)
759
+ - The implementation must use the `CustomActionCollectionPageActionResolver` type
760
+ - Access collection context through `actionParams.collectionId`
761
+
762
+ ---
763
+
764
+ ## Custom Row Click Actions
765
+
766
+ 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.
767
+
768
+ **Before You Start:**
769
+ - Only configure `onRowClick` if you need custom behavior (e.g., opening modals, side panels, custom actions)
770
+ - If you just want navigation to entity page, don't configure `onRowClick` - it's the default behavior
771
+ - Once you configure `onRowClick`, you must provide a complete working implementation
772
+
773
+ ### Configuration
774
+
775
+ Row click actions are configured at the table level using the `onRowClick` property:
776
+
777
+ ```json
778
+ {
779
+ "type": "Table",
780
+ "table": {
781
+ "columns": [...],
782
+ "onRowClick": {
783
+ "id": "handleRowClick", // MUST match the function name exactly
784
+ "type": "custom", // REQUIRED: Must be exactly "custom"
785
+ }
786
+ }
787
+ }
788
+ ```
789
+
790
+ ### Implementation Requirements
791
+
792
+ ⚠️ **CRITICAL**: When you configure `onRowClick` in your JSON, you MUST provide a complete working implementation. The Auto Patterns framework cannot function without it.
793
+
794
+ Custom row click actions use the `CustomActionCollectionPageActionOnRowClickResolver` type and MUST return a `ResolvedAction` object with all required properties:
795
+
796
+ #### Required Return Object Structure:
797
+ ```typescript
798
+ return {
799
+ label: string, // REQUIRED: Action label
800
+ icon: ReactElement, // REQUIRED: Icon component
801
+ onClick: () => void // REQUIRED: Click handler function
802
+ };
803
+ ```
804
+
805
+ #### Complete Implementation Example:
806
+
807
+ ```typescript
808
+ import { CustomActionCollectionPageActionOnRowClickResolver } from '@wix/auto-patterns';
809
+ import React from 'react';
810
+ import { More } from '@wix/wix-ui-icons-common';
811
+
812
+ // IMPORTANT: Function name MUST match the action id in your configuration
813
+ export const handleRowClick: CustomActionCollectionPageActionOnRowClickResolver = (params) => {
814
+ const { actionParams, sdk } = params;
815
+ const { item } = actionParams; // The clicked row's data
816
+
817
+ return {
818
+ label: 'View Details', // REQUIRED
819
+ icon: <More />, // REQUIRED
820
+ onClick: () => { // REQUIRED
821
+ // Your custom row click logic here
822
+ console.log('Row clicked:', item);
823
+
824
+ // Example: Show a custom modal, perform an action, etc.
825
+ // You can access all SDK utilities here (see SDK Utilities section)
826
+ const optimisticActions = sdk.getOptimisticActions(sdk.collectionId);
827
+ const schema = sdk.getSchema(sdk.collectionId);
828
+
829
+ // Your custom logic...
830
+ },
831
+ };
832
+ };
833
+ ```
834
+
835
+ ### Common Use Cases and Complete Examples
836
+
837
+ #### 1. Opening a Side Panel Modal
838
+
839
+ This is a complete working example for opening a side panel when clicking a row:
840
+
841
+ **Step 1: Create the row click action** (`components/actions/openSidePanel.tsx`):
842
+ ```typescript
843
+ import { CustomActionCollectionPageActionOnRowClickResolver } from '@wix/auto-patterns';
844
+ import React from 'react';
845
+ import { More } from '@wix/wix-ui-icons-common';
846
+
847
+ export const openSidePanel: CustomActionCollectionPageActionOnRowClickResolver = (params) => {
848
+ const { actionParams, sdk } = params;
849
+ const { item } = actionParams;
850
+
851
+ return {
852
+ label: 'View Details',
853
+ icon: <More />,
854
+ onClick: () => {
855
+ // Open a custom modal with the item data
856
+ // You need to implement the modal opening mechanism
857
+ // This could be through a modal context, state management, etc.
858
+ console.log('Opening side panel for:', item);
859
+
860
+ // Example: Using a global modal state (you need to implement this)
861
+ // window.dispatchEvent(new CustomEvent('openSidePanel', { detail: item }));
862
+
863
+ // Or use a modal service/context that you've set up
864
+ // modalService.openSidePanel(item);
865
+ },
866
+ };
867
+ };
868
+ ```
869
+
870
+ **Step 2: Configure in JSON**:
871
+ ```json
872
+ {
873
+ "type": "Table",
874
+ "table": {
875
+ "onRowClick": {
876
+ "id": "openSidePanel",
877
+ "type": "custom"
878
+ },
879
+ "columns": [...]
880
+ }
881
+ }
882
+ ```
883
+
884
+ **Step 3: Export and Register**:
885
+ ```typescript
886
+ // components/actions/index.tsx
887
+ export * from './openSidePanel';
888
+
889
+ // page.tsx
890
+ import * as actions from './components/actions';
891
+
892
+ <PatternsWizardOverridesProvider value={{ actions }}>
893
+ <AutoPatternsApp configuration={config as AppConfig} />
894
+ </PatternsWizardOverridesProvider>
895
+ ```
896
+
897
+ #### 2. Direct Data Manipulation
898
+
899
+ ```typescript
900
+ export const quickToggle: CustomActionCollectionPageActionOnRowClickResolver = (params) => {
901
+ const { actionParams, sdk } = params;
902
+ const { item } = actionParams;
903
+
904
+ return {
905
+ label: 'Quick Toggle',
906
+ icon: <Toggle />,
907
+ onClick: () => {
908
+ const optimisticActions = sdk.getOptimisticActions(sdk.collectionId);
909
+ const schema = sdk.getSchema(sdk.collectionId);
910
+
911
+ // Example: Toggle a boolean field
912
+ const updatedItem = { ...item, isActive: !item.isActive };
913
+
914
+ optimisticActions.updateOne(updatedItem, {
915
+ submit: async (items) => schema.actions.update(items[0]),
916
+ successToast: `${item.name} toggled successfully`,
917
+ errorToast: (err, {retry}) => ({
918
+ text: 'Toggle failed',
919
+ action: { text: 'Retry', onClick: retry }
920
+ })
921
+ });
922
+ },
923
+ };
924
+ };
925
+ ```
926
+
927
+ ### Default vs Custom Behavior
928
+
929
+ **Default Behavior (when `onRowClick` is not configured):**
930
+ - Clicking a row automatically navigates to the entity page
931
+ - Uses the `entityPageId` configuration to determine the target page
932
+ - Passes the selected item's data to the entity page
933
+
934
+ **Custom Behavior (when `onRowClick` is configured):**
935
+ - Default navigation is **disabled**
936
+ - Your custom action function is executed instead
937
+ - You have complete control over the row click behavior
938
+ - You can still navigate to the entity page programmatically if needed using the SDK navigation utilities
939
+
940
+ ### Key Points for Custom Row Click Actions:
941
+ - **MANDATORY IMPLEMENTATION**: If you configure `onRowClick` in JSON, you MUST provide a complete working implementation - the framework cannot function without it
942
+ - The action `id` in the configuration MUST exactly match the function name exported from your actions folder
943
+ - The implementation must use the `CustomActionCollectionPageActionOnRowClickResolver` type
944
+ - **Required Return Object**: Must return an object with `label`, `icon`, and `onClick` properties - all are required
945
+ - Access the clicked item's data through `actionParams.item`
946
+ - The implementation must be exported as a named export and registered in your `PatternsWizardOverridesProvider`
947
+ - When `onRowClick` is configured, the default navigation to entity page is completely disabled
948
+ - **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
949
+
950
+ ## Validation Checklist for Collection Page Actions
951
+
952
+ ✓ Every collection page must include a create action.
953
+ ✓ `actions` is an optional property of `collectionPage`.
954
+ ✓ `primaryActions` and `secondaryActions` (if defined) have a valid `type` ("action" or "menu").
955
+ ✓ If `type: "action"`, `action.item` is a valid action item configuration.
956
+ ✓ If `type: "menu"`, `menu.items` is an array of valid action item configurations that can include dividers.
957
+ ✓ Each action item contains a unique `id`, and the full `collection` object (`collectionId`, `entityTypeSource: 'cms'`).
958
+ ✓ Each action item has a supported `type` (`create`, `custom`) and its corresponding configuration block (e.g., `create` block for `type: "create"`).
959
+ ✓ `create` actions specify a `create.page.id` that matches an existing `entityPage` ID in the configuration.
960
+ ✓ `custom` actions (identified by their main `id`) correspond to an action resolver function name registered in the `actions` override.
961
+ ✓ Divider actions use `{ "type": "divider" }` format and require no additional properties.
962
+ ✓ If `onRowClick` is configured in table layout, it must have a valid `id` and `type: "custom"`.
963
+ ✓ **CRITICAL**: Custom row click actions must have corresponding implementations registered in the `actions` override - configuration without implementation will cause errors.
964
+ ✓ Custom row click action implementations must return an object with `label`, `icon`, and `onClick` properties - all are required.
965
+ ✓ Custom row click action implementations must be exported as named exports and included in the actions index file.
966
+ ✓ `onRowClick` is optional - when not configured, rows navigate to entity page by default.
967
+ ✓ **IMPORTANT**: Configuring `onRowClick` completely disables default navigation - you must handle all row click logic in your custom implementation.
968
+
969
+ ---
970
+
971
+ ## SDK Utilities
972
+
973
+ 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).
974
+
975
+ ### Key SDK Utilities
976
+ The only functions exist in sdk are:
977
+
978
+ • **closeModal** - `closeModal(): void`
979
+ - Closes the currently open modal
980
+ - Example: `sdk.closeModal()` after saving or canceling
981
+
982
+ • **getOptimisticActions** - `getOptimisticActions(collectionId): OptimisticActions`
983
+ - Provides optimistic UI updates for immediate user feedback
984
+ - Supports create, update, delete operations with automatic rollback on failure
985
+ - Example: `sdk.getOptimisticActions(sdk.collectionId).updateOne(item, { ... })`
986
+
987
+ • **getSchema** - `getSchema(collectionId): SchemaConfig | undefined`
988
+ - Access to collection schema information (fields, types, validation)
989
+ - Useful for dynamic operations based on collection structure
990
+ - Example: `const schema = sdk.getSchema(sdk.collectionId)`
991
+
992
+ • **collectionId** - `string`
993
+ - Current collection context identifier
994
+ - Available in all action contexts for referencing the active collection
995
+ - Example: `sdk.collectionId` to get the current collection ID
996
+
997
+ ---
998
+
999
+ ## OptimisticActions
1000
+
1001
+ Provides immediate UI updates with automatic server synchronization and error recovery.
1002
+
1003
+ ### Usage Rules
1004
+
1005
+ **Use OptimisticActions for:**
1006
+ - Data modification operations (create, update, delete)
1007
+ - Operations requiring immediate visual feedback
1008
+
1009
+ **Do NOT use for:**
1010
+ - Read-only operations
1011
+ - Operations requiring server confirmation first
1012
+
1013
+ ### Core Pattern
1014
+
1015
+ ```typescript
1016
+ // Get instances from SDK (see SDK Utilities section)
1017
+ const optimisticActions = sdk.getOptimisticActions(sdk.collectionId);
1018
+ const schema = sdk.getSchema(sdk.collectionId);
1019
+
1020
+ optimisticActions.operation(items, {
1021
+ submit: async (items) => schema.actions.serverMethod(items),
1022
+ successToast: 'Success message',
1023
+ errorToast: (err, {retry}) => ({ text: 'Error message', action: { text: 'Retry', onClick: retry }})
1024
+ });
1025
+ ```
1026
+
1027
+ ### Available Operations
1028
+
1029
+ #### Create Operations
1030
+ - `createOne(item: T, params: OptimisticParams<T>): void`
1031
+ - `createMany(items: T[], params: OptimisticParams<T>): void`
1032
+
1033
+ #### Update Operations
1034
+ - `updateOne(item: T, params: OptimisticParams<T>): void`
1035
+ - `updateMany(items: T[], params: OptimisticParams<T>): void`
1036
+ - `updateAll(transformFn: (item: T) => Partial<T>, params: OptimisticParams<T>): void`
1037
+
1038
+ #### Delete Operations
1039
+ - `deleteOne(item: T, params: OptimisticParams<T> & { showUndoToast: true }): void`
1040
+ - `deleteMany(items: T[], params: OptimisticParams<T> & { showUndoToast: true }): void`
1041
+ - `deleteAll(params: OptimisticParams<T> & { showUndoToast: true }): void`
1042
+
1043
+ ### Type Definitions
1044
+
1045
+ ```typescript
1046
+ interface OptimisticParams<T> {
1047
+ submit: (items: T[]) => Promise<any>;
1048
+ successToast: string | ToastConfig;
1049
+ errorToast: (error: Error, actions: { retry: () => void }) => ToastConfig | string;
1050
+ showUndoToast?: boolean; // Required: true for delete operations
1051
+ }
1052
+
1053
+ interface ToastConfig {
1054
+ text: string;
1055
+ action?: { text: string; onClick: () => void };
1056
+ }
1057
+ ```
1058
+
1059
+ ### Validation Requirements
1060
+
1061
+ **Before using optimistic actions:**
1062
+ - Verify `sdk.getOptimisticActions(collectionId)` returns valid instance
1063
+ - Verify `sdk.getSchema(collectionId)` returns valid schema
1064
+ - For delete operations: `showUndoToast: true` is mandatory
1065
+ - All `submit` functions must return a Promise
1066
+
1067
+ **SDK Parameter:** Available in custom actions and modals. See SDK Utilities section for complete interface.
1068
+
1069
+ ---
1070
+
1071
+ ## SchemaConfig Usage
1072
+
1073
+ SchemaConfig provides complete collection metadata and server actions. Essential for dynamic operations and accessing collection structure information.
1074
+
1075
+ ### Key Properties
1076
+
1077
+ • **id** - `string`
1078
+ - Collection identifier (e.g., "WixPets")
1079
+ - Example: `schema.id === "WixPets"`
1080
+
1081
+ • **idField** - `string`
1082
+ - Primary key field name (usually "_id")
1083
+ - Required for all update/delete operations
1084
+ - Example: `const id = item[schema.idField]`
1085
+
1086
+ • **displayField** - `string`
1087
+ - Main field for displaying items (name, title, etc.)
1088
+ - Used in UI components for item identification
1089
+ - Example: `const label = item[schema.displayField]`
1090
+
1091
+ • **fields** - `Record<string, Field | undefined>`
1092
+ - Complete field definitions with types and metadata
1093
+ - Useful for dynamic form generation or validation
1094
+ - Example: `schema.fields.name.type === 'TEXT'`
1095
+
1096
+ • **actions** - Server operation functions
1097
+ - Pre-configured API calls for CRUD operations
1098
+ - Use with optimistic actions for best UX
1099
+ - Example: `await schema.actions.update(item)`
1100
+
1101
+ ### Available Schema Actions
1102
+
1103
+ - schema.actions.create(item) // Create single item
1104
+ - schema.actions.update(item) // Update single item
1105
+ - schema.actions.delete(itemId) // Delete by ID
1106
+ - schema.actions.bulkUpdate(updates) // Update multiple items
1107
+ - schema.actions.bulkDelete(itemIds) // Delete multiple items
1108
+
1109
+ ### Schema Validation Checklist
1110
+
1111
+ Before using schema in operations:
1112
+
1113
+ ✓ Check if schema exists: `if (!schema) return;`
1114
+ ✓ Verify required fields exist on items
1115
+ ✓ Use `schema.idField` for ID operations
1116
+ ✓ Use `schema.displayField` for UI display
1117
+ ✓ Use `schema.actions` for server operations
1118
+
1119
+ ### Common Usage Patterns
1120
+
1121
+ - **ActionCell**: Use `schema.actions.update()` or `schema.actions.delete()` for single item operations
1122
+ - **BulkActions**: Use `schema.actions.bulkUpdate()` or `schema.actions.bulkDelete()` for multiple items
1123
+ - **Dynamic UI**: Use `schema.fields` to build forms or validate data
1124
+ - **Error Messages**: Use `schema.displayField` to create meaningful user feedback
1125
+
1126
+ ---
1127
+
1128
+ ## Filters Configuration Notes
1129
+
1130
+ 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:
1131
+
1132
+ * `numberConfig`: used with fields of type `NUMBER`
1133
+ * `dateConfig`: used with fields of type `DATETIME`
1134
+ * `booleanConfig`: used with fields of type `BOOLEAN`
1135
+ * `enumConfig`: used with fields of type `ARRAY` or `ARRAY_STRING`
1136
+
1137
+ ### Enum Configuration Implementation
1138
+
1139
+ 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:
1140
+
1141
+ #### Example: User-Provided Enum Implementation
1142
+
1143
+ 1. First, collect the possible values from the user:
1144
+ ```
1145
+ User requests: "I need a filter for pet types."
1146
+ You ask: "What are the possible values for pet types that should be available in the filter?"
1147
+ User responds: "dog, cat, bird, rabbit, fish"
1148
+ ```
1149
+
1150
+ 2. Then, create the `enumConfig` structure:
1151
+ ```json
1152
+ "enumConfig": {
1153
+ "options": [
1154
+ { "value": "dog", "label": "Dog" },
1155
+ { "value": "cat", "label": "Cat" },
1156
+ { "value": "bird", "label": "Bird" },
1157
+ { "value": "rabbit", "label": "Rabbit" },
1158
+ { "value": "fish", "label": "Fish" }
1159
+ ],
1160
+ "selectionMode": "multiple",
1161
+ "optionType": "checkbox"
1162
+ }
1163
+ ```
1164
+
1165
+ Notice how the `label` is derived from the `value` by capitalizing the first letter. The user's exact values become the `value` property.
1166
+
1167
+ ### Grouping Filters with Section Title
1168
+
1169
+ * Filters can be grouped by sections using the `sectionTitle` property.
1170
+ * If multiple filter items share the same `sectionTitle`, they will be displayed together in a grouped section in the UI.
1171
+ * Filters without a `sectionTitle` will appear in a default section or be displayed individually.
1172
+ * Grouping helps maintain clarity, especially when dealing with multiple filter options.
1173
+
1174
+ ### Key Guidelines
1175
+
1176
+ * **openByDefault**: Automatically expands the filter accordion when the filters panel is opened.
1177
+ * **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`.
1178
+ * **maxInlineFilters**: Limits the number of filters shown inline in the table toolbar. Others are accessible via the panel. Default is 0.
1179
+ * **dateConfig.mode**:
1180
+
1181
+ * `ONLY_PREDEFINED`: user can select only from preset options
1182
+ * `ONLY_CUSTOM`: user must select a custom date range manually (no presets)
1183
+ * `COMBINE`: both options available
1184
+ * **dateConfig.presets** must be omitted if mode is `ONLY_CUSTOM`.
1185
+ * **dateConfig.includeTime**: Controls whether time selection is also enabled alongside date (default is `true`).
1186
+
1187
+ ---
1188
+
1189
+ ## ActionCell Configuration
1190
+
1191
+ The ActionCell feature adds an interactive action column to collection tables or grid views, enabling users to perform operations on individual entities.
1192
+
1193
+ ### Placement and Structure
1194
+
1195
+ The ActionCell has a two-level structure:
1196
+ * `primaryAction`: A single prominent action shown directly in the table/grid row
1197
+ * `secondaryActions`: Additional actions shown in a dropdown menu
1198
+
1199
+ Both properties are optional, but at least one should be provided for the ActionCell to be useful.
1200
+
1201
+ ### Inline Secondary Actions
1202
+
1203
+ **New Feature**: By default, all secondary actions are hidden in a popover menu that appears when the user hovers over or clicks the "more actions" button. However, you can now configure some secondary actions to display inline directly in the table row for improved accessibility and reduced clicks.
1204
+
1205
+ ### Action Types Reference
1206
+
1207
+ 1. **Update Action** (`type: "update"`):
1208
+ - ✓ Use when: Editing entity fields or navigating to a detailed edit page
1209
+ - ✓ Common scenarios:
1210
+ - Full entity editing (use page mode)
1211
+ - ✓ Built-in functionality: No custom implementation needed
1212
+
1213
+ 2. **Delete Action** (`type: "delete"`):
1214
+ - ✓ Use when: Removing entities with confirmation
1215
+ - ✓ Common scenarios:
1216
+ - Deleting records with confirmation
1217
+ - Soft-delete with status update
1218
+ - ✓ Built-in functionality: No custom implementation needed
1219
+
1220
+ 3. **Custom Action** (`type: "custom"`):
1221
+ - ✓ Use when: Executing custom JavaScript without UI
1222
+ - ✓ Common scenarios:
1223
+ - API calls
1224
+ - Browser interactions (alerts, downloads)
1225
+ - Complex operations
1226
+ - ⚠️ Requires implementation: Must register action in overrides
1227
+
1228
+ ### Type Selection Decision Tree
1229
+
1230
+ When choosing an action type, follow this decision process:
1231
+
1232
+ 1. IF editing entity fields:
1233
+ → Use `type: "update"`
1234
+ a. IF complex edits → Use `mode: "page"`
1235
+
1236
+ 2. IF removing entities:
1237
+ → Use `type: "delete"`
1238
+
1239
+ 3. IF executing custom logic without UI:
1240
+ → Use `type: "custom"`
1241
+ - MUST implement action handler
1242
+ - MUST register with `actions` override
1243
+
1244
+ ### Update Action Configuration
1245
+
1246
+ Update actions edit entities by navigating to an entity page.
1247
+
1248
+ #### Validation Rules:
1249
+
1250
+ 1. If `update.mode` is `"page"`:
1251
+ - `update.page` must exist
1252
+ - `update.page.id` must match an entity page ID in the configuration
1253
+
1254
+ ### Delete Action Configuration
1255
+
1256
+ Delete actions remove entities with a confirmation modal.
1257
+
1258
+ #### Validation Rules:
1259
+
1260
+ 1. `delete.mode` must be `"modal"` (currently only modal is supported)
1261
+ 2. `delete.modal` object must exist
1262
+ 3. The modal properties (title, description, actions, feedback) are all optional
1263
+
1264
+ ### Custom Action Configuration
1265
+
1266
+ Custom actions execute JavaScript code that you define. These actions receive parameters that give them access to entity data and utilities. Here's how to implement a custom action:
1267
+
1268
+ 1. First, create the actions folder structure in your page folder:
1269
+ ```
1270
+ your-page/
1271
+ ├── page.tsx
1272
+ └── components/
1273
+ └── actions/
1274
+ ├── index.tsx // Exports all actions
1275
+ └── downloadPetDetails.tsx // Your custom action (name = action id)
1276
+ ```
1277
+
1278
+ 2. Create your action handler in `downloadPetDetails.tsx` (note: the filename and function name MUST match your action id):
1279
+ ```typescript
1280
+ import { CustomActionCellActionResolver } from '@wix/auto-patterns';
1281
+ import { Download } from '@wix/wix-ui-icons-common';
1282
+ import React from 'react';
1283
+
1284
+ // IMPORTANT: Function name MUST match the action id in your configuration
1285
+ export const downloadPetDetails: CustomActionCellActionResolver = (params) => {
1286
+ const { actionParams, sdk } = params;
1287
+ const { item } = actionParams;
1288
+
1289
+ return {
1290
+ label: 'Download Details',
1291
+ icon: <Download />,
1292
+ onClick: () => {
1293
+ // sdk is provided to custom action resolvers (see SDK Utilities section)
1294
+ const optimisticActions = sdk.getOptimisticActions(sdk.collectionId);
1295
+ const schema = sdk.getSchema(sdk.collectionId);
1296
+
1297
+ // Example: Mark pet as downloaded
1298
+ const updatedItem = { ...item, lastDownloaded: new Date() };
1299
+ optimisticActions.updateOne(updatedItem, {
1300
+ submit: async (items) => {
1301
+ // Your download logic here + update server
1302
+ return await schema.actions.update(items[0]);
1303
+ },
1304
+ successToast: 'Pet details downloaded',
1305
+ errorToast: (err, {retry}) => ({
1306
+ text: 'Download failed',
1307
+ action: { text: 'Retry', onClick: retry }
1308
+ })
1309
+ });
1310
+ },
1311
+ };
1312
+ };
1313
+ ```
1314
+
1315
+ 3. Export your action in `actions/index.tsx`:
1316
+ ```typescript
1317
+ export * from './downloadPetDetails';
1318
+ ```
1319
+
1320
+ **Important:** Every time you create a new action, you must add a corresponding export line to this `index.tsx` file. For example, if you create `sendEmail.tsx`, you must add `export * from './sendEmail';` to the index file.
1321
+
1322
+ 4. Configure the action in your JSON configuration:
1323
+ ```ts
1324
+ {
1325
+ "id": "downloadPetDetails", // MUST match the function name exactly
1326
+ "type": "custom", // REQUIRED: Must be exactly "custom"
1327
+ "label": "Download Details", // Optional: Displayed text
1328
+ }
1329
+ ```
1330
+
1331
+ 5. Register your action in the `PatternsWizardOverridesProvider`:
1332
+ ```typescript
1333
+ import * as actions from './components/actions';
1334
+
1335
+ <PatternsWizardOverridesProvider value={{ actions }}>
1336
+ <AutoPatternsApp configuration={config as AppConfig} />
1337
+ </PatternsWizardOverridesProvider>
1338
+ ```
1339
+
1340
+ ### Key Points for Custom Actions:
1341
+ - The action `id` in the configuration MUST exactly match the function name exported from your actions folder
1342
+ - The function name and file name should follow a consistent naming convention (e.g., camelCase)
1343
+ - The implementation must be exported as a named export (not default export)
1344
+ - The implementation must use the `CustomActionCellActionResolver` type
1345
+
1346
+ #### Validation Rules for Custom Actions:
1347
+
1348
+ 1. `id` must:
1349
+ - Match exactly the function name of the custom action implementation
1350
+ - Be registered in the `actions` property of your `PatternsWizardOverridesProvider`
1351
+ - Follow JavaScript identifier naming rules (camelCase recommended)
1352
+
1353
+ 2. The implementation must return an object with:
1354
+ - `label`: Text displayed for the action
1355
+ - `icon`: An Icon component from "@wix/wix-ui-icons-common"
1356
+ - `onClick`: Handler function for the action
1357
+
1358
+ 3. The implementation must:
1359
+ - Use the correct type: `CustomActionCellActionResolver`
1360
+ - Be exported as a named export
1361
+ - Have a filename matching the function name
1362
+
1363
+ ### Key Implementation Decisions
1364
+
1365
+ Follow this decision process when implementing ActionCell:
1366
+
1367
+ 1. **Basic Decision**: Decide which actions users need to perform on entities:
1368
+ - Edit entities? → Use `update` actions
1369
+ - Delete entities? → Use `delete` actions
1370
+ - Custom operations? → Use `custom` actions
1371
+
1372
+ 2. **Primary vs Secondary**: Choose the most common/important action as primary:
1373
+ - Most common operation (typically Edit) → Place in `primaryAction.item`
1374
+ - Less common operations → Place in `secondaryActions.items` array
1375
+
1376
+ 3. **Inline Secondary Actions Strategy**:
1377
+ - **Action Prioritization**: Order `secondaryActions.items` by frequency of use (most used first)
1378
+ - **Inline Count**: Use `inlineCount: 1-3` for optimal UX (avoid cluttering)
1379
+ - **Visibility Control**:
1380
+ - Use `inlineAlwaysVisible: false` (default) for cleaner visual appearance
1381
+ - Use `inlineAlwaysVisible: true` only for critical actions requiring constant visibility
1382
+
1383
+ 4. **Update Action Mode**:
1384
+ - Complex, full-entity edits → Use `mode: "page"` to navigate to entity page
1385
+
1386
+ 5. **Custom Implementation**:
1387
+ - For `custom` actions, you must provide implementations in your code and register them with `PatternsWizardOverridesProvider`
1388
+
1389
+ ### ActionCell Validation Checklist
1390
+
1391
+ AI agents should verify these requirements before generating ActionCell configurations:
1392
+
1393
+ ✓ ActionCell is placed directly inside `table` or `grid` configuration
1394
+ ✓ Each action has a unique `id` and correct `type` value
1395
+ ✓ Each action type only includes its required field(s)
1396
+ ✓ Update page action refers to a valid entity page ID
1397
+ ✓ Delete action has a modal configuration
1398
+ ✓ Custom actions match implementations in overrides
1399
+ ✓ At least one of `primaryAction` or `secondaryActions` is provided
1400
+ ✓ `inlineCount` (if specified) is a non-negative number ≤ total secondary actions count
1401
+ ✓ `inlineAlwaysVisible` (if specified) is a boolean value
1402
+ ✓ Inline secondary actions configuration is applied only when secondary actions exist
1403
+
1404
+ ---
1405
+
1406
+ ## Bulk Action Toolbar Configuration
1407
+
1408
+ The Bulk Action Toolbar feature enables users to perform operations on multiple selected entities simultaneously in collection tables or grids. When configured, it adds checkboxes to each row and displays a toolbar with bulk actions when items are selected.
1409
+
1410
+ ### Placement and Structure
1411
+
1412
+ The Bulk Action Toolbar is configured within the table / grid / table-grid switch configuration using the `bulkActionToolbar` property. It has a two-level structure:
1413
+ * `primaryActions`: Actions shown directly in the bulk action toolbar
1414
+ * `secondaryActions`: Additional actions organized in sections, typically shown in a dropdown menu
1415
+
1416
+ Both properties are optional, but at least one should be provided for the bulk action toolbar to be functional.
1417
+
1418
+ ### Bulk Action Types Reference
1419
+
1420
+ 1. **Bulk Delete Action** (`type: "bulkDelete"`):
1421
+ - ✓ Use when: Removing multiple entities with confirmation
1422
+ - ✓ Common scenarios:
1423
+ - Mass deletion of records
1424
+ - Bulk cleanup operations
1425
+ - ✓ Built-in functionality: No custom implementation needed
1426
+
1427
+ 2. **Custom Action** (`type: "custom"`):
1428
+ - ✓ Use when: Executing custom JavaScript for bulk operations
1429
+ - ✓ Common scenarios:
1430
+ - Bulk API calls
1431
+ - Bulk exports/downloads
1432
+ - Complex bulk operations without UI
1433
+ - ⚠️ Requires implementation: Must register action in overrides
1434
+
1435
+ ### Type Selection Decision Tree
1436
+
1437
+ When choosing a bulk action type, follow this decision process:
1438
+
1439
+ 1. IF removing multiple entities:
1440
+ → Use `type: "bulkDelete"`
1441
+
1442
+ 2. IF executing custom logic for bulk operations without UI:
1443
+ → Use `type: "custom"`
1444
+ - MUST implement action handler
1445
+ - MUST register with `actions` override
1446
+
1447
+ ### Bulk Delete Action Configuration
1448
+
1449
+ Bulk delete actions remove multiple entities with a confirmation modal.
1450
+
1451
+ #### Validation Rules:
1452
+
1453
+ 1. `bulkDelete.mode` must be `"modal"` (currently only modal is supported)
1454
+ 2. `bulkDelete.modal` object must exist
1455
+ 3. The modal properties (title, description, actions, feedback) are all optional
1456
+
1457
+ ### Custom Bulk Action Configuration
1458
+
1459
+ Custom bulk actions execute JavaScript code that you define for bulk operations. These actions receive parameters that give them access to selected entities data and utilities. Here's how to implement a custom bulk action:
1460
+
1461
+ 1. First, create the actions folder structure in your page folder:
1462
+ ```
1463
+ your-page/
1464
+ ├── page.tsx
1465
+ └── components/
1466
+ └── actions/
1467
+ ├── index.tsx // Exports all actions
1468
+ └── bulkExportPets.tsx // Your custom bulk action
1469
+ ```
1470
+
1471
+ 2. Create your bulk action handler in `bulkExportPets.tsx`:
1472
+ ```typescript
1473
+ import { CustomBulkActionsActionResolver } from '@wix/auto-patterns';
1474
+ import { Download } from '@wix/wix-ui-icons-common';
1475
+ import React from 'react';
1476
+
1477
+ // IMPORTANT: Function name MUST match the action id in your configuration
1478
+ export const bulkExportPets: CustomBulkActionsActionResolver = (params) => {
1479
+ const { actionParams, sdk } = params;
1480
+ const { selectedValues, total } = actionParams;
1481
+
1482
+ return {
1483
+ label: 'Export Selected',
1484
+ icon: <Download />,
1485
+ onClick: () => {
1486
+ // sdk is provided to custom action resolvers (see SDK Utilities section)
1487
+ const optimisticActions = sdk.getOptimisticActions(sdk.collectionId);
1488
+ const schema = sdk.getSchema(sdk.collectionId);
1489
+
1490
+ // Example: Mark pets as exported
1491
+ const updatedItems = selectedValues.map(item => ({
1492
+ ...item,
1493
+ lastExported: new Date()
1494
+ }));
1495
+ optimisticActions.updateMany(updatedItems, {
1496
+ submit: async (items) => {
1497
+ // Your export logic here + update server
1498
+ const exportData = items.map(pet => ({
1499
+ name: pet.name,
1500
+ age: pet.age,
1501
+ owner: pet.owner
1502
+ }));
1503
+
1504
+ // Create and download CSV
1505
+ const csv = exportData.map(row => Object.values(row).join(',')).join('\n');
1506
+ const blob = new Blob([csv], { type: 'text/csv' });
1507
+ const url = URL.createObjectURL(blob);
1508
+ const a = document.createElement('a');
1509
+ a.href = url;
1510
+ a.download = 'pets-export.csv';
1511
+ a.click();
1512
+
1513
+ // Update server with export timestamp
1514
+ return await schema.actions.update(items);
1515
+ },
1516
+ successToast: `${selectedValues.length} pets exported`,
1517
+ errorToast: (err, {retry}) => ({
1518
+ text: 'Export failed',
1519
+ action: { text: 'Retry', onClick: retry }
1520
+ })
1521
+ });
1522
+ },
1523
+ };
1524
+ };
1525
+ ```
1526
+
1527
+ 3. Export your action in `actions/index.tsx`:
1528
+ ```typescript
1529
+ export * from './bulkExportPets';
1530
+ ```
1531
+
1532
+ 4. Configure the action in your JSON configuration:
1533
+ ```json
1534
+ {
1535
+ "id": "bulkExportPets", // MUST match the function name exactly
1536
+ "type": "custom", // REQUIRED: Must be exactly "custom"
1537
+ "label": "Export Selected", // Optional: Displayed text
1538
+ }
1539
+ ```
1540
+
1541
+ 5. Register your action in the `PatternsWizardOverridesProvider`:
1542
+ ```typescript
1543
+ import * as actions from './components/actions';
1544
+
1545
+ <PatternsWizardOverridesProvider value={{ actions }}>
1546
+ <AutoPatternsApp configuration={config as AppConfig} />
1547
+ </PatternsWizardOverridesProvider>
1548
+ ```
1549
+
1550
+ ### Key Points for Custom Bulk Actions:
1551
+ - The action `id` in the configuration MUST exactly match the function name exported from your actions folder
1552
+ - The function name and file name should follow a consistent naming convention (e.g., camelCase)
1553
+ - The implementation must be exported as a named export (not default export)
1554
+ - The implementation must use the `CustomBulkActionsActionResolver` type
1555
+ - Access selected entities through `actionParams.selectedValues`
1556
+ - Access total count through `actionParams.total`
1557
+
1558
+ #### Validation Rules for Custom Bulk Actions:
1559
+
1560
+ 1. `id` must:
1561
+ - Match exactly the function name of the custom bulk action implementation
1562
+ - Be registered in the `actions` property of your `PatternsWizardOverridesProvider`
1563
+ - Follow JavaScript identifier naming rules (camelCase recommended)
1564
+
1565
+ 2. The implementation must return an object with:
1566
+ - `label`: Text displayed for the action
1567
+ - `icon`: An Icon component from "@wix/wix-ui-icons-common"
1568
+ - `onClick`: Handler function for the bulk action
1569
+
1570
+ 3. The implementation must:
1571
+ - Use the correct type: `CustomBulkActionsActionResolver`
1572
+ - Be exported as a named export
1573
+ - Have a filename matching the function name
1574
+
1575
+ ### Bulk Action Toolbar Structure
1576
+
1577
+ The bulk action toolbar uses a specific structure for organizing actions:
1578
+
1579
+ #### Primary Actions Structure:
1580
+ ```json
1581
+ "bulkActionToolbar": {
1582
+ "primaryActions": [
1583
+ {
1584
+ "type": "action",
1585
+ "action": {
1586
+ "item": {
1587
+ "id": "bulkCustom",
1588
+ "type": "custom",
1589
+ "label": "Custom Bulk",
1590
+ "custom": {
1591
+ "id": "MyCustomBulk"
1592
+ }
1593
+ }
1594
+ }
1595
+ },
1596
+ {
1597
+ "type": "menu",
1598
+ "menu": {
1599
+ "label": "More actions",
1600
+ "items": [
1601
+ {
1602
+ "id": "exportItems",
1603
+ "type": "custom",
1604
+ "label": "Export Items"
1605
+ },
1606
+ { "type": "divider" },
1607
+ {
1608
+ "id": "downloadItems",
1609
+ "type": "custom",
1610
+ "label": "Download Items"
1611
+ }
1612
+ ]
1613
+ }
1614
+ }
1615
+ ]
1616
+ }
1617
+ ```
1618
+
1619
+ #### Secondary Actions Structure:
1620
+ ```json
1621
+ "bulkActionToolbar": {
1622
+ "secondaryActions": [
1623
+ {
1624
+ "id": "bulkDeleteWithModal",
1625
+ "label": "Bulk Delete",
1626
+ "type": "bulkDelete",
1627
+ "bulkDelete": {
1628
+ "mode": "modal",
1629
+ "modal": {
1630
+ "title": { "text": "Delete items" },
1631
+ "description": { "text": "Are you sure?" }
1632
+ }
1633
+ }
1634
+ },
1635
+ {
1636
+ "id": "bulkExportPets",
1637
+ "type": "custom",
1638
+ "label": "Export Selected"
1639
+ }
1640
+ ]
1641
+ }
1642
+ ```
1643
+
1644
+ ### Key Implementation Decisions
1645
+
1646
+ Follow this decision process when implementing Bulk Action Toolbar:
1647
+
1648
+ 1. **Basic Decision**: Decide which bulk operations users need to perform:
1649
+ - Delete multiple entities? → Use `bulkDelete` actions
1650
+ - Custom bulk operations? → Use `custom` actions
1651
+
1652
+ 2. **Primary vs Secondary**: Choose the most common/important bulk action as primary:
1653
+ - Most common bulk operation → Place in `primaryActions.items` array
1654
+ - Less common bulk operations → Place in `secondaryActions` array
1655
+
1656
+ 3. **Custom Implementation**:
1657
+ - For `custom` bulk actions, you must provide implementations in your code and register them with `PatternsWizardOverridesProvider`
1658
+
1659
+ ### Bulk Action Toolbar Validation Checklist
1660
+
1661
+ AI agents should verify these requirements before generating Bulk Action Toolbar configurations:
1662
+
1663
+ ✓ Bulk Action Toolbar is placed directly inside `table` or `grid` configuration as `bulkActionToolbar`
1664
+ ✓ Each bulk action has a unique `id` and correct `type` value
1665
+ ✓ Each action type only includes its required field(s)
1666
+ ✓ Bulk delete actions have modal configuration
1667
+ ✓ Custom bulk actions match implementations in overrides
1668
+ ✓ At least one of `primaryActions` or `secondaryActions` is provided
1669
+ ✓ Primary actions use `action`/`menu` structure with proper `action` or `menu` properties
1670
+ ✓ Secondary actions are an array that can include dividers
1671
+ ✓ Menu items within primary actions is array that can include dividers
1672
+
1673
+ ---
1674
+
1675
+ # Entity Page Configuration
1676
+
1677
+ ## ⚠️ Entity Page Requirements
1678
+
1679
+ All entity pages must have:
1680
+ - **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
1681
+ - **A matching `route.params` configuration** that maps the dynamic parameter
1682
+ - **A reference to their parent collection page via `parentPageId`**
1683
+
1684
+ ## Overview
1685
+
1686
+ * Displays details for a **single entity**.
1687
+ * Always tied to a single Wix collection.
1688
+ * `entityTypeSource` is always `'cms'`.
1689
+
1690
+ > The custom actions must be defined inside the `moreActions` array.
1691
+
1692
+ > 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.
1693
+
1694
+ ## Entity Page Layout Configuration
1695
+
1696
+ ### Grid System
1697
+
1698
+ - **12-Column Grid**: The layout uses a 12-column grid system.
1699
+ - The `span` property controls how many columns an item occupies (1-12).
1700
+ - When items in a row exceed 12 columns total, the next item wraps to a new line.
1701
+ - Example: If an item has `span: 8` and the next has `span: 5`, the second item will start a new line.
1702
+
1703
+ ### Layout Structure
1704
+
1705
+ - **Main Section**: Contains primary entity information and most important fields.
1706
+ - **Sidebar Section**: Contains secondary information, metadata, or supporting content.
1707
+ - Both sections support cards that can contain fields, containers, and components.
1708
+
1709
+ ### Detailed Layout Content Types
1710
+
1711
+ 1. **Field Type**:
1712
+ ```typescript
1713
+ {
1714
+ type: 'field';
1715
+ field: {
1716
+ span?: number; // How many columns this field occupies (1-12)
1717
+ fieldId: string; // Must match a valid field ID from the collection schema
1718
+ };
1719
+ }
1720
+ ```
1721
+
1722
+ 2. **Container Type** (for grouping related fields):
1723
+ ```typescript
1724
+ {
1725
+ type: 'container';
1726
+ container: {
1727
+ span?: number; // How many columns this container occupies (1-12)
1728
+ children: LayoutContent[]; // Can nest fields, other containers, or components
1729
+ };
1730
+ }
1731
+ ```
1732
+
1733
+ 3. **Component Type** (for custom rendering):
1734
+ ```typescript
1735
+ {
1736
+ type: 'component';
1737
+ component: {
1738
+ span?: number; // How many columns this component occupies (1-12)
1739
+ componentId: string; // ID matching a component override implementation
1740
+ };
1741
+ }
1742
+ ```
1743
+
1744
+ ### Layout Best Practices
1745
+
1746
+ 1. **Field Grouping**:
1747
+ - Group related fields using containers
1748
+ - Place frequently used fields at the top
1749
+ - Consider the natural flow of data entry
1750
+
1751
+ 2. **Main vs. Sidebar Usage**:
1752
+ - Main section: Put primary entity information
1753
+ - Sidebar: Place secondary information and metadata
1754
+
1755
+ 3. **Responsive Considerations**:
1756
+ - Use appropriate spans for different field types
1757
+ - Text fields often benefit from larger spans
1758
+ - Boolean fields can use smaller spans
1759
+
1760
+ 4. **Nested Containers**:
1761
+ - Use containers to create logical groupings
1762
+ - Don't nest containers too deeply for clarity
1763
+ - Consider using cards for major sections instead of deeply nested containers
1764
+
1765
+ 5. **Image Handling**:
1766
+ - For image fields, consider providing more space (larger span)
1767
+ - Images are automatically rendered with proper controls when using the field type
1768
+
1769
+ ## ⚠️ Common Entity Page Layout Mistakes to Avoid
1770
+
1771
+ - Using incorrect span values causing unexpected layout breaks
1772
+ - Referencing non-existent field IDs in the layout
1773
+ - Creating overly complex nested container structures
1774
+ - Failing to properly register component overrides
1775
+ - Confusing main and sidebar section usage (putting main content in sidebar)
1776
+ - Exceeding 12 total columns in a row without realizing content will wrap
1777
+ - Forgetting to specify the `collectionPagePath` value
1778
+ - Missing required `type: 'card'` structure in layout sections
1779
+
1780
+ ---
1781
+
1782
+ ## Entity Page Actions: `moreActions` Support
1783
+
1784
+ 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.
1785
+
1786
+ > **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.
1787
+
1788
+ ### Configuration Structure
1789
+
1790
+ - The `moreActions` property on the entity page is an **array** of action configurations that can include divider objects for visual separation.
1791
+ - Each action in `moreActions` is a Custom Action (type: "custom") or a Divider (type: "divider")
1792
+
1793
+ #### Example: Adding custom actions with dividers to an entity page
1794
+ ```json
1795
+ {
1796
+ "type": "entityPage",
1797
+ "entityPage": {
1798
+ // ... other config ...
1799
+ "moreActions": [
1800
+ {
1801
+ "id": "sendEmail",
1802
+ "type": "custom",
1803
+ "label": "Send Email"
1804
+ },
1805
+ {
1806
+ "id": "exportData",
1807
+ "type": "custom",
1808
+ "label": "Export Data"
1809
+ },
1810
+ { "type": "divider" },
1811
+ {
1812
+ "id": "archiveEntity",
1813
+ "type": "custom",
1814
+ "label": "Archive"
1815
+ }
1816
+ ]
1817
+ }
1818
+ }
1819
+ ```
1820
+
1821
+ ---
1822
+
1823
+ ### CustomEntityPageMoreActionsActionResolver
1824
+
1825
+ 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.
1826
+
1827
+ #### Function Signature
1828
+
1829
+ ```typescript
1830
+ import { CustomEntityPageMoreActionsActionResolver } from '@wix/auto-patterns/types';
1831
+
1832
+ export const myMoreAction: CustomEntityPageMoreActionsActionResolver = (params) => {
1833
+ const { actionParams: { entity, form } , sdk } = params;
1834
+
1835
+ return {
1836
+ label: 'My More Action',
1837
+ icon: <MyIcon />, // optional
1838
+ onClick: () => {
1839
+ // Your custom logic here
1840
+ },
1841
+ };
1842
+ };
1843
+ ```
1844
+
1845
+ - **entity**: The current entity data (all field values). In actionParams.
1846
+ - **form**: The react-hook-form instance for the entity page. In actionParams.
1847
+ - **sdk**: The AutoPatterns SDK (see SDK Utilities section).
1848
+
1849
+ ---
1850
+
1851
+ #### Key Points for CustomEntityPageMoreActionsActionResolver
1852
+
1853
+ - The action `id` in the configuration MUST exactly match the function name exported from your actions folder.
1854
+ - The implementation must use the `CustomEntityPageMoreActionsActionResolver` type.
1855
+ - The implementation must be exported as a named export (not default export).
1856
+ - The function receives `{ actionParams, sdk }` as parameters.
1857
+ - The returned object must include at least a `label` and an `onClick` handler (optionally an `icon`).
1858
+
1859
+ ---
1860
+
1861
+ #### Validation Checklist for More Actions
1862
+
1863
+ ✓ Each action in `moreActions` has a unique `id` and correct `type` value
1864
+ ✓ Each action type only includes its required field(s)
1865
+ ✓ Custom actions match implementations in overrides
1866
+ ✓ The resolver is exported and registered in the `actions` property of your `PatternsWizardOverridesProvider`
1867
+ ✓ The function signature matches `CustomEntityPageMoreActionsActionResolver`
1868
+ ✓ The returned object includes `label`, `onClick`, and optionally `icon`
1869
+
1870
+ ---
1871
+
1872
+ **Summary:**
1873
+ 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.
1874
+
1875
+ ---
1876
+
1877
+ # Installation & Setup
1878
+
1879
+ ## 1. Install Packages
1880
+
1881
+ Install if necessary and doesn't exists in package.json:
1882
+
1883
+ ```bash
1884
+ npm install @wix/auto-patterns @wix/patterns @wix/design-system
1885
+ ```
1886
+
1887
+ ## ⚠️ Critical Import Rules
1888
+
1889
+ - **Import `AutoPatternsApp` only from `@wix/auto-patterns`** - never from other packages
1890
+ - **CRITICAL:** Always import `AppConfig` as a type import: `import type { AppConfig } from '@wix/auto-patterns/types'` - never import it as a value import
1891
+
1892
+ ## 2. Create AppConfig JSON
1893
+
1894
+ Save this configuration as a `{collectionName}Config.patterns.json` file in the same directory as your page.tsx component.
1895
+
1896
+ For example:
1897
+ - For a "WixPets" collection: `petsConfig.patterns.json`
1898
+ - For a "Products" collection: `productsConfig.patterns.json`
1899
+ - For a "Users" collection: `usersConfig.patterns.json`
1900
+
1901
+ ## Render the Collection Page Component
1902
+
1903
+ Inside your page component, import the JSON configuration and use the `AutoPatternsApp` component. Since this is a page-level component, it should be the only component rendered on the page. Any other content or components should be removed to ensure proper functionality and avoid conflicts.
1904
+
1905
+ ### Page Component Example:
1906
+
1907
+ ```tsx
1908
+ import React, { type FC } from 'react';
1909
+ import { WixDesignSystemProvider } from '@wix/design-system';
1910
+ import '@wix/design-system/styles.global.css';
1911
+ import { WixPatternsProvider } from '@wix/patterns/provider';
1912
+ import { PatternsWizardOverridesProvider, AutoPatternsApp } from '@wix/auto-patterns';
1913
+ import type { AppConfig } from '@wix/auto-patterns/types';
1914
+ import { withDashboard } from '@wix/patterns';
1915
+
1916
+ import config from './MyCollectionConfig.patterns.json';
1917
+
1918
+ const Index: FC = () => {
1919
+ return (
1920
+ <WixDesignSystemProvider features={{ newColorsBranding: true }}>
1921
+ <WixPatternsProvider>
1922
+ <PatternsWizardOverridesProvider value={{ }}>
1923
+ <AutoPatternsApp configuration={config as AppConfig} />
1924
+ </PatternsWizardOverridesProvider>
1925
+ </WixPatternsProvider>
1926
+ </WixDesignSystemProvider>
1927
+ );
1928
+ };
1929
+
1930
+ export default withDashboard(Index);
1931
+ ```
1932
+
1933
+ ---
1934
+
1935
+ # Custom Overrides
1936
+
1937
+ ## ⚠️ Override Rules
1938
+
1939
+ - **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
1940
+ - **Always verify override implementation** - when implementing custom overrides, you MUST ensure they are correctly imported and passed to the `PatternsWizardOverridesProvider`
1941
+
1942
+ 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:
1943
+
1944
+ > **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.
1945
+
1946
+ ## Folder Structure Organization
1947
+
1948
+ 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.
1949
+
1950
+ ### Recommended Structure:
1951
+
1952
+ ```
1953
+ your-page/
1954
+ ├── page.tsx // Your main page component
1955
+ ├── MyCollectionConfig.patterns.json // Configuration file
1956
+ └── components/ // Page-specific components folder
1957
+ ├── index.tsx // Exports all overrides for easy importing
1958
+ ├── actions/ // Custom actions
1959
+ │ ├── index.tsx
1960
+ │ └── myCustomAction.tsx
1961
+ ├── columns/ // Column overrides
1962
+ │ ├── index.tsx
1963
+ │ ├── name.ts
1964
+ │ └── date.ts
1965
+ └── customComponents/ // Custom entity page components
1966
+ ├── index.tsx
1967
+ ├── CustomNameField.tsx
1968
+ └── InfoCard.tsx
1969
+ ```
1970
+
1971
+ ### Importing Overrides in Your Page
1972
+
1973
+ In your page component, import from the local components folder:
1974
+
1975
+ ```tsx
1976
+ import * as modals from './components/modals';
1977
+ import * as actions from './components/actions';
1978
+ import * as columns from './components/columns';
1979
+ import * as components from './components/customComponents';
1980
+
1981
+ <PatternsWizardOverridesProvider value={{ modals, actions, columns, components }}>
1982
+ <AutoPatternsApp configuration={config as AppConfig} />
1983
+ </PatternsWizardOverridesProvider>
1984
+ ```
1985
+
1986
+ ### Important: Updating Index Files
1987
+
1988
+ **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.
1989
+
1990
+ For example:
1991
+ - Adding a new action → Update `./components/actions/index.tsx`
1992
+ - Adding a new modal → Update `./components/modals/index.tsx`
1993
+ - Adding a new column override → Update `./components/columns/index.tsx`
1994
+ - Adding a new custom component → Update `./components/customComponents/index.tsx`
1995
+
1996
+ Without updating the index files, your implementations won't be available to the `PatternsWizardOverridesProvider`.
1997
+
1998
+ ## ⚠️ Common Override Mistakes to Avoid
1999
+
2000
+ - Attempting to override unsupported areas
2001
+ - Invalid column rendering functions
2002
+ - Missing index file exports for new implementations
2003
+ - Incorrect import paths or naming mismatches
2004
+
2005
+ ## Columns
2006
+
2007
+ 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.
2008
+
2009
+ **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.
2010
+
2011
+ ### Function Signature
2012
+
2013
+ ```typescript
2014
+ function columnOverride({ value, row }) {
2015
+ // value: The individual column value
2016
+ // row: The entire row object containing all field values
2017
+ return <YourCustomRendering />;
2018
+ }
2019
+ ```
2020
+
2021
+ ### Understanding Row Data
2022
+
2023
+ **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.
2024
+
2025
+ For example, if your collection schema has these fields:
2026
+ ```json
2027
+ {
2028
+ "fields": [
2029
+ { "key": "name", "displayName": "Pet Name", "type": "TEXT" },
2030
+ { "key": "age", "displayName": "Age", "type": "NUMBER" },
2031
+ { "key": "isVaccinated", "displayName": "Vaccinated", "type": "BOOLEAN" },
2032
+ { "key": "lastActivity", "displayName": "Last Activity", "type": "DATETIME" }
2033
+ ]
2034
+ }
2035
+ ```
2036
+
2037
+ Then in your column override, you access these values using the field IDs:
2038
+ ```typescript
2039
+ export function myColumn({ value, row }) {
2040
+ // Access field values using their schema field IDs
2041
+ const petName = row.name; // "name" field ID
2042
+ const petAge = row.age; // "age" field ID
2043
+ const isVaccinated = row.isVaccinated; // "isVaccinated" field ID
2044
+ const lastActivity = row.lastActivity; // "lastActivity" field ID
2045
+
2046
+ return <YourCustomRendering />;
2047
+ }
2048
+ ```
2049
+
2050
+ ### Use Cases for Row Data Access
2051
+
2052
+ 1. **Complex Display Columns**: Combine multiple fields into a single display (e.g., "Name (Age)" combining name and age fields)
2053
+ 2. **Conditional Rendering**: Show different content based on other field values in the same row
2054
+ 3. **Calculated Columns**: Create computed values using multiple row fields
2055
+ 4. **Cross-Field Validation Display**: Show validation status based on relationships between fields
2056
+
2057
+ ### Example: Defining and Using Column Overrides
2058
+
2059
+ In `components/columns/name.tsx`:
2060
+
2061
+ ```ts
2062
+ import React from 'react';
2063
+
2064
+ export function name({ value, row }) {
2065
+ // Simple value formatting
2066
+ return <strong>{value}</strong>;
2067
+ }
2068
+ ```
2069
+
2070
+ In `components/columns/petInfo.tsx`:
2071
+
2072
+ ```ts
2073
+ import React from 'react';
2074
+ import { Box, Text } from '@wix/design-system';
2075
+
2076
+ export function petInfo({ value, row }) {
2077
+ // Complex column combining multiple row values
2078
+ return (
2079
+ <Box direction="vertical" gap={1}>
2080
+ <Text weight="bold">{row.name}</Text>
2081
+ <Text size="small" skin="disabled">
2082
+ {row.age} years old • {row.type}
2083
+ </Text>
2084
+ {row.isVaccinated && (
2085
+ <Text size="tiny" skin="success">✓ Vaccinated</Text>
2086
+ )}
2087
+ </Box>
2088
+ );
2089
+ }
2090
+ ```
2091
+
2092
+ In `components/columns/status.tsx`:
2093
+
2094
+ ```ts
2095
+ import React from 'react';
2096
+ import { Badge } from '@wix/design-system';
2097
+
2098
+ export function status({ value, row }) {
2099
+ // Conditional rendering based on multiple row fields
2100
+ if (row.isVaccinated && row.age > 1) {
2101
+ return <Badge skin="success">Ready for Adoption</Badge>;
2102
+ } else if (!row.isVaccinated) {
2103
+ return <Badge skin="warning">Needs Vaccination</Badge>;
2104
+ } else {
2105
+ return <Badge skin="neutral">Too Young</Badge>;
2106
+ }
2107
+ }
2108
+ ```
2109
+
2110
+ In `components/columns/fullName.tsx`:
2111
+
2112
+ ```ts
2113
+ import React from 'react';
2114
+
2115
+ export function fullName({ value, row }) {
2116
+ // Calculated column using multiple fields
2117
+ return `${row.name} (owned by ${row.owner})`;
2118
+ }
2119
+ ```
2120
+
2121
+ In `components/columns/date.tsx`:
2122
+
2123
+ ```ts
2124
+ import React from 'react';
2125
+
2126
+ export function date({ value, row }) {
2127
+ // Access to other row data for enhanced date formatting
2128
+ const isRecent = row.lastActivity && new Date(row.lastActivity) > new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
2129
+
2130
+ return (
2131
+ <span style={{ color: isRecent ? 'green' : 'inherit' }}>
2132
+ <em>{new Date(value).toLocaleDateString()}</em>
2133
+ {isRecent && ' (Recent)'}
2134
+ </span>
2135
+ );
2136
+ }
2137
+ ```
2138
+
2139
+ In `components/columns/index.tsx`:
2140
+
2141
+ ```ts
2142
+ export * from './name';
2143
+ export * from './petInfo';
2144
+ export * from './status';
2145
+ export * from './fullName';
2146
+ export * from './date';
2147
+ ```
2148
+
2149
+ **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.
2150
+
2151
+ In the `PatternsWizardOverridesProvider`:
2152
+
2153
+ ```tsx
2154
+ import * as columns from './components/columns';
2155
+
2156
+ <PatternsWizardOverridesProvider value={{ columns }}>
2157
+ <AutoPatternsApp configuration={config as AppConfig} />
2158
+ </PatternsWizardOverridesProvider>
2159
+ ```
2160
+
2161
+ ### Visual Representation
2162
+
2163
+ ```
2164
+ your-page/
2165
+ └── components/
2166
+ └── columns/
2167
+ ├── index.tsx // Exports all column overrides
2168
+ ├── name.tsx // Simple value formatting
2169
+ ├── petInfo.tsx // Complex multi-field column
2170
+ ├── status.tsx // Conditional rendering column
2171
+ ├── fullName.tsx // Calculated column
2172
+ └── date.tsx // Enhanced formatting with row context
2173
+
2174
+ PatternsWizardOverridesProvider
2175
+ └── value.columns
2176
+ ├── name
2177
+ ├── petInfo
2178
+ ├── status
2179
+ ├── fullName
2180
+ └── date
2181
+ ```
2182
+
2183
+ ### Key Benefits of Row Data Access
2184
+
2185
+ 1. **Reduced Configuration Complexity**: Instead of adding multiple columns, create one complex column that shows related information
2186
+ 2. **Better User Experience**: Present related data together in a logical, readable format
2187
+ 3. **Dynamic Content**: Show different content based on the state of other fields
2188
+ 4. **Data Relationships**: Highlight relationships between different field values in the same entity
2189
+
2190
+ ### Important Guidelines
2191
+
2192
+ - **Performance**: Remember that column functions are called for every row, so keep calculations lightweight
2193
+ - **Consistency**: When using row data, ensure the column header accurately represents what's displayed
2194
+ - **Accessibility**: Maintain proper semantic structure when combining multiple values
2195
+
2196
+ ## Components
2197
+
2198
+ 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.
2199
+
2200
+ The custom components receive two essential props:
2201
+
2202
+ 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.
2203
+ 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.
2204
+
2205
+ Custom components can serve two main purposes:
2206
+
2207
+ ### 1. Standalone Custom Components
2208
+
2209
+ 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.
2210
+
2211
+ ### 2. Field Rendering Overrides
2212
+
2213
+ You can use custom components to override the default rendering of one or more fields. This allows you to:
2214
+ - Apply custom validation logic
2215
+ - Create custom input components
2216
+ - Combine multiple fields into a single UI component
2217
+ - Add field-specific functionality not available in the default renderers
2218
+
2219
+ ### Using the useController Hook for Field Overrides
2220
+
2221
+ 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:
2222
+
2223
+ ```tsx
2224
+ import { useController } from '@wix/auto-patterns/form'; // Always import from this path, not react-hook-form
2225
+ ```
2226
+
2227
+ The hook requires:
2228
+ - **name**: The field name you want to edit (should match the schema field ID)
2229
+ - **control**: Retrieved from `form.control`
2230
+ - **defaultValue**: Set from `entity?.[fieldId]` when it exists
2231
+
2232
+ ### Example: Defining a Custom Component
2233
+
2234
+ Here's an example of a custom component that overrides the rendering of the "name" field:
2235
+
2236
+ ```tsx
2237
+ import React, { FC } from 'react';
2238
+ import { Box, Card, FormField, Input, Text } from '@wix/design-system';
2239
+ import { useController } from '@wix/auto-patterns/form';
2240
+ import { CustomComponentProps } from '@wix/auto-patterns/types';
2241
+
2242
+ export const customNameField: FC<CustomComponentProps> = ({ form, entity }) => {
2243
+ // Create a controller for the name field
2244
+ const controller = useController({
2245
+ name: 'name', // Field ID from the schema
2246
+ control: form.control, // Form control
2247
+ defaultValue: entity?.name, // Default value from entity
2248
+ });
2249
+
2250
+ return (
2251
+ <FormField
2252
+ label="Name"
2253
+ required={true}
2254
+ charCount={100}
2255
+ // Connect field state to UI
2256
+ status={controller.fieldState.invalid ? 'error' : undefined}
2257
+ statusMessage={controller.fieldState.error?.message}
2258
+ dataHook={`short-text-${controller.field.name}`}
2259
+ >
2260
+ <Input
2261
+ // Connect field value and onChange
2262
+ value={controller.field.value}
2263
+ onChange={(e) => controller.field.onChange(e.target.value)}
2264
+ dataHook={`short-text-${controller.field.name}`}
2265
+ />
2266
+ </FormField>
2267
+ );
2268
+ };
2269
+ ```
2270
+
2271
+
2272
+ ### Example: Standalone Component (Not Field-Specific)
2273
+
2274
+ Custom components can also be used to add UI elements not tied to specific fields:
2275
+
2276
+ ```tsx
2277
+ import React, { FC } from 'react';
2278
+ import { Box, Card, Text, Button } from '@wix/design-system';
2279
+ import { CustomComponentProps } from '@wix/auto-patterns/types';
2280
+
2281
+ export const infoCard: FC<CustomComponentProps> = ({ entity }) => {
2282
+ return (
2283
+ <Card>
2284
+ <Card.Content>
2285
+ <Box direction="vertical" gap={2}>
2286
+ <Text weight="bold">Important Information</Text>
2287
+ <Text>
2288
+ This custom component can display additional information or functionality
2289
+ that isn't directly tied to a specific field.
2290
+ </Text>
2291
+ {entity?.isVaccinated ? (
2292
+ <Text skin="success">This pet is vaccinated</Text>
2293
+ ) : (
2294
+ <Text skin="warning">This pet needs vaccination</Text>
2295
+ )}
2296
+ </Box>
2297
+ </Card.Content>
2298
+ </Card>
2299
+ );
2300
+ };
2301
+ ```
2302
+
2303
+ ### Connecting Components in the Provider
2304
+
2305
+ In your main page file, import and provide these components via the `PatternsWizardOverridesProvider`:
2306
+
2307
+ ```tsx
2308
+ import * as components from './components';
2309
+
2310
+ <PatternsWizardOverridesProvider value={{ components }}>
2311
+ <AutoPatternsApp configuration={config as AppConfig} />
2312
+ </PatternsWizardOverridesProvider>
2313
+ ```
2314
+
2315
+ ### Important Guidelines for Custom Components
2316
+
2317
+ 1. **Always import from `@wix/auto-patterns/form`** instead of directly from `react-hook-form`
2318
+ 2. **Follow react-hook-form best practices** - the underlying infrastructure is built on react-hook-form
2319
+ 3. **Handle form state properly**:
2320
+ - Use `controller.fieldState.invalid` for error state
2321
+ - Use `controller.fieldState.error?.message` for error messages
2322
+ - Connect `controller.field.value` to input values
2323
+ - Use `controller.field.onChange` for change handlers
2324
+ 4. **Component rendering**:
2325
+ - Choose appropriate design-system components based on the field type
2326
+ - For text fields: `Input`
2327
+ - For multi-line text: `InputArea`
2328
+ - For checkboxes: `Checkbox`
2329
+ - For dates: `DatePicker`
2330
+ - For dropdowns: `Dropdown`
2331
+
2332
+ **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.
2333
+
2334
+ ### Understanding Reactivity in Custom Components
2335
+
2336
+ 5. **Reactivity and field value changes (IMPORTANT)**:
2337
+ - **NEVER rely on the `entity` object for reactive UI** - it is not reactive to form changes
2338
+ - For any reactive UI that needs to respond to field value changes in real-time:
2339
+ - Use `form.watch('fieldName')` to observe field changes reactively
2340
+ - Use `useController` hook when you need both read and write access to a field
2341
+
2342
+ #### Common Reactivity Issues and Solutions
2343
+
2344
+ ##### Example: Conditional Display Based on Field Value
2345
+
2346
+ ```tsx
2347
+ // ❌ INCORRECT APPROACH (Non-reactive)
2348
+ const CustomComponent: FC<CustomComponentProps> = ({ form, entity }) => {
2349
+ // This won't update when the user changes the name in the form
2350
+ const showSpecialMessage = entity?.name === 'special';
2351
+
2352
+ return (
2353
+ <Box>
2354
+ <Input
2355
+ value={form.getValues('name')}
2356
+ onChange={(e) => form.setValue('name', e.target.value)}
2357
+ />
2358
+
2359
+ {showSpecialMessage && (
2360
+ <Text>Special message for special name!</Text>
2361
+ )}
2362
+ </Box>
2363
+ );
2364
+ };
2365
+ ```
2366
+
2367
+ ```tsx
2368
+ // ✅ CORRECT APPROACH (Reactive)
2369
+ const CustomComponent: FC<CustomComponentProps> = ({ form, entity }) => {
2370
+ // This WILL update whenever the name field changes
2371
+ const nameValue = form.watch('name');
2372
+ const showSpecialMessage = nameValue === 'special';
2373
+
2374
+ return (
2375
+ <Box>
2376
+ <Input
2377
+ value={nameValue}
2378
+ onChange={(e) => form.setValue('name', e.target.value)}
2379
+ />
2380
+
2381
+ {showSpecialMessage && (
2382
+ <Text>Special message for special name!</Text>
2383
+ )}
2384
+ </Box>
2385
+ );
2386
+ };
2387
+ ```
2388
+
2389
+
2390
+ ##### When to Use the Entity Object
2391
+
2392
+ The `entity` object is useful for:
2393
+ - Setting initial values
2394
+ - Accessing read-only data that doesn't change
2395
+ - Comparing form state with original values (e.g., detecting if changes were made)
2396
+ - Initializing form fields with useController's defaultValue parameter
2397
+
2398
+ ```tsx
2399
+ // Example: Proper use of entity object with useController
2400
+ const CustomComponent: FC<CustomComponentProps> = ({ form, entity }) => {
2401
+ // Use entity for initialization via defaultValue
2402
+ const controller = useController({
2403
+ name: 'name', // Field ID from the schema
2404
+ control: form.control,
2405
+ defaultValue: entity?.name // Initialize from entity
2406
+ });
2407
+
2408
+ // Use watch for reactive updates
2409
+ const currentName = controller.field.value;
2410
+ const hasChanges = entity?.name !== currentName;
2411
+
2412
+ return (
2413
+ <Box>
2414
+ <FormField label="Name">
2415
+ <Input
2416
+ value={currentName}
2417
+ onChange={(e) => controller.field.onChange(e.target.value)}
2418
+ />
2419
+ </FormField>
2420
+ {hasChanges && (
2421
+ <Text size="small">Original value: {entity?.name}</Text>
2422
+ )}
2423
+ </Box>
2424
+ );
2425
+ };
2426
+ ```
2427
+
2428
+ ### Visual Representation
2429
+
2430
+ ```
2431
+ your-page/
2432
+ └── components/
2433
+ ├── index.tsx // Exports all component overrides
2434
+ ├── customNameField.tsx // Field override component
2435
+ ├── combinedNameFields.tsx // Multiple fields override
2436
+ └── infoCard.tsx // Standalone component
2437
+
2438
+ PatternsWizardOverridesProvider
2439
+ └── value.components
2440
+ ├── customNameField
2441
+ ├── combinedNameFields
2442
+ └── infoCard
2443
+ ```
2444
+
2445
+ 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.
2446
+
2447
+ ---