@open-mercato/core 0.6.5-develop.4534.1.b459babe6d → 0.6.5-develop.4544.1.71c003c861

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 (633) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +5 -0
  3. package/dist/generated/entities/role/index.js +3 -1
  4. package/dist/generated/entities/role/index.js.map +2 -2
  5. package/dist/generated/entities/user/index.js +3 -1
  6. package/dist/generated/entities/user/index.js.map +2 -2
  7. package/dist/generated/entity-fields-registry.js +2 -0
  8. package/dist/generated/entity-fields-registry.js.map +2 -2
  9. package/dist/helpers/integration/optimisticLockUi.js +104 -0
  10. package/dist/helpers/integration/optimisticLockUi.js.map +7 -0
  11. package/dist/helpers/integration/salesFixtures.js +17 -0
  12. package/dist/helpers/integration/salesFixtures.js.map +2 -2
  13. package/dist/modules/api_keys/backend/api-keys/page.js +9 -5
  14. package/dist/modules/api_keys/backend/api-keys/page.js.map +2 -2
  15. package/dist/modules/attachments/components/AttachmentPartitionSettings.js +17 -9
  16. package/dist/modules/attachments/components/AttachmentPartitionSettings.js.map +2 -2
  17. package/dist/modules/auth/api/roles/acl/route.js +32 -13
  18. package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
  19. package/dist/modules/auth/api/roles/route.js +3 -1
  20. package/dist/modules/auth/api/roles/route.js.map +2 -2
  21. package/dist/modules/auth/api/sidebar/preferences/route.js +71 -3
  22. package/dist/modules/auth/api/sidebar/preferences/route.js.map +2 -2
  23. package/dist/modules/auth/api/users/acl/route.js +42 -19
  24. package/dist/modules/auth/api/users/acl/route.js.map +2 -2
  25. package/dist/modules/auth/api/users/route.js +3 -1
  26. package/dist/modules/auth/api/users/route.js.map +2 -2
  27. package/dist/modules/auth/backend/roles/[id]/edit/page.js +24 -4
  28. package/dist/modules/auth/backend/roles/[id]/edit/page.js.map +2 -2
  29. package/dist/modules/auth/backend/roles/page.js +8 -4
  30. package/dist/modules/auth/backend/roles/page.js.map +2 -2
  31. package/dist/modules/auth/backend/users/[id]/edit/page.js +27 -5
  32. package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
  33. package/dist/modules/auth/backend/users/page.js +6 -2
  34. package/dist/modules/auth/backend/users/page.js.map +2 -2
  35. package/dist/modules/auth/components/AclEditor.js +3 -1
  36. package/dist/modules/auth/components/AclEditor.js.map +2 -2
  37. package/dist/modules/auth/data/entities.js +6 -0
  38. package/dist/modules/auth/data/entities.js.map +2 -2
  39. package/dist/modules/auth/services/sidebarPreferencesService.js +32 -4
  40. package/dist/modules/auth/services/sidebarPreferencesService.js.map +2 -2
  41. package/dist/modules/business_rules/api/rules/route.js +28 -0
  42. package/dist/modules/business_rules/api/rules/route.js.map +2 -2
  43. package/dist/modules/business_rules/api/sets/route.js +28 -0
  44. package/dist/modules/business_rules/api/sets/route.js.map +2 -2
  45. package/dist/modules/business_rules/backend/rules/[id]/page.js +11 -4
  46. package/dist/modules/business_rules/backend/rules/[id]/page.js.map +3 -3
  47. package/dist/modules/business_rules/backend/rules/page.js +20 -11
  48. package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
  49. package/dist/modules/business_rules/backend/sets/[id]/page.js +11 -4
  50. package/dist/modules/business_rules/backend/sets/[id]/page.js.map +2 -2
  51. package/dist/modules/business_rules/backend/sets/page.js +20 -11
  52. package/dist/modules/business_rules/backend/sets/page.js.map +2 -2
  53. package/dist/modules/catalog/api/categories/route.js +2 -0
  54. package/dist/modules/catalog/api/categories/route.js.map +2 -2
  55. package/dist/modules/catalog/api/products/route.js +2 -1
  56. package/dist/modules/catalog/api/products/route.js.map +2 -2
  57. package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js +2 -0
  58. package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js.map +2 -2
  59. package/dist/modules/catalog/backend/catalog/products/[id]/page.js +94 -40
  60. package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
  61. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js +37 -8
  62. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
  63. package/dist/modules/catalog/backend/catalog/products/optionSchemaClient.js.map +2 -2
  64. package/dist/modules/catalog/commands/variants.js +32 -31
  65. package/dist/modules/catalog/commands/variants.js.map +2 -2
  66. package/dist/modules/catalog/components/PriceKindSettings.js +12 -5
  67. package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
  68. package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +2 -2
  69. package/dist/modules/catalog/components/products/ProductMediaManager.js.map +2 -2
  70. package/dist/modules/catalog/components/products/ProductsDataTable.js +5 -3
  71. package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
  72. package/dist/modules/catalog/components/products/productForm.js.map +2 -2
  73. package/dist/modules/catalog/components/products/variantForm.js +2 -1
  74. package/dist/modules/catalog/components/products/variantForm.js.map +2 -2
  75. package/dist/modules/communication_channels/backend/profile/communication-channels/page.js +5 -0
  76. package/dist/modules/communication_channels/backend/profile/communication-channels/page.js.map +2 -2
  77. package/dist/modules/currencies/backend/currencies/[id]/page.js +6 -3
  78. package/dist/modules/currencies/backend/currencies/[id]/page.js.map +2 -2
  79. package/dist/modules/currencies/backend/currencies/page.js +18 -11
  80. package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
  81. package/dist/modules/currencies/backend/exchange-rates/[id]/page.js +1 -0
  82. package/dist/modules/currencies/backend/exchange-rates/[id]/page.js.map +2 -2
  83. package/dist/modules/currencies/backend/exchange-rates/page.js +10 -6
  84. package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
  85. package/dist/modules/currencies/commands/currencies.js +7 -5
  86. package/dist/modules/currencies/commands/currencies.js.map +2 -2
  87. package/dist/modules/currencies/components/CurrencyFetchingConfig.js +26 -19
  88. package/dist/modules/currencies/components/CurrencyFetchingConfig.js.map +2 -2
  89. package/dist/modules/customer_accounts/api/admin/roles/[id].js +28 -5
  90. package/dist/modules/customer_accounts/api/admin/roles/[id].js.map +2 -2
  91. package/dist/modules/customer_accounts/api/admin/roles.js +4 -2
  92. package/dist/modules/customer_accounts/api/admin/roles.js.map +2 -2
  93. package/dist/modules/customer_accounts/api/admin/users/[id].js +28 -5
  94. package/dist/modules/customer_accounts/api/admin/users/[id].js.map +2 -2
  95. package/dist/modules/customer_accounts/api/admin/users.js +2 -0
  96. package/dist/modules/customer_accounts/api/admin/users.js.map +2 -2
  97. package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js +16 -8
  98. package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js.map +2 -2
  99. package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js +8 -4
  100. package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js.map +2 -2
  101. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/page.js +8 -4
  102. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/page.js.map +2 -2
  103. package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js +29 -18
  104. package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js.map +2 -2
  105. package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js +18 -11
  106. package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +2 -2
  107. package/dist/modules/customers/api/companies/route.js +13 -2
  108. package/dist/modules/customers/api/companies/route.js.map +2 -2
  109. package/dist/modules/customers/api/deals/route.js +2 -0
  110. package/dist/modules/customers/api/deals/route.js.map +2 -2
  111. package/dist/modules/customers/api/people/route.js +11 -2
  112. package/dist/modules/customers/api/people/route.js.map +2 -2
  113. package/dist/modules/customers/api/todos/route.js +1 -0
  114. package/dist/modules/customers/api/todos/route.js.map +2 -2
  115. package/dist/modules/customers/backend/config/customers/deals/page.js.map +2 -2
  116. package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js +34 -21
  117. package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js.map +2 -2
  118. package/dist/modules/customers/backend/customers/companies/[id]/page.js +45 -27
  119. package/dist/modules/customers/backend/customers/companies/[id]/page.js.map +2 -2
  120. package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
  121. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +22 -5
  122. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
  123. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.js +30 -8
  124. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.js.map +2 -2
  125. package/dist/modules/customers/backend/customers/deals/[id]/page.js +1 -0
  126. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  127. package/dist/modules/customers/backend/customers/deals/page.js +16 -6
  128. package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
  129. package/dist/modules/customers/backend/customers/deals/pipeline/page.js +62 -39
  130. package/dist/modules/customers/backend/customers/deals/pipeline/page.js.map +2 -2
  131. package/dist/modules/customers/backend/customers/people/[id]/page.js +41 -26
  132. package/dist/modules/customers/backend/customers/people/[id]/page.js.map +2 -2
  133. package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
  134. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +50 -23
  135. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
  136. package/dist/modules/customers/commands/addresses.js +16 -14
  137. package/dist/modules/customers/commands/addresses.js.map +2 -2
  138. package/dist/modules/customers/commands/companies.js +1 -1
  139. package/dist/modules/customers/commands/companies.js.map +2 -2
  140. package/dist/modules/customers/commands/interactions.js +41 -4
  141. package/dist/modules/customers/commands/interactions.js.map +2 -2
  142. package/dist/modules/customers/commands/people.js +1 -1
  143. package/dist/modules/customers/commands/people.js.map +2 -2
  144. package/dist/modules/customers/commands/personCompanyLinks.js +8 -5
  145. package/dist/modules/customers/commands/personCompanyLinks.js.map +2 -2
  146. package/dist/modules/customers/commands/pipeline-stages.js +13 -11
  147. package/dist/modules/customers/commands/pipeline-stages.js.map +3 -3
  148. package/dist/modules/customers/components/AddressFormatSettings.js.map +2 -2
  149. package/dist/modules/customers/components/DictionarySettings.js +20 -13
  150. package/dist/modules/customers/components/DictionarySettings.js.map +2 -2
  151. package/dist/modules/customers/components/DictionarySortSettings.js +4 -0
  152. package/dist/modules/customers/components/DictionarySortSettings.js.map +2 -2
  153. package/dist/modules/customers/components/PipelineSettings.js +38 -23
  154. package/dist/modules/customers/components/PipelineSettings.js.map +2 -2
  155. package/dist/modules/customers/components/detail/ActivityTimeline.js +1 -1
  156. package/dist/modules/customers/components/detail/ActivityTimeline.js.map +2 -2
  157. package/dist/modules/customers/components/detail/AddressesSection.js +4 -0
  158. package/dist/modules/customers/components/detail/AddressesSection.js.map +2 -2
  159. package/dist/modules/customers/components/detail/CompanyPeopleSection.js +28 -22
  160. package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
  161. package/dist/modules/customers/components/detail/DealsSection.js +36 -24
  162. package/dist/modules/customers/components/detail/DealsSection.js.map +2 -2
  163. package/dist/modules/customers/components/detail/EmailCardActions.js +5 -0
  164. package/dist/modules/customers/components/detail/EmailCardActions.js.map +2 -2
  165. package/dist/modules/customers/components/detail/EntityTagsDialog.js +7 -0
  166. package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +2 -2
  167. package/dist/modules/customers/components/detail/ManageTagsDialog.js +34 -22
  168. package/dist/modules/customers/components/detail/ManageTagsDialog.js.map +2 -2
  169. package/dist/modules/customers/components/detail/PersonCompaniesSection.js +41 -29
  170. package/dist/modules/customers/components/detail/PersonCompaniesSection.js.map +2 -2
  171. package/dist/modules/customers/components/detail/RoleAssignmentRow.js +14 -8
  172. package/dist/modules/customers/components/detail/RoleAssignmentRow.js.map +2 -2
  173. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +14 -6
  174. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +2 -2
  175. package/dist/modules/customers/components/detail/hooks/useInteractionMutations.js +29 -13
  176. package/dist/modules/customers/components/detail/hooks/useInteractionMutations.js.map +2 -2
  177. package/dist/modules/customers/components/detail/hooks/useInteractions.js +77 -35
  178. package/dist/modules/customers/components/detail/hooks/useInteractions.js.map +2 -2
  179. package/dist/modules/customers/components/detail/hooks/usePersonTasks.js +25 -17
  180. package/dist/modules/customers/components/detail/hooks/usePersonTasks.js.map +2 -2
  181. package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +2 -2
  182. package/dist/modules/customers/components/formConfig.js.map +2 -2
  183. package/dist/modules/customers/data/guards.js +66 -0
  184. package/dist/modules/customers/data/guards.js.map +7 -0
  185. package/dist/modules/customers/di.js +37 -0
  186. package/dist/modules/customers/di.js.map +2 -2
  187. package/dist/modules/customers/lib/todoCompatibility.js +11 -0
  188. package/dist/modules/customers/lib/todoCompatibility.js.map +2 -2
  189. package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +2 -2
  190. package/dist/modules/data_sync/api/options.js +4 -4
  191. package/dist/modules/data_sync/api/options.js.map +2 -2
  192. package/dist/modules/data_sync/api/schedules/route.js +9 -1
  193. package/dist/modules/data_sync/api/schedules/route.js.map +2 -2
  194. package/dist/modules/data_sync/backend/data-sync/page.js +17 -8
  195. package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
  196. package/dist/modules/data_sync/components/IntegrationScheduleTab.js +43 -22
  197. package/dist/modules/data_sync/components/IntegrationScheduleTab.js.map +2 -2
  198. package/dist/modules/data_sync/lib/sync-schedule-service.js +9 -0
  199. package/dist/modules/data_sync/lib/sync-schedule-service.js.map +2 -2
  200. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js +8 -1
  201. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js.map +2 -2
  202. package/dist/modules/dictionaries/api/[dictionaryId]/route.js +17 -1
  203. package/dist/modules/dictionaries/api/[dictionaryId]/route.js.map +2 -2
  204. package/dist/modules/dictionaries/components/DictionariesManager.js +31 -10
  205. package/dist/modules/dictionaries/components/DictionariesManager.js.map +2 -2
  206. package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js +28 -15
  207. package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js.map +2 -2
  208. package/dist/modules/directory/api/organizations/route.js +3 -0
  209. package/dist/modules/directory/api/organizations/route.js.map +2 -2
  210. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js +2 -0
  211. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js.map +2 -2
  212. package/dist/modules/directory/backend/directory/organizations/page.js +9 -5
  213. package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
  214. package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js +7 -3
  215. package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js.map +2 -2
  216. package/dist/modules/directory/backend/directory/tenants/page.js +8 -4
  217. package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
  218. package/dist/modules/directory/commands/organizations.js +7 -2
  219. package/dist/modules/directory/commands/organizations.js.map +2 -2
  220. package/dist/modules/entities/api/records.js +66 -0
  221. package/dist/modules/entities/api/records.js.map +2 -2
  222. package/dist/modules/entities/backend/entities/user/[entityId]/records/[recordId]/page.js +1 -0
  223. package/dist/modules/entities/backend/entities/user/[entityId]/records/[recordId]/page.js.map +2 -2
  224. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +8 -4
  225. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
  226. package/dist/modules/entities/lib/helpers.js +17 -0
  227. package/dist/modules/entities/lib/helpers.js.map +2 -2
  228. package/dist/modules/feature_toggles/api/global/[id]/override/route.js +2 -1
  229. package/dist/modules/feature_toggles/api/global/[id]/override/route.js.map +2 -2
  230. package/dist/modules/feature_toggles/api/overrides/route.js +15 -0
  231. package/dist/modules/feature_toggles/api/overrides/route.js.map +2 -2
  232. package/dist/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.js +15 -14
  233. package/dist/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.js.map +2 -2
  234. package/dist/modules/feature_toggles/components/FeatureToggleOverrideCard.js +20 -12
  235. package/dist/modules/feature_toggles/components/FeatureToggleOverrideCard.js.map +2 -2
  236. package/dist/modules/feature_toggles/components/FeatureTogglesTable.js +6 -2
  237. package/dist/modules/feature_toggles/components/FeatureTogglesTable.js.map +2 -2
  238. package/dist/modules/feature_toggles/components/formConfig.js +2 -1
  239. package/dist/modules/feature_toggles/components/formConfig.js.map +2 -2
  240. package/dist/modules/feature_toggles/components/overrideFormConfig.js +5 -1
  241. package/dist/modules/feature_toggles/components/overrideFormConfig.js.map +2 -2
  242. package/dist/modules/feature_toggles/data/validators.js +7 -4
  243. package/dist/modules/feature_toggles/data/validators.js.map +2 -2
  244. package/dist/modules/inbox_ops/api/settings/route.js +17 -2
  245. package/dist/modules/inbox_ops/api/settings/route.js.map +2 -2
  246. package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.js +13 -8
  247. package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.js.map +2 -2
  248. package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js +9 -4
  249. package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js.map +2 -2
  250. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js +18 -11
  251. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js.map +2 -2
  252. package/dist/modules/integrations/backend/integrations/page.js +12 -8
  253. package/dist/modules/integrations/backend/integrations/page.js.map +2 -2
  254. package/dist/modules/messages/commands/messages.js +13 -10
  255. package/dist/modules/messages/commands/messages.js.map +2 -2
  256. package/dist/modules/perspectives/api/[tableId]/route.js +39 -30
  257. package/dist/modules/perspectives/api/[tableId]/route.js.map +2 -2
  258. package/dist/modules/perspectives/services/perspectiveService.js +7 -0
  259. package/dist/modules/perspectives/services/perspectiveService.js.map +2 -2
  260. package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js +6 -14
  261. package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js.map +3 -3
  262. package/dist/modules/planner/backend/planner/availability-rulesets/page.js +4 -2
  263. package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
  264. package/dist/modules/planner/components/AvailabilityRuleSetForm.js +2 -0
  265. package/dist/modules/planner/components/AvailabilityRuleSetForm.js.map +2 -2
  266. package/dist/modules/planner/components/AvailabilityRulesEditor.js +36 -11
  267. package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
  268. package/dist/modules/planner/components/AvailabilitySchedule.js +9 -5
  269. package/dist/modules/planner/components/AvailabilitySchedule.js.map +2 -2
  270. package/dist/modules/query_index/lib/engine.js +19 -0
  271. package/dist/modules/query_index/lib/engine.js.map +2 -2
  272. package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js +1 -0
  273. package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js.map +2 -2
  274. package/dist/modules/resources/backend/resources/resource-types/page.js +4 -2
  275. package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
  276. package/dist/modules/resources/backend/resources/resources/[id]/page.js +14 -3
  277. package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
  278. package/dist/modules/resources/backend/resources/resources/page.js +8 -4
  279. package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
  280. package/dist/modules/resources/components/ResourceCrudForm.js +2 -0
  281. package/dist/modules/resources/components/ResourceCrudForm.js.map +2 -2
  282. package/dist/modules/resources/components/ResourceTypeCrudForm.js +1 -0
  283. package/dist/modules/resources/components/ResourceTypeCrudForm.js.map +2 -2
  284. package/dist/modules/sales/api/documents/factory.js +7 -2
  285. package/dist/modules/sales/api/documents/factory.js.map +2 -2
  286. package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js +3 -1
  287. package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js.map +2 -2
  288. package/dist/modules/sales/backend/sales/channels/offers/page.js +13 -4
  289. package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
  290. package/dist/modules/sales/backend/sales/channels/page.js +16 -4
  291. package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
  292. package/dist/modules/sales/backend/sales/documents/[id]/page.js +68 -22
  293. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  294. package/dist/modules/sales/backend/sales/documents/create/page.js.map +2 -2
  295. package/dist/modules/sales/commands/documentAddresses.js +181 -2
  296. package/dist/modules/sales/commands/documentAddresses.js.map +2 -2
  297. package/dist/modules/sales/commands/documents.js +29 -1
  298. package/dist/modules/sales/commands/documents.js.map +2 -2
  299. package/dist/modules/sales/commands/returns.js +12 -2
  300. package/dist/modules/sales/commands/returns.js.map +2 -2
  301. package/dist/modules/sales/commands/shared.js +15 -0
  302. package/dist/modules/sales/commands/shared.js.map +2 -2
  303. package/dist/modules/sales/commands/shipments.js +4 -1
  304. package/dist/modules/sales/commands/shipments.js.map +2 -2
  305. package/dist/modules/sales/components/AdjustmentKindSettings.js +19 -11
  306. package/dist/modules/sales/components/AdjustmentKindSettings.js.map +2 -2
  307. package/dist/modules/sales/components/DocumentNumberSettings.js.map +2 -2
  308. package/dist/modules/sales/components/OrderEditingSettings.js.map +2 -2
  309. package/dist/modules/sales/components/PaymentMethodsSettings.js +12 -4
  310. package/dist/modules/sales/components/PaymentMethodsSettings.js.map +2 -2
  311. package/dist/modules/sales/components/ShippingMethodsSettings.js +12 -4
  312. package/dist/modules/sales/components/ShippingMethodsSettings.js.map +2 -2
  313. package/dist/modules/sales/components/StatusSettings.js +18 -11
  314. package/dist/modules/sales/components/StatusSettings.js.map +2 -2
  315. package/dist/modules/sales/components/TaxRatesSettings.js +12 -4
  316. package/dist/modules/sales/components/TaxRatesSettings.js.map +2 -2
  317. package/dist/modules/sales/components/channels/ChannelOfferForm.js +47 -16
  318. package/dist/modules/sales/components/channels/ChannelOfferForm.js.map +2 -2
  319. package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js +8 -4
  320. package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
  321. package/dist/modules/sales/components/documents/AddressesSection.js +44 -25
  322. package/dist/modules/sales/components/documents/AddressesSection.js.map +2 -2
  323. package/dist/modules/sales/components/documents/AdjustmentsSection.js +43 -23
  324. package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +2 -2
  325. package/dist/modules/sales/components/documents/ItemsSection.js +22 -13
  326. package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
  327. package/dist/modules/sales/components/documents/LineItemDialog.js +23 -10
  328. package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
  329. package/dist/modules/sales/components/documents/PaymentDialog.js +29 -14
  330. package/dist/modules/sales/components/documents/PaymentDialog.js.map +2 -2
  331. package/dist/modules/sales/components/documents/PaymentsSection.js +20 -10
  332. package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
  333. package/dist/modules/sales/components/documents/ReturnDialog.js +26 -17
  334. package/dist/modules/sales/components/documents/ReturnDialog.js.map +2 -2
  335. package/dist/modules/sales/components/documents/ReturnsSection.js +3 -1
  336. package/dist/modules/sales/components/documents/ReturnsSection.js.map +2 -2
  337. package/dist/modules/sales/components/documents/SalesDocumentsTable.js +10 -5
  338. package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
  339. package/dist/modules/sales/components/documents/ShipmentDialog.js +21 -7
  340. package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
  341. package/dist/modules/sales/components/documents/ShipmentsSection.js +19 -10
  342. package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
  343. package/dist/modules/sales/components/documents/optimisticLock.js +27 -0
  344. package/dist/modules/sales/components/documents/optimisticLock.js.map +7 -0
  345. package/dist/modules/sales/di.js +18 -0
  346. package/dist/modules/sales/di.js.map +2 -2
  347. package/dist/modules/staff/api/job-histories.js +11 -2
  348. package/dist/modules/staff/api/job-histories.js.map +2 -2
  349. package/dist/modules/staff/api/timesheets/time-entries/route.js +11 -4
  350. package/dist/modules/staff/api/timesheets/time-entries/route.js.map +2 -2
  351. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +13 -8
  352. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
  353. package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js +2 -1
  354. package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js.map +2 -2
  355. package/dist/modules/staff/backend/staff/team-members/[id]/page.js +7 -4
  356. package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
  357. package/dist/modules/staff/backend/staff/team-members/page.js +4 -2
  358. package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
  359. package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js +1 -0
  360. package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js.map +2 -2
  361. package/dist/modules/staff/backend/staff/team-roles/page.js +4 -2
  362. package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
  363. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +5 -2
  364. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
  365. package/dist/modules/staff/backend/staff/teams/page.js +12 -3
  366. package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
  367. package/dist/modules/staff/backend/staff/timesheets/page.js +4 -1
  368. package/dist/modules/staff/backend/staff/timesheets/page.js.map +2 -2
  369. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js.map +2 -2
  370. package/dist/modules/staff/backend/staff/timesheets/projects/page.js +12 -3
  371. package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
  372. package/dist/modules/staff/commands/job-histories.js +40 -3
  373. package/dist/modules/staff/commands/job-histories.js.map +2 -2
  374. package/dist/modules/staff/components/LeaveRequestForm.js +1 -0
  375. package/dist/modules/staff/components/LeaveRequestForm.js.map +2 -2
  376. package/dist/modules/staff/components/TeamForm.js +1 -0
  377. package/dist/modules/staff/components/TeamForm.js.map +2 -2
  378. package/dist/modules/staff/components/TeamMemberForm.js +1 -0
  379. package/dist/modules/staff/components/TeamMemberForm.js.map +2 -2
  380. package/dist/modules/staff/components/TeamRoleForm.js +1 -0
  381. package/dist/modules/staff/components/TeamRoleForm.js.map +2 -2
  382. package/dist/modules/staff/components/detail/JobHistorySection.js +20 -7
  383. package/dist/modules/staff/components/detail/JobHistorySection.js.map +2 -2
  384. package/dist/modules/staff/data/validators.js +7 -1
  385. package/dist/modules/staff/data/validators.js.map +2 -2
  386. package/dist/modules/staff/lib/leaveRequestHelpers.js +2 -1
  387. package/dist/modules/staff/lib/leaveRequestHelpers.js.map +2 -2
  388. package/dist/modules/translations/components/TranslationManager.js +12 -8
  389. package/dist/modules/translations/components/TranslationManager.js.map +2 -2
  390. package/dist/modules/workflows/api/definitions/[id]/route.js +106 -0
  391. package/dist/modules/workflows/api/definitions/[id]/route.js.map +2 -2
  392. package/dist/modules/workflows/backend/definitions/[id]/page.js +11 -3
  393. package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
  394. package/dist/modules/workflows/backend/definitions/page.js +19 -8
  395. package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
  396. package/dist/modules/workflows/backend/definitions/visual-editor/page.js +29 -16
  397. package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
  398. package/dist/modules/workflows/components/formConfig.js +4 -1
  399. package/dist/modules/workflows/components/formConfig.js.map +2 -2
  400. package/dist/modules/workflows/di.js +12 -0
  401. package/dist/modules/workflows/di.js.map +2 -2
  402. package/generated/entities/role/index.ts +1 -0
  403. package/generated/entities/user/index.ts +1 -0
  404. package/generated/entity-fields-registry.ts +2 -0
  405. package/jest.setup.ts +17 -0
  406. package/package.json +8 -7
  407. package/src/helpers/integration/optimisticLockUi.ts +172 -0
  408. package/src/helpers/integration/salesFixtures.ts +29 -0
  409. package/src/modules/api_keys/backend/api-keys/page.tsx +10 -5
  410. package/src/modules/attachments/components/AttachmentPartitionSettings.tsx +19 -9
  411. package/src/modules/auth/api/roles/acl/route.ts +37 -11
  412. package/src/modules/auth/api/roles/route.ts +2 -0
  413. package/src/modules/auth/api/sidebar/preferences/route.ts +73 -0
  414. package/src/modules/auth/api/users/acl/route.ts +46 -18
  415. package/src/modules/auth/api/users/route.ts +2 -0
  416. package/src/modules/auth/backend/roles/[id]/edit/page.tsx +29 -4
  417. package/src/modules/auth/backend/roles/page.tsx +9 -4
  418. package/src/modules/auth/backend/users/[id]/edit/page.tsx +37 -4
  419. package/src/modules/auth/backend/users/page.tsx +7 -2
  420. package/src/modules/auth/components/AclEditor.tsx +10 -1
  421. package/src/modules/auth/data/entities.ts +7 -1
  422. package/src/modules/auth/services/sidebarPreferencesService.ts +38 -4
  423. package/src/modules/business_rules/api/rules/route.ts +30 -0
  424. package/src/modules/business_rules/api/sets/route.ts +30 -0
  425. package/src/modules/business_rules/backend/rules/[id]/page.tsx +16 -4
  426. package/src/modules/business_rules/backend/rules/page.tsx +20 -11
  427. package/src/modules/business_rules/backend/sets/[id]/page.tsx +16 -4
  428. package/src/modules/business_rules/backend/sets/page.tsx +20 -11
  429. package/src/modules/catalog/api/categories/route.ts +3 -0
  430. package/src/modules/catalog/api/products/route.ts +4 -0
  431. package/src/modules/catalog/backend/catalog/categories/[id]/edit/page.tsx +5 -0
  432. package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +112 -35
  433. package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +56 -7
  434. package/src/modules/catalog/backend/catalog/products/optionSchemaClient.ts +2 -0
  435. package/src/modules/catalog/commands/variants.ts +32 -32
  436. package/src/modules/catalog/components/PriceKindSettings.tsx +20 -7
  437. package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +1 -0
  438. package/src/modules/catalog/components/products/ProductMediaManager.tsx +2 -0
  439. package/src/modules/catalog/components/products/ProductsDataTable.tsx +8 -4
  440. package/src/modules/catalog/components/products/productForm.ts +3 -0
  441. package/src/modules/catalog/components/products/variantForm.ts +9 -0
  442. package/src/modules/communication_channels/backend/profile/communication-channels/page.tsx +5 -0
  443. package/src/modules/currencies/backend/currencies/[id]/page.tsx +13 -6
  444. package/src/modules/currencies/backend/currencies/page.tsx +18 -11
  445. package/src/modules/currencies/backend/exchange-rates/[id]/page.tsx +3 -0
  446. package/src/modules/currencies/backend/exchange-rates/page.tsx +10 -6
  447. package/src/modules/currencies/commands/currencies.ts +10 -5
  448. package/src/modules/currencies/components/CurrencyFetchingConfig.tsx +31 -21
  449. package/src/modules/customer_accounts/api/admin/roles/[id].ts +35 -5
  450. package/src/modules/customer_accounts/api/admin/roles.ts +2 -0
  451. package/src/modules/customer_accounts/api/admin/users/[id].ts +38 -5
  452. package/src/modules/customer_accounts/api/admin/users.ts +2 -0
  453. package/src/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.tsx +34 -20
  454. package/src/modules/customer_accounts/backend/customer_accounts/roles/page.tsx +9 -4
  455. package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/page.tsx +11 -4
  456. package/src/modules/customer_accounts/backend/customer_accounts/users/[id]/page.tsx +28 -17
  457. package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +19 -11
  458. package/src/modules/customers/AGENTS.md +2 -2
  459. package/src/modules/customers/api/companies/route.ts +14 -1
  460. package/src/modules/customers/api/deals/route.ts +3 -0
  461. package/src/modules/customers/api/people/route.ts +12 -1
  462. package/src/modules/customers/api/todos/route.ts +1 -0
  463. package/src/modules/customers/backend/config/customers/deals/page.tsx +1 -0
  464. package/src/modules/customers/backend/config/customers/pipeline-stages/page.tsx +36 -21
  465. package/src/modules/customers/backend/customers/companies/[id]/page.tsx +52 -27
  466. package/src/modules/customers/backend/customers/companies/page.tsx +2 -0
  467. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +27 -5
  468. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.ts +39 -7
  469. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +1 -0
  470. package/src/modules/customers/backend/customers/deals/page.tsx +18 -6
  471. package/src/modules/customers/backend/customers/deals/pipeline/page.tsx +64 -39
  472. package/src/modules/customers/backend/customers/people/[id]/page.tsx +46 -26
  473. package/src/modules/customers/backend/customers/people/page.tsx +2 -0
  474. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +84 -24
  475. package/src/modules/customers/commands/addresses.ts +16 -14
  476. package/src/modules/customers/commands/companies.ts +3 -1
  477. package/src/modules/customers/commands/interactions.ts +50 -4
  478. package/src/modules/customers/commands/people.ts +2 -1
  479. package/src/modules/customers/commands/personCompanyLinks.ts +8 -5
  480. package/src/modules/customers/commands/pipeline-stages.ts +16 -16
  481. package/src/modules/customers/components/AddressFormatSettings.tsx +1 -0
  482. package/src/modules/customers/components/DictionarySettings.tsx +18 -13
  483. package/src/modules/customers/components/DictionarySortSettings.tsx +4 -0
  484. package/src/modules/customers/components/PipelineSettings.tsx +42 -21
  485. package/src/modules/customers/components/detail/ActivityTimeline.tsx +3 -3
  486. package/src/modules/customers/components/detail/AddressesSection.tsx +4 -0
  487. package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +2 -0
  488. package/src/modules/customers/components/detail/DealsSection.tsx +4 -0
  489. package/src/modules/customers/components/detail/EmailCardActions.tsx +5 -0
  490. package/src/modules/customers/components/detail/EntityTagsDialog.tsx +7 -0
  491. package/src/modules/customers/components/detail/ManageTagsDialog.tsx +4 -0
  492. package/src/modules/customers/components/detail/PersonCompaniesSection.tsx +4 -0
  493. package/src/modules/customers/components/detail/RoleAssignmentRow.tsx +2 -0
  494. package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +23 -7
  495. package/src/modules/customers/components/detail/hooks/useInteractionMutations.ts +25 -15
  496. package/src/modules/customers/components/detail/hooks/useInteractions.ts +76 -35
  497. package/src/modules/customers/components/detail/hooks/usePersonTasks.ts +30 -17
  498. package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +2 -0
  499. package/src/modules/customers/components/detail/types.ts +1 -0
  500. package/src/modules/customers/components/formConfig.tsx +2 -0
  501. package/src/modules/customers/data/guards.ts +67 -0
  502. package/src/modules/customers/di.ts +66 -0
  503. package/src/modules/customers/i18n/de.json +2 -0
  504. package/src/modules/customers/i18n/en.json +2 -0
  505. package/src/modules/customers/i18n/es.json +2 -0
  506. package/src/modules/customers/i18n/pl.json +2 -0
  507. package/src/modules/customers/lib/todoCompatibility.ts +14 -0
  508. package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +2 -0
  509. package/src/modules/data_sync/api/options.ts +7 -4
  510. package/src/modules/data_sync/api/schedules/route.ts +9 -1
  511. package/src/modules/data_sync/backend/data-sync/page.tsx +18 -5
  512. package/src/modules/data_sync/components/IntegrationScheduleTab.tsx +46 -19
  513. package/src/modules/data_sync/lib/sync-schedule-service.ts +11 -0
  514. package/src/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.ts +8 -1
  515. package/src/modules/dictionaries/api/[dictionaryId]/route.ts +23 -0
  516. package/src/modules/dictionaries/components/DictionariesManager.tsx +32 -9
  517. package/src/modules/dictionaries/components/DictionaryEntriesEditor.tsx +30 -14
  518. package/src/modules/dictionaries/i18n/de.json +1 -0
  519. package/src/modules/dictionaries/i18n/en.json +1 -0
  520. package/src/modules/dictionaries/i18n/es.json +1 -0
  521. package/src/modules/dictionaries/i18n/pl.json +1 -0
  522. package/src/modules/directory/api/organizations/route.ts +3 -0
  523. package/src/modules/directory/backend/directory/organizations/[id]/edit/page.tsx +8 -0
  524. package/src/modules/directory/backend/directory/organizations/page.tsx +10 -5
  525. package/src/modules/directory/backend/directory/tenants/[id]/edit/page.tsx +16 -5
  526. package/src/modules/directory/backend/directory/tenants/page.tsx +8 -4
  527. package/src/modules/directory/commands/organizations.ts +7 -4
  528. package/src/modules/entities/api/records.ts +99 -0
  529. package/src/modules/entities/backend/entities/user/[entityId]/records/[recordId]/page.tsx +7 -0
  530. package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +8 -4
  531. package/src/modules/entities/lib/helpers.ts +17 -0
  532. package/src/modules/feature_toggles/api/global/[id]/override/route.ts +1 -0
  533. package/src/modules/feature_toggles/api/overrides/route.ts +19 -0
  534. package/src/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.tsx +19 -13
  535. package/src/modules/feature_toggles/components/FeatureToggleOverrideCard.tsx +22 -12
  536. package/src/modules/feature_toggles/components/FeatureTogglesTable.tsx +7 -2
  537. package/src/modules/feature_toggles/components/formConfig.tsx +2 -1
  538. package/src/modules/feature_toggles/components/overrideFormConfig.tsx +10 -1
  539. package/src/modules/feature_toggles/data/validators.ts +11 -3
  540. package/src/modules/inbox_ops/api/settings/route.ts +18 -0
  541. package/src/modules/inbox_ops/backend/inbox-ops/settings/page.tsx +15 -10
  542. package/src/modules/inbox_ops/components/proposals/EditActionDialog.tsx +9 -4
  543. package/src/modules/integrations/backend/integrations/bundle/[id]/page.tsx +20 -11
  544. package/src/modules/integrations/backend/integrations/page.tsx +13 -8
  545. package/src/modules/messages/commands/messages.ts +27 -15
  546. package/src/modules/perspectives/api/[tableId]/route.ts +11 -2
  547. package/src/modules/perspectives/services/perspectiveService.ts +13 -1
  548. package/src/modules/planner/backend/planner/availability-rulesets/[id]/page.tsx +16 -14
  549. package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +6 -3
  550. package/src/modules/planner/components/AvailabilityRuleSetForm.tsx +3 -0
  551. package/src/modules/planner/components/AvailabilityRulesEditor.tsx +58 -15
  552. package/src/modules/planner/components/AvailabilitySchedule.tsx +22 -7
  553. package/src/modules/query_index/lib/engine.ts +34 -0
  554. package/src/modules/resources/backend/resources/resource-types/[id]/edit/page.tsx +7 -1
  555. package/src/modules/resources/backend/resources/resource-types/page.tsx +6 -3
  556. package/src/modules/resources/backend/resources/resources/[id]/page.tsx +23 -3
  557. package/src/modules/resources/backend/resources/resources/page.tsx +15 -4
  558. package/src/modules/resources/components/ResourceCrudForm.tsx +3 -0
  559. package/src/modules/resources/components/ResourceTypeCrudForm.tsx +2 -0
  560. package/src/modules/sales/api/documents/factory.ts +13 -1
  561. package/src/modules/sales/backend/sales/channels/[channelId]/edit/page.tsx +6 -0
  562. package/src/modules/sales/backend/sales/channels/offers/page.tsx +10 -4
  563. package/src/modules/sales/backend/sales/channels/page.tsx +19 -4
  564. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +73 -20
  565. package/src/modules/sales/backend/sales/documents/create/page.tsx +2 -0
  566. package/src/modules/sales/commands/documentAddresses.ts +226 -4
  567. package/src/modules/sales/commands/documents.ts +28 -0
  568. package/src/modules/sales/commands/returns.ts +12 -3
  569. package/src/modules/sales/commands/shared.ts +36 -0
  570. package/src/modules/sales/commands/shipments.ts +17 -1
  571. package/src/modules/sales/components/AdjustmentKindSettings.tsx +20 -11
  572. package/src/modules/sales/components/DocumentNumberSettings.tsx +1 -0
  573. package/src/modules/sales/components/OrderEditingSettings.tsx +1 -0
  574. package/src/modules/sales/components/PaymentMethodsSettings.tsx +12 -4
  575. package/src/modules/sales/components/ShippingMethodsSettings.tsx +12 -4
  576. package/src/modules/sales/components/StatusSettings.tsx +20 -11
  577. package/src/modules/sales/components/TaxRatesSettings.tsx +12 -5
  578. package/src/modules/sales/components/channels/ChannelOfferForm.tsx +67 -14
  579. package/src/modules/sales/components/channels/SalesChannelOffersPanel.tsx +7 -4
  580. package/src/modules/sales/components/documents/AddressesSection.tsx +35 -25
  581. package/src/modules/sales/components/documents/AdjustmentsSection.tsx +50 -25
  582. package/src/modules/sales/components/documents/ItemsSection.tsx +24 -13
  583. package/src/modules/sales/components/documents/LineItemDialog.tsx +26 -9
  584. package/src/modules/sales/components/documents/PaymentDialog.tsx +33 -14
  585. package/src/modules/sales/components/documents/PaymentsSection.tsx +22 -10
  586. package/src/modules/sales/components/documents/ReturnDialog.tsx +28 -17
  587. package/src/modules/sales/components/documents/ReturnsSection.tsx +4 -1
  588. package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +11 -4
  589. package/src/modules/sales/components/documents/ShipmentDialog.tsx +23 -8
  590. package/src/modules/sales/components/documents/ShipmentsSection.tsx +20 -10
  591. package/src/modules/sales/components/documents/optimisticLock.ts +34 -0
  592. package/src/modules/sales/components/documents/shipmentTypes.ts +1 -0
  593. package/src/modules/sales/di.ts +35 -0
  594. package/src/modules/sales/i18n/de.json +3 -0
  595. package/src/modules/sales/i18n/en.json +3 -0
  596. package/src/modules/sales/i18n/es.json +3 -0
  597. package/src/modules/sales/i18n/pl.json +3 -0
  598. package/src/modules/staff/api/job-histories.ts +12 -2
  599. package/src/modules/staff/api/timesheets/time-entries/route.ts +16 -4
  600. package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +12 -7
  601. package/src/modules/staff/backend/staff/my-leave-requests/[id]/page.tsx +2 -0
  602. package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +16 -5
  603. package/src/modules/staff/backend/staff/team-members/page.tsx +6 -2
  604. package/src/modules/staff/backend/staff/team-roles/[id]/edit/page.tsx +8 -0
  605. package/src/modules/staff/backend/staff/team-roles/page.tsx +6 -2
  606. package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +13 -3
  607. package/src/modules/staff/backend/staff/teams/page.tsx +9 -3
  608. package/src/modules/staff/backend/staff/timesheets/page.tsx +10 -1
  609. package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.tsx +4 -0
  610. package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +9 -3
  611. package/src/modules/staff/commands/job-histories.ts +42 -3
  612. package/src/modules/staff/components/LeaveRequestForm.tsx +2 -0
  613. package/src/modules/staff/components/TeamForm.tsx +2 -0
  614. package/src/modules/staff/components/TeamMemberForm.tsx +2 -0
  615. package/src/modules/staff/components/TeamRoleForm.tsx +2 -0
  616. package/src/modules/staff/components/detail/JobHistorySection.tsx +28 -6
  617. package/src/modules/staff/data/validators.ts +6 -0
  618. package/src/modules/staff/i18n/de.json +1 -0
  619. package/src/modules/staff/i18n/en.json +1 -0
  620. package/src/modules/staff/i18n/es.json +1 -0
  621. package/src/modules/staff/i18n/pl.json +1 -0
  622. package/src/modules/staff/lib/leaveRequestHelpers.ts +4 -0
  623. package/src/modules/translations/components/TranslationManager.tsx +13 -8
  624. package/src/modules/workflows/api/definitions/[id]/route.ts +112 -0
  625. package/src/modules/workflows/backend/definitions/[id]/page.tsx +20 -4
  626. package/src/modules/workflows/backend/definitions/page.tsx +20 -9
  627. package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +29 -16
  628. package/src/modules/workflows/components/formConfig.tsx +5 -0
  629. package/src/modules/workflows/di.ts +20 -0
  630. package/src/modules/workflows/i18n/de.json +1 -0
  631. package/src/modules/workflows/i18n/en.json +1 -0
  632. package/src/modules/workflows/i18n/es.json +1 -0
  633. package/src/modules/workflows/i18n/pl.json +1 -0
