@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.
Files changed (414) hide show
  1. package/CHANGELOG.md +114 -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 -0
  21. package/dist/config.js +5 -3
  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 +22 -89
  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 +1 -2
  41. package/dist/implementations/dms/manifest.js +2 -0
  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 +28 -45
  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/realtime.d.ts +13 -1
  117. package/dist/routes/realtime.js +114 -29
  118. package/dist/routes/realtime.js.map +1 -1
  119. package/dist/startup-config.d.ts +2 -0
  120. package/dist/startup-config.js +62 -0
  121. package/dist/startup-config.js.map +1 -0
  122. package/dist/store/interfaces.d.ts +3 -2
  123. package/dist/store/interfaces.js +16 -6
  124. package/dist/store/interfaces.js.map +1 -1
  125. package/dist/store/listing.js +24 -13
  126. package/dist/store/listing.js.map +1 -1
  127. package/dist/store/operations.js +4 -0
  128. package/dist/store/operations.js.map +1 -1
  129. package/dist/store/requirements.js +3 -2
  130. package/dist/store/requirements.js.map +1 -1
  131. package/dist/store/runtime.d.ts +10 -1
  132. package/dist/store/runtime.js +33 -6
  133. package/dist/store/runtime.js.map +1 -1
  134. package/dist/store/types.d.ts +10 -0
  135. package/dist/validation/auth.schema.d.ts +2 -2
  136. package/dist/validation/member-invite.schema.d.ts +2 -10
  137. package/dist/validation/member-invite.schema.js +2 -15
  138. package/dist/validation/member-invite.schema.js.map +1 -1
  139. package/frontend-vue/dms.frontend.ts +24 -5
  140. package/frontend-vue/dms.server.ts +17 -0
  141. package/frontend-vue/layers/dms-auth/server/accounts.ts +3 -4
  142. package/frontend-vue/layers/dms-core/app/build/composables/renderNow.ts +34 -0
  143. package/frontend-vue/layers/dms-core/app/build/composables/user/tablePreferences.ts +5 -1
  144. package/frontend-vue/layers/dms-core/app/build/utils/crossTab.ts +199 -0
  145. package/frontend-vue/layers/dms-core/app/build/utils/sharedRealtimeConnection.ts +410 -0
  146. package/frontend-vue/layers/dms-core/app/composables/auth/useApiData.ts +77 -12
  147. package/frontend-vue/layers/dms-core/app/composables/data-types/useDataType.ts +26 -0
  148. package/frontend-vue/layers/dms-core/app/composables/hydration/isHydratingComponent.ts +29 -0
  149. package/frontend-vue/layers/dms-core/app/composables/live/livePauseSource.ts +29 -0
  150. package/frontend-vue/layers/dms-core/app/composables/period/compareResolvers.ts +150 -9
  151. package/frontend-vue/layers/dms-core/app/composables/period/usePeriod.ts +6 -4
  152. package/frontend-vue/layers/dms-core/app/composables/period/usePeriodScope.ts +27 -1
  153. package/frontend-vue/layers/dms-core/app/composables/realtime/useUserRealtime.ts +256 -119
  154. package/frontend-vue/layers/dms-core/app/composables/translation/useComposedText.ts +21 -8
  155. package/frontend-vue/layers/dms-core/app/composables/translation/useTranslation.ts +22 -5
  156. package/frontend-vue/layers/dms-core/app/plugins/dev-error-log.ts +16 -0
  157. package/frontend-vue/layers/dms-core/app/types/user.ts +6 -0
  158. package/frontend-vue/layers/dms-core/app/utils/composedText.ts +7 -2
  159. package/frontend-vue/layers/dms-core/app/utils/formatter.ts +166 -35
  160. package/frontend-vue/layers/dms-core/app/utils/url-interpolation.ts +18 -1
  161. package/frontend-vue/layers/dms-core/i18n/locales/core-en-GB.json +134 -2
  162. package/frontend-vue/layers/dms-core/i18n/locales/core-fr-FR.json +134 -2
  163. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardBanners.vue +3 -2
  164. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardHeader.vue +41 -21
  165. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardPageBody.vue +9 -0
  166. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardSidebar.vue +4 -19
  167. package/frontend-vue/layers/dms-layout/app/build/components/layout/Footer.vue +11 -3
  168. package/frontend-vue/layers/dms-layout/app/build/components/layout/GithubStarPrompt.vue +18 -7
  169. package/frontend-vue/layers/dms-layout/app/build/components/layout/PageHeaderActionBar.vue +8 -0
  170. package/frontend-vue/layers/dms-layout/app/build/components/layout/PageHeaderActionsOutlet.vue +14 -0
  171. package/frontend-vue/layers/dms-layout/app/build/components/layout/RowSidePanel.vue +43 -82
  172. package/frontend-vue/layers/dms-layout/app/build/components/layout/SidebarUserMenu.vue +44 -3
  173. package/frontend-vue/layers/dms-layout/app/build/components/layout/UserIdentity.vue +11 -3
  174. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleCatalogTile.vue +132 -35
  175. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleManageMenu.vue +59 -0
  176. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleSourceLabel.vue +25 -0
  177. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreBanners.vue +73 -0
  178. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreOperation.vue +116 -0
  179. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreRequirements.vue +8 -3
  180. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreTile.vue +85 -207
  181. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleTile.vue +10 -3
  182. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleTileSkeleton.vue +68 -0
  183. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationInboxDisplay.vue +24 -8
  184. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationInboxItem.vue +8 -5
  185. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/region/RegionTimeZoneInput.vue +1 -0
  186. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/role-permissions.ts +19 -0
  187. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/useRoleEditor.ts +2 -1
  188. package/frontend-vue/layers/dms-layout/app/build/composables/layout/useSidePanelWidth.ts +31 -70
  189. package/frontend-vue/layers/dms-layout/app/build/composables/notification/useNotificationGroupsOpen.ts +11 -1
  190. package/frontend-vue/layers/dms-layout/app/build/utils/dev-reload-stream.ts +81 -0
  191. package/frontend-vue/layers/dms-layout/app/build/utils/module-store-catalog.ts +232 -36
  192. package/frontend-vue/layers/dms-layout/app/build/utils/modules-catalog.ts +122 -14
  193. package/frontend-vue/layers/dms-layout/app/composables/layout/useLayoutBanners.ts +32 -3
  194. package/frontend-vue/layers/dms-layout/app/composables/layout/usePageRecord.ts +50 -0
  195. package/frontend-vue/layers/dms-layout/app/composables/layout/useServedHeaderActions.ts +25 -7
  196. package/frontend-vue/layers/dms-layout/app/composables/page/useModuleHistory.ts +3 -2
  197. package/frontend-vue/layers/dms-layout/app/composables/page/useModuleStore.ts +51 -4
  198. package/frontend-vue/layers/dms-layout/app/composables/page/useModuleStoreActions.ts +194 -0
  199. package/frontend-vue/layers/dms-layout/app/composables/page/usePageComponentPreload.ts +23 -3
  200. package/frontend-vue/layers/dms-layout/app/composables/page/usePageLayout.ts +4 -2
  201. package/frontend-vue/layers/dms-layout/app/composables/page/useSiteLayout.ts +6 -1
  202. package/frontend-vue/layers/dms-layout/app/custom-layouts/DefaultLayout.vue +9 -0
  203. package/frontend-vue/layers/dms-layout/app/custom-layouts/SettingsLayout.vue +9 -0
  204. package/frontend-vue/layers/dms-layout/app/custom-pages/modules-store.vue +291 -0
  205. package/frontend-vue/layers/dms-layout/app/custom-pages/modules.vue +87 -474
  206. package/frontend-vue/layers/dms-layout/app/middleware/module-routing.global.ts +3 -0
  207. package/frontend-vue/layers/dms-layout/app/pages/[...slug].vue +6 -22
  208. package/frontend-vue/layers/dms-layout/app/plugins/command-palette-navigation.client.ts +2 -1
  209. package/frontend-vue/layers/dms-layout/app/plugins/command-palette-personal-pages.client.ts +14 -44
  210. package/frontend-vue/layers/dms-layout/app/plugins/dms-dev-reload.client.ts +14 -9
  211. package/frontend-vue/layers/dms-layout/app/theme/form-controls.ts +9 -4
  212. package/frontend-vue/layers/dms-layout/app/theme/surfaces.ts +22 -6
  213. package/frontend-vue/layers/dms-layout/app/types/module-store.ts +9 -0
  214. package/frontend-vue/layers/dms-layout/app/types/page.ts +15 -1
  215. package/frontend-vue/layers/dms-layout/app/utils/account-menu.ts +11 -0
  216. package/frontend-vue/layers/dms-layout/app/utils/breadcrumb.ts +57 -0
  217. package/frontend-vue/layers/dms-layout/app/utils/pageQuery.ts +26 -0
  218. package/frontend-vue/layers/dms-layout/app/utils/pageRecord.ts +71 -0
  219. package/frontend-vue/layers/dms-layout/i18n/locales/layout-en-GB.json +39 -14
  220. package/frontend-vue/layers/dms-layout/i18n/locales/layout-fr-FR.json +38 -13
  221. package/frontend-vue/layers/dms-ui/app/build/components/containers/TargetComponentTree.vue +31 -0
  222. package/frontend-vue/layers/dms-ui/app/build/components/containers/constants.ts +25 -0
  223. package/frontend-vue/layers/dms-ui/app/build/components/containers/drawer/DynamicDrawer.vue +244 -15
  224. package/frontend-vue/layers/dms-ui/app/build/components/containers/modal/DynamicModal.vue +42 -25
  225. package/frontend-vue/layers/dms-ui/app/build/components/containers/row/RowHeader.vue +153 -0
  226. package/frontend-vue/layers/dms-ui/app/build/components/containers/row/RowNotFound.vue +44 -0
  227. package/frontend-vue/layers/dms-ui/app/build/components/containers/row/drawerRowHeader.ts +35 -0
  228. package/frontend-vue/layers/dms-ui/app/build/components/form/FormEntries.vue +44 -9
  229. package/frontend-vue/layers/dms-ui/app/build/components/form/FormErrorSummary.vue +11 -4
  230. package/frontend-vue/layers/dms-ui/app/build/components/form/FormFieldControl.vue +38 -5
  231. package/frontend-vue/layers/dms-ui/app/build/components/form/FormFieldNotes.vue +29 -5
  232. package/frontend-vue/layers/dms-ui/app/build/components/form/FormSectionNav.vue +3 -1
  233. package/frontend-vue/layers/dms-ui/app/build/components/form/FormSections.vue +106 -27
  234. package/frontend-vue/layers/dms-ui/app/build/components/table/Actions.vue +12 -4
  235. package/frontend-vue/layers/dms-ui/app/build/components/table/Empty.vue +4 -2
  236. package/frontend-vue/layers/dms-ui/app/build/components/table/FiltersRow.vue +38 -1
  237. package/frontend-vue/layers/dms-ui/app/build/components/table/Pagination.vue +55 -54
  238. package/frontend-vue/layers/dms-ui/app/build/components/table/RowSelection.vue +2 -1
  239. package/frontend-vue/layers/dms-ui/app/build/components/table/Table.vue +396 -288
  240. package/frontend-vue/layers/dms-ui/app/build/components/table/Tabs.vue +2 -1
  241. package/frontend-vue/layers/dms-ui/app/build/components/table/Views.vue +2 -1
  242. package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardAvatar.vue +59 -0
  243. package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardGridSkeleton.vue +19 -2
  244. package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardRowActions.vue +38 -0
  245. package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardsDisplay.vue +148 -104
  246. package/frontend-vue/layers/dms-ui/app/build/components/table-view/LiveHoldBanner.vue +17 -2
  247. package/frontend-vue/layers/dms-ui/app/build/composables/actions/bulkSelection.ts +43 -9
  248. package/frontend-vue/layers/dms-ui/app/build/composables/actions/rowComponentOptions.ts +76 -0
  249. package/frontend-vue/layers/dms-ui/app/build/composables/actions/rowNavigation.ts +172 -27
  250. package/frontend-vue/layers/dms-ui/app/build/composables/actions/useActionTargets.ts +270 -46
  251. package/frontend-vue/layers/dms-ui/app/build/composables/confirm/confirmDialogTexts.ts +2 -0
  252. package/frontend-vue/layers/dms-ui/app/build/composables/containers/closingLayers.ts +186 -0
  253. package/frontend-vue/layers/dms-ui/app/build/composables/containers/context.ts +14 -0
  254. package/frontend-vue/layers/dms-ui/app/build/composables/containers/drawerSize.ts +229 -0
  255. package/frontend-vue/layers/dms-ui/app/build/composables/containers/useResizableSize.ts +175 -0
  256. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/metricCells.ts +18 -35
  257. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/numberSuffix.ts +47 -0
  258. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerDefaults.ts +99 -24
  259. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerFieldTypes.ts +2 -1
  260. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationFilter.ts +75 -0
  261. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationRows.ts +71 -0
  262. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationValue.ts +39 -0
  263. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/twoLineCell.ts +3 -3
  264. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/useColumnValueRenderer.ts +6 -2
  265. package/frontend-vue/layers/dms-ui/app/build/composables/form/createFormFields.ts +15 -0
  266. package/frontend-vue/layers/dms-ui/app/build/composables/form/fieldSaved.ts +40 -0
  267. package/frontend-vue/layers/dms-ui/app/build/composables/form/fieldValueRule.ts +62 -0
  268. package/frontend-vue/layers/dms-ui/app/build/composables/form/formEntryContext.ts +5 -0
  269. package/frontend-vue/layers/dms-ui/app/build/composables/form/formFooter.ts +42 -7
  270. package/frontend-vue/layers/dms-ui/app/build/composables/form/formLayout.ts +106 -4
  271. package/frontend-vue/layers/dms-ui/app/build/composables/form/formSections.ts +32 -0
  272. package/frontend-vue/layers/dms-ui/app/build/composables/form/readonlyValue.ts +19 -0
  273. package/frontend-vue/layers/dms-ui/app/build/composables/form/registerFormFunctions.ts +27 -0
  274. package/frontend-vue/layers/dms-ui/app/build/composables/form/repeaterTable.ts +65 -0
  275. package/frontend-vue/layers/dms-ui/app/build/composables/form/serverFieldErrors.ts +49 -0
  276. package/frontend-vue/layers/dms-ui/app/build/composables/form/toasterClearance.ts +118 -0
  277. package/frontend-vue/layers/dms-ui/app/build/composables/form/useInstantForm.ts +12 -1
  278. package/frontend-vue/layers/dms-ui/app/build/composables/live/currentPageLive.ts +41 -3
  279. package/frontend-vue/layers/dms-ui/app/build/composables/live/livePoller.ts +10 -2
  280. package/frontend-vue/layers/dms-ui/app/build/composables/live/pageReadClock.ts +28 -0
  281. package/frontend-vue/layers/dms-ui/app/build/composables/live/shortcuts.ts +1 -1
  282. package/frontend-vue/layers/dms-ui/app/build/composables/live/usePageLiveHost.ts +17 -3
  283. package/frontend-vue/layers/dms-ui/app/build/composables/live/useUpdatedLabel.ts +38 -0
  284. package/frontend-vue/layers/dms-ui/app/build/composables/page-toolbar/pageToolbarContext.ts +75 -0
  285. package/frontend-vue/layers/dms-ui/app/build/composables/page-toolbar/toolbarControlHeight.ts +29 -0
  286. package/frontend-vue/layers/dms-ui/app/build/composables/period/periodComparison.ts +52 -0
  287. package/frontend-vue/layers/dms-ui/app/build/composables/period/periodDisplay.ts +21 -0
  288. package/frontend-vue/layers/dms-ui/app/build/composables/period/periodShortLabels.ts +28 -0
  289. package/frontend-vue/layers/dms-ui/app/build/composables/period/usePeriodDraft.ts +1 -0
  290. package/frontend-vue/layers/dms-ui/app/build/composables/table/useRelationFilterLabels.ts +73 -0
  291. package/frontend-vue/layers/dms-ui/app/build/composables/table/useRowScrollAnchor.ts +106 -0
  292. package/frontend-vue/layers/dms-ui/app/build/composables/table/useTable.ts +9 -0
  293. package/frontend-vue/layers/dms-ui/app/build/composables/table/useTableColumns.ts +1 -2
  294. package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/archivedCount.ts +31 -0
  295. package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/filterEditorValue.ts +38 -0
  296. package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/formatFilterValue.ts +33 -2
  297. package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/scrollEdges.ts +31 -0
  298. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useCardFields.ts +33 -0
  299. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useMobileDisplay.ts +48 -0
  300. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useScrolledPastTop.ts +41 -18
  301. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableFooter.ts +3 -2
  302. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableLinkedVisit.ts +78 -0
  303. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableLiveHold.ts +135 -22
  304. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableRows.ts +56 -25
  305. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViewRowActions.ts +77 -32
  306. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViews.ts +86 -10
  307. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/bulkActions.ts +14 -4
  308. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/card.ts +127 -2
  309. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/compareValues.ts +13 -0
  310. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/expandedRows.ts +28 -0
  311. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/groupedRows.ts +114 -1
  312. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/linkedArrival.ts +308 -0
  313. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/locateRow.ts +106 -0
  314. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/pageArrival.ts +34 -0
  315. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/pinnedRows.ts +17 -0
  316. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/quickFilters.ts +41 -33
  317. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/recordLink.ts +24 -8
  318. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/tableCounts.ts +113 -0
  319. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/tableQuery.ts +27 -4
  320. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/views.ts +22 -6
  321. package/frontend-vue/layers/dms-ui/app/build/utils/addressSuggestions.ts +49 -0
  322. package/frontend-vue/layers/dms-ui/app/build/utils/eyebrow.ts +12 -0
  323. package/frontend-vue/layers/dms-ui/app/build/utils/fieldOptionsI18n.ts +51 -11
  324. package/frontend-vue/layers/dms-ui/app/build/utils/inputWidth.ts +53 -0
  325. package/frontend-vue/layers/dms-ui/app/build/utils/numberAdjustment.ts +6 -3
  326. package/frontend-vue/layers/dms-ui/app/build/utils/relativeDate.ts +19 -5
  327. package/frontend-vue/layers/dms-ui/app/build/utils/scrollWithin.ts +99 -0
  328. package/frontend-vue/layers/dms-ui/app/build/utils/urlVariables.ts +36 -14
  329. package/frontend-vue/layers/dms-ui/app/components/PasswordStrength.vue +1 -1
  330. package/frontend-vue/layers/dms-ui/app/components/RecursiveComponent.vue +9 -1
  331. package/frontend-vue/layers/dms-ui/app/components/blocks/LiveToggleBlock.vue +80 -32
  332. package/frontend-vue/layers/dms-ui/app/components/blocks/PageToolbarBlock.vue +137 -0
  333. package/frontend-vue/layers/dms-ui/app/components/blocks/StatGroupBlock.vue +5 -0
  334. package/frontend-vue/layers/dms-ui/app/components/chart/ApexChartHost.vue +16 -2
  335. package/frontend-vue/layers/dms-ui/app/components/chart/Chart.vue +24 -5
  336. package/frontend-vue/layers/dms-ui/app/components/chart/ChartCard.vue +41 -23
  337. package/frontend-vue/layers/dms-ui/app/components/confirm/ConfirmModal.vue +1 -1
  338. package/frontend-vue/layers/dms-ui/app/components/container-footer/ContainerFooter.vue +34 -0
  339. package/frontend-vue/layers/dms-ui/app/components/field-row/FieldRow.vue +25 -2
  340. package/frontend-vue/layers/dms-ui/app/components/flow-canvas/FlowCanvas.vue +2 -2
  341. package/frontend-vue/layers/dms-ui/app/components/form/Form.vue +118 -36
  342. package/frontend-vue/layers/dms-ui/app/components/form/components/DatePicker.vue +20 -1
  343. package/frontend-vue/layers/dms-ui/app/components/form/components/Display.vue +13 -1
  344. package/frontend-vue/layers/dms-ui/app/components/form/components/Image.vue +8 -3
  345. package/frontend-vue/layers/dms-ui/app/components/form/components/InputAddress.vue +53 -5
  346. package/frontend-vue/layers/dms-ui/app/components/form/components/InputCode.vue +29 -5
  347. package/frontend-vue/layers/dms-ui/app/components/form/components/InputNumber.vue +45 -8
  348. package/frontend-vue/layers/dms-ui/app/components/form/components/InputPercentage.vue +28 -5
  349. package/frontend-vue/layers/dms-ui/app/components/form/components/InputSecret.vue +5 -0
  350. package/frontend-vue/layers/dms-ui/app/components/form/components/InputText.vue +19 -2
  351. package/frontend-vue/layers/dms-ui/app/components/form/components/InputTime.vue +2 -1
  352. package/frontend-vue/layers/dms-ui/app/components/form/components/Relation.vue +205 -65
  353. package/frontend-vue/layers/dms-ui/app/components/form/components/Repeater.vue +80 -30
  354. package/frontend-vue/layers/dms-ui/app/components/form/components/RepeaterTable.vue +203 -0
  355. package/frontend-vue/layers/dms-ui/app/components/form/components/Select.vue +4 -2
  356. package/frontend-vue/layers/dms-ui/app/components/grid/GridRow.vue +11 -2
  357. package/frontend-vue/layers/dms-ui/app/components/key-value-list/KeyValueList.vue +79 -70
  358. package/frontend-vue/layers/dms-ui/app/components/kpi/KpiCard.vue +117 -21
  359. package/frontend-vue/layers/dms-ui/app/components/meter/Meter.vue +2 -1
  360. package/frontend-vue/layers/dms-ui/app/components/period/PeriodSelector.vue +113 -34
  361. package/frontend-vue/layers/dms-ui/app/components/save-bar/SaveBar.vue +14 -2
  362. package/frontend-vue/layers/dms-ui/app/components/section-header/Eyebrow.vue +6 -1
  363. package/frontend-vue/layers/dms-ui/app/components/segmented/Segmented.vue +13 -0
  364. package/frontend-vue/layers/dms-ui/app/components/stat-group/StatGroup.vue +52 -3
  365. package/frontend-vue/layers/dms-ui/app/components/tab/Tab.vue +2 -1
  366. package/frontend-vue/layers/dms-ui/app/components/table-view/KanbanBoard.vue +45 -35
  367. package/frontend-vue/layers/dms-ui/app/components/table-view/KanbanDisplay.vue +4 -1
  368. package/frontend-vue/layers/dms-ui/app/components/table-view/TableView.vue +410 -96
  369. package/frontend-vue/layers/dms-ui/app/components/top-list/TopListCard.vue +33 -5
  370. package/frontend-vue/layers/dms-ui/app/composables/chart/apexCategoryLabels.ts +68 -0
  371. package/frontend-vue/layers/dms-ui/app/composables/chart/apexDatetimeBuckets.ts +306 -0
  372. package/frontend-vue/layers/dms-ui/app/composables/chart/formatValue.ts +4 -3
  373. package/frontend-vue/layers/dms-ui/app/composables/chart/heatmapColors.ts +93 -0
  374. package/frontend-vue/layers/dms-ui/app/composables/chart/localizeSeries.ts +62 -0
  375. package/frontend-vue/layers/dms-ui/app/composables/chart/useApexChart.ts +116 -8
  376. package/frontend-vue/layers/dms-ui/app/composables/chart/useApexChart.types.ts +7 -0
  377. package/frontend-vue/layers/dms-ui/app/composables/containers/types.ts +84 -1
  378. package/frontend-vue/layers/dms-ui/app/composables/containers/useDrawer.ts +69 -8
  379. package/frontend-vue/layers/dms-ui/app/composables/form/types/field-saved.ts +11 -0
  380. package/frontend-vue/layers/dms-ui/app/composables/form/types/field.ts +4 -0
  381. package/frontend-vue/layers/dms-ui/app/composables/form/types/functions.ts +1 -0
  382. package/frontend-vue/layers/dms-ui/app/composables/form/useForm.ts +142 -21
  383. package/frontend-vue/layers/dms-ui/app/composables/live/usePageLive.ts +11 -4
  384. package/frontend-vue/layers/dms-ui/app/composables/page-toolbar/usePageToolbarSize.ts +30 -0
  385. package/frontend-vue/layers/dms-ui/app/composables/table-view/kanban.ts +4 -2
  386. package/frontend-vue/layers/dms-ui/app/composables/table-view/types/action-target.ts +22 -3
  387. package/frontend-vue/layers/dms-ui/app/composables/table-view/types/config.ts +4 -0
  388. package/frontend-vue/layers/dms-ui/app/composables/table-view/types/display.ts +24 -1
  389. package/frontend-vue/layers/dms-ui/app/plugins/closing-layers.client.ts +10 -0
  390. package/frontend-vue/layers/dms-ui/app/plugins/live-pause-source.ts +15 -0
  391. package/frontend-vue/layers/dms-ui/app/plugins/register.ts +2 -0
  392. package/frontend-vue/layers/dms-ui/app/types/input-number.ts +3 -2
  393. package/frontend-vue/layers/dms-ui/app/types/page-toolbar.ts +7 -0
  394. package/frontend-vue/layers/dms-ui/app/types/row-action.ts +0 -2
  395. package/frontend-vue/layers/dms-ui/app/types/row-navigation.ts +17 -0
  396. package/frontend-vue/layers/dms-ui/app/types/table/query.ts +2 -1
  397. package/frontend-vue/layers/dms-ui/app/utils/blockRefresh.ts +3 -1
  398. package/frontend-vue/layers/dms-ui/app/utils/componentTree.ts +24 -0
  399. package/frontend-vue/layers/dms-ui/i18n/locales/ui-en-GB.json +16 -4
  400. package/frontend-vue/layers/dms-ui/i18n/locales/ui-fr-FR.json +16 -4
  401. package/frontend-vue/package.json +2 -2
  402. package/package.json +7 -6
  403. package/skills/dms/SKILL.md +1 -1
  404. package/skills/dms-auth/SKILL.md +5 -3
  405. package/skills/dms-best-practices/REFERENCE.md +2 -0
  406. package/skills/dms-best-practices/SKILL.md +4 -0
  407. package/skills/dms-module/SKILL.md +3 -2
  408. package/skills/dms-pages/REFERENCE.md +125 -16
  409. package/skills/dms-pages/SKILL.md +1 -1
  410. package/skills/dms-project/DEV-SERVERS.md +23 -1
  411. package/skills/dms-project/REFERENCE.md +1 -1
  412. package/skills/dms-project/SKILL.md +4 -1
  413. package/skills/dms-project/scripts/dms-dev.sh +205 -17
  414. package/frontend-vue/layers/dms-core/app/composables/period/periodRenderNow.ts +0 -42
