@antelopejs/dms 0.8.3 → 0.9.1
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/CHANGELOG.md +36 -0
- package/data/module-store/catalog.json +71 -0
- package/dist/config.d.ts +7 -0
- package/dist/config.js +8 -0
- package/dist/config.js.map +1 -1
- package/dist/implementations/dms/frontend-backend-proxies.d.ts +3 -0
- package/dist/implementations/dms/frontend-backend-proxies.js +39 -0
- package/dist/implementations/dms/frontend-backend-proxies.js.map +1 -0
- package/dist/implementations/dms/frontend-bootstrap.d.ts +1 -0
- package/dist/implementations/dms/frontend-bootstrap.js +13 -0
- package/dist/implementations/dms/frontend-bootstrap.js.map +1 -1
- package/dist/implementations/dms/frontend-modules.d.ts +6 -2
- package/dist/implementations/dms/frontend-modules.js +37 -8
- package/dist/implementations/dms/frontend-modules.js.map +1 -1
- package/dist/implementations/dms/frontend-ready.d.ts +8 -0
- package/dist/implementations/dms/frontend-ready.js +34 -0
- package/dist/implementations/dms/frontend-ready.js.map +1 -0
- package/dist/implementations/dms/manifest.d.ts +7 -0
- package/dist/implementations/dms/manifest.js +13 -0
- package/dist/implementations/dms/manifest.js.map +1 -1
- package/dist/implementations/dms/menu-categories.d.ts +16 -0
- package/dist/implementations/dms/menu-categories.js +30 -0
- package/dist/implementations/dms/menu-categories.js.map +1 -0
- package/dist/implementations/dms/nav-badges.d.ts +0 -8
- package/dist/implementations/dms/nav-badges.js +0 -16
- package/dist/implementations/dms/nav-badges.js.map +1 -1
- package/dist/implementations/dms/page.d.ts +13 -5
- package/dist/implementations/dms/page.js +72 -41
- package/dist/implementations/dms/page.js.map +1 -1
- package/dist/implementations/dms-html-render/index.js +5 -2
- package/dist/implementations/dms-html-render/index.js.map +1 -1
- package/dist/implementations/dms-notifications/index.d.ts +4 -3
- package/dist/implementations/dms-notifications/index.js +14 -6
- package/dist/implementations/dms-notifications/index.js.map +1 -1
- package/dist/pages/settings/settings-index.js +3 -2
- package/dist/pages/settings/settings-index.js.map +1 -1
- package/dist/pages/settings/users/invites.js +2 -2
- package/dist/pages/settings/users/invites.js.map +1 -1
- package/dist/pages/settings/users/member-change-notifications.js +17 -6
- package/dist/pages/settings/users/member-change-notifications.js.map +1 -1
- package/dist/pages/settings/users/member-invite-form.d.ts +3 -2
- package/dist/pages/settings/users/member-invite-form.js +7 -4
- package/dist/pages/settings/users/member-invite-form.js.map +1 -1
- package/dist/pages/settings/users/member-roles-field.js +2 -1
- package/dist/pages/settings/users/member-roles-field.js.map +1 -1
- package/dist/pages/settings/users/members.js +4 -1
- package/dist/pages/settings/users/members.js.map +1 -1
- package/dist/pages/settings/users/notifications.d.ts +6 -0
- package/dist/pages/settings/users/notifications.js +23 -15
- package/dist/pages/settings/users/notifications.js.map +1 -1
- package/dist/pages/settings/users/profile.js +1 -1
- package/dist/pages/settings/users/profile.js.map +1 -1
- package/dist/pages/settings/users/region-form.d.ts +1 -1
- package/dist/pages/settings/users/region-form.js +2 -1
- package/dist/pages/settings/users/region-form.js.map +1 -1
- package/dist/pages/settings/users/role-editor-store.d.ts +3 -1
- package/dist/pages/settings/users/role-editor-store.js +17 -4
- package/dist/pages/settings/users/role-editor-store.js.map +1 -1
- package/dist/pages/settings/users/roles.js +1 -0
- package/dist/pages/settings/users/roles.js.map +1 -1
- package/dist/realtime/registry.d.ts +1 -0
- package/dist/realtime/registry.js +5 -0
- package/dist/realtime/registry.js.map +1 -1
- package/dist/routes/index.d.ts +1 -0
- package/dist/routes/index.js +1 -0
- package/dist/routes/index.js.map +1 -1
- package/dist/routes/realtime.d.ts +5 -1
- package/dist/routes/realtime.js +16 -9
- package/dist/routes/realtime.js.map +1 -1
- package/dist/routes/store.d.ts +21 -0
- package/dist/routes/store.js +130 -0
- package/dist/routes/store.js.map +1 -0
- package/dist/store/activity.d.ts +2 -0
- package/dist/store/activity.js +12 -0
- package/dist/store/activity.js.map +1 -0
- package/dist/store/cache.d.ts +8 -0
- package/dist/store/cache.js +29 -0
- package/dist/store/cache.js.map +1 -0
- package/dist/store/catalog.d.ts +4 -0
- package/dist/store/catalog.js +69 -0
- package/dist/store/catalog.js.map +1 -0
- package/dist/store/compatibility.d.ts +3 -0
- package/dist/store/compatibility.js +45 -0
- package/dist/store/compatibility.js.map +1 -0
- package/dist/store/declarations.d.ts +18 -0
- package/dist/store/declarations.js +116 -0
- package/dist/store/declarations.js.map +1 -0
- package/dist/store/frontend-compatibility.d.ts +18 -0
- package/dist/store/frontend-compatibility.js +93 -0
- package/dist/store/frontend-compatibility.js.map +1 -0
- package/dist/store/interfaces.d.ts +6 -0
- package/dist/store/interfaces.js +126 -0
- package/dist/store/interfaces.js.map +1 -0
- package/dist/store/listing.d.ts +2 -0
- package/dist/store/listing.js +180 -0
- package/dist/store/listing.js.map +1 -0
- package/dist/store/operations.d.ts +8 -0
- package/dist/store/operations.js +254 -0
- package/dist/store/operations.js.map +1 -0
- package/dist/store/registry.d.ts +4 -0
- package/dist/store/registry.js +61 -0
- package/dist/store/registry.js.map +1 -0
- package/dist/store/requirements.d.ts +14 -0
- package/dist/store/requirements.js +81 -0
- package/dist/store/requirements.js.map +1 -0
- package/dist/store/runtime.d.ts +11 -0
- package/dist/store/runtime.js +78 -0
- package/dist/store/runtime.js.map +1 -0
- package/dist/store/tarball.d.ts +2 -0
- package/dist/store/tarball.js +80 -0
- package/dist/store/tarball.js.map +1 -0
- package/dist/store/types.d.ts +98 -0
- package/dist/store/types.js +3 -0
- package/dist/store/types.js.map +1 -0
- package/dist/test/integration/account-deletion.test.js +2 -2
- package/dist/test/integration/account-deletion.test.js.map +1 -1
- package/dist/test/integration/auth/auth-key-rotation.test.js +2 -1
- package/dist/test/integration/auth/auth-key-rotation.test.js.map +1 -1
- package/dist/test/integration/auth/current-password.test.js +2 -1
- package/dist/test/integration/auth/current-password.test.js.map +1 -1
- package/dist/test/integration/auth/session-revocation.test.js +2 -1
- package/dist/test/integration/auth/session-revocation.test.js.map +1 -1
- package/dist/test/integration/auth/sign-in-country.test.js +2 -1
- package/dist/test/integration/auth/sign-in-country.test.js.map +1 -1
- package/dist/test/integration/auth/two-factor-codes.test.js +2 -1
- package/dist/test/integration/auth/two-factor-codes.test.js.map +1 -1
- package/dist/test/integration/auth/two-factor-password.test.js +3 -2
- package/dist/test/integration/auth/two-factor-password.test.js.map +1 -1
- package/dist/test/integration/email-change.test.js +2 -1
- package/dist/test/integration/email-change.test.js.map +1 -1
- package/dist/test/integration/files/component-files.test.js +2 -2
- package/dist/test/integration/files/component-files.test.js.map +1 -1
- package/dist/test/integration/member-settings-access.test.js +8 -7
- package/dist/test/integration/member-settings-access.test.js.map +1 -1
- package/dist/test/integration/menu-access-events.test.d.ts +1 -0
- package/dist/test/integration/menu-access-events.test.js +148 -0
- package/dist/test/integration/menu-access-events.test.js.map +1 -0
- package/dist/test/integration/notification-inbox.test.js +4 -1
- package/dist/test/integration/notification-inbox.test.js.map +1 -1
- package/dist/test/integration/notification-locked-subjects.test.js +3 -2
- package/dist/test/integration/notification-locked-subjects.test.js.map +1 -1
- package/dist/test/integration/notification-unread-badge.test.js +51 -5
- package/dist/test/integration/notification-unread-badge.test.js.map +1 -1
- package/dist/test/integration/page-layout-route-guard.test.d.ts +1 -0
- package/dist/test/integration/page-layout-route-guard.test.js +56 -0
- package/dist/test/integration/page-layout-route-guard.test.js.map +1 -0
- package/dist/test/integration/permission-warnings.test.js +3 -2
- package/dist/test/integration/permission-warnings.test.js.map +1 -1
- package/dist/test/integration/removed-member-notifications.test.js +3 -2
- package/dist/test/integration/removed-member-notifications.test.js.map +1 -1
- package/dist/test/integration/role-delete-reassign.test.js +2 -1
- package/dist/test/integration/role-delete-reassign.test.js.map +1 -1
- package/dist/test/integration/role-permission-ancestors.test.js +2 -1
- package/dist/test/integration/role-permission-ancestors.test.js.map +1 -1
- package/dist/test/unit/frontend-bootstrap.test.js +13 -0
- package/dist/test/unit/frontend-bootstrap.test.js.map +1 -1
- package/dist/test/unit/implementations/dms/category-slug-registry.test.js +14 -5
- package/dist/test/unit/implementations/dms/category-slug-registry.test.js.map +1 -1
- package/dist/test/unit/implementations/dms/frontend-backend-proxies.test.d.ts +1 -0
- package/dist/test/unit/implementations/dms/frontend-backend-proxies.test.js +66 -0
- package/dist/test/unit/implementations/dms/frontend-backend-proxies.test.js.map +1 -0
- package/dist/test/unit/implementations/dms/manifest-strip.test.js +26 -0
- package/dist/test/unit/implementations/dms/manifest-strip.test.js.map +1 -1
- package/dist/test/unit/implementations/dms/nav-badges.test.js +23 -9
- package/dist/test/unit/implementations/dms/nav-badges.test.js.map +1 -1
- package/dist/test/unit/implementations/dms-html-render/generate-html.test.js +22 -4
- package/dist/test/unit/implementations/dms-html-render/generate-html.test.js.map +1 -1
- package/dist/test/unit/interfaces/dms/page-layout-query.test.js +12 -0
- package/dist/test/unit/interfaces/dms/page-layout-query.test.js.map +1 -1
- package/dist/test/unit/interfaces/dms/page-teardown.test.js +1 -1
- package/dist/test/unit/interfaces/dms/page-teardown.test.js.map +1 -1
- package/dist/test/unit/pages/settings/member-roles-field.test.js +1 -1
- package/dist/test/unit/pages/settings/member-roles-field.test.js.map +1 -1
- package/dist/test/unit/pages/settings/role-delete-confirm.test.js.map +1 -1
- package/dist/test/unit/realtime/menu-topics.test.d.ts +1 -0
- package/dist/test/unit/realtime/menu-topics.test.js +26 -0
- package/dist/test/unit/realtime/menu-topics.test.js.map +1 -0
- package/dist/test/unit/store/store.test.d.ts +1 -0
- package/dist/test/unit/store/store.test.js +127 -0
- package/dist/test/unit/store/store.test.js.map +1 -0
- package/dist/validation/store.schema.d.ts +39 -0
- package/dist/validation/store.schema.js +27 -0
- package/dist/validation/store.schema.js.map +1 -0
- package/frontend-vue/deferred-plugins.ts +3 -4
- package/frontend-vue/dms.email.ts +5 -1
- package/frontend-vue/dms.frontend.ts +15 -5
- package/frontend-vue/dms.server.ts +74 -0
- package/frontend-vue/layers/dms-auth/app/composables/useLogout.ts +1 -1
- package/frontend-vue/layers/dms-auth/app/composables/usePostLoginRedirect.ts +16 -3
- package/frontend-vue/layers/dms-auth/app/custom-pages/auth/2fa.vue +3 -1
- package/frontend-vue/layers/dms-auth/app/custom-pages/auth/backup.vue +3 -1
- package/frontend-vue/layers/dms-auth/app/custom-pages/auth/forgot-validation.vue +1 -1
- package/frontend-vue/layers/dms-auth/app/custom-pages/auth/oauth-complete.vue +26 -3
- package/frontend-vue/layers/dms-auth/app/custom-pages/auth/recover.vue +1 -1
- package/frontend-vue/layers/dms-auth/app/custom-pages/auth/signup.vue +22 -25
- package/frontend-vue/layers/dms-auth/app/custom-pages/auth/validate.vue +1 -1
- package/frontend-vue/layers/dms-auth/app/middleware/auth.ts +5 -7
- package/frontend-vue/layers/dms-auth/app/plugins/permissions-preload.ts +17 -0
- package/frontend-vue/layers/dms-auth/server/accounts.ts +135 -0
- package/frontend-vue/layers/dms-auth/server/actions.ts +251 -0
- package/frontend-vue/layers/dms-auth/server/oauth.ts +260 -0
- package/frontend-vue/layers/dms-auth/server/session.ts +158 -0
- package/frontend-vue/layers/dms-core/app/build/utils/asyncDataScope.ts +47 -0
- package/frontend-vue/layers/dms-core/app/build/utils/permission-preview.ts +6 -2
- package/frontend-vue/layers/dms-core/app/composables/auth/useApiData.ts +148 -0
- package/frontend-vue/layers/dms-core/app/composables/auth/useAuthFetch.ts +7 -20
- package/frontend-vue/layers/dms-core/app/composables/auth/useCurrentUser.ts +2 -2
- package/frontend-vue/layers/dms-core/app/composables/auth/useMultiAccount.ts +18 -5
- package/frontend-vue/layers/dms-core/app/composables/auth/usePermissions.ts +35 -6
- package/frontend-vue/layers/dms-core/app/composables/auth/useSessionRecovery.ts +1 -1
- package/frontend-vue/layers/dms-core/app/composables/period/compareResolvers.ts +20 -14
- package/frontend-vue/layers/dms-core/app/composables/period/periodClock.ts +121 -0
- package/frontend-vue/layers/dms-core/app/composables/period/periodRenderNow.ts +42 -0
- package/frontend-vue/layers/dms-core/app/composables/period/periodTimeZone.ts +31 -0
- package/frontend-vue/layers/dms-core/app/composables/period/presetResolvers.ts +48 -19
- package/frontend-vue/layers/dms-core/app/composables/period/usePeriod.ts +33 -4
- package/frontend-vue/layers/dms-core/app/composables/period/usePeriodScope.ts +78 -25
- package/frontend-vue/layers/dms-core/app/composables/realtime/usePageRealtime.ts +3 -0
- package/frontend-vue/layers/dms-core/app/composables/realtime/useUserRealtime.ts +36 -6
- package/frontend-vue/layers/dms-core/app/composables/user/useUserRegionalPreferences.ts +1 -1
- package/frontend-vue/layers/dms-core/app/plugins/async-data-scope.ts +26 -0
- package/frontend-vue/layers/dms-core/app/utils/pageRoutes.ts +22 -0
- package/frontend-vue/layers/dms-core/app/utils/regional.ts +36 -3
- package/frontend-vue/layers/dms-core/app/utils/trailingDeduper.ts +10 -1
- package/frontend-vue/layers/dms-core/shared/types/app-config.ts +48 -4
- package/frontend-vue/layers/dms-layout/app/app.config.ts +42 -23
- package/frontend-vue/layers/dms-layout/app/assets/css/main.css +72 -20
- package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardFrame.vue +9 -0
- package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardSidebar.vue +0 -3
- package/frontend-vue/layers/dms-layout/app/build/components/notification/NotificationPopover.vue +9 -3
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreDependencyPicker.vue +136 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreRequirements.vue +98 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreTile.vue +247 -29
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleTile.vue +19 -2
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/members/MemberRolePicker.vue +13 -12
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationInboxDisplay.vue +17 -7
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationPreferencesForm.vue +0 -1
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/profile/ProfilePersonalInfo.vue +36 -33
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/profile/ProfileSecuritySummary.vue +1 -2
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/role-types.ts +5 -4
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/security/SecuritySessions.vue +35 -28
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/security/SecurityStatus.vue +0 -1
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/security/SecurityTwoFactor.vue +1 -1
- package/frontend-vue/layers/dms-layout/app/build/composables/dev-reload/useDevReloadHolder.ts +7 -6
- package/frontend-vue/layers/dms-layout/app/build/composables/layout/sidePanelState.ts +1 -1
- package/frontend-vue/layers/dms-layout/app/build/composables/navigation/useVisitNavBadges.ts +26 -0
- package/frontend-vue/layers/dms-layout/app/build/composables/notification/useNotificationCatalog.ts +25 -23
- package/frontend-vue/layers/dms-layout/app/build/composables/notification/useNotificationPreferences.ts +44 -23
- package/frontend-vue/layers/dms-layout/app/build/composables/security/useSessionHandoff.ts +1 -1
- package/frontend-vue/layers/dms-layout/app/build/composables/settings/profile/preferencesSummary.ts +1 -1
- package/frontend-vue/layers/dms-layout/app/build/composables/settings/profile/useAccountData.ts +3 -2
- package/frontend-vue/layers/dms-layout/app/build/composables/settings/profile/useProfileAvatar.ts +1 -18
- package/frontend-vue/layers/dms-layout/app/build/composables/settings/profile/useProfilePreferences.ts +19 -23
- package/frontend-vue/layers/dms-layout/app/build/composables/settings/security/useSecurityFormat.ts +6 -3
- package/frontend-vue/layers/dms-layout/app/build/composables/settings/security/useSecurityOverview.ts +13 -18
- package/frontend-vue/layers/dms-layout/app/build/utils/module-store-catalog.ts +186 -120
- package/frontend-vue/layers/dms-layout/app/build/utils/module-store-install.ts +146 -0
- package/frontend-vue/layers/dms-layout/app/build/utils/modules-catalog.ts +8 -6
- package/frontend-vue/layers/dms-layout/app/build/utils/publicErrorMessage.ts +19 -0
- package/frontend-vue/layers/dms-layout/app/components/navigation/CollapsedMenuItem.vue +0 -11
- package/frontend-vue/layers/dms-layout/app/components/navigation/NavigationMenu.vue +3 -13
- package/frontend-vue/layers/dms-layout/app/composables/general/useSystemState.ts +7 -11
- package/frontend-vue/layers/dms-layout/app/composables/notification/useNotifications.ts +103 -22
- package/frontend-vue/layers/dms-layout/app/composables/page/useModuleStore.ts +109 -0
- package/frontend-vue/layers/dms-layout/app/composables/page/useModulesListing.ts +25 -102
- package/frontend-vue/layers/dms-layout/app/composables/page/usePageComponentPreload.ts +0 -10
- package/frontend-vue/layers/dms-layout/app/composables/page/useSiteLayout.ts +177 -96
- package/frontend-vue/layers/dms-layout/app/composables/profile/useUserLanguage.ts +3 -2
- package/frontend-vue/layers/dms-layout/app/custom-pages/modules.vue +341 -62
- package/frontend-vue/layers/dms-layout/app/emails/components/EmailLayout.vue +31 -11
- package/frontend-vue/layers/dms-layout/app/error.vue +5 -2
- package/frontend-vue/layers/dms-layout/app/middleware/module-routing.global.ts +1 -1
- package/frontend-vue/layers/dms-layout/app/middleware/page-leave-guard.global.ts +2 -2
- package/frontend-vue/layers/dms-layout/app/pages/[...slug].vue +12 -9
- package/frontend-vue/layers/dms-layout/app/plugins/dms-menu-sync.client.ts +31 -3
- package/frontend-vue/layers/dms-layout/app/plugins/favicon.ts +58 -0
- package/frontend-vue/layers/dms-layout/app/plugins/notification-stream.client.ts +15 -7
- package/frontend-vue/layers/dms-layout/app/plugins/profile-sync.client.ts +5 -1
- package/frontend-vue/layers/dms-layout/app/plugins/regional-preferences.ts +10 -4
- package/frontend-vue/layers/dms-layout/app/plugins/time-zone-cookie.client.ts +12 -0
- package/frontend-vue/layers/dms-layout/app/types/module-store.ts +134 -0
- package/frontend-vue/layers/dms-layout/app/types/page.ts +13 -0
- package/frontend-vue/layers/dms-layout/i18n/locales/layout-en-GB.json +107 -9
- package/frontend-vue/layers/dms-layout/i18n/locales/layout-fr-FR.json +107 -9
- package/frontend-vue/layers/dms-layout/server/html-render.ts +58 -0
- package/frontend-vue/layers/dms-layout/server/render-token.ts +95 -0
- package/frontend-vue/layers/dms-onboarding/app/composables/onboarding/useOnboarding.ts +25 -21
- package/frontend-vue/layers/dms-onboarding/app/middleware/onboarding.global.ts +1 -1
- package/frontend-vue/layers/dms-onboarding/app/plugins/onboarding-preload.ts +9 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerDefaults.ts +4 -1
- package/frontend-vue/layers/dms-ui/app/build/composables/files/useFileMetadata.ts +162 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/formRecordLoad.ts +23 -4
- package/frontend-vue/layers/dms-ui/app/build/composables/live/usePageDataRefresh.ts +101 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/navigation/useNavBadges.ts +33 -6
- package/frontend-vue/layers/dms-ui/app/build/composables/period/periodDisplay.ts +19 -16
- package/frontend-vue/layers/dms-ui/app/build/composables/period/periodQuery.ts +40 -20
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableFooter.ts +6 -8
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableListData.ts +42 -14
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableRows.ts +19 -8
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViews.ts +1 -1
- package/frontend-vue/layers/dms-ui/app/components/chart/ChartCard.vue +5 -2
- package/frontend-vue/layers/dms-ui/app/components/flow-canvas/FlowCanvas.vue +9 -9
- package/frontend-vue/layers/dms-ui/app/components/form/Form.vue +20 -18
- package/frontend-vue/layers/dms-ui/app/components/form/components/Cascader.vue +2 -1
- package/frontend-vue/layers/dms-ui/app/components/form/components/File.vue +26 -132
- package/frontend-vue/layers/dms-ui/app/components/form/components/Image.vue +40 -105
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputAddress.vue +2 -0
- package/frontend-vue/layers/dms-ui/app/components/form/components/Relation.vue +4 -4
- package/frontend-vue/layers/dms-ui/app/components/period/PeriodSelector.vue +9 -13
- package/frontend-vue/layers/dms-ui/app/components/table-view/CascaderPath.vue +2 -1
- package/frontend-vue/layers/dms-ui/app/components/table-view/FilePreview.vue +12 -24
- package/frontend-vue/layers/dms-ui/app/components/table-view/ImagePreview.vue +17 -29
- package/frontend-vue/layers/dms-ui/app/components/table-view/KanbanBoard.vue +7 -3
- package/frontend-vue/layers/dms-ui/app/components/table-view/TableView.vue +20 -8
- package/frontend-vue/layers/dms-ui/app/components/top-list/TopListCard.vue +8 -11
- package/frontend-vue/layers/dms-ui/app/composables/chart/useChartFetch.ts +146 -182
- package/frontend-vue/layers/dms-ui/app/composables/live/usePageLiveRefresh.ts +8 -2
- package/frontend-vue/layers/dms-ui/app/composables/useFileReadUrls.ts +11 -99
- package/frontend-vue/layers/dms-ui/app/utils/blockRefresh.ts +32 -3
- package/frontend-vue/package.json +3 -3
- package/frontend-vue/pnpm-lock.yaml +16 -22
- package/frontend-vue/server/private-options.ts +27 -0
- package/frontend-vue/tests/async-data-scope.test.ts +121 -0
- package/frontend-vue/tests/auth-middleware-error.test.ts +3 -3
- package/frontend-vue/tests/banner-block-fetch.test.ts +3 -0
- package/frontend-vue/tests/block-fetch-options-forwarding.test.ts +3 -0
- package/frontend-vue/tests/block-items-period-realtime.test.ts +3 -0
- package/frontend-vue/tests/block-not-found.test.ts +16 -2
- package/frontend-vue/tests/block-page-refresh.test.ts +3 -0
- package/frontend-vue/tests/block-route-params.test.ts +3 -0
- package/frontend-vue/tests/branding-defaults.test.ts +34 -0
- package/frontend-vue/tests/builtin-emails.test.ts +23 -2
- package/frontend-vue/tests/chart-live-pause.test.ts +4 -1
- package/frontend-vue/tests/chart-value-propagation.test.ts +4 -1
- package/frontend-vue/tests/composed-text-blocks.test.ts +3 -0
- package/frontend-vue/tests/email-layout.test.ts +66 -4
- package/frontend-vue/tests/error-page-message.test.ts +25 -2
- package/frontend-vue/tests/favicon.test.ts +131 -0
- package/frontend-vue/tests/file-fields-ssr.test.ts +145 -0
- package/frontend-vue/tests/file-read-urls.test.ts +145 -34
- package/frontend-vue/tests/file-unavailable.test.ts +5 -1
- package/frontend-vue/tests/fixtures/dataEngine.ts +44 -0
- package/frontend-vue/tests/form-load-error.test.ts +55 -1
- package/frontend-vue/tests/helpers/api-data-runtime.ts +77 -0
- package/frontend-vue/tests/image-hydration-ids.test.ts +21 -16
- package/frontend-vue/tests/image-reference-preservation.test.ts +59 -53
- package/frontend-vue/tests/input-number-adjust.test.ts +14 -0
- package/frontend-vue/tests/key-value-list-copy.test.ts +3 -0
- package/frontend-vue/tests/member-role-picker.test.ts +4 -2
- package/frontend-vue/tests/menu-sync-reconnect.test.ts +47 -0
- package/frontend-vue/tests/metadata-retry.test.ts +5 -1
- package/frontend-vue/tests/module-routing.test.ts +2 -5
- package/frontend-vue/tests/module-store-catalog.test.ts +270 -51
- package/frontend-vue/tests/modules-catalog.test.ts +17 -4
- package/frontend-vue/tests/modules-listing-transfer.test.ts +95 -0
- package/frontend-vue/tests/multi-account-validate.test.ts +23 -1
- package/frontend-vue/tests/nav-badge-tones.test.ts +66 -3
- package/frontend-vue/tests/notification-counts-from-writes.test.ts +223 -0
- package/frontend-vue/tests/notification-counts-transfer.test.ts +88 -0
- package/frontend-vue/tests/notification-inbox-display.test.ts +57 -5
- package/frontend-vue/tests/notification-popover-errors.test.ts +21 -1
- package/frontend-vue/tests/oauth-complete-handoff.test.ts +209 -0
- package/frontend-vue/tests/onboarding-middleware.test.ts +1 -1
- package/frontend-vue/tests/onboarding-transfer.test.ts +106 -0
- package/frontend-vue/tests/page-data-refresh.test.ts +141 -0
- package/frontend-vue/tests/page-fill-height.test.ts +16 -3
- package/frontend-vue/tests/page-no-visible-blocks.test.ts +12 -2
- package/frontend-vue/tests/page-realtime-remount.test.ts +1 -1
- package/frontend-vue/tests/page-record-label.test.ts +0 -7
- package/frontend-vue/tests/page-validation-redirect.test.ts +12 -2
- package/frontend-vue/tests/period-hydration-now.test.ts +185 -0
- package/frontend-vue/tests/period-live-pause.test.ts +3 -0
- package/frontend-vue/tests/period-reader-zone.test.ts +137 -0
- package/frontend-vue/tests/period-scope-first-fetch.test.ts +17 -1
- package/frontend-vue/tests/period-ssr.test.ts +195 -0
- package/frontend-vue/tests/permission-preview-partial.test.ts +0 -2
- package/frontend-vue/tests/permissions-transfer.test.ts +194 -0
- package/frontend-vue/tests/post-login-redirect.test.ts +10 -5
- package/frontend-vue/tests/profile-personal-info-ssr.test.ts +150 -0
- package/frontend-vue/tests/profile-preferences-summary.test.ts +15 -11
- package/frontend-vue/tests/realtime-reconnect.test.ts +22 -3
- package/frontend-vue/tests/roles-name-errors.test.ts +1 -1
- package/frontend-vue/tests/row-side-panel.test.ts +1 -1
- package/frontend-vue/tests/security-sessions-load-error.test.ts +3 -1
- package/frontend-vue/tests/server-routes-vs-pages.test.ts +26 -0
- package/frontend-vue/tests/server-routes.test.ts +582 -0
- package/frontend-vue/tests/session-handoff.test.ts +1 -1
- package/frontend-vue/tests/settings-reads-ssr.test.ts +232 -0
- package/frontend-vue/tests/side-panels.test.ts +8 -1
- package/frontend-vue/tests/sign-in-exit-history.test.ts +219 -0
- package/frontend-vue/tests/signup-invitation-link.test.ts +56 -8
- package/frontend-vue/tests/site-layout-categories.test.ts +42 -0
- package/frontend-vue/tests/site-layout-hydration.test.ts +3 -3
- package/frontend-vue/tests/site-layout-rendered.test.ts +103 -0
- package/frontend-vue/tests/site-layout-resync.test.ts +87 -0
- package/frontend-vue/tests/ssr-guard-preload.test.ts +188 -0
- package/frontend-vue/tests/table-cell-tones.test.ts +36 -1
- package/frontend-vue/tests/table-data-ssr.test.ts +195 -0
- package/frontend-vue/tests/table-list-data-requests.test.ts +154 -0
- package/frontend-vue/tests/table-retry-loading.test.ts +37 -0
- package/frontend-vue/tests/table-source-navigation.test.ts +0 -1
- package/frontend-vue/tests/table-source-period-scope.test.ts +0 -1
- package/frontend-vue/tests/table-view-views.test.ts +1 -1
- package/frontend-vue/tests/top-list-card-actions.test.ts +3 -0
- package/frontend-vue/tests/top-list-card-period-badge-ssr.test.ts +212 -0
- package/frontend-vue/tests/top-list-card-period-badge.test.ts +79 -0
- package/frontend-vue/tests/top-list-card-value-suffix.test.ts +3 -0
- package/frontend-vue/tests/trailing-deduper.test.ts +22 -0
- package/frontend-vue/tests/use-api-data-update.test.ts +119 -0
- package/frontend-vue/tests/use-api-data.test.ts +410 -0
- package/frontend-vue/tests/user-language.test.ts +8 -5
- package/frontend-vue/tests/widget-label-i18n.test.ts +4 -1
- package/frontend-vue/vitest.config.ts +6 -0
- package/package.json +2 -2
- package/skills/dms/SKILL.md +2 -1
- package/skills/dms-module/SKILL.md +1 -1
- package/skills/dms-pages/SKILL.md +4 -1
- package/frontend-vue/layers/dms-core/app/build/composables/page/usePageRecordLabel.ts +0 -9
- package/frontend-vue/layers/dms-layout/app/composables/page/usePrefetch.ts +0 -21
- package/frontend-vue/layers/dms-ui/app/build/composables/form/useControlError.ts +0 -10
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useServerRenderedAsyncData.ts +0 -23
- package/frontend-vue/tests/control-error-path.test.ts +0 -11
- package/frontend-vue/tests/modules-listing-per-request.test.ts +0 -104
- package/frontend-vue/tests/page-layout-background-refresh.test.ts +0 -321
|
@@ -1,137 +1,203 @@
|
|
|
1
|
+
import type { Tone } from "#dms-ui/app/types/tone";
|
|
2
|
+
import type { StatusPillDot } from "#dms-ui/app/components/status-pill/StatusPill.vue";
|
|
3
|
+
import type {
|
|
4
|
+
StoreListingEntry,
|
|
5
|
+
StoreModuleState,
|
|
6
|
+
StoreOperationKind,
|
|
7
|
+
} from "../../types/module-store";
|
|
1
8
|
import type { DisplayResolver } from "./modules-catalog";
|
|
2
9
|
|
|
3
|
-
/**
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
10
|
+
/** A store module as the Modules page filters and draws it. */
|
|
11
|
+
export type ModuleStoreEntry = StoreListingEntry & {
|
|
12
|
+
/** Store category, a `$i18n.key` (what the category chips read). */
|
|
13
|
+
catalogCategory: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/** Which store modules the store section shows. */
|
|
17
|
+
export type StoreScope = "all" | "available" | "installed";
|
|
18
|
+
|
|
19
|
+
/** What a store tile's pill says. */
|
|
20
|
+
export interface StoreTileStatus {
|
|
21
|
+
tone: Tone;
|
|
22
|
+
/** i18n key under `modules.store.state`. */
|
|
23
|
+
labelKey: string;
|
|
24
|
+
dot?: StatusPillDot;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** One action a store tile offers. */
|
|
28
|
+
export interface StoreAction {
|
|
29
|
+
kind: StoreOperationKind;
|
|
30
|
+
/** i18n key under `modules.store.actions`. */
|
|
31
|
+
labelKey: string;
|
|
32
|
+
icon: string;
|
|
33
|
+
/** The action runs only once the owner confirms it. */
|
|
34
|
+
confirm?: boolean;
|
|
9
35
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
36
|
+
* Offered in the tile's menu only, never as its button: pausing or
|
|
37
|
+
* removing a running module is not what its tile should invite.
|
|
12
38
|
*/
|
|
13
|
-
|
|
14
|
-
/** npm package the AntelopeJS CLI adds to the project. */
|
|
15
|
-
packageName: string;
|
|
16
|
-
/** Display name, a `$i18n.key`. */
|
|
17
|
-
title: string;
|
|
18
|
-
/** One-line summary, a `$i18n.key`. */
|
|
19
|
-
description: string;
|
|
20
|
-
/** Iconify name, the icon the module registers once installed. */
|
|
21
|
-
icon: string;
|
|
22
|
-
/** Store category, a `$i18n.key`. */
|
|
23
|
-
catalogCategory: string;
|
|
39
|
+
isMenuOnly?: boolean;
|
|
24
40
|
}
|
|
25
41
|
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
const CATEGORY_PREFIX = "$modules.store.category";
|
|
43
|
+
|
|
44
|
+
/** The command that turns a production frontend into one serving new layers. */
|
|
45
|
+
export const FRONTEND_BUILD_COMMAND = "ajs dms build";
|
|
46
|
+
|
|
47
|
+
const STATUSES: Record<StoreModuleState, StoreTileStatus> = {
|
|
48
|
+
available: { tone: "neutral", labelKey: "available", dot: "none" },
|
|
49
|
+
busy: { tone: "info", labelKey: "busy", dot: "live" },
|
|
50
|
+
active: { tone: "success", labelKey: "active" },
|
|
51
|
+
disabled: { tone: "neutral", labelKey: "disabled" },
|
|
52
|
+
error: { tone: "error", labelKey: "error" },
|
|
53
|
+
pending: { tone: "warning", labelKey: "pending" },
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const ACTIONS: Record<StoreOperationKind, StoreAction> = {
|
|
57
|
+
install: {
|
|
58
|
+
kind: "install",
|
|
59
|
+
labelKey: "install",
|
|
60
|
+
icon: "i-ph-download-simple",
|
|
61
|
+
},
|
|
62
|
+
update: { kind: "update", labelKey: "update", icon: "i-ph-arrow-circle-up" },
|
|
63
|
+
enable: { kind: "enable", labelKey: "enable", icon: "i-ph-play" },
|
|
64
|
+
disable: {
|
|
65
|
+
kind: "disable",
|
|
66
|
+
labelKey: "disable",
|
|
67
|
+
icon: "i-ph-pause",
|
|
68
|
+
isMenuOnly: true,
|
|
69
|
+
},
|
|
70
|
+
uninstall: {
|
|
71
|
+
kind: "uninstall",
|
|
72
|
+
labelKey: "uninstall",
|
|
73
|
+
icon: "i-ph-trash",
|
|
74
|
+
confirm: true,
|
|
75
|
+
isMenuOnly: true,
|
|
76
|
+
},
|
|
77
|
+
apply: { kind: "apply", labelKey: "apply", icon: "i-ph-arrows-clockwise" },
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/** States of a module that antelope.config.ts declares. */
|
|
81
|
+
const INSTALLED_STATES = new Set<StoreModuleState>([
|
|
82
|
+
"active",
|
|
83
|
+
"disabled",
|
|
84
|
+
"pending",
|
|
85
|
+
]);
|
|
86
|
+
|
|
87
|
+
export function toModuleStoreEntry(entry: StoreListingEntry): ModuleStoreEntry {
|
|
42
88
|
return {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
89
|
+
...entry,
|
|
90
|
+
catalogCategory: `${CATEGORY_PREFIX}.${entry.category}`,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Whether the module is installed, from the store or by the config. */
|
|
95
|
+
export function isInstalled(entry: StoreListingEntry): boolean {
|
|
96
|
+
if (INSTALLED_STATES.has(entry.state)) return true;
|
|
97
|
+
return entry.installedVersion !== undefined;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function filterByScope<T extends StoreListingEntry>(
|
|
101
|
+
entries: readonly T[],
|
|
102
|
+
scope: StoreScope,
|
|
103
|
+
): T[] {
|
|
104
|
+
if (scope === "all") return [...entries];
|
|
105
|
+
const wantsInstalled = scope === "installed";
|
|
106
|
+
return entries.filter((entry) => isInstalled(entry) === wantsInstalled);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** The store modules, alphabetical by their shown name. */
|
|
110
|
+
export function sortStoreModules<T extends StoreListingEntry>(
|
|
111
|
+
entries: readonly T[],
|
|
112
|
+
resolve: DisplayResolver,
|
|
113
|
+
): T[] {
|
|
114
|
+
return [...entries].sort((a, b) =>
|
|
115
|
+
resolve(a.title).localeCompare(resolve(b.title)),
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function storeTileStatus(entry: StoreListingEntry): StoreTileStatus {
|
|
120
|
+
if (entry.state === "active" && entry.updateAvailable) {
|
|
121
|
+
return { tone: "warning", labelKey: "update_available" };
|
|
122
|
+
}
|
|
123
|
+
return STATUSES[entry.state];
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* What the tile offers, the main action first. A module in error offers to
|
|
128
|
+
* try its last step again: installing it when the file does not hold it,
|
|
129
|
+
* applying the file otherwise.
|
|
130
|
+
*/
|
|
131
|
+
export function storeActions(entry: StoreListingEntry): StoreAction[] {
|
|
132
|
+
const installed = entry.installedVersion !== undefined;
|
|
133
|
+
const byState: Record<StoreModuleState, StoreOperationKind[]> = {
|
|
134
|
+
available: ["install"],
|
|
135
|
+
busy: [],
|
|
136
|
+
active: entry.updateAvailable
|
|
137
|
+
? ["update", "disable", "uninstall"]
|
|
138
|
+
: ["disable", "uninstall"],
|
|
139
|
+
disabled: ["enable", "uninstall"],
|
|
140
|
+
error: installed ? ["apply", "uninstall"] : ["install"],
|
|
141
|
+
pending: ["apply", "uninstall"],
|
|
49
142
|
};
|
|
143
|
+
return byState[entry.state].map((kind) => ACTIONS[kind]);
|
|
50
144
|
}
|
|
51
145
|
|
|
52
146
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* Media and Builder register no catalog module, so theirs come from their
|
|
56
|
-
* settings page and the v2 design.
|
|
147
|
+
* Whether the page waits on the frontend for this module: its backend side
|
|
148
|
+
* changed and the frontend server has not reported serving it yet.
|
|
57
149
|
*/
|
|
58
|
-
export
|
|
59
|
-
|
|
60
|
-
storeEntry(
|
|
61
|
-
"api",
|
|
62
|
-
"@antelopejs/dms-api",
|
|
63
|
-
"i-ph-brackets-curly",
|
|
64
|
-
CATEGORY.developer,
|
|
65
|
-
),
|
|
66
|
-
storeEntry(
|
|
67
|
-
"automation",
|
|
68
|
-
"@antelopejs/dms-automation",
|
|
69
|
-
"i-ph-flow-arrow",
|
|
70
|
-
CATEGORY.operations,
|
|
71
|
-
),
|
|
72
|
-
storeEntry(
|
|
73
|
-
"builder",
|
|
74
|
-
"@antelopejs/dms-builder",
|
|
75
|
-
"i-ph-hammer",
|
|
76
|
-
CATEGORY.developer,
|
|
77
|
-
),
|
|
78
|
-
storeEntry(
|
|
79
|
-
"cicd",
|
|
80
|
-
"@antelopejs-private/dms-cicd",
|
|
81
|
-
"i-ph-rocket-launch",
|
|
82
|
-
CATEGORY.operations,
|
|
83
|
-
),
|
|
84
|
-
storeEntry(
|
|
85
|
-
"database",
|
|
86
|
-
"@antelopejs/dms-database",
|
|
87
|
-
"i-ph-database",
|
|
88
|
-
CATEGORY.data,
|
|
89
|
-
),
|
|
90
|
-
storeEntry(
|
|
91
|
-
"lang",
|
|
92
|
-
"@antelopejs/dms-lang",
|
|
93
|
-
"i-ph-translate",
|
|
94
|
-
CATEGORY.content,
|
|
95
|
-
),
|
|
96
|
-
storeEntry(
|
|
97
|
-
"mailing",
|
|
98
|
-
"@antelopejs/dms-mailing",
|
|
99
|
-
"i-ph-envelope-simple",
|
|
100
|
-
CATEGORY.growth,
|
|
101
|
-
),
|
|
102
|
-
storeEntry(
|
|
103
|
-
"marketing",
|
|
104
|
-
"@antelopejs/dms-marketing",
|
|
105
|
-
"i-ph-chart-line-up",
|
|
106
|
-
CATEGORY.growth,
|
|
107
|
-
),
|
|
108
|
-
storeEntry("media", "@antelopejs/dms-media", "i-ph-images", CATEGORY.content),
|
|
109
|
-
storeEntry(
|
|
110
|
-
"saas",
|
|
111
|
-
"@antelopejs/dms-saas",
|
|
112
|
-
"i-ph-buildings",
|
|
113
|
-
CATEGORY.business,
|
|
114
|
-
),
|
|
115
|
-
];
|
|
116
|
-
|
|
117
|
-
/** The AntelopeJS CLI command that adds a package module to a project. */
|
|
118
|
-
export const MODULE_INSTALL_COMMAND = "ajs project modules add";
|
|
119
|
-
|
|
120
|
-
/** The full CLI command that adds the module to a project. */
|
|
121
|
-
export function moduleInstallCommand(entry: ModuleStoreEntry): string {
|
|
122
|
-
return `${MODULE_INSTALL_COMMAND} ${entry.packageName}`;
|
|
150
|
+
export function isAwaitingFrontend(entry: StoreListingEntry): boolean {
|
|
151
|
+
return entry.state !== "busy" && entry.frontend === "pending";
|
|
123
152
|
}
|
|
124
153
|
|
|
154
|
+
/** Why an action the tile offers cannot run, as the tile explains it. */
|
|
155
|
+
export type StoreActionBlock =
|
|
156
|
+
| "no_release"
|
|
157
|
+
| "incompatible"
|
|
158
|
+
| "frontend"
|
|
159
|
+
| "interfaces"
|
|
160
|
+
| "dependents";
|
|
161
|
+
|
|
162
|
+
/** Actions that load a new release of the module. */
|
|
163
|
+
const RELEASE_ACTIONS = new Set<StoreOperationKind>(["install", "update"]);
|
|
125
164
|
/**
|
|
126
|
-
*
|
|
127
|
-
*
|
|
165
|
+
* Actions that pick the missing interfaces' modules in a dialog; the others
|
|
166
|
+
* refuse a release that misses one.
|
|
128
167
|
*/
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
168
|
+
const PICKS_DEPENDENCIES = new Set<StoreOperationKind>(["install"]);
|
|
169
|
+
/** Actions that take a running module down. */
|
|
170
|
+
const TAKE_DOWN_ACTIONS = new Set<StoreOperationKind>(["disable", "uninstall"]);
|
|
171
|
+
|
|
172
|
+
function releaseBlock(
|
|
173
|
+
entry: StoreListingEntry,
|
|
174
|
+
kind: StoreOperationKind,
|
|
175
|
+
): StoreActionBlock | undefined {
|
|
176
|
+
if (!entry.latestVersion) return "no_release";
|
|
177
|
+
if (!entry.compatible) return "incompatible";
|
|
178
|
+
if (entry.frontendRequirement) return "frontend";
|
|
179
|
+
if (!PICKS_DEPENDENCIES.has(kind) && entry.missingInterfaces.length > 0) {
|
|
180
|
+
return "interfaces";
|
|
181
|
+
}
|
|
182
|
+
return undefined;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** Why `kind` cannot run on the module, or undefined when it can. */
|
|
186
|
+
export function storeActionBlock(
|
|
187
|
+
entry: StoreListingEntry,
|
|
188
|
+
kind: StoreOperationKind,
|
|
189
|
+
): StoreActionBlock | undefined {
|
|
190
|
+
if (RELEASE_ACTIONS.has(kind)) return releaseBlock(entry, kind);
|
|
191
|
+
if (TAKE_DOWN_ACTIONS.has(kind) && entry.dependents.length > 0) {
|
|
192
|
+
return "dependents";
|
|
193
|
+
}
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** Whether `kind` first asks which modules implement the missing interfaces. */
|
|
198
|
+
export function needsDependencyChoice(
|
|
199
|
+
entry: StoreListingEntry,
|
|
200
|
+
kind: StoreOperationKind,
|
|
201
|
+
): boolean {
|
|
202
|
+
return PICKS_DEPENDENCIES.has(kind) && entry.missingInterfaces.length > 0;
|
|
137
203
|
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
MissingInterface,
|
|
3
|
+
StoreActionBody,
|
|
4
|
+
StoreDependencyChoice,
|
|
5
|
+
} from "../../types/module-store";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The radio value of the "Other npm package" choice: not an npm package
|
|
9
|
+
* name, so no candidate can take it.
|
|
10
|
+
*/
|
|
11
|
+
export const OTHER_PACKAGE_CHOICE = ":other";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* An npm package name, scoped or not: never a path, a URL or a git source,
|
|
15
|
+
* as the store only installs from the registry.
|
|
16
|
+
*/
|
|
17
|
+
const NPM_PACKAGE_PATTERN =
|
|
18
|
+
/^(?:@[a-z0-9][a-z0-9._~-]*\/)?[a-z0-9][a-z0-9._~-]*$/;
|
|
19
|
+
const NPM_PACKAGE_MAX_LENGTH = 214;
|
|
20
|
+
|
|
21
|
+
/** What the install dialog holds for one missing interface. */
|
|
22
|
+
export interface DependencyDraft {
|
|
23
|
+
interfacePackage: string;
|
|
24
|
+
/** A candidate's package, or {@link OTHER_PACKAGE_CHOICE}. */
|
|
25
|
+
choice: string;
|
|
26
|
+
/** The package typed for the "Other npm package" choice. */
|
|
27
|
+
otherPackage: string;
|
|
28
|
+
/** The config as typed, JSON; empty means none. */
|
|
29
|
+
config: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Why a draft cannot be sent, by field: i18n keys under the dialog's errors. */
|
|
33
|
+
export type DependencyDraftError =
|
|
34
|
+
| "package_required"
|
|
35
|
+
| "package_invalid"
|
|
36
|
+
| "config_invalid";
|
|
37
|
+
|
|
38
|
+
export interface DependencyDraftErrors {
|
|
39
|
+
package?: DependencyDraftError;
|
|
40
|
+
config?: DependencyDraftError;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** A config as the dialog reads it: absent when left empty. */
|
|
44
|
+
export interface ParsedDependencyConfig {
|
|
45
|
+
isValid: boolean;
|
|
46
|
+
config?: Record<string, unknown>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function isNpmPackageName(value: string): boolean {
|
|
50
|
+
return (
|
|
51
|
+
value.length <= NPM_PACKAGE_MAX_LENGTH && NPM_PACKAGE_PATTERN.test(value)
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const isPlainObject = (value: unknown): value is Record<string, unknown> =>
|
|
56
|
+
typeof value === "object" && value !== null && !Array.isArray(value);
|
|
57
|
+
|
|
58
|
+
/** Reads a typed config: empty is no config, anything else a JSON object. */
|
|
59
|
+
export function parseDependencyConfig(text: string): ParsedDependencyConfig {
|
|
60
|
+
if (!text.trim()) return { isValid: true };
|
|
61
|
+
try {
|
|
62
|
+
const value: unknown = JSON.parse(text);
|
|
63
|
+
return isPlainObject(value)
|
|
64
|
+
? { isValid: true, config: value }
|
|
65
|
+
: { isValid: false };
|
|
66
|
+
} catch {
|
|
67
|
+
return { isValid: false };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* One draft per missing interface, the first candidate picked. A draft of
|
|
73
|
+
* an earlier attempt at the same interface is kept, so a retry starts from
|
|
74
|
+
* what the owner typed.
|
|
75
|
+
*/
|
|
76
|
+
export function createDependencyDrafts(
|
|
77
|
+
missing: readonly MissingInterface[],
|
|
78
|
+
previous: readonly DependencyDraft[] = [],
|
|
79
|
+
): DependencyDraft[] {
|
|
80
|
+
return missing.map(({ interfacePackage, candidates }) => {
|
|
81
|
+
const earlier = previous.find(
|
|
82
|
+
(draft) => draft.interfacePackage === interfacePackage,
|
|
83
|
+
);
|
|
84
|
+
if (earlier) return { ...earlier };
|
|
85
|
+
return {
|
|
86
|
+
interfacePackage,
|
|
87
|
+
choice: candidates[0]?.package ?? OTHER_PACKAGE_CHOICE,
|
|
88
|
+
otherPackage: "",
|
|
89
|
+
config: "",
|
|
90
|
+
};
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** The package a draft installs, as the owner picked or typed it. */
|
|
95
|
+
export function draftPackage(draft: DependencyDraft): string {
|
|
96
|
+
return draft.choice === OTHER_PACKAGE_CHOICE
|
|
97
|
+
? draft.otherPackage.trim()
|
|
98
|
+
: draft.choice;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function packageError(
|
|
102
|
+
draft: DependencyDraft,
|
|
103
|
+
): DependencyDraftError | undefined {
|
|
104
|
+
const packageName = draftPackage(draft);
|
|
105
|
+
if (!packageName) return "package_required";
|
|
106
|
+
return isNpmPackageName(packageName) ? undefined : "package_invalid";
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function validateDependencyDraft(
|
|
110
|
+
draft: DependencyDraft,
|
|
111
|
+
): DependencyDraftErrors {
|
|
112
|
+
const errors: DependencyDraftErrors = {};
|
|
113
|
+
const packageProblem = packageError(draft);
|
|
114
|
+
if (packageProblem) errors.package = packageProblem;
|
|
115
|
+
if (!parseDependencyConfig(draft.config).isValid) {
|
|
116
|
+
errors.config = "config_invalid";
|
|
117
|
+
}
|
|
118
|
+
return errors;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function areDependencyDraftsValid(
|
|
122
|
+
drafts: readonly DependencyDraft[],
|
|
123
|
+
): boolean {
|
|
124
|
+
return drafts.every(
|
|
125
|
+
(draft) => Object.keys(validateDependencyDraft(draft)).length === 0,
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function toDependencyChoice(draft: DependencyDraft): StoreDependencyChoice {
|
|
130
|
+
const { config } = parseDependencyConfig(draft.config);
|
|
131
|
+
const choice: StoreDependencyChoice = {
|
|
132
|
+
interfacePackage: draft.interfacePackage,
|
|
133
|
+
package: draftPackage(draft),
|
|
134
|
+
};
|
|
135
|
+
if (config) choice.config = config;
|
|
136
|
+
return choice;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** The install request for module `id`, from drafts already validated. */
|
|
140
|
+
export function buildInstallBody(
|
|
141
|
+
id: string,
|
|
142
|
+
drafts: readonly DependencyDraft[],
|
|
143
|
+
): StoreActionBody {
|
|
144
|
+
if (drafts.length === 0) return { id };
|
|
145
|
+
return { id, dependencies: drafts.map(toDependencyChoice) };
|
|
146
|
+
}
|
|
@@ -2,6 +2,7 @@ import type {
|
|
|
2
2
|
ModuleCatalogEntry,
|
|
3
3
|
ModuleStatus,
|
|
4
4
|
PageInfo,
|
|
5
|
+
SiteLayout,
|
|
5
6
|
} from "../../types/page";
|
|
6
7
|
|
|
7
8
|
/** Category of the modules that declare none. */
|
|
@@ -148,11 +149,10 @@ export function sortModules(
|
|
|
148
149
|
|
|
149
150
|
/**
|
|
150
151
|
* A page as `/dms/sitelayout` serves it: the payload also carries the
|
|
151
|
-
* owning module
|
|
152
|
+
* owning module, which the shared type leaves out.
|
|
152
153
|
*/
|
|
153
154
|
type ServedPage = PageInfo & {
|
|
154
155
|
module?: string;
|
|
155
|
-
category?: { displayName?: string; isModuleRoot?: boolean };
|
|
156
156
|
};
|
|
157
157
|
|
|
158
158
|
function isOpenablePage(page: ServedPage): boolean {
|
|
@@ -169,19 +169,21 @@ function isOpenablePage(page: ServedPage): boolean {
|
|
|
169
169
|
* the empty state can point to where the thing actually lives.
|
|
170
170
|
*/
|
|
171
171
|
export function findModulePageMatch(
|
|
172
|
-
|
|
172
|
+
siteLayout: Pick<SiteLayout, "pages" | "categories"> | undefined,
|
|
173
173
|
query: string,
|
|
174
174
|
installedModuleIds: ReadonlySet<string>,
|
|
175
175
|
resolve: DisplayResolver,
|
|
176
176
|
): ModulePageMatch | null {
|
|
177
177
|
const needle = normalizeQuery(query);
|
|
178
|
-
if (!needle || !
|
|
179
|
-
for (const page of Object.values(pages) as ServedPage[]) {
|
|
178
|
+
if (!needle || !siteLayout) return null;
|
|
179
|
+
for (const page of Object.values(siteLayout.pages) as ServedPage[]) {
|
|
180
180
|
if (!page.module || !installedModuleIds.has(page.module)) continue;
|
|
181
181
|
if (!isOpenablePage(page)) continue;
|
|
182
182
|
const pageTitle = resolve(page.displayName);
|
|
183
183
|
if (!pageTitle.toLocaleLowerCase().includes(needle)) continue;
|
|
184
|
-
const parent = page.
|
|
184
|
+
const parent = page.categoryId
|
|
185
|
+
? siteLayout.categories[page.categoryId]
|
|
186
|
+
: undefined;
|
|
185
187
|
const sectionTitle =
|
|
186
188
|
parent?.displayName && !parent.isModuleRoot
|
|
187
189
|
? resolve(parent.displayName)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// A fetch failure names the request it failed: `[GET] "http://10.0.0.4:5010/
|
|
2
|
+
// dms/page?path=/x": 502 Bad Gateway`. On a server, that is the backend's
|
|
3
|
+
// internal address, which an error page must never show.
|
|
4
|
+
const FETCH_FAILURE = /^\[[A-Z]+\]\s+"[^"]*":\s*(.*)$/s;
|
|
5
|
+
const ABSOLUTE_URL = /\b[a-z][a-z0-9+.-]*:\/\/[^\s"'<>]+/gi;
|
|
6
|
+
const SPACES = /\s{2,}/g;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The part of an error's message a page may show: a fetch failure's status
|
|
10
|
+
* text alone, and no absolute URL anywhere; nothing when nothing is left.
|
|
11
|
+
*/
|
|
12
|
+
export function publicErrorMessage(
|
|
13
|
+
message: string | undefined,
|
|
14
|
+
): string | undefined {
|
|
15
|
+
if (!message) return undefined;
|
|
16
|
+
const statusText = FETCH_FAILURE.exec(message)?.[1] ?? message;
|
|
17
|
+
const shown = statusText.replace(ABSOLUTE_URL, "").replace(SPACES, " ");
|
|
18
|
+
return shown.trim() || undefined;
|
|
19
|
+
}
|
|
@@ -102,15 +102,6 @@ const paddingLeft = computed(() => {
|
|
|
102
102
|
const chevronClass = (isOpen: boolean) => {
|
|
103
103
|
return theme({ isOpen }).chevron();
|
|
104
104
|
};
|
|
105
|
-
|
|
106
|
-
const { prefetchPageLayout } = usePrefetch();
|
|
107
|
-
|
|
108
|
-
function onLinkHover(): void {
|
|
109
|
-
const { to } = props.item;
|
|
110
|
-
if (typeof to === "string") {
|
|
111
|
-
prefetchPageLayout(stripQueryAndHash(to));
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
105
|
</script>
|
|
115
106
|
|
|
116
107
|
<template>
|
|
@@ -128,7 +119,6 @@ function onLinkHover(): void {
|
|
|
128
119
|
:is="item.to ? DmsLink : 'div'"
|
|
129
120
|
:to="item.to"
|
|
130
121
|
:class="ui.topLevelButton()"
|
|
131
|
-
@mouseenter="onLinkHover"
|
|
132
122
|
>
|
|
133
123
|
<UIcon v-if="item.icon" :name="item.icon" :class="ui.icon()" />
|
|
134
124
|
<UIcon
|
|
@@ -150,7 +140,6 @@ function onLinkHover(): void {
|
|
|
150
140
|
:class="ui.link()"
|
|
151
141
|
:style="{ paddingLeft }"
|
|
152
142
|
:title="item.title"
|
|
153
|
-
@mouseenter="onLinkHover"
|
|
154
143
|
>
|
|
155
144
|
<UIcon v-if="item.icon" :name="item.icon" :class="ui.icon()" />
|
|
156
145
|
<span>{{ item.label }}</span>
|
|
@@ -206,6 +206,9 @@ function decorateMenuItem(item: DmsMenuItem): DmsMenuItem {
|
|
|
206
206
|
|
|
207
207
|
return {
|
|
208
208
|
...item,
|
|
209
|
+
// Inertia prefetches the page on hover, the way a `DmsLink` does: the
|
|
210
|
+
// visit then shows it without a request, and its components load early.
|
|
211
|
+
...(item.to ? { prefetch: true } : {}),
|
|
209
212
|
...(variant.link ? { class: [item.class, variant.link] } : {}),
|
|
210
213
|
...(statusClass ? { trailingIcon: STATUS_DOT_ICON } : {}),
|
|
211
214
|
badge,
|
|
@@ -232,18 +235,6 @@ const groupedItems = computed((): NavigationMenuItem[][] => {
|
|
|
232
235
|
);
|
|
233
236
|
});
|
|
234
237
|
|
|
235
|
-
const { prefetchPageLayout } = usePrefetch();
|
|
236
|
-
|
|
237
|
-
function onMenuMouseover(event: MouseEvent): void {
|
|
238
|
-
const target = (event.target as HTMLElement).closest("a[href]");
|
|
239
|
-
if (!target) return;
|
|
240
|
-
|
|
241
|
-
const href = target.getAttribute("href");
|
|
242
|
-
if (href && href.startsWith("/")) {
|
|
243
|
-
prefetchPageLayout(stripQueryAndHash(href));
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
238
|
function isDesiredOpen(id: string): boolean {
|
|
248
239
|
return props.modelValue?.includes(id) ?? false;
|
|
249
240
|
}
|
|
@@ -271,7 +262,6 @@ function onStateChange(id: string, open: boolean): void {
|
|
|
271
262
|
:orientation="orientation"
|
|
272
263
|
:highlight="orientation === 'vertical'"
|
|
273
264
|
value-key="id"
|
|
274
|
-
@mouseover="onMenuMouseover"
|
|
275
265
|
>
|
|
276
266
|
<template #item-leading="{ item, active, ui }">
|
|
277
267
|
<DmsAccordionItemSync
|
|
@@ -16,17 +16,13 @@ export const useSystemState = () => {
|
|
|
16
16
|
data: systemState,
|
|
17
17
|
error,
|
|
18
18
|
refresh,
|
|
19
|
-
} =
|
|
20
|
-
SYSTEM_STATE_CACHE_KEY,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
default: () => ({ ...DEFAULT_SYSTEM_STATE }),
|
|
27
|
-
server: true,
|
|
28
|
-
},
|
|
29
|
-
);
|
|
19
|
+
} = useApiData<SystemState>(SYSTEM_STATE_ENDPOINT, {
|
|
20
|
+
key: SYSTEM_STATE_CACHE_KEY,
|
|
21
|
+
lazy: true,
|
|
22
|
+
default: () => ({ ...DEFAULT_SYSTEM_STATE }),
|
|
23
|
+
// The deployment's state, not the page's data.
|
|
24
|
+
refreshOnPageRefresh: false,
|
|
25
|
+
});
|
|
30
26
|
|
|
31
27
|
const metaTitle = computed(() => systemState.value?.meta?.title ?? "");
|
|
32
28
|
const metaDescription = computed(
|