@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
@@ -0,0 +1,73 @@
1
+ <script setup lang="ts">
2
+ import { MONO_CHIP_CLASS } from "#dms-ui/app/build/utils/monoChip";
3
+ import { FRONTEND_BUILD_COMMAND } from "../../../utils/module-store-catalog";
4
+ import type { StoreListing } from "../../../../types/module-store";
5
+ import type { StoreFrontendNotice } from "../../../../composables/page/useModuleStoreActions";
6
+
7
+ // What keeps the store from changing modules here, and what follows a
8
+ // change while the interface lags behind the backend: shown above the
9
+ // installed modules and the store alike.
10
+
11
+ interface ModuleStoreBannersProps {
12
+ listing: StoreListing | undefined;
13
+ frontendNotice: StoreFrontendNotice | null;
14
+ }
15
+
16
+ const props = defineProps<ModuleStoreBannersProps>();
17
+ const { t } = useI18n();
18
+ </script>
19
+
20
+ <template>
21
+ <DmsBanner
22
+ v-if="props.listing?.configError"
23
+ class="mb-4"
24
+ tone="error"
25
+ size="sm"
26
+ icon="i-ph-file-x"
27
+ :title="t('modules.store.config_error')"
28
+ :description="props.listing.configError"
29
+ />
30
+ <DmsBanner
31
+ v-else-if="props.listing && !props.listing.enabled"
32
+ class="mb-4"
33
+ tone="info"
34
+ size="sm"
35
+ icon="i-ph-lock-simple"
36
+ :title="t('modules.store.disabled.title')"
37
+ :description="t('modules.store.disabled.description')"
38
+ />
39
+
40
+ <!-- The interface lags behind the backend: say what follows. -->
41
+ <DmsBanner
42
+ v-if="props.frontendNotice"
43
+ class="mb-4"
44
+ :tone="props.frontendNotice.key === 'dev' ? 'info' : 'warning'"
45
+ size="sm"
46
+ :icon="
47
+ props.frontendNotice.key === 'dev'
48
+ ? 'i-ph-circle-notch'
49
+ : 'i-ph-arrows-clockwise'
50
+ "
51
+ :title="
52
+ t(`modules.store.frontend.${props.frontendNotice.key}.title`, {
53
+ modules: props.frontendNotice.names,
54
+ })
55
+ "
56
+ >
57
+ <template #description>
58
+ <i18n-t
59
+ :keypath="`modules.store.frontend.${props.frontendNotice.key}.description`"
60
+ scope="global"
61
+ tag="span"
62
+ >
63
+ <template #command>
64
+ <code
65
+ :class="[MONO_CHIP_CLASS, 'bg-elevated text-highlighted text-xs']"
66
+ >
67
+ {{ FRONTEND_BUILD_COMMAND }}
68
+ </code>
69
+ </template>
70
+ </i18n-t>
71
+ </template>
72
+ </DmsBanner>
73
+ </template>
@@ -0,0 +1,116 @@
1
+ <script setup lang="ts">
2
+ import type { ModuleStoreEntry } from "../../../utils/module-store-catalog";
3
+ import type {
4
+ StoreOperationKind,
5
+ StoreOperationStep,
6
+ } from "../../../../types/module-store";
7
+
8
+ // What the store is doing to a module, on whichever tile shows it: the steps
9
+ // of the running operation, the current one spinning, or the error the last
10
+ // one left.
11
+
12
+ interface ModuleStoreOperationProps {
13
+ entry: ModuleStoreEntry;
14
+ }
15
+
16
+ const props = defineProps<ModuleStoreOperationProps>();
17
+ const { t } = useI18n();
18
+
19
+ /** The steps an operation shows, in the order they run. */
20
+ const PROGRESS_STEPS: StoreOperationStep[] = [
21
+ "resolve",
22
+ "dependencies",
23
+ "unload",
24
+ "load",
25
+ "save",
26
+ ];
27
+ /**
28
+ * Steps an operation of this kind goes through. The file is written last:
29
+ * it only ever names a module that loaded.
30
+ */
31
+ const KIND_STEPS: Record<StoreOperationKind, StoreOperationStep[]> = {
32
+ install: ["resolve", "dependencies", "load", "save"],
33
+ update: ["resolve", "unload", "load", "save"],
34
+ enable: ["load", "save"],
35
+ disable: ["unload", "save"],
36
+ uninstall: ["unload", "save"],
37
+ apply: ["load"],
38
+ };
39
+
40
+ const STEP_ICONS: Record<string, string> = {
41
+ done: "i-ph-check-circle-fill",
42
+ running: "i-ph-circle-notch",
43
+ todo: "i-ph-circle",
44
+ };
45
+
46
+ const operation = computed(() => props.entry.operation);
47
+ /**
48
+ * Whether the running install loads modules for missing interfaces. Kept
49
+ * for the whole operation: once they run, the listing no longer misses them.
50
+ */
51
+ const isInstallingDependencies = ref(false);
52
+ watch(
53
+ operation,
54
+ (running) => {
55
+ if (!running) {
56
+ isInstallingDependencies.value = false;
57
+ return;
58
+ }
59
+ if (
60
+ running.step === "dependencies" ||
61
+ (running.kind === "install" && props.entry.missingInterfaces.length > 0)
62
+ ) {
63
+ isInstallingDependencies.value = true;
64
+ }
65
+ },
66
+ { immediate: true },
67
+ );
68
+
69
+ const steps = computed(() => {
70
+ const kind = operation.value?.kind;
71
+ if (!kind) return [];
72
+ const current = PROGRESS_STEPS.indexOf(operation.value.step);
73
+ const kindSteps = KIND_STEPS[kind].filter(
74
+ (step) => step !== "dependencies" || isInstallingDependencies.value,
75
+ );
76
+ return kindSteps.map((step) => {
77
+ const index = PROGRESS_STEPS.indexOf(step);
78
+ const state =
79
+ index < current ? "done" : index === current ? "running" : "todo";
80
+ return { step, state };
81
+ });
82
+ });
83
+ </script>
84
+
85
+ <template>
86
+ <ol
87
+ v-if="steps.length > 0"
88
+ class="flex flex-col gap-1 text-xs"
89
+ :aria-label="t(`modules.store.progress.${operation?.kind}`)"
90
+ >
91
+ <li
92
+ v-for="{ step, state } in steps"
93
+ :key="step"
94
+ class="flex items-center gap-1.5"
95
+ :class="state === 'todo' ? 'text-dimmed' : 'text-toned'"
96
+ >
97
+ <UIcon
98
+ :name="STEP_ICONS[state]"
99
+ class="size-3.5 shrink-0"
100
+ :class="{
101
+ 'animate-spin text-(--ui-primary)': state === 'running',
102
+ 'text-(--ui-success)': state === 'done',
103
+ }"
104
+ />
105
+ {{ t(`modules.store.steps.${step}`) }}
106
+ </li>
107
+ </ol>
108
+
109
+ <p
110
+ v-else-if="props.entry.state === 'error' && props.entry.error"
111
+ class="rounded-[8px] bg-(--ui-error)/8 px-2.5 py-1.5 text-xs text-(--ui-error)"
112
+ :title="props.entry.error"
113
+ >
114
+ <span class="line-clamp-3 break-words">{{ props.entry.error }}</span>
115
+ </p>
116
+ </template>
@@ -18,7 +18,10 @@ const missingInterfaces = computed(() =>
18
18
  .map((missing) => missing.interfacePackage)
19
19
  .join(LIST_SEPARATOR),
20
20
  );
21
- const dependents = computed(() => props.entry.dependents.join(LIST_SEPARATOR));
21
+ // A working copy offers no action, so who uses it changes nothing there.
22
+ const dependents = computed(() =>
23
+ props.entry.isWorkingCopy ? "" : props.entry.dependents.join(LIST_SEPARATOR),
24
+ );
22
25
  </script>
23
26
 
24
27
  <template>
@@ -92,7 +95,9 @@ const dependents = computed(() => props.entry.dependents.join(LIST_SEPARATOR));
92
95
  {{ t("modules.store.requires", { interfaces: missingInterfaces }) }}
93
96
  </p>
94
97
 
95
- <p v-if="dependents" class="text-xs text-(--ui-warning)">
96
- {{ t("modules.store.used_by", { modules: dependents }) }}
98
+ <!-- Informative only: what it takes to pause or remove the module is
99
+ said in the Manage menu, where those actions are. -->
100
+ <p v-if="dependents" class="text-dimmed truncate text-xs" :title="dependents">
101
+ {{ t("modules.store.dependents", { modules: dependents }) }}
97
102
  </p>
98
103
  </template>
@@ -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"