@byline/host-tanstack-start 4.19.0 → 5.1.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 (322) hide show
  1. package/dist/admin-shell/chrome/admin-app-bar.d.ts +7 -0
  2. package/dist/admin-shell/chrome/admin-app-bar.js +10 -2
  3. package/dist/admin-shell/chrome/session-change-boundary.d.ts +14 -0
  4. package/dist/admin-shell/chrome/session-change-boundary.js +87 -0
  5. package/dist/admin-shell/chrome/session-change-boundary.test.d.ts +8 -0
  6. package/dist/admin-shell/chrome/sign-in-page.d.ts +2 -1
  7. package/dist/admin-shell/chrome/sign-in-page.js +60 -3
  8. package/dist/admin-shell/collections/edit.d.ts +1 -1
  9. package/dist/admin-shell/collections/edit.js +151 -31
  10. package/dist/admin-shell/collections/history.js +4 -2
  11. package/dist/admin-shell/collections/list.js +30 -6
  12. package/dist/admin-shell/collections/restore-version-modal.d.ts +3 -1
  13. package/dist/admin-shell/collections/restore-version-modal.js +9 -4
  14. package/dist/admin-shell/collections/tree-list.js +16 -6
  15. package/dist/admin-shell/collections/version-history.d.ts +2 -1
  16. package/dist/admin-shell/collections/version-history.js +11 -2
  17. package/dist/admin-shell/document-mutation-notice.d.ts +6 -0
  18. package/dist/admin-shell/document-mutation-notice.js +53 -0
  19. package/dist/admin-shell/document-mutation-state.d.ts +22 -0
  20. package/dist/admin-shell/document-mutation-state.js +71 -0
  21. package/dist/admin-shell/document-mutation-state.test.d.ts +1 -0
  22. package/dist/admin-shell/scheduled-publications/list.js +15 -5
  23. package/dist/admin-shell/singletons/history.js +4 -2
  24. package/dist/admin-shell/singletons/view.d.ts +1 -1
  25. package/dist/admin-shell/singletons/view.js +98 -19
  26. package/dist/integrations/byline-admin-services.js +7 -1
  27. package/dist/integrations/byline-field-services.js +2 -9
  28. package/dist/integrations/client-ip.d.ts +19 -0
  29. package/dist/integrations/client-ip.js +34 -0
  30. package/dist/integrations/session-coordination.d.ts +24 -0
  31. package/dist/integrations/session-coordination.js +85 -0
  32. package/dist/integrations/session-middleware.d.ts +11 -0
  33. package/dist/integrations/session-middleware.js +94 -0
  34. package/dist/integrations/session-request-kind.d.ts +9 -0
  35. package/dist/integrations/session-request-kind.js +10 -0
  36. package/dist/integrations/session-request-middleware.d.ts +9 -0
  37. package/dist/integrations/session-request-middleware.js +7 -0
  38. package/dist/integrations/sign-in-body.d.ts +12 -0
  39. package/dist/integrations/sign-in-body.js +52 -0
  40. package/dist/integrations/sign-in-middleware.d.ts +9 -0
  41. package/dist/integrations/sign-in-middleware.js +10 -0
  42. package/dist/routes/create-admin-layout-route.js +46 -31
  43. package/dist/routes/create-collection-edit-route.js +1 -1
  44. package/dist/routes/create-collection-list-route.d.ts +0 -7
  45. package/dist/routes/create-collection-list-route.js +7 -9
  46. package/dist/routes/create-sign-in-route.js +4 -2
  47. package/dist/routes/create-singleton-route.d.ts +2 -0
  48. package/dist/routes/create-singleton-route.js +4 -3
  49. package/dist/server-fns/admin-account/change-password.d.ts +3 -1
  50. package/dist/server-fns/admin-account/change-password.js +9 -3
  51. package/dist/server-fns/admin-account/get.d.ts +3 -1
  52. package/dist/server-fns/admin-account/get.js +4 -1
  53. package/dist/server-fns/admin-account/index.d.ts +5 -5
  54. package/dist/server-fns/admin-account/update.d.ts +3 -1
  55. package/dist/server-fns/admin-account/update.js +4 -1
  56. package/dist/server-fns/admin-activity/get.d.ts +3 -1
  57. package/dist/server-fns/admin-activity/get.js +4 -1
  58. package/dist/server-fns/admin-permissions/get-role-abilities.d.ts +3 -1
  59. package/dist/server-fns/admin-permissions/get-role-abilities.js +4 -1
  60. package/dist/server-fns/admin-permissions/index.d.ts +4 -4
  61. package/dist/server-fns/admin-permissions/list-registered.d.ts +3 -1
  62. package/dist/server-fns/admin-permissions/list-registered.js +4 -1
  63. package/dist/server-fns/admin-permissions/set-role-abilities.d.ts +3 -1
  64. package/dist/server-fns/admin-permissions/set-role-abilities.js +4 -1
  65. package/dist/server-fns/admin-permissions/who-has.d.ts +3 -1
  66. package/dist/server-fns/admin-permissions/who-has.js +4 -1
  67. package/dist/server-fns/admin-roles/create.d.ts +3 -1
  68. package/dist/server-fns/admin-roles/create.js +4 -1
  69. package/dist/server-fns/admin-roles/delete.d.ts +3 -1
  70. package/dist/server-fns/admin-roles/delete.js +4 -1
  71. package/dist/server-fns/admin-roles/get.d.ts +3 -1
  72. package/dist/server-fns/admin-roles/get.js +4 -1
  73. package/dist/server-fns/admin-roles/index.d.ts +6 -6
  74. package/dist/server-fns/admin-roles/list.d.ts +3 -1
  75. package/dist/server-fns/admin-roles/list.js +4 -1
  76. package/dist/server-fns/admin-roles/reorder.d.ts +3 -1
  77. package/dist/server-fns/admin-roles/reorder.js +4 -1
  78. package/dist/server-fns/admin-roles/update.d.ts +3 -1
  79. package/dist/server-fns/admin-roles/update.js +4 -1
  80. package/dist/server-fns/admin-users/create.d.ts +3 -1
  81. package/dist/server-fns/admin-users/create.js +4 -1
  82. package/dist/server-fns/admin-users/delete.d.ts +3 -1
  83. package/dist/server-fns/admin-users/delete.js +4 -1
  84. package/dist/server-fns/admin-users/disable.d.ts +3 -1
  85. package/dist/server-fns/admin-users/disable.js +4 -1
  86. package/dist/server-fns/admin-users/enable.d.ts +3 -1
  87. package/dist/server-fns/admin-users/enable.js +4 -1
  88. package/dist/server-fns/admin-users/get-user-roles.d.ts +3 -1
  89. package/dist/server-fns/admin-users/get-user-roles.js +4 -1
  90. package/dist/server-fns/admin-users/get.d.ts +3 -1
  91. package/dist/server-fns/admin-users/get.js +4 -1
  92. package/dist/server-fns/admin-users/index.d.ts +10 -10
  93. package/dist/server-fns/admin-users/list.d.ts +3 -1
  94. package/dist/server-fns/admin-users/list.js +4 -1
  95. package/dist/server-fns/admin-users/set-password.d.ts +3 -1
  96. package/dist/server-fns/admin-users/set-password.js +4 -1
  97. package/dist/server-fns/admin-users/set-user-roles.d.ts +3 -1
  98. package/dist/server-fns/admin-users/set-user-roles.js +4 -1
  99. package/dist/server-fns/admin-users/update.d.ts +3 -1
  100. package/dist/server-fns/admin-users/update.js +4 -1
  101. package/dist/server-fns/ai/execute.d.ts +3 -1
  102. package/dist/server-fns/ai/execute.js +4 -1
  103. package/dist/server-fns/ai/index.d.ts +1 -1
  104. package/dist/server-fns/analytics/maintenance.d.ts +6 -2
  105. package/dist/server-fns/analytics/maintenance.js +7 -2
  106. package/dist/server-fns/analytics/queries.d.ts +18 -6
  107. package/dist/server-fns/analytics/queries.js +19 -6
  108. package/dist/server-fns/auth/current-user.d.ts +1 -0
  109. package/dist/server-fns/auth/current-user.js +5 -2
  110. package/dist/server-fns/auth/renew.d.ts +13 -0
  111. package/dist/server-fns/auth/renew.js +45 -0
  112. package/dist/server-fns/auth/sign-in.d.ts +2 -1
  113. package/dist/server-fns/auth/sign-in.js +88 -17
  114. package/dist/server-fns/auth/sign-out.d.ts +3 -1
  115. package/dist/server-fns/auth/sign-out.js +38 -6
  116. package/dist/server-fns/collections/audit.d.ts +3 -1
  117. package/dist/server-fns/collections/audit.js +4 -1
  118. package/dist/server-fns/collections/copy-to-locale.d.ts +5 -1
  119. package/dist/server-fns/collections/copy-to-locale.js +7 -2
  120. package/dist/server-fns/collections/create.d.ts +4 -1
  121. package/dist/server-fns/collections/create.js +8 -3
  122. package/dist/server-fns/collections/delete-locale.d.ts +5 -1
  123. package/dist/server-fns/collections/delete-locale.js +7 -2
  124. package/dist/server-fns/collections/delete-outcome.d.ts +7 -3
  125. package/dist/server-fns/collections/delete-outcome.js +4 -0
  126. package/dist/server-fns/collections/delete.d.ts +5 -1
  127. package/dist/server-fns/collections/delete.js +8 -3
  128. package/dist/server-fns/collections/duplicate.d.ts +5 -1
  129. package/dist/server-fns/collections/duplicate.js +8 -3
  130. package/dist/server-fns/collections/get.d.ts +1 -0
  131. package/dist/server-fns/collections/get.js +12 -6
  132. package/dist/server-fns/collections/history.d.ts +3 -1
  133. package/dist/server-fns/collections/history.js +4 -1
  134. package/dist/server-fns/collections/index.d.ts +21 -21
  135. package/dist/server-fns/collections/list.d.ts +3 -1
  136. package/dist/server-fns/collections/list.js +15 -4
  137. package/dist/server-fns/collections/reindex.d.ts +3 -1
  138. package/dist/server-fns/collections/reindex.js +4 -1
  139. package/dist/server-fns/collections/reorder.d.ts +10 -2
  140. package/dist/server-fns/collections/reorder.js +23 -76
  141. package/dist/server-fns/collections/restore-version.d.ts +6 -1
  142. package/dist/server-fns/collections/restore-version.js +8 -2
  143. package/dist/server-fns/collections/save-outcome.d.ts +1 -0
  144. package/dist/server-fns/collections/save-outcome.js +1 -0
  145. package/dist/server-fns/collections/scheduled-publication.d.ts +64 -7
  146. package/dist/server-fns/collections/scheduled-publication.js +42 -21
  147. package/dist/server-fns/collections/set-list-view-preference.d.ts +3 -1
  148. package/dist/server-fns/collections/set-list-view-preference.js +4 -1
  149. package/dist/server-fns/collections/stats.js +4 -1
  150. package/dist/server-fns/collections/status.d.ts +14 -2
  151. package/dist/server-fns/collections/status.js +18 -5
  152. package/dist/server-fns/collections/tree-mutation.d.ts +7 -6
  153. package/dist/server-fns/collections/tree-mutation.js +17 -5
  154. package/dist/server-fns/collections/tree.d.ts +29 -6
  155. package/dist/server-fns/collections/tree.js +32 -17
  156. package/dist/server-fns/collections/update.d.ts +18 -6
  157. package/dist/server-fns/collections/update.js +39 -20
  158. package/dist/server-fns/collections/upload.d.ts +11 -1
  159. package/dist/server-fns/collections/upload.js +6 -2
  160. package/dist/server-fns/document-mutation-errors.d.ts +5 -0
  161. package/dist/server-fns/document-mutation-errors.js +50 -0
  162. package/dist/server-fns/editable-revision.d.ts +9 -0
  163. package/dist/server-fns/editable-revision.js +11 -0
  164. package/dist/server-fns/i18n/set-locale.d.ts +3 -1
  165. package/dist/server-fns/i18n/set-locale.js +18 -3
  166. package/dist/server-fns/preview/disable.d.ts +3 -1
  167. package/dist/server-fns/preview/disable.js +4 -1
  168. package/dist/server-fns/preview/enable.d.ts +3 -1
  169. package/dist/server-fns/preview/enable.js +4 -1
  170. package/dist/server-fns/singleton-document-read.d.ts +1 -1
  171. package/dist/server-fns/singleton-document-read.js +7 -3
  172. package/dist/server-fns/singletons/cancel-scheduled-publish.d.ts +9 -2
  173. package/dist/server-fns/singletons/cancel-scheduled-publish.js +7 -1
  174. package/dist/server-fns/singletons/change-status.d.ts +5 -1
  175. package/dist/server-fns/singletons/change-status.js +7 -1
  176. package/dist/server-fns/singletons/confirm-scheduled-publish.d.ts +8 -2
  177. package/dist/server-fns/singletons/confirm-scheduled-publish.js +7 -2
  178. package/dist/server-fns/singletons/copy-to-locale.d.ts +5 -1
  179. package/dist/server-fns/singletons/copy-to-locale.js +7 -2
  180. package/dist/server-fns/singletons/find-by-version.d.ts +3 -1
  181. package/dist/server-fns/singletons/find-by-version.js +4 -1
  182. package/dist/server-fns/singletons/get-scheduled-publish.d.ts +3 -1
  183. package/dist/server-fns/singletons/get-scheduled-publish.js +4 -1
  184. package/dist/server-fns/singletons/get.d.ts +6 -4
  185. package/dist/server-fns/singletons/get.js +4 -1
  186. package/dist/server-fns/singletons/history.d.ts +3 -1
  187. package/dist/server-fns/singletons/history.js +4 -1
  188. package/dist/server-fns/singletons/restore-version.d.ts +5 -1
  189. package/dist/server-fns/singletons/restore-version.js +9 -3
  190. package/dist/server-fns/singletons/schedule-publish.d.ts +8 -2
  191. package/dist/server-fns/singletons/schedule-publish.js +7 -2
  192. package/dist/server-fns/singletons/unpublish.d.ts +5 -1
  193. package/dist/server-fns/singletons/unpublish.js +7 -1
  194. package/dist/server-fns/singletons/update.d.ts +6 -4
  195. package/dist/server-fns/singletons/update.js +8 -4
  196. package/dist/server-fns/structural-receipt.d.ts +4 -0
  197. package/dist/server-fns/structural-receipt.js +31 -0
  198. package/package.json +20 -20
  199. package/src/admin-shell/chrome/admin-app-bar.tsx +11 -6
  200. package/src/admin-shell/chrome/session-change-boundary.test.tsx +78 -0
  201. package/src/admin-shell/chrome/session-change-boundary.tsx +94 -0
  202. package/src/admin-shell/chrome/sign-in-page.tsx +68 -3
  203. package/src/admin-shell/collections/edit.tsx +173 -54
  204. package/src/admin-shell/collections/history.tsx +11 -2
  205. package/src/admin-shell/collections/list.tsx +22 -6
  206. package/src/admin-shell/collections/restore-version-modal.tsx +12 -3
  207. package/src/admin-shell/collections/save-navigation.test.tsx +156 -8
  208. package/src/admin-shell/collections/tree-list.tsx +16 -6
  209. package/src/admin-shell/collections/version-history.tsx +13 -3
  210. package/src/admin-shell/document-mutation-notice.tsx +45 -0
  211. package/src/admin-shell/document-mutation-state.test.tsx +146 -0
  212. package/src/admin-shell/document-mutation-state.ts +95 -0
  213. package/src/admin-shell/scheduled-publications/list.tsx +16 -6
  214. package/src/admin-shell/singletons/history.test.tsx +3 -1
  215. package/src/admin-shell/singletons/history.tsx +10 -2
  216. package/src/admin-shell/singletons/view.test.tsx +59 -18
  217. package/src/admin-shell/singletons/view.tsx +110 -29
  218. package/src/integrations/byline-admin-services.ts +7 -1
  219. package/src/integrations/byline-field-services.ts +2 -3
  220. package/src/integrations/client-ip.test.node.ts +45 -0
  221. package/src/integrations/client-ip.ts +54 -0
  222. package/src/integrations/framework-fetch-shape.test.node.ts +56 -0
  223. package/src/integrations/session-client.test.node.ts +121 -0
  224. package/src/integrations/session-coordination.test.node.ts +77 -0
  225. package/src/integrations/session-coordination.ts +96 -0
  226. package/src/integrations/session-middleware.test.node.ts +87 -0
  227. package/src/integrations/session-middleware.ts +107 -0
  228. package/src/integrations/session-request-kind.ts +18 -0
  229. package/src/integrations/session-request-middleware.ts +17 -0
  230. package/src/integrations/sign-in-body.test.node.ts +59 -0
  231. package/src/integrations/sign-in-body.ts +50 -0
  232. package/src/integrations/sign-in-middleware.ts +24 -0
  233. package/src/routes/create-admin-layout-route.tsx +48 -30
  234. package/src/routes/create-collection-edit-route.tsx +1 -0
  235. package/src/routes/create-collection-list-route.tsx +13 -2
  236. package/src/routes/create-sign-in-route.tsx +10 -2
  237. package/src/routes/create-singleton-route.test.node.ts +10 -2
  238. package/src/routes/create-singleton-route.tsx +6 -4
  239. package/src/server-fns/admin-account/change-password.test.node.ts +69 -0
  240. package/src/server-fns/admin-account/change-password.ts +13 -2
  241. package/src/server-fns/admin-account/get.ts +2 -0
  242. package/src/server-fns/admin-account/update.ts +2 -0
  243. package/src/server-fns/admin-activity/get.ts +2 -0
  244. package/src/server-fns/admin-permissions/get-role-abilities.ts +2 -0
  245. package/src/server-fns/admin-permissions/list-registered.ts +5 -4
  246. package/src/server-fns/admin-permissions/set-role-abilities.ts +2 -0
  247. package/src/server-fns/admin-permissions/who-has.ts +2 -0
  248. package/src/server-fns/admin-roles/create.ts +2 -0
  249. package/src/server-fns/admin-roles/delete.ts +2 -0
  250. package/src/server-fns/admin-roles/get.ts +2 -0
  251. package/src/server-fns/admin-roles/list.ts +5 -4
  252. package/src/server-fns/admin-roles/reorder.ts +2 -0
  253. package/src/server-fns/admin-roles/update.ts +2 -0
  254. package/src/server-fns/admin-users/create.ts +2 -0
  255. package/src/server-fns/admin-users/delete.ts +2 -0
  256. package/src/server-fns/admin-users/disable.ts +2 -0
  257. package/src/server-fns/admin-users/enable.ts +2 -0
  258. package/src/server-fns/admin-users/get-user-roles.ts +2 -0
  259. package/src/server-fns/admin-users/get.ts +2 -0
  260. package/src/server-fns/admin-users/list.ts +2 -0
  261. package/src/server-fns/admin-users/set-password.ts +2 -0
  262. package/src/server-fns/admin-users/set-user-roles.ts +2 -0
  263. package/src/server-fns/admin-users/update.ts +2 -0
  264. package/src/server-fns/ai/execute.ts +3 -0
  265. package/src/server-fns/analytics/maintenance.ts +4 -0
  266. package/src/server-fns/analytics/queries.ts +14 -8
  267. package/src/server-fns/auth/current-user.ts +7 -3
  268. package/src/server-fns/auth/renew.test.node.ts +85 -0
  269. package/src/server-fns/auth/renew.ts +54 -0
  270. package/src/server-fns/auth/sign-in.test.node.ts +114 -0
  271. package/src/server-fns/auth/sign-in.ts +80 -27
  272. package/src/server-fns/auth/sign-out.test.node.ts +85 -0
  273. package/src/server-fns/auth/sign-out.ts +44 -19
  274. package/src/server-fns/collections/audit.ts +2 -0
  275. package/src/server-fns/collections/copy-to-locale.ts +43 -36
  276. package/src/server-fns/collections/create.ts +56 -50
  277. package/src/server-fns/collections/delete-locale.ts +43 -32
  278. package/src/server-fns/collections/delete-outcome.test.node.ts +16 -0
  279. package/src/server-fns/collections/delete-outcome.ts +27 -16
  280. package/src/server-fns/collections/delete.ts +46 -38
  281. package/src/server-fns/collections/duplicate.ts +40 -32
  282. package/src/server-fns/collections/get.ts +11 -4
  283. package/src/server-fns/collections/history.ts +2 -0
  284. package/src/server-fns/collections/list.ts +10 -3
  285. package/src/server-fns/collections/reindex.ts +2 -0
  286. package/src/server-fns/collections/reorder.ts +34 -124
  287. package/src/server-fns/collections/restore-version.ts +49 -39
  288. package/src/server-fns/collections/revision-input.test.node.ts +122 -0
  289. package/src/server-fns/collections/save-outcome.test.node.ts +3 -0
  290. package/src/server-fns/collections/save-outcome.ts +2 -0
  291. package/src/server-fns/collections/scheduled-publication.ts +149 -115
  292. package/src/server-fns/collections/set-list-view-preference.ts +2 -0
  293. package/src/server-fns/collections/stats.ts +2 -0
  294. package/src/server-fns/collections/status.ts +89 -64
  295. package/src/server-fns/collections/tree-mutation.test.node.ts +87 -29
  296. package/src/server-fns/collections/tree-mutation.ts +28 -11
  297. package/src/server-fns/collections/tree.ts +156 -122
  298. package/src/server-fns/collections/update.ts +113 -86
  299. package/src/server-fns/collections/upload-singleton.test.node.ts +10 -7
  300. package/src/server-fns/collections/upload.ts +91 -77
  301. package/src/server-fns/document-mutation-errors.ts +67 -0
  302. package/src/server-fns/document-mutation-transport.test.node.ts +211 -0
  303. package/src/server-fns/editable-revision.test.node.ts +23 -0
  304. package/src/server-fns/editable-revision.ts +18 -0
  305. package/src/server-fns/i18n/set-locale.ts +19 -3
  306. package/src/server-fns/preview/disable.ts +8 -4
  307. package/src/server-fns/preview/enable.ts +9 -5
  308. package/src/server-fns/singleton-document-read.ts +7 -3
  309. package/src/server-fns/singletons/cancel-scheduled-publish.ts +12 -3
  310. package/src/server-fns/singletons/change-status.ts +12 -3
  311. package/src/server-fns/singletons/confirm-scheduled-publish.ts +14 -6
  312. package/src/server-fns/singletons/copy-to-locale.ts +22 -15
  313. package/src/server-fns/singletons/find-by-version.ts +2 -0
  314. package/src/server-fns/singletons/get-scheduled-publish.ts +2 -0
  315. package/src/server-fns/singletons/get.ts +5 -3
  316. package/src/server-fns/singletons/history.ts +2 -0
  317. package/src/server-fns/singletons/restore-version.ts +19 -12
  318. package/src/server-fns/singletons/schedule-publish.ts +20 -7
  319. package/src/server-fns/singletons/singletons.test.node.ts +69 -25
  320. package/src/server-fns/singletons/unpublish.ts +12 -3
  321. package/src/server-fns/singletons/update.ts +23 -16
  322. package/src/server-fns/structural-receipt.ts +41 -0