@@ -18,7 +18,7 @@ const TYPE_ICONS: Record<string, React.ComponentType<{ className?: string }>> =
18
18
  interface ActivityTimelineProps {
19
19
  activities: InteractionSummary[]
20
20
  onEdit?: (activity: InteractionSummary) => void
21
- onMarkDone?: (activityId: string) => void | Promise<void>
21
+ onMarkDone?: (activityId: string, updatedAt?: string | null) => void | Promise<void>
22
22
  }
23
23
 
24
24
  export function ActivityTimeline({ activities, onEdit, onMarkDone }: ActivityTimelineProps) {
@@ -77,7 +77,7 @@ function TimelineEntry({
77
77
  t: TranslateFn
78
78
  withBorder: boolean
79
79
  onEdit?: (activity: InteractionSummary) => void
80
- onMarkDone?: (activityId: string) => void | Promise<void>
80
+ onMarkDone?: (activityId: string, updatedAt?: string | null) => void | Promise<void>
81
81
  }) {
82
82
  const dateStr = activity.scheduledAt ?? activity.occurredAt ?? activity.createdAt
83
83
  const TypeIcon = TYPE_ICONS[activity.interactionType]
@@ -91,7 +91,7 @@ function TimelineEntry({
91
91
  if (!onMarkDone || markingDone) return
92
92
  setMarkingDone(true)
93
93
  try {
94
- await onMarkDone(activity.id)
94
+ await onMarkDone(activity.id, activity.updatedAt)
95
95
  } finally {
96
96
  setMarkingDone(false)
97
97
  }
@@ -107,6 +107,7 @@ export function AddressesSection({
107
107
  const response = await apiCallOrThrow<Record<string, unknown>>(
108
108
  '/api/customers/addresses',
109
109
  {
110
+ // optimistic-lock-exempt: address link add/remove sub-resource
110
111
  method: 'POST',
111
112
  headers: { 'content-type': 'application/json' },
112
113
  body: JSON.stringify({
@@ -123,6 +124,7 @@ export function AddressesSection({
123
124
  await apiCallOrThrow(
124
125
  '/api/customers/addresses',
125
126
  {
127
+ // optimistic-lock-exempt: address link add/remove sub-resource
126
128
  method: 'PUT',
127
129
  headers: { 'content-type': 'application/json' },
128
130
  body: JSON.stringify({
@@ -138,6 +140,7 @@ export function AddressesSection({
138
140
  await apiCallOrThrow(
139
141
  '/api/customers/addresses',
140
142
  {
143
+ // optimistic-lock-exempt: address link add/remove sub-resource
141
144
  method: 'DELETE',
142
145
  headers: { 'content-type': 'application/json' },
143
146
  body: JSON.stringify({ id }),
@@ -170,6 +173,7 @@ export function AddressesSection({
170
173
  const response = await apiCallOrThrow<Record<string, unknown>>(
171
174
  '/api/customers/dictionaries/address-types',
172
175
  {
176
+ // optimistic-lock-exempt: address-type dictionary create-only
173
177
  method: 'POST',
174
178
  headers: { 'content-type': 'application/json' },
175
179
  body: JSON.stringify({ value }),
@@ -360,6 +360,7 @@ export function CompanyPeopleSection({
360
360
  for (const personId of addedIds) {
361
361
  await runWriteMutation(
362
362
  () =>
363
+ // optimistic-lock-exempt: person-company link add/remove
363
364
  apiCallOrThrow(
364
365
  `/api/customers/people/${encodeURIComponent(personId)}/companies`,
365
366
  {
@@ -514,6 +515,7 @@ export function CompanyPeopleSection({
514
515
  try {
515
516
  await runWriteMutation(
516
517
  () =>
518
+ // optimistic-lock-exempt: person-company link add/remove
517
519
  apiCallOrThrow(
518
520
  `/api/customers/people/${encodeURIComponent(personId)}/companies/${encodeURIComponent(companyId)}`,
519
521
  { method: 'DELETE' },
@@ -651,6 +651,7 @@ export function DealsSection({
651
651
  : currentCompanyIds
652
652
  await runWriteMutation(
653
653
  () =>
654
+ // optimistic-lock-exempt: deal association list (link)
654
655
  updateCrud(
655
656
  'customers/deals',
656
657
  { id: dealId, personIds: nextPersonIds, companyIds: nextCompanyIds },
@@ -684,6 +685,7 @@ export function DealsSection({
684
685
  : currentCompanyIds
685
686
  await runWriteMutation(
686
687
  () =>
688
+ // optimistic-lock-exempt: deal association list (unlink)
687
689
  updateCrud(
688
690
  'customers/deals',
689
691
  { id: dealId, personIds: nextPersonIds, companyIds: nextCompanyIds },
@@ -762,6 +764,7 @@ export function DealsSection({
762
764
  if (Object.keys(custom).length) payload.customFields = custom
763
765
  const { result } = await runWriteMutation(
764
766
  () =>
767
+ // optimistic-lock-exempt: deal create-only, no prior version
765
768
  createCrud<{ id?: string }>('customers/deals', payload, {
766
769
  errorMessage: translate('customers.people.detail.deals.error', 'Failed to save deal.'),
767
770
  }),
@@ -848,6 +851,7 @@ export function DealsSection({
848
851
  }
849
852
  await runWriteMutation(
850
853
  () =>
854
+ // optimistic-lock-exempt: deal association list (unlink)
851
855
  updateCrud('customers/deals', payload, {
852
856
  errorMessage: translate('customers.people.detail.deals.unlinkError', 'Failed to unlink deal.'),
853
857
  }),
@@ -190,6 +190,11 @@ export function EmailCardActions({ data }: EmailCardActionsProps) {
190
190
  const next = data.currentVisibility === 'private' ? 'shared' : 'private'
191
191
  try {
192
192
  await runMutation({
193
+ // optimistic-lock-exempt: dedicated single-field visibility
194
+ // action endpoint (shared/private toggle), not a full-record
195
+ // edit. The canonical interaction edit/delete is version-locked
196
+ // at the command layer (customers.interactions.* commands); this
197
+ // idempotent toggle derives `next` from freshly-loaded state.
193
198
  operation: async () => {
194
199
  const r = await apiCall<{ ok?: boolean }>(
195
200
  `/api/customers/interactions/${interactionId}/visibility`,
@@ -854,6 +854,7 @@ export function EntityTagsDialog({
854
854
  readApiResultOrThrow<Record<string, unknown>>(
855
855
  '/api/customers/tags',
856
856
  {
857
+ // optimistic-lock-exempt: tag dictionary create-only
857
858
  method: 'POST',
858
859
  headers: { 'content-type': 'application/json' },
859
860
  body: JSON.stringify({
@@ -892,6 +893,7 @@ export function EntityTagsDialog({
892
893
  readApiResultOrThrow<{ id: string; slug: string; label: string }>(
893
894
  '/api/customers/labels',
894
895
  {
896
+ // optimistic-lock-exempt: label dictionary create-only
895
897
  method: 'POST',
896
898
  headers: { 'content-type': 'application/json' },
897
899
  body: JSON.stringify(payload),
@@ -956,6 +958,7 @@ export function EntityTagsDialog({
956
958
  await runGuardedMutation(
957
959
  () =>
958
960
  apiCallOrThrow(`/api/customers/${entityType === 'person' ? 'people' : 'companies'}`, {
961
+ // optimistic-lock-exempt: tag/label dictionary + custom-field selection write (assignment add/remove)
959
962
  method: 'PUT',
960
963
  headers: { 'content-type': 'application/json' },
961
964
  body: JSON.stringify({
@@ -984,6 +987,7 @@ export function EntityTagsDialog({
984
987
  await runGuardedMutation(
985
988
  () =>
986
989
  apiCallOrThrow('/api/customers/tags/assign', {
990
+ // optimistic-lock-exempt: tag assignment add/remove
987
991
  method: 'POST',
988
992
  headers: { 'content-type': 'application/json' },
989
993
  body: JSON.stringify({ tagId, entityId }),
@@ -996,6 +1000,7 @@ export function EntityTagsDialog({
996
1000
  await runGuardedMutation(
997
1001
  () =>
998
1002
  apiCallOrThrow('/api/customers/tags/unassign', {
1003
+ // optimistic-lock-exempt: tag assignment add/remove
999
1004
  method: 'POST',
1000
1005
  headers: { 'content-type': 'application/json' },
1001
1006
  body: JSON.stringify({ tagId, entityId }),
@@ -1016,6 +1021,7 @@ export function EntityTagsDialog({
1016
1021
  await runGuardedMutation(
1017
1022
  () =>
1018
1023
  apiCallOrThrow('/api/customers/labels/assign', {
1024
+ // optimistic-lock-exempt: label assignment add/remove
1019
1025
  method: 'POST',
1020
1026
  headers: { 'content-type': 'application/json' },
1021
1027
  body: JSON.stringify(payload),
@@ -1031,6 +1037,7 @@ export function EntityTagsDialog({
1031
1037
  await runGuardedMutation(
1032
1038
  () =>
1033
1039
  apiCallOrThrow('/api/customers/labels/unassign', {
1040
+ // optimistic-lock-exempt: label assignment add/remove
1034
1041
  method: 'POST',
1035
1042
  headers: { 'content-type': 'application/json' },
1036
1043
  body: JSON.stringify(payload),
@@ -760,6 +760,7 @@ export function ManageTagsDialog({ open, onClose }: ManageTagsDialogProps) {
760
760
  if (entry.id) {
761
761
  await runGuardedMutation(
762
762
  () =>
763
+ // optimistic-lock-exempt: tag dictionary entry assignment add/remove
763
764
  apiCallOrThrow(`/api/customers/dictionaries/${category.kind}/${entry.id}`, {
764
765
  method: 'DELETE',
765
766
  }),
@@ -779,6 +780,7 @@ export function ManageTagsDialog({ open, onClose }: ManageTagsDialogProps) {
779
780
  if (!entry.id) {
780
781
  await runGuardedMutation(
781
782
  () =>
783
+ // optimistic-lock-exempt: tag dictionary entry create-only
782
784
  apiCallOrThrow(`/api/customers/dictionaries/${category.kind}`, {
783
785
  method: 'POST',
784
786
  headers: { 'content-type': 'application/json' },
@@ -805,6 +807,7 @@ export function ManageTagsDialog({ open, onClose }: ManageTagsDialogProps) {
805
807
 
806
808
  await runGuardedMutation(
807
809
  () =>
810
+ // optimistic-lock-exempt: tag dictionary entry assignment add/remove
808
811
  apiCallOrThrow(`/api/customers/dictionaries/${category.kind}/${entry.id}`, {
809
812
  method: 'PATCH',
810
813
  headers: { 'content-type': 'application/json' },
@@ -891,6 +894,7 @@ export function ManageTagsDialog({ open, onClose }: ManageTagsDialogProps) {
891
894
  try {
892
895
  await runGuardedMutation(
893
896
  () =>
897
+ // optimistic-lock-exempt: tag dictionary kind-settings assignment add/remove
894
898
  apiCallOrThrow('/api/customers/dictionaries/kind-settings', {
895
899
  method: 'PATCH',
896
900
  headers: { 'content-type': 'application/json' },
@@ -238,6 +238,7 @@ export function PersonCompaniesSection({
238
238
  for (const companyId of removedIds) {
239
239
  await runWriteMutation(
240
240
  () =>
241
+ // optimistic-lock-exempt: person-company link add/remove
241
242
  apiCallOrThrow(
242
243
  `/api/customers/people/${encodeURIComponent(personId)}/companies/${encodeURIComponent(companyId)}`,
243
244
  { method: 'DELETE' },
@@ -249,6 +250,7 @@ export function PersonCompaniesSection({
249
250
  for (const companyId of addedIds) {
250
251
  await runWriteMutation(
251
252
  () =>
253
+ // optimistic-lock-exempt: person-company link add/remove
252
254
  apiCallOrThrow(
253
255
  `/api/customers/people/${encodeURIComponent(personId)}/companies`,
254
256
  {
@@ -271,6 +273,7 @@ export function PersonCompaniesSection({
271
273
  ) {
272
274
  await runWriteMutation(
273
275
  () =>
276
+ // optimistic-lock-exempt: person-company link set-primary (add/remove)
274
277
  apiCallOrThrow(
275
278
  `/api/customers/people/${encodeURIComponent(personId)}/companies/${encodeURIComponent(nextPrimaryId)}`,
276
279
  {
@@ -332,6 +335,7 @@ export function PersonCompaniesSection({
332
335
  try {
333
336
  await runWriteMutation(
334
337
  () =>
338
+ // optimistic-lock-exempt: person-company link add/remove
335
339
  apiCallOrThrow(
336
340
  `/api/customers/people/${encodeURIComponent(personId)}/companies/${encodeURIComponent(companyId)}`,
337
341
  { method: 'DELETE' },
@@ -82,6 +82,7 @@ export function RoleAssignmentRow({
82
82
  try {
83
83
  await runMutationWithContext(
84
84
  () =>
85
+ // optimistic-lock-exempt: role assignment add/remove
85
86
  apiCallOrThrow(`/api/customers/${basePath}/${entityId}/roles?roleId=${role.id}`, {
86
87
  method: 'PUT',
87
88
  headers: { 'content-type': 'application/json' },
@@ -110,6 +111,7 @@ export function RoleAssignmentRow({
110
111
  try {
111
112
  await runMutationWithContext(
112
113
  () =>
114
+ // optimistic-lock-exempt: role assignment add/remove
113
115
  apiCallOrThrow(`/api/customers/${basePath}/${entityId}/roles?roleId=${role.id}`, {
114
116
  method: 'DELETE',
115
117
  }),
@@ -5,7 +5,8 @@ import { Users, Phone, Check, Mail, Calendar, AlertTriangle, X, StickyNote } fro
5
5
  import { cn } from '@open-mercato/shared/lib/utils'
6
6
  import { useT } from '@open-mercato/shared/lib/i18n/context'
7
7
  import { validatePhoneNumber } from '@open-mercato/shared/lib/phone'
8
- import { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
8
+ import { apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
9
+ import { buildOptimisticLockHeader, extractOptimisticLockConflict } from '@open-mercato/ui/backend/utils/optimisticLock'
9
10
  import { mapCrudServerErrorToFormErrors } from '@open-mercato/ui/backend/utils/serverErrors'
10
11
  import { flash } from '@open-mercato/ui/backend/FlashMessages'
11
12
  import { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'
@@ -411,12 +412,19 @@ export function ScheduleActivityDialog({
411
412
  ...(Object.keys(customValues).length > 0 ? { customValues } : {}),
412
413
  }
413
414
  await runGuardedMutation(
414
- () =>
415
- apiCallOrThrow('/api/customers/interactions', {
416
- method: isSaveEdit ? 'PUT' : 'POST',
417
- headers: { 'content-type': 'application/json' },
418
- body: JSON.stringify(payload),
419
- }),
415
+ () => {
416
+ const call = () =>
417
+ apiCallOrThrow('/api/customers/interactions', {
418
+ method: isSaveEdit ? 'PUT' : 'POST',
419
+ headers: { 'content-type': 'application/json' },
420
+ body: JSON.stringify(payload),
421
+ })
422
+ // Optimistic lock only applies to edits — a stale modal save against a
423
+ // concurrently changed/deleted activity surfaces the conflict bar (#2055).
424
+ return isSaveEdit
425
+ ? withScopedApiRequestHeaders(buildOptimisticLockHeader(editData?.updatedAt), call)
426
+ : call()
427
+ },
420
428
  {
421
429
  operation: isSaveEdit ? 'updateActivity' : 'createActivity',
422
430
  interactionId: editData?.id ?? null,
@@ -428,6 +436,14 @@ export function ScheduleActivityDialog({
428
436
  // Delay data reload so the dialog can unmount cleanly and Radix restores body scroll
429
437
  requestAnimationFrame(() => { onActivityCreated?.() })
430
438
  } catch (err) {
439
+ // An optimistic-lock 409 was already surfaced as the persistent conflict
440
+ // bar by `runGuardedMutation` (useGuardedMutation → surfaceRecordConflict).
441
+ // Do NOT additionally flash the raw `record_modified` code here — that
442
+ // showed an untranslated toast on top of the localized bar (#2055 QA).
443
+ if (extractOptimisticLockConflict(err)) {
444
+ onClose()
445
+ return
446
+ }
431
447
  const { message, fieldErrors } = mapCrudServerErrorToFormErrors(err)
432
448
  const phoneFieldError = fieldErrors?.phoneNumber
433
449
  if (state.activityType === 'call' && phoneFieldError) {
@@ -2,7 +2,9 @@
2
2
 
3
3
  import * as React from 'react'
4
4
  import { flash } from '@open-mercato/ui/backend/FlashMessages'
5
- import { apiCallOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
5
+ import { apiCallOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
6
+ import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
7
+ import { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'
6
8
  import { useT } from '@open-mercato/shared/lib/i18n/context'
7
9
 
8
10
  export type GuardedMutationRunner = <T>(
@@ -18,8 +20,8 @@ export type UseInteractionMutationsOptions = {
18
20
  }
19
21
 
20
22
  export type UseInteractionMutationsResult = {
21
- completeInteraction: (interactionId: string) => Promise<void>
22
- cancelInteraction: (interactionId: string) => Promise<void>
23
+ completeInteraction: (interactionId: string, updatedAt?: string | null) => Promise<void>
24
+ cancelInteraction: (interactionId: string, updatedAt?: string | null) => Promise<void>
23
25
  }
24
26
 
25
27
  /**
@@ -44,20 +46,24 @@ export function useInteractionMutations({
44
46
  }, [logContext, onAfterChange])
45
47
 
46
48
  const completeInteraction = React.useCallback(
47
- async (interactionId: string) => {
49
+ async (interactionId: string, updatedAt?: string | null) => {
48
50
  try {
49
51
  await runMutationWithContext(
50
52
  () =>
51
- apiCallOrThrow('/api/customers/interactions/complete', {
52
- method: 'POST',
53
- headers: { 'content-type': 'application/json' },
54
- body: JSON.stringify({ id: interactionId, occurredAt: new Date().toISOString() }),
55
- }),
53
+ withScopedApiRequestHeaders(
54
+ buildOptimisticLockHeader(updatedAt ?? null),
55
+ () => apiCallOrThrow('/api/customers/interactions/complete', {
56
+ method: 'POST',
57
+ headers: { 'content-type': 'application/json' },
58
+ body: JSON.stringify({ id: interactionId, occurredAt: new Date().toISOString() }),
59
+ }),
60
+ ),
56
61
  { id: interactionId, status: 'done', operation: 'completeActivity' },
57
62
  )
58
63
  flash(t('customers.timeline.planned.completed', 'Activity completed'), 'success')
59
64
  await triggerRefresh()
60
65
  } catch (err) {
66
+ if (surfaceRecordConflict(err, t)) { await triggerRefresh(); return }
61
67
  console.warn(`[${logContext}] complete interaction failed`, interactionId, err)
62
68
  flash(t('customers.timeline.planned.error', 'Failed to complete activity'), 'error')
63
69
  }
@@ -66,20 +72,24 @@ export function useInteractionMutations({
66
72
  )
67
73
 
68
74
  const cancelInteraction = React.useCallback(
69
- async (interactionId: string) => {
75
+ async (interactionId: string, updatedAt?: string | null) => {
70
76
  try {
71
77
  await runMutationWithContext(
72
78
  () =>
73
- apiCallOrThrow('/api/customers/interactions', {
74
- method: 'PUT',
75
- headers: { 'content-type': 'application/json' },
76
- body: JSON.stringify({ id: interactionId, status: 'canceled' }),
77
- }),
79
+ withScopedApiRequestHeaders(
80
+ buildOptimisticLockHeader(updatedAt ?? null),
81
+ () => apiCallOrThrow('/api/customers/interactions', {
82
+ method: 'PUT',
83
+ headers: { 'content-type': 'application/json' },
84
+ body: JSON.stringify({ id: interactionId, status: 'canceled' }),
85
+ }),
86
+ ),
78
87
  { id: interactionId, status: 'canceled', operation: 'cancelActivity' },
79
88
  )
80
89
  flash(t('customers.timeline.planned.canceled', 'Activity canceled'), 'success')
81
90
  await triggerRefresh()
82
91
  } catch (err) {
92
+ if (surfaceRecordConflict(err, t)) { await triggerRefresh(); return }
83
93
  console.warn(`[${logContext}] cancel interaction failed`, interactionId, err)
84
94
  flash(t('customers.timeline.planned.cancelError', 'Failed to cancel activity'), 'error')
85
95
  }
@@ -1,7 +1,9 @@
1
1
  "use client"
2
2
 
3
3
  import * as React from 'react'
4
- import { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
4
+ import { apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
5
+ import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
6
+ import { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'
5
7
  import { useT } from '@open-mercato/shared/lib/i18n/context'
6
8
  import type { InteractionSummary } from '../types'
7
9
 
@@ -226,87 +228,126 @@ export function useInteractions({
226
228
  const updateInteraction = React.useCallback(
227
229
  async (id: string, payload: InteractionUpdatePayload) => {
228
230
  setIsMutating(true)
231
+ // Send the optimistic-lock header (target's loaded `updatedAt`) so a stale
232
+ // edit — including a task/activity edited from another tab — surfaces the
233
+ // conflict bar instead of silently overwriting (#2055). A stale edit after
234
+ // the record was deleted elsewhere maps to the same 409 via the server's
235
+ // enforceRecordGoneIsConflict, instead of a bare "Interaction not found" 404.
236
+ const target = interactions.find((entry) => entry.id === id)
229
237
  try {
230
- await apiCallOrThrow(
231
- '/api/customers/interactions',
232
- {
233
- method: 'PUT',
234
- headers: { 'content-type': 'application/json' },
235
- body: JSON.stringify({ id, ...payload }),
236
- },
237
- { errorMessage: t('customers.interactions.update.error', 'Failed to update interaction.') },
238
+ await withScopedApiRequestHeaders(
239
+ buildOptimisticLockHeader(target?.updatedAt ?? null),
240
+ () => apiCallOrThrow(
241
+ '/api/customers/interactions',
242
+ {
243
+ method: 'PUT',
244
+ headers: { 'content-type': 'application/json' },
245
+ body: JSON.stringify({ id, ...payload }),
246
+ },
247
+ { errorMessage: t('customers.interactions.update.error', 'Failed to update interaction.') },
248
+ ),
238
249
  )
239
250
  await refresh()
251
+ } catch (err) {
252
+ if (surfaceRecordConflict(err, t)) { await refresh(); return }
253
+ throw err
240
254
  } finally {
241
255
  setIsMutating(false)
242
256
  }
243
257
  },
244
- [refresh, t],
258
+ [interactions, refresh, t],
245
259
  )
246
260
 
247
261
  const completeInteraction = React.useCallback(
248
262
  async (id: string) => {
249
263
  setIsMutating(true)
250
264
  setPendingId(id)
265
+ const target = interactions.find((entry) => entry.id === id)
251
266
  try {
252
- await apiCallOrThrow(
253
- '/api/customers/interactions/complete',
254
- {
255
- method: 'POST',
256
- headers: { 'content-type': 'application/json' },
257
- body: JSON.stringify({ id }),
258
- },
259
- { errorMessage: t('customers.interactions.complete.error', 'Failed to complete interaction.') },
267
+ await withScopedApiRequestHeaders(
268
+ buildOptimisticLockHeader(target?.updatedAt ?? null),
269
+ () => apiCallOrThrow(
270
+ '/api/customers/interactions/complete',
271
+ {
272
+ method: 'POST',
273
+ headers: { 'content-type': 'application/json' },
274
+ body: JSON.stringify({ id }),
275
+ },
276
+ { errorMessage: t('customers.interactions.complete.error', 'Failed to complete interaction.') },
277
+ ),
260
278
  )
261
279
  await refresh()
280
+ } catch (err) {
281
+ if (surfaceRecordConflict(err, t)) { await refresh(); return }
282
+ throw err
262
283
  } finally {
263
284
  setPendingId(null)
264
285
  setIsMutating(false)
265
286
  }
266
287
  },
267
- [refresh, t],
288
+ [interactions, refresh, t],
268
289
  )
269
290
 
270
291
  const cancelInteraction = React.useCallback(
271
292
  async (id: string) => {
272
293
  setIsMutating(true)
273
294
  setPendingId(id)
295
+ const target = interactions.find((entry) => entry.id === id)
274
296
  try {
275
- await apiCallOrThrow(
276
- '/api/customers/interactions/cancel',
277
- {
278
- method: 'POST',
279
- headers: { 'content-type': 'application/json' },
280
- body: JSON.stringify({ id }),
281
- },
282
- { errorMessage: t('customers.interactions.cancel.error', 'Failed to cancel interaction.') },
297
+ await withScopedApiRequestHeaders(
298
+ buildOptimisticLockHeader(target?.updatedAt ?? null),
299
+ () => apiCallOrThrow(
300
+ '/api/customers/interactions/cancel',
301
+ {
302
+ method: 'POST',
303
+ headers: { 'content-type': 'application/json' },
304
+ body: JSON.stringify({ id }),
305
+ },
306
+ { errorMessage: t('customers.interactions.cancel.error', 'Failed to cancel interaction.') },
307
+ ),
283
308
  )
284
309
  await refresh()
310
+ } catch (err) {
311
+ if (surfaceRecordConflict(err, t)) { await refresh(); return }
312
+ throw err
285
313
  } finally {
286
314
  setPendingId(null)
287
315
  setIsMutating(false)
288
316
  }
289
317
  },
290
- [refresh, t],
318
+ [interactions, refresh, t],
291
319
  )
292
320
 
293
321
  const deleteInteraction = React.useCallback(
294
322
  async (id: string) => {
295
323
  setIsMutating(true)
324
+ const target = interactions.find((entry) => entry.id === id)
296
325
  try {
297
- await apiCallOrThrow(
298
- `/api/customers/interactions?id=${encodeURIComponent(id)}`,
299
- {
300
- method: 'DELETE',
301
- },
302
- { errorMessage: t('customers.interactions.delete.error', 'Failed to delete interaction.') },
326
+ await withScopedApiRequestHeaders(
327
+ buildOptimisticLockHeader(target?.updatedAt ?? null),
328
+ () =>
329
+ apiCallOrThrow(
330
+ `/api/customers/interactions?id=${encodeURIComponent(id)}`,
331
+ {
332
+ method: 'DELETE',
333
+ },
334
+ { errorMessage: t('customers.interactions.delete.error', 'Failed to delete interaction.') },
335
+ ),
303
336
  )
304
337
  await refresh()
338
+ } catch (err) {
339
+ // A stale delete (the record was changed/deleted in another tab) surfaces
340
+ // the unified conflict bar and re-syncs the list instead of a raw error (#2055).
341
+ if (surfaceRecordConflict(err, t)) {
342
+ await refresh()
343
+ return
344
+ }
345
+ throw err
305
346
  } finally {
306
347
  setIsMutating(false)
307
348
  }
308
349
  },
309
- [refresh, t],
350
+ [interactions, refresh, t],
310
351
  )
311
352
 
312
353
  const hasMore = entityId != null && nextCursor != null
@@ -1,7 +1,8 @@
1
1
  "use client"
2
2
 
3
3
  import * as React from 'react'
4
- import { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
4
+ import { apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
5
+ import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
5
6
  import { resolveTodoApiPath } from '../utils'
6
7
  import type { TodoLinkSummary } from '../types'
7
8
  import { generateTempId } from '@open-mercato/core/modules/customers/lib/detailHelpers'
@@ -22,6 +23,7 @@ type CustomerTodoRow = {
22
23
  todoDueAt: string | null
23
24
  todoCustomValues: Record<string, unknown> | null
24
25
  todoOrganizationId: string | null
26
+ todoUpdatedAt?: string | null
25
27
  organizationId: string
26
28
  tenantId: string
27
29
  createdAt: string
@@ -83,6 +85,7 @@ function mapRowToSummary(row: CustomerTodoRow): TodoLinkSummary {
83
85
  description: row.todoDescription ?? null,
84
86
  dueAt: row.todoDueAt ?? null,
85
87
  todoOrganizationId: row.todoOrganizationId ?? null,
88
+ updatedAt: row.todoUpdatedAt ?? null,
86
89
  customValues: row.todoCustomValues ?? null,
87
90
  }
88
91
  }
@@ -369,14 +372,21 @@ export function usePersonTasks({
369
372
  if (Object.keys(customValues).length) {
370
373
  body.customFields = customValues
371
374
  }
372
- await apiCallOrThrow(
373
- apiPath,
374
- {
375
- method: 'PUT',
376
- headers: { 'content-type': 'application/json' },
377
- body: JSON.stringify(body),
378
- },
379
- { errorMessage: 'Failed to update task.' },
375
+ // Send the optimistic-lock header (task's loaded updatedAt) so a stale
376
+ // edit — or an edit after the task was deleted in another tab — surfaces
377
+ // the unified conflict bar (409) instead of silently overwriting or
378
+ // returning a bare "Interaction not found" 404 (#2055).
379
+ await withScopedApiRequestHeaders(
380
+ buildOptimisticLockHeader(task.updatedAt ?? null),
381
+ () => apiCallOrThrow(
382
+ apiPath,
383
+ {
384
+ method: 'PUT',
385
+ headers: { 'content-type': 'application/json' },
386
+ body: JSON.stringify(body),
387
+ },
388
+ { errorMessage: 'Failed to update task.' },
389
+ ),
380
390
  )
381
391
  setTasks((prev) =>
382
392
  prev.map((item) => {
@@ -440,14 +450,17 @@ export function usePersonTasks({
440
450
  if (!task.id) throw new Error('Task link id missing')
441
451
  setIsMutating(true)
442
452
  try {
443
- await apiCallOrThrow(
444
- '/api/customers/todos',
445
- {
446
- method: 'DELETE',
447
- headers: { 'content-type': 'application/json' },
448
- body: JSON.stringify({ id: task.id }),
449
- },
450
- { errorMessage: 'Failed to remove task.' },
453
+ await withScopedApiRequestHeaders(
454
+ buildOptimisticLockHeader(task.updatedAt ?? null),
455
+ () => apiCallOrThrow(
456
+ '/api/customers/todos',
457
+ {
458
+ method: 'DELETE',
459
+ headers: { 'content-type': 'application/json' },
460
+ body: JSON.stringify({ id: task.id }),
461
+ },
462
+ { errorMessage: 'Failed to remove task.' },
463
+ ),
451
464
  )
452
465
  setTasks((prev) => prev.filter((item) => item.id !== task.id))
453
466
  setPageInfo((prev) => ({