@nextsparkjs/core 0.1.0-beta.187 → 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.d.ts +10 -1
- package/dist/components/dashboard/mobile/MobileTopBar.d.ts.map +1 -1
- package/dist/components/dashboard/mobile/MobileTopBar.js +4 -3
- 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,100 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { cn } from '@nextsparkjs/core/lib/utils'
|
|
3
|
+
import { buildSectionClasses } from '@nextsparkjs/core/types/blocks'
|
|
4
|
+
import { sanitizeBlockHtml } from '@nextsparkjs/core/lib/blocks/sanitize-html'
|
|
5
|
+
import type { TextContentBlockProps } from './schema'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Text Content Block Component
|
|
9
|
+
*
|
|
10
|
+
* Props from 3-tab structure:
|
|
11
|
+
* - Content: title, content (rich-text), cta
|
|
12
|
+
* - Design: backgroundColor, maxWidth, alignment
|
|
13
|
+
* - Advanced: className, id
|
|
14
|
+
*
|
|
15
|
+
* Note: `content` is the main rich-text body of this block
|
|
16
|
+
*/
|
|
17
|
+
export function TextContentBlock({
|
|
18
|
+
// Base content props
|
|
19
|
+
title,
|
|
20
|
+
content,
|
|
21
|
+
cta,
|
|
22
|
+
// Base design props
|
|
23
|
+
backgroundColor,
|
|
24
|
+
// Text-content-specific design
|
|
25
|
+
maxWidth = 'lg',
|
|
26
|
+
alignment = 'left',
|
|
27
|
+
// Base advanced props
|
|
28
|
+
className,
|
|
29
|
+
id,
|
|
30
|
+
}: TextContentBlockProps) {
|
|
31
|
+
const maxWidthClasses: Record<string, string> = {
|
|
32
|
+
sm: 'max-w-2xl',
|
|
33
|
+
md: 'max-w-3xl',
|
|
34
|
+
lg: 'max-w-4xl',
|
|
35
|
+
xl: 'max-w-5xl',
|
|
36
|
+
full: 'max-w-none',
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const alignmentClasses: Record<string, string> = {
|
|
40
|
+
left: 'text-left',
|
|
41
|
+
center: 'text-center mx-auto',
|
|
42
|
+
right: 'text-right ml-auto',
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Build section classes with background and custom className
|
|
46
|
+
const sectionClasses = buildSectionClasses(
|
|
47
|
+
'py-16 px-4 @md:py-24',
|
|
48
|
+
{ backgroundColor, className }
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<section id={id} className={sectionClasses} data-cy="block-text-content">
|
|
53
|
+
<div className="container mx-auto">
|
|
54
|
+
{/* Optional Section Title */}
|
|
55
|
+
{title && (
|
|
56
|
+
<div className={cn(
|
|
57
|
+
'mb-8',
|
|
58
|
+
maxWidthClasses[maxWidth],
|
|
59
|
+
alignmentClasses[alignment]
|
|
60
|
+
)}>
|
|
61
|
+
<h2 className="text-3xl font-bold @md:text-4xl">
|
|
62
|
+
{title}
|
|
63
|
+
</h2>
|
|
64
|
+
</div>
|
|
65
|
+
)}
|
|
66
|
+
|
|
67
|
+
{/* Rich Text Content */}
|
|
68
|
+
<div
|
|
69
|
+
className={cn(
|
|
70
|
+
'prose prose-lg dark:prose-invert',
|
|
71
|
+
maxWidthClasses[maxWidth],
|
|
72
|
+
alignmentClasses[alignment]
|
|
73
|
+
)}
|
|
74
|
+
dangerouslySetInnerHTML={{ __html: sanitizeBlockHtml(content) }}
|
|
75
|
+
/>
|
|
76
|
+
|
|
77
|
+
{/* Optional CTA */}
|
|
78
|
+
{cta && (
|
|
79
|
+
<div className={cn(
|
|
80
|
+
'mt-8',
|
|
81
|
+
maxWidthClasses[maxWidth],
|
|
82
|
+
alignmentClasses[alignment]
|
|
83
|
+
)}>
|
|
84
|
+
<a
|
|
85
|
+
href={cta.link}
|
|
86
|
+
target={cta.target}
|
|
87
|
+
rel={cta.target === '_blank' ? 'noopener noreferrer' : undefined}
|
|
88
|
+
className="inline-flex items-center justify-center rounded-md bg-primary px-8 py-3 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors"
|
|
89
|
+
>
|
|
90
|
+
{cta.text}
|
|
91
|
+
</a>
|
|
92
|
+
</div>
|
|
93
|
+
)}
|
|
94
|
+
</div>
|
|
95
|
+
</section>
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// The generated block registry imports this as the module's default.
|
|
100
|
+
export default TextContentBlock
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { BlockConfig } from '@nextsparkjs/core/types/blocks'
|
|
2
|
+
|
|
3
|
+
export const config: Omit<BlockConfig, 'schema' | 'fieldDefinitions' | 'Component' | 'examples'> = {
|
|
4
|
+
slug: 'text-content',
|
|
5
|
+
name: 'Text Content',
|
|
6
|
+
description: 'Rich text content block for paragraphs, lists, and formatted text',
|
|
7
|
+
category: 'content',
|
|
8
|
+
icon: 'FileText',
|
|
9
|
+
thumbnail: '/theme/blocks/text-content/thumbnail.png',
|
|
10
|
+
scope: ['pages']
|
|
11
|
+
}
|
|
@@ -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,
|
|
@@ -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
|
|
package/templates/contents/themes/starter/tests/cypress/e2e/api/entities/tasks/TaskAPIController.js
CHANGED
|
@@ -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/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": {
|
|
@@ -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'
|