@@ -1,4 +1,6 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { DocumentMutationNotice } from "../document-mutation-notice.js";
3
+ import { useDocumentMutationState } from "../document-mutation-state.js";
2
4
  import { useEffect, useMemo, useRef, useState } from "react";
3
5
  import { useRouter } from "@tanstack/react-router";
4
6
  import { StatusBadge, renderFormatted } from "@byline/admin/react";
@@ -55,6 +57,7 @@ function SortableTreeRow({ id, dragging, disabled, dragHandleLabel, children })
55
57
  });
56
58
  }
57
59
  const TreeListView = ({ rows, columns, workflowStatuses, useAsTitle, collection, collectionLabels, onMove, listActions })=>{
60
+ const mutation = useDocumentMutationState(void 0);
58
61
  const { t } = useTranslation('byline-admin');
59
62
  const router = useRouter();
60
63
  const toastManager = useToastManager();
@@ -66,12 +69,13 @@ const TreeListView = ({ rows, columns, workflowStatuses, useAsTitle, collection,
66
69
  const [moveController] = useState(()=>createAdminTreeMoveController());
67
70
  const preserveOptimisticForRows = useRef(null);
68
71
  useEffect(()=>{
69
- if (!shouldSyncAdminTreeRows(rows, preserveOptimisticForRows.current, isMoving)) return;
72
+ if (mutation.blocked || !shouldSyncAdminTreeRows(rows, preserveOptimisticForRows.current, isMoving)) return;
70
73
  preserveOptimisticForRows.current = null;
71
74
  setLocalPlaced(rows.filter((r)=>!r.unplaced));
72
75
  }, [
73
76
  rows,
74
- isMoving
77
+ isMoving,
78
+ mutation.blocked
75
79
  ]);
76
80
  const [activeId, setActiveId] = useState(null);
77
81
  const [overId, setOverId] = useState(null);
@@ -98,12 +102,12 @@ const TreeListView = ({ rows, columns, workflowStatuses, useAsTitle, collection,
98
102
  setOffsetLeft(0);
99
103
  };
100
104
  const handleDragStart = ({ active })=>{
101
- if (!moveController.isMoving()) setActiveId(String(active.id));
105
+ if (!mutation.blocked && !moveController.isMoving()) setActiveId(String(active.id));
102
106
  };
103
107
  const handleDragMove = ({ delta })=>setOffsetLeft(delta.x);
104
108
  const handleDragOver = ({ over })=>setOverId(over ? String(over.id) : null);
105
109
  const handleDragEnd = async ({ active, over })=>{
106
- if (moveController.isMoving()) return void resetDnd();
110
+ if (mutation.blocked || moveController.isMoving()) return void resetDnd();
107
111
  const proj = null != over ? getTreeProjection(localPlaced, String(active.id), String(over.id), offsetLeft, INDENT) : null;
108
112
  resetDnd();
109
113
  if (!onMove || null == proj) return;
@@ -125,9 +129,11 @@ const TreeListView = ({ rows, columns, workflowStatuses, useAsTitle, collection,
125
129
  setIsMoving(moveController.isMoving());
126
130
  return;
127
131
  }
132
+ if ('receipt' in outcome) mutation.reportStructure(outcome.receipt);
133
+ const handled = 'error' in outcome ? mutation.report(outcome.error) : null;
128
134
  const effects = getAdminTreeMoveUiEffects(outcome);
129
135
  if (effects.rollback) setLocalPlaced(current);
130
- if (null != effects.structuralFailure) {
136
+ if (!handled && null != effects.structuralFailure) {
131
137
  const conflict = 'conflict' === effects.structuralFailure;
132
138
  toastManager.add({
133
139
  title: t(conflict ? 'collections.list.treeConflictToast' : 'collections.list.reorderFailedToast'),
@@ -202,6 +208,10 @@ const TreeListView = ({ rows, columns, workflowStatuses, useAsTitle, collection,
202
208
  return /*#__PURE__*/ jsx(Section, {
203
209
  children: /*#__PURE__*/ jsxs(Container, {
204
210
  children: [
211
+ /*#__PURE__*/ jsx(DocumentMutationNotice, {
212
+ issue: mutation.issue,
213
+ scheduleNotice: mutation.scheduleNotice
214
+ }),
205
215
  /*#__PURE__*/ jsxs("div", {
206
216
  className: clsx('byline-coll-list-head', tree_list_module.head),
207
217
  children: [
@@ -271,7 +281,7 @@ const TreeListView = ({ rows, columns, workflowStatuses, useAsTitle, collection,
271
281
  return dndEnabled ? /*#__PURE__*/ jsx(SortableTreeRow, {
272
282
  id: row.id,
273
283
  dragging: row.id === activeId,
274
- disabled: isMoving,
284
+ disabled: mutation.blocked || isMoving,
275
285
  dragHandleLabel: t('collections.list.dragHandleAriaLabel'),
276
286
  children: renderCells(row, depth)
277
287
  }, row.id) : /*#__PURE__*/ jsx(Table.Row, {
@@ -40,6 +40,7 @@ interface VersionHistoryRowContext {
40
40
  actionLabel: string;
41
41
  restoreStatusLabel: string;
42
42
  openCompare: () => void;
43
+ mutationsBlocked: boolean;
43
44
  openRestore: () => void;
44
45
  }
45
46
  /**
@@ -66,7 +67,7 @@ export declare function VersionHistoryCore({ data, resourceDefinition, resourceP
66
67
  rowPresentation: VersionHistoryRowPresentation;
67
68
  loadHistoricalVersion: HistoricalVersionLoader;
68
69
  onPageSizeChange: (pageSize: number) => void;
69
- restoreVersion: (versionId: string) => Promise<unknown>;
70
+ restoreVersion: (versionId: string, expectedRevision: number) => Promise<unknown>;
70
71
  onRestoreComplete: () => void | Promise<void>;
71
72
  }): import("react").JSX.Element;
72
73
  export {};
@@ -1,4 +1,6 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { DocumentMutationNotice } from "../document-mutation-notice.js";
3
+ import { useDocumentMutationState } from "../document-mutation-state.js";
2
4
  import { Fragment as external_react_Fragment, Suspense, lazy, useState } from "react";
3
5
  import { getDefaultStatus, getWorkflowStatuses } from "@byline/core";
4
6
  import { useTranslation } from "@byline/i18n/react";
@@ -33,6 +35,7 @@ function padRows(value) {
33
35
  }, `empty-row-${index}`));
34
36
  }
35
37
  function VersionHistoryCore({ data, resourceDefinition, resourcePath, documentId, currentDocument, locale, rowPresentation, loadHistoricalVersion, onPageSizeChange, restoreVersion, onRestoreComplete }) {
38
+ const mutation = useDocumentMutationState(currentDocument);
36
39
  const { t } = useTranslation('byline-admin');
37
40
  const [selectedVersion, setSelectedVersion] = useState(null);
38
41
  const [restoreTarget, setRestoreTarget] = useState(null);
@@ -41,6 +44,9 @@ function VersionHistoryCore({ data, resourceDefinition, resourcePath, documentId
41
44
  const restoreStatusLabel = getWorkflowStatuses(resourceDefinition).find((status)=>status.name === restoreStatus)?.label ?? restoreStatus;
42
45
  return /*#__PURE__*/ jsxs(Fragment, {
43
46
  children: [
47
+ /*#__PURE__*/ jsx(DocumentMutationNotice, {
48
+ issue: mutation.issue
49
+ }),
44
50
  /*#__PURE__*/ jsx("div", {
45
51
  className: clsx('byline-coll-history-options', history_module.options),
46
52
  children: /*#__PURE__*/ jsx(RouterPager, {
@@ -85,7 +91,7 @@ function VersionHistoryCore({ data, resourceDefinition, resourcePath, documentId
85
91
  });
86
92
  };
87
93
  const openRestore = ()=>{
88
- if (null == versionId || versionId === currentVersionId) return;
94
+ if (mutation.blocked || null == versionId || versionId === currentVersionId) return;
89
95
  setRestoreTarget({
90
96
  versionId,
91
97
  label: versionLabel,
@@ -119,6 +125,7 @@ function VersionHistoryCore({ data, resourceDefinition, resourcePath, documentId
119
125
  actionLabel,
120
126
  restoreStatusLabel,
121
127
  openCompare,
128
+ mutationsBlocked: mutation.blocked,
122
129
  openRestore
123
130
  })
124
131
  ]
@@ -243,11 +250,13 @@ function VersionHistoryCore({ data, resourceDefinition, resourcePath, documentId
243
250
  ]
244
251
  }),
245
252
  restoreTarget ? /*#__PURE__*/ jsx(RestoreVersionModal, {
253
+ disabled: mutation.blocked,
254
+ onMutationError: mutation.report,
246
255
  versionLabel: restoreTarget.label,
247
256
  versionNumber: restoreTarget.versionNumber,
248
257
  restoreStatusLabel: restoreStatusLabel,
249
258
  onClose: ()=>setRestoreTarget(null),
250
- restoreVersion: ()=>restoreVersion(restoreTarget.versionId),
259
+ restoreVersion: ()=>restoreVersion(restoreTarget.versionId, mutation.expectedRevision()),
251
260
  onRestoreComplete: onRestoreComplete
252
261
  }) : null
253
262
  ]
@@ -0,0 +1,6 @@
1
+ import type { DocumentMutationIssue } from './document-mutation-state.js';
2
+ /** Persistent recovery for list, history and schedule views without local form drafts. */
3
+ export declare function DocumentMutationNotice({ issue, scheduleNotice, }: {
4
+ issue: DocumentMutationIssue | null;
5
+ scheduleNotice?: boolean;
6
+ }): import("react").JSX.Element | null;
@@ -0,0 +1,53 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef } from "react";
3
+ import { useTranslation } from "@byline/i18n/react";
4
+ import { Alert, Button } from "@byline/ui/react";
5
+ import { getAdminRoutePath } from "../routes/admin-path.js";
6
+ function DocumentMutationNotice({ issue, scheduleNotice = false }) {
7
+ const { t } = useTranslation('byline-admin');
8
+ const warning = useRef(null);
9
+ useEffect(()=>{
10
+ if (issue) warning.current?.focus();
11
+ }, [
12
+ issue
13
+ ]);
14
+ if (!issue && !scheduleNotice) return null;
15
+ return /*#__PURE__*/ jsxs("div", {
16
+ ref: warning,
17
+ tabIndex: -1,
18
+ role: "alert",
19
+ "aria-live": "assertive",
20
+ children: [
21
+ issue && /*#__PURE__*/ jsxs(Alert, {
22
+ close: false,
23
+ intent: "warning",
24
+ title: t(`documentConcurrency.${issue}Title`),
25
+ children: [
26
+ /*#__PURE__*/ jsx("p", {
27
+ children: t(`documentConcurrency.${issue}`)
28
+ }),
29
+ 'committed' !== issue && /*#__PURE__*/ jsx(Button, {
30
+ type: "button",
31
+ onClick: ()=>window.location.reload(),
32
+ children: t('documentConcurrency.reloadAction')
33
+ })
34
+ ]
35
+ }),
36
+ scheduleNotice && /*#__PURE__*/ jsxs(Alert, {
37
+ close: false,
38
+ intent: "warning",
39
+ title: t('documentConcurrency.schedulesTitle'),
40
+ children: [
41
+ /*#__PURE__*/ jsx("p", {
42
+ children: t('documentConcurrency.schedules')
43
+ }),
44
+ /*#__PURE__*/ jsx("a", {
45
+ href: getAdminRoutePath('scheduled-publications'),
46
+ children: t('documentConcurrency.reviewSchedules')
47
+ })
48
+ ]
49
+ })
50
+ ]
51
+ });
52
+ }
53
+ export { DocumentMutationNotice };
@@ -0,0 +1,22 @@
1
+ export type DocumentMutationIssue = 'stale' | 'reload' | 'lock' | 'unavailable' | 'committed';
2
+ /** A rejected observation stays frozen until an explicit editor reload. */
3
+ export declare function useDocumentMutationState<T extends {
4
+ id?: unknown;
5
+ versionId?: unknown;
6
+ revision?: unknown;
7
+ }>(document: T | null | undefined): {
8
+ issue: DocumentMutationIssue | null;
9
+ blocked: boolean;
10
+ scheduleNotice: boolean;
11
+ document: T | null | undefined;
12
+ revision: number | undefined;
13
+ expectedRevision: () => number;
14
+ assertWritable: () => void;
15
+ adopt: (receipt: {
16
+ documentId: string;
17
+ revision: number;
18
+ scheduledPublicationsNeedReconfirmation?: boolean;
19
+ }) => void;
20
+ report: (error: unknown) => 'blocked' | 'committed' | null;
21
+ reportStructure: (result: unknown) => void;
22
+ };
@@ -0,0 +1,71 @@
1
+ import { useRef, useState } from "react";
2
+ import { ErrorCodes, getDocumentRevisionValidationDetails, getDocumentStaleDetails, getLockConflictDetails, parseDocumentRevision } from "@byline/core";
3
+ import { getDocumentHookCommittedDetails } from "@byline/core/services";
4
+ import { committedTreeReceipt, structuralReceipt } from "../server-fns/structural-receipt.js";
5
+ function documentMutationIssue(error) {
6
+ if (getDocumentStaleDetails(error)) return 'stale';
7
+ if (getDocumentRevisionValidationDetails(error)) return 'reload';
8
+ if (getLockConflictDetails(error)) return 'lock';
9
+ if (getDocumentHookCommittedDetails(error) || committedTreeReceipt(error)) return 'committed';
10
+ if ('object' == typeof error && null !== error && Reflect.get(error, 'code') === ErrorCodes.NOT_FOUND) return 'unavailable';
11
+ return null;
12
+ }
13
+ function useDocumentMutationState(document) {
14
+ const [issue, setIssue] = useState(null);
15
+ const [scheduleNotice, setScheduleNotice] = useState(false);
16
+ const [, setReceiptRevision] = useState();
17
+ const blockedError = useRef(void 0);
18
+ const observation = useRef({
19
+ identity: document,
20
+ revision: document?.revision
21
+ });
22
+ if (observation.current.identity !== document && void 0 === blockedError.current && document?.revision === observation.current.revision) observation.current = {
23
+ identity: document,
24
+ revision: document?.revision
25
+ };
26
+ const assertWritable = ()=>{
27
+ if (void 0 !== blockedError.current) throw blockedError.current;
28
+ };
29
+ const expectedRevision = ()=>{
30
+ assertWritable();
31
+ return parseDocumentRevision(observation.current.revision);
32
+ };
33
+ const adopt = (receipt)=>{
34
+ if (void 0 !== blockedError.current) return;
35
+ if (document?.id != null && receipt.documentId !== document.id) return;
36
+ observation.current.revision = parseDocumentRevision(receipt.revision);
37
+ setReceiptRevision(receipt.revision);
38
+ if (receipt.scheduledPublicationsNeedReconfirmation) setScheduleNotice(true);
39
+ };
40
+ const reportStructure = (result)=>{
41
+ const receipt = structuralReceipt(result);
42
+ if (receipt) adopt(receipt);
43
+ };
44
+ const report = (error)=>{
45
+ const kind = documentMutationIssue(error);
46
+ if (null === kind) return null;
47
+ if ('committed' === kind) {
48
+ if (void 0 !== blockedError.current) return 'blocked';
49
+ const details = getDocumentHookCommittedDetails(error) ?? committedTreeReceipt(error);
50
+ if (details) adopt(details);
51
+ setIssue(kind);
52
+ return 'committed';
53
+ }
54
+ blockedError.current = error;
55
+ setIssue(kind);
56
+ return 'blocked';
57
+ };
58
+ return {
59
+ issue,
60
+ blocked: null !== issue && 'committed' !== issue,
61
+ scheduleNotice,
62
+ document: observation.current.identity,
63
+ revision: 'number' == typeof observation.current.revision ? observation.current.revision : void 0,
64
+ expectedRevision,
65
+ assertWritable,
66
+ adopt,
67
+ report,
68
+ reportStructure
69
+ };
70
+ }
71
+ export { useDocumentMutationState };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,5 +1,7 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { DocumentMutationNotice } from "../document-mutation-notice.js";
4
+ import { useDocumentMutationState } from "../document-mutation-state.js";
3
5
  import { useMemo, useState } from "react";
4
6
  import { useRouterState } from "@tanstack/react-router";
5
7
  import { deriveScheduledPublicationState } from "@byline/admin/react";
@@ -35,6 +37,7 @@ function ScheduledPublicationsView({ data }) {
35
37
  select: (state)=>state.location
36
38
  });
37
39
  const search = location.search;
40
+ const mutation = useDocumentMutationState(void 0);
38
41
  const [cancelling, setCancelling] = useState(null);
39
42
  const applySearch = (patch)=>{
40
43
  navigate({
@@ -46,13 +49,16 @@ function ScheduledPublicationsView({ data }) {
46
49
  }
47
50
  });
48
51
  };
49
- const cancel = async (collection, documentId)=>{
52
+ const cancel = async (collection, documentId, expectedRevision)=>{
53
+ if (mutation.blocked || cancelling) return;
50
54
  setCancelling(documentId);
51
55
  try {
56
+ mutation.assertWritable();
52
57
  const result = await cancelCollectionDocumentScheduledPublish({
53
58
  data: {
54
59
  collection,
55
- id: documentId
60
+ id: documentId,
61
+ expectedRevision
56
62
  }
57
63
  });
58
64
  const cancelled = 'cancelled' === result.status;
@@ -71,9 +77,10 @@ function ScheduledPublicationsView({ data }) {
71
77
  search: location.search
72
78
  });
73
79
  } catch (error) {
80
+ if (mutation.report(error)) return;
74
81
  toastManager.add({
75
82
  title: t('scheduledPublication.toast.failedTitle'),
76
- description: error.message,
83
+ description: t('documentConcurrency.failed'),
77
84
  data: {
78
85
  intent: 'danger',
79
86
  iconType: 'danger',
@@ -89,6 +96,9 @@ function ScheduledPublicationsView({ data }) {
89
96
  return /*#__PURE__*/ jsx(Section, {
90
97
  children: /*#__PURE__*/ jsxs(Container, {
91
98
  children: [
99
+ /*#__PURE__*/ jsx(DocumentMutationNotice, {
100
+ issue: mutation.issue
101
+ }),
92
102
  /*#__PURE__*/ jsxs("div", {
93
103
  className: clsx('byline-scheduled-list-head', list_module.head),
94
104
  children: [
@@ -264,9 +274,9 @@ function ScheduledPublicationsView({ data }) {
264
274
  size: "xs",
265
275
  type: "button",
266
276
  intent: "danger",
267
- disabled: cancelling === schedule.documentId,
277
+ disabled: mutation.blocked || null !== cancelling,
268
278
  "aria-label": t('scheduledPublication.actions.cancel'),
269
- onClick: ()=>cancel(schedule.collectionPath, schedule.documentId),
279
+ onClick: ()=>cancel(schedule.collectionPath, schedule.documentId, schedule.revision),
270
280
  children: t('common.actions.cancel')
271
281
  })
272
282
  })
@@ -53,7 +53,7 @@ function SingletonHistoryView({ singletonDefinition, adminConfig, data, currentD
53
53
  ]
54
54
  }),
55
55
  auditColSpan: 4,
56
- renderCells: ({ document, versionId, currentVersionId, actorLabel, restoreStatusLabel, openRestore })=>/*#__PURE__*/ jsxs(Fragment, {
56
+ renderCells: ({ document, versionId, currentVersionId, actorLabel, restoreStatusLabel, mutationsBlocked, openRestore })=>/*#__PURE__*/ jsxs(Fragment, {
57
57
  children: [
58
58
  /*#__PURE__*/ jsx(Table.Cell, {
59
59
  className: "byline-singleton-history-status-cell",
@@ -77,6 +77,7 @@ function SingletonHistoryView({ singletonDefinition, adminConfig, data, currentD
77
77
  variant: "outlined",
78
78
  size: "xs",
79
79
  intent: "noeffect",
80
+ disabled: mutationsBlocked,
80
81
  onClick: openRestore,
81
82
  className: clsx('byline-coll-history-restore-button', history_module.restoreButton),
82
83
  title: t('collections.history.restoreButtonTitle', {
@@ -143,8 +144,9 @@ function SingletonHistoryView({ singletonDefinition, adminConfig, data, currentD
143
144
  return historical;
144
145
  },
145
146
  onPageSizeChange: handlePageSizeChange,
146
- restoreVersion: (versionId)=>restoreSingletonVersion({
147
+ restoreVersion: (versionId, expectedRevision)=>restoreSingletonVersion({
147
148
  data: {
149
+ expectedRevision,
148
150
  singleton,
149
151
  versionId
150
152
  }
@@ -5,7 +5,7 @@ type SingletonDocument = Record<string, any> & {
5
5
  status: string;
6
6
  fields: Record<string, any>;
7
7
  };
8
- export declare function SingletonView({ singletonDefinition, adminConfig, document, initialData, locale, contentLocales, defaultContentLocale, }: {
8
+ export declare function SingletonView({ singletonDefinition, adminConfig, document: loadedDocument, initialData, locale, contentLocales, defaultContentLocale, }: {
9
9
  singletonDefinition: SingletonDefinition;
10
10
  adminConfig?: SingletonAdminConfig;
11
11
  document: SingletonDocument | null;