@nextsparkjs/core 0.1.0-beta.188 → 0.1.0-beta.189
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/api/keys/ApiKeyDisplay.js +19 -19
- package/dist/components/api/keys/CreateApiKeyDialog.js +21 -21
- package/dist/components/app/layouts/PublicNavbar.d.ts.map +1 -1
- package/dist/components/app/layouts/PublicNavbar.js +34 -16
- package/dist/components/app/misc/ThemeToggle.d.ts.map +1 -1
- package/dist/components/app/misc/ThemeToggle.js +3 -4
- package/dist/components/auth/SessionCookieRefresher.d.ts +5 -0
- package/dist/components/auth/SessionCookieRefresher.d.ts.map +1 -1
- package/dist/components/auth/SessionCookieRefresher.js +7 -1
- package/dist/components/auth/forms/LoginForm.d.ts.map +1 -1
- package/dist/components/auth/forms/LoginForm.js +49 -12
- package/dist/components/auth/forms/SignupForm.d.ts.map +1 -1
- package/dist/components/auth/forms/SignupForm.js +4 -3
- package/dist/components/dashboard/block-editor/block-settings-panel.js +1 -1
- package/dist/components/dashboard/block-editor/floating-block-toolbar.js +1 -1
- package/dist/components/dashboard/block-editor/sortable-block.js +1 -1
- package/dist/components/dashboard/layouts/Sidebar.d.ts.map +1 -1
- package/dist/components/dashboard/layouts/Sidebar.js +8 -6
- package/dist/components/dashboard/layouts/TopNavbar.d.ts.map +1 -1
- package/dist/components/dashboard/layouts/TopNavbar.js +51 -54
- package/dist/components/dashboard/misc/NotificationsDropdown.d.ts.map +1 -1
- package/dist/components/dashboard/misc/NotificationsDropdown.js +17 -15
- package/dist/components/dashboard/misc/SearchDropdown.d.ts.map +1 -1
- package/dist/components/dashboard/misc/SearchDropdown.js +19 -22
- package/dist/components/dashboard/mobile/MobileBottomNav.js +1 -1
- package/dist/components/dashboard/mobile/MobileTopBar.js +2 -2
- package/dist/components/dashboard/navigation/DynamicNavigation.js +5 -5
- package/dist/components/devtools/BlockDetailViewer.js +1 -1
- package/dist/components/devtools/BlocksViewer.js +1 -1
- package/dist/components/entities/EntityChildManager.js +5 -5
- package/dist/components/entities/EntityDetailPage.d.ts.map +1 -1
- package/dist/components/entities/EntityDetailPage.js +16 -15
- package/dist/components/entities/EntityFieldRenderer.d.ts.map +1 -1
- package/dist/components/entities/EntityFieldRenderer.js +12 -7
- package/dist/components/entities/EntityPageHeader.js +5 -5
- package/dist/components/entities/ErrorBoundary.d.ts.map +1 -1
- package/dist/components/entities/ErrorBoundary.js +20 -21
- package/dist/components/entities/wrappers/EntityDetailWrapper.js +5 -5
- package/dist/components/entities/wrappers/EntityFormWrapper.js +2 -2
- package/dist/components/entities/wrappers/EntityListWrapper.js +3 -3
- package/dist/components/permissions/NoPermission.js +10 -10
- package/dist/components/public/pageBuilder/PageRenderer.d.ts.map +1 -1
- package/dist/components/public/pageBuilder/PageRenderer.js +2 -1
- package/dist/components/settings/SettingsPageSkeleton.js +4 -4
- package/dist/components/settings/layouts/SettingsSidebar.js +6 -6
- package/dist/components/shared/MultiSelectFilter.d.ts +3 -1
- package/dist/components/shared/MultiSelectFilter.d.ts.map +1 -1
- package/dist/components/shared/MultiSelectFilter.js +7 -3
- package/dist/components/shared/SearchInput.d.ts +2 -0
- package/dist/components/shared/SearchInput.d.ts.map +1 -1
- package/dist/components/shared/SearchInput.js +64 -6
- package/dist/components/ui/address-input.js +18 -18
- package/dist/components/ui/audio-upload.js +9 -9
- package/dist/components/ui/combobox.d.ts.map +1 -1
- package/dist/components/ui/combobox.js +4 -4
- package/dist/components/ui/country-select.d.ts.map +1 -1
- package/dist/components/ui/country-select.js +3 -3
- package/dist/components/ui/currency-select.d.ts.map +1 -1
- package/dist/components/ui/currency-select.js +3 -3
- package/dist/components/ui/dynamic-icon.d.ts.map +1 -1
- package/dist/components/ui/dynamic-icon.js +3 -2
- package/dist/components/ui/file-upload.js +7 -7
- package/dist/components/ui/image-upload.js +8 -8
- package/dist/components/ui/multi-select.d.ts +2 -1
- package/dist/components/ui/multi-select.d.ts.map +1 -1
- package/dist/components/ui/multi-select.js +4 -3
- package/dist/components/ui/phone-input.d.ts.map +1 -1
- package/dist/components/ui/phone-input.js +3 -3
- package/dist/components/ui/relation-display.js +1 -1
- package/dist/components/ui/simple-relation-select.d.ts +2 -1
- package/dist/components/ui/simple-relation-select.d.ts.map +1 -1
- package/dist/components/ui/simple-relation-select.js +7 -6
- package/dist/components/ui/tags-input.d.ts.map +1 -1
- package/dist/components/ui/tags-input.js +1 -1
- package/dist/components/ui/timezone-select.d.ts.map +1 -1
- package/dist/components/ui/timezone-select.js +3 -3
- package/dist/components/ui/user-display.js +4 -4
- package/dist/components/ui/user-select.d.ts.map +1 -1
- package/dist/components/ui/user-select.js +9 -9
- package/dist/components/ui/video-upload.js +9 -9
- package/dist/contexts/SubscriptionContext.d.ts.map +1 -1
- package/dist/contexts/SubscriptionContext.js +5 -1
- package/dist/contexts/TeamContext.d.ts.map +1 -1
- package/dist/contexts/TeamContext.js +83 -26
- package/dist/emails/otp-verification.d.ts.map +1 -1
- package/dist/emails/otp-verification.js +3 -2
- package/dist/hooks/useAccountPreferencesSync.d.ts +13 -0
- package/dist/hooks/useAccountPreferencesSync.d.ts.map +1 -0
- package/dist/hooks/useAccountPreferencesSync.js +95 -0
- package/dist/hooks/useAuth.d.ts +202 -15
- package/dist/hooks/useAuth.d.ts.map +1 -1
- package/dist/hooks/useAuth.js +49 -13
- package/dist/hooks/useEntityConfig.js +2 -2
- package/dist/hooks/useEntitySearch.js +10 -10
- package/dist/hooks/useNotifications.js +12 -12
- package/dist/hooks/usePrefetch.d.ts.map +1 -1
- package/dist/hooks/usePrefetch.js +6 -2
- package/dist/hooks/useSearch.js +15 -15
- package/dist/hooks/useSessionCookieRefresh.d.ts +18 -1
- package/dist/hooks/useSessionCookieRefresh.d.ts.map +1 -1
- package/dist/hooks/useSessionCookieRefresh.js +17 -4
- package/dist/hooks/useSessionHint.d.ts +12 -0
- package/dist/hooks/useSessionHint.d.ts.map +1 -0
- package/dist/hooks/useSessionHint.js +15 -0
- package/dist/hooks/useTranslationPreload.js +6 -6
- package/dist/i18n.d.ts +13 -0
- package/dist/i18n.d.ts.map +1 -1
- package/dist/i18n.js +2 -27
- package/dist/lib/actions/entity.actions.d.ts.map +1 -1
- package/dist/lib/actions/entity.actions.js +3 -2
- package/dist/lib/api/auth/dual-auth.d.ts +4 -1
- package/dist/lib/api/auth/dual-auth.d.ts.map +1 -1
- package/dist/lib/api/auth/dual-auth.js +5 -16
- package/dist/lib/api/entities.js +33 -33
- package/dist/lib/api/keys.d.ts +27 -27
- package/dist/lib/api/keys.js +27 -27
- package/dist/lib/auth/callback-url.d.ts +11 -0
- package/dist/lib/auth/callback-url.d.ts.map +1 -0
- package/dist/lib/auth/callback-url.js +14 -0
- package/dist/lib/auth/otp-config.d.ts +55 -0
- package/dist/lib/auth/otp-config.d.ts.map +1 -0
- package/dist/lib/auth/otp-config.js +48 -0
- package/dist/lib/auth/registration-helpers.d.ts.map +1 -1
- package/dist/lib/auth/registration-helpers.js +3 -1
- package/dist/lib/auth/session-hint.d.ts +31 -0
- package/dist/lib/auth/session-hint.d.ts.map +1 -0
- package/dist/lib/auth/session-hint.js +37 -0
- package/dist/lib/auth.d.ts.map +1 -1
- package/dist/lib/auth.js +6 -4
- package/dist/lib/blocks/loader.d.ts +3 -11
- package/dist/lib/blocks/loader.d.ts.map +1 -1
- package/dist/lib/blocks/loader.js +1 -9
- package/dist/lib/blocks/loader.server.d.ts +18 -0
- package/dist/lib/blocks/loader.server.d.ts.map +1 -0
- package/dist/lib/blocks/loader.server.js +11 -0
- package/dist/lib/blocks/sanitize-html.d.ts +31 -0
- package/dist/lib/blocks/sanitize-html.d.ts.map +1 -0
- package/dist/lib/blocks/sanitize-html.js +60 -0
- package/dist/lib/config/config-sync.d.ts +1 -0
- package/dist/lib/config/config-sync.d.ts.map +1 -1
- package/dist/lib/config/config-sync.js +4 -1
- package/dist/lib/config/types.d.ts +48 -0
- package/dist/lib/config/types.d.ts.map +1 -1
- package/dist/lib/email/types.d.ts +6 -0
- package/dist/lib/email/types.d.ts.map +1 -1
- package/dist/lib/entities/serialization.d.ts.map +1 -1
- package/dist/lib/entities/serialization.js +3 -6
- package/dist/lib/icons.d.ts +12 -0
- package/dist/lib/icons.d.ts.map +1 -0
- package/dist/lib/icons.js +30 -0
- package/dist/lib/locale.d.ts +25 -1
- package/dist/lib/locale.d.ts.map +1 -1
- package/dist/lib/locale.js +49 -35
- package/dist/lib/mcp/engine.js +1 -1
- package/dist/lib/mcp/errors.js +17 -17
- package/dist/lib/mcp/schema-builder.js +16 -16
- package/dist/lib/mcp/tool-generator.js +18 -18
- package/dist/lib/search-highlighting.d.ts +7 -0
- package/dist/lib/search-highlighting.d.ts.map +1 -1
- package/dist/lib/search-highlighting.js +6 -2
- package/dist/lib/selectors/core-selectors.d.ts +2 -0
- package/dist/lib/selectors/core-selectors.d.ts.map +1 -1
- package/dist/lib/selectors/domains/auth.selectors.d.ts +1 -0
- package/dist/lib/selectors/domains/auth.selectors.d.ts.map +1 -1
- package/dist/lib/selectors/domains/auth.selectors.js +1 -0
- package/dist/lib/selectors/domains/entities.selectors.d.ts +2 -0
- package/dist/lib/selectors/domains/entities.selectors.d.ts.map +1 -1
- package/dist/lib/selectors/domains/entities.selectors.js +2 -0
- package/dist/lib/selectors/selectors.d.ts +4 -0
- package/dist/lib/selectors/selectors.d.ts.map +1 -1
- package/dist/lib/services/block.service.js +1 -1
- package/dist/lib/teams/active-team-cookie.d.ts +24 -0
- package/dist/lib/teams/active-team-cookie.d.ts.map +1 -0
- package/dist/lib/teams/active-team-cookie.js +17 -0
- package/dist/lib/teams/dashboard-team.d.ts +20 -0
- package/dist/lib/teams/dashboard-team.d.ts.map +1 -0
- package/dist/lib/teams/dashboard-team.js +38 -0
- package/dist/lib/teams/schema.d.ts.map +1 -1
- package/dist/lib/teams/schema.js +1 -1
- package/dist/lib/template-resolver.d.ts.map +1 -1
- package/dist/lib/template-resolver.js +0 -1
- package/dist/lib/theme/get-default-theme-mode.d.ts +7 -4
- package/dist/lib/theme/get-default-theme-mode.d.ts.map +1 -1
- package/dist/lib/theme/get-default-theme-mode.js +2 -44
- package/dist/messages/de/auth.json +4 -2
- package/dist/messages/de/common.json +83 -3
- package/dist/messages/de/email.json +1 -1
- package/dist/messages/de/index.d.ts +87 -0
- package/dist/messages/de/index.d.ts.map +1 -1
- package/dist/messages/de/settings.json +5 -0
- package/dist/messages/en/auth.json +4 -2
- package/dist/messages/en/common.json +83 -3
- package/dist/messages/en/email.json +1 -1
- package/dist/messages/en/index.d.ts +86 -0
- package/dist/messages/en/index.d.ts.map +1 -1
- package/dist/messages/en/settings.json +4 -0
- package/dist/messages/es/auth.json +4 -2
- package/dist/messages/es/common.json +83 -3
- package/dist/messages/es/email.json +1 -1
- package/dist/messages/es/index.d.ts +86 -0
- package/dist/messages/es/index.d.ts.map +1 -1
- package/dist/messages/es/settings.json +4 -0
- package/dist/messages/fr/auth.json +4 -2
- package/dist/messages/fr/common.json +83 -3
- package/dist/messages/fr/email.json +1 -1
- package/dist/messages/fr/index.d.ts +87 -0
- package/dist/messages/fr/index.d.ts.map +1 -1
- package/dist/messages/fr/settings.json +5 -0
- package/dist/messages/it/auth.json +4 -2
- package/dist/messages/it/common.json +83 -3
- package/dist/messages/it/email.json +1 -1
- package/dist/messages/it/index.d.ts +87 -0
- package/dist/messages/it/index.d.ts.map +1 -1
- package/dist/messages/it/settings.json +5 -0
- package/dist/messages/pt/auth.json +4 -2
- package/dist/messages/pt/common.json +83 -3
- package/dist/messages/pt/email.json +1 -1
- package/dist/messages/pt/index.d.ts +87 -0
- package/dist/messages/pt/index.d.ts.map +1 -1
- package/dist/messages/pt/settings.json +5 -0
- package/dist/nextspark-registries.d.ts +54 -0
- package/dist/providers/DashboardProviders.d.ts +13 -10
- package/dist/providers/DashboardProviders.d.ts.map +1 -1
- package/dist/providers/DashboardProviders.js +7 -1
- package/dist/templates/app/(auth)/forgot-password/page.tsx +2 -2
- package/dist/templates/app/(auth)/reset-password/page.tsx +6 -6
- package/dist/templates/app/403/page.tsx +6 -6
- package/dist/templates/app/api/v1/teams/switch/route.ts +24 -5
- package/dist/templates/app/dashboard/(main)/[entity]/layout.tsx +9 -7
- package/dist/templates/app/dashboard/(main)/layout.tsx +4 -3
- package/dist/templates/app/dashboard/settings/api-keys/page.tsx +36 -34
- package/dist/templates/app/dashboard/settings/profile/page.tsx +7 -6
- package/dist/templates/app/dashboard/settings/security/page.tsx +5 -4
- package/dist/templates/app/layout.ppr.tsx +8 -8
- package/dist/templates/app/layout.tsx +12 -17
- package/dist/templates/blocks/cta-section/component.tsx +5 -2
- package/dist/templates/blocks/cta-section/config.ts +3 -2
- package/dist/templates/blocks/cta-section/fields.ts +2 -2
- package/dist/templates/blocks/cta-section/schema.ts +2 -2
- package/dist/templates/blocks/features-grid/component.tsx +10 -2
- package/dist/templates/blocks/features-grid/config.ts +3 -2
- package/dist/templates/blocks/features-grid/fields.ts +2 -2
- package/dist/templates/blocks/features-grid/schema.ts +2 -2
- package/dist/templates/blocks/hero/component.tsx +6 -3
- package/dist/templates/blocks/hero/config.ts +3 -2
- package/dist/templates/blocks/hero/fields.ts +2 -2
- package/dist/templates/blocks/hero/schema.ts +2 -2
- package/dist/templates/blocks/testimonials/component.tsx +6 -3
- package/dist/templates/blocks/testimonials/config.ts +3 -2
- package/dist/templates/blocks/testimonials/fields.ts +2 -2
- package/dist/templates/blocks/testimonials/schema.ts +2 -2
- package/dist/templates/blocks/text-content/component.tsx +7 -3
- package/dist/templates/blocks/text-content/config.ts +3 -2
- package/dist/templates/blocks/text-content/fields.ts +2 -2
- package/dist/templates/blocks/text-content/schema.ts +2 -2
- package/dist/templates/contents/themes/starter/blocks/cta-section/component.tsx +102 -0
- package/dist/templates/contents/themes/starter/blocks/cta-section/config.ts +11 -0
- package/dist/templates/contents/themes/starter/blocks/cta-section/fields.ts +89 -0
- package/dist/templates/contents/themes/starter/blocks/cta-section/index.ts +6 -0
- package/dist/templates/contents/themes/starter/blocks/cta-section/schema.ts +32 -0
- package/dist/templates/contents/themes/starter/blocks/cta-section/thumbnail.png +0 -0
- package/dist/templates/contents/themes/starter/blocks/features-grid/component.tsx +119 -0
- package/dist/templates/contents/themes/starter/blocks/features-grid/config.ts +11 -0
- package/dist/templates/contents/themes/starter/blocks/features-grid/fields.ts +97 -0
- package/dist/templates/contents/themes/starter/blocks/features-grid/index.ts +6 -0
- package/dist/templates/contents/themes/starter/blocks/features-grid/schema.ts +40 -0
- package/dist/templates/contents/themes/starter/blocks/features-grid/thumbnail.png +0 -0
- package/dist/templates/contents/themes/starter/blocks/hero/component.tsx +105 -0
- package/dist/templates/contents/themes/starter/blocks/hero/config.ts +11 -0
- package/dist/templates/contents/themes/starter/blocks/hero/fields.ts +60 -0
- package/dist/templates/contents/themes/starter/blocks/hero/index.ts +6 -0
- package/dist/templates/contents/themes/starter/blocks/hero/schema.ts +33 -0
- package/dist/templates/contents/themes/starter/blocks/hero/thumbnail.png +0 -0
- package/dist/templates/contents/themes/starter/blocks/testimonials/component.tsx +116 -0
- package/dist/templates/contents/themes/starter/blocks/testimonials/config.ts +11 -0
- package/dist/templates/contents/themes/starter/blocks/testimonials/fields.ts +105 -0
- package/dist/templates/contents/themes/starter/blocks/testimonials/index.ts +6 -0
- package/dist/templates/contents/themes/starter/blocks/testimonials/schema.ts +41 -0
- package/dist/templates/contents/themes/starter/blocks/testimonials/thumbnail.png +0 -0
- package/dist/templates/contents/themes/starter/blocks/text-content/component.tsx +100 -0
- package/dist/templates/contents/themes/starter/blocks/text-content/config.ts +11 -0
- package/dist/templates/contents/themes/starter/blocks/text-content/fields.ts +88 -0
- package/dist/templates/contents/themes/starter/blocks/text-content/index.ts +6 -0
- package/dist/templates/contents/themes/starter/blocks/text-content/schema.ts +30 -0
- package/dist/templates/contents/themes/starter/blocks/text-content/thumbnail.png +0 -0
- package/dist/templates/contents/themes/starter/config/app.config.ts +8 -0
- package/dist/templates/contents/themes/starter/entities/tasks/tasks.config.ts +7 -0
- package/dist/templates/contents/themes/starter/tests/cypress/e2e/_utils/devtools/access.cy.ts +9 -1
- package/dist/templates/contents/themes/starter/tests/cypress/e2e/api/entities/tasks/TaskAPIController.js +2 -2
- package/dist/templates/contents/themes/starter/tests/cypress/e2e/uat/entities/tasks/tasks-crud.cy.ts +45 -38
- package/dist/templates/contents/themes/starter/tests/cypress/fixtures/entities.json +16 -0
- package/dist/templates/contents/themes/starter/tests/cypress/src/components/DevKeyringPOM.ts +3 -1
- package/dist/templates/contents/themes/starter/tests/cypress/src/core/BlockEditorBasePOM.ts +3 -3
- package/dist/templates/contents/themes/starter/tests/cypress/src/entities/PagesPOM.ts +137 -0
- package/dist/templates/contents/themes/starter/tests/cypress/src/entities/index.ts +2 -0
- package/dist/templates/contents/themes/starter/tests/cypress/src/index.ts +1 -0
- package/dist/templates/contents/themes/starter/tests/cypress/src/session-helpers.ts +42 -11
- package/dist/templates/contents/themes/starter/tests/cypress/support/commands.ts +29 -18
- package/dist/templates/features/blog/blocks/post-content/component.tsx +5 -1
- package/dist/templates/features/blog/blocks/post-content/schema.ts +1 -1
- package/dist/templates/features/pages/blocks/hero/component.tsx +3 -0
- package/dist/templates/features/pages/blocks/hero/schema.ts +1 -1
- package/dist/templates/proxy.ts +138 -53
- package/dist/types/blocks.d.ts.map +1 -1
- package/dist/types/blocks.js +1 -1
- package/dist/types/task.types.d.ts +1 -1
- package/dist/types/task.types.js +7 -7
- package/dist/utils/dev/TranslationDebugger.js +2 -2
- package/package.json +14 -5
- package/scripts/build/registry/__tests__/block-registry.test.mjs +73 -0
- package/scripts/build/registry/__tests__/icons-discovery.test.mjs +130 -0
- package/scripts/build/registry/__tests__/identifier.test.mjs +65 -0
- package/scripts/build/registry/__tests__/page-generator.test.mjs +430 -0
- package/scripts/build/registry/__tests__/scheduled-actions-registry.test.mjs +41 -0
- package/scripts/build/registry/__tests__/template-registry.test.mjs +89 -0
- package/scripts/build/registry/discovery/icons.mjs +275 -0
- package/scripts/build/registry/discovery/index.mjs +1 -0
- package/scripts/build/registry/generators/block-registry.mjs +203 -55
- package/scripts/build/registry/generators/feature-registry.mjs +9 -2
- package/scripts/build/registry/generators/icon-registry.mjs +56 -0
- package/scripts/build/registry/generators/identifier.mjs +28 -0
- package/scripts/build/registry/generators/index.mjs +1 -0
- package/scripts/build/registry/generators/plugin-registry.mjs +4 -3
- package/scripts/build/registry/generators/scheduled-actions-registry.mjs +4 -2
- package/scripts/build/registry/generators/template-registry.mjs +49 -41
- package/scripts/build/registry/generators/theme-registry.mjs +6 -7
- package/scripts/build/registry/post-build/page-generator.mjs +380 -59
- package/scripts/build/registry.mjs +9 -1
- package/templates/app/(auth)/forgot-password/page.tsx +2 -2
- package/templates/app/(auth)/reset-password/page.tsx +6 -6
- package/templates/app/403/page.tsx +6 -6
- package/templates/app/api/v1/teams/switch/route.ts +24 -5
- package/templates/app/dashboard/(main)/[entity]/layout.tsx +9 -7
- package/templates/app/dashboard/(main)/layout.tsx +4 -3
- package/templates/app/dashboard/settings/api-keys/page.tsx +36 -34
- package/templates/app/dashboard/settings/profile/page.tsx +7 -6
- package/templates/app/dashboard/settings/security/page.tsx +5 -4
- package/templates/app/layout.ppr.tsx +8 -8
- package/templates/app/layout.tsx +12 -17
- package/templates/blocks/cta-section/component.tsx +5 -2
- package/templates/blocks/cta-section/config.ts +3 -2
- package/templates/blocks/cta-section/fields.ts +2 -2
- package/templates/blocks/cta-section/schema.ts +2 -2
- package/templates/blocks/features-grid/component.tsx +10 -2
- package/templates/blocks/features-grid/config.ts +3 -2
- package/templates/blocks/features-grid/fields.ts +2 -2
- package/templates/blocks/features-grid/schema.ts +2 -2
- package/templates/blocks/hero/component.tsx +6 -3
- package/templates/blocks/hero/config.ts +3 -2
- package/templates/blocks/hero/fields.ts +2 -2
- package/templates/blocks/hero/schema.ts +2 -2
- package/templates/blocks/testimonials/component.tsx +6 -3
- package/templates/blocks/testimonials/config.ts +3 -2
- package/templates/blocks/testimonials/fields.ts +2 -2
- package/templates/blocks/testimonials/schema.ts +2 -2
- package/templates/blocks/text-content/component.tsx +7 -3
- package/templates/blocks/text-content/config.ts +3 -2
- package/templates/blocks/text-content/fields.ts +2 -2
- package/templates/blocks/text-content/schema.ts +2 -2
- package/templates/contents/themes/starter/blocks/cta-section/component.tsx +102 -0
- package/templates/contents/themes/starter/blocks/cta-section/config.ts +11 -0
- package/templates/contents/themes/starter/blocks/cta-section/fields.ts +89 -0
- package/templates/contents/themes/starter/blocks/cta-section/index.ts +6 -0
- package/templates/contents/themes/starter/blocks/cta-section/schema.ts +32 -0
- package/templates/contents/themes/starter/blocks/cta-section/thumbnail.png +0 -0
- package/templates/contents/themes/starter/blocks/features-grid/component.tsx +119 -0
- package/templates/contents/themes/starter/blocks/features-grid/config.ts +11 -0
- package/templates/contents/themes/starter/blocks/features-grid/fields.ts +97 -0
- package/templates/contents/themes/starter/blocks/features-grid/index.ts +6 -0
- package/templates/contents/themes/starter/blocks/features-grid/schema.ts +40 -0
- package/templates/contents/themes/starter/blocks/features-grid/thumbnail.png +0 -0
- package/templates/contents/themes/starter/blocks/hero/component.tsx +105 -0
- package/templates/contents/themes/starter/blocks/hero/config.ts +11 -0
- package/templates/contents/themes/starter/blocks/hero/fields.ts +60 -0
- package/templates/contents/themes/starter/blocks/hero/index.ts +6 -0
- package/templates/contents/themes/starter/blocks/hero/schema.ts +33 -0
- package/templates/contents/themes/starter/blocks/hero/thumbnail.png +0 -0
- package/templates/contents/themes/starter/blocks/testimonials/component.tsx +116 -0
- package/templates/contents/themes/starter/blocks/testimonials/config.ts +11 -0
- package/templates/contents/themes/starter/blocks/testimonials/fields.ts +105 -0
- package/templates/contents/themes/starter/blocks/testimonials/index.ts +6 -0
- package/templates/contents/themes/starter/blocks/testimonials/schema.ts +41 -0
- package/templates/contents/themes/starter/blocks/testimonials/thumbnail.png +0 -0
- package/templates/contents/themes/starter/blocks/text-content/component.tsx +100 -0
- package/templates/contents/themes/starter/blocks/text-content/config.ts +11 -0
- package/templates/contents/themes/starter/blocks/text-content/fields.ts +88 -0
- package/templates/contents/themes/starter/blocks/text-content/index.ts +6 -0
- package/templates/contents/themes/starter/blocks/text-content/schema.ts +30 -0
- package/templates/contents/themes/starter/blocks/text-content/thumbnail.png +0 -0
- package/templates/contents/themes/starter/config/app.config.ts +8 -0
- package/templates/contents/themes/starter/entities/tasks/tasks.config.ts +7 -0
- package/templates/contents/themes/starter/tests/cypress/e2e/_utils/devtools/access.cy.ts +9 -1
- package/templates/contents/themes/starter/tests/cypress/e2e/api/entities/tasks/TaskAPIController.js +2 -2
- package/templates/contents/themes/starter/tests/cypress/e2e/uat/entities/tasks/tasks-crud.cy.ts +45 -38
- package/templates/contents/themes/starter/tests/cypress/fixtures/entities.json +16 -0
- package/templates/contents/themes/starter/tests/cypress/src/components/DevKeyringPOM.ts +3 -1
- package/templates/contents/themes/starter/tests/cypress/src/core/BlockEditorBasePOM.ts +3 -3
- package/templates/contents/themes/starter/tests/cypress/src/entities/PagesPOM.ts +137 -0
- package/templates/contents/themes/starter/tests/cypress/src/entities/index.ts +2 -0
- package/templates/contents/themes/starter/tests/cypress/src/index.ts +1 -0
- package/templates/contents/themes/starter/tests/cypress/src/session-helpers.ts +42 -11
- package/templates/contents/themes/starter/tests/cypress/support/commands.ts +29 -18
- package/templates/features/blog/blocks/post-content/component.tsx +5 -1
- package/templates/features/blog/blocks/post-content/schema.ts +1 -1
- package/templates/features/pages/blocks/hero/component.tsx +3 -0
- package/templates/features/pages/blocks/hero/schema.ts +1 -1
- package/templates/proxy.ts +138 -53
- package/tests/jest/__mocks__/@nextsparkjs/registries/block-registry.client.ts +9 -0
- package/tests/jest/__mocks__/@nextsparkjs/registries/block-registry.lazy.ts +5 -0
- package/tests/jest/__mocks__/@nextsparkjs/registries/icon-registry.ts +42 -0
- package/tests/jest/__mocks__/next-intl-server.js +85 -5
- package/tests/jest/__mocks__/next-server.js +32 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { FieldDefinition } from '@nextsparkjs/core/types/blocks'
|
|
2
|
+
import {
|
|
3
|
+
baseContentFields,
|
|
4
|
+
baseDesignFields,
|
|
5
|
+
baseAdvancedFields,
|
|
6
|
+
} from '@nextsparkjs/core/types/blocks'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Text Content Block Field Definitions
|
|
10
|
+
*
|
|
11
|
+
* Organized into 3 tabs:
|
|
12
|
+
* - Content: title, cta (from base) + content (rich-text, replaces base content)
|
|
13
|
+
* - Design: backgroundColor (from base) + maxWidth, alignment
|
|
14
|
+
* - Advanced: className, id (from base)
|
|
15
|
+
*
|
|
16
|
+
* Note: The `content` field is overridden with a rich-text version
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
// Filter out base content field (we'll replace it with rich-text version)
|
|
20
|
+
const baseContentFieldsWithoutContent = baseContentFields.filter(
|
|
21
|
+
(field) => field.name !== 'content'
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
// Text-content-specific content fields (rich-text content)
|
|
25
|
+
const textContentFields: FieldDefinition[] = [
|
|
26
|
+
{
|
|
27
|
+
name: 'content',
|
|
28
|
+
label: 'Content',
|
|
29
|
+
type: 'rich-text',
|
|
30
|
+
tab: 'content',
|
|
31
|
+
required: true,
|
|
32
|
+
placeholder: 'Enter your content here...',
|
|
33
|
+
helpText: 'Rich text content with formatting support',
|
|
34
|
+
},
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
// Text-content-specific design fields
|
|
38
|
+
const textDesignFields: FieldDefinition[] = [
|
|
39
|
+
{
|
|
40
|
+
name: 'maxWidth',
|
|
41
|
+
label: 'Maximum Width',
|
|
42
|
+
type: 'select',
|
|
43
|
+
tab: 'design',
|
|
44
|
+
required: false,
|
|
45
|
+
default: 'lg',
|
|
46
|
+
helpText: 'Maximum content width',
|
|
47
|
+
options: [
|
|
48
|
+
{ label: 'Small (640px)', value: 'sm' },
|
|
49
|
+
{ label: 'Medium (768px)', value: 'md' },
|
|
50
|
+
{ label: 'Large (1024px)', value: 'lg' },
|
|
51
|
+
{ label: 'Extra Large (1280px)', value: 'xl' },
|
|
52
|
+
{ label: 'Full Width', value: 'full' },
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: 'alignment',
|
|
57
|
+
label: 'Text Alignment',
|
|
58
|
+
type: 'select',
|
|
59
|
+
tab: 'design',
|
|
60
|
+
required: false,
|
|
61
|
+
default: 'left',
|
|
62
|
+
helpText: 'Text alignment within the content area',
|
|
63
|
+
options: [
|
|
64
|
+
{ label: 'Left', value: 'left' },
|
|
65
|
+
{ label: 'Center', value: 'center' },
|
|
66
|
+
{ label: 'Right', value: 'right' },
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Complete field definitions organized by tab
|
|
73
|
+
*/
|
|
74
|
+
export const fieldDefinitions: FieldDefinition[] = [
|
|
75
|
+
// Content tab: base fields (without content) + rich-text content
|
|
76
|
+
...baseContentFieldsWithoutContent,
|
|
77
|
+
...textContentFields,
|
|
78
|
+
|
|
79
|
+
// Design tab: base fields + text-specific
|
|
80
|
+
...baseDesignFields,
|
|
81
|
+
...textDesignFields,
|
|
82
|
+
|
|
83
|
+
// Advanced tab: base fields only
|
|
84
|
+
...baseAdvancedFields,
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
// Alias for compatibility
|
|
88
|
+
export const fields = fieldDefinitions
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
import { baseBlockSchema } from '@nextsparkjs/core/types/blocks'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Text Content Block Schema
|
|
6
|
+
*
|
|
7
|
+
* Extends base schema with:
|
|
8
|
+
* - content: Rich text/HTML content (overrides base content with required)
|
|
9
|
+
* - maxWidth: Content width constraint
|
|
10
|
+
* - alignment: Text alignment
|
|
11
|
+
*
|
|
12
|
+
* Note: Uses base schema title, cta, backgroundColor, className, id
|
|
13
|
+
* The `content` field is overridden to be required and serves as rich-text body
|
|
14
|
+
*/
|
|
15
|
+
export const textContentSpecificSchema = z.object({
|
|
16
|
+
// Content: rich text body (overrides base optional content)
|
|
17
|
+
content: z.string().min(1, 'Content is required'),
|
|
18
|
+
|
|
19
|
+
// Design: layout options
|
|
20
|
+
maxWidth: z.enum(['sm', 'md', 'lg', 'xl', 'full']).default('lg'),
|
|
21
|
+
alignment: z.enum(['left', 'center', 'right']).default('left'),
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Complete Text Content Block Schema
|
|
26
|
+
* Note: textContentSpecificSchema.content overrides baseBlockSchema.content
|
|
27
|
+
*/
|
|
28
|
+
export const schema = baseBlockSchema.extend(textContentSpecificSchema.shape)
|
|
29
|
+
|
|
30
|
+
export type TextContentBlockProps = z.infer<typeof schema>
|
|
@@ -134,6 +134,14 @@ export const APP_CONFIG_OVERRIDES = {
|
|
|
134
134
|
// expiresIn: 60 * 60 * 24 * 90, // 90 days
|
|
135
135
|
// updateAge: 60 * 60 * 24 * 7, // renew weekly
|
|
136
136
|
// },
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Email OTP code lifetime (seconds) and length (digits) — defaults: 300
|
|
140
|
+
* (5 minutes) / 6. Drives the `emailOTP` plugin, the login form's
|
|
141
|
+
* countdown, and the OTP email's "expires in" notice together, so they
|
|
142
|
+
* can't drift apart:
|
|
143
|
+
*/
|
|
144
|
+
// otp: { expiresIn: 60 * 10, otpLength: 6 },
|
|
137
145
|
/**
|
|
138
146
|
* Whether Better Auth automatically sends the verification email on signup.
|
|
139
147
|
*
|
|
@@ -38,6 +38,13 @@ export const taskEntityConfig: EntityConfig = {
|
|
|
38
38
|
dashboard: {
|
|
39
39
|
showInMenu: true,
|
|
40
40
|
showInTopbar: true,
|
|
41
|
+
// `filterable` below turns the feature on; this says what to filter by.
|
|
42
|
+
// Without it the list renders no filter controls at all, which is what
|
|
43
|
+
// the UAT specs (and the cypress entities fixture) already expect.
|
|
44
|
+
filters: [
|
|
45
|
+
{ field: 'status', type: 'multiSelect' },
|
|
46
|
+
{ field: 'priority', type: 'multiSelect' },
|
|
47
|
+
],
|
|
41
48
|
},
|
|
42
49
|
public: {
|
|
43
50
|
hasArchivePage: false,
|
package/dist/templates/contents/themes/starter/tests/cypress/e2e/_utils/devtools/access.cy.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
loginAsDefaultDeveloper,
|
|
7
7
|
loginAsDefaultSuperadmin,
|
|
8
8
|
loginAsDefaultMember,
|
|
9
|
+
hasSeededTeamRoleUser,
|
|
9
10
|
CORE_USERS
|
|
10
11
|
} from '../../../src/session-helpers'
|
|
11
12
|
|
|
@@ -145,7 +146,14 @@ describe('DevTools - Access Control', {
|
|
|
145
146
|
})
|
|
146
147
|
})
|
|
147
148
|
|
|
148
|
-
|
|
149
|
+
// Needs a user with a plain team role, which the starter does not seed — it
|
|
150
|
+
// creates superadmin and developer only. ACCESS-006 above already covers a
|
|
151
|
+
// non-developer being blocked, using a user that does exist, so skipping this
|
|
152
|
+
// leaves no path untested. A theme that seeds team members sets MEMBER_EMAIL
|
|
153
|
+
// and it runs.
|
|
154
|
+
const memberSuite = hasSeededTeamRoleUser('MEMBER') ? describe : describe.skip
|
|
155
|
+
|
|
156
|
+
memberSuite('ACCESS-007: Member is BLOCKED from /devtools', { tags: '@smoke' }, () => {
|
|
149
157
|
it('should redirect member to /dashboard when attempting to access /devtools', { tags: '@smoke' }, () => {
|
|
150
158
|
allure.severity('critical')
|
|
151
159
|
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* - API Key with tasks:read, tasks:write scopes (or superadmin with *)
|
|
7
7
|
* - x-team-id header for team context
|
|
8
8
|
*/
|
|
9
|
-
const BaseAPIController = require('
|
|
10
|
-
const entitiesConfig = require('
|
|
9
|
+
const BaseAPIController = require('../../../../src/controllers/BaseAPIController')
|
|
10
|
+
const entitiesConfig = require('../../../../fixtures/entities.json')
|
|
11
11
|
|
|
12
12
|
const { slug } = entitiesConfig.entities.tasks
|
|
13
13
|
|
package/dist/templates/contents/themes/starter/tests/cypress/e2e/uat/entities/tasks/tasks-crud.cy.ts
CHANGED
|
@@ -38,24 +38,13 @@ describe('Tasks CRUD', { tags: ['@uat', '@tasks', '@crud'] }, () => {
|
|
|
38
38
|
})
|
|
39
39
|
|
|
40
40
|
afterEach(() => {
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
url: `/api/v1/tasks/${id}`,
|
|
49
|
-
headers: {
|
|
50
|
-
'Content-Type': 'application/json',
|
|
51
|
-
'x-team-id': teamId || ''
|
|
52
|
-
},
|
|
53
|
-
failOnStatusCode: false
|
|
54
|
-
})
|
|
55
|
-
})
|
|
56
|
-
createdTaskIds = []
|
|
57
|
-
})
|
|
58
|
-
}
|
|
41
|
+
// Through the command rather than a request built here: it resolves the
|
|
42
|
+
// team the API requires even before a dashboard visit has put it in
|
|
43
|
+
// localStorage. Sending an empty `x-team-id` gets a 400 that nothing
|
|
44
|
+
// reports, and the tasks survive into the next test, where a count of rows
|
|
45
|
+
// then measures the leftovers instead of what that test created.
|
|
46
|
+
createdTaskIds.forEach((id) => cy.deleteTask(id))
|
|
47
|
+
createdTaskIds = []
|
|
59
48
|
})
|
|
60
49
|
|
|
61
50
|
// ============================================================
|
|
@@ -75,7 +64,9 @@ describe('Tasks CRUD', { tags: ['@uat', '@tasks', '@crud'] }, () => {
|
|
|
75
64
|
tasks.fillTaskForm(taskData)
|
|
76
65
|
tasks.submitForm()
|
|
77
66
|
|
|
78
|
-
//
|
|
67
|
+
// Saving lands on the detail page, so reaching the list is a separate
|
|
68
|
+
// visit. What this test is about is the task existing and showing there.
|
|
69
|
+
tasks.visitList()
|
|
79
70
|
tasks.waitForList()
|
|
80
71
|
tasks.assertTaskInList(taskData.title)
|
|
81
72
|
})
|
|
@@ -93,6 +84,7 @@ describe('Tasks CRUD', { tags: ['@uat', '@tasks', '@crud'] }, () => {
|
|
|
93
84
|
tasks.fillTaskForm(taskData)
|
|
94
85
|
tasks.submitForm()
|
|
95
86
|
|
|
87
|
+
tasks.visitList()
|
|
96
88
|
tasks.waitForList()
|
|
97
89
|
tasks.assertTaskInList(taskData.title)
|
|
98
90
|
})
|
|
@@ -141,6 +133,9 @@ describe('Tasks CRUD', { tags: ['@uat', '@tasks', '@crud'] }, () => {
|
|
|
141
133
|
|
|
142
134
|
it('should navigate to task detail page', () => {
|
|
143
135
|
cy.then(() => {
|
|
136
|
+
tasks.visitList()
|
|
137
|
+
tasks.waitForList()
|
|
138
|
+
|
|
144
139
|
tasks.clickRow(testTaskId)
|
|
145
140
|
tasks.waitForDetail()
|
|
146
141
|
|
|
@@ -195,7 +190,10 @@ describe('Tasks CRUD', { tags: ['@uat', '@tasks', '@crud'] }, () => {
|
|
|
195
190
|
tasks.fillTextField('title', newTitle)
|
|
196
191
|
tasks.submitForm()
|
|
197
192
|
|
|
193
|
+
tasks.waitForDetail()
|
|
194
|
+
|
|
198
195
|
// Verify update
|
|
196
|
+
tasks.visitList()
|
|
199
197
|
tasks.waitForList()
|
|
200
198
|
tasks.assertTaskInList(newTitle)
|
|
201
199
|
tasks.assertTaskNotInList(originalTitle)
|
|
@@ -211,6 +209,9 @@ describe('Tasks CRUD', { tags: ['@uat', '@tasks', '@crud'] }, () => {
|
|
|
211
209
|
tasks.selectOption('status', 'done')
|
|
212
210
|
tasks.submitForm()
|
|
213
211
|
|
|
212
|
+
tasks.waitForDetail()
|
|
213
|
+
|
|
214
|
+
tasks.visitList()
|
|
214
215
|
tasks.waitForList()
|
|
215
216
|
// Task should now show as done
|
|
216
217
|
tasks.assertTaskInList(originalTitle)
|
|
@@ -226,6 +227,9 @@ describe('Tasks CRUD', { tags: ['@uat', '@tasks', '@crud'] }, () => {
|
|
|
226
227
|
tasks.selectOption('priority', 'urgent')
|
|
227
228
|
tasks.submitForm()
|
|
228
229
|
|
|
230
|
+
tasks.waitForDetail()
|
|
231
|
+
|
|
232
|
+
tasks.visitList()
|
|
229
233
|
tasks.waitForList()
|
|
230
234
|
tasks.assertTaskInList(originalTitle)
|
|
231
235
|
})
|
|
@@ -312,47 +316,49 @@ describe('Tasks CRUD', { tags: ['@uat', '@tasks', '@crud'] }, () => {
|
|
|
312
316
|
})
|
|
313
317
|
})
|
|
314
318
|
|
|
315
|
-
//
|
|
316
|
-
|
|
319
|
+
// The list, not a reload: `cy.reload()` keeps the current URL, so a filter
|
|
320
|
+
// the previous test left in the query string is still applied here.
|
|
321
|
+
tasks.visitList()
|
|
317
322
|
tasks.waitForList()
|
|
318
323
|
})
|
|
319
324
|
|
|
320
325
|
it('should filter tasks by status', () => {
|
|
321
|
-
// Filter by "todo" status
|
|
322
326
|
tasks.filterByStatus('todo')
|
|
323
327
|
|
|
324
|
-
//
|
|
325
|
-
|
|
328
|
+
// The filter travels in the URL, and waiting on that is what settles the
|
|
329
|
+
// list: asserting row by row while the table is still refetching detaches
|
|
330
|
+
// the very rows being checked.
|
|
331
|
+
cy.url().should('include', 'status=todo')
|
|
332
|
+
cy.get(tasks.selectors.rowGeneric).should('have.length.greaterThan', 0)
|
|
326
333
|
|
|
327
|
-
//
|
|
334
|
+
// A row shows the option's label, never the stored value.
|
|
328
335
|
cy.get(tasks.selectors.rowGeneric).each(($row) => {
|
|
329
|
-
cy.wrap($row).should('contain.text', '
|
|
336
|
+
cy.wrap($row).should('contain.text', 'To Do')
|
|
330
337
|
})
|
|
331
338
|
})
|
|
332
339
|
|
|
333
340
|
it('should filter tasks by priority', () => {
|
|
334
|
-
// Filter by "high" priority
|
|
335
341
|
tasks.filterByPriority('high')
|
|
336
342
|
|
|
337
|
-
|
|
338
|
-
cy.
|
|
343
|
+
cy.url().should('include', 'priority=high')
|
|
344
|
+
cy.get(tasks.selectors.rowGeneric).should('have.length.greaterThan', 0)
|
|
339
345
|
|
|
340
|
-
// Should show only high priority tasks
|
|
341
346
|
cy.get(tasks.selectors.rowGeneric).each(($row) => {
|
|
342
|
-
cy.wrap($row).should('contain.text', '
|
|
347
|
+
cy.wrap($row).should('contain.text', 'High')
|
|
343
348
|
})
|
|
344
349
|
})
|
|
345
350
|
|
|
346
351
|
it('should clear filters', () => {
|
|
347
|
-
// Apply filter
|
|
348
352
|
tasks.filterByStatus('todo')
|
|
349
|
-
|
|
353
|
+
// The filter travels in the URL, and waiting on that is what settles the
|
|
354
|
+
// list — a fixed wait counts rows mid-refetch and sees a partial table.
|
|
355
|
+
cy.url().should('include', 'status=todo')
|
|
350
356
|
|
|
351
|
-
// Clear filter
|
|
352
357
|
tasks.clearStatusFilter()
|
|
353
|
-
cy.
|
|
358
|
+
cy.url().should('not.include', 'status=')
|
|
354
359
|
|
|
355
|
-
//
|
|
360
|
+
// The three the beforeEach created: the starter seeds no tasks, so any
|
|
361
|
+
// higher number would be counting on a previous run's leftovers.
|
|
356
362
|
cy.get(tasks.selectors.rowGeneric).should('have.length.at.least', 3)
|
|
357
363
|
})
|
|
358
364
|
})
|
|
@@ -388,8 +394,9 @@ describe('Tasks CRUD', { tags: ['@uat', '@tasks', '@crud'] }, () => {
|
|
|
388
394
|
}
|
|
389
395
|
})
|
|
390
396
|
|
|
391
|
-
//
|
|
392
|
-
|
|
397
|
+
// The list, not a reload: a search or filter left in the query string by
|
|
398
|
+
// the previous test would still be applied.
|
|
399
|
+
tasks.visitList()
|
|
393
400
|
tasks.waitForList()
|
|
394
401
|
})
|
|
395
402
|
|
|
@@ -15,6 +15,22 @@
|
|
|
15
15
|
"status",
|
|
16
16
|
"priority"
|
|
17
17
|
]
|
|
18
|
+
},
|
|
19
|
+
"pages": {
|
|
20
|
+
"slug": "pages",
|
|
21
|
+
"singular": "page",
|
|
22
|
+
"plural": "Pages",
|
|
23
|
+
"tableName": "pages",
|
|
24
|
+
"fields": [
|
|
25
|
+
"title",
|
|
26
|
+
"slug",
|
|
27
|
+
"status",
|
|
28
|
+
"locale"
|
|
29
|
+
],
|
|
30
|
+
"filters": [
|
|
31
|
+
"status"
|
|
32
|
+
],
|
|
33
|
+
"source": "theme"
|
|
18
34
|
}
|
|
19
35
|
},
|
|
20
36
|
"tasks": {
|
package/dist/templates/contents/themes/starter/tests/cypress/src/components/DevKeyringPOM.ts
CHANGED
|
@@ -118,7 +118,9 @@ export class DevKeyringPOM extends BasePOM {
|
|
|
118
118
|
this.submitLogin()
|
|
119
119
|
|
|
120
120
|
// 3. Wait for login to complete
|
|
121
|
-
|
|
121
|
+
// No explicit timeout: an inline one wins over the run's configuration, so a
|
|
122
|
+
// slow dev server could not be waited out with `--config defaultCommandTimeout`.
|
|
123
|
+
cy.url().should('include', '/dashboard')
|
|
122
124
|
|
|
123
125
|
return this
|
|
124
126
|
}
|
|
@@ -58,9 +58,9 @@ export abstract class BlockEditorBasePOM extends BasePOM {
|
|
|
58
58
|
return {
|
|
59
59
|
// Editor main
|
|
60
60
|
container: cySelector('blockEditor.container'),
|
|
61
|
-
titleInput: cySelector('blockEditor.titleInput'),
|
|
62
|
-
slugInput: cySelector('blockEditor.slugInput'),
|
|
63
|
-
saveButton: cySelector('blockEditor.saveButton'),
|
|
61
|
+
titleInput: cySelector('blockEditor.header.titleInput'),
|
|
62
|
+
slugInput: cySelector('blockEditor.header.slugInput'),
|
|
63
|
+
saveButton: cySelector('blockEditor.header.saveButton'),
|
|
64
64
|
statusBadge: cySelector('blockEditor.statusBadge'),
|
|
65
65
|
leftSidebarToggle: cySelector('blockEditor.leftSidebarToggle'),
|
|
66
66
|
viewModeToggle: cySelector('blockEditor.viewModeToggle'),
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PagesPOM - Page Object Model for Pages entity (List operations)
|
|
3
|
+
*
|
|
4
|
+
* Extends DashboardEntityPOM for list page operations.
|
|
5
|
+
* For editing pages with the block editor, use PageBuilderPOM from features/.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* // List operations
|
|
9
|
+
* PagesPOM.create()
|
|
10
|
+
* .visitList()
|
|
11
|
+
* .waitForList()
|
|
12
|
+
* .search('About Us')
|
|
13
|
+
* .selectFilter('status', 'published')
|
|
14
|
+
*
|
|
15
|
+
* // For editing pages, use PageBuilderPOM
|
|
16
|
+
* import { PageBuilderPOM } from '../features/PageBuilderPOM'
|
|
17
|
+
* PageBuilderPOM.create().visitEdit(pageId).setTitle('New Title').save()
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { DashboardEntityPOM } from '../core/DashboardEntityPOM'
|
|
21
|
+
import entitiesConfig from '../../fixtures/entities.json'
|
|
22
|
+
|
|
23
|
+
export interface PageListFilters {
|
|
24
|
+
status?: 'draft' | 'published' | 'archived'
|
|
25
|
+
locale?: 'en' | 'es'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export class PagesPOM extends DashboardEntityPOM {
|
|
29
|
+
constructor() {
|
|
30
|
+
super(entitiesConfig.entities.pages.slug)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ============================================
|
|
34
|
+
// FACTORY METHOD
|
|
35
|
+
// ============================================
|
|
36
|
+
|
|
37
|
+
static create(): PagesPOM {
|
|
38
|
+
return new PagesPOM()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ============================================
|
|
42
|
+
// PAGE-SPECIFIC LIST METHODS
|
|
43
|
+
// ============================================
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Filter pages by status
|
|
47
|
+
*/
|
|
48
|
+
filterByStatus(status: 'draft' | 'published' | 'archived') {
|
|
49
|
+
return this.selectFilter('status', status)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Apply multiple filters at once
|
|
54
|
+
*/
|
|
55
|
+
applyFilters(filters: PageListFilters) {
|
|
56
|
+
if (filters.status) {
|
|
57
|
+
this.filterByStatus(filters.status)
|
|
58
|
+
}
|
|
59
|
+
if (filters.locale) {
|
|
60
|
+
this.selectFilter('locale', filters.locale)
|
|
61
|
+
}
|
|
62
|
+
return this
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ============================================
|
|
66
|
+
// WORKFLOW METHODS
|
|
67
|
+
// ============================================
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Navigate to create page
|
|
71
|
+
* Note: Pages use block editor, so this redirects to the editor
|
|
72
|
+
*/
|
|
73
|
+
navigateToCreate() {
|
|
74
|
+
this.clickAdd()
|
|
75
|
+
return this
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Navigate to edit page for a page
|
|
80
|
+
* Note: Pages use block editor, so this redirects to the editor
|
|
81
|
+
*/
|
|
82
|
+
navigateToEdit(id: string) {
|
|
83
|
+
this.clickRowAction('edit', id)
|
|
84
|
+
return this
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Delete page from list with API waits
|
|
89
|
+
*/
|
|
90
|
+
deletePageWithApiWait(id: string) {
|
|
91
|
+
this.visitDetailWithApiWait(id)
|
|
92
|
+
this.clickDelete()
|
|
93
|
+
this.confirmDelete()
|
|
94
|
+
this.api.waitForDelete()
|
|
95
|
+
return this
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Delete page by finding it in the list by title
|
|
100
|
+
*/
|
|
101
|
+
deletePageByTitleWithApiWait(title: string) {
|
|
102
|
+
this.clickRowByText(title)
|
|
103
|
+
this.waitForDetail()
|
|
104
|
+
this.clickDelete()
|
|
105
|
+
this.confirmDelete()
|
|
106
|
+
this.api.waitForDelete()
|
|
107
|
+
return this
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ============================================
|
|
111
|
+
// ENTITY-SPECIFIC ASSERTIONS
|
|
112
|
+
// ============================================
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Assert page appears in list
|
|
116
|
+
*/
|
|
117
|
+
assertPageInList(title: string) {
|
|
118
|
+
return this.assertInList(title)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Assert page does not appear in list
|
|
123
|
+
*/
|
|
124
|
+
assertPageNotInList(title: string) {
|
|
125
|
+
return this.assertNotInList(title)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Assert page has specific status badge
|
|
130
|
+
*/
|
|
131
|
+
assertPageStatus(id: string, status: string) {
|
|
132
|
+
cy.get(this.selectors.row(id)).should('contain.text', status)
|
|
133
|
+
return this
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export default PagesPOM
|
|
@@ -4,9 +4,11 @@
|
|
|
4
4
|
* Page Object Models for specific entities:
|
|
5
5
|
* - TasksPOM: Tasks CRUD operations
|
|
6
6
|
* - PatternsPOM: Patterns CRUD operations with usage tracking (core entity)
|
|
7
|
+
* - PagesPOM: Pages CRUD operations (the block editor specs build on it)
|
|
7
8
|
*
|
|
8
9
|
* Add more entity POMs as you create new entities.
|
|
9
10
|
*/
|
|
10
11
|
|
|
11
12
|
export { TasksPOM, type TaskFormData } from './TasksPOM'
|
|
12
13
|
export { PatternsPOM } from './PatternsPOM'
|
|
14
|
+
export { PagesPOM } from './PagesPOM'
|
|
@@ -39,19 +39,50 @@ const SUPERADMIN_PASSWORD = Cypress.env('SUPERADMIN_PASSWORD') || 'Pandora1234'
|
|
|
39
39
|
const TEST_PASSWORD = Cypress.env('TEST_PASSWORD') || 'Test1234'
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
|
-
*
|
|
43
|
-
* Teams: Everpoint Labs, Ironvale Global, Riverstone Ventures
|
|
42
|
+
* Team-role test users.
|
|
44
43
|
*
|
|
45
|
-
*
|
|
44
|
+
* The starter seeds exactly two users (core migration 090): superadmin and
|
|
45
|
+
* developer. The names below come from the default theme's richer sample data,
|
|
46
|
+
* and every one of them has to be pointed at a real user through the matching
|
|
47
|
+
* env var before the specs that use it can run.
|
|
48
|
+
*
|
|
49
|
+
* OWNER is the exception, and it matters: it is what the CRUD specs log in as,
|
|
50
|
+
* so its fallback is the user the starter actually creates — superadmin owns
|
|
51
|
+
* the initial team. Leaving it on a name with no row made the whole UAT suite
|
|
52
|
+
* fail in session setup, before a single assertion.
|
|
46
53
|
*/
|
|
47
54
|
export const DEFAULT_THEME_USERS = {
|
|
48
|
-
OWNER: Cypress.env('OWNER_EMAIL') || '
|
|
55
|
+
OWNER: Cypress.env('OWNER_EMAIL') || 'superadmin@nextspark.dev',
|
|
49
56
|
ADMIN: Cypress.env('ADMIN_EMAIL') || 'james.wilson@nextspark.dev',
|
|
50
57
|
MEMBER: Cypress.env('MEMBER_EMAIL') || 'emily.johnson@nextspark.dev',
|
|
51
58
|
EDITOR: Cypress.env('EDITOR_EMAIL') || 'diego.ramirez@nextspark.dev',
|
|
52
59
|
VIEWER: Cypress.env('VIEWER_EMAIL') || 'sarah.davis@nextspark.dev',
|
|
53
60
|
} as const
|
|
54
61
|
|
|
62
|
+
/**
|
|
63
|
+
* The password that goes with OWNER.
|
|
64
|
+
*
|
|
65
|
+
* OWNER falls back to the seeded superadmin, and that user's password is the
|
|
66
|
+
* superadmin one, not the demo-user one. A theme that points OWNER at a user of
|
|
67
|
+
* its own sets OWNER_EMAIL, and then the demo password is the right default.
|
|
68
|
+
*/
|
|
69
|
+
const OWNER_PASSWORD =
|
|
70
|
+
Cypress.env('OWNER_PASSWORD') ||
|
|
71
|
+
(Cypress.env('OWNER_EMAIL') ? TEST_PASSWORD : SUPERADMIN_PASSWORD)
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Whether a non-owner team role points at a user that exists.
|
|
75
|
+
*
|
|
76
|
+
* Only OWNER has a seeded fallback. The other four keep the default theme's
|
|
77
|
+
* names, which resolve to nothing here until the theme seeds them and sets the
|
|
78
|
+
* matching env var. A spec that needs one guards on this instead of failing in
|
|
79
|
+
* session setup, where the error is a ten-second timeout on the Dev Keyring
|
|
80
|
+
* rather than "this user does not exist".
|
|
81
|
+
*/
|
|
82
|
+
export function hasSeededTeamRoleUser(role: 'ADMIN' | 'MEMBER' | 'EDITOR' | 'VIEWER'): boolean {
|
|
83
|
+
return Boolean(Cypress.env(`${role}_EMAIL`))
|
|
84
|
+
}
|
|
85
|
+
|
|
55
86
|
/**
|
|
56
87
|
* Core System Users (from core/migrations/090_sample_data.sql)
|
|
57
88
|
* These users have special global roles, not team-based roles
|
|
@@ -164,7 +195,7 @@ function apiLogin(email: string, password: string = TEST_PASSWORD): Cypress.Chai
|
|
|
164
195
|
*/
|
|
165
196
|
export function loginAsDefaultOwner() {
|
|
166
197
|
cy.session('default-owner-session', () => {
|
|
167
|
-
apiLogin(DEFAULT_THEME_USERS.OWNER).then((apiLoginSucceeded) => {
|
|
198
|
+
apiLogin(DEFAULT_THEME_USERS.OWNER, OWNER_PASSWORD).then((apiLoginSucceeded) => {
|
|
168
199
|
// If API login succeeded, we need to visit a page before setting localStorage
|
|
169
200
|
if (apiLoginSucceeded) {
|
|
170
201
|
cy.visit('/dashboard', { timeout: 60000 })
|
|
@@ -389,22 +420,22 @@ export function getThemeUsers() {
|
|
|
389
420
|
*/
|
|
390
421
|
export const BILLING_TEAMS = {
|
|
391
422
|
FREE: {
|
|
392
|
-
teamId: 'team-personal-carlos-001',
|
|
423
|
+
teamId: Cypress.env('BILLING_FREE_TEAM_ID') || 'team-personal-carlos-001',
|
|
393
424
|
name: 'Carlos Personal',
|
|
394
425
|
planSlug: 'free',
|
|
395
|
-
owner: 'carlos.mendoza@nextspark.dev'
|
|
426
|
+
owner: Cypress.env('BILLING_FREE_OWNER') || 'carlos.mendoza@nextspark.dev'
|
|
396
427
|
},
|
|
397
428
|
PRO: {
|
|
398
|
-
teamId: 'team-everpoint-001',
|
|
429
|
+
teamId: Cypress.env('BILLING_PRO_TEAM_ID') || 'team-everpoint-001',
|
|
399
430
|
name: 'Everpoint Labs',
|
|
400
431
|
planSlug: 'pro',
|
|
401
|
-
owner: 'carlos.mendoza@nextspark.dev'
|
|
432
|
+
owner: Cypress.env('BILLING_PRO_OWNER') || 'carlos.mendoza@nextspark.dev'
|
|
402
433
|
},
|
|
403
434
|
ENTERPRISE: {
|
|
404
|
-
teamId: 'team-ironvale-002',
|
|
435
|
+
teamId: Cypress.env('BILLING_ENTERPRISE_TEAM_ID') || 'team-ironvale-002',
|
|
405
436
|
name: 'Ironvale Global',
|
|
406
437
|
planSlug: 'enterprise',
|
|
407
|
-
owner: 'ana.garcia@nextspark.dev'
|
|
438
|
+
owner: Cypress.env('BILLING_ENTERPRISE_OWNER') || 'ana.garcia@nextspark.dev'
|
|
408
439
|
}
|
|
409
440
|
} as const
|
|
410
441
|
|