@antelopejs/dms 0.9.8 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +171 -0
- package/README.md +1 -1
- package/data/module-store/catalog.json +2 -2
- package/dist/attachments/table-view.js +2 -2
- package/dist/attachments/table-view.js.map +1 -1
- package/dist/automation/actions.d.ts +2 -0
- package/dist/automation/actions.js +116 -71
- package/dist/automation/actions.js.map +1 -1
- package/dist/automation/i18n.d.ts +4 -0
- package/dist/automation/i18n.js +19 -0
- package/dist/automation/i18n.js.map +1 -0
- package/dist/automation/send-notification.d.ts +21 -0
- package/dist/automation/send-notification.js +163 -0
- package/dist/automation/send-notification.js.map +1 -0
- package/dist/automation/triggers.js +19 -25
- package/dist/automation/triggers.js.map +1 -1
- package/dist/client-origin-cors.d.ts +1 -0
- package/dist/client-origin-cors.js +19 -0
- package/dist/client-origin-cors.js.map +1 -0
- package/dist/config.d.ts +3 -2
- package/dist/config.js +5 -7
- package/dist/config.js.map +1 -1
- package/dist/frontend-module.d.ts +4 -0
- package/dist/frontend-module.js +37 -0
- package/dist/frontend-module.js.map +1 -0
- package/dist/implementations/dms/client-ip.js +1 -1
- package/dist/implementations/dms/client-ip.js.map +1 -1
- package/dist/implementations/dms/dev-reload.d.ts +5 -0
- package/dist/implementations/dms/dev-reload.js +23 -3
- package/dist/implementations/dms/dev-reload.js.map +1 -1
- package/dist/implementations/dms/frontend-modules.d.ts +2 -4
- package/dist/implementations/dms/frontend-modules.js +38 -94
- package/dist/implementations/dms/frontend-modules.js.map +1 -1
- package/dist/implementations/dms/frontend-ready.d.ts +12 -2
- package/dist/implementations/dms/frontend-ready.js +34 -4
- package/dist/implementations/dms/frontend-ready.js.map +1 -1
- package/dist/implementations/dms/layout-banners.d.ts +2 -1
- package/dist/implementations/dms/layout-banners.js +9 -0
- package/dist/implementations/dms/layout-banners.js.map +1 -1
- package/dist/implementations/dms/manifest.d.ts +7 -2
- package/dist/implementations/dms/manifest.js +12 -7
- package/dist/implementations/dms/manifest.js.map +1 -1
- package/dist/implementations/dms/page.d.ts +4 -3
- package/dist/implementations/dms/page.js +49 -18
- package/dist/implementations/dms/page.js.map +1 -1
- package/dist/implementations/dms/permissions-resolver.d.ts +2 -2
- package/dist/implementations/dms/permissions-resolver.js +2 -2
- package/dist/implementations/dms/permissions-resolver.js.map +1 -1
- package/dist/implementations/dms/realtime.js +1 -0
- package/dist/implementations/dms/realtime.js.map +1 -1
- package/dist/implementations/dms-base/bulk-selection.d.ts +1 -1
- package/dist/implementations/dms-base/bulk-selection.js +23 -1
- package/dist/implementations/dms-base/bulk-selection.js.map +1 -1
- package/dist/implementations/dms-base/filter-tokens.js +5 -3
- package/dist/implementations/dms-base/filter-tokens.js.map +1 -1
- package/dist/implementations/dms-base/search-route.d.ts +1 -0
- package/dist/implementations/dms-base/search-route.js +35 -13
- package/dist/implementations/dms-base/search-route.js.map +1 -1
- package/dist/implementations/dms-base/table-view.js +11 -6
- package/dist/implementations/dms-base/table-view.js.map +1 -1
- package/dist/implementations/dms-notifications/index.d.ts +2 -2
- package/dist/implementations/dms-notifications/index.js +5 -5
- package/dist/implementations/dms-notifications/index.js.map +1 -1
- package/dist/index.js +32 -55
- package/dist/index.js.map +1 -1
- package/dist/pages/modules/index.d.ts +1 -0
- package/dist/pages/modules/index.js +1 -0
- package/dist/pages/modules/index.js.map +1 -1
- package/dist/pages/modules/modules-store.d.ts +9 -0
- package/dist/pages/modules/modules-store.js +30 -0
- package/dist/pages/modules/modules-store.js.map +1 -0
- package/dist/pages/settings/users/account-credentials.js +2 -2
- package/dist/pages/settings/users/account-credentials.js.map +1 -1
- package/dist/pages/settings/users/account-data-store.js +25 -8
- package/dist/pages/settings/users/account-data-store.js.map +1 -1
- package/dist/pages/settings/users/invite-extension-routes.js +9 -3
- package/dist/pages/settings/users/invite-extension-routes.js.map +1 -1
- package/dist/pages/settings/users/member-management.js +13 -14
- package/dist/pages/settings/users/member-management.js.map +1 -1
- package/dist/pages/settings/users/profile.d.ts +1 -4
- package/dist/pages/settings/users/profile.js +0 -35
- package/dist/pages/settings/users/profile.js.map +1 -1
- package/dist/pages/settings/users/role-editor-store.js +26 -18
- package/dist/pages/settings/users/role-editor-store.js.map +1 -1
- package/dist/pages/settings/users/role-editor.d.ts +0 -1
- package/dist/pages/settings/users/role-editor.js +1 -2
- package/dist/pages/settings/users/role-editor.js.map +1 -1
- package/dist/pages/settings/users/role-preview.js +1 -2
- package/dist/pages/settings/users/role-preview.js.map +1 -1
- package/dist/pages/settings/users/roles.js +2 -2
- package/dist/pages/settings/users/roles.js.map +1 -1
- package/dist/pages/settings/users/two-factor-operations.js.map +1 -1
- package/dist/realtime/broker.d.ts +6 -0
- package/dist/realtime/broker.js +8 -1
- package/dist/realtime/broker.js.map +1 -1
- package/dist/realtime/presence.d.ts +8 -3
- package/dist/realtime/presence.js +8 -4
- package/dist/realtime/presence.js.map +1 -1
- package/dist/realtime/sessions.d.ts +11 -1
- package/dist/realtime/sessions.js +21 -3
- package/dist/realtime/sessions.js.map +1 -1
- package/dist/realtime/table-view.d.ts +2 -2
- package/dist/realtime/table-view.js +4 -3
- package/dist/realtime/table-view.js.map +1 -1
- package/dist/routes/auth/client-ip.d.ts +1 -0
- package/dist/routes/auth/client-ip.js +18 -0
- package/dist/routes/auth/client-ip.js.map +1 -1
- package/dist/routes/auth/oauth/config.d.ts +2 -1
- package/dist/routes/auth/oauth/config.js +5 -1
- package/dist/routes/auth/oauth/config.js.map +1 -1
- package/dist/routes/auth/session-handoff.d.ts +0 -1
- package/dist/routes/auth/session-handoff.js +0 -2
- package/dist/routes/auth/session-handoff.js.map +1 -1
- package/dist/routes/auth.js +3 -2
- package/dist/routes/auth.js.map +1 -1
- package/dist/routes/index.d.ts +0 -1
- package/dist/routes/index.js +0 -1
- package/dist/routes/index.js.map +1 -1
- package/dist/routes/realtime.d.ts +13 -1
- package/dist/routes/realtime.js +114 -29
- package/dist/routes/realtime.js.map +1 -1
- package/dist/startup-config.d.ts +2 -0
- package/dist/startup-config.js +62 -0
- package/dist/startup-config.js.map +1 -0
- package/dist/store/interfaces.d.ts +3 -2
- package/dist/store/interfaces.js +16 -6
- package/dist/store/interfaces.js.map +1 -1
- package/dist/store/listing.js +25 -15
- package/dist/store/listing.js.map +1 -1
- package/dist/store/operations.js +5 -2
- package/dist/store/operations.js.map +1 -1
- package/dist/store/requirements.js +3 -2
- package/dist/store/requirements.js.map +1 -1
- package/dist/store/runtime.d.ts +10 -1
- package/dist/store/runtime.js +33 -6
- package/dist/store/runtime.js.map +1 -1
- package/dist/store/types.d.ts +10 -0
- package/dist/utils/ensure-default-tenant.d.ts +2 -1
- package/dist/utils/ensure-default-tenant.js +13 -1
- package/dist/utils/ensure-default-tenant.js.map +1 -1
- package/dist/utils/export-jobs.js +2 -1
- package/dist/utils/export-jobs.js.map +1 -1
- package/dist/validation/auth.schema.d.ts +2 -2
- package/dist/validation/member-invite.schema.d.ts +2 -10
- package/dist/validation/member-invite.schema.js +2 -15
- package/dist/validation/member-invite.schema.js.map +1 -1
- package/frontend-vue/dms.frontend.ts +24 -5
- package/frontend-vue/dms.server.ts +17 -0
- package/frontend-vue/layers/dms-auth/server/accounts.ts +3 -4
- package/frontend-vue/layers/dms-core/app/build/composables/renderNow.ts +33 -0
- package/frontend-vue/layers/dms-core/app/build/composables/user/tablePreferences.ts +5 -1
- package/frontend-vue/layers/dms-core/app/build/utils/crossTab.ts +199 -0
- package/frontend-vue/layers/dms-core/app/build/utils/sharedRealtimeConnection.ts +410 -0
- package/frontend-vue/layers/dms-core/app/composables/auth/useApiData.ts +77 -12
- package/frontend-vue/layers/dms-core/app/composables/data-types/useDataType.ts +26 -0
- package/frontend-vue/layers/dms-core/app/composables/live/livePauseSource.ts +29 -0
- package/frontend-vue/layers/dms-core/app/composables/period/compareResolvers.ts +150 -9
- package/frontend-vue/layers/dms-core/app/composables/period/usePeriod.ts +6 -4
- package/frontend-vue/layers/dms-core/app/composables/period/usePeriodScope.ts +27 -1
- package/frontend-vue/layers/dms-core/app/composables/realtime/useUserRealtime.ts +256 -119
- package/frontend-vue/layers/dms-core/app/composables/translation/useComposedText.ts +21 -8
- package/frontend-vue/layers/dms-core/app/composables/translation/useTranslation.ts +25 -5
- package/frontend-vue/layers/dms-core/app/composables/useApiError.ts +3 -5
- package/frontend-vue/layers/dms-core/app/composables/useFieldErrors.ts +61 -26
- package/frontend-vue/layers/dms-core/app/plugins/dev-error-log.ts +16 -0
- package/frontend-vue/layers/dms-core/app/types/user.ts +6 -0
- package/frontend-vue/layers/dms-core/app/utils/composedText.ts +7 -2
- package/frontend-vue/layers/dms-core/app/utils/formatter.ts +134 -35
- package/frontend-vue/layers/dms-core/app/utils/url-interpolation.ts +18 -1
- package/frontend-vue/layers/dms-core/i18n/locales/core-en-GB.json +136 -2
- package/frontend-vue/layers/dms-core/i18n/locales/core-fr-FR.json +136 -2
- package/frontend-vue/layers/dms-core/shared/types/app-config.ts +0 -2
- package/frontend-vue/layers/dms-layout/app/app.config.ts +0 -1
- package/frontend-vue/layers/dms-layout/app/assets/css/main.css +11 -1
- package/frontend-vue/layers/dms-layout/app/assets/fonts/Geist-Italic-Variable.woff2 +0 -0
- package/frontend-vue/layers/dms-layout/app/assets/fonts/Geist-Variable.woff2 +0 -0
- package/frontend-vue/layers/dms-layout/app/assets/fonts/GeistMono-Italic-Variable.woff2 +0 -0
- package/frontend-vue/layers/dms-layout/app/assets/fonts/GeistMono-Variable.woff2 +0 -0
- package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardBanners.vue +3 -2
- package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardHeader.vue +41 -21
- package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardPageBody.vue +6 -2
- package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardSidebar.vue +4 -19
- package/frontend-vue/layers/dms-layout/app/build/components/layout/Footer.vue +11 -107
- package/frontend-vue/layers/dms-layout/app/build/components/layout/GithubStarPrompt.vue +18 -7
- package/frontend-vue/layers/dms-layout/app/build/components/layout/PageHeaderActionsOutlet.vue +4 -0
- package/frontend-vue/layers/dms-layout/app/build/components/layout/RowSidePanel.vue +43 -82
- package/frontend-vue/layers/dms-layout/app/build/components/layout/SidebarUserMenu.vue +44 -3
- package/frontend-vue/layers/dms-layout/app/build/components/layout/UserIdentity.vue +11 -3
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleCatalogTile.vue +132 -35
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleManageMenu.vue +59 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleSourceLabel.vue +25 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreBanners.vue +73 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreOperation.vue +116 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreRequirements.vue +8 -3
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreTile.vue +85 -207
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleTile.vue +10 -3
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleTileSkeleton.vue +68 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationInboxDisplay.vue +24 -8
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationInboxItem.vue +8 -5
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/region/RegionTimeZoneInput.vue +1 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/role-permissions.ts +19 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/useRoleEditor.ts +2 -1
- package/frontend-vue/layers/dms-layout/app/build/composables/layout/useSidePanelWidth.ts +31 -70
- package/frontend-vue/layers/dms-layout/app/build/composables/notification/useNotificationGroupsOpen.ts +11 -1
- package/frontend-vue/layers/dms-layout/app/build/utils/dev-reload-stream.ts +81 -0
- package/frontend-vue/layers/dms-layout/app/build/utils/github-repository.ts +2 -2
- package/frontend-vue/layers/dms-layout/app/build/utils/module-store-catalog.ts +232 -36
- package/frontend-vue/layers/dms-layout/app/build/utils/modules-catalog.ts +122 -14
- package/frontend-vue/layers/dms-layout/app/composables/layout/useLayoutBanners.ts +32 -3
- package/frontend-vue/layers/dms-layout/app/composables/layout/useServedHeaderActions.ts +49 -11
- package/frontend-vue/layers/dms-layout/app/composables/page/useModuleHistory.ts +3 -2
- package/frontend-vue/layers/dms-layout/app/composables/page/useModuleStore.ts +59 -4
- package/frontend-vue/layers/dms-layout/app/composables/page/useModuleStoreActions.ts +194 -0
- package/frontend-vue/layers/dms-layout/app/composables/page/usePageComponentPreload.ts +23 -3
- package/frontend-vue/layers/dms-layout/app/composables/page/usePageLayout.ts +4 -2
- package/frontend-vue/layers/dms-layout/app/composables/page/usePageRecordDeletion.ts +162 -0
- package/frontend-vue/layers/dms-layout/app/composables/page/useSiteLayout.ts +6 -1
- package/frontend-vue/layers/dms-layout/app/custom-layouts/DefaultLayout.vue +6 -2
- package/frontend-vue/layers/dms-layout/app/custom-layouts/SettingsLayout.vue +6 -2
- package/frontend-vue/layers/dms-layout/app/custom-pages/modules-store.vue +291 -0
- package/frontend-vue/layers/dms-layout/app/custom-pages/modules.vue +87 -474
- package/frontend-vue/layers/dms-layout/app/middleware/module-routing.global.ts +3 -0
- package/frontend-vue/layers/dms-layout/app/pages/[...slug].vue +13 -22
- package/frontend-vue/layers/dms-layout/app/plugins/command-palette-navigation.client.ts +11 -10
- package/frontend-vue/layers/dms-layout/app/plugins/command-palette-personal-pages.client.ts +22 -52
- package/frontend-vue/layers/dms-layout/app/plugins/command-palette-quick-actions.client.ts +7 -7
- package/frontend-vue/layers/dms-layout/app/plugins/command-palette-session.client.ts +11 -10
- package/frontend-vue/layers/dms-layout/app/plugins/dms-dev-reload.client.ts +14 -9
- package/frontend-vue/layers/dms-layout/app/theme/actions.ts +5 -4
- package/frontend-vue/layers/dms-layout/app/theme/form-controls.ts +9 -4
- package/frontend-vue/layers/dms-layout/app/theme/surfaces.ts +22 -6
- package/frontend-vue/layers/dms-layout/app/types/module-store.ts +9 -0
- package/frontend-vue/layers/dms-layout/app/types/page.ts +15 -1
- package/frontend-vue/layers/dms-layout/app/utils/account-menu.ts +11 -0
- package/frontend-vue/layers/dms-layout/app/utils/breadcrumb.ts +57 -0
- package/frontend-vue/layers/dms-layout/app/utils/pageQuery.ts +26 -0
- package/frontend-vue/layers/dms-layout/i18n/locales/layout-en-GB.json +45 -18
- package/frontend-vue/layers/dms-layout/i18n/locales/layout-fr-FR.json +44 -17
- package/frontend-vue/layers/dms-ui/app/build/components/containers/TargetComponentTree.vue +31 -0
- package/frontend-vue/layers/dms-ui/app/build/components/containers/constants.ts +25 -0
- package/frontend-vue/layers/dms-ui/app/build/components/containers/drawer/DynamicDrawer.vue +244 -15
- package/frontend-vue/layers/dms-ui/app/build/components/containers/modal/DynamicModal.vue +42 -25
- package/frontend-vue/layers/dms-ui/app/build/components/containers/row/RowHeader.vue +153 -0
- package/frontend-vue/layers/dms-ui/app/build/components/containers/row/RowNotFound.vue +44 -0
- package/frontend-vue/layers/dms-ui/app/build/components/containers/row/drawerRowHeader.ts +35 -0
- package/frontend-vue/layers/dms-ui/app/build/components/form/FormEntries.vue +44 -9
- package/frontend-vue/layers/dms-ui/app/build/components/form/FormErrorSummary.vue +11 -4
- package/frontend-vue/layers/dms-ui/app/build/components/form/FormFieldControl.vue +38 -5
- package/frontend-vue/layers/dms-ui/app/build/components/form/FormFieldNotes.vue +29 -5
- package/frontend-vue/layers/dms-ui/app/build/components/form/FormLoadError.vue +5 -1
- package/frontend-vue/layers/dms-ui/app/build/components/form/FormSectionNav.vue +3 -1
- package/frontend-vue/layers/dms-ui/app/build/components/form/FormSections.vue +106 -27
- package/frontend-vue/layers/dms-ui/app/build/components/table/Actions.vue +12 -4
- package/frontend-vue/layers/dms-ui/app/build/components/table/Empty.vue +4 -2
- package/frontend-vue/layers/dms-ui/app/build/components/table/FiltersRow.vue +48 -1
- package/frontend-vue/layers/dms-ui/app/build/components/table/Pagination.vue +55 -54
- package/frontend-vue/layers/dms-ui/app/build/components/table/RowSelection.vue +2 -1
- package/frontend-vue/layers/dms-ui/app/build/components/table/Table.vue +396 -288
- package/frontend-vue/layers/dms-ui/app/build/components/table/Tabs.vue +2 -1
- package/frontend-vue/layers/dms-ui/app/build/components/table/Views.vue +2 -1
- package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardAvatar.vue +59 -0
- package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardGridSkeleton.vue +19 -2
- package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardRowActions.vue +38 -0
- package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardsDisplay.vue +148 -104
- package/frontend-vue/layers/dms-ui/app/build/components/table-view/LiveHoldBanner.vue +17 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/actions/bulkSelection.ts +43 -9
- package/frontend-vue/layers/dms-ui/app/build/composables/actions/rowComponentOptions.ts +76 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/actions/rowNavigation.ts +172 -27
- package/frontend-vue/layers/dms-ui/app/build/composables/actions/useActionTargets.ts +270 -46
- package/frontend-vue/layers/dms-ui/app/build/composables/confirm/actionError.ts +6 -1
- package/frontend-vue/layers/dms-ui/app/build/composables/confirm/confirmDialogTexts.ts +2 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/containers/closingLayers.ts +186 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/containers/context.ts +14 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/containers/drawerSize.ts +229 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/containers/useResizableSize.ts +175 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/metricCells.ts +18 -35
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/numberSuffix.ts +44 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerDefaults.ts +123 -27
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerFieldTypes.ts +2 -1
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationFilter.ts +75 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationRows.ts +92 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationValue.ts +39 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/twoLineCell.ts +3 -3
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/useColumnValueRenderer.ts +6 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/form/createFormFields.ts +15 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/fieldSaved.ts +40 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/fieldValueRule.ts +62 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/formEntryContext.ts +5 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/formFooter.ts +42 -7
- package/frontend-vue/layers/dms-ui/app/build/composables/form/formLayout.ts +106 -4
- package/frontend-vue/layers/dms-ui/app/build/composables/form/formRecordLoad.ts +11 -5
- package/frontend-vue/layers/dms-ui/app/build/composables/form/formSections.ts +32 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/formValidation.ts +36 -4
- package/frontend-vue/layers/dms-ui/app/build/composables/form/readonlyValue.ts +19 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/registerFormFunctions.ts +27 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/repeaterTable.ts +78 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/serverFieldErrors.ts +49 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/toasterClearance.ts +118 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/useInstantForm.ts +12 -1
- package/frontend-vue/layers/dms-ui/app/build/composables/live/currentPageLive.ts +41 -3
- package/frontend-vue/layers/dms-ui/app/build/composables/live/livePoller.ts +10 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/live/pageReadClock.ts +28 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/live/shortcuts.ts +1 -1
- package/frontend-vue/layers/dms-ui/app/build/composables/live/usePageLiveHost.ts +17 -3
- package/frontend-vue/layers/dms-ui/app/build/composables/live/useUpdatedLabel.ts +38 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/page-toolbar/pageToolbarContext.ts +75 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/page-toolbar/toolbarControlHeight.ts +29 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/period/periodComparison.ts +52 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/period/periodDisplay.ts +21 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/period/periodShortLabels.ts +28 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/period/usePeriodDraft.ts +1 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table/useRelationFilterLabels.ts +97 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table/useRowScrollAnchor.ts +106 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table/useTable.ts +9 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table/useTableColumns.ts +1 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/archivedCount.ts +31 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/filterEditorValue.ts +38 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/formatFilterValue.ts +33 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/scrollEdges.ts +31 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useCardFields.ts +33 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useMobileDisplay.ts +48 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useScrolledPastTop.ts +41 -18
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableFooter.ts +3 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableLinkedVisit.ts +78 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableLiveHold.ts +135 -22
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableRows.ts +56 -25
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViewRowActions.ts +90 -35
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViews.ts +86 -10
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/bulkActions.ts +14 -4
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/card.ts +127 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/compareValues.ts +13 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/expandedRows.ts +28 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/groupedRows.ts +114 -1
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/linkedArrival.ts +308 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/locateRow.ts +106 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/pageArrival.ts +34 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/pinnedRows.ts +17 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/quickFilters.ts +41 -33
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/recordLink.ts +24 -8
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/tableCounts.ts +113 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/tableQuery.ts +27 -4
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/views.ts +22 -6
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/writeError.ts +21 -0
- package/frontend-vue/layers/dms-ui/app/build/utils/addressSuggestions.ts +49 -0
- package/frontend-vue/layers/dms-ui/app/build/utils/codeHighlight.ts +67 -29
- package/frontend-vue/layers/dms-ui/app/build/utils/eyebrow.ts +12 -0
- package/frontend-vue/layers/dms-ui/app/build/utils/fieldOptionsI18n.ts +51 -11
- package/frontend-vue/layers/dms-ui/app/build/utils/htmlGrammar.ts +79 -0
- package/frontend-vue/layers/dms-ui/app/build/utils/inputWidth.ts +53 -0
- package/frontend-vue/layers/dms-ui/app/build/utils/numberAdjustment.ts +6 -3
- package/frontend-vue/layers/dms-ui/app/build/utils/relativeDate.ts +19 -5
- package/frontend-vue/layers/dms-ui/app/build/utils/scrollWithin.ts +99 -0
- package/frontend-vue/layers/dms-ui/app/build/utils/shellParser.ts +1 -1
- package/frontend-vue/layers/dms-ui/app/build/utils/streamHighlight.ts +90 -0
- package/frontend-vue/layers/dms-ui/app/build/utils/urlVariables.ts +36 -14
- package/frontend-vue/layers/dms-ui/app/components/PasswordStrength.vue +1 -1
- package/frontend-vue/layers/dms-ui/app/components/RecursiveComponent.vue +9 -1
- package/frontend-vue/layers/dms-ui/app/components/blocks/LiveToggleBlock.vue +80 -32
- package/frontend-vue/layers/dms-ui/app/components/blocks/PageToolbarBlock.vue +137 -0
- package/frontend-vue/layers/dms-ui/app/components/blocks/StatGroupBlock.vue +5 -0
- package/frontend-vue/layers/dms-ui/app/components/chart/ApexChartHost.vue +16 -2
- package/frontend-vue/layers/dms-ui/app/components/chart/Chart.vue +24 -5
- package/frontend-vue/layers/dms-ui/app/components/chart/ChartCard.vue +41 -23
- package/frontend-vue/layers/dms-ui/app/components/code-snippet/CodeSnippet.vue +23 -12
- package/frontend-vue/layers/dms-ui/app/components/confirm/ConfirmModal.vue +1 -1
- package/frontend-vue/layers/dms-ui/app/components/container-footer/ContainerFooter.vue +34 -0
- package/frontend-vue/layers/dms-ui/app/components/field-row/FieldRow.vue +25 -2
- package/frontend-vue/layers/dms-ui/app/components/flow-canvas/FlowCanvas.vue +2 -2
- package/frontend-vue/layers/dms-ui/app/components/form/Form.vue +119 -36
- package/frontend-vue/layers/dms-ui/app/components/form/components/Cascader.vue +53 -22
- package/frontend-vue/layers/dms-ui/app/components/form/components/DatePicker.vue +20 -1
- package/frontend-vue/layers/dms-ui/app/components/form/components/Display.vue +13 -1
- package/frontend-vue/layers/dms-ui/app/components/form/components/Image.vue +8 -3
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputAddress.vue +53 -5
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputCode.vue +29 -5
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputNumber.vue +45 -8
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputPercentage.vue +28 -5
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputSecret.vue +5 -0
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputText.vue +19 -2
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputTime.vue +2 -1
- package/frontend-vue/layers/dms-ui/app/components/form/components/Relation.vue +226 -65
- package/frontend-vue/layers/dms-ui/app/components/form/components/Repeater.vue +80 -30
- package/frontend-vue/layers/dms-ui/app/components/form/components/RepeaterTable.vue +210 -0
- package/frontend-vue/layers/dms-ui/app/components/form/components/Select.vue +4 -2
- package/frontend-vue/layers/dms-ui/app/components/grid/GridRow.vue +11 -2
- package/frontend-vue/layers/dms-ui/app/components/key-value-list/KeyValueList.vue +79 -70
- package/frontend-vue/layers/dms-ui/app/components/kpi/KpiCard.vue +117 -21
- package/frontend-vue/layers/dms-ui/app/components/meter/Meter.vue +2 -1
- package/frontend-vue/layers/dms-ui/app/components/period/PeriodSelector.vue +113 -34
- package/frontend-vue/layers/dms-ui/app/components/save-bar/SaveBar.vue +14 -2
- package/frontend-vue/layers/dms-ui/app/components/section-header/Eyebrow.vue +6 -1
- package/frontend-vue/layers/dms-ui/app/components/segmented/Segmented.vue +13 -0
- package/frontend-vue/layers/dms-ui/app/components/stat-group/StatGroup.vue +52 -3
- package/frontend-vue/layers/dms-ui/app/components/tab/Tab.vue +2 -1
- package/frontend-vue/layers/dms-ui/app/components/table-view/CascaderPath.vue +74 -25
- package/frontend-vue/layers/dms-ui/app/components/table-view/KanbanBoard.vue +48 -44
- package/frontend-vue/layers/dms-ui/app/components/table-view/KanbanDisplay.vue +4 -1
- package/frontend-vue/layers/dms-ui/app/components/table-view/TableView.vue +426 -97
- package/frontend-vue/layers/dms-ui/app/components/top-list/TopListCard.vue +33 -5
- package/frontend-vue/layers/dms-ui/app/composables/chart/apexCategoryLabels.ts +68 -0
- package/frontend-vue/layers/dms-ui/app/composables/chart/apexDatetimeBuckets.ts +306 -0
- package/frontend-vue/layers/dms-ui/app/composables/chart/formatValue.ts +4 -3
- package/frontend-vue/layers/dms-ui/app/composables/chart/heatmapColors.ts +93 -0
- package/frontend-vue/layers/dms-ui/app/composables/chart/localizeSeries.ts +62 -0
- package/frontend-vue/layers/dms-ui/app/composables/chart/useApexChart.ts +116 -8
- package/frontend-vue/layers/dms-ui/app/composables/chart/useApexChart.types.ts +7 -0
- package/frontend-vue/layers/dms-ui/app/composables/containers/types.ts +84 -1
- package/frontend-vue/layers/dms-ui/app/composables/containers/useDrawer.ts +69 -8
- package/frontend-vue/layers/dms-ui/app/composables/form/types/field-saved.ts +11 -0
- package/frontend-vue/layers/dms-ui/app/composables/form/types/field.ts +16 -0
- package/frontend-vue/layers/dms-ui/app/composables/form/types/functions.ts +1 -0
- package/frontend-vue/layers/dms-ui/app/composables/form/useForm.ts +189 -28
- package/frontend-vue/layers/dms-ui/app/composables/live/usePageLive.ts +29 -12
- package/frontend-vue/layers/dms-ui/app/composables/page-toolbar/usePageToolbarSize.ts +30 -0
- package/frontend-vue/layers/dms-ui/app/composables/table-view/kanban.ts +4 -2
- package/frontend-vue/layers/dms-ui/app/composables/table-view/types/action-target.ts +22 -3
- package/frontend-vue/layers/dms-ui/app/composables/table-view/types/config.ts +4 -0
- package/frontend-vue/layers/dms-ui/app/composables/table-view/types/display.ts +24 -1
- package/frontend-vue/layers/dms-ui/app/plugins/closing-layers.client.ts +10 -0
- package/frontend-vue/layers/dms-ui/app/plugins/live-pause-source.ts +15 -0
- package/frontend-vue/layers/dms-ui/app/plugins/register.ts +2 -0
- package/frontend-vue/layers/dms-ui/app/types/input-number.ts +3 -2
- package/frontend-vue/layers/dms-ui/app/types/page-toolbar.ts +7 -0
- package/frontend-vue/layers/dms-ui/app/types/row-action.ts +0 -2
- package/frontend-vue/layers/dms-ui/app/types/row-navigation.ts +17 -0
- package/frontend-vue/layers/dms-ui/app/types/table/query.ts +2 -1
- package/frontend-vue/layers/dms-ui/app/utils/blockRefresh.ts +3 -1
- package/frontend-vue/layers/dms-ui/app/utils/cascader.ts +94 -3
- package/frontend-vue/layers/dms-ui/app/utils/componentTree.ts +24 -0
- package/frontend-vue/layers/dms-ui/i18n/locales/ui-en-GB.json +20 -5
- package/frontend-vue/layers/dms-ui/i18n/locales/ui-fr-FR.json +20 -5
- package/frontend-vue/package.json +6 -2
- package/package.json +11 -10
- package/skills/dms/SKILL.md +1 -1
- package/skills/dms-auth/SKILL.md +5 -3
- package/skills/dms-best-practices/REFERENCE.md +2 -0
- package/skills/dms-best-practices/SKILL.md +4 -0
- package/skills/dms-module/SKILL.md +3 -2
- package/skills/dms-pages/REFERENCE.md +129 -16
- package/skills/dms-pages/SKILL.md +1 -1
- package/skills/dms-project/DEV-SERVERS.md +23 -1
- package/skills/dms-project/REFERENCE.md +1 -1
- package/skills/dms-project/SKILL.md +4 -1
- package/skills/dms-project/scripts/dms-dev.sh +205 -17
- package/dist/hooks/tenant-instances.d.ts +0 -1
- package/dist/hooks/tenant-instances.js +0 -13
- package/dist/hooks/tenant-instances.js.map +0 -1
- package/dist/routes/startup-gate.d.ts +0 -7
- package/dist/routes/startup-gate.js +0 -39
- package/dist/routes/startup-gate.js.map +0 -1
- package/frontend-vue/layers/dms-core/app/composables/period/periodRenderNow.ts +0 -42
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import type { Tone } from "#dms-ui/app/types/tone";
|
|
2
2
|
import type { StatusPillDot } from "#dms-ui/app/components/status-pill/StatusPill.vue";
|
|
3
|
-
import type
|
|
3
|
+
import { type ModuleCatalogEntry, MODULE_URL_PREFIX } from "../../types/page";
|
|
4
4
|
import type {
|
|
5
|
+
ModuleSourceKind,
|
|
5
6
|
StoreListingEntry,
|
|
6
7
|
StoreModuleState,
|
|
7
8
|
StoreOperationKind,
|
|
8
9
|
} from "../../types/module-store";
|
|
9
|
-
import
|
|
10
|
+
import {
|
|
11
|
+
type DisplayResolver,
|
|
12
|
+
compareDisplayNames,
|
|
13
|
+
moduleStatus,
|
|
14
|
+
} from "./modules-catalog";
|
|
10
15
|
|
|
11
16
|
/** A store module as the Modules page filters and draws it. */
|
|
12
17
|
export type ModuleStoreEntry = StoreListingEntry & {
|
|
@@ -17,13 +22,19 @@ export type ModuleStoreEntry = StoreListingEntry & {
|
|
|
17
22
|
/** Which store modules the store section shows. */
|
|
18
23
|
export type StoreScope = "all" | "available" | "installed";
|
|
19
24
|
|
|
20
|
-
/**
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
/**
|
|
26
|
+
* The scopes in the order the store's switch shows them. The store is for
|
|
27
|
+
* discovering, so it opens on what can still be installed; "all" comes last,
|
|
28
|
+
* the widest view.
|
|
29
|
+
*/
|
|
30
|
+
export const STORE_SCOPES: readonly StoreScope[] = [
|
|
31
|
+
"available",
|
|
32
|
+
"installed",
|
|
33
|
+
"all",
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
/** The scope the store opens on. */
|
|
37
|
+
export const DEFAULT_STORE_SCOPE: StoreScope = "available";
|
|
27
38
|
|
|
28
39
|
/** One action a store tile offers. */
|
|
29
40
|
export interface StoreAction {
|
|
@@ -42,18 +53,18 @@ export interface StoreAction {
|
|
|
42
53
|
|
|
43
54
|
const CATEGORY_PREFIX = "$modules.store.category";
|
|
44
55
|
|
|
56
|
+
/** The icon a tile's footer names a module's source with. */
|
|
57
|
+
export const MODULE_SOURCE_ICONS: Record<ModuleSourceKind, string> = {
|
|
58
|
+
npm: "i-ph-package",
|
|
59
|
+
github: "i-ph-github-logo",
|
|
60
|
+
gitlab: "i-ph-gitlab-logo",
|
|
61
|
+
git: "i-ph-git-branch",
|
|
62
|
+
local: "i-ph-folder-simple",
|
|
63
|
+
};
|
|
64
|
+
|
|
45
65
|
/** The command that turns a production frontend into one serving new layers. */
|
|
46
66
|
export const FRONTEND_BUILD_COMMAND = "ajs dms build";
|
|
47
67
|
|
|
48
|
-
const STATUSES: Record<StoreModuleState, StoreTileStatus> = {
|
|
49
|
-
available: { tone: "neutral", labelKey: "available", dot: "none" },
|
|
50
|
-
busy: { tone: "info", labelKey: "busy", dot: "live" },
|
|
51
|
-
active: { tone: "success", labelKey: "active" },
|
|
52
|
-
disabled: { tone: "neutral", labelKey: "disabled" },
|
|
53
|
-
error: { tone: "error", labelKey: "error" },
|
|
54
|
-
pending: { tone: "warning", labelKey: "pending" },
|
|
55
|
-
};
|
|
56
|
-
|
|
57
68
|
const ACTIONS: Record<StoreOperationKind, StoreAction> = {
|
|
58
69
|
install: {
|
|
59
70
|
kind: "install",
|
|
@@ -85,21 +96,85 @@ const INSTALLED_STATES = new Set<StoreModuleState>([
|
|
|
85
96
|
"pending",
|
|
86
97
|
]);
|
|
87
98
|
|
|
99
|
+
/**
|
|
100
|
+
* The category a module is filed under, the same on its installed tile and
|
|
101
|
+
* its store tile: the one its registration names, else the store catalog's.
|
|
102
|
+
*/
|
|
103
|
+
export function resolveCatalogCategory(
|
|
104
|
+
registered: Pick<ModuleCatalogEntry, "catalogCategory"> | undefined,
|
|
105
|
+
entry: Pick<StoreListingEntry, "category">,
|
|
106
|
+
): string {
|
|
107
|
+
return (
|
|
108
|
+
registered?.catalogCategory?.trim() ||
|
|
109
|
+
`${CATEGORY_PREFIX}.${entry.category}`
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
88
113
|
export function toModuleStoreEntry(
|
|
89
114
|
entry: StoreListingEntry,
|
|
90
|
-
registeredModules: readonly Pick<
|
|
115
|
+
registeredModules: readonly Pick<
|
|
116
|
+
ModuleCatalogEntry,
|
|
117
|
+
"id" | "title" | "catalogCategory"
|
|
118
|
+
>[] = [],
|
|
91
119
|
): ModuleStoreEntry {
|
|
120
|
+
const registered = registeredModules.find((module) => module.id === entry.id);
|
|
92
121
|
return {
|
|
93
122
|
...entry,
|
|
94
123
|
// The registration also names Installed and navigation. Keep the catalog
|
|
95
124
|
// fallback for unloaded modules, whose translations may not be served.
|
|
96
|
-
title:
|
|
97
|
-
|
|
98
|
-
entry.title,
|
|
99
|
-
catalogCategory: `${CATEGORY_PREFIX}.${entry.category}`,
|
|
125
|
+
title: registered?.title ?? entry.title,
|
|
126
|
+
catalogCategory: resolveCatalogCategory(registered, entry),
|
|
100
127
|
};
|
|
101
128
|
}
|
|
102
129
|
|
|
130
|
+
/** A version as written, not a range: what an installed tile prints. */
|
|
131
|
+
const PLAIN_VERSION = /^\d+\.\d+\.\d+/;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Installed modules with the version, category and source their registration
|
|
135
|
+
* leaves out, read from the store listing of the same id. A module that registers
|
|
136
|
+
* neither still reads like the others on its tile and in the filters.
|
|
137
|
+
*/
|
|
138
|
+
export function withStoreDetails<T extends ModuleCatalogEntry>(
|
|
139
|
+
modules: readonly T[],
|
|
140
|
+
store: readonly StoreListingEntry[],
|
|
141
|
+
): T[] {
|
|
142
|
+
const byId = new Map(store.map((entry) => [entry.id, entry]));
|
|
143
|
+
return modules.map((module) => {
|
|
144
|
+
const entry = byId.get(module.id);
|
|
145
|
+
if (!entry) return module;
|
|
146
|
+
const installed = entry.installedVersion;
|
|
147
|
+
return {
|
|
148
|
+
...module,
|
|
149
|
+
version:
|
|
150
|
+
module.version ??
|
|
151
|
+
(installed && PLAIN_VERSION.test(installed) ? installed : undefined),
|
|
152
|
+
catalogCategory: resolveCatalogCategory(module, entry),
|
|
153
|
+
source: entry.source,
|
|
154
|
+
};
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Where a store tile's Open button leads: the landing page of the installed
|
|
160
|
+
* module of the same id, when the caller may open it and it has pages (a
|
|
161
|
+
* module without one lands on its own address, which has nothing to show).
|
|
162
|
+
*/
|
|
163
|
+
export function storeOpenTarget(
|
|
164
|
+
entry: Pick<StoreListingEntry, "id">,
|
|
165
|
+
installedModules: readonly Pick<
|
|
166
|
+
ModuleCatalogEntry,
|
|
167
|
+
"id" | "hasAccess" | "landingSlug"
|
|
168
|
+
>[],
|
|
169
|
+
): string | undefined {
|
|
170
|
+
const module = installedModules.find(
|
|
171
|
+
(candidate) => candidate.id === entry.id,
|
|
172
|
+
);
|
|
173
|
+
if (!module?.hasAccess || !module.landingSlug) return undefined;
|
|
174
|
+
const ownAddress = `${MODULE_URL_PREFIX}/${entry.id}`;
|
|
175
|
+
return module.landingSlug === ownAddress ? undefined : module.landingSlug;
|
|
176
|
+
}
|
|
177
|
+
|
|
103
178
|
/** Whether the module is installed, from the store or by the config. */
|
|
104
179
|
export function isInstalled(entry: StoreListingEntry): boolean {
|
|
105
180
|
if (INSTALLED_STATES.has(entry.state)) return true;
|
|
@@ -115,29 +190,26 @@ export function filterByScope<T extends StoreListingEntry>(
|
|
|
115
190
|
return entries.filter((entry) => isInstalled(entry) === wantsInstalled);
|
|
116
191
|
}
|
|
117
192
|
|
|
118
|
-
/** The store modules, alphabetical by their shown name. */
|
|
193
|
+
/** The store modules, alphabetical by their shown name in `locale`'s order. */
|
|
119
194
|
export function sortStoreModules<T extends StoreListingEntry>(
|
|
120
195
|
entries: readonly T[],
|
|
121
196
|
resolve: DisplayResolver,
|
|
197
|
+
locale?: string,
|
|
122
198
|
): T[] {
|
|
199
|
+
const compare = compareDisplayNames(locale);
|
|
123
200
|
return [...entries].sort((a, b) =>
|
|
124
|
-
resolve(a.title)
|
|
201
|
+
compare(resolve(a.title), resolve(b.title)),
|
|
125
202
|
);
|
|
126
203
|
}
|
|
127
204
|
|
|
128
|
-
export function storeTileStatus(entry: StoreListingEntry): StoreTileStatus {
|
|
129
|
-
if (entry.state === "active" && entry.updateAvailable) {
|
|
130
|
-
return { tone: "warning", labelKey: "update_available" };
|
|
131
|
-
}
|
|
132
|
-
return STATUSES[entry.state];
|
|
133
|
-
}
|
|
134
|
-
|
|
135
205
|
/**
|
|
136
206
|
* What the tile offers, the main action first. A module in error offers to
|
|
137
207
|
* try its last step again: installing it when the file does not hold it,
|
|
138
208
|
* applying the file otherwise.
|
|
139
209
|
*/
|
|
140
210
|
export function storeActions(entry: StoreListingEntry): StoreAction[] {
|
|
211
|
+
// The developer's working copy is theirs to change in antelope.config.ts.
|
|
212
|
+
if (entry.isWorkingCopy) return [];
|
|
141
213
|
const installed = entry.installedVersion !== undefined;
|
|
142
214
|
const byState: Record<StoreModuleState, StoreOperationKind[]> = {
|
|
143
215
|
available: ["install"],
|
|
@@ -166,6 +238,7 @@ export type StoreActionBlock =
|
|
|
166
238
|
| "incompatible"
|
|
167
239
|
| "frontend"
|
|
168
240
|
| "interfaces"
|
|
241
|
+
| "used_by_project"
|
|
169
242
|
| "dependents";
|
|
170
243
|
|
|
171
244
|
/** Actions that load a new release of the module. */
|
|
@@ -197,10 +270,55 @@ export function storeActionBlock(
|
|
|
197
270
|
kind: StoreOperationKind,
|
|
198
271
|
): StoreActionBlock | undefined {
|
|
199
272
|
if (RELEASE_ACTIONS.has(kind)) return releaseBlock(entry, kind);
|
|
200
|
-
if (TAKE_DOWN_ACTIONS.has(kind)
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
return undefined;
|
|
273
|
+
if (!TAKE_DOWN_ACTIONS.has(kind)) return undefined;
|
|
274
|
+
// The project cannot be removed first: only a change to its code frees it.
|
|
275
|
+
if (entry.usedByProject) return "used_by_project";
|
|
276
|
+
return entry.dependents.length > 0 ? "dependents" : undefined;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/** Translates an i18n key with its named parameters. */
|
|
280
|
+
export type StoreTranslate = (
|
|
281
|
+
key: string,
|
|
282
|
+
params?: Record<string, string>,
|
|
283
|
+
) => string;
|
|
284
|
+
|
|
285
|
+
const LIST_SEPARATOR = ", ";
|
|
286
|
+
|
|
287
|
+
const BLOCK_MESSAGES: Record<
|
|
288
|
+
StoreActionBlock,
|
|
289
|
+
(entry: StoreListingEntry, t: StoreTranslate) => string
|
|
290
|
+
> = {
|
|
291
|
+
no_release: (_entry, t) => t("modules.store.no_release"),
|
|
292
|
+
incompatible: (entry, t) =>
|
|
293
|
+
t("modules.store.incompatible", {
|
|
294
|
+
range: entry.requiredInterfaceRange ?? "",
|
|
295
|
+
}),
|
|
296
|
+
frontend: (entry, t) =>
|
|
297
|
+
t("modules.store.frontend_requirement.needs", {
|
|
298
|
+
range: entry.frontendRequirement?.range ?? "",
|
|
299
|
+
running: entry.frontendRequirement?.running ?? "",
|
|
300
|
+
}),
|
|
301
|
+
interfaces: (entry, t) =>
|
|
302
|
+
t("modules.store.requires_first", {
|
|
303
|
+
interfaces: entry.missingInterfaces
|
|
304
|
+
.map((missing) => missing.interfacePackage)
|
|
305
|
+
.join(LIST_SEPARATOR),
|
|
306
|
+
}),
|
|
307
|
+
used_by_project: (_entry, t) => t("modules.store.used_by_project"),
|
|
308
|
+
dependents: (entry, t) =>
|
|
309
|
+
t("modules.store.used_by", {
|
|
310
|
+
modules: entry.dependents.join(LIST_SEPARATOR),
|
|
311
|
+
}),
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
/** Why `kind` cannot run on the module, worded for its tile, if it cannot. */
|
|
315
|
+
export function storeBlockMessage(
|
|
316
|
+
entry: StoreListingEntry,
|
|
317
|
+
kind: StoreOperationKind,
|
|
318
|
+
t: StoreTranslate,
|
|
319
|
+
): string | undefined {
|
|
320
|
+
const block = storeActionBlock(entry, kind);
|
|
321
|
+
return block ? BLOCK_MESSAGES[block](entry, t) : undefined;
|
|
204
322
|
}
|
|
205
323
|
|
|
206
324
|
/** Whether `kind` first asks which modules implement the missing interfaces. */
|
|
@@ -210,3 +328,81 @@ export function needsDependencyChoice(
|
|
|
210
328
|
): boolean {
|
|
211
329
|
return PICKS_DEPENDENCIES.has(kind) && entry.missingInterfaces.length > 0;
|
|
212
330
|
}
|
|
331
|
+
|
|
332
|
+
/** What an installed module's pill says. */
|
|
333
|
+
export interface InstalledTileStatus {
|
|
334
|
+
tone: Tone;
|
|
335
|
+
/** Full i18n key of the label. */
|
|
336
|
+
labelKey: string;
|
|
337
|
+
dot?: StatusPillDot;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/** Store states an installed module's pill says before anything else. */
|
|
341
|
+
const STORE_STATE_PILLS: Partial<
|
|
342
|
+
Record<StoreModuleState, InstalledTileStatus>
|
|
343
|
+
> = {
|
|
344
|
+
busy: { tone: "info", labelKey: "modules.store.state.busy", dot: "live" },
|
|
345
|
+
error: { tone: "error", labelKey: "modules.store.state.error" },
|
|
346
|
+
disabled: { tone: "warning", labelKey: "modules.store.state.disabled" },
|
|
347
|
+
pending: { tone: "warning", labelKey: "modules.store.state.pending" },
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
const MODULE_STATUS_PILLS: Record<
|
|
351
|
+
ReturnType<typeof moduleStatus>,
|
|
352
|
+
InstalledTileStatus
|
|
353
|
+
> = {
|
|
354
|
+
live: { tone: "success", labelKey: "modules.status.live" },
|
|
355
|
+
beta: { tone: "secondary", labelKey: "modules.status.beta" },
|
|
356
|
+
update: { tone: "warning", labelKey: "modules.status.update" },
|
|
357
|
+
attention: { tone: "error", labelKey: "modules.status.attention" },
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* The pill of an installed module: what the store says of it first (an
|
|
362
|
+
* operation, an error, paused, not applied, a frontend to restart, an
|
|
363
|
+
* update), then what the module reports of itself, Active otherwise.
|
|
364
|
+
*/
|
|
365
|
+
export function installedTileStatus(
|
|
366
|
+
module: ModuleCatalogEntry,
|
|
367
|
+
entry: StoreListingEntry | undefined,
|
|
368
|
+
): InstalledTileStatus {
|
|
369
|
+
const storeStatus = entry && STORE_STATE_PILLS[entry.state];
|
|
370
|
+
if (storeStatus) return storeStatus;
|
|
371
|
+
if (entry && isAwaitingFrontend(entry)) {
|
|
372
|
+
return { tone: "warning", labelKey: "modules.status.restart_required" };
|
|
373
|
+
}
|
|
374
|
+
if (entry?.updateAvailable) {
|
|
375
|
+
return { tone: "warning", labelKey: "modules.status.update" };
|
|
376
|
+
}
|
|
377
|
+
return MODULE_STATUS_PILLS[moduleStatus(module)];
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Installed store modules that register no module of their own, as the
|
|
382
|
+
* Installed grid lists them: a paused module, one that did not start, or one
|
|
383
|
+
* without pages. antelope.config.ts still declares them, so they stay listed
|
|
384
|
+
* and managed there, with what the store knows of them.
|
|
385
|
+
*/
|
|
386
|
+
export function storeOnlyModules(
|
|
387
|
+
store: readonly ModuleStoreEntry[],
|
|
388
|
+
registered: readonly Pick<ModuleCatalogEntry, "id">[],
|
|
389
|
+
): ModuleCatalogEntry[] {
|
|
390
|
+
const registeredIds = new Set(registered.map((module) => module.id));
|
|
391
|
+
return store
|
|
392
|
+
.filter((entry) => isInstalled(entry) && !registeredIds.has(entry.id))
|
|
393
|
+
.map((entry) => ({
|
|
394
|
+
id: entry.id,
|
|
395
|
+
title: entry.title,
|
|
396
|
+
description: entry.description,
|
|
397
|
+
icon: entry.icon,
|
|
398
|
+
hasAccess: true,
|
|
399
|
+
// Nothing to open: the module serves no page.
|
|
400
|
+
landingSlug: "",
|
|
401
|
+
catalogCategory: entry.catalogCategory,
|
|
402
|
+
version:
|
|
403
|
+
entry.installedVersion && PLAIN_VERSION.test(entry.installedVersion)
|
|
404
|
+
? entry.installedVersion
|
|
405
|
+
: undefined,
|
|
406
|
+
source: entry.source,
|
|
407
|
+
}));
|
|
408
|
+
}
|
|
@@ -1,9 +1,30 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ModuleCatalogEntry,
|
|
3
3
|
ModuleStatus,
|
|
4
|
+
ModuleWithAccess,
|
|
4
5
|
PageInfo,
|
|
5
6
|
SiteLayout,
|
|
7
|
+
SiteLayoutTree,
|
|
6
8
|
} from "../../types/page";
|
|
9
|
+
import { resolveModuleLandingSlug } from "../../utils/moduleLanding";
|
|
10
|
+
|
|
11
|
+
/** The Modules page, which lists and manages the installed modules. */
|
|
12
|
+
export const MODULES_PAGE_PATH = "/modules";
|
|
13
|
+
/** The module store, its own view under the Modules page. */
|
|
14
|
+
export const MODULE_STORE_PATH = `${MODULES_PAGE_PATH}/store`;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The grid of both module views, installed and store: three columns on a
|
|
18
|
+
* laptop, so a tile's description, readout and footer line have room. The
|
|
19
|
+
* min() keeps one column from overflowing a phone.
|
|
20
|
+
*/
|
|
21
|
+
export const MODULE_TILE_GRID_CLASS =
|
|
22
|
+
"grid grid-cols-[repeat(auto-fill,minmax(min(340px,100%),1fr))] gap-4";
|
|
23
|
+
|
|
24
|
+
/** Where an installed module's tile is, the one that manages it. */
|
|
25
|
+
export function installedModuleLink(moduleId: string): string {
|
|
26
|
+
return `${MODULES_PAGE_PATH}#module-${moduleId}`;
|
|
27
|
+
}
|
|
7
28
|
|
|
8
29
|
/** Category of the modules that declare none. */
|
|
9
30
|
export const MODULE_CATEGORY_OTHER = "$modules.category_other";
|
|
@@ -12,6 +33,18 @@ export const MODULE_CATEGORY_ALL = "";
|
|
|
12
33
|
|
|
13
34
|
export type ModuleSortMode = "recent" | "name";
|
|
14
35
|
|
|
36
|
+
/** The order the installed modules open in until the user picks another. */
|
|
37
|
+
export const DEFAULT_MODULE_SORT_MODE: ModuleSortMode = "name";
|
|
38
|
+
|
|
39
|
+
const MODULE_SORT_MODES: readonly ModuleSortMode[] = ["name", "recent"];
|
|
40
|
+
|
|
41
|
+
/** A remembered sort mode, or the default when it is missing or unknown. */
|
|
42
|
+
export function parseModuleSortMode(value: unknown): ModuleSortMode {
|
|
43
|
+
return (
|
|
44
|
+
MODULE_SORT_MODES.find((mode) => mode === value) ?? DEFAULT_MODULE_SORT_MODE
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
15
48
|
/** Turns a display string (possibly a `$i18n.key`) into the shown text. */
|
|
16
49
|
export type DisplayResolver = (value: string) => string;
|
|
17
50
|
|
|
@@ -78,23 +111,28 @@ export function summarizeModules(
|
|
|
78
111
|
/**
|
|
79
112
|
* Category filter options: the categories present, alphabetical, with
|
|
80
113
|
* "Other" last. The "All" option is the caller's to add.
|
|
114
|
+
*
|
|
115
|
+
* Categories are told apart by their shown name: two modules that each name
|
|
116
|
+
* "Content" through their own i18n key share one option, whose value is the
|
|
117
|
+
* first key met.
|
|
81
118
|
*/
|
|
82
119
|
export function moduleCategoryOptions(
|
|
83
120
|
entries: readonly FilterableModule[],
|
|
84
121
|
resolve: DisplayResolver,
|
|
85
122
|
): ModuleCategoryOption[] {
|
|
86
|
-
const
|
|
123
|
+
const byLabel = new Map<string, ModuleCategoryOption>();
|
|
87
124
|
for (const entry of entries) {
|
|
88
|
-
const
|
|
89
|
-
|
|
125
|
+
const value = moduleCategory(entry);
|
|
126
|
+
const label = resolve(value);
|
|
127
|
+
const option = byLabel.get(label);
|
|
128
|
+
if (option) option.count += 1;
|
|
129
|
+
else byLabel.set(label, { value, label, count: 1 });
|
|
90
130
|
}
|
|
91
|
-
return [...
|
|
92
|
-
|
|
93
|
-
.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
return a.label.localeCompare(b.label);
|
|
97
|
-
});
|
|
131
|
+
return [...byLabel.values()].sort((a, b) => {
|
|
132
|
+
if (a.value === MODULE_CATEGORY_OTHER) return 1;
|
|
133
|
+
if (b.value === MODULE_CATEGORY_OTHER) return -1;
|
|
134
|
+
return a.label.localeCompare(b.label);
|
|
135
|
+
});
|
|
98
136
|
}
|
|
99
137
|
|
|
100
138
|
function normalizeQuery(query: string): string {
|
|
@@ -106,10 +144,14 @@ export function filterModules<T extends FilterableModule>(
|
|
|
106
144
|
options: { query: string; category: string; resolve: DisplayResolver },
|
|
107
145
|
): T[] {
|
|
108
146
|
const query = normalizeQuery(options.query);
|
|
147
|
+
const category =
|
|
148
|
+
options.category === MODULE_CATEGORY_ALL
|
|
149
|
+
? undefined
|
|
150
|
+
: options.resolve(options.category);
|
|
109
151
|
return entries.filter((entry) => {
|
|
110
152
|
if (
|
|
111
|
-
|
|
112
|
-
moduleCategory(entry) !==
|
|
153
|
+
category !== undefined &&
|
|
154
|
+
options.resolve(moduleCategory(entry)) !== category
|
|
113
155
|
) {
|
|
114
156
|
return false;
|
|
115
157
|
}
|
|
@@ -126,18 +168,36 @@ export function filterModules<T extends FilterableModule>(
|
|
|
126
168
|
});
|
|
127
169
|
}
|
|
128
170
|
|
|
171
|
+
/**
|
|
172
|
+
* Compares shown names as `locale` orders them: accents and case only break
|
|
173
|
+
* ties ("Mailing", "Marketing", "Médiathèque"), and digits read as numbers.
|
|
174
|
+
* An unknown locale falls back to the runtime's own.
|
|
175
|
+
*/
|
|
176
|
+
export function compareDisplayNames(
|
|
177
|
+
locale?: string,
|
|
178
|
+
): (a: string, b: string) => number {
|
|
179
|
+
const options: Intl.CollatorOptions = { numeric: true };
|
|
180
|
+
try {
|
|
181
|
+
return new Intl.Collator(locale, options).compare;
|
|
182
|
+
} catch {
|
|
183
|
+
return new Intl.Collator(undefined, options).compare;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
129
187
|
/**
|
|
130
188
|
* `recent`: most recently opened first, never-opened modules after them by
|
|
131
|
-
* name. `name`: alphabetical.
|
|
189
|
+
* name. `name`: alphabetical by shown name, in `locale`'s order.
|
|
132
190
|
*/
|
|
133
191
|
export function sortModules(
|
|
134
192
|
entries: readonly ModuleCatalogEntry[],
|
|
135
193
|
mode: ModuleSortMode,
|
|
136
194
|
visitedAt: ReadonlyMap<string, number>,
|
|
137
195
|
resolve: DisplayResolver,
|
|
196
|
+
locale?: string,
|
|
138
197
|
): ModuleCatalogEntry[] {
|
|
198
|
+
const compare = compareDisplayNames(locale);
|
|
139
199
|
const byName = (a: ModuleCatalogEntry, b: ModuleCatalogEntry) =>
|
|
140
|
-
resolve(a.title)
|
|
200
|
+
compare(resolve(a.title), resolve(b.title));
|
|
141
201
|
return [...entries].sort((a, b) => {
|
|
142
202
|
if (mode === "recent") {
|
|
143
203
|
const delta = (visitedAt.get(b.id) ?? -1) - (visitedAt.get(a.id) ?? -1);
|
|
@@ -197,3 +257,51 @@ export function findModulePageMatch(
|
|
|
197
257
|
}
|
|
198
258
|
return null;
|
|
199
259
|
}
|
|
260
|
+
|
|
261
|
+
/** A visited module as the command palette's recent modules list it. */
|
|
262
|
+
export interface RecentModule {
|
|
263
|
+
moduleId: string;
|
|
264
|
+
/** Display name, possibly a `$i18n.key`. */
|
|
265
|
+
title: string;
|
|
266
|
+
icon: string;
|
|
267
|
+
/** The module's landing page, never the page it was left on. */
|
|
268
|
+
to: string;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/** A visit of the module history, oldest first as it keeps them. */
|
|
272
|
+
export interface ModuleVisit {
|
|
273
|
+
moduleId: string;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* The visited modules the caller may still open, most recent first, each
|
|
278
|
+
* leading to its landing page: every way into a module lands there. A module
|
|
279
|
+
* with no page the caller may open is left out.
|
|
280
|
+
*/
|
|
281
|
+
export function recentModules(
|
|
282
|
+
visits: readonly ModuleVisit[],
|
|
283
|
+
modules: Readonly<Record<string, ModuleWithAccess>> | undefined,
|
|
284
|
+
tree: SiteLayoutTree | undefined,
|
|
285
|
+
): RecentModule[] {
|
|
286
|
+
return visits
|
|
287
|
+
.slice()
|
|
288
|
+
.reverse()
|
|
289
|
+
.flatMap((visit) => {
|
|
290
|
+
const module = modules?.[visit.moduleId];
|
|
291
|
+
if (!module?.hasAccess) return [];
|
|
292
|
+
const to = resolveModuleLandingSlug(
|
|
293
|
+
tree,
|
|
294
|
+
visit.moduleId,
|
|
295
|
+
module.landingPage,
|
|
296
|
+
);
|
|
297
|
+
if (!to) return [];
|
|
298
|
+
return [
|
|
299
|
+
{
|
|
300
|
+
moduleId: visit.moduleId,
|
|
301
|
+
title: module.title,
|
|
302
|
+
icon: module.icon,
|
|
303
|
+
to,
|
|
304
|
+
},
|
|
305
|
+
];
|
|
306
|
+
});
|
|
307
|
+
}
|
|
@@ -27,11 +27,37 @@ export const resolveLayoutBannerPresentation = (
|
|
|
27
27
|
return { ...presentation, icon: banner.icon ?? presentation.icon };
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Whether a path is in the module area: the modules page, the module store
|
|
32
|
+
* and every module's own pages, all under `MODULE_URL_PREFIX`.
|
|
33
|
+
*/
|
|
34
|
+
export const isModuleAreaPath = (path: string): boolean =>
|
|
35
|
+
path === MODULE_URL_PREFIX || path.startsWith(`${MODULE_URL_PREFIX}/`);
|
|
36
|
+
|
|
37
|
+
const SCOPE_MATCHERS: Record<
|
|
38
|
+
LayoutBannerScope,
|
|
39
|
+
(isModuleArea: boolean) => boolean
|
|
40
|
+
> = {
|
|
41
|
+
app: (isModuleArea) => !isModuleArea,
|
|
42
|
+
modules: (isModuleArea) => isModuleArea,
|
|
43
|
+
everywhere: () => true,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/** Whether a banner's scope, as the backend serves it, covers a page. */
|
|
47
|
+
export const isLayoutBannerInScope = (
|
|
48
|
+
banner: LayoutBanner,
|
|
49
|
+
path: string,
|
|
50
|
+
): boolean => SCOPE_MATCHERS[banner.scope](isModuleAreaPath(path));
|
|
51
|
+
|
|
30
52
|
/**
|
|
31
53
|
* The global banners rendered under the dashboard header, as resolved by the
|
|
32
54
|
* server for this request (see `RegisterLayoutBanner` in
|
|
33
|
-
* `@antelopejs/interface-dms/layout-banners`),
|
|
34
|
-
* dismissed.
|
|
55
|
+
* `@antelopejs/interface-dms/layout-banners`), keeping the ones whose scope
|
|
56
|
+
* covers the current route, minus the ones the user dismissed.
|
|
57
|
+
*
|
|
58
|
+
* The site layout is shared by every page, so the scope is applied here
|
|
59
|
+
* against the route: on the server-rendered page and again on each
|
|
60
|
+
* client-side navigation, without re-fetching the layout.
|
|
35
61
|
*
|
|
36
62
|
* Dismissals are kept in a session cookie rather than in local storage so the
|
|
37
63
|
* server-rendered page already leaves a dismissed banner out, instead of
|
|
@@ -39,6 +65,7 @@ export const resolveLayoutBannerPresentation = (
|
|
|
39
65
|
*/
|
|
40
66
|
export const useLayoutBanners = () => {
|
|
41
67
|
const { siteLayout } = useSiteLayout();
|
|
68
|
+
const route = useDmsRoute();
|
|
42
69
|
const dismissed = useDmsCookie<string[]>(DISMISSED_BANNERS_COOKIE, {
|
|
43
70
|
default: () => [],
|
|
44
71
|
sameSite: "lax",
|
|
@@ -46,7 +73,9 @@ export const useLayoutBanners = () => {
|
|
|
46
73
|
|
|
47
74
|
const banners = computed<LayoutBanner[]>(() =>
|
|
48
75
|
(siteLayout.value?.banners ?? []).filter(
|
|
49
|
-
(banner) =>
|
|
76
|
+
(banner) =>
|
|
77
|
+
isLayoutBannerInScope(banner, route.path) &&
|
|
78
|
+
(!banner.dismissible || !dismissed.value.includes(banner.key)),
|
|
50
79
|
),
|
|
51
80
|
);
|
|
52
81
|
|