@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.
Files changed (451) hide show
  1. package/CHANGELOG.md +171 -0
  2. package/README.md +1 -1
  3. package/data/module-store/catalog.json +2 -2
  4. package/dist/attachments/table-view.js +2 -2
  5. package/dist/attachments/table-view.js.map +1 -1
  6. package/dist/automation/actions.d.ts +2 -0
  7. package/dist/automation/actions.js +116 -71
  8. package/dist/automation/actions.js.map +1 -1
  9. package/dist/automation/i18n.d.ts +4 -0
  10. package/dist/automation/i18n.js +19 -0
  11. package/dist/automation/i18n.js.map +1 -0
  12. package/dist/automation/send-notification.d.ts +21 -0
  13. package/dist/automation/send-notification.js +163 -0
  14. package/dist/automation/send-notification.js.map +1 -0
  15. package/dist/automation/triggers.js +19 -25
  16. package/dist/automation/triggers.js.map +1 -1
  17. package/dist/client-origin-cors.d.ts +1 -0
  18. package/dist/client-origin-cors.js +19 -0
  19. package/dist/client-origin-cors.js.map +1 -0
  20. package/dist/config.d.ts +3 -2
  21. package/dist/config.js +5 -7
  22. package/dist/config.js.map +1 -1
  23. package/dist/frontend-module.d.ts +4 -0
  24. package/dist/frontend-module.js +37 -0
  25. package/dist/frontend-module.js.map +1 -0
  26. package/dist/implementations/dms/client-ip.js +1 -1
  27. package/dist/implementations/dms/client-ip.js.map +1 -1
  28. package/dist/implementations/dms/dev-reload.d.ts +5 -0
  29. package/dist/implementations/dms/dev-reload.js +23 -3
  30. package/dist/implementations/dms/dev-reload.js.map +1 -1
  31. package/dist/implementations/dms/frontend-modules.d.ts +2 -4
  32. package/dist/implementations/dms/frontend-modules.js +38 -94
  33. package/dist/implementations/dms/frontend-modules.js.map +1 -1
  34. package/dist/implementations/dms/frontend-ready.d.ts +12 -2
  35. package/dist/implementations/dms/frontend-ready.js +34 -4
  36. package/dist/implementations/dms/frontend-ready.js.map +1 -1
  37. package/dist/implementations/dms/layout-banners.d.ts +2 -1
  38. package/dist/implementations/dms/layout-banners.js +9 -0
  39. package/dist/implementations/dms/layout-banners.js.map +1 -1
  40. package/dist/implementations/dms/manifest.d.ts +7 -2
  41. package/dist/implementations/dms/manifest.js +12 -7
  42. package/dist/implementations/dms/manifest.js.map +1 -1
  43. package/dist/implementations/dms/page.d.ts +4 -3
  44. package/dist/implementations/dms/page.js +49 -18
  45. package/dist/implementations/dms/page.js.map +1 -1
  46. package/dist/implementations/dms/permissions-resolver.d.ts +2 -2
  47. package/dist/implementations/dms/permissions-resolver.js +2 -2
  48. package/dist/implementations/dms/permissions-resolver.js.map +1 -1
  49. package/dist/implementations/dms/realtime.js +1 -0
  50. package/dist/implementations/dms/realtime.js.map +1 -1
  51. package/dist/implementations/dms-base/bulk-selection.d.ts +1 -1
  52. package/dist/implementations/dms-base/bulk-selection.js +23 -1
  53. package/dist/implementations/dms-base/bulk-selection.js.map +1 -1
  54. package/dist/implementations/dms-base/filter-tokens.js +5 -3
  55. package/dist/implementations/dms-base/filter-tokens.js.map +1 -1
  56. package/dist/implementations/dms-base/search-route.d.ts +1 -0
  57. package/dist/implementations/dms-base/search-route.js +35 -13
  58. package/dist/implementations/dms-base/search-route.js.map +1 -1
  59. package/dist/implementations/dms-base/table-view.js +11 -6
  60. package/dist/implementations/dms-base/table-view.js.map +1 -1
  61. package/dist/implementations/dms-notifications/index.d.ts +2 -2
  62. package/dist/implementations/dms-notifications/index.js +5 -5
  63. package/dist/implementations/dms-notifications/index.js.map +1 -1
  64. package/dist/index.js +32 -55
  65. package/dist/index.js.map +1 -1
  66. package/dist/pages/modules/index.d.ts +1 -0
  67. package/dist/pages/modules/index.js +1 -0
  68. package/dist/pages/modules/index.js.map +1 -1
  69. package/dist/pages/modules/modules-store.d.ts +9 -0
  70. package/dist/pages/modules/modules-store.js +30 -0
  71. package/dist/pages/modules/modules-store.js.map +1 -0
  72. package/dist/pages/settings/users/account-credentials.js +2 -2
  73. package/dist/pages/settings/users/account-credentials.js.map +1 -1
  74. package/dist/pages/settings/users/account-data-store.js +25 -8
  75. package/dist/pages/settings/users/account-data-store.js.map +1 -1
  76. package/dist/pages/settings/users/invite-extension-routes.js +9 -3
  77. package/dist/pages/settings/users/invite-extension-routes.js.map +1 -1
  78. package/dist/pages/settings/users/member-management.js +13 -14
  79. package/dist/pages/settings/users/member-management.js.map +1 -1
  80. package/dist/pages/settings/users/profile.d.ts +1 -4
  81. package/dist/pages/settings/users/profile.js +0 -35
  82. package/dist/pages/settings/users/profile.js.map +1 -1
  83. package/dist/pages/settings/users/role-editor-store.js +26 -18
  84. package/dist/pages/settings/users/role-editor-store.js.map +1 -1
  85. package/dist/pages/settings/users/role-editor.d.ts +0 -1
  86. package/dist/pages/settings/users/role-editor.js +1 -2
  87. package/dist/pages/settings/users/role-editor.js.map +1 -1
  88. package/dist/pages/settings/users/role-preview.js +1 -2
  89. package/dist/pages/settings/users/role-preview.js.map +1 -1
  90. package/dist/pages/settings/users/roles.js +2 -2
  91. package/dist/pages/settings/users/roles.js.map +1 -1
  92. package/dist/pages/settings/users/two-factor-operations.js.map +1 -1
  93. package/dist/realtime/broker.d.ts +6 -0
  94. package/dist/realtime/broker.js +8 -1
  95. package/dist/realtime/broker.js.map +1 -1
  96. package/dist/realtime/presence.d.ts +8 -3
  97. package/dist/realtime/presence.js +8 -4
  98. package/dist/realtime/presence.js.map +1 -1
  99. package/dist/realtime/sessions.d.ts +11 -1
  100. package/dist/realtime/sessions.js +21 -3
  101. package/dist/realtime/sessions.js.map +1 -1
  102. package/dist/realtime/table-view.d.ts +2 -2
  103. package/dist/realtime/table-view.js +4 -3
  104. package/dist/realtime/table-view.js.map +1 -1
  105. package/dist/routes/auth/client-ip.d.ts +1 -0
  106. package/dist/routes/auth/client-ip.js +18 -0
  107. package/dist/routes/auth/client-ip.js.map +1 -1
  108. package/dist/routes/auth/oauth/config.d.ts +2 -1
  109. package/dist/routes/auth/oauth/config.js +5 -1
  110. package/dist/routes/auth/oauth/config.js.map +1 -1
  111. package/dist/routes/auth/session-handoff.d.ts +0 -1
  112. package/dist/routes/auth/session-handoff.js +0 -2
  113. package/dist/routes/auth/session-handoff.js.map +1 -1
  114. package/dist/routes/auth.js +3 -2
  115. package/dist/routes/auth.js.map +1 -1
  116. package/dist/routes/index.d.ts +0 -1
  117. package/dist/routes/index.js +0 -1
  118. package/dist/routes/index.js.map +1 -1
  119. package/dist/routes/realtime.d.ts +13 -1
  120. package/dist/routes/realtime.js +114 -29
  121. package/dist/routes/realtime.js.map +1 -1
  122. package/dist/startup-config.d.ts +2 -0
  123. package/dist/startup-config.js +62 -0
  124. package/dist/startup-config.js.map +1 -0
  125. package/dist/store/interfaces.d.ts +3 -2
  126. package/dist/store/interfaces.js +16 -6
  127. package/dist/store/interfaces.js.map +1 -1
  128. package/dist/store/listing.js +25 -15
  129. package/dist/store/listing.js.map +1 -1
  130. package/dist/store/operations.js +5 -2
  131. package/dist/store/operations.js.map +1 -1
  132. package/dist/store/requirements.js +3 -2
  133. package/dist/store/requirements.js.map +1 -1
  134. package/dist/store/runtime.d.ts +10 -1
  135. package/dist/store/runtime.js +33 -6
  136. package/dist/store/runtime.js.map +1 -1
  137. package/dist/store/types.d.ts +10 -0
  138. package/dist/utils/ensure-default-tenant.d.ts +2 -1
  139. package/dist/utils/ensure-default-tenant.js +13 -1
  140. package/dist/utils/ensure-default-tenant.js.map +1 -1
  141. package/dist/utils/export-jobs.js +2 -1
  142. package/dist/utils/export-jobs.js.map +1 -1
  143. package/dist/validation/auth.schema.d.ts +2 -2
  144. package/dist/validation/member-invite.schema.d.ts +2 -10
  145. package/dist/validation/member-invite.schema.js +2 -15
  146. package/dist/validation/member-invite.schema.js.map +1 -1
  147. package/frontend-vue/dms.frontend.ts +24 -5
  148. package/frontend-vue/dms.server.ts +17 -0
  149. package/frontend-vue/layers/dms-auth/server/accounts.ts +3 -4
  150. package/frontend-vue/layers/dms-core/app/build/composables/renderNow.ts +33 -0
  151. package/frontend-vue/layers/dms-core/app/build/composables/user/tablePreferences.ts +5 -1
  152. package/frontend-vue/layers/dms-core/app/build/utils/crossTab.ts +199 -0
  153. package/frontend-vue/layers/dms-core/app/build/utils/sharedRealtimeConnection.ts +410 -0
  154. package/frontend-vue/layers/dms-core/app/composables/auth/useApiData.ts +77 -12
  155. package/frontend-vue/layers/dms-core/app/composables/data-types/useDataType.ts +26 -0
  156. package/frontend-vue/layers/dms-core/app/composables/live/livePauseSource.ts +29 -0
  157. package/frontend-vue/layers/dms-core/app/composables/period/compareResolvers.ts +150 -9
  158. package/frontend-vue/layers/dms-core/app/composables/period/usePeriod.ts +6 -4
  159. package/frontend-vue/layers/dms-core/app/composables/period/usePeriodScope.ts +27 -1
  160. package/frontend-vue/layers/dms-core/app/composables/realtime/useUserRealtime.ts +256 -119
  161. package/frontend-vue/layers/dms-core/app/composables/translation/useComposedText.ts +21 -8
  162. package/frontend-vue/layers/dms-core/app/composables/translation/useTranslation.ts +25 -5
  163. package/frontend-vue/layers/dms-core/app/composables/useApiError.ts +3 -5
  164. package/frontend-vue/layers/dms-core/app/composables/useFieldErrors.ts +61 -26
  165. package/frontend-vue/layers/dms-core/app/plugins/dev-error-log.ts +16 -0
  166. package/frontend-vue/layers/dms-core/app/types/user.ts +6 -0
  167. package/frontend-vue/layers/dms-core/app/utils/composedText.ts +7 -2
  168. package/frontend-vue/layers/dms-core/app/utils/formatter.ts +134 -35
  169. package/frontend-vue/layers/dms-core/app/utils/url-interpolation.ts +18 -1
  170. package/frontend-vue/layers/dms-core/i18n/locales/core-en-GB.json +136 -2
  171. package/frontend-vue/layers/dms-core/i18n/locales/core-fr-FR.json +136 -2
  172. package/frontend-vue/layers/dms-core/shared/types/app-config.ts +0 -2
  173. package/frontend-vue/layers/dms-layout/app/app.config.ts +0 -1
  174. package/frontend-vue/layers/dms-layout/app/assets/css/main.css +11 -1
  175. package/frontend-vue/layers/dms-layout/app/assets/fonts/Geist-Italic-Variable.woff2 +0 -0
  176. package/frontend-vue/layers/dms-layout/app/assets/fonts/Geist-Variable.woff2 +0 -0
  177. package/frontend-vue/layers/dms-layout/app/assets/fonts/GeistMono-Italic-Variable.woff2 +0 -0
  178. package/frontend-vue/layers/dms-layout/app/assets/fonts/GeistMono-Variable.woff2 +0 -0
  179. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardBanners.vue +3 -2
  180. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardHeader.vue +41 -21
  181. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardPageBody.vue +6 -2
  182. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardSidebar.vue +4 -19
  183. package/frontend-vue/layers/dms-layout/app/build/components/layout/Footer.vue +11 -107
  184. package/frontend-vue/layers/dms-layout/app/build/components/layout/GithubStarPrompt.vue +18 -7
  185. package/frontend-vue/layers/dms-layout/app/build/components/layout/PageHeaderActionsOutlet.vue +4 -0
  186. package/frontend-vue/layers/dms-layout/app/build/components/layout/RowSidePanel.vue +43 -82
  187. package/frontend-vue/layers/dms-layout/app/build/components/layout/SidebarUserMenu.vue +44 -3
  188. package/frontend-vue/layers/dms-layout/app/build/components/layout/UserIdentity.vue +11 -3
  189. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleCatalogTile.vue +132 -35
  190. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleManageMenu.vue +59 -0
  191. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleSourceLabel.vue +25 -0
  192. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreBanners.vue +73 -0
  193. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreOperation.vue +116 -0
  194. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreRequirements.vue +8 -3
  195. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreTile.vue +85 -207
  196. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleTile.vue +10 -3
  197. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleTileSkeleton.vue +68 -0
  198. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationInboxDisplay.vue +24 -8
  199. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationInboxItem.vue +8 -5
  200. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/region/RegionTimeZoneInput.vue +1 -0
  201. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/role-permissions.ts +19 -0
  202. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/useRoleEditor.ts +2 -1
  203. package/frontend-vue/layers/dms-layout/app/build/composables/layout/useSidePanelWidth.ts +31 -70
  204. package/frontend-vue/layers/dms-layout/app/build/composables/notification/useNotificationGroupsOpen.ts +11 -1
  205. package/frontend-vue/layers/dms-layout/app/build/utils/dev-reload-stream.ts +81 -0
  206. package/frontend-vue/layers/dms-layout/app/build/utils/github-repository.ts +2 -2
  207. package/frontend-vue/layers/dms-layout/app/build/utils/module-store-catalog.ts +232 -36
  208. package/frontend-vue/layers/dms-layout/app/build/utils/modules-catalog.ts +122 -14
  209. package/frontend-vue/layers/dms-layout/app/composables/layout/useLayoutBanners.ts +32 -3
  210. package/frontend-vue/layers/dms-layout/app/composables/layout/useServedHeaderActions.ts +49 -11
  211. package/frontend-vue/layers/dms-layout/app/composables/page/useModuleHistory.ts +3 -2
  212. package/frontend-vue/layers/dms-layout/app/composables/page/useModuleStore.ts +59 -4
  213. package/frontend-vue/layers/dms-layout/app/composables/page/useModuleStoreActions.ts +194 -0
  214. package/frontend-vue/layers/dms-layout/app/composables/page/usePageComponentPreload.ts +23 -3
  215. package/frontend-vue/layers/dms-layout/app/composables/page/usePageLayout.ts +4 -2
  216. package/frontend-vue/layers/dms-layout/app/composables/page/usePageRecordDeletion.ts +162 -0
  217. package/frontend-vue/layers/dms-layout/app/composables/page/useSiteLayout.ts +6 -1
  218. package/frontend-vue/layers/dms-layout/app/custom-layouts/DefaultLayout.vue +6 -2
  219. package/frontend-vue/layers/dms-layout/app/custom-layouts/SettingsLayout.vue +6 -2
  220. package/frontend-vue/layers/dms-layout/app/custom-pages/modules-store.vue +291 -0
  221. package/frontend-vue/layers/dms-layout/app/custom-pages/modules.vue +87 -474
  222. package/frontend-vue/layers/dms-layout/app/middleware/module-routing.global.ts +3 -0
  223. package/frontend-vue/layers/dms-layout/app/pages/[...slug].vue +13 -22
  224. package/frontend-vue/layers/dms-layout/app/plugins/command-palette-navigation.client.ts +11 -10
  225. package/frontend-vue/layers/dms-layout/app/plugins/command-palette-personal-pages.client.ts +22 -52
  226. package/frontend-vue/layers/dms-layout/app/plugins/command-palette-quick-actions.client.ts +7 -7
  227. package/frontend-vue/layers/dms-layout/app/plugins/command-palette-session.client.ts +11 -10
  228. package/frontend-vue/layers/dms-layout/app/plugins/dms-dev-reload.client.ts +14 -9
  229. package/frontend-vue/layers/dms-layout/app/theme/actions.ts +5 -4
  230. package/frontend-vue/layers/dms-layout/app/theme/form-controls.ts +9 -4
  231. package/frontend-vue/layers/dms-layout/app/theme/surfaces.ts +22 -6
  232. package/frontend-vue/layers/dms-layout/app/types/module-store.ts +9 -0
  233. package/frontend-vue/layers/dms-layout/app/types/page.ts +15 -1
  234. package/frontend-vue/layers/dms-layout/app/utils/account-menu.ts +11 -0
  235. package/frontend-vue/layers/dms-layout/app/utils/breadcrumb.ts +57 -0
  236. package/frontend-vue/layers/dms-layout/app/utils/pageQuery.ts +26 -0
  237. package/frontend-vue/layers/dms-layout/i18n/locales/layout-en-GB.json +45 -18
  238. package/frontend-vue/layers/dms-layout/i18n/locales/layout-fr-FR.json +44 -17
  239. package/frontend-vue/layers/dms-ui/app/build/components/containers/TargetComponentTree.vue +31 -0
  240. package/frontend-vue/layers/dms-ui/app/build/components/containers/constants.ts +25 -0
  241. package/frontend-vue/layers/dms-ui/app/build/components/containers/drawer/DynamicDrawer.vue +244 -15
  242. package/frontend-vue/layers/dms-ui/app/build/components/containers/modal/DynamicModal.vue +42 -25
  243. package/frontend-vue/layers/dms-ui/app/build/components/containers/row/RowHeader.vue +153 -0
  244. package/frontend-vue/layers/dms-ui/app/build/components/containers/row/RowNotFound.vue +44 -0
  245. package/frontend-vue/layers/dms-ui/app/build/components/containers/row/drawerRowHeader.ts +35 -0
  246. package/frontend-vue/layers/dms-ui/app/build/components/form/FormEntries.vue +44 -9
  247. package/frontend-vue/layers/dms-ui/app/build/components/form/FormErrorSummary.vue +11 -4
  248. package/frontend-vue/layers/dms-ui/app/build/components/form/FormFieldControl.vue +38 -5
  249. package/frontend-vue/layers/dms-ui/app/build/components/form/FormFieldNotes.vue +29 -5
  250. package/frontend-vue/layers/dms-ui/app/build/components/form/FormLoadError.vue +5 -1
  251. package/frontend-vue/layers/dms-ui/app/build/components/form/FormSectionNav.vue +3 -1
  252. package/frontend-vue/layers/dms-ui/app/build/components/form/FormSections.vue +106 -27
  253. package/frontend-vue/layers/dms-ui/app/build/components/table/Actions.vue +12 -4
  254. package/frontend-vue/layers/dms-ui/app/build/components/table/Empty.vue +4 -2
  255. package/frontend-vue/layers/dms-ui/app/build/components/table/FiltersRow.vue +48 -1
  256. package/frontend-vue/layers/dms-ui/app/build/components/table/Pagination.vue +55 -54
  257. package/frontend-vue/layers/dms-ui/app/build/components/table/RowSelection.vue +2 -1
  258. package/frontend-vue/layers/dms-ui/app/build/components/table/Table.vue +396 -288
  259. package/frontend-vue/layers/dms-ui/app/build/components/table/Tabs.vue +2 -1
  260. package/frontend-vue/layers/dms-ui/app/build/components/table/Views.vue +2 -1
  261. package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardAvatar.vue +59 -0
  262. package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardGridSkeleton.vue +19 -2
  263. package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardRowActions.vue +38 -0
  264. package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardsDisplay.vue +148 -104
  265. package/frontend-vue/layers/dms-ui/app/build/components/table-view/LiveHoldBanner.vue +17 -2
  266. package/frontend-vue/layers/dms-ui/app/build/composables/actions/bulkSelection.ts +43 -9
  267. package/frontend-vue/layers/dms-ui/app/build/composables/actions/rowComponentOptions.ts +76 -0
  268. package/frontend-vue/layers/dms-ui/app/build/composables/actions/rowNavigation.ts +172 -27
  269. package/frontend-vue/layers/dms-ui/app/build/composables/actions/useActionTargets.ts +270 -46
  270. package/frontend-vue/layers/dms-ui/app/build/composables/confirm/actionError.ts +6 -1
  271. package/frontend-vue/layers/dms-ui/app/build/composables/confirm/confirmDialogTexts.ts +2 -0
  272. package/frontend-vue/layers/dms-ui/app/build/composables/containers/closingLayers.ts +186 -0
  273. package/frontend-vue/layers/dms-ui/app/build/composables/containers/context.ts +14 -0
  274. package/frontend-vue/layers/dms-ui/app/build/composables/containers/drawerSize.ts +229 -0
  275. package/frontend-vue/layers/dms-ui/app/build/composables/containers/useResizableSize.ts +175 -0
  276. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/metricCells.ts +18 -35
  277. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/numberSuffix.ts +44 -0
  278. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerDefaults.ts +123 -27
  279. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerFieldTypes.ts +2 -1
  280. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationFilter.ts +75 -0
  281. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationRows.ts +92 -0
  282. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationValue.ts +39 -0
  283. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/twoLineCell.ts +3 -3
  284. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/useColumnValueRenderer.ts +6 -2
  285. package/frontend-vue/layers/dms-ui/app/build/composables/form/createFormFields.ts +15 -0
  286. package/frontend-vue/layers/dms-ui/app/build/composables/form/fieldSaved.ts +40 -0
  287. package/frontend-vue/layers/dms-ui/app/build/composables/form/fieldValueRule.ts +62 -0
  288. package/frontend-vue/layers/dms-ui/app/build/composables/form/formEntryContext.ts +5 -0
  289. package/frontend-vue/layers/dms-ui/app/build/composables/form/formFooter.ts +42 -7
  290. package/frontend-vue/layers/dms-ui/app/build/composables/form/formLayout.ts +106 -4
  291. package/frontend-vue/layers/dms-ui/app/build/composables/form/formRecordLoad.ts +11 -5
  292. package/frontend-vue/layers/dms-ui/app/build/composables/form/formSections.ts +32 -0
  293. package/frontend-vue/layers/dms-ui/app/build/composables/form/formValidation.ts +36 -4
  294. package/frontend-vue/layers/dms-ui/app/build/composables/form/readonlyValue.ts +19 -0
  295. package/frontend-vue/layers/dms-ui/app/build/composables/form/registerFormFunctions.ts +27 -0
  296. package/frontend-vue/layers/dms-ui/app/build/composables/form/repeaterTable.ts +78 -0
  297. package/frontend-vue/layers/dms-ui/app/build/composables/form/serverFieldErrors.ts +49 -0
  298. package/frontend-vue/layers/dms-ui/app/build/composables/form/toasterClearance.ts +118 -0
  299. package/frontend-vue/layers/dms-ui/app/build/composables/form/useInstantForm.ts +12 -1
  300. package/frontend-vue/layers/dms-ui/app/build/composables/live/currentPageLive.ts +41 -3
  301. package/frontend-vue/layers/dms-ui/app/build/composables/live/livePoller.ts +10 -2
  302. package/frontend-vue/layers/dms-ui/app/build/composables/live/pageReadClock.ts +28 -0
  303. package/frontend-vue/layers/dms-ui/app/build/composables/live/shortcuts.ts +1 -1
  304. package/frontend-vue/layers/dms-ui/app/build/composables/live/usePageLiveHost.ts +17 -3
  305. package/frontend-vue/layers/dms-ui/app/build/composables/live/useUpdatedLabel.ts +38 -0
  306. package/frontend-vue/layers/dms-ui/app/build/composables/page-toolbar/pageToolbarContext.ts +75 -0
  307. package/frontend-vue/layers/dms-ui/app/build/composables/page-toolbar/toolbarControlHeight.ts +29 -0
  308. package/frontend-vue/layers/dms-ui/app/build/composables/period/periodComparison.ts +52 -0
  309. package/frontend-vue/layers/dms-ui/app/build/composables/period/periodDisplay.ts +21 -0
  310. package/frontend-vue/layers/dms-ui/app/build/composables/period/periodShortLabels.ts +28 -0
  311. package/frontend-vue/layers/dms-ui/app/build/composables/period/usePeriodDraft.ts +1 -0
  312. package/frontend-vue/layers/dms-ui/app/build/composables/table/useRelationFilterLabels.ts +97 -0
  313. package/frontend-vue/layers/dms-ui/app/build/composables/table/useRowScrollAnchor.ts +106 -0
  314. package/frontend-vue/layers/dms-ui/app/build/composables/table/useTable.ts +9 -0
  315. package/frontend-vue/layers/dms-ui/app/build/composables/table/useTableColumns.ts +1 -2
  316. package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/archivedCount.ts +31 -0
  317. package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/filterEditorValue.ts +38 -0
  318. package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/formatFilterValue.ts +33 -2
  319. package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/scrollEdges.ts +31 -0
  320. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useCardFields.ts +33 -0
  321. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useMobileDisplay.ts +48 -0
  322. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useScrolledPastTop.ts +41 -18
  323. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableFooter.ts +3 -2
  324. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableLinkedVisit.ts +78 -0
  325. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableLiveHold.ts +135 -22
  326. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableRows.ts +56 -25
  327. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViewRowActions.ts +90 -35
  328. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViews.ts +86 -10
  329. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/bulkActions.ts +14 -4
  330. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/card.ts +127 -2
  331. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/compareValues.ts +13 -0
  332. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/expandedRows.ts +28 -0
  333. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/groupedRows.ts +114 -1
  334. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/linkedArrival.ts +308 -0
  335. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/locateRow.ts +106 -0
  336. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/pageArrival.ts +34 -0
  337. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/pinnedRows.ts +17 -0
  338. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/quickFilters.ts +41 -33
  339. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/recordLink.ts +24 -8
  340. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/tableCounts.ts +113 -0
  341. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/tableQuery.ts +27 -4
  342. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/views.ts +22 -6
  343. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/writeError.ts +21 -0
  344. package/frontend-vue/layers/dms-ui/app/build/utils/addressSuggestions.ts +49 -0
  345. package/frontend-vue/layers/dms-ui/app/build/utils/codeHighlight.ts +67 -29
  346. package/frontend-vue/layers/dms-ui/app/build/utils/eyebrow.ts +12 -0
  347. package/frontend-vue/layers/dms-ui/app/build/utils/fieldOptionsI18n.ts +51 -11
  348. package/frontend-vue/layers/dms-ui/app/build/utils/htmlGrammar.ts +79 -0
  349. package/frontend-vue/layers/dms-ui/app/build/utils/inputWidth.ts +53 -0
  350. package/frontend-vue/layers/dms-ui/app/build/utils/numberAdjustment.ts +6 -3
  351. package/frontend-vue/layers/dms-ui/app/build/utils/relativeDate.ts +19 -5
  352. package/frontend-vue/layers/dms-ui/app/build/utils/scrollWithin.ts +99 -0
  353. package/frontend-vue/layers/dms-ui/app/build/utils/shellParser.ts +1 -1
  354. package/frontend-vue/layers/dms-ui/app/build/utils/streamHighlight.ts +90 -0
  355. package/frontend-vue/layers/dms-ui/app/build/utils/urlVariables.ts +36 -14
  356. package/frontend-vue/layers/dms-ui/app/components/PasswordStrength.vue +1 -1
  357. package/frontend-vue/layers/dms-ui/app/components/RecursiveComponent.vue +9 -1
  358. package/frontend-vue/layers/dms-ui/app/components/blocks/LiveToggleBlock.vue +80 -32
  359. package/frontend-vue/layers/dms-ui/app/components/blocks/PageToolbarBlock.vue +137 -0
  360. package/frontend-vue/layers/dms-ui/app/components/blocks/StatGroupBlock.vue +5 -0
  361. package/frontend-vue/layers/dms-ui/app/components/chart/ApexChartHost.vue +16 -2
  362. package/frontend-vue/layers/dms-ui/app/components/chart/Chart.vue +24 -5
  363. package/frontend-vue/layers/dms-ui/app/components/chart/ChartCard.vue +41 -23
  364. package/frontend-vue/layers/dms-ui/app/components/code-snippet/CodeSnippet.vue +23 -12
  365. package/frontend-vue/layers/dms-ui/app/components/confirm/ConfirmModal.vue +1 -1
  366. package/frontend-vue/layers/dms-ui/app/components/container-footer/ContainerFooter.vue +34 -0
  367. package/frontend-vue/layers/dms-ui/app/components/field-row/FieldRow.vue +25 -2
  368. package/frontend-vue/layers/dms-ui/app/components/flow-canvas/FlowCanvas.vue +2 -2
  369. package/frontend-vue/layers/dms-ui/app/components/form/Form.vue +119 -36
  370. package/frontend-vue/layers/dms-ui/app/components/form/components/Cascader.vue +53 -22
  371. package/frontend-vue/layers/dms-ui/app/components/form/components/DatePicker.vue +20 -1
  372. package/frontend-vue/layers/dms-ui/app/components/form/components/Display.vue +13 -1
  373. package/frontend-vue/layers/dms-ui/app/components/form/components/Image.vue +8 -3
  374. package/frontend-vue/layers/dms-ui/app/components/form/components/InputAddress.vue +53 -5
  375. package/frontend-vue/layers/dms-ui/app/components/form/components/InputCode.vue +29 -5
  376. package/frontend-vue/layers/dms-ui/app/components/form/components/InputNumber.vue +45 -8
  377. package/frontend-vue/layers/dms-ui/app/components/form/components/InputPercentage.vue +28 -5
  378. package/frontend-vue/layers/dms-ui/app/components/form/components/InputSecret.vue +5 -0
  379. package/frontend-vue/layers/dms-ui/app/components/form/components/InputText.vue +19 -2
  380. package/frontend-vue/layers/dms-ui/app/components/form/components/InputTime.vue +2 -1
  381. package/frontend-vue/layers/dms-ui/app/components/form/components/Relation.vue +226 -65
  382. package/frontend-vue/layers/dms-ui/app/components/form/components/Repeater.vue +80 -30
  383. package/frontend-vue/layers/dms-ui/app/components/form/components/RepeaterTable.vue +210 -0
  384. package/frontend-vue/layers/dms-ui/app/components/form/components/Select.vue +4 -2
  385. package/frontend-vue/layers/dms-ui/app/components/grid/GridRow.vue +11 -2
  386. package/frontend-vue/layers/dms-ui/app/components/key-value-list/KeyValueList.vue +79 -70
  387. package/frontend-vue/layers/dms-ui/app/components/kpi/KpiCard.vue +117 -21
  388. package/frontend-vue/layers/dms-ui/app/components/meter/Meter.vue +2 -1
  389. package/frontend-vue/layers/dms-ui/app/components/period/PeriodSelector.vue +113 -34
  390. package/frontend-vue/layers/dms-ui/app/components/save-bar/SaveBar.vue +14 -2
  391. package/frontend-vue/layers/dms-ui/app/components/section-header/Eyebrow.vue +6 -1
  392. package/frontend-vue/layers/dms-ui/app/components/segmented/Segmented.vue +13 -0
  393. package/frontend-vue/layers/dms-ui/app/components/stat-group/StatGroup.vue +52 -3
  394. package/frontend-vue/layers/dms-ui/app/components/tab/Tab.vue +2 -1
  395. package/frontend-vue/layers/dms-ui/app/components/table-view/CascaderPath.vue +74 -25
  396. package/frontend-vue/layers/dms-ui/app/components/table-view/KanbanBoard.vue +48 -44
  397. package/frontend-vue/layers/dms-ui/app/components/table-view/KanbanDisplay.vue +4 -1
  398. package/frontend-vue/layers/dms-ui/app/components/table-view/TableView.vue +426 -97
  399. package/frontend-vue/layers/dms-ui/app/components/top-list/TopListCard.vue +33 -5
  400. package/frontend-vue/layers/dms-ui/app/composables/chart/apexCategoryLabels.ts +68 -0
  401. package/frontend-vue/layers/dms-ui/app/composables/chart/apexDatetimeBuckets.ts +306 -0
  402. package/frontend-vue/layers/dms-ui/app/composables/chart/formatValue.ts +4 -3
  403. package/frontend-vue/layers/dms-ui/app/composables/chart/heatmapColors.ts +93 -0
  404. package/frontend-vue/layers/dms-ui/app/composables/chart/localizeSeries.ts +62 -0
  405. package/frontend-vue/layers/dms-ui/app/composables/chart/useApexChart.ts +116 -8
  406. package/frontend-vue/layers/dms-ui/app/composables/chart/useApexChart.types.ts +7 -0
  407. package/frontend-vue/layers/dms-ui/app/composables/containers/types.ts +84 -1
  408. package/frontend-vue/layers/dms-ui/app/composables/containers/useDrawer.ts +69 -8
  409. package/frontend-vue/layers/dms-ui/app/composables/form/types/field-saved.ts +11 -0
  410. package/frontend-vue/layers/dms-ui/app/composables/form/types/field.ts +16 -0
  411. package/frontend-vue/layers/dms-ui/app/composables/form/types/functions.ts +1 -0
  412. package/frontend-vue/layers/dms-ui/app/composables/form/useForm.ts +189 -28
  413. package/frontend-vue/layers/dms-ui/app/composables/live/usePageLive.ts +29 -12
  414. package/frontend-vue/layers/dms-ui/app/composables/page-toolbar/usePageToolbarSize.ts +30 -0
  415. package/frontend-vue/layers/dms-ui/app/composables/table-view/kanban.ts +4 -2
  416. package/frontend-vue/layers/dms-ui/app/composables/table-view/types/action-target.ts +22 -3
  417. package/frontend-vue/layers/dms-ui/app/composables/table-view/types/config.ts +4 -0
  418. package/frontend-vue/layers/dms-ui/app/composables/table-view/types/display.ts +24 -1
  419. package/frontend-vue/layers/dms-ui/app/plugins/closing-layers.client.ts +10 -0
  420. package/frontend-vue/layers/dms-ui/app/plugins/live-pause-source.ts +15 -0
  421. package/frontend-vue/layers/dms-ui/app/plugins/register.ts +2 -0
  422. package/frontend-vue/layers/dms-ui/app/types/input-number.ts +3 -2
  423. package/frontend-vue/layers/dms-ui/app/types/page-toolbar.ts +7 -0
  424. package/frontend-vue/layers/dms-ui/app/types/row-action.ts +0 -2
  425. package/frontend-vue/layers/dms-ui/app/types/row-navigation.ts +17 -0
  426. package/frontend-vue/layers/dms-ui/app/types/table/query.ts +2 -1
  427. package/frontend-vue/layers/dms-ui/app/utils/blockRefresh.ts +3 -1
  428. package/frontend-vue/layers/dms-ui/app/utils/cascader.ts +94 -3
  429. package/frontend-vue/layers/dms-ui/app/utils/componentTree.ts +24 -0
  430. package/frontend-vue/layers/dms-ui/i18n/locales/ui-en-GB.json +20 -5
  431. package/frontend-vue/layers/dms-ui/i18n/locales/ui-fr-FR.json +20 -5
  432. package/frontend-vue/package.json +6 -2
  433. package/package.json +11 -10
  434. package/skills/dms/SKILL.md +1 -1
  435. package/skills/dms-auth/SKILL.md +5 -3
  436. package/skills/dms-best-practices/REFERENCE.md +2 -0
  437. package/skills/dms-best-practices/SKILL.md +4 -0
  438. package/skills/dms-module/SKILL.md +3 -2
  439. package/skills/dms-pages/REFERENCE.md +129 -16
  440. package/skills/dms-pages/SKILL.md +1 -1
  441. package/skills/dms-project/DEV-SERVERS.md +23 -1
  442. package/skills/dms-project/REFERENCE.md +1 -1
  443. package/skills/dms-project/SKILL.md +4 -1
  444. package/skills/dms-project/scripts/dms-dev.sh +205 -17
  445. package/dist/hooks/tenant-instances.d.ts +0 -1
  446. package/dist/hooks/tenant-instances.js +0 -13
  447. package/dist/hooks/tenant-instances.js.map +0 -1
  448. package/dist/routes/startup-gate.d.ts +0 -7
  449. package/dist/routes/startup-gate.js +0 -39
  450. package/dist/routes/startup-gate.js.map +0 -1
  451. package/frontend-vue/layers/dms-core/app/composables/period/periodRenderNow.ts +0 -42
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import { readableNumberFormat } from "#dms-core/app/utils/formatter";
2
3
  import type {
3
4
  ColumnDef,
4
5
  ColumnFiltersOptions,
@@ -21,6 +22,8 @@ import type {
21
22
  } from "@tanstack/vue-table";
22
23
  import type { DmsAppConfig } from "#dms-core/shared/types/app-config";
23
24
  import { useTable } from "../../composables/table/useTable";
25
+ import { MAX_PAGE_SIZE } from "../../composables/table/constants";
26
+ import { useRowScrollAnchor } from "../../composables/table/useRowScrollAnchor";
24
27
  import type { LabeledColumn } from "../../composables/table/useTableColumns";
25
28
  import {
26
29
  defaultSortingState,
@@ -200,6 +203,12 @@ export interface TableProps<T> {
200
203
  * amber strip and swaps the row and bulk actions to restore.
201
204
  */
202
205
  archiveToggle?: boolean;
206
+ /**
207
+ * Caption count while the archived rows show: a `$` key receiving
208
+ * `{ count }` and pluralized on it, or a text with `{count}`. Defaults to
209
+ * "Archived: {count}".
210
+ */
211
+ archivedCountLabel?: string;
203
212
  /**
204
213
  * Controls drawn around the rows (the resolved backend `chrome`). Defaults
205
214
  * to the full chrome.
@@ -406,6 +415,10 @@ export interface TableSharedData<T> {
406
415
  * too.
407
416
  */
408
417
  emptyStates?: TableViewEmptyStatesConfig;
418
+ /** The add action's configured label (`$`: i18n key), if any. */
419
+ addLabel?: string;
420
+ /** The add action's configured icon, if any. */
421
+ addIcon?: string;
409
422
  }
410
423
  </script>
411
424
 
@@ -440,6 +453,7 @@ import TableRowSelection from "./RowSelection.vue";
440
453
  import TableTabs from "./Tabs.vue";
441
454
  import { createTableViewDeleteShortcut } from "../../../composables/table-view/shortcuts/tableViewDelete";
442
455
  import { FULL_TABLE_CHROME } from "../../composables/table-view/utils/chrome";
456
+ import { formatArchivedCount } from "../../composables/table/utils/archivedCount";
443
457
  import {
444
458
  clearTableColumnFilters,
445
459
  clearTableFilters,
@@ -453,6 +467,11 @@ import {
453
467
  DEFAULT_PAGE_SIZE,
454
468
  } from "../../composables/table/constants";
455
469
  import { mergeColumnOrder } from "../../composables/table/utils/columnOrder";
470
+ import {
471
+ horizontalScrollEdges,
472
+ type ScrollEdges,
473
+ } from "../../composables/table/utils/scrollEdges";
474
+ import { groupRows } from "../../composables/table-view/utils/groupedRows";
456
475
  import { EYEBROW_CLASS } from "../../utils/eyebrow";
457
476
  import { isRowClickTrigger } from "../../utils/rowClickTrigger";
458
477
 
@@ -512,6 +531,10 @@ const theme = tv({
512
531
  captionCount: "font-mono text-xs font-medium tabular-nums text-dimmed",
513
532
  captionCountPlaceholder: "h-3 w-6 rounded-[4px]",
514
533
 
534
+ scrollFrame: "relative",
535
+ // An inset shadow, whatever the card's background, on the side the
536
+ // table still hides columns.
537
+ scrollFade: "pointer-events-none absolute inset-y-0 z-30 w-3",
515
538
  tableRoot: "relative overflow-x-auto whitespace-nowrap",
516
539
  tableBase: "inline-block min-w-full align-middle",
517
540
  table: "text-default w-full min-w-full table-fixed text-left text-[13px]/5",
@@ -639,6 +662,14 @@ const theme = tv({
639
662
  scrolled: {
640
663
  true: "",
641
664
  },
665
+ side: {
666
+ start: {
667
+ scrollFade: "shadow-[inset_12px_0_10px_-10px_rgb(0_0_0/0.28)]",
668
+ },
669
+ end: {
670
+ scrollFade: "shadow-[inset_-12px_0_10px_-10px_rgb(0_0_0/0.28)]",
671
+ },
672
+ },
642
673
  // Rows listed while viewing the archive read as set aside.
643
674
  // Restore stays on show there, it is the only thing to do with them.
644
675
  archived: {
@@ -794,8 +825,10 @@ const isShowingArchived = computed(
794
825
  () => !!props.archiveToggle && showArchivedState.value,
795
826
  );
796
827
 
797
- // As many placeholder rows as the page will list (capped), fading out.
798
- const SKELETON_MAX_ROW_COUNT = 10;
828
+ // As many placeholder rows as the page will list, fading out: the footer
829
+ // (count, page size, pages) and what follows the table already stand where a
830
+ // full page puts them, and do not move when the rows land.
831
+ const SKELETON_MAX_ROW_COUNT = MAX_PAGE_SIZE;
799
832
  const SKELETON_TOTAL_FADE = 0.7;
800
833
  const SKELETON_WIDTHS = ["62%", "48%", "70%", "54%", "40%"];
801
834
  const skeletonWidth = (rowIndex: number, columnIndex: number): string =>
@@ -804,7 +837,15 @@ const skeletonWidth = (rowIndex: number, columnIndex: number): string =>
804
837
  // The scroll shadow under a sticky header only shows once rows went under it.
805
838
  const hasScrollArea = computed(() => !!props.maxHeight);
806
839
  const isScrolled = ref(false);
840
+ // Columns beyond the card's edge fade out on that side: the scrollbar sits
841
+ // under the last row, out of view on a long list.
842
+ const scrollEdges = ref<ScrollEdges>({ start: false, end: false });
843
+ const syncScrollEdges = () => {
844
+ const area = tableRootRef.value;
845
+ if (area) scrollEdges.value = horizontalScrollEdges(area);
846
+ };
807
847
  const onTableScroll = (event: Event) => {
848
+ syncScrollEdges();
808
849
  if (!hasScrollArea.value) return;
809
850
  isScrolled.value = (event.target as HTMLElement).scrollTop > 0;
810
851
  };
@@ -812,6 +853,20 @@ const onTableScroll = (event: Event) => {
812
853
  // the visible scroll area.
813
854
  const tableRootRef = useTemplateRef<HTMLElement>("tableRoot");
814
855
  const { width: tableViewportWidth } = useElementSize(tableRootRef);
856
+ const tableBaseRef = useTemplateRef<HTMLElement>("tableBase");
857
+ const { width: tableContentWidth } = useElementSize(tableBaseRef);
858
+ watch([tableViewportWidth, tableContentWidth], syncScrollEdges);
859
+ // The column header band's height, for what the table view lays over the
860
+ // first rows (the live hold's pill) to land under it, sticky or not; unset
861
+ // while a custom display draws no header.
862
+ const tableHeadRef = useTemplateRef<HTMLElement>("tableHead");
863
+ const { height: tableHeadHeight } = useElementSize(tableHeadRef, undefined, {
864
+ box: "border-box",
865
+ });
866
+ const rootStyle = computed(() => ({
867
+ "--dms-table-head-height":
868
+ tableHeadHeight.value > 0 ? `${tableHeadHeight.value}px` : undefined,
869
+ }));
815
870
  const tableRootStyle = computed(() => ({
816
871
  maxHeight: props.maxHeight,
817
872
  "--dms-table-viewport":
@@ -887,6 +942,17 @@ const stickyPinnedSides = computed(() => {
887
942
  return { left: keepLeft, right: keepRight };
888
943
  });
889
944
 
945
+ // The fades sit inside the columns pinned on their side, which never scroll.
946
+ const scrollFadeInsets = computed(() => {
947
+ const sides = stickyPinnedSides.value;
948
+ return {
949
+ start:
950
+ (sides.left ? table.getLeftTotalSize() : 0) +
951
+ (hasPresenceRail.value ? PRESENCE_RAIL_WIDTH : 0),
952
+ end: sides.right ? table.getRightTotalSize() : 0,
953
+ };
954
+ });
955
+
890
956
  const getStickyPin = (column: { getIsPinned: () => unknown }) => {
891
957
  const pinned = column.getIsPinned();
892
958
  if (pinned === "left" && stickyPinnedSides.value.left) return "left";
@@ -1031,35 +1097,46 @@ const bodyEntries = computed<BodyEntry[]>(() => {
1031
1097
  const grouping = props.grouping;
1032
1098
  if (!grouping) return rows.map((row) => ({ kind: "row", id: row.id, row }));
1033
1099
  const entries: BodyEntry[] = [];
1034
- let currentKey: string | undefined;
1035
- for (const row of rows) {
1036
- const key = grouping.keyOf(row.original);
1037
- if (key !== currentKey) {
1038
- currentKey = key;
1039
- entries.push({
1040
- kind: "group",
1041
- id: GROUP_ENTRY_PREFIX + key,
1042
- row,
1043
- key,
1044
- header: () => grouping.header(key, row.original),
1045
- });
1046
- }
1047
- if (!collapsedGroups.value.includes(key)) {
1100
+ for (const group of groupRows(rows, (row) => grouping.keyOf(row.original))) {
1101
+ const { key } = group;
1102
+ const [first] = group.rows as [TableRow];
1103
+ entries.push({
1104
+ kind: "group",
1105
+ id: GROUP_ENTRY_PREFIX + key,
1106
+ row: first,
1107
+ key,
1108
+ header: () => grouping.header(key, first.original),
1109
+ });
1110
+ if (collapsedGroups.value.includes(key)) continue;
1111
+ for (const row of group.rows) {
1048
1112
  entries.push({ kind: "row", id: row.id, row });
1049
1113
  }
1050
1114
  }
1051
1115
  return entries;
1052
1116
  });
1053
1117
 
1118
+ // Rows added above the ones the reader scrolled to (a live list's new rows)
1119
+ // do not push them down.
1120
+ useRowScrollAnchor(tableRootRef, () =>
1121
+ bodyEntries.value
1122
+ .filter((entry) => entry.kind === "row")
1123
+ .map((entry) => entry.id),
1124
+ );
1125
+
1054
1126
  const { t, locale } = useI18n();
1055
1127
 
1056
1128
  const formattedRowCount = computed(() =>
1057
- new Intl.NumberFormat(locale.value).format(rowCount.value),
1129
+ readableNumberFormat(locale.value).format(rowCount.value),
1058
1130
  );
1059
1131
 
1060
1132
  const captionCountLabel = computed(() =>
1061
1133
  isShowingArchived.value
1062
- ? t("dms.table.archived_count", { count: formattedRowCount.value })
1134
+ ? formatArchivedCount(
1135
+ t,
1136
+ rowCount.value,
1137
+ formattedRowCount.value,
1138
+ props.archivedCountLabel,
1139
+ )
1063
1140
  : formattedRowCount.value,
1064
1141
  );
1065
1142
 
@@ -1089,6 +1166,13 @@ const canAddFromToolbar = computed(() => {
1089
1166
  const add = normalizeActionConfig(props.rowActions?.add);
1090
1167
  return !!add.isEnabled && add.placement !== HEADER_PLACEMENT;
1091
1168
  });
1169
+ // Drawn on the toolbar and empty-state buttons, as the header one draws them.
1170
+ const addLabel = computed(
1171
+ () => normalizeActionConfig(props.rowActions?.add).label,
1172
+ );
1173
+ const addIcon = computed(
1174
+ () => normalizeActionConfig(props.rowActions?.add).icon,
1175
+ );
1092
1176
 
1093
1177
  // The bulk bar shows whenever selected rows have something to go to.
1094
1178
  const hasBulkActions = computed(
@@ -1234,6 +1318,8 @@ watchEffect(() => {
1234
1318
  defaultPageSize: props.defaultPageSize,
1235
1319
  accumulation: props.accumulation,
1236
1320
  emptyStates: props.emptyStates,
1321
+ addLabel: addLabel.value,
1322
+ addIcon: addIcon.value,
1237
1323
  };
1238
1324
  });
1239
1325
 
@@ -1310,7 +1396,7 @@ defineShortcuts({
1310
1396
  </script>
1311
1397
 
1312
1398
  <template>
1313
- <div :class="uiTable.root()">
1399
+ <div :class="uiTable.root()" :style="rootStyle">
1314
1400
  <template v-if="resolvedCapabilities.header">
1315
1401
  <header
1316
1402
  :class="
@@ -1351,6 +1437,8 @@ defineShortcuts({
1351
1437
  v-model:show-archived="showArchivedState"
1352
1438
  :table
1353
1439
  :can-add-row="canAddFromToolbar"
1440
+ :add-label="addLabel"
1441
+ :add-icon="addIcon"
1354
1442
  :archive-toggle="archiveToggle"
1355
1443
  :custom-buttons="toolbarButtons"
1356
1444
  :on-custom-button="onCustomButton"
@@ -1424,298 +1512,318 @@ defineShortcuts({
1424
1512
  <slot name="notice" />
1425
1513
 
1426
1514
  <slot name="body" :table="table">
1427
- <section
1428
- ref="tableRoot"
1429
- :class="uiTable.tableRoot()"
1430
- :style="tableRootStyle"
1431
- @scroll.passive="onTableScroll"
1432
- >
1433
- <div
1434
- v-if="loading && !isFirstPageLoading"
1435
- aria-hidden="true"
1436
- :class="uiTable.loadingBar()"
1515
+ <div :class="uiTable.scrollFrame()">
1516
+ <section
1517
+ ref="tableRoot"
1518
+ :class="uiTable.tableRoot()"
1519
+ :style="tableRootStyle"
1520
+ @scroll.passive="onTableScroll"
1437
1521
  >
1438
- <span :class="uiTable.loadingBarIndicator()" />
1439
- </div>
1440
-
1441
- <div :class="uiTable.tableBase()">
1442
- <table :class="uiTable.table()">
1443
- <caption v-if="caption" :class="uiTable.tableCaption()">
1444
- {{ caption }}
1445
- </caption>
1446
-
1447
- <thead>
1448
- <tr
1449
- v-for="headerGroup in table.getHeaderGroups()"
1450
- :key="headerGroup.id"
1451
- >
1452
- <th
1453
- v-if="hasPresenceRail"
1454
- :class="[
1455
- HEADER_MATCH_BG,
1456
- 'border-b-default sticky left-0 z-30 border-b p-0',
1457
- hasScrollArea && 'top-0 z-40',
1458
- ]"
1459
- :style="{
1460
- width: PRESENCE_RAIL_WIDTH_PX,
1461
- minWidth: PRESENCE_RAIL_WIDTH_PX,
1462
- }"
1463
- />
1464
- <th
1465
- v-if="reorder"
1466
- :class="uiTable.handleHeadCell()"
1467
- :aria-label="t('dms.table.reorder.column')"
1468
- />
1469
- <th
1470
- v-for="header in headerGroup.headers"
1471
- :key="header.id"
1472
- :colspan="header.colSpan"
1473
- :aria-sort="headerAriaSort(header.column)"
1474
- :data-pinned="header.column.getIsPinned()"
1475
- :class="
1476
- uiTable.headCell({
1477
- pinned: getPinnedVariant(header.column),
1478
- })
1479
- "
1480
- :style="{
1481
- width: getHeaderWidth(header),
1482
- left: getPinnedLeftOffset(header.column),
1483
- right: getPinnedRightOffset(header.column),
1484
- }"
1522
+ <div
1523
+ v-if="loading && !isFirstPageLoading"
1524
+ aria-hidden="true"
1525
+ :class="uiTable.loadingBar()"
1526
+ >
1527
+ <span :class="uiTable.loadingBarIndicator()" />
1528
+ </div>
1529
+
1530
+ <div ref="tableBase" :class="uiTable.tableBase()">
1531
+ <table :class="uiTable.table()">
1532
+ <caption v-if="caption" :class="uiTable.tableCaption()">
1533
+ {{ caption }}
1534
+ </caption>
1535
+
1536
+ <thead ref="tableHead">
1537
+ <tr
1538
+ v-for="headerGroup in table.getHeaderGroups()"
1539
+ :key="headerGroup.id"
1485
1540
  >
1486
- <slot
1487
- :name="`${header.id}-header`"
1488
- v-bind="header.getContext()"
1541
+ <th
1542
+ v-if="hasPresenceRail"
1543
+ :class="[
1544
+ HEADER_MATCH_BG,
1545
+ 'border-b-default sticky left-0 z-30 border-b p-0',
1546
+ hasScrollArea && 'top-0 z-40',
1547
+ ]"
1548
+ :style="{
1549
+ width: PRESENCE_RAIL_WIDTH_PX,
1550
+ minWidth: PRESENCE_RAIL_WIDTH_PX,
1551
+ }"
1552
+ />
1553
+ <th
1554
+ v-if="reorder"
1555
+ :class="uiTable.handleHeadCell()"
1556
+ :aria-label="t('dms.table.reorder.column')"
1557
+ />
1558
+ <th
1559
+ v-for="header in headerGroup.headers"
1560
+ :key="header.id"
1561
+ :colspan="header.colSpan"
1562
+ :aria-sort="headerAriaSort(header.column)"
1563
+ :data-pinned="header.column.getIsPinned()"
1564
+ :class="
1565
+ uiTable.headCell({
1566
+ pinned: getPinnedVariant(header.column),
1567
+ })
1568
+ "
1569
+ :style="{
1570
+ width: getHeaderWidth(header),
1571
+ left: getPinnedLeftOffset(header.column),
1572
+ right: getPinnedRightOffset(header.column),
1573
+ }"
1489
1574
  >
1490
- <FlexRender
1491
- v-if="!header.isPlaceholder"
1492
- :render="header.column.columnDef.header"
1493
- :props="header.getContext()"
1494
- />
1495
-
1496
- <div
1497
- v-if="header.column.getCanResize()"
1498
- :class="
1499
- uiTable.colResizer({
1500
- isResizing: header.column.getIsResizing(),
1501
- })
1502
- "
1503
- @dblclick="header.column.resetSize()"
1504
- @mousedown="onResize($event, header)"
1505
- @touchstart="onResize($event, header)"
1506
- />
1507
- </slot>
1508
- </th>
1509
- </tr>
1510
- </thead>
1511
-
1512
- <tbody>
1513
- <template v-if="table.getRowModel().rows?.length">
1514
- <template
1515
- v-for="{ kind, id, row, key, header } in bodyEntries"
1516
- :key="id"
1517
- >
1518
- <tr v-if="kind === 'group' && grouping">
1519
- <td
1520
- :colspan="row.getVisibleCells().length + leadingCellCount"
1521
- :class="uiTable.groupCell()"
1522
- >
1523
- <div :class="uiTable.groupHeader()">
1524
- <component
1525
- :is="grouping.collapsible ? 'button' : 'span'"
1526
- :type="grouping.collapsible ? 'button' : undefined"
1527
- :aria-expanded="
1528
- grouping.collapsible
1529
- ? !collapsedGroups.includes(key!)
1530
- : undefined
1531
- "
1532
- :class="uiTable.groupToggle()"
1533
- @click="grouping.collapsible && toggleGroup(key!)"
1534
- >
1535
- <UIcon
1536
- v-if="grouping.collapsible"
1537
- :name="
1538
- collapsedGroups.includes(key!)
1539
- ? 'i-ph-caret-right'
1540
- : 'i-ph-caret-down'
1541
- "
1542
- class="size-3"
1543
- />
1544
- <component :is="header" />
1545
- </component>
1546
- <span
1547
- v-if="grouping.countOf?.(key!) !== undefined"
1548
- :class="uiTable.groupCount()"
1549
- >
1550
- {{ grouping.countOf(key!) }}
1551
- </span>
1552
- </div>
1553
- </td>
1554
- </tr>
1555
- <template v-else>
1556
- <tr
1557
- :data-selected="row.getIsSelected()"
1558
- :data-expanded="row.getIsExpanded()"
1559
- :data-open="isOpenRow(row.original) || undefined"
1560
- :aria-current="isOpenRow(row.original) || undefined"
1561
- :data-presence="!!getRowPresence(row.original)"
1562
- :title="
1563
- getRowPresence(row.original)
1564
- ? presenceTooltipText(getRowPresence(row.original)!)
1565
- : undefined
1566
- "
1567
- :class="[
1568
- uiTable.row({
1569
- loading,
1570
- rowClickable: isRowClickable(row.original),
1571
- presence: !!getRowPresence(row.original),
1572
- }),
1573
- { 'cursor-pointer': isSingleClickRow(row.original) },
1574
- ]"
1575
- @click="handleRowPointer($event, row.original)"
1576
- @dblclick="handleRowPointer($event, row.original)"
1577
- @mouseenter="handleRowHover(row)"
1578
- @mouseleave="handleRowLeave"
1579
- @dragover="reorderHandles.allowDrop"
1580
- @drop="reorderHandles.drop(row.index)"
1575
+ <slot
1576
+ :name="`${header.id}-header`"
1577
+ v-bind="header.getContext()"
1581
1578
  >
1582
- <td
1583
- v-if="hasPresenceRail"
1584
- :class="[
1585
- 'border-b-muted sticky left-0 z-30 border-b p-0 in-[tr:last-child]:border-b-0',
1586
- row.getIsSelected() && !getRowPresence(row.original)
1587
- ? SELECTION_RAIL_BG
1588
- : presenceRailBackground(row.original),
1589
- ]"
1590
- :style="{
1591
- width: PRESENCE_RAIL_WIDTH_PX,
1592
- minWidth: PRESENCE_RAIL_WIDTH_PX,
1593
- }"
1579
+ <FlexRender
1580
+ v-if="!header.isPlaceholder"
1581
+ :render="header.column.columnDef.header"
1582
+ :props="header.getContext()"
1594
1583
  />
1595
- <td v-if="reorder" :class="uiTable.handleCell()">
1596
- <button
1597
- v-bind="reorderHandles.handleFor(row.index)"
1598
- :class="uiTable.handle()"
1599
- >
1600
- <UIcon name="i-ph-dots-six-vertical" />
1601
- </button>
1602
- </td>
1603
- <td
1604
- v-for="cell in row.getVisibleCells()"
1605
- :key="cell.id"
1606
- :data-pinned="cell.column.getIsPinned()"
1584
+
1585
+ <div
1586
+ v-if="header.column.getCanResize()"
1607
1587
  :class="
1608
- uiTable.rowCell({
1609
- pinned: getPinnedVariant(cell.column),
1610
- loading,
1611
- rowClickable: isRowClickable(row.original),
1612
- cellWrap: (cell.column.columnDef as TableColumn<T>)
1613
- .cellWrap,
1588
+ uiTable.colResizer({
1589
+ isResizing: header.column.getIsResizing(),
1614
1590
  })
1615
1591
  "
1616
- :style="{
1617
- left: getPinnedLeftOffset(cell.column),
1618
- right: getPinnedRightOffset(cell.column),
1619
- }"
1620
- >
1621
- <div :class="uiTable.rowContainer()">
1622
- <div :class="uiTable.rowInternal({ loading })">
1623
- <slot
1624
- :name="`${cell.column.id}-cell`"
1625
- v-bind="cell.getContext()"
1626
- >
1627
- <div
1628
- :class="
1629
- uiTable.rowSpan({
1630
- cellWrap: (
1631
- cell.column.columnDef as TableColumn<T>
1632
- ).cellWrap,
1633
- })
1634
- "
1635
- @mouseenter="syncClippedTitle"
1636
- >
1637
- <FlexRender
1638
- :render="cell.column.columnDef.cell"
1639
- :props="cell.getContext()"
1640
- />
1641
- </div>
1642
- </slot>
1643
- </div>
1644
- </div>
1645
- </td>
1646
- </tr>
1647
- <tr
1648
- v-if="row.getIsExpanded()"
1649
- :id="expandedRowDomId(row.id)"
1650
- >
1592
+ @dblclick="header.column.resetSize()"
1593
+ @mousedown="onResize($event, header)"
1594
+ @touchstart="onResize($event, header)"
1595
+ />
1596
+ </slot>
1597
+ </th>
1598
+ </tr>
1599
+ </thead>
1600
+
1601
+ <tbody>
1602
+ <template v-if="table.getRowModel().rows?.length">
1603
+ <template
1604
+ v-for="{ kind, id, row, key, header } in bodyEntries"
1605
+ :key="id"
1606
+ >
1607
+ <tr v-if="kind === 'group' && grouping">
1651
1608
  <td
1652
1609
  :colspan="
1653
1610
  row.getVisibleCells().length + leadingCellCount
1654
1611
  "
1655
- :class="uiTable.expandedCell()"
1612
+ :class="uiTable.groupCell()"
1656
1613
  >
1657
- <div :class="uiTable.expandedBody()">
1658
- <slot name="expanded" :row="row" />
1614
+ <div :class="uiTable.groupHeader()">
1615
+ <component
1616
+ :is="grouping.collapsible ? 'button' : 'span'"
1617
+ :type="grouping.collapsible ? 'button' : undefined"
1618
+ :aria-expanded="
1619
+ grouping.collapsible
1620
+ ? !collapsedGroups.includes(key!)
1621
+ : undefined
1622
+ "
1623
+ :class="uiTable.groupToggle()"
1624
+ @click="grouping.collapsible && toggleGroup(key!)"
1625
+ >
1626
+ <UIcon
1627
+ v-if="grouping.collapsible"
1628
+ :name="
1629
+ collapsedGroups.includes(key!)
1630
+ ? 'i-ph-caret-right'
1631
+ : 'i-ph-caret-down'
1632
+ "
1633
+ class="size-3"
1634
+ />
1635
+ <component :is="header" />
1636
+ </component>
1637
+ <span
1638
+ v-if="grouping.countOf?.(key!) !== undefined"
1639
+ :class="uiTable.groupCount()"
1640
+ >
1641
+ {{ grouping.countOf(key!) }}
1642
+ </span>
1659
1643
  </div>
1660
1644
  </td>
1661
1645
  </tr>
1646
+ <template v-else>
1647
+ <tr
1648
+ :data-row-id="id"
1649
+ :data-selected="row.getIsSelected()"
1650
+ :data-expanded="row.getIsExpanded()"
1651
+ :data-open="isOpenRow(row.original) || undefined"
1652
+ :aria-current="isOpenRow(row.original) || undefined"
1653
+ :data-presence="!!getRowPresence(row.original)"
1654
+ :title="
1655
+ getRowPresence(row.original)
1656
+ ? presenceTooltipText(getRowPresence(row.original)!)
1657
+ : undefined
1658
+ "
1659
+ :class="[
1660
+ uiTable.row({
1661
+ loading,
1662
+ rowClickable: isRowClickable(row.original),
1663
+ presence: !!getRowPresence(row.original),
1664
+ }),
1665
+ { 'cursor-pointer': isSingleClickRow(row.original) },
1666
+ ]"
1667
+ @click="handleRowPointer($event, row.original)"
1668
+ @dblclick="handleRowPointer($event, row.original)"
1669
+ @mouseenter="handleRowHover(row)"
1670
+ @mouseleave="handleRowLeave"
1671
+ @dragover="reorderHandles.allowDrop"
1672
+ @drop="reorderHandles.drop(row.index)"
1673
+ >
1674
+ <td
1675
+ v-if="hasPresenceRail"
1676
+ :class="[
1677
+ 'border-b-muted sticky left-0 z-30 border-b p-0 in-[tr:last-child]:border-b-0',
1678
+ row.getIsSelected() && !getRowPresence(row.original)
1679
+ ? SELECTION_RAIL_BG
1680
+ : presenceRailBackground(row.original),
1681
+ ]"
1682
+ :style="{
1683
+ width: PRESENCE_RAIL_WIDTH_PX,
1684
+ minWidth: PRESENCE_RAIL_WIDTH_PX,
1685
+ }"
1686
+ />
1687
+ <td v-if="reorder" :class="uiTable.handleCell()">
1688
+ <button
1689
+ v-bind="reorderHandles.handleFor(row.index)"
1690
+ :class="uiTable.handle()"
1691
+ >
1692
+ <UIcon name="i-ph-dots-six-vertical" />
1693
+ </button>
1694
+ </td>
1695
+ <td
1696
+ v-for="cell in row.getVisibleCells()"
1697
+ :key="cell.id"
1698
+ :data-pinned="cell.column.getIsPinned()"
1699
+ :class="
1700
+ uiTable.rowCell({
1701
+ pinned: getPinnedVariant(cell.column),
1702
+ loading,
1703
+ rowClickable: isRowClickable(row.original),
1704
+ cellWrap: (
1705
+ cell.column.columnDef as TableColumn<T>
1706
+ ).cellWrap,
1707
+ })
1708
+ "
1709
+ :style="{
1710
+ left: getPinnedLeftOffset(cell.column),
1711
+ right: getPinnedRightOffset(cell.column),
1712
+ }"
1713
+ >
1714
+ <div :class="uiTable.rowContainer()">
1715
+ <div :class="uiTable.rowInternal({ loading })">
1716
+ <slot
1717
+ :name="`${cell.column.id}-cell`"
1718
+ v-bind="cell.getContext()"
1719
+ >
1720
+ <div
1721
+ :class="
1722
+ uiTable.rowSpan({
1723
+ cellWrap: (
1724
+ cell.column.columnDef as TableColumn<T>
1725
+ ).cellWrap,
1726
+ })
1727
+ "
1728
+ @mouseenter="syncClippedTitle"
1729
+ >
1730
+ <FlexRender
1731
+ :render="cell.column.columnDef.cell"
1732
+ :props="cell.getContext()"
1733
+ />
1734
+ </div>
1735
+ </slot>
1736
+ </div>
1737
+ </div>
1738
+ </td>
1739
+ </tr>
1740
+ <tr
1741
+ v-if="row.getIsExpanded()"
1742
+ :id="expandedRowDomId(row.id)"
1743
+ >
1744
+ <td
1745
+ :colspan="
1746
+ row.getVisibleCells().length + leadingCellCount
1747
+ "
1748
+ :class="uiTable.expandedCell()"
1749
+ >
1750
+ <div :class="uiTable.expandedBody()">
1751
+ <slot name="expanded" :row="row" />
1752
+ </div>
1753
+ </td>
1754
+ </tr>
1755
+ </template>
1662
1756
  </template>
1663
1757
  </template>
1664
- </template>
1665
- <!-- First load: skeleton rows keep the column rhythm instead of
1758
+ <!-- First load: skeleton rows keep the column rhythm instead of
1666
1759
  flashing the empty state. -->
1667
- <template v-else-if="isFirstPageLoading">
1668
- <tr
1669
- v-for="rowIndex in skeletonRowCount"
1670
- :key="`skeleton-${rowIndex}`"
1671
- aria-hidden="true"
1672
- :class="uiTable.skeletonRow()"
1673
- :style="{ opacity: skeletonRowOpacity(rowIndex) }"
1674
- >
1675
- <td
1676
- v-if="hasPresenceRail"
1677
- class="border-b-muted border-b p-0 in-[tr:last-child]:border-b-0"
1678
- />
1679
- <td v-if="reorder" :class="uiTable.handleCell()" />
1680
- <td
1681
- v-for="(
1682
- column, columnIndex
1683
- ) in table.getVisibleLeafColumns()"
1684
- :key="column.id"
1685
- :class="uiTable.rowCell()"
1760
+ <template v-else-if="isFirstPageLoading">
1761
+ <tr
1762
+ v-for="rowIndex in skeletonRowCount"
1763
+ :key="`skeleton-${rowIndex}`"
1764
+ aria-hidden="true"
1765
+ :class="uiTable.skeletonRow()"
1766
+ :style="{ opacity: skeletonRowOpacity(rowIndex) }"
1686
1767
  >
1687
- <USkeleton
1688
- :aria-label="t('dms.a11y.loading')"
1689
- v-if="column.columnDef.meta"
1690
- :class="uiTable.skeletonCell()"
1691
- :style="{ width: skeletonWidth(rowIndex, columnIndex) }"
1768
+ <td
1769
+ v-if="hasPresenceRail"
1770
+ class="border-b-muted border-b p-0 in-[tr:last-child]:border-b-0"
1692
1771
  />
1772
+ <td v-if="reorder" :class="uiTable.handleCell()" />
1773
+ <td
1774
+ v-for="(
1775
+ column, columnIndex
1776
+ ) in table.getVisibleLeafColumns()"
1777
+ :key="column.id"
1778
+ :class="uiTable.rowCell()"
1779
+ >
1780
+ <USkeleton
1781
+ :aria-label="t('dms.a11y.loading')"
1782
+ v-if="column.columnDef.meta"
1783
+ :class="uiTable.skeletonCell()"
1784
+ :style="{ width: skeletonWidth(rowIndex, columnIndex) }"
1785
+ />
1786
+ </td>
1787
+ </tr>
1788
+ </template>
1789
+ <tr v-else>
1790
+ <td
1791
+ :colspan="
1792
+ table.getVisibleLeafColumns().length + leadingCellCount
1793
+ "
1794
+ class="p-0"
1795
+ >
1796
+ <div :class="uiTable.emptyBody()">
1797
+ <TableEmpty
1798
+ :can-add-row="
1799
+ normalizeActionConfig(rowActions?.add).isEnabled
1800
+ "
1801
+ :load-error="loadError"
1802
+ :archived="isShowingArchived"
1803
+ :empty-states="emptyStates"
1804
+ />
1805
+ </div>
1693
1806
  </td>
1694
1807
  </tr>
1695
- </template>
1696
- <tr v-else>
1697
- <td
1698
- :colspan="
1699
- table.getVisibleLeafColumns().length + leadingCellCount
1700
- "
1701
- class="p-0"
1702
- >
1703
- <div :class="uiTable.emptyBody()">
1704
- <TableEmpty
1705
- :can-add-row="
1706
- normalizeActionConfig(rowActions?.add).isEnabled
1707
- "
1708
- :load-error="loadError"
1709
- :archived="isShowingArchived"
1710
- :empty-states="emptyStates"
1711
- />
1712
- </div>
1713
- </td>
1714
- </tr>
1715
- </tbody>
1716
- </table>
1717
- </div>
1718
- </section>
1808
+ </tbody>
1809
+ </table>
1810
+ </div>
1811
+ </section>
1812
+ <span
1813
+ v-if="scrollEdges.start"
1814
+ aria-hidden="true"
1815
+ data-table-scroll-fade="start"
1816
+ :class="uiTable.scrollFade({ side: 'start' })"
1817
+ :style="{ insetInlineStart: `${scrollFadeInsets.start}px` }"
1818
+ />
1819
+ <span
1820
+ v-if="scrollEdges.end"
1821
+ aria-hidden="true"
1822
+ data-table-scroll-fade="end"
1823
+ :class="uiTable.scrollFade({ side: 'end' })"
1824
+ :style="{ insetInlineEnd: `${scrollFadeInsets.end}px` }"
1825
+ />
1826
+ </div>
1719
1827
 
1720
1828
  <TablePagination />
1721
1829
  </slot>