@@ -1,24 +1,29 @@
1
1
  <script setup lang="ts">
2
2
  import ModuleTile from "./ModuleTile.vue";
3
+ import ModuleSourceLabel from "./ModuleSourceLabel.vue";
4
+ import ModuleStoreOperation from "./ModuleStoreOperation.vue";
3
5
  import ModuleStoreRequirements from "./ModuleStoreRequirements.vue";
4
6
  import {
5
7
  type ModuleStoreEntry,
6
8
  type StoreAction,
7
- type StoreActionBlock,
8
- storeActionBlock,
9
+ isInstalled,
9
10
  storeActions,
10
- storeTileStatus,
11
+ storeBlockMessage,
11
12
  } from "../../../utils/module-store-catalog";
12
- import type {
13
- StoreOperationKind,
14
- StoreOperationStep,
15
- } from "../../../../types/module-store";
13
+ import type { StoreOperationKind } from "../../../../types/module-store";
14
+
15
+ // A module of the catalog, as the store presents it: what it is, whether it
16
+ // is installed here, and Install when it is not. Everything else about an
17
+ // installed module is managed from its tile among the installed modules,
18
+ // which this one links to.
16
19
 
17
20
  interface ModuleStoreTileProps {
18
21
  /** The store module the tile presents. */
19
22
  entry: ModuleStoreEntry;
20
23
  /** Another module's operation runs: every action waits for it. */
21
24
  isLocked?: boolean;
25
+ /** Where the installed module's own tile is, the one that manages it. */
26
+ installedTo?: string;
22
27
  }
