@antelopejs/dms 0.9.8 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +171 -0
- package/README.md +1 -1
- package/data/module-store/catalog.json +2 -2
- package/dist/attachments/table-view.js +2 -2
- package/dist/attachments/table-view.js.map +1 -1
- package/dist/automation/actions.d.ts +2 -0
- package/dist/automation/actions.js +116 -71
- package/dist/automation/actions.js.map +1 -1
- package/dist/automation/i18n.d.ts +4 -0
- package/dist/automation/i18n.js +19 -0
- package/dist/automation/i18n.js.map +1 -0
- package/dist/automation/send-notification.d.ts +21 -0
- package/dist/automation/send-notification.js +163 -0
- package/dist/automation/send-notification.js.map +1 -0
- package/dist/automation/triggers.js +19 -25
- package/dist/automation/triggers.js.map +1 -1
- package/dist/client-origin-cors.d.ts +1 -0
- package/dist/client-origin-cors.js +19 -0
- package/dist/client-origin-cors.js.map +1 -0
- package/dist/config.d.ts +3 -2
- package/dist/config.js +5 -7
- package/dist/config.js.map +1 -1
- package/dist/frontend-module.d.ts +4 -0
- package/dist/frontend-module.js +37 -0
- package/dist/frontend-module.js.map +1 -0
- package/dist/implementations/dms/client-ip.js +1 -1
- package/dist/implementations/dms/client-ip.js.map +1 -1
- package/dist/implementations/dms/dev-reload.d.ts +5 -0
- package/dist/implementations/dms/dev-reload.js +23 -3
- package/dist/implementations/dms/dev-reload.js.map +1 -1
- package/dist/implementations/dms/frontend-modules.d.ts +2 -4
- package/dist/implementations/dms/frontend-modules.js +38 -94
- package/dist/implementations/dms/frontend-modules.js.map +1 -1
- package/dist/implementations/dms/frontend-ready.d.ts +12 -2
- package/dist/implementations/dms/frontend-ready.js +34 -4
- package/dist/implementations/dms/frontend-ready.js.map +1 -1
- package/dist/implementations/dms/layout-banners.d.ts +2 -1
- package/dist/implementations/dms/layout-banners.js +9 -0
- package/dist/implementations/dms/layout-banners.js.map +1 -1
- package/dist/implementations/dms/manifest.d.ts +7 -2
- package/dist/implementations/dms/manifest.js +12 -7
- package/dist/implementations/dms/manifest.js.map +1 -1
- package/dist/implementations/dms/page.d.ts +4 -3
- package/dist/implementations/dms/page.js +49 -18
- package/dist/implementations/dms/page.js.map +1 -1
- package/dist/implementations/dms/permissions-resolver.d.ts +2 -2
- package/dist/implementations/dms/permissions-resolver.js +2 -2
- package/dist/implementations/dms/permissions-resolver.js.map +1 -1
- package/dist/implementations/dms/realtime.js +1 -0
- package/dist/implementations/dms/realtime.js.map +1 -1
- package/dist/implementations/dms-base/bulk-selection.d.ts +1 -1
- package/dist/implementations/dms-base/bulk-selection.js +23 -1
- package/dist/implementations/dms-base/bulk-selection.js.map +1 -1
- package/dist/implementations/dms-base/filter-tokens.js +5 -3
- package/dist/implementations/dms-base/filter-tokens.js.map +1 -1
- package/dist/implementations/dms-base/search-route.d.ts +1 -0
- package/dist/implementations/dms-base/search-route.js +35 -13
- package/dist/implementations/dms-base/search-route.js.map +1 -1
- package/dist/implementations/dms-base/table-view.js +11 -6
- package/dist/implementations/dms-base/table-view.js.map +1 -1
- package/dist/implementations/dms-notifications/index.d.ts +2 -2
- package/dist/implementations/dms-notifications/index.js +5 -5
- package/dist/implementations/dms-notifications/index.js.map +1 -1
- package/dist/index.js +32 -55
- package/dist/index.js.map +1 -1
- package/dist/pages/modules/index.d.ts +1 -0
- package/dist/pages/modules/index.js +1 -0
- package/dist/pages/modules/index.js.map +1 -1
- package/dist/pages/modules/modules-store.d.ts +9 -0
- package/dist/pages/modules/modules-store.js +30 -0
- package/dist/pages/modules/modules-store.js.map +1 -0
- package/dist/pages/settings/users/account-credentials.js +2 -2
- package/dist/pages/settings/users/account-credentials.js.map +1 -1
- package/dist/pages/settings/users/account-data-store.js +25 -8
- package/dist/pages/settings/users/account-data-store.js.map +1 -1
- package/dist/pages/settings/users/invite-extension-routes.js +9 -3
- package/dist/pages/settings/users/invite-extension-routes.js.map +1 -1
- package/dist/pages/settings/users/member-management.js +13 -14
- package/dist/pages/settings/users/member-management.js.map +1 -1
- package/dist/pages/settings/users/profile.d.ts +1 -4
- package/dist/pages/settings/users/profile.js +0 -35
- package/dist/pages/settings/users/profile.js.map +1 -1
- package/dist/pages/settings/users/role-editor-store.js +26 -18
- package/dist/pages/settings/users/role-editor-store.js.map +1 -1
- package/dist/pages/settings/users/role-editor.d.ts +0 -1
- package/dist/pages/settings/users/role-editor.js +1 -2
- package/dist/pages/settings/users/role-editor.js.map +1 -1
- package/dist/pages/settings/users/role-preview.js +1 -2
- package/dist/pages/settings/users/role-preview.js.map +1 -1
- package/dist/pages/settings/users/roles.js +2 -2
- package/dist/pages/settings/users/roles.js.map +1 -1
- package/dist/pages/settings/users/two-factor-operations.js.map +1 -1
- package/dist/realtime/broker.d.ts +6 -0
- package/dist/realtime/broker.js +8 -1
- package/dist/realtime/broker.js.map +1 -1
- package/dist/realtime/presence.d.ts +8 -3
- package/dist/realtime/presence.js +8 -4
- package/dist/realtime/presence.js.map +1 -1
- package/dist/realtime/sessions.d.ts +11 -1
- package/dist/realtime/sessions.js +21 -3
- package/dist/realtime/sessions.js.map +1 -1
- package/dist/realtime/table-view.d.ts +2 -2
- package/dist/realtime/table-view.js +4 -3
- package/dist/realtime/table-view.js.map +1 -1
- package/dist/routes/auth/client-ip.d.ts +1 -0
- package/dist/routes/auth/client-ip.js +18 -0
- package/dist/routes/auth/client-ip.js.map +1 -1
- package/dist/routes/auth/oauth/config.d.ts +2 -1
- package/dist/routes/auth/oauth/config.js +5 -1
- package/dist/routes/auth/oauth/config.js.map +1 -1
- package/dist/routes/auth/session-handoff.d.ts +0 -1
- package/dist/routes/auth/session-handoff.js +0 -2
- package/dist/routes/auth/session-handoff.js.map +1 -1
- package/dist/routes/auth.js +3 -2
- package/dist/routes/auth.js.map +1 -1
- package/dist/routes/index.d.ts +0 -1
- package/dist/routes/index.js +0 -1
- package/dist/routes/index.js.map +1 -1
- package/dist/routes/realtime.d.ts +13 -1
- package/dist/routes/realtime.js +114 -29
- package/dist/routes/realtime.js.map +1 -1
- package/dist/startup-config.d.ts +2 -0
- package/dist/startup-config.js +62 -0
- package/dist/startup-config.js.map +1 -0
- package/dist/store/interfaces.d.ts +3 -2
- package/dist/store/interfaces.js +16 -6
- package/dist/store/interfaces.js.map +1 -1
- package/dist/store/listing.js +25 -15
- package/dist/store/listing.js.map +1 -1
- package/dist/store/operations.js +5 -2
- package/dist/store/operations.js.map +1 -1
- package/dist/store/requirements.js +3 -2
- package/dist/store/requirements.js.map +1 -1
- package/dist/store/runtime.d.ts +10 -1
- package/dist/store/runtime.js +33 -6
- package/dist/store/runtime.js.map +1 -1
- package/dist/store/types.d.ts +10 -0
- package/dist/utils/ensure-default-tenant.d.ts +2 -1
- package/dist/utils/ensure-default-tenant.js +13 -1
- package/dist/utils/ensure-default-tenant.js.map +1 -1
- package/dist/utils/export-jobs.js +2 -1
- package/dist/utils/export-jobs.js.map +1 -1
- package/dist/validation/auth.schema.d.ts +2 -2
- package/dist/validation/member-invite.schema.d.ts +2 -10
- package/dist/validation/member-invite.schema.js +2 -15
- package/dist/validation/member-invite.schema.js.map +1 -1
- package/frontend-vue/dms.frontend.ts +24 -5
- package/frontend-vue/dms.server.ts +17 -0
- package/frontend-vue/layers/dms-auth/server/accounts.ts +3 -4
- package/frontend-vue/layers/dms-core/app/build/composables/renderNow.ts +33 -0
- package/frontend-vue/layers/dms-core/app/build/composables/user/tablePreferences.ts +5 -1
- package/frontend-vue/layers/dms-core/app/build/utils/crossTab.ts +199 -0
- package/frontend-vue/layers/dms-core/app/build/utils/sharedRealtimeConnection.ts +410 -0
- package/frontend-vue/layers/dms-core/app/composables/auth/useApiData.ts +77 -12
- package/frontend-vue/layers/dms-core/app/composables/data-types/useDataType.ts +26 -0
- package/frontend-vue/layers/dms-core/app/composables/live/livePauseSource.ts +29 -0
- package/frontend-vue/layers/dms-core/app/composables/period/compareResolvers.ts +150 -9
- package/frontend-vue/layers/dms-core/app/composables/period/usePeriod.ts +6 -4
- package/frontend-vue/layers/dms-core/app/composables/period/usePeriodScope.ts +27 -1
- package/frontend-vue/layers/dms-core/app/composables/realtime/useUserRealtime.ts +256 -119
- package/frontend-vue/layers/dms-core/app/composables/translation/useComposedText.ts +21 -8
- package/frontend-vue/layers/dms-core/app/composables/translation/useTranslation.ts +25 -5
- package/frontend-vue/layers/dms-core/app/composables/useApiError.ts +3 -5
- package/frontend-vue/layers/dms-core/app/composables/useFieldErrors.ts +61 -26
- package/frontend-vue/layers/dms-core/app/plugins/dev-error-log.ts +16 -0
- package/frontend-vue/layers/dms-core/app/types/user.ts +6 -0
- package/frontend-vue/layers/dms-core/app/utils/composedText.ts +7 -2
- package/frontend-vue/layers/dms-core/app/utils/formatter.ts +134 -35
- package/frontend-vue/layers/dms-core/app/utils/url-interpolation.ts +18 -1
- package/frontend-vue/layers/dms-core/i18n/locales/core-en-GB.json +136 -2
- package/frontend-vue/layers/dms-core/i18n/locales/core-fr-FR.json +136 -2
- package/frontend-vue/layers/dms-core/shared/types/app-config.ts +0 -2
- package/frontend-vue/layers/dms-layout/app/app.config.ts +0 -1
- package/frontend-vue/layers/dms-layout/app/assets/css/main.css +11 -1
- package/frontend-vue/layers/dms-layout/app/assets/fonts/Geist-Italic-Variable.woff2 +0 -0
- package/frontend-vue/layers/dms-layout/app/assets/fonts/Geist-Variable.woff2 +0 -0
- package/frontend-vue/layers/dms-layout/app/assets/fonts/GeistMono-Italic-Variable.woff2 +0 -0
- package/frontend-vue/layers/dms-layout/app/assets/fonts/GeistMono-Variable.woff2 +0 -0
- package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardBanners.vue +3 -2
- package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardHeader.vue +41 -21
- package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardPageBody.vue +6 -2
- package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardSidebar.vue +4 -19
- package/frontend-vue/layers/dms-layout/app/build/components/layout/Footer.vue +11 -107
- package/frontend-vue/layers/dms-layout/app/build/components/layout/GithubStarPrompt.vue +18 -7
- package/frontend-vue/layers/dms-layout/app/build/components/layout/PageHeaderActionsOutlet.vue +4 -0
- package/frontend-vue/layers/dms-layout/app/build/components/layout/RowSidePanel.vue +43 -82
- package/frontend-vue/layers/dms-layout/app/build/components/layout/SidebarUserMenu.vue +44 -3
- package/frontend-vue/layers/dms-layout/app/build/components/layout/UserIdentity.vue +11 -3
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleCatalogTile.vue +132 -35
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleManageMenu.vue +59 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleSourceLabel.vue +25 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreBanners.vue +73 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreOperation.vue +116 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreRequirements.vue +8 -3
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreTile.vue +85 -207
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleTile.vue +10 -3
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleTileSkeleton.vue +68 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationInboxDisplay.vue +24 -8
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationInboxItem.vue +8 -5
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/region/RegionTimeZoneInput.vue +1 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/role-permissions.ts +19 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/useRoleEditor.ts +2 -1
- package/frontend-vue/layers/dms-layout/app/build/composables/layout/useSidePanelWidth.ts +31 -70
- package/frontend-vue/layers/dms-layout/app/build/composables/notification/useNotificationGroupsOpen.ts +11 -1
- package/frontend-vue/layers/dms-layout/app/build/utils/dev-reload-stream.ts +81 -0
- package/frontend-vue/layers/dms-layout/app/build/utils/github-repository.ts +2 -2
- package/frontend-vue/layers/dms-layout/app/build/utils/module-store-catalog.ts +232 -36
- package/frontend-vue/layers/dms-layout/app/build/utils/modules-catalog.ts +122 -14
- package/frontend-vue/layers/dms-layout/app/composables/layout/useLayoutBanners.ts +32 -3
- package/frontend-vue/layers/dms-layout/app/composables/layout/useServedHeaderActions.ts +49 -11
- package/frontend-vue/layers/dms-layout/app/composables/page/useModuleHistory.ts +3 -2
- package/frontend-vue/layers/dms-layout/app/composables/page/useModuleStore.ts +59 -4
- package/frontend-vue/layers/dms-layout/app/composables/page/useModuleStoreActions.ts +194 -0
- package/frontend-vue/layers/dms-layout/app/composables/page/usePageComponentPreload.ts +23 -3
- package/frontend-vue/layers/dms-layout/app/composables/page/usePageLayout.ts +4 -2
- package/frontend-vue/layers/dms-layout/app/composables/page/usePageRecordDeletion.ts +162 -0
- package/frontend-vue/layers/dms-layout/app/composables/page/useSiteLayout.ts +6 -1
- package/frontend-vue/layers/dms-layout/app/custom-layouts/DefaultLayout.vue +6 -2
- package/frontend-vue/layers/dms-layout/app/custom-layouts/SettingsLayout.vue +6 -2
- package/frontend-vue/layers/dms-layout/app/custom-pages/modules-store.vue +291 -0
- package/frontend-vue/layers/dms-layout/app/custom-pages/modules.vue +87 -474
- package/frontend-vue/layers/dms-layout/app/middleware/module-routing.global.ts +3 -0
- package/frontend-vue/layers/dms-layout/app/pages/[...slug].vue +13 -22
- package/frontend-vue/layers/dms-layout/app/plugins/command-palette-navigation.client.ts +11 -10
- package/frontend-vue/layers/dms-layout/app/plugins/command-palette-personal-pages.client.ts +22 -52
- package/frontend-vue/layers/dms-layout/app/plugins/command-palette-quick-actions.client.ts +7 -7
- package/frontend-vue/layers/dms-layout/app/plugins/command-palette-session.client.ts +11 -10
- package/frontend-vue/layers/dms-layout/app/plugins/dms-dev-reload.client.ts +14 -9
- package/frontend-vue/layers/dms-layout/app/theme/actions.ts +5 -4
- package/frontend-vue/layers/dms-layout/app/theme/form-controls.ts +9 -4
- package/frontend-vue/layers/dms-layout/app/theme/surfaces.ts +22 -6
- package/frontend-vue/layers/dms-layout/app/types/module-store.ts +9 -0
- package/frontend-vue/layers/dms-layout/app/types/page.ts +15 -1
- package/frontend-vue/layers/dms-layout/app/utils/account-menu.ts +11 -0
- package/frontend-vue/layers/dms-layout/app/utils/breadcrumb.ts +57 -0
- package/frontend-vue/layers/dms-layout/app/utils/pageQuery.ts +26 -0
- package/frontend-vue/layers/dms-layout/i18n/locales/layout-en-GB.json +45 -18
- package/frontend-vue/layers/dms-layout/i18n/locales/layout-fr-FR.json +44 -17
- package/frontend-vue/layers/dms-ui/app/build/components/containers/TargetComponentTree.vue +31 -0
- package/frontend-vue/layers/dms-ui/app/build/components/containers/constants.ts +25 -0
- package/frontend-vue/layers/dms-ui/app/build/components/containers/drawer/DynamicDrawer.vue +244 -15
- package/frontend-vue/layers/dms-ui/app/build/components/containers/modal/DynamicModal.vue +42 -25
- package/frontend-vue/layers/dms-ui/app/build/components/containers/row/RowHeader.vue +153 -0
- package/frontend-vue/layers/dms-ui/app/build/components/containers/row/RowNotFound.vue +44 -0
- package/frontend-vue/layers/dms-ui/app/build/components/containers/row/drawerRowHeader.ts +35 -0
- package/frontend-vue/layers/dms-ui/app/build/components/form/FormEntries.vue +44 -9
- package/frontend-vue/layers/dms-ui/app/build/components/form/FormErrorSummary.vue +11 -4
- package/frontend-vue/layers/dms-ui/app/build/components/form/FormFieldControl.vue +38 -5
- package/frontend-vue/layers/dms-ui/app/build/components/form/FormFieldNotes.vue +29 -5
- package/frontend-vue/layers/dms-ui/app/build/components/form/FormLoadError.vue +5 -1
- package/frontend-vue/layers/dms-ui/app/build/components/form/FormSectionNav.vue +3 -1
- package/frontend-vue/layers/dms-ui/app/build/components/form/FormSections.vue +106 -27
- package/frontend-vue/layers/dms-ui/app/build/components/table/Actions.vue +12 -4
- package/frontend-vue/layers/dms-ui/app/build/components/table/Empty.vue +4 -2
- package/frontend-vue/layers/dms-ui/app/build/components/table/FiltersRow.vue +48 -1
- package/frontend-vue/layers/dms-ui/app/build/components/table/Pagination.vue +55 -54
- package/frontend-vue/layers/dms-ui/app/build/components/table/RowSelection.vue +2 -1
- package/frontend-vue/layers/dms-ui/app/build/components/table/Table.vue +396 -288
- package/frontend-vue/layers/dms-ui/app/build/components/table/Tabs.vue +2 -1
- package/frontend-vue/layers/dms-ui/app/build/components/table/Views.vue +2 -1
- package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardAvatar.vue +59 -0
- package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardGridSkeleton.vue +19 -2
- package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardRowActions.vue +38 -0
- package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardsDisplay.vue +148 -104
- package/frontend-vue/layers/dms-ui/app/build/components/table-view/LiveHoldBanner.vue +17 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/actions/bulkSelection.ts +43 -9
- package/frontend-vue/layers/dms-ui/app/build/composables/actions/rowComponentOptions.ts +76 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/actions/rowNavigation.ts +172 -27
- package/frontend-vue/layers/dms-ui/app/build/composables/actions/useActionTargets.ts +270 -46
- package/frontend-vue/layers/dms-ui/app/build/composables/confirm/actionError.ts +6 -1
- package/frontend-vue/layers/dms-ui/app/build/composables/confirm/confirmDialogTexts.ts +2 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/containers/closingLayers.ts +186 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/containers/context.ts +14 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/containers/drawerSize.ts +229 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/containers/useResizableSize.ts +175 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/metricCells.ts +18 -35
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/numberSuffix.ts +44 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerDefaults.ts +123 -27
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerFieldTypes.ts +2 -1
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationFilter.ts +75 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationRows.ts +92 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationValue.ts +39 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/twoLineCell.ts +3 -3
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/useColumnValueRenderer.ts +6 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/form/createFormFields.ts +15 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/fieldSaved.ts +40 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/fieldValueRule.ts +62 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/formEntryContext.ts +5 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/formFooter.ts +42 -7
- package/frontend-vue/layers/dms-ui/app/build/composables/form/formLayout.ts +106 -4
- package/frontend-vue/layers/dms-ui/app/build/composables/form/formRecordLoad.ts +11 -5
- package/frontend-vue/layers/dms-ui/app/build/composables/form/formSections.ts +32 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/formValidation.ts +36 -4
- package/frontend-vue/layers/dms-ui/app/build/composables/form/readonlyValue.ts +19 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/registerFormFunctions.ts +27 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/repeaterTable.ts +78 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/serverFieldErrors.ts +49 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/toasterClearance.ts +118 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/useInstantForm.ts +12 -1
- package/frontend-vue/layers/dms-ui/app/build/composables/live/currentPageLive.ts +41 -3
- package/frontend-vue/layers/dms-ui/app/build/composables/live/livePoller.ts +10 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/live/pageReadClock.ts +28 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/live/shortcuts.ts +1 -1
- package/frontend-vue/layers/dms-ui/app/build/composables/live/usePageLiveHost.ts +17 -3
- package/frontend-vue/layers/dms-ui/app/build/composables/live/useUpdatedLabel.ts +38 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/page-toolbar/pageToolbarContext.ts +75 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/page-toolbar/toolbarControlHeight.ts +29 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/period/periodComparison.ts +52 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/period/periodDisplay.ts +21 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/period/periodShortLabels.ts +28 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/period/usePeriodDraft.ts +1 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table/useRelationFilterLabels.ts +97 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table/useRowScrollAnchor.ts +106 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table/useTable.ts +9 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table/useTableColumns.ts +1 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/archivedCount.ts +31 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/filterEditorValue.ts +38 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/formatFilterValue.ts +33 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/scrollEdges.ts +31 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useCardFields.ts +33 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useMobileDisplay.ts +48 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useScrolledPastTop.ts +41 -18
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableFooter.ts +3 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableLinkedVisit.ts +78 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableLiveHold.ts +135 -22
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableRows.ts +56 -25
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViewRowActions.ts +90 -35
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViews.ts +86 -10
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/bulkActions.ts +14 -4
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/card.ts +127 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/compareValues.ts +13 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/expandedRows.ts +28 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/groupedRows.ts +114 -1
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/linkedArrival.ts +308 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/locateRow.ts +106 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/pageArrival.ts +34 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/pinnedRows.ts +17 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/quickFilters.ts +41 -33
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/recordLink.ts +24 -8
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/tableCounts.ts +113 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/tableQuery.ts +27 -4
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/views.ts +22 -6
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/writeError.ts +21 -0
- package/frontend-vue/layers/dms-ui/app/build/utils/addressSuggestions.ts +49 -0
- package/frontend-vue/layers/dms-ui/app/build/utils/codeHighlight.ts +67 -29
- package/frontend-vue/layers/dms-ui/app/build/utils/eyebrow.ts +12 -0
- package/frontend-vue/layers/dms-ui/app/build/utils/fieldOptionsI18n.ts +51 -11
- package/frontend-vue/layers/dms-ui/app/build/utils/htmlGrammar.ts +79 -0
- package/frontend-vue/layers/dms-ui/app/build/utils/inputWidth.ts +53 -0
- package/frontend-vue/layers/dms-ui/app/build/utils/numberAdjustment.ts +6 -3
- package/frontend-vue/layers/dms-ui/app/build/utils/relativeDate.ts +19 -5
- package/frontend-vue/layers/dms-ui/app/build/utils/scrollWithin.ts +99 -0
- package/frontend-vue/layers/dms-ui/app/build/utils/shellParser.ts +1 -1
- package/frontend-vue/layers/dms-ui/app/build/utils/streamHighlight.ts +90 -0
- package/frontend-vue/layers/dms-ui/app/build/utils/urlVariables.ts +36 -14
- package/frontend-vue/layers/dms-ui/app/components/PasswordStrength.vue +1 -1
- package/frontend-vue/layers/dms-ui/app/components/RecursiveComponent.vue +9 -1
- package/frontend-vue/layers/dms-ui/app/components/blocks/LiveToggleBlock.vue +80 -32
- package/frontend-vue/layers/dms-ui/app/components/blocks/PageToolbarBlock.vue +137 -0
- package/frontend-vue/layers/dms-ui/app/components/blocks/StatGroupBlock.vue +5 -0
- package/frontend-vue/layers/dms-ui/app/components/chart/ApexChartHost.vue +16 -2
- package/frontend-vue/layers/dms-ui/app/components/chart/Chart.vue +24 -5
- package/frontend-vue/layers/dms-ui/app/components/chart/ChartCard.vue +41 -23
- package/frontend-vue/layers/dms-ui/app/components/code-snippet/CodeSnippet.vue +23 -12
- package/frontend-vue/layers/dms-ui/app/components/confirm/ConfirmModal.vue +1 -1
- package/frontend-vue/layers/dms-ui/app/components/container-footer/ContainerFooter.vue +34 -0
- package/frontend-vue/layers/dms-ui/app/components/field-row/FieldRow.vue +25 -2
- package/frontend-vue/layers/dms-ui/app/components/flow-canvas/FlowCanvas.vue +2 -2
- package/frontend-vue/layers/dms-ui/app/components/form/Form.vue +119 -36
- package/frontend-vue/layers/dms-ui/app/components/form/components/Cascader.vue +53 -22
- package/frontend-vue/layers/dms-ui/app/components/form/components/DatePicker.vue +20 -1
- package/frontend-vue/layers/dms-ui/app/components/form/components/Display.vue +13 -1
- package/frontend-vue/layers/dms-ui/app/components/form/components/Image.vue +8 -3
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputAddress.vue +53 -5
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputCode.vue +29 -5
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputNumber.vue +45 -8
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputPercentage.vue +28 -5
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputSecret.vue +5 -0
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputText.vue +19 -2
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputTime.vue +2 -1
- package/frontend-vue/layers/dms-ui/app/components/form/components/Relation.vue +226 -65
- package/frontend-vue/layers/dms-ui/app/components/form/components/Repeater.vue +80 -30
- package/frontend-vue/layers/dms-ui/app/components/form/components/RepeaterTable.vue +210 -0
- package/frontend-vue/layers/dms-ui/app/components/form/components/Select.vue +4 -2
- package/frontend-vue/layers/dms-ui/app/components/grid/GridRow.vue +11 -2
- package/frontend-vue/layers/dms-ui/app/components/key-value-list/KeyValueList.vue +79 -70
- package/frontend-vue/layers/dms-ui/app/components/kpi/KpiCard.vue +117 -21
- package/frontend-vue/layers/dms-ui/app/components/meter/Meter.vue +2 -1
- package/frontend-vue/layers/dms-ui/app/components/period/PeriodSelector.vue +113 -34
- package/frontend-vue/layers/dms-ui/app/components/save-bar/SaveBar.vue +14 -2
- package/frontend-vue/layers/dms-ui/app/components/section-header/Eyebrow.vue +6 -1
- package/frontend-vue/layers/dms-ui/app/components/segmented/Segmented.vue +13 -0
- package/frontend-vue/layers/dms-ui/app/components/stat-group/StatGroup.vue +52 -3
- package/frontend-vue/layers/dms-ui/app/components/tab/Tab.vue +2 -1
- package/frontend-vue/layers/dms-ui/app/components/table-view/CascaderPath.vue +74 -25
- package/frontend-vue/layers/dms-ui/app/components/table-view/KanbanBoard.vue +48 -44
- package/frontend-vue/layers/dms-ui/app/components/table-view/KanbanDisplay.vue +4 -1
- package/frontend-vue/layers/dms-ui/app/components/table-view/TableView.vue +426 -97
- package/frontend-vue/layers/dms-ui/app/components/top-list/TopListCard.vue +33 -5
- package/frontend-vue/layers/dms-ui/app/composables/chart/apexCategoryLabels.ts +68 -0
- package/frontend-vue/layers/dms-ui/app/composables/chart/apexDatetimeBuckets.ts +306 -0
- package/frontend-vue/layers/dms-ui/app/composables/chart/formatValue.ts +4 -3
- package/frontend-vue/layers/dms-ui/app/composables/chart/heatmapColors.ts +93 -0
- package/frontend-vue/layers/dms-ui/app/composables/chart/localizeSeries.ts +62 -0
- package/frontend-vue/layers/dms-ui/app/composables/chart/useApexChart.ts +116 -8
- package/frontend-vue/layers/dms-ui/app/composables/chart/useApexChart.types.ts +7 -0
- package/frontend-vue/layers/dms-ui/app/composables/containers/types.ts +84 -1
- package/frontend-vue/layers/dms-ui/app/composables/containers/useDrawer.ts +69 -8
- package/frontend-vue/layers/dms-ui/app/composables/form/types/field-saved.ts +11 -0
- package/frontend-vue/layers/dms-ui/app/composables/form/types/field.ts +16 -0
- package/frontend-vue/layers/dms-ui/app/composables/form/types/functions.ts +1 -0
- package/frontend-vue/layers/dms-ui/app/composables/form/useForm.ts +189 -28
- package/frontend-vue/layers/dms-ui/app/composables/live/usePageLive.ts +29 -12
- package/frontend-vue/layers/dms-ui/app/composables/page-toolbar/usePageToolbarSize.ts +30 -0
- package/frontend-vue/layers/dms-ui/app/composables/table-view/kanban.ts +4 -2
- package/frontend-vue/layers/dms-ui/app/composables/table-view/types/action-target.ts +22 -3
- package/frontend-vue/layers/dms-ui/app/composables/table-view/types/config.ts +4 -0
- package/frontend-vue/layers/dms-ui/app/composables/table-view/types/display.ts +24 -1
- package/frontend-vue/layers/dms-ui/app/plugins/closing-layers.client.ts +10 -0
- package/frontend-vue/layers/dms-ui/app/plugins/live-pause-source.ts +15 -0
- package/frontend-vue/layers/dms-ui/app/plugins/register.ts +2 -0
- package/frontend-vue/layers/dms-ui/app/types/input-number.ts +3 -2
- package/frontend-vue/layers/dms-ui/app/types/page-toolbar.ts +7 -0
- package/frontend-vue/layers/dms-ui/app/types/row-action.ts +0 -2
- package/frontend-vue/layers/dms-ui/app/types/row-navigation.ts +17 -0
- package/frontend-vue/layers/dms-ui/app/types/table/query.ts +2 -1
- package/frontend-vue/layers/dms-ui/app/utils/blockRefresh.ts +3 -1
- package/frontend-vue/layers/dms-ui/app/utils/cascader.ts +94 -3
- package/frontend-vue/layers/dms-ui/app/utils/componentTree.ts +24 -0
- package/frontend-vue/layers/dms-ui/i18n/locales/ui-en-GB.json +20 -5
- package/frontend-vue/layers/dms-ui/i18n/locales/ui-fr-FR.json +20 -5
- package/frontend-vue/package.json +6 -2
- package/package.json +11 -10
- package/skills/dms/SKILL.md +1 -1
- package/skills/dms-auth/SKILL.md +5 -3
- package/skills/dms-best-practices/REFERENCE.md +2 -0
- package/skills/dms-best-practices/SKILL.md +4 -0
- package/skills/dms-module/SKILL.md +3 -2
- package/skills/dms-pages/REFERENCE.md +129 -16
- package/skills/dms-pages/SKILL.md +1 -1
- package/skills/dms-project/DEV-SERVERS.md +23 -1
- package/skills/dms-project/REFERENCE.md +1 -1
- package/skills/dms-project/SKILL.md +4 -1
- package/skills/dms-project/scripts/dms-dev.sh +205 -17
- package/dist/hooks/tenant-instances.d.ts +0 -1
- package/dist/hooks/tenant-instances.js +0 -13
- package/dist/hooks/tenant-instances.js.map +0 -1
- package/dist/routes/startup-gate.d.ts +0 -7
- package/dist/routes/startup-gate.js +0 -39
- package/dist/routes/startup-gate.js.map +0 -1
- package/frontend-vue/layers/dms-core/app/composables/period/periodRenderNow.ts +0 -42
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts" generic="T extends Data">
|
|
2
|
+
import { get } from "@nuxt/ui/runtime/utils/index.js";
|
|
3
|
+
import DmsBlockStatus from "../../build/components/blocks/BlockStatus.vue";
|
|
4
|
+
import { readFetchNotFound } from "../../build/utils/fetchNotFound";
|
|
2
5
|
import type {
|
|
3
6
|
ColumnSizingState,
|
|
4
7
|
ExpandedState,
|
|
@@ -52,15 +55,15 @@ import {
|
|
|
52
55
|
KANBAN_DISPLAY_BRIDGE_KEY,
|
|
53
56
|
} from "../../composables/table-view/kanban";
|
|
54
57
|
import { useTableRowActions } from "../../build/composables/table-view/useTableViewRowActions";
|
|
58
|
+
import { describeTableWriteError } from "../../build/composables/table-view/utils/writeError";
|
|
55
59
|
import {
|
|
56
60
|
buildTableQuery,
|
|
57
61
|
isFilterEffective,
|
|
58
62
|
} from "../../build/composables/table-view/utils/tableQuery";
|
|
59
63
|
import { buildTableViewShortcuts } from "../../composables/table-view/shortcuts";
|
|
60
64
|
import {
|
|
61
|
-
|
|
65
|
+
expandedRowsOnListing,
|
|
62
66
|
type ExpandedRowMap,
|
|
63
|
-
keepListedRows,
|
|
64
67
|
nextExpandedRows,
|
|
65
68
|
} from "../../build/composables/table-view/utils/expandedRows";
|
|
66
69
|
import { resolveTableChrome } from "../../build/composables/table-view/utils/chrome";
|
|
@@ -128,16 +131,32 @@ import {
|
|
|
128
131
|
type WatchSource,
|
|
129
132
|
} from "vue";
|
|
130
133
|
import { useTableViewConfig } from "../../build/composables/table-view/useTableViewConfig";
|
|
131
|
-
import {
|
|
134
|
+
import {
|
|
135
|
+
keptViewId,
|
|
136
|
+
useTableViews,
|
|
137
|
+
} from "../../build/composables/table-view/useTableViews";
|
|
132
138
|
import { useGroupedRows } from "../../build/composables/table-view/useGroupedRows";
|
|
133
139
|
import { useTableFooter } from "../../build/composables/table-view/useTableFooter";
|
|
134
140
|
import { useAccumulatedPages } from "../../build/composables/table-view/useAccumulatedPages";
|
|
141
|
+
import type { RowStep } from "../../build/composables/actions/rowNavigation";
|
|
142
|
+
import { rowLocator } from "../../build/composables/table-view/utils/locateRow";
|
|
135
143
|
import { usePersistedPagination } from "../../build/composables/table-view/usePersistedPagination";
|
|
136
144
|
import { useTablePreferences } from "../../build/composables/table-view/useTablePreferences";
|
|
145
|
+
import {
|
|
146
|
+
isLinkedArrival,
|
|
147
|
+
linkedArrivalPreferences,
|
|
148
|
+
linkFollowingPreferences,
|
|
149
|
+
linkKeyScope,
|
|
150
|
+
urlFilterScope,
|
|
151
|
+
} from "../../build/composables/table-view/utils/linkedArrival";
|
|
152
|
+
import { pageArrivalKind } from "../../build/composables/table-view/utils/pageArrival";
|
|
153
|
+
import { useTableLinkedVisit } from "../../build/composables/table-view/useTableLinkedVisit";
|
|
154
|
+
import { useMobileDisplay } from "../../build/composables/table-view/useMobileDisplay";
|
|
137
155
|
import type { Ref } from "vue";
|
|
138
156
|
import type { TableField } from "#dms-core/app/build/composables/user/tablePreferences";
|
|
139
157
|
import { useTableRows } from "../../build/composables/table-view/useTableRows";
|
|
140
158
|
import { useRefreshTriggers } from "../../build/composables/blocks/useRefreshTriggers";
|
|
159
|
+
import { refreshPageBlocks } from "../../utils/blockRefresh";
|
|
141
160
|
import { useTableLiveHold } from "../../build/composables/table-view/useTableLiveHold";
|
|
142
161
|
import type { TableViewLiveHoldOptions } from "../../types/live";
|
|
143
162
|
import { usePageLive } from "../../composables/live/usePageLive";
|
|
@@ -145,13 +164,24 @@ import LiveHoldBanner from "../../build/components/table-view/LiveHoldBanner.vue
|
|
|
145
164
|
import { useTableReorder } from "../../build/composables/table-view/useTableReorder";
|
|
146
165
|
import {
|
|
147
166
|
groupedOptionsFor,
|
|
148
|
-
|
|
167
|
+
listTableSorting,
|
|
168
|
+
orderGroupedRows,
|
|
169
|
+
pickedTableSorting,
|
|
170
|
+
type TableSortingInput,
|
|
149
171
|
isGroupableColumn,
|
|
150
172
|
} from "../../build/composables/table-view/utils/groupedRows";
|
|
151
173
|
import {
|
|
152
174
|
readTableUrlTab,
|
|
153
175
|
useTableUrlTab,
|
|
154
176
|
} from "../../build/composables/table-view/useTableUrlTab";
|
|
177
|
+
import {
|
|
178
|
+
buildTableCountQueries,
|
|
179
|
+
isCountNarrowed,
|
|
180
|
+
navBadgeCount,
|
|
181
|
+
VIEW_COUNT_ID_PREFIX,
|
|
182
|
+
type TableCountState,
|
|
183
|
+
} from "../../build/composables/table-view/utils/tableCounts";
|
|
184
|
+
import { viewFilters } from "../../build/composables/table-view/utils/views";
|
|
155
185
|
import { useTableRecordLink } from "../../build/composables/table-view/useTableRecordLink";
|
|
156
186
|
import TableViews, {
|
|
157
187
|
type TableViewItem,
|
|
@@ -187,6 +217,7 @@ interface RealtimePresenceActor {
|
|
|
187
217
|
type RealtimePresenceMap = Record<string, RealtimePresenceActor[]>;
|
|
188
218
|
|
|
189
219
|
/** A kept field of the table, its state, and its default. */
|
|
220
|
+
// The default may move once mounted (a phone's display): read when written.
|
|
190
221
|
type TableStatePreference = [TableField, Ref<unknown>, unknown];
|
|
191
222
|
|
|
192
223
|
// The backend options of a table view, declared here as well so the
|
|
@@ -194,6 +225,8 @@ type TableStatePreference = [TableField, Ref<unknown>, unknown];
|
|
|
194
225
|
interface TableViewProps<T extends Data> extends TableViewConfig<T> {
|
|
195
226
|
/** Expandable rows: caret column + detail band (backend `expandable`). */
|
|
196
227
|
expandable?: TableViewExpandableConfig;
|
|
228
|
+
/** Caption count while the archived rows show (backend `archivedCountLabel`). */
|
|
229
|
+
archivedCountLabel?: string;
|
|
197
230
|
/** Placeholder of the search field. */
|
|
198
231
|
searchPlaceholder?: string;
|
|
199
232
|
/** Key opening the search (`defineShortcuts` notation); `shift_f` else. */
|
|
@@ -254,7 +287,51 @@ const {
|
|
|
254
287
|
defaultDisplay,
|
|
255
288
|
} = useTableViewConfig<T>(props);
|
|
256
289
|
|
|
257
|
-
const
|
|
290
|
+
const route = useDmsRoute();
|
|
291
|
+
const urlScope = {
|
|
292
|
+
tableId: props.tableId,
|
|
293
|
+
isSoleTableView: props.isSoleTableView,
|
|
294
|
+
};
|
|
295
|
+
const ALL_TAB_ID = "all";
|
|
296
|
+
|
|
297
|
+
const keptPreferences = useTablePreferences(componentId, pageId);
|
|
298
|
+
// A link naming a view, a tab, a record or a URL filter opens on the table's
|
|
299
|
+
// defaults plus what it names, never over the state kept from the last visit
|
|
300
|
+
// (which stays kept for the next plain visit), until the user makes the
|
|
301
|
+
// state shown their own: a view, a tab, a filter or a sort they pick. Only a
|
|
302
|
+
// reload (or Back) of the URL the table wrote for that state restores it.
|
|
303
|
+
const isLinked = isLinkedArrival({
|
|
304
|
+
query: route.query,
|
|
305
|
+
urlScope,
|
|
306
|
+
queryParamFilters,
|
|
307
|
+
isVisit: pageArrivalKind() === "visit",
|
|
308
|
+
rememberedTab: keptPreferences.get<string>("activeTab", ALL_TAB_ID),
|
|
309
|
+
keptLinkScope: keptPreferences.get<string | undefined>(
|
|
310
|
+
"linkScope",
|
|
311
|
+
undefined,
|
|
312
|
+
),
|
|
313
|
+
shownLink: keptPreferences.get<string | undefined>("shownLink", undefined),
|
|
314
|
+
});
|
|
315
|
+
const tablePreferences = linkFollowingPreferences(
|
|
316
|
+
isLinked ? linkedArrivalPreferences(keptPreferences) : keptPreferences,
|
|
317
|
+
{
|
|
318
|
+
isLinkedArrival: isLinked,
|
|
319
|
+
urlScope,
|
|
320
|
+
linkScope: () => urlFilterScope(route.query, queryParamFilters),
|
|
321
|
+
linkKeys: () => linkKeyScope(route.query, urlScope, queryParamFilters),
|
|
322
|
+
// Read once the table is mounted, past the declarations below. A page
|
|
323
|
+
// kept without its scope is restored as it is (`usePersistedPagination`).
|
|
324
|
+
listingState: () => [
|
|
325
|
+
["activeView", keptViewId(activeViewId.value), undefined],
|
|
326
|
+
["activeTab", activeTabId.value, ALL_TAB_ID],
|
|
327
|
+
["columnFilters", columnFilters.value, []],
|
|
328
|
+
["sorting", sorting.value, defaultSortState],
|
|
329
|
+
["pagination", paginationState.value, DEFAULT_PAGINATION],
|
|
330
|
+
["paginationScope", undefined, undefined],
|
|
331
|
+
],
|
|
332
|
+
},
|
|
333
|
+
);
|
|
334
|
+
onMounted(() => void tablePreferences.settleArrival());
|
|
258
335
|
const { sendComponentEvent } = useComponentEvent(componentId);
|
|
259
336
|
const { processI18n } = useTranslation();
|
|
260
337
|
|
|
@@ -394,8 +471,6 @@ const resolvedChrome = resolveTableChrome(props.layout, {
|
|
|
394
471
|
});
|
|
395
472
|
const GLOBAL_FILTER_DEBOUNCE_MS = 400;
|
|
396
473
|
|
|
397
|
-
const route = useDmsRoute();
|
|
398
|
-
|
|
399
474
|
const DEFAULT_FILTER_MODE = "is";
|
|
400
475
|
|
|
401
476
|
const queryParamHiddenFilters = computed<TableFilter[]>(() => {
|
|
@@ -511,12 +586,16 @@ const defaultSortKind = tableDefaultSort
|
|
|
511
586
|
?.type?.id,
|
|
512
587
|
)
|
|
513
588
|
: undefined;
|
|
589
|
+
// A hand-ordered table has no sort to pick: a sort saved before it was
|
|
590
|
+
// ordered by hand is not read back.
|
|
514
591
|
const sorting = ref<SortingState>(
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
592
|
+
reorderConfig
|
|
593
|
+
? defaultSortState
|
|
594
|
+
: sortingOrDefault(
|
|
595
|
+
tablePreferences.get<SortingState>("sorting", defaultSortState),
|
|
596
|
+
declaredSortableIds,
|
|
597
|
+
defaultSortState,
|
|
598
|
+
),
|
|
520
599
|
);
|
|
521
600
|
|
|
522
601
|
const savedFilters = tablePreferences.get<TableFilter[]>("columnFilters", []);
|
|
@@ -538,6 +617,16 @@ const manualFilters = savedFilters
|
|
|
538
617
|
.filter((f) => !pinnedKeys.has(f.accessorKey))
|
|
539
618
|
.map((f) => ({ ...f, pinned: false }));
|
|
540
619
|
const initialFilters = [...buildPinnedFilters(), ...manualFilters];
|
|
620
|
+
// The pinned filters at their declared value: what a view leaves out of them.
|
|
621
|
+
const pinnedDefaultFilters: TableFilter[] = (defaultFilters || []).map(
|
|
622
|
+
(filter) => ({
|
|
623
|
+
accessorKey: filter.accessorKey,
|
|
624
|
+
mode: filter.mode,
|
|
625
|
+
value: filter.value,
|
|
626
|
+
pinned: true,
|
|
627
|
+
initialValue: filter.value,
|
|
628
|
+
}),
|
|
629
|
+
);
|
|
541
630
|
|
|
542
631
|
const columnFilters = ref<TableFilter[]>(initialFilters);
|
|
543
632
|
const columnVisibility = ref<VisibilityState>(
|
|
@@ -559,18 +648,21 @@ const globalFilterDebounced = refDebounced(
|
|
|
559
648
|
);
|
|
560
649
|
const showArchived = ref(false);
|
|
561
650
|
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
651
|
+
// The display the table counts as its default: the phone's `mobileDisplay`
|
|
652
|
+
// once applied (see `useMobileDisplay` below).
|
|
653
|
+
const displayDefault = ref(
|
|
654
|
+
offeredDisplayIds.has(defaultDisplay) ? defaultDisplay : fallbackDisplayId,
|
|
655
|
+
);
|
|
566
656
|
|
|
567
657
|
// Views: named states of the whole table, the module's and the user's own.
|
|
568
658
|
const {
|
|
569
659
|
items: tableViewItems,
|
|
570
660
|
activeViewId,
|
|
661
|
+
activeView,
|
|
571
662
|
isModified: isViewModified,
|
|
572
663
|
canSaveViews,
|
|
573
|
-
|
|
664
|
+
selectView,
|
|
665
|
+
openLinkedView,
|
|
574
666
|
resetView,
|
|
575
667
|
saveView,
|
|
576
668
|
saveAsNewView,
|
|
@@ -578,21 +670,16 @@ const {
|
|
|
578
670
|
} = useTableViews({
|
|
579
671
|
views: props.views,
|
|
580
672
|
defaults: {
|
|
581
|
-
pinnedFilters:
|
|
582
|
-
accessorKey: filter.accessorKey,
|
|
583
|
-
mode: filter.mode,
|
|
584
|
-
value: filter.value,
|
|
585
|
-
pinned: true,
|
|
586
|
-
initialValue: filter.value,
|
|
587
|
-
})),
|
|
673
|
+
pinnedFilters: pinnedDefaultFilters,
|
|
588
674
|
sorting: defaultSortState,
|
|
589
675
|
visibility: initialVisibility,
|
|
590
676
|
columnOrder: listableColumns.map(
|
|
591
677
|
(column) => column.id ?? column.accessorKey,
|
|
592
678
|
),
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
679
|
+
// Read when a view opens: a phone's `mobileDisplay` once applied.
|
|
680
|
+
get display() {
|
|
681
|
+
return displayDefault.value;
|
|
682
|
+
},
|
|
596
683
|
density: props.density ?? DEFAULT_DENSITY,
|
|
597
684
|
displays: offeredDisplayIds,
|
|
598
685
|
},
|
|
@@ -610,9 +697,22 @@ const {
|
|
|
610
697
|
urlScope,
|
|
611
698
|
});
|
|
612
699
|
|
|
613
|
-
|
|
700
|
+
// A phone opens on the table's `mobileDisplay` (cards rather than a grid cut
|
|
701
|
+
// after its first columns) unless a display was chosen: saved, fixed by the
|
|
702
|
+
// open view, or the only way in.
|
|
703
|
+
useMobileDisplay({
|
|
704
|
+
mobileDisplay: props.mobileDisplay,
|
|
705
|
+
defaultDisplay: displayDefault,
|
|
706
|
+
offered: offeredDisplayIds,
|
|
707
|
+
display: activeDisplayId,
|
|
708
|
+
activeView,
|
|
709
|
+
isDisplayChosen: () =>
|
|
710
|
+
isDefaultDisplayStandalone ||
|
|
711
|
+
tablePreferences.get<string | undefined>("viewMode", undefined) !==
|
|
712
|
+
undefined,
|
|
713
|
+
});
|
|
614
714
|
|
|
615
|
-
const { t, te } = useI18n();
|
|
715
|
+
const { t, te, locale } = useI18n();
|
|
616
716
|
|
|
617
717
|
// A tab named by the URL wins over the one kept from the last visit.
|
|
618
718
|
const activeTabId = ref<string>(
|
|
@@ -668,12 +768,33 @@ const activeTabFilters = computed<TableFilter[]>(() => {
|
|
|
668
768
|
return tab?.filters || [];
|
|
669
769
|
});
|
|
670
770
|
|
|
771
|
+
const isOpenableTab = (tabId: string) =>
|
|
772
|
+
resolvedTabs.value.some((tab) => !tab.to && tab.id === tabId);
|
|
773
|
+
|
|
671
774
|
useTableUrlTab({
|
|
672
775
|
route,
|
|
673
776
|
urlScope,
|
|
674
777
|
activeTabId,
|
|
675
|
-
isOpenable:
|
|
676
|
-
|
|
778
|
+
isOpenable: isOpenableTab,
|
|
779
|
+
});
|
|
780
|
+
|
|
781
|
+
// A link to this page while it is shown opens like a linked arrival: on the
|
|
782
|
+
// table's defaults plus what it names, leaving the kept state as it was.
|
|
783
|
+
useTableLinkedVisit({
|
|
784
|
+
route,
|
|
785
|
+
urlScope,
|
|
786
|
+
queryParamFilters,
|
|
787
|
+
activeView: () => activeViewId.value,
|
|
788
|
+
activeTab: () => activeTabId.value,
|
|
789
|
+
canOpenView: (id) => tableViewItems.value.some((view) => view.id === id),
|
|
790
|
+
canOpenTab: isOpenableTab,
|
|
791
|
+
follow: (query) => {
|
|
792
|
+
void tablePreferences.followLink(() => {
|
|
793
|
+
openLinkedView(query);
|
|
794
|
+
const tab = readTableUrlTab(query, urlScope);
|
|
795
|
+
activeTabId.value = tab && isOpenableTab(tab) ? tab : ALL_TAB_ID;
|
|
796
|
+
});
|
|
797
|
+
},
|
|
677
798
|
});
|
|
678
799
|
|
|
679
800
|
watch(resolvedTabs, (next) => {
|
|
@@ -700,6 +821,7 @@ const tableRows = useTableRows<T>({
|
|
|
700
821
|
// Quick filters: dropdowns of the toolbar over a column's values (a select's
|
|
701
822
|
// items, a boolean, the rows a relation points to), writing that column's
|
|
702
823
|
// filter like the filters row does.
|
|
824
|
+
const { getDataType } = useDataTypes();
|
|
703
825
|
const relationQuickFilterValues = ref<Record<string, QuickFilterItem[]>>({});
|
|
704
826
|
// Relation values load after mount: until then their buttons hold their place.
|
|
705
827
|
const relationQuickFiltersLoaded = ref(false);
|
|
@@ -712,7 +834,7 @@ const quickFilterDefinitions = (props.quickFilters ?? []).map((filter) => {
|
|
|
712
834
|
column,
|
|
713
835
|
mode: quickFilterMode(column, filter.mode),
|
|
714
836
|
items: staticQuickFilterItems(column, processI18n),
|
|
715
|
-
source: relationQuickFilterSource(column),
|
|
837
|
+
source: relationQuickFilterSource(column, getDataType),
|
|
716
838
|
};
|
|
717
839
|
});
|
|
718
840
|
|
|
@@ -726,7 +848,9 @@ const loadRelationQuickFilters = async () => {
|
|
|
726
848
|
try {
|
|
727
849
|
const response = await $authFetch<
|
|
728
850
|
TableViewListResponse<Record<string, unknown>>
|
|
729
|
-
>(source!.
|
|
851
|
+
>(source!.searchUrl, {
|
|
852
|
+
query: { limit: RELATION_QUICK_FILTER_LIMIT },
|
|
853
|
+
});
|
|
730
854
|
relationQuickFilterValues.value = {
|
|
731
855
|
...relationQuickFilterValues.value,
|
|
732
856
|
[filter.field]: relationQuickFilterItems(response.results, source!),
|
|
@@ -800,17 +924,22 @@ const effectiveGlobalFilter = computed(() =>
|
|
|
800
924
|
const isGroupedDisplay = computed(
|
|
801
925
|
() => activeDisplayId.value === GROUPED_DISPLAY_ID && !!groupedOptions,
|
|
802
926
|
);
|
|
927
|
+
const sortingInput = computed<TableSortingInput>(() => ({
|
|
928
|
+
reorderField: reorderConfig?.field,
|
|
929
|
+
grouped: isGroupedDisplay.value ? activeGroupedOptions.value : undefined,
|
|
930
|
+
canSort: activeCapabilities.value.sorting,
|
|
931
|
+
sorting: sorting.value,
|
|
932
|
+
defaultSorting: defaultSortState,
|
|
933
|
+
}));
|
|
934
|
+
// The order the rows are wanted in; the grouped display lists them on the
|
|
935
|
+
// grouped column and orders each group by it (`shownResults`).
|
|
936
|
+
const pickedSorting = computed(() => pickedTableSorting(sortingInput.value));
|
|
803
937
|
const effectiveSorting = computed<SortingState>(() => {
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
isGroupedDisplay.value && activeGroupedOptions.value
|
|
810
|
-
? groupedSorting(picked, activeGroupedOptions.value)
|
|
811
|
-
: picked,
|
|
812
|
-
sortableIds.value,
|
|
813
|
-
);
|
|
938
|
+
const listed = listTableSorting(sortingInput.value);
|
|
939
|
+
// The hand order is kept whole: its field need not be a sortable column.
|
|
940
|
+
return reorderConfig && !sortingInput.value.grouped
|
|
941
|
+
? listed
|
|
942
|
+
: sanitizeSorting(listed, sortableIds.value);
|
|
814
943
|
});
|
|
815
944
|
|
|
816
945
|
// A feed grows by pages (`loadMore`, `infinite`) rather than paging.
|
|
@@ -852,6 +981,7 @@ const openRowId = computed(() =>
|
|
|
852
981
|
|
|
853
982
|
// The gate is set up with the other refresh triggers below; the hold only
|
|
854
983
|
// reads it once the table is on screen.
|
|
984
|
+
const NEW_ROWS_COUNT_ID = "liveHold:new";
|
|
855
985
|
const tableRoot = useTemplateRef<ComponentPublicInstance>("tableRoot");
|
|
856
986
|
const liveHold = useTableLiveHold({
|
|
857
987
|
liveHold: props.liveHold,
|
|
@@ -863,6 +993,32 @@ const liveHold = useTableLiveHold({
|
|
|
863
993
|
isSorted: () => !isSameSorting(effectiveSorting.value, defaultSortState),
|
|
864
994
|
tableElement: () => tableRoot.value?.$el ?? null,
|
|
865
995
|
},
|
|
996
|
+
// The pill counts the rows the table would list, on its own count route:
|
|
997
|
+
// the rows its tab, search and filters match now, less those it holds.
|
|
998
|
+
newRows: {
|
|
999
|
+
heldList: () => data.value,
|
|
1000
|
+
countNow: async (signal) => {
|
|
1001
|
+
const counts = await tableRows.countBatch(
|
|
1002
|
+
[
|
|
1003
|
+
{
|
|
1004
|
+
id: NEW_ROWS_COUNT_ID,
|
|
1005
|
+
query: {
|
|
1006
|
+
...buildTableQuery({
|
|
1007
|
+
pagination: { pageIndex: 0, pageSize: 0 },
|
|
1008
|
+
sorting: [],
|
|
1009
|
+
columnFilters: effectiveColumnFilters.value,
|
|
1010
|
+
hiddenFilters: hiddenFilters.value,
|
|
1011
|
+
globalFilter: effectiveGlobalFilter.value,
|
|
1012
|
+
}),
|
|
1013
|
+
...archiveQuery.value,
|
|
1014
|
+
},
|
|
1015
|
+
},
|
|
1016
|
+
],
|
|
1017
|
+
signal,
|
|
1018
|
+
);
|
|
1019
|
+
return counts[NEW_ROWS_COUNT_ID];
|
|
1020
|
+
},
|
|
1021
|
+
},
|
|
866
1022
|
});
|
|
867
1023
|
|
|
868
1024
|
// The list, its counters and its footer figures load in parallel: a server
|
|
@@ -911,6 +1067,11 @@ const listLoadError = computed(() => {
|
|
|
911
1067
|
: "error.500";
|
|
912
1068
|
});
|
|
913
1069
|
|
|
1070
|
+
// A list answering 404 names a resource that does not exist (the workspace
|
|
1071
|
+
// its rows belong to was deleted): no retry fixes it, so the table gives way
|
|
1072
|
+
// to the not-found state blocks show, with what the 404 said.
|
|
1073
|
+
const listNotFound = computed(() => readFetchNotFound(settledError.value));
|
|
1074
|
+
|
|
914
1075
|
// useDmsAsyncData keeps the previous result when a refetch fails, so rows kept
|
|
915
1076
|
// on screen would masquerade as the newly requested page/filter. Hide them
|
|
916
1077
|
// while the latest query is in error; the error panel takes their place.
|
|
@@ -919,7 +1080,13 @@ const listLoadError = computed(() => {
|
|
|
919
1080
|
const shownData = computed(() =>
|
|
920
1081
|
listLoadError.value ? undefined : data.value,
|
|
921
1082
|
);
|
|
922
|
-
const shownResults = computed(() =>
|
|
1083
|
+
const shownResults = computed(() => {
|
|
1084
|
+
const results = shownData.value?.results;
|
|
1085
|
+
const grouped = activeGroupedOptions.value;
|
|
1086
|
+
return results && isGroupedDisplay.value && grouped
|
|
1087
|
+
? orderGroupedRows(results, grouped, pickedSorting.value, locale.value)
|
|
1088
|
+
: results;
|
|
1089
|
+
});
|
|
923
1090
|
|
|
924
1091
|
// Rows selected before the failure can no longer be seen or verified, yet the
|
|
925
1092
|
// selection toolbar would keep offering delete/archive/export on them.
|
|
@@ -1003,28 +1170,46 @@ watch(
|
|
|
1003
1170
|
},
|
|
1004
1171
|
);
|
|
1005
1172
|
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
buildTableQuery({
|
|
1010
|
-
pagination: { pageIndex: 0, pageSize: 0 },
|
|
1011
|
-
sorting: [],
|
|
1012
|
-
columnFilters: filters,
|
|
1013
|
-
hiddenFilters: queryParamHiddenFilters.value,
|
|
1014
|
-
globalFilter: search,
|
|
1015
|
-
});
|
|
1016
|
-
|
|
1017
|
-
const tabCountsQuery = computed(() => [
|
|
1018
|
-
...resolvedTabs.value
|
|
1019
|
-
.filter((tab) => !tab.to)
|
|
1020
|
-
.map((tab) => ({ id: tab.id, query: countQuery(tab.filters) })),
|
|
1021
|
-
...tableViewItems.value
|
|
1022
|
-
.filter((view) => view.count)
|
|
1023
|
-
.map((view) => ({
|
|
1024
|
-
id: `${VIEW_COUNT_ID_PREFIX}${view.id}`,
|
|
1025
|
-
query: countQuery(view.filters ?? [], view.search),
|
|
1026
|
-
})),
|
|
1173
|
+
const scopeFilters = computed<TableFilter[]>(() => [
|
|
1174
|
+
...queryParamHiddenFilters.value,
|
|
1175
|
+
...routeParamHiddenFilters.value,
|
|
1027
1176
|
]);
|
|
1177
|
+
const countState = computed<TableCountState>(() => ({
|
|
1178
|
+
scopeFilters: scopeFilters.value,
|
|
1179
|
+
tabFilters: activeTabFilters.value,
|
|
1180
|
+
columnFilters: effectiveColumnFilters.value,
|
|
1181
|
+
search: effectiveGlobalFilter.value,
|
|
1182
|
+
}));
|
|
1183
|
+
const isCountStateNarrowed = computed(() => isCountNarrowed(countState.value));
|
|
1184
|
+
|
|
1185
|
+
// Each counter counts what a click on it would list, so the counters follow
|
|
1186
|
+
// the filters, the search, the view and the tab: picks made in a row (quick
|
|
1187
|
+
// filters toggled one after the other) are counted once, when they settle.
|
|
1188
|
+
const COUNTS_DEBOUNCE_MS = 200;
|
|
1189
|
+
const debouncedCountsQuery = refDebounced(
|
|
1190
|
+
computed(() =>
|
|
1191
|
+
buildTableCountQueries({
|
|
1192
|
+
...countState.value,
|
|
1193
|
+
tabs: resolvedTabs.value
|
|
1194
|
+
.filter((tab) => !tab.to)
|
|
1195
|
+
.map((tab) => ({
|
|
1196
|
+
id: tab.id,
|
|
1197
|
+
filters: tab.filters,
|
|
1198
|
+
hasNavBadge: !!tab.navBadge,
|
|
1199
|
+
})),
|
|
1200
|
+
views: tableViewItems.value
|
|
1201
|
+
.filter((view) => view.count)
|
|
1202
|
+
.map((view) => ({
|
|
1203
|
+
id: view.id,
|
|
1204
|
+
filters: viewFilters(view, pinnedDefaultFilters),
|
|
1205
|
+
search: view.search,
|
|
1206
|
+
})),
|
|
1207
|
+
activeViewId: activeViewId.value,
|
|
1208
|
+
}),
|
|
1209
|
+
),
|
|
1210
|
+
COUNTS_DEBOUNCE_MS,
|
|
1211
|
+
);
|
|
1212
|
+
const tabCountsQuery = computed(() => debouncedCountsQuery.value);
|
|
1028
1213
|
|
|
1029
1214
|
// No default: `null` until the counts arrive, so the tabs draw placeholders
|
|
1030
1215
|
// instead of a count of nothing.
|
|
@@ -1095,6 +1280,83 @@ const hasMoreRows = computed(
|
|
|
1095
1280
|
const loadMoreRows = () => {
|
|
1096
1281
|
if (hasMoreRows.value && !isListLoading.value) loadNextPage();
|
|
1097
1282
|
};
|
|
1283
|
+
// A row's drawer or side panel steps through every row the table lists: past
|
|
1284
|
+
// the rows loaded, it turns the table's page (or grows its feed) and steps
|
|
1285
|
+
// onto the rows that arrive. A display reading its own rows keeps to them.
|
|
1286
|
+
const ADJACENT_ROWS_TIMEOUT_MS = 15_000;
|
|
1287
|
+
const listsServerPages = computed(() => !isActiveDisplaySelfManaged.value);
|
|
1288
|
+
// What a display reading its own rows shows (`setShownRows`), in its order:
|
|
1289
|
+
// the rows its row's container steps through. Another display, another set.
|
|
1290
|
+
const selfManagedRows = shallowRef<Data[]>([]);
|
|
1291
|
+
const setSelfManagedRows = (rows: T[]) => {
|
|
1292
|
+
selfManagedRows.value = rows as Data[];
|
|
1293
|
+
};
|
|
1294
|
+
watch(activeDisplayId, () => {
|
|
1295
|
+
selfManagedRows.value = [];
|
|
1296
|
+
});
|
|
1297
|
+
const navigableRows = (): Data[] =>
|
|
1298
|
+
listsServerPages.value
|
|
1299
|
+
? ((shownResults.value ?? []) as Data[])
|
|
1300
|
+
: selfManagedRows.value;
|
|
1301
|
+
const loadedRowsOffset = () => {
|
|
1302
|
+
if (isAccumulating || !listsServerPages.value) return 0;
|
|
1303
|
+
const { pageIndex, pageSize } = paginationState.value;
|
|
1304
|
+
return pageSize > 0 ? pageIndex * pageSize : 0;
|
|
1305
|
+
};
|
|
1306
|
+
const turnPage = (step: RowStep): boolean => {
|
|
1307
|
+
if (isAccumulating) {
|
|
1308
|
+
if (step < 0 || !hasMoreRows.value) return false;
|
|
1309
|
+
loadNextPage();
|
|
1310
|
+
return true;
|
|
1311
|
+
}
|
|
1312
|
+
const { pageIndex, pageSize } = paginationState.value;
|
|
1313
|
+
const next = pageIndex + step;
|
|
1314
|
+
const total = data.value?.total ?? 0;
|
|
1315
|
+
if (pageSize <= 0 || next < 0 || next * pageSize >= total) return false;
|
|
1316
|
+
paginationState.value = { ...paginationState.value, pageIndex: next };
|
|
1317
|
+
return true;
|
|
1318
|
+
};
|
|
1319
|
+
let adjacentRowsLoad: Promise<boolean> | undefined;
|
|
1320
|
+
const loadAdjacentRows = (step: RowStep): Promise<boolean> => {
|
|
1321
|
+
// A second J while the page loads waits for the same page.
|
|
1322
|
+
if (adjacentRowsLoad) return adjacentRowsLoad;
|
|
1323
|
+
if (!listsServerPages.value || isListLoading.value || !turnPage(step)) {
|
|
1324
|
+
return Promise.resolve(false);
|
|
1325
|
+
}
|
|
1326
|
+
const before = shownResults.value;
|
|
1327
|
+
adjacentRowsLoad = until(
|
|
1328
|
+
() => shownResults.value !== before && !isListLoading.value,
|
|
1329
|
+
)
|
|
1330
|
+
.toBe(true, { timeout: ADJACENT_ROWS_TIMEOUT_MS })
|
|
1331
|
+
.then(() => !listLoadError.value && shownResults.value !== before)
|
|
1332
|
+
.finally(() => {
|
|
1333
|
+
adjacentRowsLoad = undefined;
|
|
1334
|
+
});
|
|
1335
|
+
return adjacentRowsLoad;
|
|
1336
|
+
};
|
|
1337
|
+
// A row past the rows loaded (a deep link, a row live rows pushed out) is
|
|
1338
|
+
// found in the table's whole result, under the query the list reads: its
|
|
1339
|
+
// position, and its neighbours for the steps. Its rows read in the order
|
|
1340
|
+
// the table shows them: pinned rows lead each page it reads, not the result.
|
|
1341
|
+
const locateRow = rowLocator({
|
|
1342
|
+
list: async (offset, limit) => {
|
|
1343
|
+
if (!listsServerPages.value) return null;
|
|
1344
|
+
const page = await tableRows.listAsShown(
|
|
1345
|
+
{
|
|
1346
|
+
...queryRequest.value,
|
|
1347
|
+
...archiveQuery.value,
|
|
1348
|
+
...liveHold.heldQuery(),
|
|
1349
|
+
offset,
|
|
1350
|
+
limit,
|
|
1351
|
+
},
|
|
1352
|
+
requestedPagination.value.pageSize,
|
|
1353
|
+
);
|
|
1354
|
+
return page && { results: page.results as Data[], total: page.total };
|
|
1355
|
+
},
|
|
1356
|
+
rowIdKey: props.rowIdKey ?? ROW_ID_DEFAULT_KEY,
|
|
1357
|
+
isWholeRead: () => !!props.source && !props.source.capabilities.paginate,
|
|
1358
|
+
});
|
|
1359
|
+
|
|
1098
1360
|
const accumulation = computed<TableAccumulation | undefined>(() =>
|
|
1099
1361
|
isAccumulating
|
|
1100
1362
|
? {
|
|
@@ -1130,7 +1392,7 @@ const { reorderState } = useTableReorder<T>({
|
|
|
1130
1392
|
onError: (failure) =>
|
|
1131
1393
|
toast.add({
|
|
1132
1394
|
title: t("dms.table.reorder.error"),
|
|
1133
|
-
description:
|
|
1395
|
+
description: describeTableWriteError(failure, t, allColumns, processI18n),
|
|
1134
1396
|
color: Color.error,
|
|
1135
1397
|
icon: "i-ph-warning-circle",
|
|
1136
1398
|
}),
|
|
@@ -1160,6 +1422,7 @@ provide(KANBAN_DISPLAY_BRIDGE_KEY, {
|
|
|
1160
1422
|
groupByField: kanbanGroupBy,
|
|
1161
1423
|
editAction: tableProps.value.rowActions?.edit,
|
|
1162
1424
|
deleteAction: tableProps.value.rowActions?.delete,
|
|
1425
|
+
onCardMoved: () => void refreshCounts(),
|
|
1163
1426
|
});
|
|
1164
1427
|
|
|
1165
1428
|
// A link tab counts the rows of the list it opens; a list the caller may not
|
|
@@ -1198,14 +1461,19 @@ const refreshLinkTabCounts = async () => {
|
|
|
1198
1461
|
// event) or a refresh: what summarises them elsewhere (a navigation count)
|
|
1199
1462
|
// is told to read its figure again.
|
|
1200
1463
|
const { notifyTableDataChanged } = useTableDataChanges();
|
|
1201
|
-
const
|
|
1464
|
+
const refreshCounts = async () => {
|
|
1202
1465
|
notifyTableDataChanged(location);
|
|
1203
1466
|
await Promise.all([
|
|
1204
|
-
refresh(),
|
|
1205
1467
|
refreshTabCounts(),
|
|
1206
1468
|
refreshLinkTabCounts(),
|
|
1207
1469
|
refreshGroupCounts(),
|
|
1208
1470
|
refreshSummaries(),
|
|
1471
|
+
]);
|
|
1472
|
+
};
|
|
1473
|
+
const refreshAll = async () => {
|
|
1474
|
+
await Promise.all([
|
|
1475
|
+
refresh(),
|
|
1476
|
+
refreshCounts(),
|
|
1209
1477
|
activeDisplayRef.value?.refresh?.(),
|
|
1210
1478
|
]);
|
|
1211
1479
|
};
|
|
@@ -1222,6 +1490,11 @@ const refreshByUser = () => {
|
|
|
1222
1490
|
liveGate.acknowledge();
|
|
1223
1491
|
return refreshAll();
|
|
1224
1492
|
};
|
|
1493
|
+
// A write of the user's (a row or bulk action, a form saved) can move what
|
|
1494
|
+
// the rest of the page shows of the same records — a KPI, a tab's badge,
|
|
1495
|
+
// another list: every block of the page reads its data again, this table
|
|
1496
|
+
// among them, at once even on a paused live page.
|
|
1497
|
+
const refreshAfterWrite = () => refreshPageBlocks();
|
|
1225
1498
|
|
|
1226
1499
|
// "Preview as role": a link tab to a page the previewed role could not open
|
|
1227
1500
|
// is drawn locked, one to a page it opens partially is drawn partially
|
|
@@ -1259,19 +1532,27 @@ const tabsWithCount = computed(() =>
|
|
|
1259
1532
|
|
|
1260
1533
|
// A tab declared with `navBadge` keeps the navigation badge the server
|
|
1261
1534
|
// counted for the page it stands for (the linked page, or this one) up to
|
|
1262
|
-
// date with
|
|
1535
|
+
// date: with the tab's own counter while nothing narrows it, else with a
|
|
1536
|
+
// count of the tab alone, since the badge stands for the whole page. An
|
|
1537
|
+
// empty badge stands for zero.
|
|
1263
1538
|
const { setNavBadge } = useNavBadges();
|
|
1539
|
+
const tabNavBadgeCount = (tab: ResolvedTab, count: number | undefined) =>
|
|
1540
|
+
tab.to
|
|
1541
|
+
? count
|
|
1542
|
+
: navBadgeCount(tabCountsData.value, tab.id, isCountStateNarrowed.value);
|
|
1264
1543
|
watch(
|
|
1265
1544
|
tabsWithCount,
|
|
1266
1545
|
(next) => {
|
|
1267
1546
|
for (const tab of next) {
|
|
1268
1547
|
const source = resolvedTabs.value.find((entry) => entry.id === tab.id);
|
|
1269
|
-
if (!source?.navBadge
|
|
1548
|
+
if (!source?.navBadge) continue;
|
|
1549
|
+
const count = tabNavBadgeCount(source, tab.count);
|
|
1550
|
+
if (count === undefined) continue;
|
|
1270
1551
|
const fullId = source.to ? source.toPage : pageId;
|
|
1271
1552
|
const tone =
|
|
1272
1553
|
typeof source.navBadge === "object" ? source.navBadge.tone : undefined;
|
|
1273
1554
|
if (fullId) {
|
|
1274
|
-
setNavBadge(fullId,
|
|
1555
|
+
setNavBadge(fullId, count > 0 ? String(count) : "", tone);
|
|
1275
1556
|
}
|
|
1276
1557
|
}
|
|
1277
1558
|
},
|
|
@@ -1296,10 +1577,11 @@ const {
|
|
|
1296
1577
|
} = useTableRowActions<T>({
|
|
1297
1578
|
api: $authFetch,
|
|
1298
1579
|
location,
|
|
1580
|
+
columns: allColumns,
|
|
1299
1581
|
caption,
|
|
1300
1582
|
labelKey,
|
|
1301
1583
|
rowIdKey: props.rowIdKey,
|
|
1302
|
-
refreshCallback:
|
|
1584
|
+
refreshCallback: refreshAfterWrite,
|
|
1303
1585
|
formComponents,
|
|
1304
1586
|
formContainer,
|
|
1305
1587
|
formPages,
|
|
@@ -1308,9 +1590,16 @@ const {
|
|
|
1308
1590
|
pageId: pageId!,
|
|
1309
1591
|
queryParamFilters,
|
|
1310
1592
|
rowNavigation: {
|
|
1311
|
-
rows:
|
|
1593
|
+
rows: navigableRows,
|
|
1312
1594
|
rowIdKey: props.rowIdKey ?? ROW_ID_DEFAULT_KEY,
|
|
1313
1595
|
getRow: (id) => tableRows.getRow(id) as Promise<Data | undefined>,
|
|
1596
|
+
total: () =>
|
|
1597
|
+
listsServerPages.value
|
|
1598
|
+
? (shownData.value?.total ?? undefined)
|
|
1599
|
+
: undefined,
|
|
1600
|
+
offset: loadedRowsOffset,
|
|
1601
|
+
loadAdjacent: loadAdjacentRows,
|
|
1602
|
+
locate: locateRow,
|
|
1314
1603
|
},
|
|
1315
1604
|
recordScope: urlScope,
|
|
1316
1605
|
onRecordShown: (id) => recordLink?.shown(id),
|
|
@@ -1382,12 +1671,14 @@ const deselectRows = (ids: string[]) => {
|
|
|
1382
1671
|
};
|
|
1383
1672
|
|
|
1384
1673
|
// From the archive, a delete is a permanent one: its confirmation says so.
|
|
1385
|
-
|
|
1674
|
+
// A display holding the rows (a kanban card) hands them for its wording.
|
|
1675
|
+
const deleteRows = async (ids: string[], rows?: T[]) => {
|
|
1386
1676
|
const done = await deleteRowsAction(
|
|
1387
1677
|
ids,
|
|
1388
1678
|
tableProps.value.rowActions?.delete,
|
|
1389
1679
|
{
|
|
1390
1680
|
permanently: !!archiveMode && showArchived.value,
|
|
1681
|
+
rows,
|
|
1391
1682
|
},
|
|
1392
1683
|
);
|
|
1393
1684
|
if (done) deselectRows(ids);
|
|
@@ -1414,12 +1705,18 @@ const rowActionConfig = (key: "details" | "duplicate" | "add" | "edit") =>
|
|
|
1414
1705
|
tableProps.value.rowActions?.[key];
|
|
1415
1706
|
const handleRowClick = (item: T) =>
|
|
1416
1707
|
runConfirmedBuiltIn(rowActionConfig("details"), item, () => openRow(item));
|
|
1417
|
-
|
|
1418
|
-
|
|
1708
|
+
// Its dialog words the row shown (`{name}`), else only its id.
|
|
1709
|
+
const handleRowDuplicate = (itemId: string) => {
|
|
1710
|
+
const idKey = props.rowIdKey ?? ROW_ID_DEFAULT_KEY;
|
|
1711
|
+
const shown = shownResults.value?.find(
|
|
1712
|
+
(row) => String(get(row, idKey)) === itemId,
|
|
1713
|
+
);
|
|
1714
|
+
return runConfirmedBuiltIn(
|
|
1419
1715
|
rowActionConfig("duplicate"),
|
|
1420
|
-
{ [
|
|
1716
|
+
shown ?? { [idKey]: itemId },
|
|
1421
1717
|
() => duplicateRow(itemId),
|
|
1422
1718
|
);
|
|
1719
|
+
};
|
|
1423
1720
|
const handleRowAdd = () =>
|
|
1424
1721
|
runConfirmedBuiltIn(rowActionConfig("add"), undefined, () =>
|
|
1425
1722
|
newRow(queryParamDefaults.value),
|
|
@@ -1484,12 +1781,14 @@ const realtimeEventHandlers: Record<
|
|
|
1484
1781
|
return refreshAll();
|
|
1485
1782
|
},
|
|
1486
1783
|
[REALTIME_EVENT_TYPE.CREATED]: () => refreshAll(),
|
|
1784
|
+
// An edited row can change tab, group or column: the counts are read again
|
|
1785
|
+
// with it.
|
|
1487
1786
|
[REALTIME_EVENT_TYPE.UPDATED]: async (ids) => {
|
|
1488
1787
|
if (isActiveDisplaySelfManaged.value) {
|
|
1489
|
-
await activeDisplayRef.value?.refresh?.();
|
|
1788
|
+
await Promise.all([activeDisplayRef.value?.refresh?.(), refreshCounts()]);
|
|
1490
1789
|
return;
|
|
1491
1790
|
}
|
|
1492
|
-
await Promise.all(ids.map((id) => patchRowLocal(id)));
|
|
1791
|
+
await Promise.all([...ids.map((id) => patchRowLocal(id)), refreshCounts()]);
|
|
1493
1792
|
},
|
|
1494
1793
|
};
|
|
1495
1794
|
|
|
@@ -1636,22 +1935,20 @@ const expandedModel = computed<ExpandedState>({
|
|
|
1636
1935
|
},
|
|
1637
1936
|
});
|
|
1638
1937
|
|
|
1639
|
-
let
|
|
1938
|
+
let expandedListedKey: string | undefined;
|
|
1640
1939
|
if (expandableConfig) {
|
|
1641
1940
|
watch(
|
|
1642
1941
|
shownResults,
|
|
1643
1942
|
(rows) => {
|
|
1644
|
-
const
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
}
|
|
1649
|
-
expandedQueryKey = queryKey;
|
|
1650
|
-
expanded.value = defaultExpandedRows(
|
|
1651
|
-
rowIdsOf(rows),
|
|
1943
|
+
const next = expandedRowsOnListing(
|
|
1944
|
+
{ expanded: expanded.value, listedKey: expandedListedKey },
|
|
1945
|
+
rows ? rowIdsOf(rows) : undefined,
|
|
1946
|
+
JSON.stringify([queryRequest.value, archiveQuery.value]),
|
|
1652
1947
|
expandableConfig.defaultExpanded,
|
|
1653
1948
|
expandableConfig.single,
|
|
1654
1949
|
);
|
|
1950
|
+
expandedListedKey = next.listedKey;
|
|
1951
|
+
expanded.value = next.expanded;
|
|
1655
1952
|
},
|
|
1656
1953
|
{ immediate: true },
|
|
1657
1954
|
);
|
|
@@ -1896,6 +2193,7 @@ const displayContext = computed(
|
|
|
1896
2193
|
pageId,
|
|
1897
2194
|
options: optionsForDisplay(activeDisplayId.value),
|
|
1898
2195
|
refresh: refreshByUser,
|
|
2196
|
+
setShownRows: setSelfManagedRows,
|
|
1899
2197
|
reorder: reorderState.value,
|
|
1900
2198
|
table: displayTable.value,
|
|
1901
2199
|
}),
|
|
@@ -1993,13 +2291,16 @@ defineShortcuts(
|
|
|
1993
2291
|
);
|
|
1994
2292
|
|
|
1995
2293
|
// Each kept field with its default: a value back to it is forgotten.
|
|
2294
|
+
// A hand-ordered table keeps no sort.
|
|
1996
2295
|
const tableStatePreferences: TableStatePreference[] = [
|
|
1997
|
-
|
|
2296
|
+
...(reorderConfig
|
|
2297
|
+
? []
|
|
2298
|
+
: [["sorting", sorting, defaultSortState] as TableStatePreference]),
|
|
1998
2299
|
["columnFilters", columnFilters, []],
|
|
1999
2300
|
["columnVisibility", columnVisibility, initialVisibility],
|
|
2000
2301
|
["filtersOpen", filtersRowOpen, hasEmptyDefaultFilter],
|
|
2001
2302
|
["activeTab", activeTabId, ALL_TAB_ID],
|
|
2002
|
-
["viewMode", activeDisplayId,
|
|
2303
|
+
["viewMode", activeDisplayId, displayDefault],
|
|
2003
2304
|
["columnOrder", columnOrder, []],
|
|
2004
2305
|
["kanbanGroupBy", kanbanGroupBy, defaultKanbanGroupBy],
|
|
2005
2306
|
["groupedGroupBy", groupedGroupBy, defaultGroupedGroupBy],
|
|
@@ -2010,7 +2311,7 @@ tableStatePreferences.forEach(([field, state, defaultValue]) => {
|
|
|
2010
2311
|
watch(
|
|
2011
2312
|
state,
|
|
2012
2313
|
(newValue) => {
|
|
2013
|
-
tablePreferences.set(field, newValue, defaultValue);
|
|
2314
|
+
tablePreferences.set(field, newValue, unref(defaultValue));
|
|
2014
2315
|
},
|
|
2015
2316
|
{ deep: true },
|
|
2016
2317
|
);
|
|
@@ -2099,7 +2400,13 @@ onMounted(() => {
|
|
|
2099
2400
|
</script>
|
|
2100
2401
|
|
|
2101
2402
|
<template>
|
|
2403
|
+
<DmsBlockStatus
|
|
2404
|
+
v-if="listNotFound"
|
|
2405
|
+
state="not-found"
|
|
2406
|
+
:not-found="listNotFound"
|
|
2407
|
+
/>
|
|
2102
2408
|
<UTable
|
|
2409
|
+
v-else
|
|
2103
2410
|
ref="tableRoot"
|
|
2104
2411
|
v-bind="tableProps"
|
|
2105
2412
|
v-model:pagination="paginationState"
|
|
@@ -2132,6 +2439,7 @@ onMounted(() => {
|
|
|
2132
2439
|
:url-filters="shownUrlFilters"
|
|
2133
2440
|
:default-page-size="props.pageSize"
|
|
2134
2441
|
:archive-toggle="canToggleArchived"
|
|
2442
|
+
:archived-count-label="props.archivedCountLabel"
|
|
2135
2443
|
:displays="availableDisplays"
|
|
2136
2444
|
:active-capabilities="activeCapabilities"
|
|
2137
2445
|
:kanban-group-by-options="kanbanGroupByOptions"
|
|
@@ -2143,7 +2451,10 @@ onMounted(() => {
|
|
|
2143
2451
|
:load-error="listLoadError"
|
|
2144
2452
|
:data="shownResults || []"
|
|
2145
2453
|
:pagination-options="{ manualPagination: true, rowCount: data?.total }"
|
|
2146
|
-
:sorting-options="{
|
|
2454
|
+
:sorting-options="{
|
|
2455
|
+
manualSorting: true,
|
|
2456
|
+
enableSorting: activeCapabilities.sorting,
|
|
2457
|
+
}"
|
|
2147
2458
|
:default-sort="tableDefaultSort"
|
|
2148
2459
|
:default-sort-label="defaultSortLabel"
|
|
2149
2460
|
:default-sort-kind="defaultSortKind"
|
|
@@ -2171,10 +2482,7 @@ onMounted(() => {
|
|
|
2171
2482
|
@remove-url-filter="removeUrlFilter"
|
|
2172
2483
|
@edit="handleRowEdit"
|
|
2173
2484
|
>
|
|
2174
|
-
<template
|
|
2175
|
-
v-if="liveHold.newCount.value > 0 || liveHold.reason.value"
|
|
2176
|
-
#notice
|
|
2177
|
-
>
|
|
2485
|
+
<template v-if="liveHold.reason.value" #notice>
|
|
2178
2486
|
<LiveHoldBanner
|
|
2179
2487
|
:count="liveHold.newCount.value"
|
|
2180
2488
|
:reason="liveHold.reason.value"
|
|
@@ -2183,6 +2491,27 @@ onMounted(() => {
|
|
|
2183
2491
|
@show="liveHold.showNew"
|
|
2184
2492
|
/>
|
|
2185
2493
|
</template>
|
|
2494
|
+
<!-- What came in while the rows were read or the page paused: a pill
|
|
2495
|
+
over the first rows, under the column header band (the table sets
|
|
2496
|
+
its height; a sticky one stays put above a scrolled area, so the pill
|
|
2497
|
+
stays under it), taking no room, so the rows stay where they are.
|
|
2498
|
+
Above the pinned columns and the presence rail it overlaps. -->
|
|
2499
|
+
<template v-else-if="liveHold.newCount.value > 0" #notice>
|
|
2500
|
+
<div class="relative z-30 h-0">
|
|
2501
|
+
<div
|
|
2502
|
+
class="pointer-events-none absolute inset-x-0 top-[calc(var(--dms-table-head-height,0px)+0.5rem)] flex justify-center px-4"
|
|
2503
|
+
>
|
|
2504
|
+
<LiveHoldBanner
|
|
2505
|
+
floating
|
|
2506
|
+
class="pointer-events-auto"
|
|
2507
|
+
:count="liveHold.newCount.value"
|
|
2508
|
+
:missed-label="liveHold.missedLabel"
|
|
2509
|
+
:detail="liveHold.missedDetail.value"
|
|
2510
|
+
@show="liveHold.showNew"
|
|
2511
|
+
/>
|
|
2512
|
+
</div>
|
|
2513
|
+
</div>
|
|
2514
|
+
</template>
|
|
2186
2515
|
<template v-if="hasViews" #views>
|
|
2187
2516
|
<TableViews
|
|
2188
2517
|
:items="viewItems"
|
|
@@ -2191,7 +2520,7 @@ onMounted(() => {
|
|
|
2191
2520
|
:modified="isViewModified"
|
|
2192
2521
|
:can-save-as="canSaveViews"
|
|
2193
2522
|
:divided="tabsWithCount.length === 0"
|
|
2194
|
-
@open="
|
|
2523
|
+
@open="selectView"
|
|
2195
2524
|
@reset="resetView"
|
|
2196
2525
|
@save="saveView"
|
|
2197
2526
|
@save-as="saveAsNewView"
|