@wix/agent-skills 1.21.0 → 1.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/skills/wix-app/SKILL.md +60 -4
- package/skills/wix-app/references/DASHBOARD_PAGE.md +11 -25
- package/skills/wix-app/references/DATA_COLLECTION.md +16 -219
- package/skills/wix-app/references/dashboard-page/DATA_SOURCES.md +182 -0
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE.md +97 -0
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_COLLECTION.md +184 -0
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_ROUTER.md +203 -0
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_SETTINGS.md +44 -0
- package/skills/wix-app/references/dashboard-page/QUERY_AND_PAGING.md +182 -0
- package/skills/wix-app/references/dashboard-page/TABLE_STATE.md +133 -0
- package/skills/wix-app/references/dashboard-page/UX_SUCCESS_MODEL.md +10 -5
- package/skills/wix-app/references/data-collection/LIFECYCLE.md +68 -0
- package/skills/wix-app/references/data-collection/PERMISSIONS.md +47 -0
- package/skills/wix-app/references/data-collection/SCHEMA.md +181 -0
- package/skills/wix-app/references/data-collection/WIX_DATA.md +38 -66
- package/skills/wix-headless-fast/SKILL.md +61 -223
- package/skills/wix-headless-fast/cold-start/bootstrap.mjs +156 -0
- package/skills/wix-headless-fast/{entry/skill.md → cold-start/cold-start.md} +11 -12
- package/skills/wix-headless-fast/guides/existing-site.md +76 -0
- package/skills/wix-headless-fast/guides/reference-mode.md +97 -0
- package/skills/wix-headless-fast/install/AGENTS.md +6 -3
- package/skills/wix-headless-fast/install/attach.mjs +15 -47
- package/skills/wix-headless-fast/install/deploy.mjs +21 -60
- package/skills/wix-headless-fast/install/lock.mjs +55 -0
- package/skills/wix-headless-fast/install/setup.mjs +32 -12
- package/skills/wix-headless-fast/install/templates.mjs +168 -0
- package/skills/wix-manage/references/google-ads/google-ads-dashboard-navigation.md +27 -0
- package/skills/wix-manage/references/google-ads/manage-campaign-success-guide.md +83 -37
- package/skills/wix-headless-fast/references/blog/INSTRUCTIONS.md +0 -303
- package/skills/wix-headless-fast/references/blog/app/components/blog/BlogFeedView.tsx +0 -136
- package/skills/wix-headless-fast/references/blog/app/components/blog/PostView.tsx +0 -112
- package/skills/wix-headless-fast/references/blog/app/components/blog/RichContent.tsx +0 -42
- package/skills/wix-headless-fast/references/blog/app/hooks/blog/useBlogFeed.ts +0 -31
- package/skills/wix-headless-fast/references/blog/app/hooks/blog/usePost.ts +0 -22
- package/skills/wix-headless-fast/references/blog/app/wix/blog/blog-feed-store.ts +0 -137
- package/skills/wix-headless-fast/references/blog/app/wix/blog/post-store.ts +0 -78
- package/skills/wix-headless-fast/references/blog/app/wix/blog/posts-core.ts +0 -117
- package/skills/wix-headless-fast/references/blog/app/wix/blog/posts.ts +0 -52
- package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy-core.ts +0 -47
- package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy.ts +0 -58
- package/skills/wix-headless-fast/references/blog/app/wix/blog/types.ts +0 -62
- package/skills/wix-headless-fast/references/blog/app-astro/layouts/SiteLayout.astro +0 -40
- package/skills/wix-headless-fast/references/blog/app-astro/pages/blog/[...slug].astro +0 -97
- package/skills/wix-headless-fast/references/blog/app-astro/pages/blog.astro +0 -24
- package/skills/wix-headless-fast/references/blog/lock/astro/package-lock.json +0 -16156
- package/skills/wix-headless-fast/references/blog/rest/posts.ts +0 -42
- package/skills/wix-headless-fast/references/blog/rest/taxonomy.ts +0 -62
- package/skills/wix-headless-fast/references/blog/seed/SEED.md +0 -81
- package/skills/wix-headless-fast/references/blog/seed/read-site.mjs +0 -22
- package/skills/wix-headless-fast/references/blog/seed/seed-blog.mjs +0 -287
- package/skills/wix-headless-fast/references/bookings/INSTRUCTIONS.md +0 -277
- package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServiceBookingView.tsx +0 -144
- package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServicesView.tsx +0 -119
- package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useBookingFlow.ts +0 -32
- package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useServices.ts +0 -23
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking-core.ts +0 -218
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking-flow-store.ts +0 -169
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking.ts +0 -121
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services-core.ts +0 -92
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services-store.ts +0 -90
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services.ts +0 -57
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/types.ts +0 -72
- package/skills/wix-headless-fast/references/bookings/app-astro/layouts/SiteLayout.astro +0 -40
- package/skills/wix-headless-fast/references/bookings/app-astro/pages/services/[slug].astro +0 -76
- package/skills/wix-headless-fast/references/bookings/app-astro/pages/services.astro +0 -22
- package/skills/wix-headless-fast/references/bookings/lock/astro/package-lock.json +0 -11962
- package/skills/wix-headless-fast/references/bookings/rest/booking.ts +0 -113
- package/skills/wix-headless-fast/references/bookings/rest/services.ts +0 -55
- package/skills/wix-headless-fast/references/bookings/seed/SEED.md +0 -71
- package/skills/wix-headless-fast/references/bookings/seed/read-site.mjs +0 -28
- package/skills/wix-headless-fast/references/bookings/seed/seed-bookings.mjs +0 -302
- package/skills/wix-headless-fast/references/cms/INSTRUCTIONS.md +0 -355
- package/skills/wix-headless-fast/references/cms/app/hooks/cms/useCollection.ts +0 -50
- package/skills/wix-headless-fast/references/cms/app/hooks/cms/useItem.ts +0 -37
- package/skills/wix-headless-fast/references/cms/app/wix/cms/collection-store.ts +0 -158
- package/skills/wix-headless-fast/references/cms/app/wix/cms/item-store.ts +0 -93
- package/skills/wix-headless-fast/references/cms/app/wix/cms/items-core.ts +0 -177
- package/skills/wix-headless-fast/references/cms/app/wix/cms/items.ts +0 -123
- package/skills/wix-headless-fast/references/cms/app/wix/cms/types.ts +0 -75
- package/skills/wix-headless-fast/references/cms/app-astro/layouts/SiteLayout.astro +0 -41
- package/skills/wix-headless-fast/references/cms/lock/astro/package-lock.json +0 -11262
- package/skills/wix-headless-fast/references/cms/rest/items.ts +0 -125
- package/skills/wix-headless-fast/references/cms/seed/SEED.md +0 -112
- package/skills/wix-headless-fast/references/cms/seed/read-site.mjs +0 -20
- package/skills/wix-headless-fast/references/cms/seed/seed-cms.mjs +0 -324
- package/skills/wix-headless-fast/references/events/INSTRUCTIONS.md +0 -307
- package/skills/wix-headless-fast/references/events/app/components/events/EventConfirmationView.tsx +0 -66
- package/skills/wix-headless-fast/references/events/app/components/events/EventRegistrationView.tsx +0 -178
- package/skills/wix-headless-fast/references/events/app/components/events/EventsView.tsx +0 -118
- package/skills/wix-headless-fast/references/events/app/hooks/events/useEventRegistration.ts +0 -35
- package/skills/wix-headless-fast/references/events/app/hooks/events/useEvents.ts +0 -24
- package/skills/wix-headless-fast/references/events/app/wix/events/events-core.ts +0 -130
- package/skills/wix-headless-fast/references/events/app/wix/events/events-store.ts +0 -97
- package/skills/wix-headless-fast/references/events/app/wix/events/events.ts +0 -55
- package/skills/wix-headless-fast/references/events/app/wix/events/registration-core.ts +0 -113
- package/skills/wix-headless-fast/references/events/app/wix/events/registration-store.ts +0 -156
- package/skills/wix-headless-fast/references/events/app/wix/events/registration.ts +0 -97
- package/skills/wix-headless-fast/references/events/app/wix/events/types.ts +0 -61
- package/skills/wix-headless-fast/references/events/app-astro/layouts/SiteLayout.astro +0 -40
- package/skills/wix-headless-fast/references/events/app-astro/pages/event-confirmation.astro +0 -12
- package/skills/wix-headless-fast/references/events/app-astro/pages/events/[slug].astro +0 -80
- package/skills/wix-headless-fast/references/events/app-astro/pages/events.astro +0 -21
- package/skills/wix-headless-fast/references/events/lock/astro/package-lock.json +0 -11884
- package/skills/wix-headless-fast/references/events/rest/events.ts +0 -57
- package/skills/wix-headless-fast/references/events/rest/registration.ts +0 -83
- package/skills/wix-headless-fast/references/events/seed/SEED.md +0 -95
- package/skills/wix-headless-fast/references/events/seed/read-site.mjs +0 -26
- package/skills/wix-headless-fast/references/events/seed/seed-events.mjs +0 -276
- package/skills/wix-headless-fast/references/forms/INSTRUCTIONS.md +0 -340
- package/skills/wix-headless-fast/references/forms/app/hooks/forms/useWixForm.ts +0 -85
- package/skills/wix-headless-fast/references/forms/app/wix/forms/form-store.ts +0 -332
- package/skills/wix-headless-fast/references/forms/app/wix/forms/forms-core.ts +0 -238
- package/skills/wix-headless-fast/references/forms/app/wix/forms/forms.ts +0 -54
- package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions-core.ts +0 -216
- package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions.ts +0 -59
- package/skills/wix-headless-fast/references/forms/app/wix/forms/types.ts +0 -135
- package/skills/wix-headless-fast/references/forms/lock/astro/package-lock.json +0 -10593
- package/skills/wix-headless-fast/references/forms/rest/forms.ts +0 -34
- package/skills/wix-headless-fast/references/forms/rest/submissions.ts +0 -56
- package/skills/wix-headless-fast/references/forms/seed/SEED.md +0 -116
- package/skills/wix-headless-fast/references/forms/seed/read-site.mjs +0 -20
- package/skills/wix-headless-fast/references/forms/seed/seed-forms.mjs +0 -327
- package/skills/wix-headless-fast/references/members/INSTRUCTIONS.md +0 -316
- package/skills/wix-headless-fast/references/members/app/components/members/AccountView.tsx +0 -60
- package/skills/wix-headless-fast/references/members/app/components/members/LoginForm.tsx +0 -155
- package/skills/wix-headless-fast/references/members/app/components/members/MemberMenu.tsx +0 -78
- package/skills/wix-headless-fast/references/members/app/components/members/RequireAuth.tsx +0 -47
- package/skills/wix-headless-fast/references/members/app/hooks/members/useMember.ts +0 -66
- package/skills/wix-headless-fast/references/members/app/wix/members/auth-core.ts +0 -105
- package/skills/wix-headless-fast/references/members/app/wix/members/auth.ts +0 -59
- package/skills/wix-headless-fast/references/members/app/wix/members/client.ts +0 -53
- package/skills/wix-headless-fast/references/members/app/wix/members/member-store.ts +0 -122
- package/skills/wix-headless-fast/references/members/app/wix/members/members-core.ts +0 -43
- package/skills/wix-headless-fast/references/members/app/wix/members/members.ts +0 -29
- package/skills/wix-headless-fast/references/members/app/wix/members/types.ts +0 -21
- package/skills/wix-headless-fast/references/members/app-astro/layouts/SiteLayout.astro +0 -42
- package/skills/wix-headless-fast/references/members/app-astro/pages/account.astro +0 -10
- package/skills/wix-headless-fast/references/members/app-astro/pages/login.astro +0 -11
- package/skills/wix-headless-fast/references/members/lock/astro/package-lock.json +0 -10329
- package/skills/wix-headless-fast/references/members/rest/auth.ts +0 -215
- package/skills/wix-headless-fast/references/members/rest/members.ts +0 -26
- package/skills/wix-headless-fast/references/members/seed/SEED.md +0 -39
- package/skills/wix-headless-fast/references/members/seed/read-site.mjs +0 -15
- package/skills/wix-headless-fast/references/members/seed/seed-members.mjs +0 -94
- package/skills/wix-headless-fast/references/portfolio/INSTRUCTIONS.md +0 -315
- package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionProjectsView.tsx +0 -110
- package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionsView.tsx +0 -90
- package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/GalleryMedia.tsx +0 -35
- package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/ProjectDetailView.tsx +0 -85
- package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollectionProjects.ts +0 -32
- package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollections.ts +0 -21
- package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useProjectDetail.ts +0 -31
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/collection-projects-store.ts +0 -82
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/collections-store.ts +0 -58
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio-core.ts +0 -177
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio.ts +0 -78
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/project-detail-store.ts +0 -81
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/types.ts +0 -55
- package/skills/wix-headless-fast/references/portfolio/app-astro/layouts/SiteLayout.astro +0 -40
- package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio/[slug].astro +0 -30
- package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio.astro +0 -21
- package/skills/wix-headless-fast/references/portfolio/app-astro/pages/projects/[slug].astro +0 -29
- package/skills/wix-headless-fast/references/portfolio/lock/astro/package-lock.json +0 -10197
- package/skills/wix-headless-fast/references/portfolio/rest/portfolio.ts +0 -75
- package/skills/wix-headless-fast/references/portfolio/seed/SEED.md +0 -86
- package/skills/wix-headless-fast/references/portfolio/seed/read-site.mjs +0 -20
- package/skills/wix-headless-fast/references/portfolio/seed/seed-portfolio.mjs +0 -256
- package/skills/wix-headless-fast/references/pricing-plans/INSTRUCTIONS.md +0 -296
- package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlanDetailView.tsx +0 -47
- package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlansView.tsx +0 -101
- package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/SubscribeButton.tsx +0 -41
- package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlanPurchase.ts +0 -16
- package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlans.ts +0 -22
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plan-purchase-store.ts +0 -54
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans-core.ts +0 -106
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans-store.ts +0 -64
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans.ts +0 -27
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase-core.ts +0 -43
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase.ts +0 -22
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/types.ts +0 -30
- package/skills/wix-headless-fast/references/pricing-plans/app-astro/layouts/SiteLayout.astro +0 -41
- package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans/[slug].astro +0 -40
- package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans.astro +0 -21
- package/skills/wix-headless-fast/references/pricing-plans/lock/astro/package-lock.json +0 -11226
- package/skills/wix-headless-fast/references/pricing-plans/rest/plans.ts +0 -31
- package/skills/wix-headless-fast/references/pricing-plans/rest/purchase.ts +0 -20
- package/skills/wix-headless-fast/references/pricing-plans/seed/SEED.md +0 -79
- package/skills/wix-headless-fast/references/pricing-plans/seed/read-site.mjs +0 -21
- package/skills/wix-headless-fast/references/pricing-plans/seed/seed-pricing-plans.mjs +0 -279
- package/skills/wix-headless-fast/references/restaurants/INSTRUCTIONS.md +0 -360
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/MenuView.tsx +0 -142
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartButton.tsx +0 -26
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartDrawer.tsx +0 -121
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/ReservationView.tsx +0 -155
- package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useMenus.ts +0 -34
- package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useOrderCart.ts +0 -43
- package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useReservation.ts +0 -34
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu-core.ts +0 -155
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu-store.ts +0 -89
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu.ts +0 -71
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/order-store.ts +0 -103
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering-core.ts +0 -124
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering.ts +0 -185
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservation-store.ts +0 -193
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations-core.ts +0 -94
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations.ts +0 -74
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/types.ts +0 -168
- package/skills/wix-headless-fast/references/restaurants/app-astro/layouts/SiteLayout.astro +0 -47
- package/skills/wix-headless-fast/references/restaurants/app-astro/pages/menu.astro +0 -22
- package/skills/wix-headless-fast/references/restaurants/app-astro/pages/reservations.astro +0 -12
- package/skills/wix-headless-fast/references/restaurants/lock/astro/package-lock.json +0 -12560
- package/skills/wix-headless-fast/references/restaurants/rest/menu.ts +0 -60
- package/skills/wix-headless-fast/references/restaurants/rest/ordering.ts +0 -169
- package/skills/wix-headless-fast/references/restaurants/rest/reservations.ts +0 -68
- package/skills/wix-headless-fast/references/restaurants/seed/SEED.md +0 -89
- package/skills/wix-headless-fast/references/restaurants/seed/read-site.mjs +0 -25
- package/skills/wix-headless-fast/references/restaurants/seed/seed-restaurants.mjs +0 -499
- package/skills/wix-headless-fast/references/shared/CONTENT.md +0 -22
- package/skills/wix-headless-fast/references/shared/CUSTOM_OPERATIONS.md +0 -73
- package/skills/wix-headless-fast/references/shared/DESIGN.md +0 -26
- package/skills/wix-headless-fast/references/shared/SUPPLIED-CONTENT.md +0 -23
- package/skills/wix-headless-fast/references/shared/app/styles/global.css +0 -52
- package/skills/wix-headless-fast/references/shared/app/wix/config.ts +0 -15
- package/skills/wix-headless-fast/references/shared/app/wix/media.ts +0 -81
- package/skills/wix-headless-fast/references/shared/app/wix/money.ts +0 -24
- package/skills/wix-headless-fast/references/shared/app/wix/sdk.ts +0 -89
- package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app/wix/media-upload/client.ts +0 -46
- package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app-astro/pages/api/wix/media-upload.ts +0 -46
- package/skills/wix-headless-fast/references/shared/rest/client.ts +0 -155
- package/skills/wix-headless-fast/references/shared/rest/config.ts +0 -3
- package/skills/wix-headless-fast/references/shared/rest/media.ts +0 -65
- package/skills/wix-headless-fast/references/shared/seed/images.mjs +0 -145
- package/skills/wix-headless-fast/references/shared/seed/read-site.mjs +0 -99
- package/skills/wix-headless-fast/references/storefront/INSTRUCTIONS.md +0 -612
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartButton.tsx +0 -26
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartDrawer.tsx +0 -155
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/FilterPanel.tsx +0 -266
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/OptionPicker.tsx +0 -95
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/QuickAdd.tsx +0 -136
- package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useCart.ts +0 -48
- package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useProductDetail.ts +0 -39
- package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useShop.ts +0 -34
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-core.ts +0 -121
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-store.ts +0 -107
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart.ts +0 -138
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog-core.ts +0 -314
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog.ts +0 -133
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/product-detail-store.ts +0 -147
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/shop-store.ts +0 -289
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/types.ts +0 -169
- package/skills/wix-headless-fast/references/storefront/app-astro/layouts/SiteLayout.astro +0 -65
- package/skills/wix-headless-fast/references/storefront/lock/astro/package-lock.json +0 -12247
- package/skills/wix-headless-fast/references/storefront/rest/cart.ts +0 -132
- package/skills/wix-headless-fast/references/storefront/rest/catalog.ts +0 -123
- package/skills/wix-headless-fast/references/storefront/seed/SEED.md +0 -130
- package/skills/wix-headless-fast/references/storefront/seed/read-site.mjs +0 -38
- package/skills/wix-headless-fast/references/storefront/seed/seed-store.mjs +0 -561
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# Draft Template — Cases A, B and D (router-wired)
|
|
2
|
+
|
|
3
|
+
**Applies to [DRAFT_TEMPLATE.md](DRAFT_TEMPLATE.md)'s Cases A, B and D.** All three need `PatternsReactRouter`, because in all three a row opens a page of its own — a panel is not the drill-in ([UX_SUCCESS_MODEL.md](UX_SUCCESS_MODEL.md)). Case A's detail route is read-only (§4); B and D route to a full `EntityPage`. The collection and settings components live in [DRAFT_TEMPLATE.md](DRAFT_TEMPLATE.md); this file covers only what a router adds — the entry file, the app shell, and the detail/entity page.
|
|
4
|
+
|
|
5
|
+
Every snippet below is copied from the installed `dist/docs/*.md` this session read, not from memory.
|
|
6
|
+
|
|
7
|
+
## 1. Entry — `location` is manual in a Wix CLI app, and only because the router needs it
|
|
8
|
+
|
|
9
|
+
`PatternsReactRouter` reads the page location through `container.usePageLocation()`, which only `withDashboard`'s `location` prop feeds — nothing supplies it automatically in a Wix CLI app the way Yoshi BM flow does:
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
// {feature}.tsx — Case A, B or D
|
|
13
|
+
import { useEffect, useState, type FC } from 'react';
|
|
14
|
+
import { dashboard } from '@wix/dashboard';
|
|
15
|
+
import { WixDesignSystemProvider } from '@wix/design-system';
|
|
16
|
+
import '@wix/design-system/styles.global.css';
|
|
17
|
+
import { {Feature}App } from './{Feature}App';
|
|
18
|
+
|
|
19
|
+
type PageLocation = Parameters<Parameters<typeof dashboard.observeState>[0]>[1]['pageLocation'];
|
|
20
|
+
|
|
21
|
+
const Page: FC = () => {
|
|
22
|
+
const [location, setLocation] = useState<PageLocation | undefined>();
|
|
23
|
+
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
const subscription = dashboard.observeState((_pageParams, environment) => {
|
|
26
|
+
setLocation(environment.pageLocation);
|
|
27
|
+
});
|
|
28
|
+
return () => subscription.disconnect();
|
|
29
|
+
}, []);
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<WixDesignSystemProvider>
|
|
33
|
+
{location ? <{Feature}App location={location} /> : null}
|
|
34
|
+
</WixDesignSystemProvider>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export default Page;
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Skipping this is a runtime-only failure.** Per `PatternsReactRouter`'s own docs: "Nothing catches this before runtime — type checking and bundling both pass, because neither renders the page." `tsc` and `wix build` will not catch a missing `location` — only opening the page in a browser will. This is exactly why [Step 5's Preview](../../SKILL.md#validation) is not optional for Case B/D.
|
|
42
|
+
|
|
43
|
+
## 2. App shell — provider, router, routes
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
// {Feature}App.tsx — Case A, B or D
|
|
47
|
+
import { withDashboard } from '@wix/patterns';
|
|
48
|
+
import { WixPatternsProvider } from '@wix/patterns/provider';
|
|
49
|
+
import { PatternsReactRouter, PatternsReactRoute } from '@wix/patterns/router';
|
|
50
|
+
import { {Feature}CollectionPage } from './{Feature}CollectionPage';
|
|
51
|
+
import { {Feature}EntityPage } from './{Feature}EntityPage';
|
|
52
|
+
// Case D only:
|
|
53
|
+
import { {Feature}SettingsPage } from './{Feature}SettingsPage';
|
|
54
|
+
|
|
55
|
+
export const {Feature}App = withDashboard(() => (
|
|
56
|
+
<WixPatternsProvider>
|
|
57
|
+
<PatternsReactRouter>
|
|
58
|
+
<PatternsReactRoute type="collection" path="/" element={<{Feature}CollectionPage />} />
|
|
59
|
+
{/* Case B/D — editable record. Case A registers this ONE route instead, with
|
|
60
|
+
{Feature}DetailPage as the element and no /new route (§4). Either way the
|
|
61
|
+
type is `editEntity`: it wires back-navigation to the collection. */}
|
|
62
|
+
<PatternsReactRoute type="editEntity" path="/:id" element={<{Feature}EntityPage />} />
|
|
63
|
+
{/* Case B/D only — Case A has nothing to create: */}
|
|
64
|
+
<PatternsReactRoute type="createEntity" path="/new" element={<{Feature}EntityPage />} />
|
|
65
|
+
{/* Case D only: */}
|
|
66
|
+
<PatternsReactRoute type="other" path="/settings" element={<{Feature}SettingsPage />} />
|
|
67
|
+
</PatternsReactRouter>
|
|
68
|
+
</WixPatternsProvider>
|
|
69
|
+
));
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`PatternsReactRoute`'s `type` is one of exactly `"collection" | "createEntity" | "editEntity" | "other"` — no dedicated settings value, so a settings route is `"other"`. Case B: delete the `/settings` route and the import above it — nothing else changes.
|
|
73
|
+
|
|
74
|
+
`{Feature}CollectionPage` is [DRAFT_TEMPLATE_COLLECTION.md](DRAFT_TEMPLATE_COLLECTION.md)'s component, unchanged; `{Feature}SettingsPage` (Case D) is [DRAFT_TEMPLATE_SETTINGS.md](DRAFT_TEMPLATE_SETTINGS.md).
|
|
75
|
+
|
|
76
|
+
## 2b. The collection side of the handoff
|
|
77
|
+
|
|
78
|
+
The router file above registers `/new`; something has to navigate there. All three of these live on
|
|
79
|
+
the collection page, and `usePatternsNavigate` comes from **`@wix/patterns/router`** — not the root
|
|
80
|
+
export, which is where it is easy to reach for it:
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
import { PrimaryPageButton } from '@wix/patterns';
|
|
84
|
+
import { usePatternsNavigate } from '@wix/patterns/router';
|
|
85
|
+
|
|
86
|
+
const { navigateToEntityPage } = usePatternsNavigate<{Entity}>();
|
|
87
|
+
const openNew = () => navigateToEntityPage({ path: '/new' }); // no record yet — omit `entity`
|
|
88
|
+
|
|
89
|
+
// CollectionPage.Header — primaryAction takes an ELEMENT, not a { text, onClick } config:
|
|
90
|
+
<CollectionPage.Header
|
|
91
|
+
title={{ text: '{Page Title}' }}
|
|
92
|
+
primaryAction={<PrimaryPageButton text="Add {entity}" onClick={openNew} />}
|
|
93
|
+
/>
|
|
94
|
+
|
|
95
|
+
// the empty state should offer the same action, and this one IS a config object:
|
|
96
|
+
<CollectionEmptyState title="No {feature} yet" addNewCta={{ text: 'Add {entity}', onClick: openNew }} />
|
|
97
|
+
|
|
98
|
+
// and a row opens the edit route:
|
|
99
|
+
onRowClick={(item) => navigateToEntityPage({ path: `/${item.id}`, entity: item })}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The two shapes differ on purpose — `primaryAction` is an element, `addNewCta` is `{ text, onClick }`.
|
|
103
|
+
Guessing either costs a compile round.
|
|
104
|
+
|
|
105
|
+
## 3. Entity page — one component for both `/new` and `/:id`
|
|
106
|
+
|
|
107
|
+
Full call details (both generics, what `onSave` receives, the `UseEntityPageParams` pick list) are in `<pkgRoot>/dist/docs/useEntityPage.md` — read it before filling in fields. The part specific to this router-based shape:
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
// {Feature}EntityPage.tsx — Case B or D (sketch — see dist/docs/useEntityPage.md for the full call)
|
|
111
|
+
import { useParams } from 'react-router-dom'; // NOT @wix/patterns/router — PatternsReactRoute wraps react-router-dom's Route, but only exports PatternsReactRoute/PatternsReactRouter/usePatternsNavigate itself
|
|
112
|
+
import { useEntityPage, EntityPage } from '@wix/patterns';
|
|
113
|
+
import { useForm } from '@wix/patterns/form';
|
|
114
|
+
import { fetch{Entity}, save{Entity}, type {Entity} } from './{feature}-api';
|
|
115
|
+
|
|
116
|
+
// The form's shape is yours to declare, and need not match the saved entity type.
|
|
117
|
+
type {Entity}FormFields = { name: string };
|
|
118
|
+
|
|
119
|
+
export const {Feature}EntityPage = () => {
|
|
120
|
+
const { id } = useParams<{ id?: string }>();
|
|
121
|
+
const form = useForm<{Entity}FormFields>();
|
|
122
|
+
|
|
123
|
+
const state = useEntityPage<{Entity}, {Entity}FormFields>({
|
|
124
|
+
parentPath: '/', // NOT parentPageId — this shape always uses Patterns Router
|
|
125
|
+
isNewEntity: () => !id, // a getter: the route can change (/new -> /:id after save) while this stays mounted
|
|
126
|
+
form,
|
|
127
|
+
fetch: () => (id ? fetch{Entity}(id).then((entity) => ({ entity })) : Promise.resolve({ entity: undefined })),
|
|
128
|
+
onSave: ({ widgetsFormData }) =>
|
|
129
|
+
save{Entity}({ id, ...form.getValues(), ...widgetsFormData }).then((updatedEntity) => ({ updatedEntity })),
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
return (
|
|
133
|
+
<EntityPage state={state}>
|
|
134
|
+
<EntityPage.Header title={{ text: id ? 'Edit {Entity}' : 'New {Entity}' }} />
|
|
135
|
+
<EntityPage.Content>
|
|
136
|
+
<EntityPage.MainContent>{/* form cards — see dist/docs/EntityPage.md */}</EntityPage.MainContent>
|
|
137
|
+
</EntityPage.Content>
|
|
138
|
+
</EntityPage>
|
|
139
|
+
);
|
|
140
|
+
};
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`useEntityPage`'s own docs are explicit about both details above: `parentPath` "Must be passed if using Patterns Router" (`parentPageId` is the non-router alternative — irrelevant here, since Case B/D always uses the router), and `isNewEntity` should be "a getter when the route can change while the page stays mounted" — exactly this component's case, since a successful create typically navigates `/new` → `/:newId`.
|
|
144
|
+
|
|
145
|
+
**`UseEntityPageParams` is a `Pick<>`, so a param missing from it is a compile error, not an ignored prop.** `isNewEntity` is in that list at 1.470.0 and absent before ~1.46x. If it doesn't compile, read the pick list in your installed `dist/types/hooks/useEntityPage.d.ts` and upgrade — deleting the line makes a create route behave as an edit.
|
|
146
|
+
|
|
147
|
+
## 4. Read-only detail route — Case A
|
|
148
|
+
|
|
149
|
+
A display-only collection still routes its rows to a page — but not an `EntityPage`, which has no
|
|
150
|
+
read-only mode and still has none at **1.471.0**: `fetch` and `onSave` are both required, and
|
|
151
|
+
`actionsBarConfig` (`saveCta.text`, `cancelCta`) can retext Save but not remove it. It would ship
|
|
152
|
+
two buttons that either do nothing or save a form nobody was offered.
|
|
153
|
+
|
|
154
|
+
Use a WDS `Page` — what Cairo does itself: `example-bm`'s `DataExtensionEntityViewPage` and
|
|
155
|
+
auto-patterns' `ViewModeEntityPage` are both plain WDS `Page`s, the latter unexported.
|
|
156
|
+
|
|
157
|
+
```tsx
|
|
158
|
+
// {Feature}DetailPage.tsx — Case A
|
|
159
|
+
import { useEffect, useState } from 'react';
|
|
160
|
+
import { useParams } from 'react-router-dom';
|
|
161
|
+
import { Card, Loader, Page, Text } from '@wix/design-system';
|
|
162
|
+
import { usePatternsNavigate } from '@wix/patterns/router';
|
|
163
|
+
import { fetch{Entity}, type {Entity} } from './{feature}-api';
|
|
164
|
+
|
|
165
|
+
export const {Feature}DetailPage = () => {
|
|
166
|
+
const { id } = useParams<{ id: string }>();
|
|
167
|
+
const { navigateToCollectionPage } = usePatternsNavigate();
|
|
168
|
+
const [entity, setEntity] = useState<{Entity} | undefined>();
|
|
169
|
+
|
|
170
|
+
useEffect(() => {
|
|
171
|
+
if (id) {
|
|
172
|
+
fetch{Entity}(id).then(setEntity);
|
|
173
|
+
}
|
|
174
|
+
}, [id]);
|
|
175
|
+
|
|
176
|
+
return (
|
|
177
|
+
<Page>
|
|
178
|
+
{/* The way back is the header's back button — a read-only page has no Cancel. */}
|
|
179
|
+
<Page.Header
|
|
180
|
+
title={entity?.name ?? '{Entity}'}
|
|
181
|
+
showBackButton
|
|
182
|
+
onBackClicked={() => navigateToCollectionPage({ path: '/' })}
|
|
183
|
+
/>
|
|
184
|
+
<Page.Content>
|
|
185
|
+
{entity ? (
|
|
186
|
+
<Card>
|
|
187
|
+
<Card.Header title="Details" />
|
|
188
|
+
<Card.Divider />
|
|
189
|
+
<Card.Content>
|
|
190
|
+
<Text>{entity.name}</Text>
|
|
191
|
+
</Card.Content>
|
|
192
|
+
</Card>
|
|
193
|
+
) : (
|
|
194
|
+
<Loader />
|
|
195
|
+
)}
|
|
196
|
+
</Page.Content>
|
|
197
|
+
</Page>
|
|
198
|
+
);
|
|
199
|
+
};
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
If the request later grows an edit form this becomes §3's `EntityPage`, route type and `onRowClick`
|
|
203
|
+
unchanged — which is why Case A registers `editEntity`, not `other`.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Draft Template — Settings page (Cases C and D)
|
|
2
|
+
|
|
3
|
+
> Pick your case in [DRAFT_TEMPLATE.md](DRAFT_TEMPLATE.md) first; this page covers Case C or D.
|
|
4
|
+
|
|
5
|
+
## The settings page
|
|
6
|
+
|
|
7
|
+
No dedicated toolkit file exists for this yet (unlike Entity/Collection) — the shape, verified against `useSettingsPage.md`:
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
// {Feature}SettingsPage.tsx — Case C or D
|
|
11
|
+
import { SettingsPage, useSettingsPage, useSettings } from '@wix/patterns';
|
|
12
|
+
import { useForm } from '@wix/patterns/form';
|
|
13
|
+
import { fetch{Feature}Settings, save{Feature}Settings, type {Feature}Settings } from './{feature}-api';
|
|
14
|
+
|
|
15
|
+
// The form's shape is yours to declare, and need not match the saved settings type —
|
|
16
|
+
// one field per control on the page.
|
|
17
|
+
type {Feature}SettingsFormFields = { reminderHours: number; notifyStaff: boolean };
|
|
18
|
+
|
|
19
|
+
export const {Feature}SettingsPage = () => {
|
|
20
|
+
const form = useForm<{Feature}SettingsFormFields>();
|
|
21
|
+
|
|
22
|
+
const state = useSettingsPage<{Feature}Settings, {Feature}SettingsFormFields>({
|
|
23
|
+
form,
|
|
24
|
+
fetch: () => fetch{Feature}Settings().then((settings) => ({ settings })),
|
|
25
|
+
onSave: () => save{Feature}Settings(form.getValues()),
|
|
26
|
+
onCancel: async () => form.reset(),
|
|
27
|
+
saveSuccessToast: 'Settings saved',
|
|
28
|
+
saveErrorToast: (err, { retry }) => ({ message: 'Failed to save settings', action: { text: 'Retry', onClick: retry } }),
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const settings = useSettings<{Feature}Settings, {Feature}SettingsFormFields>(state);
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<SettingsPage state={state}>
|
|
35
|
+
<SettingsPage.Header title={{ text: '{Settings Page Title}' }} />
|
|
36
|
+
<SettingsPage.Content>
|
|
37
|
+
<SettingsPage.MainContent>{/* form cards — same field-controller patterns as EntityPage */}</SettingsPage.MainContent>
|
|
38
|
+
</SettingsPage.Content>
|
|
39
|
+
</SettingsPage>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`useSettingsPage`'s params are all required except `saveSuccessToast`/`saveErrorToast`: `form`, `fetch`, `onSave`, `onCancel`. There is no `parentPath`/`parentPageId` — a settings page isn't reached by drilling into a row, so it carries no back-navigation contract, and Case C needs no router at all to reach it (Section 1's entry renders it directly).
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# Querying and paging a Wix API from a collection page
|
|
2
|
+
|
|
3
|
+
> [DATA_SOURCES.md](DATA_SOURCES.md) covers finding the method and its fields; this page is about
|
|
4
|
+
> calling it.
|
|
5
|
+
|
|
6
|
+
Filters are written in **WQL**, which is shared across the platform — the rules below come from
|
|
7
|
+
[About the Wix API Query Language][wql], not from one endpoint's behaviour, so they hold for
|
|
8
|
+
`@wix/ecom`, `@wix/stores`, `@wix/bookings` and the rest alike.
|
|
9
|
+
|
|
10
|
+
## The filterable fields are a closed list, published per endpoint
|
|
11
|
+
|
|
12
|
+
> "This endpoint declares which fields it can filter and sort by, and with which operators; that
|
|
13
|
+
> list is closed and covers this endpoint only. Anything else errors or silently returns the wrong
|
|
14
|
+
> rows." — [WQL][wql]
|
|
15
|
+
|
|
16
|
+
So a field path is never inferable from the entity shape, and the endpoint's own prose is not
|
|
17
|
+
authoritative either. **Most query endpoints publish a "Supported Filters and Sorting" page**, and
|
|
18
|
+
the SDK typedoc for the query's `filter` field links to it — Contacts, Orders, Products V3,
|
|
19
|
+
Pipelines and Bookings all do. Find the link before you guess:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
grep -rho "https://[^)]*supported-filters[^)]*" node_modules/@wix/<pkg>/build/es/*.d.mts | sort -u
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Read the page, don't just find it.** It is a table of field → operators, and it routinely lists
|
|
26
|
+
more than the endpoint's prose implies — Query Extended Bookings' prose mentions filtering courses
|
|
27
|
+
"by `scheduleId`", while its table also declares `serviceId` and the staff `resource.id` on both
|
|
28
|
+
`bookedEntity` branches, and `contactDetails.contactId` / `.email`. Those are the difference between
|
|
29
|
+
a page with two working filters and one with five.
|
|
30
|
+
|
|
31
|
+
**Honour the *Filter Performance* note.** Many pages carry one, naming fields to include in every
|
|
32
|
+
request — Query Extended Bookings "strongly recommends" `startDate` in all of them. Don't satisfy it
|
|
33
|
+
by hiding a clause in `fetchData`: a filter the user cannot see or clear makes rows go missing for no
|
|
34
|
+
visible reason. Seed the visible filter instead, so the default is applied, labelled and adjustable:
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
const dateFilter = dateRangeFilter({
|
|
38
|
+
name: 'Date',
|
|
39
|
+
initialValue: { from: startOfDay(subDays(new Date(), 30)), to: null },
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`initialValue` is on every filter factory (`FilterStateBaseParams`), so the same trick seeds a status
|
|
44
|
+
or category default. Pick a window that matches the page's job — a booking review wants recent and
|
|
45
|
+
upcoming, an audit log wants the last 24 hours.
|
|
46
|
+
|
|
47
|
+
**A seeded default must not defeat search.** Search is a "find this anywhere" gesture, so a window
|
|
48
|
+
the user never chose silently hiding matches from it reads as broken search — a measured run shipped
|
|
49
|
+
exactly that, and the report was "search doesn't work", not "the date filter is too narrow". Bypass
|
|
50
|
+
the range while it is still the seeded value, and keep it once the user has set their own:
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
const DEFAULT_FROM = startOfDayDaysAgo(30);
|
|
54
|
+
const isUntouchedDefault = (r?: { from?: Date; to?: Date }) =>
|
|
55
|
+
!r?.to && r?.from?.getTime() === DEFAULT_FROM.getTime();
|
|
56
|
+
// in fetchData AND fetchTotal:
|
|
57
|
+
dateRange: search?.trim() && isUntouchedDefault(range) ? undefined : range,
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Whatever a filter or a permission removes from the result, **say so in `noResultsState`** — "no
|
|
61
|
+
matches" and "no matches because a default you didn't set, or a scope you don't hold, excluded them"
|
|
62
|
+
look identical, and only the second is actionable.
|
|
63
|
+
|
|
64
|
+
Two traps the list resolves, both of which look like a working filter:
|
|
65
|
+
|
|
66
|
+
**Nested paths.** A field that reads as top-level on the entity is often only filterable at its full
|
|
67
|
+
path. Query Extended Bookings describes itself as filtering "by `scheduleId` of the relevant
|
|
68
|
+
service", and a bare `scheduleId` is rejected outright — the accepted paths are nested under
|
|
69
|
+
`bookedEntity`. The error names the offending path exactly, so one call settles it:
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{ "code": "INVALID_FILTER", "data": { "unknownField": { "fieldPath": "scheduleId" } } }
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Oneof branches.** When the entity has a oneof, one path covers only one branch, and a filter over
|
|
76
|
+
just that branch silently drops every row of the other kind — exactly as the row mapper has to
|
|
77
|
+
handle both. Cover them with `$or`, and check each branch separately before wiring it into a page:
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
$or: [
|
|
81
|
+
{ 'bookedEntity.item.slot.scheduleId': { $in: scheduleIds } },
|
|
82
|
+
{ 'bookedEntity.item.schedule.scheduleId': { $in: scheduleIds } },
|
|
83
|
+
]
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## One operator per field
|
|
87
|
+
|
|
88
|
+
> "The filter is written in WQL, where each field takes a single operator, so conditions are
|
|
89
|
+
> combined with the logical operators instead: `$and` and `$or` take an array of expressions,
|
|
90
|
+
> `$not` takes one, and they can nest. They are WQL syntax, not field capabilities." — [WQL][wql]
|
|
91
|
+
|
|
92
|
+
A date range written the obvious way therefore fails, and the error quotes the whole object back as
|
|
93
|
+
the offending "operator", which reads like a parser bug and is actually the rule:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
{ startDate: { $gte: from, $lte: to } } // INVALID_FILTER — unknownOperator
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Ranges are two clauses under `$and`; `$or` nests inside it:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
{ $and: [
|
|
103
|
+
{ status: { $in: statuses } },
|
|
104
|
+
{ startDate: { $gte: from } },
|
|
105
|
+
{ startDate: { $lte: to } },
|
|
106
|
+
{ $or: [ /* the oneof branches */ ] },
|
|
107
|
+
] }
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Build the filter as a list of clauses and wrap it at the end — return the bare clause when there is
|
|
111
|
+
only one, `{}` when there are none — rather than mutating one object and hoping the operators do not
|
|
112
|
+
collide. A page with several filters hits this the moment two of them apply at once, which is
|
|
113
|
+
usually after the single-filter case has already been called working. The full operator set —
|
|
114
|
+
including `$not`, `$nin`, `$exists`, `$isEmpty`, `$hasAll`, `$hasSome` — is in the [WQL article][wql].
|
|
115
|
+
|
|
116
|
+
## A follow-up cursor page carries the cursor alone
|
|
117
|
+
|
|
118
|
+
The cursor already encodes the filter and sort of the query that produced it, so re-sending them is
|
|
119
|
+
rejected. This is not one API's quirk: it is stated on the `cursorPaging.cursor` field of every
|
|
120
|
+
generated Wix SDK that offers cursor paging — 46 of the 179 `auto_sdk_*` packages in one install —
|
|
121
|
+
in a standard sentence you can read before making a request:
|
|
122
|
+
|
|
123
|
+
> "Cursor token pointing to a page of results. Not used in the first request. Following requests use
|
|
124
|
+
> the cursor token and not `filter` or `sort`."
|
|
125
|
+
|
|
126
|
+
Build the first request and the follow-ups differently:
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
const response = await ns.query(
|
|
130
|
+
query.cursor
|
|
131
|
+
? { cursorPaging: { limit: query.limit, cursor: query.cursor } }
|
|
132
|
+
: { filter, sort, cursorPaging: { limit: query.limit } },
|
|
133
|
+
);
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Sending them together answers `"Invalid cursor. Sort or filter can not be specified together with
|
|
137
|
+
cursor"` — and because the collection retries, that renders as a spinner under the last row, which
|
|
138
|
+
reads as "still loading". What you return on the **last** page is the collection's own contract, and
|
|
139
|
+
has its own trap: [TABLE_STATE.md](TABLE_STATE.md#query-and-result-shapes).
|
|
140
|
+
|
|
141
|
+
Cursor mode also takes a separate `fetchTotal`, since a cursor-paged response carries no total.
|
|
142
|
+
Build its filter exactly as the page's, or the count disagrees with the rows it counts.
|
|
143
|
+
|
|
144
|
+
## What `fetchTotal` is allowed to call
|
|
145
|
+
|
|
146
|
+
`fetchTotal: (query) => Promise<number>`. It has to resolve **a number from something that
|
|
147
|
+
counts** — and the obvious-looking source is not one. A cursor-paged response carries no total,
|
|
148
|
+
so `pagingMetadata.total` is `undefined` — and `undefined` reaches the collection as `0`.
|
|
149
|
+
`@wix/data` spells the rule out on `PagingMetadataV2.total`: "Returned if offset paging is used,
|
|
150
|
+
`returnTotalCount` is `true` in the request, and `tooManyToCount` is false." Read the field's own
|
|
151
|
+
doc comment in the SDK you are calling rather than assuming it is populated. That is the whole of the
|
|
152
|
+
"`SummaryBar` reads 0 while the table under it is full of rows" bug, and it survives review
|
|
153
|
+
because nothing throws and nothing fails to compile.
|
|
154
|
+
|
|
155
|
+
Use a real count, in this order:
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
// 1. A CMS collection: `items.query(id)` returns a builder whose `.count()` is
|
|
159
|
+
// `Promise<number>` and honours the filter you put on it. Apply the page's
|
|
160
|
+
// filter with the same function fetchData uses, so the two cannot drift.
|
|
161
|
+
// (The standalone `items.count(id)` is marked @internal and takes no filter.)
|
|
162
|
+
const count{Feature} = (q: {Feature}Query): Promise<number> =>
|
|
163
|
+
apply{Feature}Filter(items.query(COLLECTION_ID), q).count();
|
|
164
|
+
|
|
165
|
+
// 2. A vertical SDK with its own count endpoint: call that — it already returns a number.
|
|
166
|
+
|
|
167
|
+
// 3. Offset paging only — ask for the count, then read it back:
|
|
168
|
+
const { pagingMetadata } = await ns.query({ paging: { limit, offset }, returnTotalCount: true });
|
|
169
|
+
return pagingMetadata?.total ?? 0; // `?? 0` is honest HERE: you asked for the count
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**If the API offers no count at all, omit `fetchTotal`.** `collection.total` then falls back to the
|
|
173
|
+
rows loaded so far, which is a real number you can label ("50 shown") instead of a confident `0`.
|
|
174
|
+
Never paper over the gap with `?? 0` on a field that is simply absent.
|
|
175
|
+
|
|
176
|
+
## When a table will not settle
|
|
177
|
+
|
|
178
|
+
An extension runs in a cross-origin iframe whose console you cannot read, but its own `SummaryBar`
|
|
179
|
+
will happily display `state.collection.status.status`, a fetch counter and the last rejection
|
|
180
|
+
message. That is what turns "it spins" into a named error in one reload.
|
|
181
|
+
|
|
182
|
+
[wql]: https://dev.wix.com/docs/api-reference/articles/work-with-wix-apis/data-retrieval/about-the-wix-api-query-language
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Reading the state object `useTableCollection` hands you
|
|
2
|
+
|
|
3
|
+
> **Scope.** The [Component Docs Gate](../../SKILL.md) covers component *names and props*, and the
|
|
4
|
+
> package's own `TableState` declaration is the member list. This file covers only what that
|
|
5
|
+
> declaration cannot tell you: the plausible members that are absent from it, and the behaviour
|
|
6
|
+
> behind the ones that are there.
|
|
7
|
+
|
|
8
|
+
## Why guessing here always fails
|
|
9
|
+
|
|
10
|
+
`useTableCollection()` returns a `TableState`. For the members themselves, read the declaration the
|
|
11
|
+
index names — `Read <pkgRoot>/dist/dts-bundle/index.json`, then its `file`. Reading them is not the
|
|
12
|
+
hard part; the hard part is that several plausible members don't exist at all, and one that does
|
|
13
|
+
means something other than its name suggests (see
|
|
14
|
+
[Four that bite in practice](#four-that-bite-in-practice)).
|
|
15
|
+
|
|
16
|
+
**One thing not to conclude from the docs bundle.** `dist/dts-bundle/` publishes `CollectionState`
|
|
17
|
+
as a stub:
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
declare class CollectionState<T = any, F = any> { [key: string]: unknown }
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
That is a documentation abridgement, not the declaration your code compiles against. `tsc` resolves
|
|
24
|
+
`dist/types/index.d.ts`, which re-exports the **fully typed** `CollectionState` from
|
|
25
|
+
`@wix/bex-core` — no index signature. So `state.collection.…` is properly typed, a wrong member is a
|
|
26
|
+
compile error at the access, and reading `state.collection.status.status` to debug a stuck table is
|
|
27
|
+
sound. See [WIX_PATTERNS_DOCS.md § 5](../WIX_PATTERNS_DOCS.md#5--traps-that-make-a-read-wrong).
|
|
28
|
+
|
|
29
|
+
Prefer a typed member on `TableState` itself anyway — it is the object the hook hands you, and the
|
|
30
|
+
table's own view of the collection.
|
|
31
|
+
|
|
32
|
+
## Four that bite in practice
|
|
33
|
+
|
|
34
|
+
**`state.filters` does not exist.** Filter state lives on the filter objects you created with
|
|
35
|
+
`stringsArrayFilter()` / `dateRangeFilter()` and passed into `filters`. Keep those in module-level
|
|
36
|
+
consts and reference the const in both the hook config and the JSX — that is also what
|
|
37
|
+
`MultiSelectCheckboxFilter`'s `filter` prop wants.
|
|
38
|
+
|
|
39
|
+
**`showLoadingState` is not "the query is running".** It stays `true` when the query resolves with
|
|
40
|
+
zero rows, so binding `SummaryBar`'s `status` to it leaves the bar on skeleton pills permanently on
|
|
41
|
+
an empty collection — which reads as a hung network rather than an empty result. Use
|
|
42
|
+
`state.showErrorState ? 'error' : 'success'`.
|
|
43
|
+
|
|
44
|
+
**`collection.isLoading` and `collection.refresh()` are not members.** They look plausible, they
|
|
45
|
+
compile against the index signature, and neither exists at runtime.
|
|
46
|
+
|
|
47
|
+
### A `fetchTotal` that resolves undefined shows 0, not the rows
|
|
48
|
+
|
|
49
|
+
This is the "`SummaryBar` says 0 while the table under it is full" report, and it is worth tracing
|
|
50
|
+
once because every step is silent. `FetchTotalState` wraps your function in a second, one-item
|
|
51
|
+
collection whose page is literally `{ items: [], total: await fetchTotal(query) }`. That page then
|
|
52
|
+
goes through `CollectionState.updateResult`, which computes
|
|
53
|
+
`lastPage.total ?? lastPage.items.length` — so a `total` of `undefined` becomes `0`, because the
|
|
54
|
+
synthetic page has no items to fall back on. And `QueryResultState.total` reads
|
|
55
|
+
`fetchTotal ? fetchTotal.total : this._totals.processed`: **the moment `fetchTotal` exists it wins,
|
|
56
|
+
and the loaded-rows fallback is gone.**
|
|
57
|
+
|
|
58
|
+
Two consequences worth keeping in mind:
|
|
59
|
+
|
|
60
|
+
- **A wrong `fetchTotal` is worse than no `fetchTotal`.** Omit it and `total` degrades to the rows
|
|
61
|
+
you have; wire it to something that resolves `undefined` and a page with 4,000 matching rows
|
|
62
|
+
reports `0`. Nothing throws, nothing fails `tsc`, and the table beside it is correct.
|
|
63
|
+
- **`pagingMetadata.total` is not a count.** A cursor-paged response carries no total, and
|
|
64
|
+
`@wix/data` documents the field as returned only under *offset* paging with
|
|
65
|
+
`returnTotalCount: true`. Under the cursor paging these pages default to, expect `undefined`.
|
|
66
|
+
Call something that counts —
|
|
67
|
+
[QUERY_AND_PAGING.md](QUERY_AND_PAGING.md#what-fetchtotal-is-allowed-to-call).
|
|
68
|
+
|
|
69
|
+
To tell the two apart in a running page, show `state.collection.totalStatus` next to the number:
|
|
70
|
+
it is the totals collection's own status, so a `success` beside a `0` means your function resolved
|
|
71
|
+
nothing, not that the query failed.
|
|
72
|
+
|
|
73
|
+
## Reading state outside the table: it is MobX
|
|
74
|
+
|
|
75
|
+
`@wix/patterns` depends on `mobx` and `mobx-react-lite`, so the state object is observable and a
|
|
76
|
+
plain React component does not track it. Anything you derive from `state` in your own component —
|
|
77
|
+
a `SummaryBar` count, a badge total, a header figure — is computed once on first render, when the
|
|
78
|
+
collection is still empty, and never recomputed. The table itself updates because it observes
|
|
79
|
+
internally; your derived numbers sit at zero next to a table full of rows, which reads as a bug in
|
|
80
|
+
the query rather than in the wiring.
|
|
81
|
+
|
|
82
|
+
`useSelector` from `@wix/patterns` subscribes:
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
const loadedCount = useSelector(() => state.keyedItems.length);
|
|
86
|
+
const rows = useMemo(() => state.keyedItems.map((k) => k.item), [loadedCount]);
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Select a primitive.** Returning a fresh array or object from the selector gives it a new identity
|
|
90
|
+
on every evaluation. Select a length, a total or an id, then derive the rest once it fires.
|
|
91
|
+
|
|
92
|
+
## Query and result shapes
|
|
93
|
+
|
|
94
|
+
`fetchData(query)` receives a `ComputedQuery<F>`: `limit`, `offset`, `page`, `search`, `rawSearch`,
|
|
95
|
+
`cursor`, `filters`, `rawFilters`, `sort`.
|
|
96
|
+
|
|
97
|
+
**Read the return type from `@wix/bex-core`, not from `@wix/patterns`.** The name
|
|
98
|
+
`CursorQueryResult` exists in both packages and they are different types. The one your `fetchData`
|
|
99
|
+
must satisfy is the generic in `node_modules/@wix/bex-core/dist/types/hooks/paginationModeConfig.d.ts`:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
interface DataResultRaw<T> {
|
|
103
|
+
items: T[];
|
|
104
|
+
total?: number | null;
|
|
105
|
+
available?: number; // total BEFORE filters
|
|
106
|
+
cursor?: string | undefined | null;
|
|
107
|
+
hasNext?: boolean | null;
|
|
108
|
+
}
|
|
109
|
+
type OffsetQueryResult<T> = Omit<DataResultRaw<T>, 'cursor'>;
|
|
110
|
+
type CursorQueryResult<T> = Omit<DataResultRaw<T>, 'cursor'> & { cursor: string | undefined | null };
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Three consequences, each of which has shipped as a bug:
|
|
114
|
+
|
|
115
|
+
**In cursor mode the `cursor` key is required; its value may be `undefined`.** The intersection
|
|
116
|
+
re-declares `cursor` without `?`, so `return { items }` does not compile — but
|
|
117
|
+
`{ items, cursor: undefined }` does. "Required" is about the key, not the value.
|
|
118
|
+
|
|
119
|
+
**On the last page return `undefined`, never `''`.** An empty string is still a cursor to the
|
|
120
|
+
collection: it requests the next page forever and appends the same rows each pass, a table that
|
|
121
|
+
grows without end while the API is perfectly happy, rendering as a spinner under the last row that
|
|
122
|
+
reads as "still loading". Derive it so the empty case collapses:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
cursor: response.pagingMetadata?.cursors?.next || undefined,
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**`hasNext` and `total` exist in both modes** — they are on `DataResultRaw`, which both aliases
|
|
129
|
+
extend. Cursor mode also accepts a separate `fetchTotal`, since a cursor-paged response carries no
|
|
130
|
+
total; build its filter exactly as the page's or the count disagrees with the rows it counts.
|
|
131
|
+
|
|
132
|
+
Look any of these up yourself with `Read <pkgRoot>/dist/dts-bundle/index.json` and the `file` path it
|
|
133
|
+
gives; the index is the single source of truth, and it moves between versions.
|
|
@@ -124,12 +124,17 @@ Choose the smallest interface that gives users enough context and room to comple
|
|
|
124
124
|
|
|
125
125
|
| Interface | Use when… | Success looks like… |
|
|
126
126
|
|---|---|---|
|
|
127
|
-
| **
|
|
128
|
-
| **
|
|
129
|
-
| **
|
|
130
|
-
| **Inline or expanded row** |
|
|
127
|
+
| **Entity page** | The item is editable — the default for a business record. | Enough space and structure to complete deeper work. |
|
|
128
|
+
| **Read-only detail page** | The collection is display-only. | Fully readable, linkable, one back-click from the list. |
|
|
129
|
+
| **Modal** | A focused, bounded task that is not "open this record". | Attention stays on one task; the user returns cleanly. |
|
|
130
|
+
| **Inline or expanded row** | A quick look *alongside* the drill-in, not instead of it. | Detail appears without a separate workspace. |
|
|
131
131
|
|
|
132
|
-
|
|
132
|
+
Opening an item is a **route**, editable or not — a constraint, not a preference, and it outranks
|
|
133
|
+
"smallest interface". A side panel is not one of the choices: in Cairo it hosts a page's own
|
|
134
|
+
panels. A display-only record still routes, just to a WDS `Page`, since `EntityPage` has no view
|
|
135
|
+
mode.
|
|
136
|
+
|
|
137
|
+
Which Wix primitive builds each of these — and which components serve the summaries, filters and empty states named above — is in the installed package's `Collection Toolkit.md` guide — reached through [The Discovery Chain](../WIX_PATTERNS_DOCS.md#the-discovery-chain).
|
|
133
138
|
|
|
134
139
|
|
|
135
140
|
## Data Success
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Data Collection — getting it onto the site
|
|
2
|
+
|
|
3
|
+
> Declaring a collection is not the same as creating one. Releasing, updating the site, the CMS
|
|
4
|
+
> prerequisite, and what access the extension actually grants.
|
|
5
|
+
|
|
6
|
+
## Item access and collection management are different scopes
|
|
7
|
+
|
|
8
|
+
The data-collections extension gives your app read/write access to the **items** in its own
|
|
9
|
+
collections — `items.query/insert/update` work with no extra scope. It does **not** grant the
|
|
10
|
+
collection-*management* API: `collections.listDataCollections()` and friends answer 403 unless the
|
|
11
|
+
app holds a Data Collections management scope.
|
|
12
|
+
|
|
13
|
+
That asymmetry is worth knowing before you debug: a page whose table loads rows has proved its
|
|
14
|
+
collection exists, because Wix Data errors on a missing collection rather than returning empty. If
|
|
15
|
+
that same page cannot list collections, the app is missing a management scope — a separate fact
|
|
16
|
+
about tooling, not evidence about the collection.
|
|
17
|
+
|
|
18
|
+
## Reading the collection from a dashboard page
|
|
19
|
+
|
|
20
|
+
A page over a CMS collection is an ordinary collection page: the template is
|
|
21
|
+
[DRAFT_TEMPLATE_COLLECTION.md](../dashboard-page/DRAFT_TEMPLATE_COLLECTION.md), and its `fetchData`
|
|
22
|
+
calls `@wix/data` `items.query()` — see [WIX_DATA.md](WIX_DATA.md) for the query, result and paging
|
|
23
|
+
shapes. You write the filters and the columns yourself, exactly as for a vertical SDK.
|
|
24
|
+
|
|
25
|
+
## The site must have CMS, or nothing is created at all
|
|
26
|
+
|
|
27
|
+
**The installing site needs the CMS (Content Manager) app.** Per the extension's own docs:
|
|
28
|
+
"Without it, collections added by the extension won't appear after installation." Nothing warns
|
|
29
|
+
you — the release succeeds, the update succeeds, and the collection silently never exists. Bundle
|
|
30
|
+
CMS as an [app dependency](https://dev.wix.com/docs/build-apps/launch-your-app/market-listing/add-app-dependencies)
|
|
31
|
+
so installing your app brings it, and list "add CMS to the site" under
|
|
32
|
+
[Manual Steps Required](../../SKILL.md#-manual-steps-required) for any site that may not have it.
|
|
33
|
+
|
|
34
|
+
This is the first thing to check when a collection is missing after a correct release and update.
|
|
35
|
+
|
|
36
|
+
## The extension does not create the collection
|
|
37
|
+
|
|
38
|
+
Scaffolding the extension, compiling, and even releasing all leave the site's CMS unchanged.
|
|
39
|
+
A collection appears only when the app is **installed or updated on the site** with a version that
|
|
40
|
+
contains the extension — and any change under `data-collections/` needs a **major** version:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npx wix release --version-type major -c "<what changed>"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Releasing is only half of it. **Report both remaining browser steps under
|
|
47
|
+
[Manual Steps Required](../../SKILL.md#-manual-steps-required)** — they are the difference between a
|
|
48
|
+
page that works and one that shows an empty table:
|
|
49
|
+
|
|
50
|
+
1. Update the app on the site to the new version.
|
|
51
|
+
2. Wait up to 5 minutes for propagation.
|
|
52
|
+
|
|
53
|
+
A dev server running a version override does not create collections either, so "I ran `wix dev` and
|
|
54
|
+
the collection isn't in the CMS" is this step, not a bug.
|
|
55
|
+
|
|
56
|
+
## App Version Updates
|
|
57
|
+
|
|
58
|
+
Changes to your data collections extension require releasing a new major version of your app. When a user updates to the new major version, their collections are updated as follows:
|
|
59
|
+
|
|
60
|
+
- **Adding a new collection:** The new collection is created on the site.
|
|
61
|
+
- **Removing a collection:** If the old app version defined a collection and the new version doesn't, the collection is removed from the site.
|
|
62
|
+
- **Modifying a collection schema:** Field additions, removals, and type changes are applied to the collection. Existing data is preserved.
|
|
63
|
+
|
|
64
|
+
**Important notes:**
|
|
65
|
+
|
|
66
|
+
- Collection changes only affect users who update to the new major version. Users who don't update retain their current collections.
|
|
67
|
+
- Collection changes take up to 5 minutes to propagate after an update.
|
|
68
|
+
- **Initial data is only imported when a collection is first created.** If a collection already contains data, `initialData` is ignored during updates.
|