@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
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
import type { FormField } from "../../composables/form/types/field";
|
|
9
9
|
import {
|
|
10
10
|
cloneFormValue,
|
|
11
|
+
fieldValuesOfSubmitDefaults,
|
|
11
12
|
type FormServerFieldError,
|
|
12
13
|
formShowsActions,
|
|
13
14
|
isAcceptanceField,
|
|
@@ -18,6 +19,7 @@ import {
|
|
|
18
19
|
type FormValidator,
|
|
19
20
|
} from "../../composables/form/types/validation";
|
|
20
21
|
import { FORM_FIELD_LOADING_KEY } from "../../composables/form/types/field-loading";
|
|
22
|
+
import { FORM_FIELD_SAVED_KEY } from "../../composables/form/types/field-saved";
|
|
21
23
|
import {
|
|
22
24
|
FORM_HANDLE_KEY,
|
|
23
25
|
linkedFieldId,
|
|
@@ -42,6 +44,7 @@ import {
|
|
|
42
44
|
fieldErrorPattern,
|
|
43
45
|
} from "../../build/composables/form/formEntryContext";
|
|
44
46
|
import {
|
|
47
|
+
CONTAINER_LAYOUT_CLASSES,
|
|
45
48
|
FORM_LAYOUT_CLASSES,
|
|
46
49
|
FORM_SURFACE_CLASSES,
|
|
47
50
|
type FormSurface,
|
|
@@ -58,7 +61,15 @@ import {
|
|
|
58
61
|
sectionState,
|
|
59
62
|
} from "../../build/composables/form/formSections";
|
|
60
63
|
import { FORM_CONTROL_ERRORS_KEY } from "../../build/composables/form/formControlErrors";
|
|
64
|
+
import {
|
|
65
|
+
changedServerErrorFields,
|
|
66
|
+
keptServerErrors,
|
|
67
|
+
serverErrorValue,
|
|
68
|
+
type KeptServerError,
|
|
69
|
+
type PlacedServerError,
|
|
70
|
+
} from "../../build/composables/form/serverFieldErrors";
|
|
61
71
|
import { useInstantForm } from "../../build/composables/form/useInstantForm";
|
|
72
|
+
import { fieldSavedMarker } from "../../build/composables/form/fieldSaved";
|
|
62
73
|
import { useInstantSaveHeader } from "#dms-layout/app/composables/layout/useInstantSaveHeader";
|
|
63
74
|
import DmsFormEntries from "../../build/components/form/FormEntries.vue";
|
|
64
75
|
import DmsFormErrorSummary from "../../build/components/form/FormErrorSummary.vue";
|
|
@@ -70,6 +81,8 @@ import {
|
|
|
70
81
|
} from "../../build/composables/form/formRecordLoad";
|
|
71
82
|
import DmsFormRequiredLegend from "./FormRequiredLegend.vue";
|
|
72
83
|
import DmsFormSections from "../../build/components/form/FormSections.vue";
|
|
84
|
+
import { scrollWithin } from "../../build/utils/scrollWithin";
|
|
85
|
+
import { isHiddenOnCreate } from "../../build/composables/form/createFormFields";
|
|
73
86
|
|
|
74
87
|
const REALTIME_PRESENCE_FLAG = "_presence=1";
|
|
75
88
|
const REALTIME_ACQUIRE_PATH = "/api/realtime/acquire";
|
|
@@ -97,10 +110,11 @@ const FormWrapper =
|
|
|
97
110
|
|
|
98
111
|
const { processI18n, processApiMessage } = useTranslation();
|
|
99
112
|
|
|
100
|
-
// Server errors stay on their field until its value changes
|
|
101
|
-
// re-validates
|
|
102
|
-
// them
|
|
103
|
-
|
|
113
|
+
// Server errors stay on their field until its value changes or the form is
|
|
114
|
+
// saved, whatever re-validates the field in between: UForm's `validate`
|
|
115
|
+
// answers them with its schema's (see `keptServerErrors`). Each one shown,
|
|
116
|
+
// with the value it was raised against, by field id.
|
|
117
|
+
const serverErrors = new Map<string, KeptServerError>();
|
|
104
118
|
|
|
105
119
|
/** The control of a field, by its id, inside this form only. */
|
|
106
120
|
function fieldControl(name: string | undefined): HTMLElement | null {
|
|
@@ -171,13 +185,14 @@ async function focusField(name: string | undefined): Promise<void> {
|
|
|
171
185
|
target.focus();
|
|
172
186
|
return;
|
|
173
187
|
}
|
|
174
|
-
row
|
|
188
|
+
if (row) scrollWithin(row, { block: "center" });
|
|
175
189
|
}
|
|
176
190
|
|
|
177
191
|
/** Brings a field into view and focuses it: a link's anchor, a field's request. */
|
|
178
192
|
async function revealField(fieldId: string): Promise<void> {
|
|
179
193
|
await formSettled();
|
|
180
|
-
fieldRow(fieldId)
|
|
194
|
+
const row = fieldRow(fieldId);
|
|
195
|
+
if (row) scrollWithin(row, { block: "center" });
|
|
181
196
|
await focusField(fieldId);
|
|
182
197
|
}
|
|
183
198
|
|
|
@@ -193,14 +208,19 @@ function showFieldErrors(errors: FormServerFieldError[]): boolean {
|
|
|
193
208
|
// instant form) replaces its own only.
|
|
194
209
|
if (!isInstant) {
|
|
195
210
|
target.setErrors([]);
|
|
196
|
-
|
|
211
|
+
serverErrors.clear();
|
|
197
212
|
}
|
|
198
213
|
for (const error of errors) placeServerError(target, error);
|
|
199
214
|
const shown = errors.filter(
|
|
200
215
|
(error) => target.getErrors(fieldErrorPattern(error.name)).length,
|
|
201
216
|
);
|
|
202
217
|
for (const error of shown) {
|
|
203
|
-
|
|
218
|
+
serverErrors.set(error.name, {
|
|
219
|
+
value: serverErrorValue(state.value[error.name]),
|
|
220
|
+
errors: target
|
|
221
|
+
.getErrors(fieldErrorPattern(error.name))
|
|
222
|
+
.map(({ name, message }: PlacedServerError) => ({ name, message })),
|
|
223
|
+
});
|
|
204
224
|
}
|
|
205
225
|
showsErrorSummary.value = shown.length > 0;
|
|
206
226
|
void focusField(target.errors[0]?.name);
|
|
@@ -229,7 +249,9 @@ function onValidationError(event: { errors: Array<{ name?: string }> }): void {
|
|
|
229
249
|
}
|
|
230
250
|
|
|
231
251
|
// Once a submit is refused, the form lists what to fix above its fields
|
|
232
|
-
// until it is saved.
|
|
252
|
+
// until it is saved. The last fix empties the list, not the place it holds:
|
|
253
|
+
// the fields, and the submit button with them, would move up under the
|
|
254
|
+
// pointer on its way to it, and the click would land beside it.
|
|
233
255
|
const showsErrorSummary = ref(false);
|
|
234
256
|
|
|
235
257
|
const {
|
|
@@ -251,20 +273,33 @@ const {
|
|
|
251
273
|
isFieldGroup,
|
|
252
274
|
submitSucceeded,
|
|
253
275
|
resolvedFetchUrl,
|
|
276
|
+
createsRecord,
|
|
277
|
+
effectiveSubmitDefaults,
|
|
254
278
|
} = useForm(props, { showFieldErrors, onSaved: markFormClean });
|
|
255
279
|
|
|
256
280
|
watch(
|
|
257
281
|
state,
|
|
258
282
|
(current) => {
|
|
259
|
-
for (const
|
|
260
|
-
|
|
261
|
-
serverErrorValues.delete(name);
|
|
283
|
+
for (const name of changedServerErrorFields(serverErrors, current)) {
|
|
284
|
+
serverErrors.delete(name);
|
|
262
285
|
form.value?.clear(fieldErrorPattern(name));
|
|
263
286
|
}
|
|
264
287
|
},
|
|
265
288
|
{ deep: true },
|
|
266
289
|
);
|
|
267
290
|
|
|
291
|
+
// UForm is busy while it validates a submit: the kept errors stay out of it.
|
|
292
|
+
const validateServerErrors = (current: Record<string, unknown>) =>
|
|
293
|
+
keptServerErrors(serverErrors, current, !!form.value?.loading);
|
|
294
|
+
|
|
295
|
+
/** A saved form: what the server refused before no longer stands. */
|
|
296
|
+
function clearServerErrors(): void {
|
|
297
|
+
for (const name of serverErrors.keys()) {
|
|
298
|
+
form.value?.clear(fieldErrorPattern(name));
|
|
299
|
+
}
|
|
300
|
+
serverErrors.clear();
|
|
301
|
+
}
|
|
302
|
+
|
|
268
303
|
const allFieldIds = computed(() => toValue(allFields).map((field) => field.id));
|
|
269
304
|
|
|
270
305
|
const showActions = computed(() => formShowsActions(props, toValue(allFields)));
|
|
@@ -291,6 +326,7 @@ const localizedSchema = computed(() => {
|
|
|
291
326
|
id: field.id,
|
|
292
327
|
type: field.type,
|
|
293
328
|
localized: field.localized,
|
|
329
|
+
fallbackLocale: field.fallbackLocale,
|
|
294
330
|
required: isFieldRequired(field),
|
|
295
331
|
acceptance: isAcceptanceField(field),
|
|
296
332
|
}));
|
|
@@ -335,7 +371,7 @@ watch(
|
|
|
335
371
|
const previous = fieldValueSnapshots.get(field.id);
|
|
336
372
|
fieldValueSnapshots.set(field.id, snapshot);
|
|
337
373
|
if (previous === undefined || previous === snapshot) continue;
|
|
338
|
-
if (!form.value ||
|
|
374
|
+
if (!form.value || serverErrors.has(field.id)) continue;
|
|
339
375
|
const pattern = fieldErrorPattern(field.id);
|
|
340
376
|
if (!form.value.getErrors(pattern).length) continue;
|
|
341
377
|
void form.value.validate({ name: errorNames(field), silent: true });
|
|
@@ -346,10 +382,12 @@ watch(
|
|
|
346
382
|
|
|
347
383
|
const { t, locale, locales } = useI18n();
|
|
348
384
|
|
|
385
|
+
// A new row is created, not "changes" saved.
|
|
386
|
+
const DEFAULT_SUBMIT_LABEL = createsRecord
|
|
387
|
+
? "dms.button.create"
|
|
388
|
+
: "dms.button.save_changes";
|
|
349
389
|
const submitButtonLabel = computed(() =>
|
|
350
|
-
props.submitLabel
|
|
351
|
-
? processI18n(props.submitLabel)
|
|
352
|
-
: t("dms.button.save_changes"),
|
|
390
|
+
props.submitLabel ? processI18n(props.submitLabel) : t(DEFAULT_SUBMIT_LABEL),
|
|
353
391
|
);
|
|
354
392
|
|
|
355
393
|
watch(disabledFields, (newDisabled, oldDisabled) => {
|
|
@@ -413,6 +451,7 @@ onMounted(() => {
|
|
|
413
451
|
function markFormClean(): void {
|
|
414
452
|
isTouched = false;
|
|
415
453
|
showsErrorSummary.value = false;
|
|
454
|
+
clearServerErrors();
|
|
416
455
|
formDirty.markClean();
|
|
417
456
|
instantSave?.start();
|
|
418
457
|
}
|
|
@@ -441,11 +480,20 @@ const isDirty = computed(
|
|
|
441
480
|
|
|
442
481
|
useUnsavedChanges({ dirty: isDirty, containerId, element: form });
|
|
443
482
|
|
|
444
|
-
// A form offers Cancel
|
|
445
|
-
//
|
|
446
|
-
// saves from its footer band, never from the
|
|
483
|
+
// A form offers Cancel when it has somewhere to go back to: its drawer or
|
|
484
|
+
// modal, `backTo` on a page, or the page of the app the user came from. An
|
|
485
|
+
// action form (send, invite, run) saves from its footer band, never from the
|
|
486
|
+
// floating bar.
|
|
447
487
|
const isActionForm = props.kind === "action";
|
|
448
|
-
|
|
488
|
+
// Read once mounted: the server renders no history.
|
|
489
|
+
const cameFromAppPage = ref(false);
|
|
490
|
+
onMounted(() => {
|
|
491
|
+
cameFromAppPage.value = !!previousAppPage();
|
|
492
|
+
});
|
|
493
|
+
const canCancel = computed(
|
|
494
|
+
() =>
|
|
495
|
+
inFormContainer || !!container || !!props.backTo || cameFromAppPage.value,
|
|
496
|
+
);
|
|
449
497
|
const usesSaveBar = saveMode === "bar" && !inFormContainer && !isActionForm;
|
|
450
498
|
|
|
451
499
|
/** Validates one field alone: whether it holds no error. */
|
|
@@ -479,19 +527,30 @@ const hasChangeableFields = computed(() =>
|
|
|
479
527
|
const router = useDmsRouter();
|
|
480
528
|
const route = useDmsRoute();
|
|
481
529
|
/**
|
|
482
|
-
*
|
|
483
|
-
*
|
|
484
|
-
*
|
|
530
|
+
* The page of the app this one was reached from, which the router records
|
|
531
|
+
* in the history entry: none for a page opened from a link outside the app,
|
|
532
|
+
* a bookmark or a new tab, where going back would leave the app.
|
|
533
|
+
*/
|
|
534
|
+
function previousAppPage(): string | undefined {
|
|
535
|
+
const back = (window.history.state as { back?: unknown } | null)?.back;
|
|
536
|
+
return typeof back === "string" ? back : undefined;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* Cancel: drops what was changed, then closes the drawer or modal, or leaves
|
|
541
|
+
* a page form for the page of the app the user came from (its list, when
|
|
542
|
+
* opened from one), or its `backTo` when the form was opened directly.
|
|
543
|
+
* Discarding first means leaving never asks about changes the user just chose
|
|
544
|
+
* to drop.
|
|
485
545
|
*/
|
|
486
546
|
function cancelForm(): void {
|
|
547
|
+
if (isDirty.value) discardChanges();
|
|
487
548
|
if (container) {
|
|
488
549
|
void container.close();
|
|
489
550
|
return;
|
|
490
551
|
}
|
|
491
|
-
|
|
492
|
-
.
|
|
493
|
-
if (navigation?.canGoBack ?? window.history.length > 1) {
|
|
494
|
-
window.history.back();
|
|
552
|
+
if (previousAppPage()) {
|
|
553
|
+
router.back();
|
|
495
554
|
return;
|
|
496
555
|
}
|
|
497
556
|
if (props.backTo) void router.push(pageLink(props.backTo));
|
|
@@ -537,6 +596,15 @@ provide(FORM_HANDLE_KEY, {
|
|
|
537
596
|
revealField,
|
|
538
597
|
});
|
|
539
598
|
provide(FORM_FIELD_LOADING_KEY, setFieldLoading);
|
|
599
|
+
provide(
|
|
600
|
+
FORM_FIELD_SAVED_KEY,
|
|
601
|
+
fieldSavedMarker({
|
|
602
|
+
hasField: (id) => toValue(allFields).some((field) => field.id === id),
|
|
603
|
+
initialValues,
|
|
604
|
+
dirty: formDirty,
|
|
605
|
+
instantSave,
|
|
606
|
+
}),
|
|
607
|
+
);
|
|
540
608
|
provide(FORM_CONTENT_LANGUAGE_KEY, "*");
|
|
541
609
|
|
|
542
610
|
allFields.value.forEach((field) => {
|
|
@@ -547,6 +615,15 @@ allFields.value.forEach((field) => {
|
|
|
547
615
|
) as FormFieldValue;
|
|
548
616
|
});
|
|
549
617
|
|
|
618
|
+
// A field the form submits a default under (the parent a table is filtered
|
|
619
|
+
// on) holds it from the start: it shows, and a mandatory one is filled.
|
|
620
|
+
for (const [id, value] of Object.entries(
|
|
621
|
+
fieldValuesOfSubmitDefaults(allFields.value, effectiveSubmitDefaults.value),
|
|
622
|
+
)) {
|
|
623
|
+
state.value[id] = cloneFormValue(value);
|
|
624
|
+
initialValues.value[id] = cloneFormValue(value) as FormFieldValue;
|
|
625
|
+
}
|
|
626
|
+
|
|
550
627
|
let recordLoad: FormRecordLoad | undefined;
|
|
551
628
|
if (props.fetchUrl) {
|
|
552
629
|
// Keyed on the record too: the load outlives a drawer or modal, and the
|
|
@@ -648,7 +725,10 @@ function layoutClasses(inSectionCard: boolean) {
|
|
|
648
725
|
if ((inSectionCard || inSection) && isHorizontal) {
|
|
649
726
|
return SECTION_LAYOUT_CLASSES;
|
|
650
727
|
}
|
|
651
|
-
|
|
728
|
+
const orientation = isHorizontal ? "horizontal" : "vertical";
|
|
729
|
+
return inFormContainer
|
|
730
|
+
? CONTAINER_LAYOUT_CLASSES[orientation]
|
|
731
|
+
: FORM_LAYOUT_CLASSES[orientation];
|
|
652
732
|
}
|
|
653
733
|
|
|
654
734
|
function isFieldDisabled(field: FormField): boolean {
|
|
@@ -657,7 +737,8 @@ function isFieldDisabled(field: FormField): boolean {
|
|
|
657
737
|
}
|
|
658
738
|
|
|
659
739
|
function isFieldHidden(field: FormField): boolean {
|
|
660
|
-
|
|
740
|
+
if (hiddenFields.value?.has(field.id)) return true;
|
|
741
|
+
return createsRecord && isHiddenOnCreate(field, state.value[field.id]);
|
|
661
742
|
}
|
|
662
743
|
|
|
663
744
|
function isFieldRequired(field: FormField): boolean {
|
|
@@ -684,7 +765,10 @@ provide(FORM_ENTRY_CONTEXT_KEY, {
|
|
|
684
765
|
isFieldHidden,
|
|
685
766
|
isFieldDisabled,
|
|
686
767
|
isFieldRequired,
|
|
687
|
-
|
|
768
|
+
isReadOnly: computed(() => !hasChangeableFields.value),
|
|
769
|
+
// A new row has no earlier value to compare with: "Changed · was empty"
|
|
770
|
+
// on every field it fills would say nothing.
|
|
771
|
+
showsChanges: !isInstant && !isActionForm && !createsRecord,
|
|
688
772
|
isFieldChanged: (fieldId) => changedFieldIds.value.has(fieldId),
|
|
689
773
|
baselineValue: (fieldId) => formDirty.baseline.value[fieldId],
|
|
690
774
|
fieldSaveState: (fieldId) => instantSave?.states[fieldId] ?? "idle",
|
|
@@ -739,10 +823,6 @@ const sectionOfField = computed(() => {
|
|
|
739
823
|
return owners;
|
|
740
824
|
});
|
|
741
825
|
|
|
742
|
-
watch(invalidFields, (invalid) => {
|
|
743
|
-
if (invalid.size === 0) showsErrorSummary.value = false;
|
|
744
|
-
});
|
|
745
|
-
|
|
746
826
|
// One entry per row to fix: the unlabelled fields of a group share its
|
|
747
827
|
// label, and its first invalid field stands for them.
|
|
748
828
|
const errorSummaryItems = computed(() => {
|
|
@@ -916,6 +996,7 @@ onUnmounted(async () => {
|
|
|
916
996
|
ref="form"
|
|
917
997
|
:state
|
|
918
998
|
:schema="localizedSchema"
|
|
999
|
+
:validate="validateServerErrors"
|
|
919
1000
|
:disabled="allFields.every((field) => field.disabled)"
|
|
920
1001
|
@submit="onSubmit"
|
|
921
1002
|
@error="onValidationError"
|
|
@@ -963,7 +1044,7 @@ onUnmounted(async () => {
|
|
|
963
1044
|
/>
|
|
964
1045
|
|
|
965
1046
|
<DmsFormErrorSummary
|
|
966
|
-
v-if="
|
|
1047
|
+
v-if="showsErrorSummary"
|
|
967
1048
|
:items="errorSummaryItems"
|
|
968
1049
|
:class="hasSections ? 'mb-5' : 'mt-4'"
|
|
969
1050
|
@select="focusField"
|
|
@@ -1014,7 +1095,9 @@ onUnmounted(async () => {
|
|
|
1014
1095
|
:saving="loading || isAnyFieldLoading"
|
|
1015
1096
|
:changes="changedFieldLabels"
|
|
1016
1097
|
:form="formElementId"
|
|
1017
|
-
:save-label="
|
|
1098
|
+
:save-label="
|
|
1099
|
+
usesSaveBar && !createsRecord ? props.submitLabel : submitButtonLabel
|
|
1100
|
+
"
|
|
1018
1101
|
:cancellable="canCancel"
|
|
1019
1102
|
:resettable="hasChangeableFields"
|
|
1020
1103
|
:class="usesSaveBar ? 'mx-3' : surfaceClasses.foot"
|
|
@@ -6,7 +6,10 @@ import {
|
|
|
6
6
|
findCascaderNode,
|
|
7
7
|
formatCascaderPath,
|
|
8
8
|
isCascaderNodeSelectable,
|
|
9
|
+
readCascaderAncestry,
|
|
9
10
|
resolveCascaderKeyMapping,
|
|
11
|
+
buildCascaderPathLabels,
|
|
12
|
+
CASCADER_PATH_SEPARATOR,
|
|
10
13
|
searchCascaderTree,
|
|
11
14
|
type CascaderKeyMapping,
|
|
12
15
|
type CascaderNode,
|
|
@@ -18,6 +21,7 @@ import {
|
|
|
18
21
|
FIELD_TRIGGER_INVALID_CLASS,
|
|
19
22
|
FIELD_TRIGGER_UI,
|
|
20
23
|
} from "../../../build/utils/fieldTrigger";
|
|
24
|
+
import { useRelationRows } from "../../../build/composables/data-types/relationRows";
|
|
21
25
|
|
|
22
26
|
interface CascaderProps {
|
|
23
27
|
searchUrl: string;
|
|
@@ -88,6 +92,36 @@ const { data, status, execute } = await useDmsAsyncData(
|
|
|
88
92
|
);
|
|
89
93
|
|
|
90
94
|
const keyMapping = computed(() => resolveCascaderKeyMapping(props.keyMapping));
|
|
95
|
+
const selectedValues = computed<string[]>(() => {
|
|
96
|
+
if (Array.isArray(props.modelValue)) {
|
|
97
|
+
return props.modelValue.map(String);
|
|
98
|
+
}
|
|
99
|
+
return props.modelValue ? [String(props.modelValue)] : [];
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// The picked rows and their ancestors, read by `?ids=` level by level: the
|
|
103
|
+
// field names its value before the menu is opened, whatever the tree's size.
|
|
104
|
+
const { readRelationRows } = useRelationRows();
|
|
105
|
+
const { data: ancestry } = await useDmsAsyncData(
|
|
106
|
+
() => `cascader-value-${instanceId}-${selectedValues.value.join(",")}`,
|
|
107
|
+
() =>
|
|
108
|
+
selectedValues.value.length > 0
|
|
109
|
+
? readCascaderAncestry(
|
|
110
|
+
(ids) =>
|
|
111
|
+
readRelationRows(
|
|
112
|
+
{
|
|
113
|
+
searchUrl: props.searchUrl,
|
|
114
|
+
keyMapping: { value: keyMapping.value.value },
|
|
115
|
+
},
|
|
116
|
+
ids,
|
|
117
|
+
),
|
|
118
|
+
keyMapping.value,
|
|
119
|
+
selectedValues.value,
|
|
120
|
+
)
|
|
121
|
+
: Promise.resolve(undefined),
|
|
122
|
+
// The field's label, not the page's data.
|
|
123
|
+
{ lazy: true, refreshOnPageRefresh: false },
|
|
124
|
+
);
|
|
91
125
|
const rows = computed(() => data.value?.results ?? []);
|
|
92
126
|
const isPartial = computed(
|
|
93
127
|
() => (data.value?.total ?? 0) > rows.value.length && rows.value.length > 0,
|
|
@@ -100,12 +134,6 @@ const selectionRules = computed(() => ({
|
|
|
100
134
|
maxDepth: props.maxDepth,
|
|
101
135
|
}));
|
|
102
136
|
|
|
103
|
-
const selectedValues = computed<string[]>(() => {
|
|
104
|
-
if (Array.isArray(props.modelValue)) {
|
|
105
|
-
return props.modelValue.map(String);
|
|
106
|
-
}
|
|
107
|
-
return props.modelValue ? [String(props.modelValue)] : [];
|
|
108
|
-
});
|
|
109
137
|
const selectedSet = computed(() => new Set(selectedValues.value));
|
|
110
138
|
|
|
111
139
|
const open = ref(false);
|
|
@@ -134,14 +162,11 @@ const columns = computed<CascaderNode[][]>(() => {
|
|
|
134
162
|
return result;
|
|
135
163
|
});
|
|
136
164
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const label = (source as Record<string, unknown>)[keyMapping.value.label];
|
|
143
|
-
return label === undefined || label === null ? undefined : String(label);
|
|
144
|
-
}
|
|
165
|
+
/** The picked id no row answers (deleted, out of reach), if it is one. */
|
|
166
|
+
const notFoundValue = computed(() => {
|
|
167
|
+
const value = selectedValues.value[0];
|
|
168
|
+
return value && ancestry.value?.notFound.includes(value) ? value : undefined;
|
|
169
|
+
});
|
|
145
170
|
|
|
146
171
|
const triggerLabel = computed(() => {
|
|
147
172
|
if (selectedValues.value.length === 0) return "";
|
|
@@ -151,9 +176,15 @@ const triggerLabel = computed(() => {
|
|
|
151
176
|
});
|
|
152
177
|
}
|
|
153
178
|
const value = selectedValues.value[0]!;
|
|
179
|
+
if (notFoundValue.value) return t("dms.form.relation.not_found");
|
|
154
180
|
const node = findCascaderNode(roots.value, value);
|
|
155
181
|
if (node) return formatCascaderPath(node);
|
|
156
|
-
|
|
182
|
+
const path = buildCascaderPathLabels(
|
|
183
|
+
ancestry.value?.rows ?? [],
|
|
184
|
+
keyMapping.value,
|
|
185
|
+
value,
|
|
186
|
+
);
|
|
187
|
+
return path.length > 0 ? path.join(CASCADER_PATH_SEPARATOR) : value;
|
|
157
188
|
});
|
|
158
189
|
|
|
159
190
|
const placeholderLabel = computed(() =>
|
|
@@ -339,12 +370,6 @@ watch(searchTerm, () => {
|
|
|
339
370
|
};
|
|
340
371
|
});
|
|
341
372
|
|
|
342
|
-
onMounted(() => {
|
|
343
|
-
if (selectedValues.value.length > 0 || props.initialValue) {
|
|
344
|
-
void execute();
|
|
345
|
-
}
|
|
346
|
-
});
|
|
347
|
-
|
|
348
373
|
function nodeClasses(node: CascaderNode, isHighlighted: boolean): string[] {
|
|
349
374
|
return [
|
|
350
375
|
"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm",
|
|
@@ -383,7 +408,13 @@ function nodeClasses(node: CascaderNode, isHighlighted: boolean): string[] {
|
|
|
383
408
|
:aria-label="placeholderLabel"
|
|
384
409
|
v-bind="ariaAttrs"
|
|
385
410
|
>
|
|
386
|
-
<span
|
|
411
|
+
<span
|
|
412
|
+
v-if="triggerLabel"
|
|
413
|
+
:class="['truncate', notFoundValue && 'text-muted']"
|
|
414
|
+
:title="notFoundValue ?? triggerLabel"
|
|
415
|
+
>
|
|
416
|
+
{{ triggerLabel }}
|
|
417
|
+
</span>
|
|
387
418
|
<span v-else class="text-dimmed truncate">{{ placeholderLabel }}</span>
|
|
388
419
|
</UButton>
|
|
389
420
|
|
|
@@ -176,7 +176,21 @@ function trackRangePick(value: unknown): void {
|
|
|
176
176
|
if (!isHalfPicked) report(undefined);
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
+
const isPickerOpen = ref(false);
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Whether a pick completes the field: a day, or a range's end. A multiple
|
|
183
|
+
* picker stays open for the next day, a range for its end.
|
|
184
|
+
*/
|
|
185
|
+
function isPickComplete(value: unknown): boolean {
|
|
186
|
+
if (!value || props.multiple) return false;
|
|
187
|
+
if (!props.range) return true;
|
|
188
|
+
const ends = value as Partial<StrictDateRange>;
|
|
189
|
+
return !!ends.start && !!ends.end;
|
|
190
|
+
}
|
|
191
|
+
|
|
179
192
|
function onPickerToggle(open: boolean): void {
|
|
193
|
+
isPickerOpen.value = open;
|
|
180
194
|
if (open) return;
|
|
181
195
|
if (props.range && isHalfPicked) report(RANGE_INCOMPLETE);
|
|
182
196
|
emitFormBlur();
|
|
@@ -214,6 +228,10 @@ const wrappedEmits = (event: EmitEvent, value: EmitValue) => {
|
|
|
214
228
|
if (event === "update:modelValue" && props.range) trackRangePick(value);
|
|
215
229
|
// After the update: the field re-validates its new value.
|
|
216
230
|
if (event === "update:modelValue") emitFormChange();
|
|
231
|
+
// The day picked, the calendar closes, as it does when left.
|
|
232
|
+
if (event === "update:modelValue" && isPickComplete(value)) {
|
|
233
|
+
onPickerToggle(false);
|
|
234
|
+
}
|
|
217
235
|
};
|
|
218
236
|
|
|
219
237
|
function forwardEmit(event: EmitEvent, value: EmitValue): void {
|
|
@@ -286,10 +304,11 @@ const label = computed(() => {
|
|
|
286
304
|
</script>
|
|
287
305
|
|
|
288
306
|
<template>
|
|
289
|
-
<UPopover @update:open="onPickerToggle">
|
|
307
|
+
<UPopover :open="isPickerOpen" @update:open="onPickerToggle">
|
|
290
308
|
<UButton
|
|
291
309
|
:id="props.id"
|
|
292
310
|
:label="label ?? t('dms.form.select_date')"
|
|
311
|
+
:title="label"
|
|
293
312
|
:ui="{
|
|
294
313
|
...FIELD_TRIGGER_UI,
|
|
295
314
|
label: label ? 'truncate text-highlighted' : 'truncate text-dimmed',
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { isVNode } from "vue";
|
|
3
|
+
import { NUMERIC_TYPE_IDS } from "../../../build/composables/data-types/useColumnValueRenderer";
|
|
3
4
|
|
|
4
5
|
interface DisplayProps {
|
|
5
6
|
modelValue?: unknown;
|
|
6
7
|
type?: string;
|
|
7
8
|
loading?: boolean;
|
|
9
|
+
/** The field's label, which names the value where it is not text (an image). */
|
|
10
|
+
label?: string;
|
|
11
|
+
/** The record the value belongs to, read as a grid cell reads its row. */
|
|
12
|
+
row?: Record<string, unknown>;
|
|
8
13
|
}
|
|
9
14
|
|
|
10
15
|
const props = defineProps<DisplayProps>();
|
|
@@ -33,10 +38,16 @@ const formattedValue = computed(() => {
|
|
|
33
38
|
if (isEmptyValue(props.modelValue)) return EMPTY_FALLBACK;
|
|
34
39
|
const formatter = dataType.value?.formatter?.default;
|
|
35
40
|
if (!formatter) return String(props.modelValue);
|
|
36
|
-
|
|
41
|
+
const formatterOptions = props.label
|
|
42
|
+
? { ...options, fieldLabel: props.label }
|
|
43
|
+
: options;
|
|
44
|
+
return formatter(props.modelValue, locale.value, formatterOptions, props.row);
|
|
37
45
|
});
|
|
38
46
|
|
|
39
47
|
const isVNodeValue = computed(() => isVNode(formattedValue.value));
|
|
48
|
+
// Amounts read in tabular figures, so a read-only list's amounts and the
|
|
49
|
+
// totals under it line up in one font.
|
|
50
|
+
const isNumeric = computed(() => NUMERIC_TYPE_IDS.has(props.type ?? ""));
|
|
40
51
|
</script>
|
|
41
52
|
|
|
42
53
|
<template>
|
|
@@ -56,6 +67,7 @@ const isVNodeValue = computed(() => isVNode(formattedValue.value));
|
|
|
56
67
|
<div
|
|
57
68
|
v-else
|
|
58
69
|
class="text-default flex min-h-9 items-center py-1.5 text-sm"
|
|
70
|
+
:class="isNumeric && 'tabular-nums'"
|
|
59
71
|
:title="typeof formattedValue === 'string' ? formattedValue : undefined"
|
|
60
72
|
>
|
|
61
73
|
<component :is="formattedValue" v-if="isVNodeValue" />
|
|
@@ -536,7 +536,9 @@ onBeforeUnmount(() => {
|
|
|
536
536
|
</script>
|
|
537
537
|
|
|
538
538
|
<template>
|
|
539
|
-
|
|
539
|
+
<!-- A size container: the preview sits beside its details once the field
|
|
540
|
+
itself has room (a drawer, a form column), not the window. -->
|
|
541
|
+
<div class="@container" @paste="onPaste">
|
|
540
542
|
<input
|
|
541
543
|
ref="fileInput"
|
|
542
544
|
type="file"
|
|
@@ -740,9 +742,12 @@ onBeforeUnmount(() => {
|
|
|
740
742
|
</span>
|
|
741
743
|
</button>
|
|
742
744
|
|
|
743
|
-
<div
|
|
745
|
+
<div
|
|
746
|
+
v-else
|
|
747
|
+
class="flex flex-col gap-4 @min-[480px]:flex-row @min-[480px]:items-stretch"
|
|
748
|
+
>
|
|
744
749
|
<div
|
|
745
|
-
class="group relative aspect-[4/3] w-full flex-none overflow-hidden rounded-xl shadow-sm
|
|
750
|
+
class="group relative aspect-[4/3] w-full flex-none overflow-hidden rounded-xl shadow-sm @min-[480px]:w-58"
|
|
746
751
|
:class="{
|
|
747
752
|
'ring-primary ring-2': isDraggingOver,
|
|
748
753
|
'ring-error ring-2': !isDraggingOver && invalid,
|