23
28
 
24
29
  interface ModuleStoreTileEmits {
@@ -27,131 +32,31 @@ interface ModuleStoreTileEmits {
27
32
 
28
33
  const props = withDefaults(defineProps<ModuleStoreTileProps>(), {
29
34
  isLocked: false,
35
+ installedTo: undefined,
30
36
  });
31
37
  const emit = defineEmits<ModuleStoreTileEmits>();
32
38
  const { t } = useI18n();
33
39
  const { processI18n } = useTranslation();
34
40
 
35
41
  const TOOLTIP_CONTENT = { side: "top", sideOffset: 6 } as const;
36
- /** The steps an operation shows, in the order they run. */
37
- const PROGRESS_STEPS: StoreOperationStep[] = [
38
- "resolve",
39
- "dependencies",
40
- "unload",
41
- "load",
42
- "save",
43
- ];
44
- /**
45
- * Steps an operation of this kind goes through. The file is written last:
46
- * it only ever names a module that loaded.
47
- */
48
- const KIND_STEPS: Record<StoreOperationKind, StoreOperationStep[]> = {
49
- install: ["resolve", "dependencies", "load", "save"],
50
- update: ["resolve", "unload", "load", "save"],
51
- enable: ["load", "save"],
52
- disable: ["unload", "save"],
53
- uninstall: ["unload", "save"],
54
- apply: ["load"],
55
- };
56
-
57
- const status = computed(() => storeTileStatus(props.entry));
58
- const actions = computed(() => storeActions(props.entry));
59
- const primary = computed<StoreAction | undefined>(() =>
60
- actions.value.find((action) => !action.isMenuOnly),
61
- );
62
- const secondary = computed(() =>
63
- actions.value
64
- .filter((action) => action !== primary.value)
65
- .map((action) => ({
66
- label: t(`modules.store.actions.${action.labelKey}`),
67
- icon: action.icon,
68
- color: action.kind === "uninstall" ? ("error" as const) : undefined,
69
- disabled: storeActionBlock(props.entry, action.kind) !== undefined,
70
- onSelect: () => emit("action", action.kind),
71
- })),
72
- );
73
-
74
- const isInstalledHere = computed(
75
- () => props.entry.installedVersion !== undefined,
42
+ const INSTALLED_STATUS = { tone: "primary", dot: "none" } as const;
43
+ const FOOTER_FACTS_CLASS = "flex min-w-0 items-center gap-2";
44
+
45
+ const isInstalledHere = computed(() => isInstalled(props.entry));
46
+ const isOperating = computed(() => props.entry.operation !== undefined);
47
+ /** Install, the one action a store tile offers, while it is not installed. */
48
+ const install = computed<StoreAction | undefined>(() =>
49
+ storeActions(props.entry).find((action) => action.kind === "install"),
76
50
  );
77
- const LIST_SEPARATOR = ", ";
78
-
79
- const BLOCK_MESSAGES: Record<StoreActionBlock, () => string> = {
80
- no_release: () => t("modules.store.no_release"),
81
- incompatible: () =>
82
- t("modules.store.incompatible", {
83
- range: props.entry.requiredInterfaceRange ?? "",
84
- }),
85
- frontend: () =>
86
- t("modules.store.frontend_requirement.needs", {
87
- range: props.entry.frontendRequirement?.range ?? "",
88
- running: props.entry.frontendRequirement?.running ?? "",
89
- }),
90
- interfaces: () =>
91
- t("modules.store.requires_first", {
92
- interfaces: props.entry.missingInterfaces
93
- .map((missing) => missing.interfacePackage)
94
- .join(LIST_SEPARATOR),
95
- }),
96
- dependents: () =>
97
- t("modules.store.used_by", {
98
- modules: props.entry.dependents.join(LIST_SEPARATOR),
99
- }),
100
- };
101
51
 
102
- /** Why the main action waits, when it does. */
52
+ /** Why Install waits, when it does. */
103
53
  const blockedReason = computed(() => {
54
+ if (!install.value) return undefined;
104
55
  if (props.isLocked) return t("modules.store.locked");
105
- if (!primary.value) return undefined;
106
- const block = storeActionBlock(props.entry, primary.value.kind);
107
- return block ? BLOCK_MESSAGES[block]() : undefined;
56
+ return storeBlockMessage(props.entry, install.value.kind, t);
108
57
  });
109
58
  const isBlocked = computed(() => blockedReason.value !== undefined);
110
59
 
111
- const operation = computed(() => props.entry.operation);
112
- /**
113
- * Whether the running install loads modules for missing interfaces. Kept
114
- * for the whole operation: once they run, the listing no longer misses them.
115
- */
116
- const isInstallingDependencies = ref(false);
117
- watch(
118
- operation,
119
- (running) => {
120
- if (!running) {
121
- isInstallingDependencies.value = false;
122
- return;
123
- }
124
- if (
125
- running.step === "dependencies" ||
126
- (running.kind === "install" && props.entry.missingInterfaces.length > 0)
127
- ) {
128
- isInstallingDependencies.value = true;
129
- }
130
- },
131
- { immediate: true },
132
- );
133
-
134
- const steps = computed(() => {
135
- const kind = operation.value?.kind;
136
- if (!kind) return [];
137
- const current = PROGRESS_STEPS.indexOf(operation.value.step);
138
- const kindSteps = KIND_STEPS[kind].filter(
139
- (step) => step !== "dependencies" || isInstallingDependencies.value,
140
- );
141
- return kindSteps.map((step) => {
142
- const index = PROGRESS_STEPS.indexOf(step);
143
- const state =
144
- index < current ? "done" : index === current ? "running" : "todo";
145
- return { step, state };
146
- });
147
- });
148
-
149
- const STEP_ICONS: Record<string, string> = {
150
- done: "i-ph-check-circle-fill",
151
- running: "i-ph-circle-notch",
152
- todo: "i-ph-circle",
153
- };
154
-
155
60
  const PLAIN_VERSION = /^\d/;
156
61
 
157
62
  /** A version as the footer shows it: `v1.2.3`, or a range as written. */
@@ -177,77 +82,72 @@ const versionLabel = computed(() => {
177
82
  :icon="props.entry.icon"
178
83
  :title="processI18n(props.entry.title)"
179
84
  :description="processI18n(props.entry.description)"
180
- :status="{
181
- tone: status.tone,
182
- dot: status.dot,
183
- label: t(`modules.store.state.${status.labelKey}`),
184
- }"
85
+ :status="
86
+ isInstalledHere
87
+ ? { ...INSTALLED_STATUS, label: t('modules.store.installed') }
88
+ : undefined
89
+ "
185
90
  :is-solid="isInstalledHere"
186
91
  >
187
- <!-- Running operation: its steps, the current one spinning. -->
188
- <ol
189
- v-if="steps.length > 0"
190
- class="flex flex-col gap-1 text-xs"
191
- :aria-label="t(`modules.store.progress.${operation?.kind}`)"
192
- >
193
- <li
194
- v-for="{ step, state } in steps"
195
- :key="step"
196
- class="flex items-center gap-1.5"
197
- :class="state === 'todo' ? 'text-dimmed' : 'text-toned'"
92
+ <ModuleStoreOperation :entry="props.entry" />
93
+
94
+ <template v-if="!isOperating">
95
+ <p v-if="props.entry.isWorkingCopy" class="text-dimmed text-xs">
96
+ {{ t("modules.store.working_copy_hint") }}
97
+ </p>
98
+
99
+ <!-- The npm package the module comes from. -->
100
+ <div
101
+ v-else-if="!isInstalledHere"
102
+ class="text-dimmed flex h-[30px] min-w-0 items-center rounded-[8px] border border-(--ui-border) bg-(--dms-bg-muted) px-2.5 font-mono text-[11.5px]"
103
+ :title="props.entry.package"
198
104
  >
199
- <UIcon
200
- :name="STEP_ICONS[state]"
201
- class="size-3.5 shrink-0"
202
- :class="{
203
- 'animate-spin text-(--ui-primary)': state === 'running',
204
- 'text-(--ui-success)': state === 'done',
205
- }"
206
- />
207
- {{ t(`modules.store.steps.${step}`) }}
208
- </li>
209
- </ol>
105
+ <span class="truncate">{{ props.entry.package }}</span>
106
+ </div>
210
107
 
211
- <p
212
- v-else-if="props.entry.state === 'error' && props.entry.error"
213
- class="rounded-[8px] bg-(--ui-error)/8 px-2.5 py-1.5 text-xs text-(--ui-error)"
214
- :title="props.entry.error"
215
- >
216
- <span class="line-clamp-3 break-words">{{ props.entry.error }}</span>
217
- </p>
108
+ <ModuleStoreRequirements v-if="!isInstalledHere" :entry="props.entry" />
218
109
 
219
- <p
220
- v-else-if="props.entry.state === 'pending'"
221
- class="text-xs text-(--ui-warning)"
222
- >
223
- {{ t("modules.store.pending_hint") }}
224
- </p>
225
-
226
- <!-- The npm package the module comes from. -->
227
- <div
228
- v-else
229
- class="text-dimmed flex h-[30px] min-w-0 items-center rounded-[8px] border border-(--ui-border) bg-(--dms-bg-muted) px-2.5 font-mono text-[11.5px]"
230
- :title="props.entry.package"
231
- >
232
- <span class="truncate">{{ props.entry.package }}</span>
233
- </div>
234
-
235
- <ModuleStoreRequirements v-if="steps.length === 0" :entry="props.entry" />
110
+ <ULink
111
+ v-if="isInstalledHere && props.installedTo"
112
+ :to="props.installedTo"
113
+ class="text-primary inline-flex items-center gap-1 text-xs font-semibold"
114
+ >
115
+ {{ t("modules.store.view_installed") }}
116
+ <UIcon name="i-ph-arrow-right" class="size-3.5" :aria-hidden="true" />
117
+ </ULink>
118
+ </template>
236
119
 
237
120
  <template #footer>
238
- <span class="truncate">
239
- {{ processI18n(props.entry.catalogCategory) }}
240
- </span>
241
- <span
242
- v-if="versionLabel"
243
- class="shrink-0"
244
- :class="props.entry.updateAvailable ? 'text-(--ui-warning)' : ''"
245
- >
246
- {{ versionLabel }}
121
+ <!-- v0.5.0 · npm · Content, as on an installed module's tile, and
122
+ kept whole the same way. -->
123
+ <span :class="FOOTER_FACTS_CLASS">
124
+ <span
125
+ v-if="versionLabel"
126
+ class="shrink-0"
127
+ :class="props.entry.updateAvailable ? 'text-(--ui-warning)' : ''"
128
+ >
129
+ {{ versionLabel }}
130
+ </span>
131
+ <span v-if="versionLabel" aria-hidden="true">·</span>
132
+ <ModuleSourceLabel :source="props.entry.source" />
133
+ <span class="min-w-0 truncate">
134
+ ·
135
+ {{ processI18n(props.entry.catalogCategory) }}
136
+ </span>
247
137
  </span>
248
138
  <span class="ms-auto flex shrink-0 items-center gap-1 font-sans">
139
+ <!-- An update is made where the module is managed. -->
140
+ <UButton
141
+ v-if="isInstalledHere && props.entry.updateAvailable"
142
+ :to="props.installedTo"
143
+ size="xs"
144
+ color="warning"
145
+ variant="soft"
146
+ icon="i-ph-arrow-circle-up"
147
+ :label="t('modules.store.update_available')"
148
+ />
249
149
  <UTooltip
250
- v-if="primary"
150
+ v-else-if="install"
251
151
  :text="blockedReason"
252
152
  :disabled="!blockedReason"
253
153
  :content="TOOLTIP_CONTENT"
@@ -256,37 +156,15 @@ const versionLabel = computed(() => {
256
156
  tooltip, which says why it waits. -->
257
157
  <UButton
258
158
  size="xs"
259
- :color="primary.kind === 'update' ? 'warning' : 'neutral'"
260
- :variant="primary.kind === 'install' ? 'solid' : 'outline'"
261
- :icon="primary.icon"
262
- :label="t(`modules.store.actions.${primary.labelKey}`)"
159
+ color="neutral"
160
+ variant="solid"
161
+ :icon="install.icon"
162
+ :label="t(`modules.store.actions.${install.labelKey}`)"
263
163
  :aria-disabled="isBlocked ? 'true' : undefined"
264
164
  :class="{ 'cursor-not-allowed opacity-50': isBlocked }"
265
- @click="!isBlocked && emit('action', primary.kind)"
165
+ @click="!isBlocked && emit('action', install.kind)"
266
166
  />
267
167
  </UTooltip>
268
- <UDropdownMenu
269
- v-if="secondary.length > 0 && !props.isLocked"
270
- :items="secondary"
271
- :content="{ align: 'end' }"
272
- >
273
- <UButton
274
- v-if="primary"
275
- size="xs"
276
- color="neutral"
277
- variant="ghost"
278
- icon="i-ph-dots-three-vertical"
279
- :aria-label="t('modules.store.more_actions')"
280
- />
281
- <UButton
282
- v-else
283
- size="xs"
284
- color="neutral"
285
- variant="outline"
286
- trailing-icon="i-ph-caret-down"
287
- :label="t('modules.store.actions.manage')"
288
- />
289
- </UDropdownMenu>
290
168
  </span>
291
169
  </template>
292
170
  </ModuleTile>
@@ -20,7 +20,8 @@ interface ModuleTileProps {
20
20
  icon: string;
21
21
  title: string;
22
22
  description: string;
23
- status: ModuleTileStatus;
23
+ /** The pill of the tile's head; a tile without one shows none. */
24
+ status?: ModuleTileStatus;
24
25
  /** Where the tile leads; without it, the tile is a placeholder. */
25
26
  to?: string;
26
27
  /**
@@ -35,11 +36,16 @@ interface ModuleTileSlots {
35
36
  readout?: () => unknown;
36
37
  /** Under the description (an install command). */
37
38
  default?: () => unknown;
38
- /** The footer band's content. */
39
+ /**
40
+ * The footer band's content. The band wraps: a facts group (version,
41
+ * source, category) kept whole, then actions pushed to the end with
42
+ * `ms-auto`, which drop to a second line when both do not fit.
43
+ */
39
44
  footer: () => unknown;
40
45
  }
41
46
 
42
47
  const props = withDefaults(defineProps<ModuleTileProps>(), {
48
+ status: undefined,
43
49
  to: undefined,
44
50
  isSolid: false,
45
51
  });
@@ -49,7 +55,7 @@ const theme = tv({
49
55
  slots: {
50
56
  root: "flex min-h-[228px] flex-col gap-3 overflow-hidden px-4 pt-4",
51
57
  footer:
52
- "text-dimmed -mx-4 mt-auto flex items-center gap-2 border-t border-(--ui-border-muted) ps-4 pe-3 font-mono text-[11px] font-medium",
58
+ "text-dimmed -mx-4 mt-auto flex flex-wrap items-center gap-x-2 gap-y-1.5 border-t border-(--ui-border-muted) ps-4 pe-3 font-mono text-[11px] font-medium",
53
59
  },
54
60
  variants: {
55
61
  isPlaceholder: {
@@ -91,6 +97,7 @@ const ui = computed(() =>
91
97
  :tone="props.to || props.isSolid ? undefined : 'muted'"
92
98
  />
93
99
  <DmsStatusPill
100
+ v-if="props.status"
94
101
  :tone="props.status.tone"
95
102
  :dot="props.status.dot"
96
103
  :label="props.status.label"
@@ -0,0 +1,68 @@
1
+ <script setup lang="ts">
2
+ // The placeholder of a ModuleTile while the grid loads, block for block the
3
+ // tile's size: the 36px icon well and the 20px pill, the title's 28px line,
4
+ // two description lines, and the footer band with its xs button. Nothing
5
+ // moves once the tiles replace it.
6
+
7
+ interface ModuleTileSkeletonProps {
8
+ /**
9
+ * A store tile still to install: no status pill, and the 30px npm package
10
+ * line under the description.
11
+ */
12
+ isStore?: boolean;
13
+ }
14
+
15
+ const props = withDefaults(defineProps<ModuleTileSkeletonProps>(), {
16
+ isStore: false,
17
+ });
18
+
19
+ const { t } = useI18n();
20
+ </script>
21
+
22
+ <template>
23
+ <div
24
+ class="dms-card flex min-h-[228px] flex-col gap-3 overflow-hidden px-4 pt-4"
25
+ aria-hidden="true"
26
+ >
27
+ <div class="flex items-start justify-between gap-2.5">
28
+ <USkeleton
29
+ :aria-label="t('dms.a11y.loading')"
30
+ class="size-9 rounded-[10px]"
31
+ />
32
+ <USkeleton
33
+ v-if="!props.isStore"
34
+ :aria-label="t('dms.a11y.loading')"
35
+ class="h-5 w-16 rounded-full"
36
+ />
37
+ </div>
38
+
39
+ <div class="flex h-7 items-center">
40
+ <USkeleton :aria-label="t('dms.a11y.loading')" class="h-4 w-2/5" />
41
+ </div>
42
+ <!-- The description's two lines, each its line height tall. -->
43
+ <div class="-mt-1.5 text-sm leading-[1.45]">
44
+ <div class="flex h-[1.45em] items-center">
45
+ <USkeleton :aria-label="t('dms.a11y.loading')" class="h-3 w-full" />
46
+ </div>
47
+ <div class="flex h-[1.45em] items-center">
48
+ <USkeleton :aria-label="t('dms.a11y.loading')" class="h-3 w-3/5" />
49
+ </div>
50
+ </div>
51
+
52
+ <USkeleton
53
+ v-if="props.isStore"
54
+ :aria-label="t('dms.a11y.loading')"
55
+ class="h-[30px] rounded-[8px]"
56
+ />
57
+
58
+ <div
59
+ class="-mx-4 mt-auto flex items-center justify-between gap-2 border-t border-(--ui-border-muted) bg-(--dms-bg-muted) py-[7px] ps-4 pe-3"
60
+ >
61
+ <USkeleton :aria-label="t('dms.a11y.loading')" class="h-3 w-24" />
62
+ <USkeleton
63
+ :aria-label="t('dms.a11y.loading')"
64
+ class="h-6 w-16 rounded-md"
65
+ />
66
+ </div>
67
+ </div>
68
+ </template>
@@ -4,6 +4,7 @@ import { formatRelativeTime } from "#dms-core/app/utils/formatter";
4
4
  import TableEmpty from "#dms-ui/app/build/components/table/Empty.vue";
5
5
  import TablePagination from "#dms-ui/app/build/components/table/Pagination.vue";
6
6
  import type { TableViewDisplayContext } from "#dms-ui/app/composables/table-view/types/display";
7
+ import { useConfirm } from "#dms-ui/app/composables/confirm";
7
8
  import { useNotificationCatalog } from "../../../../composables/notification/useNotificationCatalog";
8
9
  import {
9
10
  type UserNotification,
@@ -31,6 +32,7 @@ const SKELETON_ROWS = 3;
31
32
 
32
33
  const { t, locale } = useI18n();
33
34
  const toast = useToast();
35
+ const { confirm } = useConfirm();
34
36
  const catalog = useNotificationCatalog();
35
37
  const {
36
38
  unreadCount,
@@ -97,16 +99,30 @@ const toggleRead = (notification: UserNotification) =>
97
99
  : markAsRead(notification._id),
98
100
  );
99
101
 
102
+ // A deletion cannot be undone, and its button sits next to Mark read: it is
103
+ // asked first, as "Delete all" is, with the safe answer focused.
104
+ const removeNotification = async (notification: UserNotification) => {
105
+ const isConfirmed = await confirm({
106
+ title: t("page.settings.notifications.delete_one_title"),
107
+ description: t("page.settings.notifications.delete_one_description"),
108
+ icon: "i-ph-trash",
109
+ color: "error",
110
+ confirmIcon: "i-ph-trash",
111
+ confirmLabel: t("page.settings.notifications.delete"),
112
+ cancelLabel: t("page.settings.notifications.cancel"),
113
+ initialFocus: "cancel",
114
+ });
115
+ if (isConfirmed) {
116
+ await runThenRefresh(() => deleteNotification(notification._id));
117
+ }
118
+ };
119
+
100
120
  // What the stream changes elsewhere (a notification arriving, read in
101
121
  // another tab) is listed again here: once per change of the count or of the
102
122
  // newest notification, not each time the bell's lists are rebuilt.
103
- watch(
104
- [unreadCount, () => notifications.value[0]?._id],
105
- () => {
106
- if (ownChanges === 0) void props.context.refresh();
107
- },
108
- );
109
-
123
+ watch([unreadCount, () => notifications.value[0]?._id], () => {
124
+ if (ownChanges === 0) void props.context.refresh();
125
+ });
110
126
  </script>
111
127
 
112
128
  <template>
@@ -136,7 +152,7 @@ watch(
136
152
  :source="sourceOf(notification)"
137
153
  @open="openNotification(notification)"
138
154
  @toggle-read="toggleRead(notification)"
139
- @delete="runThenRefresh(() => deleteNotification(notification._id))"
155
+ @delete="removeNotification(notification)"
140
156
  />
141
157
  </section>
142
158
  </template>
@@ -32,12 +32,15 @@ const readToggleLabel = computed(() =>
32
32
  ? t("page.settings.notifications.mark_read")
33
33
  : t("page.settings.notifications.mark_unread"),
34
34
  );
35
- // Row actions stay compact until the row is hovered or holds focus, then
36
- // show their labels (v2 C07).
37
- // Hover or focus spells the actions out, except on phones: a tap focuses
38
- // the row, and the labels would squeeze the text there.
35
+ // Row actions stay quiet until the row is hovered or holds focus, then
36
+ // show their labels (v2 C07). The labels only fade in: they keep their room
37
+ // laid out, so the buttons never move under the pointer on the way to one
38
+ // (a label appearing used to slide Delete under a Mark read click). Phones
39
+ // show the icons alone: a tap focuses the row, and the labels would squeeze
40
+ // the text there.
39
41
  const actionLabelUi = {
40
- label: "hidden sm:group-hover:inline sm:group-focus-within:inline",
42
+ label:
43
+ "hidden sm:inline sm:opacity-0 sm:transition-opacity sm:duration-150 sm:group-hover:opacity-100 sm:group-focus-within:opacity-100",
41
44
  };
42
45
  </script>
43
46
 
@@ -54,6 +54,7 @@ const options = computed(() => [
54
54
  :filter-fields="['label', 'value', 'offset']"
55
55
  :search-input="{ placeholder: t('page.settings.region.time_zone_search') }"
56
56
  :virtualize="{ estimateSize: ITEM_HEIGHT }"
57
+ :aria-label="t('dms.a11y.show_options')"
57
58
  >
58
59
  <template #item-trailing="{ item }">
59
60
  <span class="text-dimmed font-mono text-[11px]">{{ item.offset }}</span>
@@ -393,6 +393,25 @@ export function revokePermission(
393
393
  return remaining;
394
394
  }
395
395
 
396
+ /**
397
+ * The "added automatically" hints still true of a selection: a node no
398
+ * longer granted loses its hint, and a hint stops naming what is no longer
399
+ * granted, so a revoke that cascades (unticking a list takes the edit that
400
+ * had added it) leaves no hint on an unticked row.
401
+ */
402
+ export function keepGrantedAutoAdded(
403
+ autoAdded: Map<string, string[]>,
404
+ selection: Set<string>,
405
+ ): Map<string, string[]> {
406
+ const kept = new Map<string, string[]>();
407
+ for (const [id, added] of autoAdded) {
408
+ if (!selection.has(id)) continue;
409
+ const granted = added.filter((addedId) => selection.has(addedId));
410
+ if (granted.length > 0) kept.set(id, granted);
411
+ }
412
+ return kept;
413
+ }
414
+
396
415
  function matchesQuery(
397
416
  node: RolePermissionNode,
398
417
  query: string,
@@ -5,6 +5,7 @@ import {
5
5
  buildPermissionIndex,
6
6
  diffPermissions,
7
7
  grantPermission,
8
+ keepGrantedAutoAdded,
8
9
  revokePermission,
9
10
  } from "./role-permissions";
10
11
  import {
@@ -173,7 +174,7 @@ export function useRoleEditor(data: Ref<RolesPageData | null>) {
173
174
  } else {
174
175
  selection.value = revokePermission(index.value, selection.value, id);
175
176
  }
176
- autoAdded.value = nextAutoAdded;
177
+ autoAdded.value = keepGrantedAutoAdded(nextAutoAdded, selection.value);
177
178
  }
178
179
 
179
180
  const payload = computed<RoleDraft>(() => ({