@antelopejs/dms 0.9.8 → 0.10.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 +102 -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 -0
- package/dist/config.js +5 -3
- 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 +22 -89
- 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 +1 -2
- package/dist/implementations/dms/manifest.js +2 -0
- 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 +28 -48
- 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 +24 -13
- package/dist/store/listing.js.map +1 -1
- package/dist/store/operations.js +4 -0
- 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/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 +34 -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/hydration/isHydratingComponent.ts +29 -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 +22 -5
- 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 +166 -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 +134 -2
- package/frontend-vue/layers/dms-core/i18n/locales/core-fr-FR.json +134 -2
- 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 +9 -0
- 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 -3
- package/frontend-vue/layers/dms-layout/app/build/components/layout/GithubStarPrompt.vue +18 -7
- package/frontend-vue/layers/dms-layout/app/build/components/layout/PageHeaderActionBar.vue +8 -0
- package/frontend-vue/layers/dms-layout/app/build/components/layout/PageHeaderActionsOutlet.vue +14 -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/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/usePageRecord.ts +50 -0
- package/frontend-vue/layers/dms-layout/app/composables/layout/useServedHeaderActions.ts +25 -7
- package/frontend-vue/layers/dms-layout/app/composables/page/useModuleHistory.ts +3 -2
- package/frontend-vue/layers/dms-layout/app/composables/page/useModuleStore.ts +51 -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/useSiteLayout.ts +6 -1
- package/frontend-vue/layers/dms-layout/app/custom-layouts/DefaultLayout.vue +9 -0
- package/frontend-vue/layers/dms-layout/app/custom-layouts/SettingsLayout.vue +9 -0
- 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 +6 -22
- package/frontend-vue/layers/dms-layout/app/plugins/command-palette-navigation.client.ts +2 -1
- package/frontend-vue/layers/dms-layout/app/plugins/command-palette-personal-pages.client.ts +14 -44
- package/frontend-vue/layers/dms-layout/app/plugins/dms-dev-reload.client.ts +14 -9
- 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/app/utils/pageRecord.ts +71 -0
- package/frontend-vue/layers/dms-layout/i18n/locales/layout-en-GB.json +39 -14
- package/frontend-vue/layers/dms-layout/i18n/locales/layout-fr-FR.json +38 -13
- 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/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 +38 -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/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 +47 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerDefaults.ts +99 -24
- 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 +71 -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/formSections.ts +32 -0
- 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 +65 -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 +73 -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 +77 -32
- 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/utils/addressSuggestions.ts +49 -0
- 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/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/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/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 +118 -36
- 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 +205 -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 +203 -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/KanbanBoard.vue +45 -35
- 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 +410 -96
- 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 +4 -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 +142 -21
- package/frontend-vue/layers/dms-ui/app/composables/live/usePageLive.ts +11 -4
- 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/componentTree.ts +24 -0
- package/frontend-vue/layers/dms-ui/i18n/locales/ui-en-GB.json +16 -4
- package/frontend-vue/layers/dms-ui/i18n/locales/ui-fr-FR.json +16 -4
- package/frontend-vue/package.json +2 -2
- package/package.json +7 -6
- 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 +125 -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/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)));
|
|
@@ -335,7 +370,7 @@ watch(
|
|
|
335
370
|
const previous = fieldValueSnapshots.get(field.id);
|
|
336
371
|
fieldValueSnapshots.set(field.id, snapshot);
|
|
337
372
|
if (previous === undefined || previous === snapshot) continue;
|
|
338
|
-
if (!form.value ||
|
|
373
|
+
if (!form.value || serverErrors.has(field.id)) continue;
|
|
339
374
|
const pattern = fieldErrorPattern(field.id);
|
|
340
375
|
if (!form.value.getErrors(pattern).length) continue;
|
|
341
376
|
void form.value.validate({ name: errorNames(field), silent: true });
|
|
@@ -346,10 +381,12 @@ watch(
|
|
|
346
381
|
|
|
347
382
|
const { t, locale, locales } = useI18n();
|
|
348
383
|
|
|
384
|
+
// A new row is created, not "changes" saved.
|
|
385
|
+
const DEFAULT_SUBMIT_LABEL = createsRecord
|
|
386
|
+
? "dms.button.create"
|
|
387
|
+
: "dms.button.save_changes";
|
|
349
388
|
const submitButtonLabel = computed(() =>
|
|
350
|
-
props.submitLabel
|
|
351
|
-
? processI18n(props.submitLabel)
|
|
352
|
-
: t("dms.button.save_changes"),
|
|
389
|
+
props.submitLabel ? processI18n(props.submitLabel) : t(DEFAULT_SUBMIT_LABEL),
|
|
353
390
|
);
|
|
354
391
|
|
|
355
392
|
watch(disabledFields, (newDisabled, oldDisabled) => {
|
|
@@ -413,6 +450,7 @@ onMounted(() => {
|
|
|
413
450
|
function markFormClean(): void {
|
|
414
451
|
isTouched = false;
|
|
415
452
|
showsErrorSummary.value = false;
|
|
453
|
+
clearServerErrors();
|
|
416
454
|
formDirty.markClean();
|
|
417
455
|
instantSave?.start();
|
|
418
456
|
}
|
|
@@ -441,11 +479,20 @@ const isDirty = computed(
|
|
|
441
479
|
|
|
442
480
|
useUnsavedChanges({ dirty: isDirty, containerId, element: form });
|
|
443
481
|
|
|
444
|
-
// A form offers Cancel
|
|
445
|
-
//
|
|
446
|
-
// saves from its footer band, never from the
|
|
482
|
+
// A form offers Cancel when it has somewhere to go back to: its drawer or
|
|
483
|
+
// modal, `backTo` on a page, or the page of the app the user came from. An
|
|
484
|
+
// action form (send, invite, run) saves from its footer band, never from the
|
|
485
|
+
// floating bar.
|
|
447
486
|
const isActionForm = props.kind === "action";
|
|
448
|
-
|
|
487
|
+
// Read once mounted: the server renders no history.
|
|
488
|
+
const cameFromAppPage = ref(false);
|
|
489
|
+
onMounted(() => {
|
|
490
|
+
cameFromAppPage.value = !!previousAppPage();
|
|
491
|
+
});
|
|
492
|
+
const canCancel = computed(
|
|
493
|
+
() =>
|
|
494
|
+
inFormContainer || !!container || !!props.backTo || cameFromAppPage.value,
|
|
495
|
+
);
|
|
449
496
|
const usesSaveBar = saveMode === "bar" && !inFormContainer && !isActionForm;
|
|
450
497
|
|
|
451
498
|
/** Validates one field alone: whether it holds no error. */
|
|
@@ -479,19 +526,30 @@ const hasChangeableFields = computed(() =>
|
|
|
479
526
|
const router = useDmsRouter();
|
|
480
527
|
const route = useDmsRoute();
|
|
481
528
|
/**
|
|
482
|
-
*
|
|
483
|
-
*
|
|
484
|
-
*
|
|
529
|
+
* The page of the app this one was reached from, which the router records
|
|
530
|
+
* in the history entry: none for a page opened from a link outside the app,
|
|
531
|
+
* a bookmark or a new tab, where going back would leave the app.
|
|
532
|
+
*/
|
|
533
|
+
function previousAppPage(): string | undefined {
|
|
534
|
+
const back = (window.history.state as { back?: unknown } | null)?.back;
|
|
535
|
+
return typeof back === "string" ? back : undefined;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* Cancel: drops what was changed, then closes the drawer or modal, or leaves
|
|
540
|
+
* a page form for the page of the app the user came from (its list, when
|
|
541
|
+
* opened from one), or its `backTo` when the form was opened directly.
|
|
542
|
+
* Discarding first means leaving never asks about changes the user just chose
|
|
543
|
+
* to drop.
|
|
485
544
|
*/
|
|
486
545
|
function cancelForm(): void {
|
|
546
|
+
if (isDirty.value) discardChanges();
|
|
487
547
|
if (container) {
|
|
488
548
|
void container.close();
|
|
489
549
|
return;
|
|
490
550
|
}
|
|
491
|
-
|
|
492
|
-
.
|
|
493
|
-
if (navigation?.canGoBack ?? window.history.length > 1) {
|
|
494
|
-
window.history.back();
|
|
551
|
+
if (previousAppPage()) {
|
|
552
|
+
router.back();
|
|
495
553
|
return;
|
|
496
554
|
}
|
|
497
555
|
if (props.backTo) void router.push(pageLink(props.backTo));
|
|
@@ -537,6 +595,15 @@ provide(FORM_HANDLE_KEY, {
|
|
|
537
595
|
revealField,
|
|
538
596
|
});
|
|
539
597
|
provide(FORM_FIELD_LOADING_KEY, setFieldLoading);
|
|
598
|
+
provide(
|
|
599
|
+
FORM_FIELD_SAVED_KEY,
|
|
600
|
+
fieldSavedMarker({
|
|
601
|
+
hasField: (id) => toValue(allFields).some((field) => field.id === id),
|
|
602
|
+
initialValues,
|
|
603
|
+
dirty: formDirty,
|
|
604
|
+
instantSave,
|
|
605
|
+
}),
|
|
606
|
+
);
|
|
540
607
|
provide(FORM_CONTENT_LANGUAGE_KEY, "*");
|
|
541
608
|
|
|
542
609
|
allFields.value.forEach((field) => {
|
|
@@ -547,6 +614,15 @@ allFields.value.forEach((field) => {
|
|
|
547
614
|
) as FormFieldValue;
|
|
548
615
|
});
|
|
549
616
|
|
|
617
|
+
// A field the form submits a default under (the parent a table is filtered
|
|
618
|
+
// on) holds it from the start: it shows, and a mandatory one is filled.
|
|
619
|
+
for (const [id, value] of Object.entries(
|
|
620
|
+
fieldValuesOfSubmitDefaults(allFields.value, effectiveSubmitDefaults.value),
|
|
621
|
+
)) {
|
|
622
|
+
state.value[id] = cloneFormValue(value);
|
|
623
|
+
initialValues.value[id] = cloneFormValue(value) as FormFieldValue;
|
|
624
|
+
}
|
|
625
|
+
|
|
550
626
|
let recordLoad: FormRecordLoad | undefined;
|
|
551
627
|
if (props.fetchUrl) {
|
|
552
628
|
// Keyed on the record too: the load outlives a drawer or modal, and the
|
|
@@ -648,7 +724,10 @@ function layoutClasses(inSectionCard: boolean) {
|
|
|
648
724
|
if ((inSectionCard || inSection) && isHorizontal) {
|
|
649
725
|
return SECTION_LAYOUT_CLASSES;
|
|
650
726
|
}
|
|
651
|
-
|
|
727
|
+
const orientation = isHorizontal ? "horizontal" : "vertical";
|
|
728
|
+
return inFormContainer
|
|
729
|
+
? CONTAINER_LAYOUT_CLASSES[orientation]
|
|
730
|
+
: FORM_LAYOUT_CLASSES[orientation];
|
|
652
731
|
}
|
|
653
732
|
|
|
654
733
|
function isFieldDisabled(field: FormField): boolean {
|
|
@@ -657,7 +736,8 @@ function isFieldDisabled(field: FormField): boolean {
|
|
|
657
736
|
}
|
|
658
737
|
|
|
659
738
|
function isFieldHidden(field: FormField): boolean {
|
|
660
|
-
|
|
739
|
+
if (hiddenFields.value?.has(field.id)) return true;
|
|
740
|
+
return createsRecord && isHiddenOnCreate(field, state.value[field.id]);
|
|
661
741
|
}
|
|
662
742
|
|
|
663
743
|
function isFieldRequired(field: FormField): boolean {
|
|
@@ -684,7 +764,10 @@ provide(FORM_ENTRY_CONTEXT_KEY, {
|
|
|
684
764
|
isFieldHidden,
|
|
685
765
|
isFieldDisabled,
|
|
686
766
|
isFieldRequired,
|
|
687
|
-
|
|
767
|
+
isReadOnly: computed(() => !hasChangeableFields.value),
|
|
768
|
+
// A new row has no earlier value to compare with: "Changed · was empty"
|
|
769
|
+
// on every field it fills would say nothing.
|
|
770
|
+
showsChanges: !isInstant && !isActionForm && !createsRecord,
|
|
688
771
|
isFieldChanged: (fieldId) => changedFieldIds.value.has(fieldId),
|
|
689
772
|
baselineValue: (fieldId) => formDirty.baseline.value[fieldId],
|
|
690
773
|
fieldSaveState: (fieldId) => instantSave?.states[fieldId] ?? "idle",
|
|
@@ -739,10 +822,6 @@ const sectionOfField = computed(() => {
|
|
|
739
822
|
return owners;
|
|
740
823
|
});
|
|
741
824
|
|
|
742
|
-
watch(invalidFields, (invalid) => {
|
|
743
|
-
if (invalid.size === 0) showsErrorSummary.value = false;
|
|
744
|
-
});
|
|
745
|
-
|
|
746
825
|
// One entry per row to fix: the unlabelled fields of a group share its
|
|
747
826
|
// label, and its first invalid field stands for them.
|
|
748
827
|
const errorSummaryItems = computed(() => {
|
|
@@ -916,6 +995,7 @@ onUnmounted(async () => {
|
|
|
916
995
|
ref="form"
|
|
917
996
|
:state
|
|
918
997
|
:schema="localizedSchema"
|
|
998
|
+
:validate="validateServerErrors"
|
|
919
999
|
:disabled="allFields.every((field) => field.disabled)"
|
|
920
1000
|
@submit="onSubmit"
|
|
921
1001
|
@error="onValidationError"
|
|
@@ -963,7 +1043,7 @@ onUnmounted(async () => {
|
|
|
963
1043
|
/>
|
|
964
1044
|
|
|
965
1045
|
<DmsFormErrorSummary
|
|
966
|
-
v-if="
|
|
1046
|
+
v-if="showsErrorSummary"
|
|
967
1047
|
:items="errorSummaryItems"
|
|
968
1048
|
:class="hasSections ? 'mb-5' : 'mt-4'"
|
|
969
1049
|
@select="focusField"
|
|
@@ -1014,7 +1094,9 @@ onUnmounted(async () => {
|
|
|
1014
1094
|
:saving="loading || isAnyFieldLoading"
|
|
1015
1095
|
:changes="changedFieldLabels"
|
|
1016
1096
|
:form="formElementId"
|
|
1017
|
-
:save-label="
|
|
1097
|
+
:save-label="
|
|
1098
|
+
usesSaveBar && !createsRecord ? props.submitLabel : submitButtonLabel
|
|
1099
|
+
"
|
|
1018
1100
|
:cancellable="canCancel"
|
|
1019
1101
|
:resettable="hasChangeableFields"
|
|
1020
1102
|
:class="usesSaveBar ? 'mx-3' : surfaceClasses.foot"
|
|
@@ -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,
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
import { pageRequestUrl } from "../../../build/composables/page/pageUrlValues";
|
|
3
3
|
import type { SelectMenuItem } from "@nuxt/ui";
|
|
4
4
|
import { refDebounced } from "@vueuse/core";
|
|
5
|
+
import {
|
|
6
|
+
rankAddressSuggestions,
|
|
7
|
+
suggestionPoolSize,
|
|
8
|
+
} from "../../../build/utils/addressSuggestions";
|
|
5
9
|
import {
|
|
6
10
|
formErrorsInjectionKey,
|
|
7
11
|
formInputsInjectionKey,
|
|
@@ -48,6 +52,12 @@ interface AddressProps {
|
|
|
48
52
|
label?: string;
|
|
49
53
|
value?: string;
|
|
50
54
|
};
|
|
55
|
+
/**
|
|
56
|
+
* ISO 3166-1 alpha-2 code ("BE") the country shows while the address has
|
|
57
|
+
* none, written with the first part typed, and the country whose places
|
|
58
|
+
* the street suggestions list first.
|
|
59
|
+
*/
|
|
60
|
+
defaultCountry?: string;
|
|
51
61
|
}
|
|
52
62
|
|
|
53
63
|
const props = defineProps<AddressProps>();
|
|
@@ -68,7 +78,18 @@ const defaultAddress: AddressValue = {
|
|
|
68
78
|
countryCode: "",
|
|
69
79
|
};
|
|
70
80
|
|
|
71
|
-
const
|
|
81
|
+
const defaultCountryCode = computed(
|
|
82
|
+
() => props.defaultCountry?.trim().toUpperCase() ?? "",
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
// An address with no country shows the default one; it is written with the
|
|
86
|
+
// first part typed, so an address left empty stays empty.
|
|
87
|
+
const safeModelValue = computed<AddressValue>(() => {
|
|
88
|
+
const value = modelValue.value ?? defaultAddress;
|
|
89
|
+
return value.countryCode || !defaultCountryCode.value
|
|
90
|
+
? value
|
|
91
|
+
: { ...value, countryCode: defaultCountryCode.value };
|
|
92
|
+
});
|
|
72
93
|
|
|
73
94
|
/* -------------------------------------------------------------------------- */
|
|
74
95
|
/* Field state: which parts show the field's error */
|
|
@@ -308,6 +329,7 @@ interface PhotonResponse {
|
|
|
308
329
|
interface AddressSuggestion {
|
|
309
330
|
id: string;
|
|
310
331
|
label: string;
|
|
332
|
+
countryCode?: string;
|
|
311
333
|
patch: Partial<AddressValue>;
|
|
312
334
|
}
|
|
313
335
|
|
|
@@ -329,6 +351,9 @@ const streetQueryDebounced = refDebounced(streetQuery, SEARCH_DEBOUNCE_MS);
|
|
|
329
351
|
const suggestions = ref<AddressSuggestion[]>([]);
|
|
330
352
|
const isSearching = ref(false);
|
|
331
353
|
const showSuggestions = ref(false);
|
|
354
|
+
// Suggestions only open under the street field while it has the focus: an
|
|
355
|
+
// answer arriving once the user left it must not cover the next fields.
|
|
356
|
+
const isStreetFocused = ref(false);
|
|
332
357
|
|
|
333
358
|
// Photon/OSM exposes a single `housenumber`. We only pull a box/unit out when it
|
|
334
359
|
// is *explicitly* marked (BE "bte", NL "bus", "box", or a "/" separator). A bare
|
|
@@ -403,22 +428,31 @@ watch(streetQueryDebounced, async (query) => {
|
|
|
403
428
|
params: {
|
|
404
429
|
q: query,
|
|
405
430
|
lang: photonLang.value,
|
|
406
|
-
|
|
431
|
+
// A wider pool, so the places of the address's country can come
|
|
432
|
+
// first and the duplicates can go.
|
|
433
|
+
limit: suggestionPoolSize(photonLimit.value),
|
|
407
434
|
},
|
|
408
435
|
});
|
|
409
436
|
|
|
410
437
|
if (seq !== searchSeq) return;
|
|
411
438
|
|
|
412
|
-
|
|
439
|
+
const found = (response.features ?? [])
|
|
413
440
|
.filter(
|
|
414
441
|
(feature) => feature.properties?.street || feature.properties?.name,
|
|
415
442
|
)
|
|
416
443
|
.map((feature, index) => ({
|
|
417
444
|
id: String(index),
|
|
418
445
|
label: formatPhotonLabel(feature.properties),
|
|
446
|
+
countryCode: feature.properties.countrycode?.toUpperCase(),
|
|
419
447
|
patch: mapPhotonFeature(feature.properties),
|
|
420
448
|
}));
|
|
421
|
-
|
|
449
|
+
suggestions.value = rankAddressSuggestions(
|
|
450
|
+
found,
|
|
451
|
+
safeModelValue.value.countryCode,
|
|
452
|
+
photonLimit.value,
|
|
453
|
+
);
|
|
454
|
+
showSuggestions.value =
|
|
455
|
+
isStreetFocused.value && suggestions.value.length > 0;
|
|
422
456
|
} catch {
|
|
423
457
|
if (seq === searchSeq) suggestions.value = [];
|
|
424
458
|
} finally {
|
|
@@ -438,7 +472,9 @@ const streetModel = computed({
|
|
|
438
472
|
});
|
|
439
473
|
|
|
440
474
|
const applySuggestion = (suggestion: AddressSuggestion) => {
|
|
441
|
-
|
|
475
|
+
// A place the geocoder gives no country keeps the one shown.
|
|
476
|
+
const { countryCode, ...located } = suggestion.patch;
|
|
477
|
+
patchFields(countryCode ? suggestion.patch : located);
|
|
442
478
|
// Bump the sequence so any still-in-flight request is discarded and cannot
|
|
443
479
|
// repopulate the list / reopen the dropdown after the user picked a result.
|
|
444
480
|
searchSeq++;
|
|
@@ -449,17 +485,27 @@ const applySuggestion = (suggestion: AddressSuggestion) => {
|
|
|
449
485
|
let blurTimer: ReturnType<typeof setTimeout> | undefined;
|
|
450
486
|
|
|
451
487
|
const onStreetFocus = () => {
|
|
488
|
+
isStreetFocused.value = true;
|
|
452
489
|
if (autocompleteEnabled.value && suggestions.value.length > 0) {
|
|
453
490
|
showSuggestions.value = true;
|
|
454
491
|
}
|
|
455
492
|
};
|
|
456
493
|
|
|
457
494
|
const onStreetBlur = () => {
|
|
495
|
+
isStreetFocused.value = false;
|
|
458
496
|
blurTimer = setTimeout(() => {
|
|
459
497
|
showSuggestions.value = false;
|
|
460
498
|
}, BLUR_CLOSE_DELAY_MS);
|
|
461
499
|
};
|
|
462
500
|
|
|
501
|
+
/** Escape closes the suggestions, as it would any list; typing reopens it. */
|
|
502
|
+
const onStreetEscape = (event: KeyboardEvent) => {
|
|
503
|
+
if (!showSuggestions.value) return;
|
|
504
|
+
// Only the list closes, not the drawer or modal around the form.
|
|
505
|
+
event.stopPropagation();
|
|
506
|
+
showSuggestions.value = false;
|
|
507
|
+
};
|
|
508
|
+
|
|
463
509
|
onBeforeUnmount(() => {
|
|
464
510
|
if (blurTimer) clearTimeout(blurTimer);
|
|
465
511
|
});
|
|
@@ -532,6 +578,7 @@ const streetPlaceholder = computed(() => {
|
|
|
532
578
|
autocomplete="off"
|
|
533
579
|
@focus="onStreetFocus"
|
|
534
580
|
@blur="onStreetBlur"
|
|
581
|
+
@keydown.esc="onStreetEscape"
|
|
535
582
|
/>
|
|
536
583
|
<div
|
|
537
584
|
v-if="autocompleteEnabled && showSuggestions && suggestions.length"
|
|
@@ -635,6 +682,7 @@ const streetPlaceholder = computed(() => {
|
|
|
635
682
|
value-key="value"
|
|
636
683
|
label-key="label"
|
|
637
684
|
searchable
|
|
685
|
+
:aria-label="t('dms.a11y.show_options')"
|
|
638
686
|
@update:model-value="updateField('countryCode', $event)"
|
|
639
687
|
/>
|
|
640
688
|
</div>
|
|
@@ -21,6 +21,12 @@ interface InputCodeProps {
|
|
|
21
21
|
completions?: CodeEditorCompletion[];
|
|
22
22
|
placeholder?: string;
|
|
23
23
|
disabled?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Fills the height its flex parent leaves it (a drawer's body, a stacked
|
|
26
|
+
* `DmsFieldRow fill`) and scrolls inside it: `minLines` stays its floor
|
|
27
|
+
* (the parent scrolls below it), `maxLines` is ignored.
|
|
28
|
+
*/
|
|
29
|
+
fill?: boolean;
|
|
24
30
|
}
|
|
25
31
|
|
|
26
32
|
interface CompletionsResponse {
|
|
@@ -35,6 +41,7 @@ const props = withDefaults(defineProps<InputCodeProps>(), {
|
|
|
35
41
|
completions: undefined,
|
|
36
42
|
placeholder: undefined,
|
|
37
43
|
id: undefined,
|
|
44
|
+
fill: false,
|
|
38
45
|
});
|
|
39
46
|
const model = defineModel<string | null | undefined>();
|
|
40
47
|
const { t } = useI18n();
|
|
@@ -152,13 +159,18 @@ onBeforeUnmount(() => {
|
|
|
152
159
|
</script>
|
|
153
160
|
|
|
154
161
|
<template>
|
|
162
|
+
<!-- Filling, the root clips without scrolling (`overflow-clip`): its
|
|
163
|
+
minimum stays its content's, the editor's floor, and the parent scrolls
|
|
164
|
+
below it. The editor's area holds no size of its own (`contain-size`): a
|
|
165
|
+
long text scrolls in it instead of growing the root. -->
|
|
155
166
|
<div
|
|
156
|
-
class="border-accented
|
|
157
|
-
:class="
|
|
167
|
+
class="border-accented rounded-md border focus-within:ring-2"
|
|
168
|
+
:class="[
|
|
158
169
|
isInvalid
|
|
159
170
|
? 'border-error focus-within:ring-error/25'
|
|
160
|
-
: 'focus-within:border-primary focus-within:ring-primary/25'
|
|
161
|
-
|
|
171
|
+
: 'focus-within:border-primary focus-within:ring-primary/25',
|
|
172
|
+
fill ? 'flex flex-1 flex-col overflow-clip' : 'overflow-hidden',
|
|
173
|
+
]"
|
|
162
174
|
:style="sizeStyle"
|
|
163
175
|
@focusout="emitFormBlur"
|
|
164
176
|
>
|
|
@@ -167,11 +179,23 @@ onBeforeUnmount(() => {
|
|
|
167
179
|
<pre
|
|
168
180
|
v-if="!isReady"
|
|
169
181
|
class="text-highlighted min-h-(--dms-code-min-height) overflow-auto px-3 py-2 font-mono text-[12.5px] whitespace-pre-wrap"
|
|
182
|
+
:class="fill && 'flex-1 contain-size'"
|
|
170
183
|
>{{ model }}</pre
|
|
171
184
|
>
|
|
185
|
+
<!-- Important: CodeMirror's unlayered `.cm-content { min-height: 100% }`
|
|
186
|
+
outranks a utility, and `min-lines` would never apply. -->
|
|
172
187
|
<div
|
|
173
188
|
ref="host"
|
|
174
|
-
|
|
189
|
+
data-dms-code-host
|
|
190
|
+
class="[&_.cm-content]:min-h-(--dms-code-min-height)! [&_.cm-scroller]:overflow-auto"
|
|
191
|
+
:class="
|
|
192
|
+
fill
|
|
193
|
+
? [
|
|
194
|
+
'flex flex-col contain-size [&_.cm-editor]:min-h-0 [&_.cm-editor]:flex-1 [&_.cm-scroller]:min-h-0 [&_.cm-scroller]:flex-1',
|
|
195
|
+
isReady && 'min-h-(--dms-code-min-height) flex-1',
|
|
196
|
+
]
|
|
197
|
+
: '[&_.cm-scroller]:max-h-(--dms-code-max-height)'
|
|
198
|
+
"
|
|
175
199
|
/>
|
|
176
200
|
<div
|
|
177
201
|
class="border-default text-dimmed flex items-center gap-3 border-t bg-(--dms-bg-muted) px-3 py-1 font-mono text-[11px]"
|