@antelopejs/dms 0.9.7 → 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 +114 -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 -45
- 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/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/frontend-vue/layers/dms-core/app/composables/period/periodRenderNow.ts +0 -42
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { readableNumberFormat } from "#dms-core/app/utils/formatter";
|
|
2
3
|
import { MONO_CHIP_CLASS } from "../../utils/monoChip";
|
|
3
4
|
import { onMounted, ref, resolveComponent, useTemplateRef } from "vue";
|
|
4
5
|
import { useResizeObserver } from "@vueuse/core";
|
|
@@ -143,7 +144,7 @@ const fadeStyle = computed(() => {
|
|
|
143
144
|
});
|
|
144
145
|
|
|
145
146
|
const { locale, t } = useI18n();
|
|
146
|
-
const countFormat = computed(() =>
|
|
147
|
+
const countFormat = computed(() => readableNumberFormat(locale.value));
|
|
147
148
|
</script>
|
|
148
149
|
|
|
149
150
|
<template>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { readableNumberFormat } from "#dms-core/app/utils/formatter";
|
|
2
3
|
import { EYEBROW_CLASS } from "../../utils/eyebrow";
|
|
3
4
|
import { tv } from "tailwind-variants";
|
|
4
5
|
import type { DmsAppConfig } from "#dms-core/shared/types/app-config";
|
|
@@ -78,7 +79,7 @@ const uiVariant = tv({
|
|
|
78
79
|
const ui = computed(() => uiVariant({ divided: props.divided }));
|
|
79
80
|
|
|
80
81
|
const { t, locale } = useI18n();
|
|
81
|
-
const countFormat = computed(() =>
|
|
82
|
+
const countFormat = computed(() => readableNumberFormat(locale.value));
|
|
82
83
|
|
|
83
84
|
const activeView = computed(() =>
|
|
84
85
|
props.items.find((view) => view.id === props.activeId),
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, watch } from "vue";
|
|
3
|
+
import { useFileReadUrls } from "../../../composables/useFileReadUrls";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The leading tile of a built-in card: the row's avatar when its title column
|
|
7
|
+
* declares one (an image value, read through the file API, or a URL), else
|
|
8
|
+
* the initials of its title.
|
|
9
|
+
*/
|
|
10
|
+
interface CardAvatarProps {
|
|
11
|
+
avatar?: { key: string } | string;
|
|
12
|
+
/** File storage the avatar's key lives in. */
|
|
13
|
+
storage?: string;
|
|
14
|
+
/** The card's title, whose initials stand in for a missing avatar. */
|
|
15
|
+
label: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const props = defineProps<CardAvatarProps>();
|
|
19
|
+
|
|
20
|
+
const INITIALS_LENGTH = 2;
|
|
21
|
+
|
|
22
|
+
const { getUrl, resolve } = useFileReadUrls(props.storage);
|
|
23
|
+
|
|
24
|
+
const avatarKey = computed(() =>
|
|
25
|
+
props.avatar && typeof props.avatar === "object" ? props.avatar.key : null,
|
|
26
|
+
);
|
|
27
|
+
watch(avatarKey, (key) => key && resolve(key), { immediate: true });
|
|
28
|
+
|
|
29
|
+
const src = computed(() => {
|
|
30
|
+
if (typeof props.avatar === "string") return props.avatar;
|
|
31
|
+
return avatarKey.value ? getUrl(avatarKey.value) : undefined;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const initials = computed(() =>
|
|
35
|
+
props.label
|
|
36
|
+
.split(/\s+/)
|
|
37
|
+
.filter(Boolean)
|
|
38
|
+
.slice(0, INITIALS_LENGTH)
|
|
39
|
+
.map((word) => word.charAt(0).toUpperCase())
|
|
40
|
+
.join(""),
|
|
41
|
+
);
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
<template>
|
|
45
|
+
<UAvatar
|
|
46
|
+
v-if="src"
|
|
47
|
+
:src="src"
|
|
48
|
+
:alt="props.label"
|
|
49
|
+
:text="initials"
|
|
50
|
+
size="sm"
|
|
51
|
+
class="size-7 shrink-0 rounded-[7px]"
|
|
52
|
+
/>
|
|
53
|
+
<span
|
|
54
|
+
v-else
|
|
55
|
+
class="bg-accented text-default grid size-7 shrink-0 place-items-center rounded-[7px] font-mono text-[10.5px] font-bold"
|
|
56
|
+
>
|
|
57
|
+
{{ initials }}
|
|
58
|
+
</span>
|
|
59
|
+
</template>
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { MAX_PAGE_SIZE } from "../../composables/table/constants";
|
|
3
|
+
import {
|
|
4
|
+
CARD_GRID_CLASS,
|
|
5
|
+
cardGridStyle,
|
|
6
|
+
} from "../../composables/table-view/utils/card";
|
|
7
|
+
|
|
2
8
|
/**
|
|
3
9
|
* Placeholder of a table view card grid while its first page loads: cards
|
|
4
10
|
* built like the cards display's (same frame, same line boxes), so nothing
|
|
@@ -11,13 +17,22 @@ interface CardGridSkeletonProps {
|
|
|
11
17
|
fields: number;
|
|
12
18
|
/** Size classes of a field label, to match the real card's line box. */
|
|
13
19
|
labelClass?: string;
|
|
20
|
+
/** The narrowest card, a CSS length: the table's `card.minWidth`. */
|
|
21
|
+
minWidth?: string;
|
|
22
|
+
/**
|
|
23
|
+
* The height of a card, a CSS length: the table's `card.skeletonHeight`,
|
|
24
|
+
* for a custom card taller than the built-in one.
|
|
25
|
+
*/
|
|
26
|
+
cardHeight?: string;
|
|
14
27
|
}
|
|
15
28
|
|
|
16
29
|
const props = withDefaults(defineProps<CardGridSkeletonProps>(), {
|
|
17
30
|
labelClass: "text-[10.5px] leading-[1.2]",
|
|
18
31
|
});
|
|
19
32
|
|
|
20
|
-
|
|
33
|
+
// A full page of cards, as for the rows of a table: the pagination footer
|
|
34
|
+
// below them stands where the loaded page puts it.
|
|
35
|
+
const MAX_CARD_COUNT = MAX_PAGE_SIZE;
|
|
21
36
|
const cardCount = computed(() =>
|
|
22
37
|
Math.max(1, Math.min(props.count, MAX_CARD_COUNT)),
|
|
23
38
|
);
|
|
@@ -28,12 +43,14 @@ const { t } = useI18n();
|
|
|
28
43
|
<template>
|
|
29
44
|
<div
|
|
30
45
|
aria-hidden="true"
|
|
31
|
-
class="
|
|
46
|
+
:class="CARD_GRID_CLASS"
|
|
47
|
+
:style="cardGridStyle(props.minWidth, cardCount)"
|
|
32
48
|
>
|
|
33
49
|
<div
|
|
34
50
|
v-for="n in cardCount"
|
|
35
51
|
:key="n"
|
|
36
52
|
class="border-default @container rounded-[10px] border bg-(--ui-bg) p-3.5 text-[12.5px]"
|
|
53
|
+
:style="props.cardHeight ? { minHeight: props.cardHeight } : undefined"
|
|
37
54
|
>
|
|
38
55
|
<div class="flex items-center gap-2.5">
|
|
39
56
|
<USkeleton
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script setup lang="ts" generic="T extends Record<string, unknown>">
|
|
2
|
+
import { computed } from "vue";
|
|
3
|
+
import { FlexRender, type Table } from "@tanstack/vue-table";
|
|
4
|
+
import { ACTIONS_COLUMN_ID } from "../../composables/table/constants";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A card's row actions: the cell of the grid's actions column for the card's
|
|
8
|
+
* row, so its buttons and its … menu offer the same actions, under the same
|
|
9
|
+
* rules and confirmations, as the row does in the grid. Nothing is drawn
|
|
10
|
+
* outside a table (no TanStack instance) or for a table with no row action.
|
|
11
|
+
*/
|
|
12
|
+
interface CardRowActionsProps {
|
|
13
|
+
table?: Table<T>;
|
|
14
|
+
rowId: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const props = defineProps<CardRowActionsProps>();
|
|
18
|
+
|
|
19
|
+
// The core model holds every listed row: the paginated one may not, when the
|
|
20
|
+
// table pages on the client.
|
|
21
|
+
const cell = computed(() =>
|
|
22
|
+
props.table
|
|
23
|
+
?.getCoreRowModel()
|
|
24
|
+
.rowsById[props.rowId]?.getAllCells()
|
|
25
|
+
.find((candidate) => candidate.column.id === ACTIONS_COLUMN_ID),
|
|
26
|
+
);
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<template>
|
|
30
|
+
<!-- Full strength: the grid fades a row's actions until it is hovered,
|
|
31
|
+
which a phone never does. -->
|
|
32
|
+
<div v-if="cell" class="flex shrink-0 [&>div]:opacity-100" @click.stop>
|
|
33
|
+
<FlexRender
|
|
34
|
+
:render="cell.column.columnDef.cell"
|
|
35
|
+
:props="cell.getContext()"
|
|
36
|
+
/>
|
|
37
|
+
</div>
|
|
38
|
+
</template>
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
<script setup lang="ts" generic="T extends Record<string, unknown>">
|
|
2
|
+
import { defineComponent, markRaw, type Component } from "vue";
|
|
2
3
|
import { get } from "@nuxt/ui/runtime/utils/index.js";
|
|
4
|
+
import type { Table } from "@tanstack/vue-table";
|
|
3
5
|
import TablePagination from "../table/Pagination.vue";
|
|
4
6
|
import TableEmpty from "../table/Empty.vue";
|
|
5
7
|
import CardGridSkeleton from "./CardGridSkeleton.vue";
|
|
8
|
+
import CardAvatar from "./CardAvatar.vue";
|
|
9
|
+
import CardRowActions from "./CardRowActions.vue";
|
|
6
10
|
import type { TableViewColumn } from "../../../composables/table-view/types/column";
|
|
7
11
|
import type {
|
|
8
12
|
TableViewCardConfig,
|
|
@@ -11,12 +15,20 @@ import type {
|
|
|
11
15
|
} from "../../../composables/table-view/types/display";
|
|
12
16
|
import {
|
|
13
17
|
buildCardProps,
|
|
18
|
+
CARD_GRID_CLASS,
|
|
19
|
+
cardAvatar,
|
|
14
20
|
cardFieldColumns,
|
|
21
|
+
cardGridStyle,
|
|
22
|
+
cardIdentity,
|
|
23
|
+
cardSubtitle,
|
|
15
24
|
} from "../../composables/table-view/utils/card";
|
|
25
|
+
import { readSubline } from "../../composables/data-types/cellHelpers";
|
|
26
|
+
import { useComposedText } from "#dms-core/app/composables/translation/useComposedText";
|
|
16
27
|
import {
|
|
17
28
|
REORDER_HANDLE_CLASS,
|
|
18
29
|
useReorderHandles,
|
|
19
30
|
} from "../../composables/table-view/useReorderHandles";
|
|
31
|
+
import { useCardFields } from "../../composables/table-view/useCardFields";
|
|
20
32
|
|
|
21
33
|
interface CardsDisplayProps {
|
|
22
34
|
context: TableViewDisplayContext<T>;
|
|
@@ -24,12 +36,9 @@ interface CardsDisplayProps {
|
|
|
24
36
|
|
|
25
37
|
const props = defineProps<CardsDisplayProps>();
|
|
26
38
|
|
|
27
|
-
const INITIALS_LENGTH = 2;
|
|
28
|
-
const EMPTY_VALUE = "—";
|
|
29
|
-
|
|
30
|
-
const { locale } = useI18n();
|
|
31
39
|
const { processI18n } = useTranslation();
|
|
32
|
-
const {
|
|
40
|
+
const { processText } = useComposedText();
|
|
41
|
+
const { renderField } = useCardFields();
|
|
33
42
|
|
|
34
43
|
const rowId = (item: T): string =>
|
|
35
44
|
String(get(item, props.context.rowIdKey) ?? "");
|
|
@@ -43,13 +52,20 @@ const titleOf = (item: T): string => {
|
|
|
43
52
|
: rowId(item);
|
|
44
53
|
};
|
|
45
54
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
55
|
+
// The subtitle and avatar the title column's identity display declares.
|
|
56
|
+
const identity = computed(() =>
|
|
57
|
+
cardIdentity(props.context.columns, props.context.labelKey),
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
// An id or an address is data: only a composed text is translated.
|
|
61
|
+
const subtitleOf = (item: T): string | undefined =>
|
|
62
|
+
readSubline(
|
|
63
|
+
cardSubtitle(item, identity.value, {
|
|
64
|
+
labelKey: props.context.labelKey,
|
|
65
|
+
rowIdKey: props.context.rowIdKey,
|
|
66
|
+
}),
|
|
67
|
+
{ processText, isStringTranslated: false },
|
|
68
|
+
)?.text;
|
|
53
69
|
|
|
54
70
|
const card = computed(
|
|
55
71
|
() =>
|
|
@@ -69,28 +85,35 @@ const fieldColumns = computed<TableViewColumn[]>(() =>
|
|
|
69
85
|
}),
|
|
70
86
|
);
|
|
71
87
|
|
|
72
|
-
// A field renders the same way a table cell does: through
|
|
73
|
-
//
|
|
74
|
-
const FieldValue = (fieldProps: { column: TableViewColumn; item: T }) =>
|
|
75
|
-
|
|
76
|
-
if (value === null || value === undefined || value === "") {
|
|
77
|
-
return h("span", { class: "text-dimmed" }, EMPTY_VALUE);
|
|
78
|
-
}
|
|
79
|
-
const options = fieldProps.column.type.inputComponent?.options as
|
|
80
|
-
| Record<string, unknown>
|
|
81
|
-
| undefined;
|
|
82
|
-
const formatter = getDataType(fieldProps.column.type.id)?.formatter;
|
|
83
|
-
const rendered = formatter
|
|
84
|
-
? formatter.default(value, locale.value, options)
|
|
85
|
-
: value;
|
|
86
|
-
if (typeof rendered === "string" || typeof rendered === "number") {
|
|
87
|
-
return h("span", { class: "truncate" }, String(rendered));
|
|
88
|
-
}
|
|
89
|
-
return rendered as ReturnType<typeof h>;
|
|
90
|
-
};
|
|
88
|
+
// A field renders the same way a table cell does: through its column's
|
|
89
|
+
// display, else its data type (status pills, links, dates…).
|
|
90
|
+
const FieldValue = (fieldProps: { column: TableViewColumn; item: T }) =>
|
|
91
|
+
renderField(fieldProps.column, fieldProps.item);
|
|
91
92
|
|
|
92
93
|
const openItem = (item: T) => props.context.actions.open(item);
|
|
93
94
|
|
|
95
|
+
// A custom card draws its row's actions where it likes, as a component: one
|
|
96
|
+
// per row, kept across renders so an open menu is not remounted shut.
|
|
97
|
+
const rowActionsComponents = new Map<string, Component>();
|
|
98
|
+
const rowActionsFor = (id: string): Component => {
|
|
99
|
+
let component = rowActionsComponents.get(id);
|
|
100
|
+
if (!component) {
|
|
101
|
+
component = markRaw(
|
|
102
|
+
defineComponent({
|
|
103
|
+
name: "CardRowActionsOf",
|
|
104
|
+
render: () =>
|
|
105
|
+
h(CardRowActions, {
|
|
106
|
+
// `h` cannot carry the display's row type to a generic component.
|
|
107
|
+
table: props.context.table as Table<Record<string, unknown>>,
|
|
108
|
+
rowId: id,
|
|
109
|
+
}),
|
|
110
|
+
}),
|
|
111
|
+
);
|
|
112
|
+
rowActionsComponents.set(id, component);
|
|
113
|
+
}
|
|
114
|
+
return component;
|
|
115
|
+
};
|
|
116
|
+
|
|
94
117
|
// A hand-ordered table (backend `reorder`): each card carries a move handle,
|
|
95
118
|
// and is where another card dragged by its handle drops.
|
|
96
119
|
const { draggedIndex, handleFor, drop, allowDrop } = useReorderHandles({
|
|
@@ -110,12 +133,14 @@ const cardReorder = (index: number): TableViewCardReorder | undefined =>
|
|
|
110
133
|
|
|
111
134
|
<template>
|
|
112
135
|
<div>
|
|
113
|
-
<!-- v2 cards display: an auto-
|
|
136
|
+
<!-- v2 cards display: an auto-fit grid inside the table card, sharing
|
|
114
137
|
its selection and its pagination footer. -->
|
|
115
138
|
<CardGridSkeleton
|
|
116
139
|
v-if="props.context.firstPageLoading"
|
|
117
140
|
:count="props.context.pagination.pageSize"
|
|
118
141
|
:fields="fieldColumns.length"
|
|
142
|
+
:min-width="card?.minWidth"
|
|
143
|
+
:card-height="card?.skeletonHeight"
|
|
119
144
|
/>
|
|
120
145
|
|
|
121
146
|
<TableEmpty
|
|
@@ -123,11 +148,15 @@ const cardReorder = (index: number): TableViewCardReorder | undefined =>
|
|
|
123
148
|
:can-add-row="props.context.actions.canAdd"
|
|
124
149
|
/>
|
|
125
150
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
151
|
+
<!-- A custom card loads lazily, and so may the components it draws (a
|
|
152
|
+
record card, a pill): the skeleton stays until every one of them is
|
|
153
|
+
there, rather than an empty grid lifting the footer for a beat. A
|
|
154
|
+
server render and a hydration draw the cards at once. -->
|
|
155
|
+
<Suspense v-else-if="cardComponent">
|
|
156
|
+
<div
|
|
157
|
+
:class="CARD_GRID_CLASS"
|
|
158
|
+
:style="cardGridStyle(card?.minWidth, props.context.items.length)"
|
|
159
|
+
>
|
|
131
160
|
<!-- A wrapper out of the grid's layout, catching the drop on the
|
|
132
161
|
card whatever its root element. -->
|
|
133
162
|
<div
|
|
@@ -143,82 +172,97 @@ const cardReorder = (index: number): TableViewCardReorder | undefined =>
|
|
|
143
172
|
...(card?.component?.options ?? {}),
|
|
144
173
|
...buildCardProps(item, props.context),
|
|
145
174
|
reorder: cardReorder(index),
|
|
175
|
+
rowActions: rowActionsFor(rowId(item)),
|
|
146
176
|
}"
|
|
147
177
|
/>
|
|
148
178
|
</div>
|
|
179
|
+
</div>
|
|
180
|
+
<template #fallback>
|
|
181
|
+
<CardGridSkeleton
|
|
182
|
+
:count="props.context.pagination.pageSize"
|
|
183
|
+
:fields="fieldColumns.length"
|
|
184
|
+
:min-width="card?.minWidth"
|
|
185
|
+
:card-height="card?.skeletonHeight"
|
|
186
|
+
/>
|
|
149
187
|
</template>
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
188
|
+
</Suspense>
|
|
189
|
+
|
|
190
|
+
<div
|
|
191
|
+
v-else
|
|
192
|
+
:class="CARD_GRID_CLASS"
|
|
193
|
+
:style="cardGridStyle(card?.minWidth, props.context.items.length)"
|
|
194
|
+
>
|
|
195
|
+
<article
|
|
196
|
+
v-for="(item, index) in props.context.items"
|
|
197
|
+
:key="rowId(item)"
|
|
198
|
+
class="group border-default hover:border-primary/35 @container cursor-pointer rounded-[10px] border bg-(--ui-bg) p-3.5 text-[12.5px] transition-colors focus-visible:outline-2 focus-visible:outline-(--dms-accent-line)"
|
|
199
|
+
:class="{
|
|
200
|
+
'border-primary ring-primary ring-1':
|
|
201
|
+
props.context.selection.isSelected(rowId(item)),
|
|
202
|
+
'opacity-50': draggedIndex === index,
|
|
203
|
+
}"
|
|
204
|
+
tabindex="0"
|
|
205
|
+
@click="openItem(item)"
|
|
206
|
+
@keydown.enter.self="openItem(item)"
|
|
207
|
+
@dragover="allowDrop"
|
|
208
|
+
@drop="drop(index)"
|
|
209
|
+
>
|
|
210
|
+
<header class="flex items-center gap-2.5">
|
|
211
|
+
<button
|
|
212
|
+
v-if="props.context.reorder"
|
|
213
|
+
v-bind="handleFor(index)"
|
|
214
|
+
:class="['-ms-1.5', REORDER_HANDLE_CLASS]"
|
|
215
|
+
>
|
|
216
|
+
<UIcon name="i-ph-dots-six-vertical" />
|
|
217
|
+
</button>
|
|
218
|
+
<CardAvatar
|
|
219
|
+
:avatar="cardAvatar(item, identity)"
|
|
220
|
+
:storage="identity.storage"
|
|
221
|
+
:label="titleOf(item)"
|
|
222
|
+
/>
|
|
223
|
+
<div class="min-w-0 flex-1">
|
|
224
|
+
<div
|
|
225
|
+
class="text-highlighted truncate text-[13px] font-semibold"
|
|
226
|
+
:title="titleOf(item)"
|
|
176
227
|
>
|
|
177
|
-
{{
|
|
178
|
-
</span>
|
|
179
|
-
<div class="min-w-0 flex-1">
|
|
180
|
-
<div
|
|
181
|
-
class="text-highlighted truncate text-[13px] font-semibold"
|
|
182
|
-
:title="titleOf(item)"
|
|
183
|
-
>
|
|
184
|
-
{{ titleOf(item) }}
|
|
185
|
-
</div>
|
|
186
|
-
<div class="text-dimmed truncate font-mono text-[11px]">
|
|
187
|
-
{{ rowId(item) }}
|
|
188
|
-
</div>
|
|
228
|
+
{{ titleOf(item) }}
|
|
189
229
|
</div>
|
|
190
|
-
<UCheckbox
|
|
191
|
-
:model-value="props.context.selection.isSelected(rowId(item))"
|
|
192
|
-
:aria-label="titleOf(item)"
|
|
193
|
-
@click.stop
|
|
194
|
-
@update:model-value="
|
|
195
|
-
props.context.selection.toggle(rowId(item), !!$event)
|
|
196
|
-
"
|
|
197
|
-
/>
|
|
198
|
-
</header>
|
|
199
|
-
|
|
200
|
-
<!-- A phone-narrow card stacks its fields: two columns would clip
|
|
201
|
-
every value. -->
|
|
202
|
-
<dl
|
|
203
|
-
class="mt-3 grid grid-cols-2 gap-x-3 gap-y-2.5 max-sm:@max-[16rem]:grid-cols-1"
|
|
204
|
-
>
|
|
205
230
|
<div
|
|
206
|
-
v-
|
|
207
|
-
|
|
208
|
-
|
|
231
|
+
v-if="subtitleOf(item)"
|
|
232
|
+
class="text-dimmed truncate font-mono text-[11px]"
|
|
233
|
+
:title="subtitleOf(item)"
|
|
209
234
|
>
|
|
210
|
-
|
|
211
|
-
as="dt"
|
|
212
|
-
truncate
|
|
213
|
-
:label="processI18n(column.header)"
|
|
214
|
-
/>
|
|
215
|
-
<dd class="text-default mt-0.5 flex min-w-0">
|
|
216
|
-
<FieldValue :column="column" :item="item" />
|
|
217
|
-
</dd>
|
|
235
|
+
{{ subtitleOf(item) }}
|
|
218
236
|
</div>
|
|
219
|
-
</
|
|
220
|
-
|
|
221
|
-
|
|
237
|
+
</div>
|
|
238
|
+
<UCheckbox
|
|
239
|
+
:model-value="props.context.selection.isSelected(rowId(item))"
|
|
240
|
+
:aria-label="titleOf(item)"
|
|
241
|
+
@click.stop
|
|
242
|
+
@update:model-value="
|
|
243
|
+
props.context.selection.toggle(rowId(item), !!$event)
|
|
244
|
+
"
|
|
245
|
+
/>
|
|
246
|
+
<CardRowActions
|
|
247
|
+
:table="props.context.table"
|
|
248
|
+
:row-id="rowId(item)"
|
|
249
|
+
class="-me-1.5"
|
|
250
|
+
/>
|
|
251
|
+
</header>
|
|
252
|
+
|
|
253
|
+
<!-- A phone-narrow card stacks its fields: two columns would clip
|
|
254
|
+
every value. -->
|
|
255
|
+
<dl
|
|
256
|
+
class="mt-3 grid grid-cols-2 gap-x-3 gap-y-2.5 max-sm:@max-[16rem]:grid-cols-1"
|
|
257
|
+
>
|
|
258
|
+
<div v-for="column in fieldColumns" :key="column.id" class="min-w-0">
|
|
259
|
+
<DmsEyebrow as="dt" truncate :label="processI18n(column.header)" />
|
|
260
|
+
<dd class="text-default mt-0.5 flex min-w-0">
|
|
261
|
+
<FieldValue :column="column" :item="item" />
|
|
262
|
+
</dd>
|
|
263
|
+
</div>
|
|
264
|
+
</dl>
|
|
265
|
+
</article>
|
|
222
266
|
</div>
|
|
223
267
|
|
|
224
268
|
<TablePagination />
|
|
@@ -11,6 +11,9 @@ import type { PageLiveNote } from "../../../types/live";
|
|
|
11
11
|
* live ("Table on hold · search active · 3 new · Show"), and followed, while
|
|
12
12
|
* the page is paused, by the breakdown a component gave the page ("12 new
|
|
13
13
|
* requests · 2 in 5xx · Show"). Show reads the rows once; the hold stays.
|
|
14
|
+
* `floating`, it is a pill laid over the first rows, under the column header band instead: what came
|
|
15
|
+
* in while the user had the rows on screen, or the page paused, says so
|
|
16
|
+
* without pushing them down.
|
|
14
17
|
*/
|
|
15
18
|
const props = withDefaults(
|
|
16
19
|
defineProps<{
|
|
@@ -22,10 +25,20 @@ const props = withDefaults(
|
|
|
22
25
|
missedLabel?: string;
|
|
23
26
|
/** The breakdown of what the paused page missed. */
|
|
24
27
|
detail?: PageLiveNote | null;
|
|
28
|
+
/** A pill over the rows, taking no room, in place of the strip. */
|
|
29
|
+
floating?: boolean;
|
|
25
30
|
}>(),
|
|
26
|
-
{ reason: null, missedLabel: undefined, detail: null },
|
|
31
|
+
{ reason: null, missedLabel: undefined, detail: null, floating: false },
|
|
27
32
|
);
|
|
28
33
|
|
|
34
|
+
// Literal class strings (Tailwind extracts them). The pill is opaque and
|
|
35
|
+
// lifted by the theme's pop shadow (deeper in dark), so the rows under it
|
|
36
|
+
// stay apart from it.
|
|
37
|
+
const STRIP_CLASS =
|
|
38
|
+
"border-b border-(--dms-info-line) bg-(--dms-info-tint) py-[7px] ps-[18px] pe-3.5 text-[13px]";
|
|
39
|
+
const PILL_CLASS =
|
|
40
|
+
"rounded-full border border-(--dms-info-line) bg-(--ui-bg) py-1 ps-2.5 pe-3.5 text-[12.5px] shadow-(--dms-shadow-pop)";
|
|
41
|
+
|
|
29
42
|
const emit = defineEmits<{ show: [] }>();
|
|
30
43
|
|
|
31
44
|
const { t } = useI18n();
|
|
@@ -55,7 +68,9 @@ const detailNote = computed(() =>
|
|
|
55
68
|
<template>
|
|
56
69
|
<div
|
|
57
70
|
role="status"
|
|
58
|
-
|
|
71
|
+
aria-live="polite"
|
|
72
|
+
class="dms-live-hold-banner text-highlighted flex items-center gap-2.5"
|
|
73
|
+
:class="props.floating ? PILL_CLASS : STRIP_CLASS"
|
|
59
74
|
>
|
|
60
75
|
<UIcon name="i-ph-pause-circle" class="text-info size-4 shrink-0" />
|
|
61
76
|
<span v-if="reasonText" class="dms-live-hold-banner__reason min-w-0">
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { ActionTarget } from "../../../composables/table-view/types/action-target";
|
|
2
2
|
import type { CustomRowAction } from "../../../types/row-action";
|
|
3
|
+
import { namesRowField } from "#dms-core/app/utils/url-interpolation";
|
|
4
|
+
import { dropRowTokens } from "../../utils/urlVariables";
|
|
3
5
|
|
|
4
6
|
/** Query flag of a bulk request covering every matching row. */
|
|
5
7
|
export const ALL_MATCHING_QUERY_KEY = "allMatching";
|
|
@@ -34,17 +36,27 @@ export function bulkSelectionQuery(
|
|
|
34
36
|
return query;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
|
-
|
|
39
|
+
const FRAGMENT_SEPARATOR = "#";
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* `url` with `query` appended, a list value as a repeated key. The URL's own
|
|
43
|
+
* query is kept as written: its tokens (`{{query.X}}`, `{{row.X}}`) are filled
|
|
44
|
+
* after, which percent-encoded braces would no longer match.
|
|
45
|
+
*/
|
|
38
46
|
export function withQuery(url: string, query: Record<string, QueryValue>) {
|
|
39
|
-
const
|
|
40
|
-
const params = new URLSearchParams(search);
|
|
47
|
+
const params = new URLSearchParams();
|
|
41
48
|
for (const [key, value] of Object.entries(query)) {
|
|
42
49
|
for (const entry of Array.isArray(value) ? value : [value]) {
|
|
43
50
|
params.append(key, entry);
|
|
44
51
|
}
|
|
45
52
|
}
|
|
46
|
-
const
|
|
47
|
-
|
|
53
|
+
const appended = params.toString();
|
|
54
|
+
if (!appended) return url;
|
|
55
|
+
const [base = "", ...fragment] = url.split(FRAGMENT_SEPARATOR);
|
|
56
|
+
const separator = !base.includes("?") ? "?" : /[?&]$/.test(base) ? "" : "&";
|
|
57
|
+
return [`${base}${separator}${appended}`, ...fragment].join(
|
|
58
|
+
FRAGMENT_SEPARATOR,
|
|
59
|
+
);
|
|
48
60
|
}
|
|
49
61
|
|
|
50
62
|
const URL_TARGET_TYPES = new Set([
|
|
@@ -55,14 +67,36 @@ const URL_TARGET_TYPES = new Set([
|
|
|
55
67
|
"exportJob",
|
|
56
68
|
]);
|
|
57
69
|
|
|
58
|
-
|
|
70
|
+
type UrlTarget = ActionTarget & { url: string };
|
|
71
|
+
|
|
72
|
+
export const isUrlTarget = (target: ActionTarget): target is UrlTarget =>
|
|
73
|
+
URL_TARGET_TYPES.has(target.type);
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* A target sending the selection along: its URL carries the query. Sent
|
|
77
|
+
* without a row, its `{{row.X}}` tokens are taken out (a `?ids={{row._id}}`
|
|
78
|
+
* pair gives way to the selection's `ids`).
|
|
79
|
+
*/
|
|
59
80
|
export function targetWithSelection(
|
|
60
81
|
target: ActionTarget,
|
|
61
82
|
query: Record<string, QueryValue>,
|
|
62
83
|
): ActionTarget {
|
|
63
|
-
if (!
|
|
64
|
-
const
|
|
65
|
-
return { ...target, url
|
|
84
|
+
if (!isUrlTarget(target)) return target;
|
|
85
|
+
const url = withQuery(dropRowTokens(target.url), query);
|
|
86
|
+
return { ...target, url } as ActionTarget;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* A bulk action's target run on one row: its URL carries that row's id as the
|
|
91
|
+
* selection bar's carries the selection's, unless it names the row itself
|
|
92
|
+
* (`{{row._id}}`), which then fills it.
|
|
93
|
+
*/
|
|
94
|
+
export function targetForRow(
|
|
95
|
+
target: ActionTarget,
|
|
96
|
+
query: Record<string, QueryValue>,
|
|
97
|
+
): ActionTarget {
|
|
98
|
+
if (!isUrlTarget(target) || namesRowField(target.url)) return target;
|
|
99
|
+
return { ...target, url: withQuery(target.url, query) } as ActionTarget;
|
|
66
100
|
}
|
|
67
101
|
|
|
68
102
|
/** Whether a custom action runs on the selection bar. */
|