@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,4 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import type { Ref, VNode } from "vue";
|
|
2
3
|
import { MONO_CHIP_CLASS } from "#dms-ui/app/build/utils/monoChip";
|
|
3
4
|
import UButton from "@nuxt/ui/components/Button.vue";
|
|
4
5
|
import UIcon from "@nuxt/ui/runtime/vue/components/Icon.vue";
|
|
@@ -13,6 +14,7 @@ import { useKeyboardPlatform } from "#dms-ui/app/composables/global/keyboardPlat
|
|
|
13
14
|
import DmsChipGroup from "#dms-ui/app/build/components/form/ChipGroup.vue";
|
|
14
15
|
import ModuleCatalogTile from "../build/components/pages/modules/ModuleCatalogTile.vue";
|
|
15
16
|
import ModuleStoreTile from "../build/components/pages/modules/ModuleStoreTile.vue";
|
|
17
|
+
import ModuleStoreDependencyPicker from "../build/components/pages/modules/ModuleStoreDependencyPicker.vue";
|
|
16
18
|
import { usePageHeaderActions } from "../composables/layout/usePageHeaderActions";
|
|
17
19
|
import {
|
|
18
20
|
ENDPOINT_MODULES_LISTING,
|
|
@@ -30,13 +32,33 @@ import {
|
|
|
30
32
|
type ModuleSortMode,
|
|
31
33
|
} from "../build/utils/modules-catalog";
|
|
32
34
|
import {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
type ModuleStoreEntry,
|
|
36
|
+
type StoreScope,
|
|
37
|
+
FRONTEND_BUILD_COMMAND,
|
|
38
|
+
filterByScope,
|
|
39
|
+
isAwaitingFrontend,
|
|
40
|
+
needsDependencyChoice,
|
|
41
|
+
sortStoreModules,
|
|
42
|
+
toModuleStoreEntry,
|
|
35
43
|
} from "../build/utils/module-store-catalog";
|
|
44
|
+
import {
|
|
45
|
+
type DependencyDraft,
|
|
46
|
+
areDependencyDraftsValid,
|
|
47
|
+
buildInstallBody,
|
|
48
|
+
createDependencyDrafts,
|
|
49
|
+
} from "../build/utils/module-store-install";
|
|
50
|
+
import { useModuleStore } from "../composables/page/useModuleStore";
|
|
51
|
+
import {
|
|
52
|
+
ConfirmActionError,
|
|
53
|
+
useConfirm,
|
|
54
|
+
} from "#dms-ui/app/composables/confirm";
|
|
55
|
+
import type {
|
|
56
|
+
StoreActionBody,
|
|
57
|
+
StoreOperationKind,
|
|
58
|
+
} from "../types/module-store";
|
|
36
59
|
import DmsSearchInput from "#dms-ui/app/build/components/form/SearchInput.vue";
|
|
37
60
|
|
|
38
61
|
const SKELETON_PLACEHOLDER_COUNT = 6;
|
|
39
|
-
const MODULES_LISTING_DATA_KEY = "modules-page-listing";
|
|
40
62
|
|
|
41
63
|
const { t } = useI18n();
|
|
42
64
|
const { processI18n } = useTranslation();
|
|
@@ -85,37 +107,16 @@ if (!siteLayout.siteLayout.value) {
|
|
|
85
107
|
// 403 page, the same answer as any page they may not open (the entry is not in
|
|
86
108
|
// their menu either).
|
|
87
109
|
if (!isOwner.value) {
|
|
88
|
-
throw
|
|
110
|
+
throw showDmsError({
|
|
89
111
|
statusCode: HTTP_FORBIDDEN,
|
|
90
112
|
statusMessage: "Access denied",
|
|
91
113
|
});
|
|
92
114
|
}
|
|
93
115
|
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
if (isOwner.value) {
|
|
99
|
-
const { data: renderedListing } = await useDmsAsyncData<
|
|
100
|
-
ModuleCatalogEntry[] | null
|
|
101
|
-
>(MODULES_LISTING_DATA_KEY, async () => {
|
|
102
|
-
await modulesListing.loadModulesListing();
|
|
103
|
-
return modulesListing.modules.value ?? null;
|
|
104
|
-
});
|
|
105
|
-
if (modulesListing.modules.value === undefined) {
|
|
106
|
-
if (renderedListing.value) {
|
|
107
|
-
modulesListing.modules.value = renderedListing.value;
|
|
108
|
-
} else {
|
|
109
|
-
await modulesListing.loadModulesListing();
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
onMounted(() => {
|
|
115
|
-
if (isOwner.value && modulesListing.modules.value !== undefined) {
|
|
116
|
-
void modulesListing.revalidate();
|
|
117
|
-
}
|
|
118
|
-
});
|
|
116
|
+
// Read with the page, which the server renders and hands over: the
|
|
117
|
+
// hydration reuses the listing the server rendered (read again, its live
|
|
118
|
+
// readouts, an uptime a minute on, would no longer match the markup).
|
|
119
|
+
await modulesListing.loadModulesListing();
|
|
119
120
|
|
|
120
121
|
const isForbidden = computed(
|
|
121
122
|
() =>
|
|
@@ -204,7 +205,7 @@ const trimmedQuery = computed(() => query.value.trim());
|
|
|
204
205
|
const pageMatch = computed(() => {
|
|
205
206
|
if (visibleModules.value.length > 0 || !trimmedQuery.value) return null;
|
|
206
207
|
const match = findModulePageMatch(
|
|
207
|
-
siteLayout.siteLayout.value
|
|
208
|
+
siteLayout.siteLayout.value,
|
|
208
209
|
trimmedQuery.value,
|
|
209
210
|
new Set(modules.value.map((entry) => entry.id)),
|
|
210
211
|
processI18n,
|
|
@@ -219,26 +220,49 @@ function clearFilters(): void {
|
|
|
219
220
|
category.value = MODULE_CATEGORY_ALL;
|
|
220
221
|
}
|
|
221
222
|
|
|
222
|
-
// ── Module store
|
|
223
|
-
|
|
224
|
-
|
|
223
|
+
// ── Module store ───────────────────────────────────────────────────
|
|
224
|
+
const moduleStore = useModuleStore();
|
|
225
|
+
const toast = useToast();
|
|
226
|
+
const { confirm } = useConfirm();
|
|
227
|
+
|
|
228
|
+
onMounted(() => {
|
|
229
|
+
if (isOwner.value) void moduleStore.load();
|
|
230
|
+
});
|
|
231
|
+
onBeforeUnmount(() => moduleStore.stop());
|
|
232
|
+
|
|
233
|
+
const storeListing = computed(() => moduleStore.listing.value);
|
|
234
|
+
const isStoreLoading = computed(
|
|
235
|
+
() => storeListing.value === undefined && !moduleStore.loadingError.value,
|
|
236
|
+
);
|
|
225
237
|
const storeModules = computed(() =>
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
new Set((modulesListing.modules.value ?? []).map((entry) => entry.id)),
|
|
238
|
+
sortStoreModules(
|
|
239
|
+
(storeListing.value?.modules ?? []).map(toModuleStoreEntry),
|
|
229
240
|
processI18n,
|
|
230
241
|
),
|
|
231
242
|
);
|
|
243
|
+
const storeScope = ref<StoreScope>("all");
|
|
232
244
|
const storeQuery = ref("");
|
|
233
245
|
const storeCategory = ref<string>(MODULE_CATEGORY_ALL);
|
|
234
246
|
|
|
247
|
+
const storeScopeItems = computed(() =>
|
|
248
|
+
(["all", "available", "installed"] as const).map((scope) => ({
|
|
249
|
+
value: scope,
|
|
250
|
+
label: t(`modules.store.scope.${scope}`, {
|
|
251
|
+
count: filterByScope(storeModules.value, scope).length,
|
|
252
|
+
}),
|
|
253
|
+
})),
|
|
254
|
+
);
|
|
255
|
+
const scopedStoreModules = computed(() =>
|
|
256
|
+
filterByScope(storeModules.value, storeScope.value),
|
|
257
|
+
);
|
|
258
|
+
|
|
235
259
|
const storeCategoryOptions = computed(() => [
|
|
236
260
|
{
|
|
237
261
|
value: MODULE_CATEGORY_ALL,
|
|
238
262
|
label: t("modules.category.all"),
|
|
239
|
-
count:
|
|
263
|
+
count: scopedStoreModules.value.length,
|
|
240
264
|
},
|
|
241
|
-
...moduleCategoryOptions(
|
|
265
|
+
...moduleCategoryOptions(scopedStoreModules.value, processI18n),
|
|
242
266
|
]);
|
|
243
267
|
|
|
244
268
|
watch(storeCategoryOptions, (options) => {
|
|
@@ -248,7 +272,7 @@ watch(storeCategoryOptions, (options) => {
|
|
|
248
272
|
});
|
|
249
273
|
|
|
250
274
|
const visibleStoreModules = computed(() =>
|
|
251
|
-
filterModules(
|
|
275
|
+
filterModules(scopedStoreModules.value, {
|
|
252
276
|
query: storeQuery.value,
|
|
253
277
|
category: storeCategory.value,
|
|
254
278
|
resolve: processI18n,
|
|
@@ -261,6 +285,153 @@ function clearStoreFilters(): void {
|
|
|
261
285
|
storeCategory.value = MODULE_CATEGORY_ALL;
|
|
262
286
|
}
|
|
263
287
|
|
|
288
|
+
/** Store modules whose interface the running frontend does not match yet. */
|
|
289
|
+
const frontendLagging = computed(() =>
|
|
290
|
+
storeModules.value.filter(
|
|
291
|
+
(entry) =>
|
|
292
|
+
isAwaitingFrontend(entry) ||
|
|
293
|
+
(entry.frontend === "unknown" &&
|
|
294
|
+
moduleStore.awaitingReload.value.has(entry.id)),
|
|
295
|
+
),
|
|
296
|
+
);
|
|
297
|
+
const frontendNotice = computed(() => {
|
|
298
|
+
const lagging = frontendLagging.value;
|
|
299
|
+
if (lagging.length === 0) return null;
|
|
300
|
+
const names = lagging.map((entry) => processI18n(entry.title)).join(", ");
|
|
301
|
+
const hasReported = lagging.every((entry) => entry.frontend !== "unknown");
|
|
302
|
+
const key = !hasReported
|
|
303
|
+
? "unknown"
|
|
304
|
+
: storeListing.value?.dev
|
|
305
|
+
? "dev"
|
|
306
|
+
: "production";
|
|
307
|
+
return { key, names };
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Runs `kind` from a dialog: a refusal is worded as the toast words it and
|
|
312
|
+
* shown in the dialog, which stays open.
|
|
313
|
+
*/
|
|
314
|
+
async function runFromDialog(
|
|
315
|
+
kind: StoreOperationKind,
|
|
316
|
+
entry: ModuleStoreEntry,
|
|
317
|
+
body?: StoreActionBody,
|
|
318
|
+
): Promise<void> {
|
|
319
|
+
try {
|
|
320
|
+
await moduleStore.run(kind, entry, body);
|
|
321
|
+
} catch (error) {
|
|
322
|
+
throw new ConfirmActionError({
|
|
323
|
+
title: t("modules.store.action_failed", {
|
|
324
|
+
module: processI18n(entry.title),
|
|
325
|
+
}),
|
|
326
|
+
description: resolveStoreError(error),
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/** What the owner last picked in a module's install dialog, for a retry. */
|
|
332
|
+
const lastDependencyDrafts = new Map<string, DependencyDraft[]>();
|
|
333
|
+
|
|
334
|
+
function renderDependencyPicker(
|
|
335
|
+
entry: ModuleStoreEntry,
|
|
336
|
+
drafts: Ref<DependencyDraft[]>,
|
|
337
|
+
showErrors: boolean,
|
|
338
|
+
): VNode {
|
|
339
|
+
return h(ModuleStoreDependencyPicker, {
|
|
340
|
+
missing: entry.missingInterfaces,
|
|
341
|
+
drafts: drafts.value,
|
|
342
|
+
showErrors,
|
|
343
|
+
onUpdate: (index: number, patch: Partial<DependencyDraft>) => {
|
|
344
|
+
drafts.value = drafts.value.map((draft, position) =>
|
|
345
|
+
position === index ? { ...draft, ...patch } : draft,
|
|
346
|
+
);
|
|
347
|
+
},
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Asks which modules implement the interfaces the release misses, then
|
|
353
|
+
* installs them with it. A refusal shows in the dialog, kept open.
|
|
354
|
+
*/
|
|
355
|
+
async function installWithDependencies(entry: ModuleStoreEntry): Promise<void> {
|
|
356
|
+
const title = processI18n(entry.title);
|
|
357
|
+
const drafts = ref(
|
|
358
|
+
createDependencyDrafts(
|
|
359
|
+
entry.missingInterfaces,
|
|
360
|
+
lastDependencyDrafts.get(entry.id),
|
|
361
|
+
),
|
|
362
|
+
);
|
|
363
|
+
const showErrors = ref(false);
|
|
364
|
+
await confirm({
|
|
365
|
+
title: t("modules.store.install_dialog.title", { module: title }),
|
|
366
|
+
description: t("modules.store.install_dialog.description", {
|
|
367
|
+
module: title,
|
|
368
|
+
}),
|
|
369
|
+
confirmLabel: t("modules.store.actions.install"),
|
|
370
|
+
confirmIcon: "i-ph-download-simple",
|
|
371
|
+
icon: "i-ph-puzzle-piece",
|
|
372
|
+
body: () => renderDependencyPicker(entry, drafts, showErrors.value),
|
|
373
|
+
validate: () => {
|
|
374
|
+
showErrors.value = true;
|
|
375
|
+
return areDependencyDraftsValid(drafts.value);
|
|
376
|
+
},
|
|
377
|
+
onConfirm: async () => {
|
|
378
|
+
lastDependencyDrafts.set(entry.id, drafts.value);
|
|
379
|
+
await runFromDialog(
|
|
380
|
+
"install",
|
|
381
|
+
entry,
|
|
382
|
+
buildInstallBody(entry.id, drafts.value),
|
|
383
|
+
);
|
|
384
|
+
},
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
async function runStoreAction(
|
|
389
|
+
kind: StoreOperationKind,
|
|
390
|
+
entry: ModuleStoreEntry,
|
|
391
|
+
): Promise<void> {
|
|
392
|
+
const title = processI18n(entry.title);
|
|
393
|
+
if (needsDependencyChoice(entry, kind)) {
|
|
394
|
+
await installWithDependencies(entry);
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
if (kind === "uninstall") {
|
|
398
|
+
await confirm({
|
|
399
|
+
title: t("modules.store.uninstall_confirm.title", { module: title }),
|
|
400
|
+
description: t("modules.store.uninstall_confirm.description", {
|
|
401
|
+
module: title,
|
|
402
|
+
}),
|
|
403
|
+
confirmLabel: t("modules.store.actions.uninstall"),
|
|
404
|
+
color: "error",
|
|
405
|
+
icon: "i-ph-trash",
|
|
406
|
+
onConfirm: () => runFromDialog(kind, entry),
|
|
407
|
+
});
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
try {
|
|
411
|
+
await moduleStore.run(kind, entry);
|
|
412
|
+
} catch (error) {
|
|
413
|
+
toast.add({
|
|
414
|
+
color: "error",
|
|
415
|
+
icon: "i-ph-warning-circle",
|
|
416
|
+
title: t("modules.store.action_failed", { module: title }),
|
|
417
|
+
description: resolveStoreError(error),
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/** What a refused store request carries: the server's error key, if any. */
|
|
423
|
+
interface StoreRequestError {
|
|
424
|
+
data?: unknown;
|
|
425
|
+
message?: string;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function resolveStoreError(error: unknown): string {
|
|
429
|
+
const details = error as StoreRequestError | undefined;
|
|
430
|
+
const key = typeof details?.data === "string" ? details.data : undefined;
|
|
431
|
+
if (!key) return details?.message ?? "";
|
|
432
|
+
return t(`modules.store.errors.${key.replace("error.", "")}`);
|
|
433
|
+
}
|
|
434
|
+
|
|
264
435
|
// ── Actions ────────────────────────────────────────────────────────
|
|
265
436
|
async function retry(): Promise<void> {
|
|
266
437
|
if (isRetrying.value) return;
|
|
@@ -528,49 +699,141 @@ const summaryCards = computed<StatGroupItem[]>(() =>
|
|
|
528
699
|
</div>
|
|
529
700
|
</section>
|
|
530
701
|
|
|
531
|
-
<!-- Module store:
|
|
702
|
+
<!-- Module store: the official modules, installed or not. -->
|
|
532
703
|
<section class="mt-10" aria-labelledby="module-store-title">
|
|
533
704
|
<DmsSectionHeader
|
|
534
705
|
class="mb-3"
|
|
535
|
-
:count="
|
|
706
|
+
:count="isStoreLoading ? undefined : storeModules.length"
|
|
536
707
|
:description="t('modules.store.description')"
|
|
537
708
|
>
|
|
538
709
|
<template #title>
|
|
539
710
|
<span id="module-store-title">{{ t("modules.store.title") }}</span>
|
|
540
711
|
</template>
|
|
541
|
-
<template #
|
|
542
|
-
<
|
|
543
|
-
|
|
544
|
-
:
|
|
712
|
+
<template #trailing>
|
|
713
|
+
<span
|
|
714
|
+
v-if="storeListing?.frontendVersion"
|
|
715
|
+
:class="[
|
|
716
|
+
MONO_CHIP_CLASS,
|
|
717
|
+
'text-dimmed border border-(--ui-border) text-[11px] max-sm:hidden',
|
|
718
|
+
]"
|
|
719
|
+
:title="
|
|
720
|
+
storeListing.frontendVersionSource
|
|
721
|
+
? t(
|
|
722
|
+
`modules.store.frontend_version.${storeListing.frontendVersionSource}`,
|
|
723
|
+
)
|
|
724
|
+
: undefined
|
|
725
|
+
"
|
|
726
|
+
>
|
|
727
|
+
{{
|
|
728
|
+
t("modules.store.frontend_version.label", {
|
|
729
|
+
version: storeListing.frontendVersion,
|
|
730
|
+
})
|
|
731
|
+
}}
|
|
732
|
+
</span>
|
|
733
|
+
<DmsSegmented
|
|
734
|
+
v-model="storeScope"
|
|
735
|
+
:items="storeScopeItems"
|
|
545
736
|
size="sm"
|
|
546
|
-
|
|
737
|
+
:aria-label="t('modules.store.scope.label')"
|
|
547
738
|
/>
|
|
548
739
|
</template>
|
|
549
740
|
</DmsSectionHeader>
|
|
550
741
|
|
|
551
742
|
<DmsBanner
|
|
743
|
+
v-if="storeListing?.configError"
|
|
744
|
+
class="mb-4"
|
|
745
|
+
tone="error"
|
|
746
|
+
size="sm"
|
|
747
|
+
icon="i-ph-file-x"
|
|
748
|
+
:title="t('modules.store.config_error')"
|
|
749
|
+
:description="storeListing.configError"
|
|
750
|
+
/>
|
|
751
|
+
<DmsBanner
|
|
752
|
+
v-else-if="storeListing && !storeListing.enabled"
|
|
552
753
|
class="mb-4"
|
|
553
754
|
tone="info"
|
|
554
755
|
size="sm"
|
|
555
|
-
icon="i-ph-
|
|
556
|
-
:title="t('modules.store.
|
|
557
|
-
:description="t('modules.store.
|
|
756
|
+
icon="i-ph-lock-simple"
|
|
757
|
+
:title="t('modules.store.disabled.title')"
|
|
758
|
+
:description="t('modules.store.disabled.description')"
|
|
558
759
|
/>
|
|
559
760
|
|
|
560
|
-
<!--
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
:
|
|
761
|
+
<!-- The interface lags behind the backend: say what follows. -->
|
|
762
|
+
<DmsBanner
|
|
763
|
+
v-if="frontendNotice"
|
|
764
|
+
class="mb-4"
|
|
765
|
+
:tone="frontendNotice.key === 'dev' ? 'info' : 'warning'"
|
|
766
|
+
size="sm"
|
|
767
|
+
:icon="
|
|
768
|
+
frontendNotice.key === 'dev'
|
|
769
|
+
? 'i-ph-circle-notch'
|
|
770
|
+
: 'i-ph-arrows-clockwise'
|
|
771
|
+
"
|
|
772
|
+
:title="
|
|
773
|
+
t(`modules.store.frontend.${frontendNotice.key}.title`, {
|
|
774
|
+
modules: frontendNotice.names,
|
|
775
|
+
})
|
|
776
|
+
"
|
|
565
777
|
>
|
|
566
|
-
<
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
778
|
+
<template #description>
|
|
779
|
+
<i18n-t
|
|
780
|
+
:keypath="`modules.store.frontend.${frontendNotice.key}.description`"
|
|
781
|
+
scope="global"
|
|
782
|
+
tag="span"
|
|
783
|
+
>
|
|
784
|
+
<template #command>
|
|
785
|
+
<code
|
|
786
|
+
:class="[
|
|
787
|
+
MONO_CHIP_CLASS,
|
|
788
|
+
'bg-elevated text-highlighted text-xs',
|
|
789
|
+
]"
|
|
790
|
+
>
|
|
791
|
+
{{ FRONTEND_BUILD_COMMAND }}
|
|
792
|
+
</code>
|
|
793
|
+
</template>
|
|
794
|
+
</i18n-t>
|
|
795
|
+
</template>
|
|
796
|
+
</DmsBanner>
|
|
572
797
|
|
|
573
|
-
<
|
|
798
|
+
<div v-if="isStoreLoading" :class="TILE_GRID_CLASS" aria-busy="true">
|
|
799
|
+
<DmsCard
|
|
800
|
+
v-for="placeholder in skeletonItems"
|
|
801
|
+
:key="placeholder"
|
|
802
|
+
:padded="false"
|
|
803
|
+
class="flex min-h-[228px] flex-col gap-3 p-4"
|
|
804
|
+
>
|
|
805
|
+
<USkeleton
|
|
806
|
+
:aria-label="t('dms.a11y.loading')"
|
|
807
|
+
class="size-9 rounded-[10px]"
|
|
808
|
+
/>
|
|
809
|
+
<USkeleton
|
|
810
|
+
:aria-label="t('dms.a11y.loading')"
|
|
811
|
+
class="mt-auto h-2.5 w-3/5"
|
|
812
|
+
/>
|
|
813
|
+
</DmsCard>
|
|
814
|
+
</div>
|
|
815
|
+
|
|
816
|
+
<!-- Only when nothing is on screen yet: a follow-up read that fails
|
|
817
|
+
while the frontend restarts keeps the tiles and tries again. -->
|
|
818
|
+
<DmsBanner
|
|
819
|
+
v-else-if="moduleStore.loadingError.value && !storeListing"
|
|
820
|
+
tone="error"
|
|
821
|
+
size="sm"
|
|
822
|
+
icon="i-ph-plugs"
|
|
823
|
+
:title="t('modules.store.load_error')"
|
|
824
|
+
>
|
|
825
|
+
<template #actions>
|
|
826
|
+
<UButton
|
|
827
|
+
color="error"
|
|
828
|
+
size="sm"
|
|
829
|
+
icon="i-ph-arrows-clockwise"
|
|
830
|
+
:label="t('modules.error.retry')"
|
|
831
|
+
@click="moduleStore.load()"
|
|
832
|
+
/>
|
|
833
|
+
</template>
|
|
834
|
+
</DmsBanner>
|
|
835
|
+
|
|
836
|
+
<template v-else>
|
|
574
837
|
<div :class="TOOLBAR_CLASS">
|
|
575
838
|
<DmsSearchInput
|
|
576
839
|
v-model="storeQuery"
|
|
@@ -586,7 +849,18 @@ const summaryCards = computed<StatGroupItem[]>(() =>
|
|
|
586
849
|
/>
|
|
587
850
|
</div>
|
|
588
851
|
|
|
589
|
-
<DmsCard
|
|
852
|
+
<DmsCard
|
|
853
|
+
v-if="scopedStoreModules.length === 0 && storeScope === 'available'"
|
|
854
|
+
:padded="false"
|
|
855
|
+
>
|
|
856
|
+
<DmsEmptyState
|
|
857
|
+
icon="i-ph-check-circle"
|
|
858
|
+
:title="t('modules.store.all_installed.title')"
|
|
859
|
+
:description="t('modules.store.all_installed.description')"
|
|
860
|
+
/>
|
|
861
|
+
</DmsCard>
|
|
862
|
+
|
|
863
|
+
<DmsCard v-else-if="visibleStoreModules.length === 0" :padded="false">
|
|
590
864
|
<DmsEmptyState
|
|
591
865
|
variant="no-result"
|
|
592
866
|
:title="
|
|
@@ -614,6 +888,11 @@ const summaryCards = computed<StatGroupItem[]>(() =>
|
|
|
614
888
|
v-for="entry in visibleStoreModules"
|
|
615
889
|
:key="entry.id"
|
|
616
890
|
:entry="entry"
|
|
891
|
+
:is-locked="
|
|
892
|
+
!storeListing?.enabled ||
|
|
893
|
+
(storeListing?.busy === true && entry.state !== 'busy')
|
|
894
|
+
"
|
|
895
|
+
@action="runStoreAction($event, entry)"
|
|
617
896
|
/>
|
|
618
897
|
</div>
|
|
619
898
|
</template>
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import type { DmsLogoSources } from "#dms-core/shared/types/app-config";
|
|
2
3
|
import { emailLogoUrl, emailStyles } from "./index";
|
|
3
4
|
|
|
5
|
+
interface EmailLogoConfig {
|
|
6
|
+
default?: Partial<DmsLogoSources>;
|
|
7
|
+
email?: Partial<DmsLogoSources>;
|
|
8
|
+
}
|
|
9
|
+
|
|
4
10
|
interface EmailAppConfig {
|
|
5
11
|
branding?: {
|
|
6
|
-
logo?:
|
|
7
|
-
default?: {
|
|
8
|
-
light?: string;
|
|
9
|
-
};
|
|
10
|
-
};
|
|
12
|
+
logo?: EmailLogoConfig;
|
|
11
13
|
};
|
|
12
14
|
}
|
|
13
15
|
|
|
16
|
+
const DARK_SCHEME_MEDIA = "(prefers-color-scheme: dark)";
|
|
17
|
+
|
|
14
18
|
const props = withDefaults(
|
|
15
19
|
defineProps<{
|
|
16
20
|
/** Shown as the email's heading; no heading when omitted. */
|
|
@@ -33,13 +37,20 @@ const props = withDefaults(
|
|
|
33
37
|
const appConfig = useDmsAppConfig() as EmailAppConfig;
|
|
34
38
|
const runtimeConfig = useDmsRuntimeConfig();
|
|
35
39
|
|
|
36
|
-
const
|
|
40
|
+
const logo = appConfig.branding?.logo;
|
|
37
41
|
const clientBaseUrl = runtimeConfig.public.dms?.clientBaseUrl ?? "";
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
|
|
43
|
+
function logoSource(path: string | undefined): string {
|
|
44
|
+
if (props.publicLogoOnly) return emailLogoUrl(path, clientBaseUrl);
|
|
45
|
+
return path?.startsWith("/") ? `${clientBaseUrl}${path}` : (path ?? "");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const logoUrl = logoSource(logo?.email?.light || logo?.default?.light);
|
|
49
|
+
// Offered to the mail clients that follow the reader's dark mode; the others
|
|
50
|
+
// skip the picture's source and draw the light image. Taken from the email
|
|
51
|
+
// slot only, so an instance that sets none keeps its single image.
|
|
52
|
+
const darkCandidate = logoSource(logo?.email?.dark);
|
|
53
|
+
const darkLogoUrl = darkCandidate === logoUrl ? "" : darkCandidate;
|
|
43
54
|
</script>
|
|
44
55
|
|
|
45
56
|
<template>
|
|
@@ -52,7 +63,16 @@ const logoUrl = props.publicLogoOnly
|
|
|
52
63
|
<EContainer :style="emailStyles.container">
|
|
53
64
|
<ESection :style="emailStyles.card">
|
|
54
65
|
<ESection v-if="logoUrl" :style="emailStyles.logo">
|
|
66
|
+
<picture v-if="darkLogoUrl">
|
|
67
|
+
<source :media="DARK_SCHEME_MEDIA" :srcset="darkLogoUrl" />
|
|
68
|
+
<EImg
|
|
69
|
+
:src="logoUrl"
|
|
70
|
+
:alt="logoAlt"
|
|
71
|
+
:style="emailStyles.logoImage"
|
|
72
|
+
/>
|
|
73
|
+
</picture>
|
|
55
74
|
<EImg
|
|
75
|
+
v-else
|
|
56
76
|
:src="logoUrl"
|
|
57
77
|
:alt="logoAlt"
|
|
58
78
|
:style="emailStyles.logoImage"
|
|
@@ -4,6 +4,7 @@ import StageCard, {
|
|
|
4
4
|
type StageCardTone,
|
|
5
5
|
} from "./build/components/layout/StageCard.vue";
|
|
6
6
|
import EmptyLayout from "./custom-layouts/EmptyLayout.vue";
|
|
7
|
+
import { publicErrorMessage } from "./build/utils/publicErrorMessage";
|
|
7
8
|
|
|
8
9
|
interface ErrorConfig {
|
|
9
10
|
icon: string;
|
|
@@ -66,10 +67,12 @@ const statusCode = computed(
|
|
|
66
67
|
() => props.error.statusCode || DEFAULT_STATUS_CODE,
|
|
67
68
|
);
|
|
68
69
|
|
|
70
|
+
// Never the backend's address a failed request names (see
|
|
71
|
+
// `publicErrorMessage`).
|
|
69
72
|
const visibleErrorMessage = computed(() =>
|
|
70
73
|
STATUSES_WITHOUT_ERROR_MESSAGE.has(statusCode.value)
|
|
71
74
|
? undefined
|
|
72
|
-
: props.error.message,
|
|
75
|
+
: publicErrorMessage(props.error.message),
|
|
73
76
|
);
|
|
74
77
|
|
|
75
78
|
const errorConfig = computed(
|
|
@@ -89,7 +92,7 @@ const description = computed(() =>
|
|
|
89
92
|
);
|
|
90
93
|
|
|
91
94
|
const handleError = async () => {
|
|
92
|
-
|
|
95
|
+
clearDmsError();
|
|
93
96
|
if (!loggedIn.value) {
|
|
94
97
|
await redirectToAuth(homepage);
|
|
95
98
|
} else {
|
|
@@ -89,7 +89,7 @@ export default defineDmsMiddleware(async (to, from) => {
|
|
|
89
89
|
const moduleEntry = siteLayout.modules.value?.[moduleId];
|
|
90
90
|
|
|
91
91
|
if (!moduleId || !moduleEntry) {
|
|
92
|
-
throw
|
|
92
|
+
throw createDmsError({
|
|
93
93
|
statusCode: MODULE_NOT_FOUND_STATUS,
|
|
94
94
|
statusMessage: MODULE_NOT_FOUND_MESSAGE,
|
|
95
95
|
data: { kind: MODULE_NOT_FOUND_KIND },
|
|
@@ -8,7 +8,7 @@ export default defineDmsMiddleware(async (to, from) => {
|
|
|
8
8
|
// Unsaved changes anywhere (the page's forms, an open drawer or modal, a
|
|
9
9
|
// settings panel): one warning dialog, whatever holds them.
|
|
10
10
|
if (!(await confirmLeave())) {
|
|
11
|
-
return
|
|
11
|
+
return abortDmsNavigation();
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
const { executeGuards } = useLeaveGuard();
|
|
@@ -17,6 +17,6 @@ export default defineDmsMiddleware(async (to, from) => {
|
|
|
17
17
|
const canLeave = await executeGuards(pageKey);
|
|
18
18
|
|
|
19
19
|
if (!canLeave) {
|
|
20
|
-
return
|
|
20
|
+
return abortDmsNavigation();
|
|
21
21
|
}
|
|
22
22
|
});
|