@open-mercato/core 0.7.1-develop.7178.1.ab93fbaf4e → 0.7.1-develop.7180.1.9717fbbb43

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 (808) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities/staff_time_entry/index.js +14 -0
  3. package/dist/generated/entities/staff_time_entry/index.js.map +2 -2
  4. package/dist/generated/entities/staff_time_entry_tag/index.js +15 -0
  5. package/dist/generated/entities/staff_time_entry_tag/index.js.map +7 -0
  6. package/dist/generated/entities/staff_time_project/index.js +16 -0
  7. package/dist/generated/entities/staff_time_project/index.js.map +2 -2
  8. package/dist/generated/entities/staff_time_report/index.js +57 -0
  9. package/dist/generated/entities/staff_time_report/index.js.map +7 -0
  10. package/dist/generated/entities/staff_time_report_entry/index.js +27 -0
  11. package/dist/generated/entities/staff_time_report_entry/index.js.map +7 -0
  12. package/dist/generated/entities/staff_time_report_event/index.js +21 -0
  13. package/dist/generated/entities/staff_time_report_event/index.js.map +7 -0
  14. package/dist/generated/entities/staff_time_report_project/index.js +15 -0
  15. package/dist/generated/entities/staff_time_report_project/index.js.map +7 -0
  16. package/dist/generated/entities/staff_time_tag/index.js +21 -0
  17. package/dist/generated/entities/staff_time_tag/index.js.map +7 -0
  18. package/dist/generated/entities/staff_time_task/index.js +37 -0
  19. package/dist/generated/entities/staff_time_task/index.js.map +7 -0
  20. package/dist/generated/entities/staff_time_task_comment/index.js +21 -0
  21. package/dist/generated/entities/staff_time_task_comment/index.js.map +7 -0
  22. package/dist/generated/entities/staff_time_task_status/index.js +29 -0
  23. package/dist/generated/entities/staff_time_task_status/index.js.map +7 -0
  24. package/dist/generated/entities/staff_time_task_tag/index.js +15 -0
  25. package/dist/generated/entities/staff_time_task_tag/index.js.map +7 -0
  26. package/dist/generated/entities.ids.generated.js +11 -1
  27. package/dist/generated/entities.ids.generated.js.map +2 -2
  28. package/dist/generated/entity-fields-registry.js +149 -0
  29. package/dist/generated/entity-fields-registry.js.map +2 -2
  30. package/dist/helpers/integration/timesheetFixtures.js +7 -0
  31. package/dist/helpers/integration/timesheetFixtures.js.map +2 -2
  32. package/dist/modules/auth/cli.js +16 -0
  33. package/dist/modules/auth/cli.js.map +2 -2
  34. package/dist/modules/auth/lib/backendChrome.js +1 -0
  35. package/dist/modules/auth/lib/backendChrome.js.map +2 -2
  36. package/dist/modules/customer_accounts/lib/customerRoleAcls.js +44 -0
  37. package/dist/modules/customer_accounts/lib/customerRoleAcls.js.map +7 -0
  38. package/dist/modules/customer_accounts/setup.js +1 -28
  39. package/dist/modules/customer_accounts/setup.js.map +2 -2
  40. package/dist/modules/data_sync/api/options.js +2 -0
  41. package/dist/modules/data_sync/api/options.js.map +2 -2
  42. package/dist/modules/data_sync/backend/data-sync/page.js +39 -17
  43. package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
  44. package/dist/modules/data_sync/lib/start-controls.js +42 -0
  45. package/dist/modules/data_sync/lib/start-controls.js.map +7 -0
  46. package/dist/modules/staff/acl.js +9 -1
  47. package/dist/modules/staff/acl.js.map +2 -2
  48. package/dist/modules/staff/ai-agents.js +142 -0
  49. package/dist/modules/staff/ai-agents.js.map +7 -0
  50. package/dist/modules/staff/ai-tools/time-tracking-pack.js +348 -0
  51. package/dist/modules/staff/ai-tools/time-tracking-pack.js.map +7 -0
  52. package/dist/modules/staff/ai-tools/types.js +54 -0
  53. package/dist/modules/staff/ai-tools/types.js.map +7 -0
  54. package/dist/modules/staff/ai-tools.js +8 -0
  55. package/dist/modules/staff/ai-tools.js.map +7 -0
  56. package/dist/modules/staff/analytics.js +84 -1
  57. package/dist/modules/staff/analytics.js.map +2 -2
  58. package/dist/modules/staff/api/guards.js +37 -3
  59. package/dist/modules/staff/api/guards.js.map +2 -2
  60. package/dist/modules/staff/api/leave-requests/accept/route.js +1 -3
  61. package/dist/modules/staff/api/leave-requests/accept/route.js.map +2 -2
  62. package/dist/modules/staff/api/leave-requests/reject/route.js +1 -3
  63. package/dist/modules/staff/api/leave-requests/reject/route.js.map +2 -2
  64. package/dist/modules/staff/api/portal/time-reports/[id]/route.js +131 -0
  65. package/dist/modules/staff/api/portal/time-reports/[id]/route.js.map +7 -0
  66. package/dist/modules/staff/api/portal/time-reports/route.js +179 -0
  67. package/dist/modules/staff/api/portal/time-reports/route.js.map +7 -0
  68. package/dist/modules/staff/api/team-members/self/route.js +1 -3
  69. package/dist/modules/staff/api/team-members/self/route.js.map +2 -2
  70. package/dist/modules/staff/api/team-members/tags/assign/route.js +1 -3
  71. package/dist/modules/staff/api/team-members/tags/assign/route.js.map +2 -2
  72. package/dist/modules/staff/api/team-members/tags/unassign/route.js +1 -3
  73. package/dist/modules/staff/api/team-members/tags/unassign/route.js.map +2 -2
  74. package/dist/modules/staff/api/timesheets/_shared/withTimesheetInterceptors.js +174 -0
  75. package/dist/modules/staff/api/timesheets/_shared/withTimesheetInterceptors.js.map +7 -0
  76. package/dist/modules/staff/api/timesheets/access-requests/route.js +226 -0
  77. package/dist/modules/staff/api/timesheets/access-requests/route.js.map +7 -0
  78. package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js +15 -8
  79. package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js.map +2 -2
  80. package/dist/modules/staff/api/timesheets/my-projects/route.js +13 -1
  81. package/dist/modules/staff/api/timesheets/my-projects/route.js.map +2 -2
  82. package/dist/modules/staff/api/timesheets/my-work/myWorkAggregate.js +42 -0
  83. package/dist/modules/staff/api/timesheets/my-work/myWorkAggregate.js.map +7 -0
  84. package/dist/modules/staff/api/timesheets/my-work/route.js +383 -0
  85. package/dist/modules/staff/api/timesheets/my-work/route.js.map +7 -0
  86. package/dist/modules/staff/api/timesheets/projects/kpis/route.js +14 -2
  87. package/dist/modules/staff/api/timesheets/projects/kpis/route.js.map +2 -2
  88. package/dist/modules/staff/api/timesheets/reports/[id]/close/route.js +168 -0
  89. package/dist/modules/staff/api/timesheets/reports/[id]/close/route.js.map +7 -0
  90. package/dist/modules/staff/api/timesheets/reports/[id]/export/route.js +246 -0
  91. package/dist/modules/staff/api/timesheets/reports/[id]/export/route.js.map +7 -0
  92. package/dist/modules/staff/api/timesheets/reports/[id]/sheet/route.js +183 -0
  93. package/dist/modules/staff/api/timesheets/reports/[id]/sheet/route.js.map +7 -0
  94. package/dist/modules/staff/api/timesheets/reports/[id]/unlock/route.js +164 -0
  95. package/dist/modules/staff/api/timesheets/reports/[id]/unlock/route.js.map +7 -0
  96. package/dist/modules/staff/api/timesheets/reports/preview/route.js +360 -0
  97. package/dist/modules/staff/api/timesheets/reports/preview/route.js.map +7 -0
  98. package/dist/modules/staff/api/timesheets/reports/route.js +316 -0
  99. package/dist/modules/staff/api/timesheets/reports/route.js.map +7 -0
  100. package/dist/modules/staff/api/timesheets/reports/shared.js +63 -0
  101. package/dist/modules/staff/api/timesheets/reports/shared.js.map +7 -0
  102. package/dist/modules/staff/api/timesheets/settings/reapply-rounding/route.js +164 -0
  103. package/dist/modules/staff/api/timesheets/settings/reapply-rounding/route.js.map +7 -0
  104. package/dist/modules/staff/api/timesheets/settings/rounding-impact/route.js +168 -0
  105. package/dist/modules/staff/api/timesheets/settings/rounding-impact/route.js.map +7 -0
  106. package/dist/modules/staff/api/timesheets/settings/route.js +199 -0
  107. package/dist/modules/staff/api/timesheets/settings/route.js.map +7 -0
  108. package/dist/modules/staff/api/timesheets/tags/access.js +76 -0
  109. package/dist/modules/staff/api/timesheets/tags/access.js.map +7 -0
  110. package/dist/modules/staff/api/timesheets/tags/entry-assignments/route.js +235 -0
  111. package/dist/modules/staff/api/timesheets/tags/entry-assignments/route.js.map +7 -0
  112. package/dist/modules/staff/api/timesheets/tags/route.js +160 -0
  113. package/dist/modules/staff/api/timesheets/tags/route.js.map +7 -0
  114. package/dist/modules/staff/api/timesheets/tags/task-assignments/route.js +233 -0
  115. package/dist/modules/staff/api/timesheets/tags/task-assignments/route.js.map +7 -0
  116. package/dist/modules/staff/api/timesheets/task-statuses/route.js +188 -0
  117. package/dist/modules/staff/api/timesheets/task-statuses/route.js.map +7 -0
  118. package/dist/modules/staff/api/timesheets/tasks/[id]/comments/route.js +399 -0
  119. package/dist/modules/staff/api/timesheets/tasks/[id]/comments/route.js.map +7 -0
  120. package/dist/modules/staff/api/timesheets/tasks/[id]/status/route.js +210 -0
  121. package/dist/modules/staff/api/timesheets/tasks/[id]/status/route.js.map +7 -0
  122. package/dist/modules/staff/api/timesheets/tasks/route.js +333 -0
  123. package/dist/modules/staff/api/timesheets/tasks/route.js.map +7 -0
  124. package/dist/modules/staff/api/timesheets/time-entries/[id]/duplicate/route.js +228 -0
  125. package/dist/modules/staff/api/timesheets/time-entries/[id]/duplicate/route.js.map +7 -0
  126. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js +29 -10
  127. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js.map +2 -2
  128. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js +31 -18
  129. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js.map +2 -2
  130. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js +21 -7
  131. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js.map +2 -2
  132. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js +27 -7
  133. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js.map +2 -2
  134. package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js +215 -32
  135. package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js.map +2 -2
  136. package/dist/modules/staff/api/timesheets/time-entries/copy-day/route.js +378 -0
  137. package/dist/modules/staff/api/timesheets/time-entries/copy-day/route.js.map +7 -0
  138. package/dist/modules/staff/api/timesheets/time-entries/overlaps/route.js +340 -0
  139. package/dist/modules/staff/api/timesheets/time-entries/overlaps/route.js.map +7 -0
  140. package/dist/modules/staff/api/timesheets/time-entries/route.js +238 -26
  141. package/dist/modules/staff/api/timesheets/time-entries/route.js.map +2 -2
  142. package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js +23 -8
  143. package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js.map +2 -2
  144. package/dist/modules/staff/api/timesheets/time-projects/[id]/change-currency/route.js +209 -0
  145. package/dist/modules/staff/api/timesheets/time-projects/[id]/change-currency/route.js.map +7 -0
  146. package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js +59 -2
  147. package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js.map +2 -2
  148. package/dist/modules/staff/api/timesheets/time-projects/route.js +264 -22
  149. package/dist/modules/staff/api/timesheets/time-projects/route.js.map +2 -2
  150. package/dist/modules/staff/backend/staff/time-tracking/board/page.js +110 -0
  151. package/dist/modules/staff/backend/staff/time-tracking/board/page.js.map +7 -0
  152. package/dist/modules/staff/backend/staff/time-tracking/board/page.meta.js +18 -0
  153. package/dist/modules/staff/backend/staff/time-tracking/board/page.meta.js.map +7 -0
  154. package/dist/modules/staff/backend/staff/time-tracking/entries/page.js +981 -0
  155. package/dist/modules/staff/backend/staff/time-tracking/entries/page.js.map +7 -0
  156. package/dist/modules/staff/backend/staff/time-tracking/entries/page.meta.js +18 -0
  157. package/dist/modules/staff/backend/staff/time-tracking/entries/page.meta.js.map +7 -0
  158. package/dist/modules/staff/backend/staff/time-tracking/page.js +583 -0
  159. package/dist/modules/staff/backend/staff/time-tracking/page.js.map +7 -0
  160. package/dist/modules/staff/backend/staff/time-tracking/page.meta.js +15 -0
  161. package/dist/modules/staff/backend/staff/time-tracking/page.meta.js.map +7 -0
  162. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.js +65 -0
  163. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.js.map +7 -0
  164. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.meta.js +16 -0
  165. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.meta.js.map +7 -0
  166. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.js +229 -0
  167. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.js.map +7 -0
  168. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.meta.js +16 -0
  169. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.meta.js.map +7 -0
  170. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js +1014 -0
  171. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js.map +7 -0
  172. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.meta.js +16 -0
  173. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.meta.js.map +7 -0
  174. package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.js +97 -0
  175. package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.js.map +7 -0
  176. package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.meta.js +16 -0
  177. package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.meta.js.map +7 -0
  178. package/dist/modules/staff/backend/staff/time-tracking/projects/page.js +1040 -0
  179. package/dist/modules/staff/backend/staff/time-tracking/projects/page.js.map +7 -0
  180. package/dist/modules/staff/backend/staff/time-tracking/projects/page.meta.js +19 -0
  181. package/dist/modules/staff/backend/staff/time-tracking/projects/page.meta.js.map +7 -0
  182. package/dist/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.js +353 -0
  183. package/dist/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.js.map +7 -0
  184. package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.js +457 -0
  185. package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.js.map +7 -0
  186. package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.meta.js +16 -0
  187. package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.meta.js.map +7 -0
  188. package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.js +697 -0
  189. package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.js.map +7 -0
  190. package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.meta.js +16 -0
  191. package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.meta.js.map +7 -0
  192. package/dist/modules/staff/backend/staff/time-tracking/reports/page.js +174 -0
  193. package/dist/modules/staff/backend/staff/time-tracking/reports/page.js.map +7 -0
  194. package/dist/modules/staff/backend/staff/time-tracking/reports/page.meta.js +18 -0
  195. package/dist/modules/staff/backend/staff/time-tracking/reports/page.meta.js.map +7 -0
  196. package/dist/modules/staff/backend/staff/time-tracking/settings/page.js +546 -0
  197. package/dist/modules/staff/backend/staff/time-tracking/settings/page.js.map +7 -0
  198. package/dist/modules/staff/backend/staff/time-tracking/settings/page.meta.js +18 -0
  199. package/dist/modules/staff/backend/staff/time-tracking/settings/page.meta.js.map +7 -0
  200. package/dist/modules/staff/backend/staff/time-tracking/timesheet/GridView.js +710 -0
  201. package/dist/modules/staff/backend/staff/time-tracking/timesheet/GridView.js.map +7 -0
  202. package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.js +646 -0
  203. package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.js.map +7 -0
  204. package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.meta.js +18 -0
  205. package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.meta.js.map +7 -0
  206. package/dist/modules/staff/backend/staff/timesheets/page.js +4 -793
  207. package/dist/modules/staff/backend/staff/timesheets/page.js.map +2 -2
  208. package/dist/modules/staff/backend/staff/timesheets/page.meta.js +2 -7
  209. package/dist/modules/staff/backend/staff/timesheets/page.meta.js.map +2 -2
  210. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.js +5 -136
  211. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.js.map +2 -2
  212. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.js +1 -7
  213. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.js.map +2 -2
  214. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js +5 -445
  215. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js.map +3 -3
  216. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.js +1 -7
  217. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.js.map +2 -2
  218. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.js +4 -76
  219. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.js.map +2 -2
  220. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.meta.js +1 -7
  221. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.meta.js.map +2 -2
  222. package/dist/modules/staff/backend/staff/timesheets/projects/page.js +4 -613
  223. package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
  224. package/dist/modules/staff/backend/staff/timesheets/projects/page.meta.js +2 -17
  225. package/dist/modules/staff/backend/staff/timesheets/projects/page.meta.js.map +2 -2
  226. package/dist/modules/staff/ce.js +40 -0
  227. package/dist/modules/staff/ce.js.map +2 -2
  228. package/dist/modules/staff/cli.js +166 -1
  229. package/dist/modules/staff/cli.js.map +2 -2
  230. package/dist/modules/staff/commands/index.js +5 -0
  231. package/dist/modules/staff/commands/index.js.map +2 -2
  232. package/dist/modules/staff/commands/timesheets-entries.js +569 -21
  233. package/dist/modules/staff/commands/timesheets-entries.js.map +3 -3
  234. package/dist/modules/staff/commands/timesheets-projects.js +450 -7
  235. package/dist/modules/staff/commands/timesheets-projects.js.map +2 -2
  236. package/dist/modules/staff/commands/timesheets-reports.js +1036 -0
  237. package/dist/modules/staff/commands/timesheets-reports.js.map +7 -0
  238. package/dist/modules/staff/commands/timesheets-tags.js +1015 -0
  239. package/dist/modules/staff/commands/timesheets-tags.js.map +7 -0
  240. package/dist/modules/staff/commands/timesheets-task-comments.js +438 -0
  241. package/dist/modules/staff/commands/timesheets-task-comments.js.map +7 -0
  242. package/dist/modules/staff/commands/timesheets-task-statuses.js +723 -0
  243. package/dist/modules/staff/commands/timesheets-task-statuses.js.map +7 -0
  244. package/dist/modules/staff/commands/timesheets-tasks.js +834 -0
  245. package/dist/modules/staff/commands/timesheets-tasks.js.map +7 -0
  246. package/dist/modules/staff/data/enrichers.js +426 -12
  247. package/dist/modules/staff/data/enrichers.js.map +2 -2
  248. package/dist/modules/staff/data/entities.js +552 -3
  249. package/dist/modules/staff/data/entities.js.map +2 -2
  250. package/dist/modules/staff/data/extensions.js +41 -0
  251. package/dist/modules/staff/data/extensions.js.map +7 -0
  252. package/dist/modules/staff/data/validators.js +254 -9
  253. package/dist/modules/staff/data/validators.js.map +2 -2
  254. package/dist/modules/staff/di.js +42 -1
  255. package/dist/modules/staff/di.js.map +2 -2
  256. package/dist/modules/staff/events.js +84 -6
  257. package/dist/modules/staff/events.js.map +2 -2
  258. package/dist/modules/staff/events.payloads.js +158 -0
  259. package/dist/modules/staff/events.payloads.js.map +7 -0
  260. package/dist/modules/staff/extension-points.js +261 -0
  261. package/dist/modules/staff/extension-points.js.map +7 -0
  262. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.js +138 -0
  263. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.js.map +7 -0
  264. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.meta.js +12 -0
  265. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.meta.js.map +7 -0
  266. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.js +133 -0
  267. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.js.map +7 -0
  268. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.meta.js +19 -0
  269. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.meta.js.map +7 -0
  270. package/dist/modules/staff/lib/crud.js +11 -1
  271. package/dist/modules/staff/lib/crud.js.map +2 -2
  272. package/dist/modules/staff/lib/time-tracking/access.js +92 -0
  273. package/dist/modules/staff/lib/time-tracking/access.js.map +7 -0
  274. package/dist/modules/staff/lib/time-tracking/billability.js +39 -0
  275. package/dist/modules/staff/lib/time-tracking/billability.js.map +7 -0
  276. package/dist/modules/staff/lib/time-tracking/capacity.js +68 -0
  277. package/dist/modules/staff/lib/time-tracking/capacity.js.map +7 -0
  278. package/dist/modules/staff/lib/time-tracking/componentContracts.js +15 -0
  279. package/dist/modules/staff/lib/time-tracking/componentContracts.js.map +7 -0
  280. package/dist/modules/staff/lib/time-tracking/cost.js +82 -0
  281. package/dist/modules/staff/lib/time-tracking/cost.js.map +7 -0
  282. package/dist/modules/staff/lib/time-tracking/duration.js +55 -0
  283. package/dist/modules/staff/lib/time-tracking/duration.js.map +7 -0
  284. package/dist/modules/staff/lib/time-tracking/featureAccess.js +41 -0
  285. package/dist/modules/staff/lib/time-tracking/featureAccess.js.map +7 -0
  286. package/dist/modules/staff/lib/time-tracking/interval.js +72 -0
  287. package/dist/modules/staff/lib/time-tracking/interval.js.map +7 -0
  288. package/dist/modules/staff/lib/time-tracking/migrateProjectCodes.js +88 -0
  289. package/dist/modules/staff/lib/time-tracking/migrateProjectCodes.js.map +7 -0
  290. package/dist/modules/staff/lib/time-tracking/moneyVisibility.js +10 -0
  291. package/dist/modules/staff/lib/time-tracking/moneyVisibility.js.map +7 -0
  292. package/dist/modules/staff/lib/time-tracking/overlap.js +87 -0
  293. package/dist/modules/staff/lib/time-tracking/overlap.js.map +7 -0
  294. package/dist/modules/staff/lib/time-tracking/portalRecipients.js +27 -0
  295. package/dist/modules/staff/lib/time-tracking/portalRecipients.js.map +7 -0
  296. package/dist/modules/staff/lib/time-tracking/portalReports.js +16 -0
  297. package/dist/modules/staff/lib/time-tracking/portalReports.js.map +7 -0
  298. package/dist/modules/staff/lib/time-tracking/projectCode.js +135 -0
  299. package/dist/modules/staff/lib/time-tracking/projectCode.js.map +7 -0
  300. package/dist/modules/staff/lib/time-tracking/reapplyRounding.js +187 -0
  301. package/dist/modules/staff/lib/time-tracking/reapplyRounding.js.map +7 -0
  302. package/dist/modules/staff/lib/time-tracking/recalculationRunner.js +80 -0
  303. package/dist/modules/staff/lib/time-tracking/recalculationRunner.js.map +7 -0
  304. package/dist/modules/staff/lib/time-tracking/recalculations.js +56 -0
  305. package/dist/modules/staff/lib/time-tracking/recalculations.js.map +7 -0
  306. package/dist/modules/staff/lib/time-tracking/registries/invoke.js +63 -0
  307. package/dist/modules/staff/lib/time-tracking/registries/invoke.js.map +7 -0
  308. package/dist/modules/staff/lib/time-tracking/registries/registry.js +62 -0
  309. package/dist/modules/staff/lib/time-tracking/registries/registry.js.map +7 -0
  310. package/dist/modules/staff/lib/time-tracking/registries/scope.js +21 -0
  311. package/dist/modules/staff/lib/time-tracking/registries/scope.js.map +7 -0
  312. package/dist/modules/staff/lib/time-tracking/rollup.js +34 -0
  313. package/dist/modules/staff/lib/time-tracking/rollup.js.map +7 -0
  314. package/dist/modules/staff/lib/time-tracking/rounding.js +66 -0
  315. package/dist/modules/staff/lib/time-tracking/rounding.js.map +7 -0
  316. package/dist/modules/staff/lib/time-tracking/roundingImpact.js +39 -0
  317. package/dist/modules/staff/lib/time-tracking/roundingImpact.js.map +7 -0
  318. package/dist/modules/staff/lib/time-tracking/settingKeys.js +214 -0
  319. package/dist/modules/staff/lib/time-tracking/settingKeys.js.map +7 -0
  320. package/dist/modules/staff/lib/time-tracking/settings.js +87 -0
  321. package/dist/modules/staff/lib/time-tracking/settings.js.map +7 -0
  322. package/dist/modules/staff/lib/time-tracking/sqlInClause.js +9 -0
  323. package/dist/modules/staff/lib/time-tracking/sqlInClause.js.map +7 -0
  324. package/dist/modules/staff/lib/time-tracking/timeEntrySources.js +48 -0
  325. package/dist/modules/staff/lib/time-tracking/timeEntrySources.js.map +7 -0
  326. package/dist/modules/staff/lib/time-tracking-ui/BoardFilterChips.js +283 -0
  327. package/dist/modules/staff/lib/time-tracking-ui/BoardFilterChips.js.map +7 -0
  328. package/dist/modules/staff/lib/time-tracking-ui/CustomerPicker.js +324 -0
  329. package/dist/modules/staff/lib/time-tracking-ui/CustomerPicker.js.map +7 -0
  330. package/dist/modules/staff/lib/time-tracking-ui/DurationInput.js +121 -0
  331. package/dist/modules/staff/lib/time-tracking-ui/DurationInput.js.map +7 -0
  332. package/dist/modules/staff/lib/time-tracking-ui/EntryDetailsFields.js +188 -0
  333. package/dist/modules/staff/lib/time-tracking-ui/EntryDetailsFields.js.map +7 -0
  334. package/dist/modules/staff/lib/time-tracking-ui/EntryFilterBar.js +89 -0
  335. package/dist/modules/staff/lib/time-tracking-ui/EntryFilterBar.js.map +7 -0
  336. package/dist/modules/staff/lib/time-tracking-ui/KanbanBoard.js +855 -0
  337. package/dist/modules/staff/lib/time-tracking-ui/KanbanBoard.js.map +7 -0
  338. package/dist/modules/staff/lib/time-tracking-ui/KanbanCard.js +360 -0
  339. package/dist/modules/staff/lib/time-tracking-ui/KanbanCard.js.map +7 -0
  340. package/dist/modules/staff/lib/time-tracking-ui/KanbanColumn.js +259 -0
  341. package/dist/modules/staff/lib/time-tracking-ui/KanbanColumn.js.map +7 -0
  342. package/dist/modules/staff/lib/time-tracking-ui/NewTaskDialog.js +238 -0
  343. package/dist/modules/staff/lib/time-tracking-ui/NewTaskDialog.js.map +7 -0
  344. package/dist/modules/staff/lib/time-tracking-ui/NoProjectAccess.js +130 -0
  345. package/dist/modules/staff/lib/time-tracking-ui/NoProjectAccess.js.map +7 -0
  346. package/dist/modules/staff/lib/time-tracking-ui/PeriodSelector.js +98 -0
  347. package/dist/modules/staff/lib/time-tracking-ui/PeriodSelector.js.map +7 -0
  348. package/dist/modules/staff/lib/time-tracking-ui/PhasePlaceholder.js +27 -0
  349. package/dist/modules/staff/lib/time-tracking-ui/PhasePlaceholder.js.map +7 -0
  350. package/dist/modules/staff/lib/time-tracking-ui/ProjectCodeField.js +166 -0
  351. package/dist/modules/staff/lib/time-tracking-ui/ProjectCodeField.js.map +7 -0
  352. package/dist/modules/staff/lib/time-tracking-ui/ProjectCurrencyField.js +295 -0
  353. package/dist/modules/staff/lib/time-tracking-ui/ProjectCurrencyField.js.map +7 -0
  354. package/dist/modules/staff/lib/time-tracking-ui/ProjectFormSections.js +212 -0
  355. package/dist/modules/staff/lib/time-tracking-ui/ProjectFormSections.js.map +7 -0
  356. package/dist/modules/staff/lib/time-tracking-ui/ProjectTeamDrawer.js +729 -0
  357. package/dist/modules/staff/lib/time-tracking-ui/ProjectTeamDrawer.js.map +7 -0
  358. package/dist/modules/staff/lib/time-tracking-ui/ReportSheet.js +217 -0
  359. package/dist/modules/staff/lib/time-tracking-ui/ReportSheet.js.map +7 -0
  360. package/dist/modules/staff/lib/time-tracking-ui/TagPicker.js +158 -0
  361. package/dist/modules/staff/lib/time-tracking-ui/TagPicker.js.map +7 -0
  362. package/dist/modules/staff/lib/time-tracking-ui/TaskBoardScreen.js +224 -0
  363. package/dist/modules/staff/lib/time-tracking-ui/TaskBoardScreen.js.map +7 -0
  364. package/dist/modules/staff/lib/time-tracking-ui/TaskCommentThread.js +93 -0
  365. package/dist/modules/staff/lib/time-tracking-ui/TaskCommentThread.js.map +7 -0
  366. package/dist/modules/staff/lib/time-tracking-ui/TaskDrawer.js +1196 -0
  367. package/dist/modules/staff/lib/time-tracking-ui/TaskDrawer.js.map +7 -0
  368. package/dist/modules/staff/lib/time-tracking-ui/TaskListView.js +176 -0
  369. package/dist/modules/staff/lib/time-tracking-ui/TaskListView.js.map +7 -0
  370. package/dist/modules/staff/lib/time-tracking-ui/TaskPicker.js +307 -0
  371. package/dist/modules/staff/lib/time-tracking-ui/TaskPicker.js.map +7 -0
  372. package/dist/modules/staff/lib/time-tracking-ui/TaskQuickLog.js +284 -0
  373. package/dist/modules/staff/lib/time-tracking-ui/TaskQuickLog.js.map +7 -0
  374. package/dist/modules/staff/lib/time-tracking-ui/TimeEntriesSummaryFooter.js +73 -0
  375. package/dist/modules/staff/lib/time-tracking-ui/TimeEntriesSummaryFooter.js.map +7 -0
  376. package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDialog.js +1499 -0
  377. package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDialog.js.map +7 -0
  378. package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDurationCell.js +95 -0
  379. package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDurationCell.js.map +7 -0
  380. package/dist/modules/staff/lib/time-tracking-ui/TimesheetCalendar.js +188 -0
  381. package/dist/modules/staff/lib/time-tracking-ui/TimesheetCalendar.js.map +7 -0
  382. package/dist/modules/staff/lib/time-tracking-ui/TimesheetPeriodFooter.js +61 -0
  383. package/dist/modules/staff/lib/time-tracking-ui/TimesheetPeriodFooter.js.map +7 -0
  384. package/dist/modules/staff/lib/time-tracking-ui/TimesheetViewSwitch.js +45 -0
  385. package/dist/modules/staff/lib/time-tracking-ui/TimesheetViewSwitch.js.map +7 -0
  386. package/dist/modules/staff/lib/time-tracking-ui/boardDirectory.js +176 -0
  387. package/dist/modules/staff/lib/time-tracking-ui/boardDirectory.js.map +7 -0
  388. package/dist/modules/staff/lib/time-tracking-ui/boardFilters.js +82 -0
  389. package/dist/modules/staff/lib/time-tracking-ui/boardFilters.js.map +7 -0
  390. package/dist/modules/staff/lib/time-tracking-ui/boardSummary.js +5 -0
  391. package/dist/modules/staff/lib/time-tracking-ui/boardSummary.js.map +7 -0
  392. package/dist/modules/staff/lib/time-tracking-ui/kanbanBoardData.js +152 -0
  393. package/dist/modules/staff/lib/time-tracking-ui/kanbanBoardData.js.map +7 -0
  394. package/dist/modules/staff/lib/time-tracking-ui/projectTeamAssignment.js +92 -0
  395. package/dist/modules/staff/lib/time-tracking-ui/projectTeamAssignment.js.map +7 -0
  396. package/dist/modules/staff/lib/time-tracking-ui/taskDrawerData.js +111 -0
  397. package/dist/modules/staff/lib/time-tracking-ui/taskDrawerData.js.map +7 -0
  398. package/dist/modules/staff/lib/time-tracking-ui/timeEntryDialogState.js +243 -0
  399. package/dist/modules/staff/lib/time-tracking-ui/timeEntryDialogState.js.map +7 -0
  400. package/dist/modules/staff/lib/time-tracking-ui/timeEntryListData.js +151 -0
  401. package/dist/modules/staff/lib/time-tracking-ui/timeEntryListData.js.map +7 -0
  402. package/dist/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.js +105 -0
  403. package/dist/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.js.map +7 -0
  404. package/dist/modules/staff/lib/time-tracking-ui/timesheetData.js +132 -0
  405. package/dist/modules/staff/lib/time-tracking-ui/timesheetData.js.map +7 -0
  406. package/dist/modules/staff/lib/time-tracking-ui/timesheetPeriod.js +205 -0
  407. package/dist/modules/staff/lib/time-tracking-ui/timesheetPeriod.js.map +7 -0
  408. package/dist/modules/staff/lib/time-tracking-ui/timesheetTargets.js +53 -0
  409. package/dist/modules/staff/lib/time-tracking-ui/timesheetTargets.js.map +7 -0
  410. package/dist/modules/staff/lib/time-tracking-ui/useBoardFilters.js +77 -0
  411. package/dist/modules/staff/lib/time-tracking-ui/useBoardFilters.js.map +7 -0
  412. package/dist/modules/staff/lib/time-tracking-ui/useTimesheetPreferences.js +151 -0
  413. package/dist/modules/staff/lib/time-tracking-ui/useTimesheetPreferences.js.map +7 -0
  414. package/dist/modules/staff/lib/timeTrackingSeeds.js +809 -0
  415. package/dist/modules/staff/lib/timeTrackingSeeds.js.map +7 -0
  416. package/dist/modules/staff/lib/timesheets/timeEntryCacheInvalidation.js +2 -3
  417. package/dist/modules/staff/lib/timesheets/timeEntryCacheInvalidation.js.map +2 -2
  418. package/dist/modules/staff/lib/timesheets/timeEntryDecoration.js +152 -0
  419. package/dist/modules/staff/lib/timesheets/timeEntryDecoration.js.map +7 -0
  420. package/dist/modules/staff/lib/timesheets-projects/budgetBurn.js +36 -0
  421. package/dist/modules/staff/lib/timesheets-projects/budgetBurn.js.map +7 -0
  422. package/dist/modules/staff/lib/timesheets-projects/budgetThreshold.js +66 -0
  423. package/dist/modules/staff/lib/timesheets-projects/budgetThreshold.js.map +7 -0
  424. package/dist/modules/staff/lib/timesheets-projects/budgetThresholdState.js +78 -0
  425. package/dist/modules/staff/lib/timesheets-projects/budgetThresholdState.js.map +7 -0
  426. package/dist/modules/staff/lib/timesheets-projects/computeProjectFinancials.js +81 -0
  427. package/dist/modules/staff/lib/timesheets-projects/computeProjectFinancials.js.map +7 -0
  428. package/dist/modules/staff/lib/timesheets-projects/reportSelection.js +44 -0
  429. package/dist/modules/staff/lib/timesheets-projects/reportSelection.js.map +7 -0
  430. package/dist/modules/staff/lib/timesheets-projects-ui/AssignMembersDialog.js +169 -0
  431. package/dist/modules/staff/lib/timesheets-projects-ui/AssignMembersDialog.js.map +7 -0
  432. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectBudgetCell.js +22 -0
  433. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectBudgetCell.js.map +7 -0
  434. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectCard.js +51 -1
  435. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectCard.js.map +2 -2
  436. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectsBulkActionsBar.js +70 -0
  437. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectsBulkActionsBar.js.map +7 -0
  438. package/dist/modules/staff/lib/timesheets-reports/buildReportSheet.js +63 -0
  439. package/dist/modules/staff/lib/timesheets-reports/buildReportSheet.js.map +7 -0
  440. package/dist/modules/staff/lib/timesheets-reports/loadReportData.js +170 -0
  441. package/dist/modules/staff/lib/timesheets-reports/loadReportData.js.map +7 -0
  442. package/dist/modules/staff/lib/timesheets-reports/pdf.js +205 -0
  443. package/dist/modules/staff/lib/timesheets-reports/pdf.js.map +7 -0
  444. package/dist/modules/staff/lib/timesheets-reports/reportApprovalPolicies.js +68 -0
  445. package/dist/modules/staff/lib/timesheets-reports/reportApprovalPolicies.js.map +7 -0
  446. package/dist/modules/staff/lib/timesheets-reports/reportConfigData.js +135 -0
  447. package/dist/modules/staff/lib/timesheets-reports/reportConfigData.js.map +7 -0
  448. package/dist/modules/staff/lib/timesheets-reports/reportConfigState.js +48 -0
  449. package/dist/modules/staff/lib/timesheets-reports/reportConfigState.js.map +7 -0
  450. package/dist/modules/staff/lib/timesheets-reports/reportExport.js +262 -0
  451. package/dist/modules/staff/lib/timesheets-reports/reportExport.js.map +7 -0
  452. package/dist/modules/staff/lib/timesheets-reports/reportExportFormats.js +34 -0
  453. package/dist/modules/staff/lib/timesheets-reports/reportExportFormats.js.map +7 -0
  454. package/dist/modules/staff/lib/timesheets-reports/reportGroupings.js +79 -0
  455. package/dist/modules/staff/lib/timesheets-reports/reportGroupings.js.map +7 -0
  456. package/dist/modules/staff/lib/timesheets-reports/reportLabels.js +11 -0
  457. package/dist/modules/staff/lib/timesheets-reports/reportLabels.js.map +7 -0
  458. package/dist/modules/staff/lib/timesheets-reports/reportReference.js +83 -0
  459. package/dist/modules/staff/lib/timesheets-reports/reportReference.js.map +7 -0
  460. package/dist/modules/staff/lib/timesheets-reports/reportRows.js +42 -0
  461. package/dist/modules/staff/lib/timesheets-reports/reportRows.js.map +7 -0
  462. package/dist/modules/staff/lib/timesheets-reports/reportSheetData.js +107 -0
  463. package/dist/modules/staff/lib/timesheets-reports/reportSheetData.js.map +7 -0
  464. package/dist/modules/staff/lib/timesheets-reports/reportTotals.js +289 -0
  465. package/dist/modules/staff/lib/timesheets-reports/reportTotals.js.map +7 -0
  466. package/dist/modules/staff/lib/timesheets-reports/xlsx.js +145 -0
  467. package/dist/modules/staff/lib/timesheets-reports/xlsx.js.map +7 -0
  468. package/dist/modules/staff/lib/timesheets-tasks/computeTaskRollups.js +116 -0
  469. package/dist/modules/staff/lib/timesheets-tasks/computeTaskRollups.js.map +7 -0
  470. package/dist/modules/staff/lib/timesheets-tasks/defaultStatusTemplate.js +50 -0
  471. package/dist/modules/staff/lib/timesheets-tasks/defaultStatusTemplate.js.map +7 -0
  472. package/dist/modules/staff/lib/timesheets-tasks/seedProjectStatuses.js +27 -0
  473. package/dist/modules/staff/lib/timesheets-tasks/seedProjectStatuses.js.map +7 -0
  474. package/dist/modules/staff/lib/timesheets-tasks/statusPositions.js +65 -0
  475. package/dist/modules/staff/lib/timesheets-tasks/statusPositions.js.map +7 -0
  476. package/dist/modules/staff/lib/timesheets-tasks/statusSlug.js +31 -0
  477. package/dist/modules/staff/lib/timesheets-tasks/statusSlug.js.map +7 -0
  478. package/dist/modules/staff/lib/timesheets-tasks/taskHierarchy.js +31 -0
  479. package/dist/modules/staff/lib/timesheets-tasks/taskHierarchy.js.map +7 -0
  480. package/dist/modules/staff/lib/timesheets-tasks/taskHoursTotals.js +17 -0
  481. package/dist/modules/staff/lib/timesheets-tasks/taskHoursTotals.js.map +7 -0
  482. package/dist/modules/staff/lib/timesheets-tasks/taskReference.js +51 -0
  483. package/dist/modules/staff/lib/timesheets-tasks/taskReference.js.map +7 -0
  484. package/dist/modules/staff/lib/timesheets-ui/CreateProjectDialog.js +11 -4
  485. package/dist/modules/staff/lib/timesheets-ui/CreateProjectDialog.js.map +2 -2
  486. package/dist/modules/staff/lib/timesheets-ui/ListView.js +369 -111
  487. package/dist/modules/staff/lib/timesheets-ui/ListView.js.map +2 -2
  488. package/dist/modules/staff/lib/timesheets-ui/TimerBar.js +47 -2
  489. package/dist/modules/staff/lib/timesheets-ui/TimerBar.js.map +2 -2
  490. package/dist/modules/staff/migrations/Migration20260813073131_staff.js +79 -0
  491. package/dist/modules/staff/migrations/Migration20260813073131_staff.js.map +7 -0
  492. package/dist/modules/staff/migrations/Migration20260824143357_staff.js +15 -0
  493. package/dist/modules/staff/migrations/Migration20260824143357_staff.js.map +7 -0
  494. package/dist/modules/staff/notifications.client.js +16 -0
  495. package/dist/modules/staff/notifications.client.js.map +7 -0
  496. package/dist/modules/staff/notifications.handlers.js +80 -0
  497. package/dist/modules/staff/notifications.handlers.js.map +7 -0
  498. package/dist/modules/staff/notifications.js +168 -0
  499. package/dist/modules/staff/notifications.js.map +2 -2
  500. package/dist/modules/staff/search.js +159 -1
  501. package/dist/modules/staff/search.js.map +2 -2
  502. package/dist/modules/staff/setup.js +20 -1
  503. package/dist/modules/staff/setup.js.map +2 -2
  504. package/dist/modules/staff/subscribers/time-project-access-requested-notification.js +68 -0
  505. package/dist/modules/staff/subscribers/time-project-access-requested-notification.js.map +7 -0
  506. package/dist/modules/staff/subscribers/time-project-budget-threshold-notification.js +149 -0
  507. package/dist/modules/staff/subscribers/time-project-budget-threshold-notification.js.map +7 -0
  508. package/dist/modules/staff/subscribers/time-report-approved-notification.js +78 -0
  509. package/dist/modules/staff/subscribers/time-report-approved-notification.js.map +7 -0
  510. package/dist/modules/staff/subscribers/time-report-portal-broadcast.js +78 -0
  511. package/dist/modules/staff/subscribers/time-report-portal-broadcast.js.map +7 -0
  512. package/dist/modules/staff/translations.js +4 -1
  513. package/dist/modules/staff/translations.js.map +2 -2
  514. package/dist/modules/staff/widgets/components.js +7 -0
  515. package/dist/modules/staff/widgets/components.js.map +7 -0
  516. package/dist/modules/staff/widgets/injection/timer-sidebar-indicator/widget.js +5 -4
  517. package/dist/modules/staff/widgets/injection/timer-sidebar-indicator/widget.js.map +2 -2
  518. package/dist/modules/staff/widgets/notifications/TimeProjectAccessRequestedRenderer.js +135 -0
  519. package/dist/modules/staff/widgets/notifications/TimeProjectAccessRequestedRenderer.js.map +7 -0
  520. package/dist/modules/staff/widgets/notifications/index.js +5 -0
  521. package/dist/modules/staff/widgets/notifications/index.js.map +7 -0
  522. package/dist/modules/staff/workers/timesheets-reapply-rounding.js +43 -0
  523. package/dist/modules/staff/workers/timesheets-reapply-rounding.js.map +7 -0
  524. package/generated/entities/staff_time_entry/index.ts +7 -0
  525. package/generated/entities/staff_time_entry_tag/index.ts +6 -0
  526. package/generated/entities/staff_time_project/index.ts +8 -0
  527. package/generated/entities/staff_time_report/index.ts +27 -0
  528. package/generated/entities/staff_time_report_entry/index.ts +12 -0
  529. package/generated/entities/staff_time_report_event/index.ts +9 -0
  530. package/generated/entities/staff_time_report_project/index.ts +6 -0
  531. package/generated/entities/staff_time_tag/index.ts +9 -0
  532. package/generated/entities/staff_time_task/index.ts +17 -0
  533. package/generated/entities/staff_time_task_comment/index.ts +9 -0
  534. package/generated/entities/staff_time_task_status/index.ts +13 -0
  535. package/generated/entities/staff_time_task_tag/index.ts +6 -0
  536. package/generated/entities.ids.generated.ts +11 -1
  537. package/generated/entity-fields-registry.ts +149 -0
  538. package/package.json +7 -7
  539. package/src/helpers/integration/timesheetFixtures.ts +31 -1
  540. package/src/modules/auth/README.md +1 -1
  541. package/src/modules/auth/cli.ts +35 -1
  542. package/src/modules/auth/i18n/de.json +7 -0
  543. package/src/modules/auth/i18n/en.json +7 -0
  544. package/src/modules/auth/i18n/es.json +7 -0
  545. package/src/modules/auth/i18n/ko.json +7 -0
  546. package/src/modules/auth/i18n/pl.json +7 -0
  547. package/src/modules/auth/lib/backendChrome.tsx +1 -0
  548. package/src/modules/customer_accounts/lib/customerRoleAcls.ts +79 -0
  549. package/src/modules/customer_accounts/setup.ts +1 -45
  550. package/src/modules/data_sync/AGENTS.md +34 -0
  551. package/src/modules/data_sync/api/options.ts +2 -0
  552. package/src/modules/data_sync/backend/data-sync/page.tsx +82 -33
  553. package/src/modules/data_sync/i18n/de.json +1 -0
  554. package/src/modules/data_sync/i18n/en.json +1 -0
  555. package/src/modules/data_sync/i18n/es.json +1 -0
  556. package/src/modules/data_sync/i18n/ko.json +1 -0
  557. package/src/modules/data_sync/i18n/pl.json +1 -0
  558. package/src/modules/data_sync/lib/adapter.ts +45 -0
  559. package/src/modules/data_sync/lib/start-controls.ts +89 -0
  560. package/src/modules/staff/AGENTS.md +769 -1
  561. package/src/modules/staff/acl.ts +9 -0
  562. package/src/modules/staff/ai-agents.ts +189 -0
  563. package/src/modules/staff/ai-tools/time-tracking-pack.ts +494 -0
  564. package/src/modules/staff/ai-tools/types.ts +82 -0
  565. package/src/modules/staff/ai-tools.ts +13 -0
  566. package/src/modules/staff/analytics.ts +113 -0
  567. package/src/modules/staff/api/guards.ts +85 -3
  568. package/src/modules/staff/api/leave-requests/accept/route.ts +0 -2
  569. package/src/modules/staff/api/leave-requests/reject/route.ts +0 -2
  570. package/src/modules/staff/api/portal/time-reports/[id]/route.ts +182 -0
  571. package/src/modules/staff/api/portal/time-reports/route.ts +270 -0
  572. package/src/modules/staff/api/team-members/self/route.ts +0 -2
  573. package/src/modules/staff/api/team-members/tags/assign/route.ts +0 -2
  574. package/src/modules/staff/api/team-members/tags/unassign/route.ts +0 -2
  575. package/src/modules/staff/api/timesheets/_shared/withTimesheetInterceptors.ts +292 -0
  576. package/src/modules/staff/api/timesheets/access-requests/route.ts +299 -0
  577. package/src/modules/staff/api/timesheets/my-projects/[projectId]/route.ts +15 -7
  578. package/src/modules/staff/api/timesheets/my-projects/route.ts +14 -1
  579. package/src/modules/staff/api/timesheets/my-work/myWorkAggregate.ts +90 -0
  580. package/src/modules/staff/api/timesheets/my-work/route.ts +475 -0
  581. package/src/modules/staff/api/timesheets/projects/kpis/route.ts +15 -2
  582. package/src/modules/staff/api/timesheets/reports/[id]/close/route.ts +203 -0
  583. package/src/modules/staff/api/timesheets/reports/[id]/export/route.ts +315 -0
  584. package/src/modules/staff/api/timesheets/reports/[id]/sheet/route.ts +220 -0
  585. package/src/modules/staff/api/timesheets/reports/[id]/unlock/route.ts +208 -0
  586. package/src/modules/staff/api/timesheets/reports/preview/route.ts +449 -0
  587. package/src/modules/staff/api/timesheets/reports/route.ts +386 -0
  588. package/src/modules/staff/api/timesheets/reports/shared.ts +121 -0
  589. package/src/modules/staff/api/timesheets/settings/reapply-rounding/route.ts +205 -0
  590. package/src/modules/staff/api/timesheets/settings/rounding-impact/route.ts +226 -0
  591. package/src/modules/staff/api/timesheets/settings/route.ts +242 -0
  592. package/src/modules/staff/api/timesheets/tags/access.ts +134 -0
  593. package/src/modules/staff/api/timesheets/tags/entry-assignments/route.ts +290 -0
  594. package/src/modules/staff/api/timesheets/tags/route.ts +177 -0
  595. package/src/modules/staff/api/timesheets/tags/task-assignments/route.ts +294 -0
  596. package/src/modules/staff/api/timesheets/task-statuses/route.ts +232 -0
  597. package/src/modules/staff/api/timesheets/tasks/[id]/comments/route.ts +532 -0
  598. package/src/modules/staff/api/timesheets/tasks/[id]/status/route.ts +271 -0
  599. package/src/modules/staff/api/timesheets/tasks/route.ts +443 -0
  600. package/src/modules/staff/api/timesheets/time-entries/[id]/duplicate/route.ts +306 -0
  601. package/src/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.ts +32 -10
  602. package/src/modules/staff/api/timesheets/time-entries/[id]/segments/route.ts +32 -17
  603. package/src/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.ts +27 -6
  604. package/src/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.ts +36 -6
  605. package/src/modules/staff/api/timesheets/time-entries/bulk/route.ts +331 -34
  606. package/src/modules/staff/api/timesheets/time-entries/copy-day/route.ts +533 -0
  607. package/src/modules/staff/api/timesheets/time-entries/overlaps/route.ts +457 -0
  608. package/src/modules/staff/api/timesheets/time-entries/route.ts +378 -24
  609. package/src/modules/staff/api/timesheets/time-entries/start-timer/route.ts +31 -9
  610. package/src/modules/staff/api/timesheets/time-projects/[id]/change-currency/route.ts +246 -0
  611. package/src/modules/staff/api/timesheets/time-projects/[id]/employees/route.ts +62 -2
  612. package/src/modules/staff/api/timesheets/time-projects/route.ts +397 -22
  613. package/src/modules/staff/backend/staff/time-tracking/board/page.meta.ts +14 -0
  614. package/src/modules/staff/backend/staff/time-tracking/board/page.tsx +151 -0
  615. package/src/modules/staff/backend/staff/time-tracking/entries/page.meta.ts +14 -0
  616. package/src/modules/staff/backend/staff/time-tracking/entries/page.tsx +1229 -0
  617. package/src/modules/staff/backend/staff/time-tracking/page.meta.ts +11 -0
  618. package/src/modules/staff/backend/staff/time-tracking/page.tsx +823 -0
  619. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.meta.ts +12 -0
  620. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.tsx +81 -0
  621. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.meta.ts +12 -0
  622. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.tsx +275 -0
  623. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/page.meta.ts +12 -0
  624. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/page.tsx +1420 -0
  625. package/src/modules/staff/backend/staff/time-tracking/projects/create/page.meta.ts +12 -0
  626. package/src/modules/staff/backend/staff/time-tracking/projects/create/page.tsx +109 -0
  627. package/src/modules/staff/backend/staff/time-tracking/projects/page.meta.ts +15 -0
  628. package/src/modules/staff/backend/staff/time-tracking/projects/page.tsx +1254 -0
  629. package/src/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.ts +466 -0
  630. package/src/modules/staff/backend/staff/time-tracking/reports/[id]/page.meta.ts +12 -0
  631. package/src/modules/staff/backend/staff/time-tracking/reports/[id]/page.tsx +632 -0
  632. package/src/modules/staff/backend/staff/time-tracking/reports/create/page.meta.ts +12 -0
  633. package/src/modules/staff/backend/staff/time-tracking/reports/create/page.tsx +867 -0
  634. package/src/modules/staff/backend/staff/time-tracking/reports/page.meta.ts +14 -0
  635. package/src/modules/staff/backend/staff/time-tracking/reports/page.tsx +246 -0
  636. package/src/modules/staff/backend/staff/time-tracking/settings/page.meta.ts +14 -0
  637. package/src/modules/staff/backend/staff/time-tracking/settings/page.tsx +701 -0
  638. package/src/modules/staff/backend/staff/time-tracking/timesheet/GridView.tsx +953 -0
  639. package/src/modules/staff/backend/staff/time-tracking/timesheet/page.meta.ts +14 -0
  640. package/src/modules/staff/backend/staff/time-tracking/timesheet/page.tsx +800 -0
  641. package/src/modules/staff/backend/staff/timesheets/page.meta.ts +6 -6
  642. package/src/modules/staff/backend/staff/timesheets/page.tsx +12 -1010
  643. package/src/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.ts +0 -6
  644. package/src/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.tsx +4 -158
  645. package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.ts +0 -6
  646. package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.tsx +4 -609
  647. package/src/modules/staff/backend/staff/timesheets/projects/create/page.meta.ts +0 -6
  648. package/src/modules/staff/backend/staff/timesheets/projects/create/page.tsx +3 -89
  649. package/src/modules/staff/backend/staff/timesheets/projects/page.meta.ts +2 -19
  650. package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +3 -778
  651. package/src/modules/staff/ce.ts +63 -0
  652. package/src/modules/staff/cli.ts +207 -1
  653. package/src/modules/staff/commands/index.ts +5 -0
  654. package/src/modules/staff/commands/timesheets-entries.ts +1006 -28
  655. package/src/modules/staff/commands/timesheets-projects.ts +593 -7
  656. package/src/modules/staff/commands/timesheets-reports.ts +1329 -0
  657. package/src/modules/staff/commands/timesheets-tags.ts +1315 -0
  658. package/src/modules/staff/commands/timesheets-task-comments.ts +583 -0
  659. package/src/modules/staff/commands/timesheets-task-statuses.ts +889 -0
  660. package/src/modules/staff/commands/timesheets-tasks.ts +1121 -0
  661. package/src/modules/staff/data/enrichers.ts +675 -10
  662. package/src/modules/staff/data/entities.ts +494 -2
  663. package/src/modules/staff/data/extensions.ts +68 -0
  664. package/src/modules/staff/data/validators.ts +348 -3
  665. package/src/modules/staff/di.ts +96 -0
  666. package/src/modules/staff/events.payloads.ts +268 -0
  667. package/src/modules/staff/events.ts +87 -5
  668. package/src/modules/staff/extension-points.ts +308 -0
  669. package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.meta.ts +10 -0
  670. package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.tsx +225 -0
  671. package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/page.meta.ts +17 -0
  672. package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/page.tsx +182 -0
  673. package/src/modules/staff/i18n/de.json +899 -0
  674. package/src/modules/staff/i18n/en.json +899 -0
  675. package/src/modules/staff/i18n/es.json +899 -0
  676. package/src/modules/staff/i18n/ko.json +899 -0
  677. package/src/modules/staff/i18n/pl.json +899 -0
  678. package/src/modules/staff/lib/crud.ts +14 -3
  679. package/src/modules/staff/lib/time-tracking/access.ts +155 -0
  680. package/src/modules/staff/lib/time-tracking/billability.ts +68 -0
  681. package/src/modules/staff/lib/time-tracking/capacity.ts +124 -0
  682. package/src/modules/staff/lib/time-tracking/componentContracts.ts +26 -0
  683. package/src/modules/staff/lib/time-tracking/cost.ts +144 -0
  684. package/src/modules/staff/lib/time-tracking/duration.ts +68 -0
  685. package/src/modules/staff/lib/time-tracking/featureAccess.ts +115 -0
  686. package/src/modules/staff/lib/time-tracking/interval.ts +90 -0
  687. package/src/modules/staff/lib/time-tracking/migrateProjectCodes.ts +161 -0
  688. package/src/modules/staff/lib/time-tracking/moneyVisibility.ts +37 -0
  689. package/src/modules/staff/lib/time-tracking/overlap.ts +159 -0
  690. package/src/modules/staff/lib/time-tracking/portalRecipients.ts +76 -0
  691. package/src/modules/staff/lib/time-tracking/portalReports.ts +31 -0
  692. package/src/modules/staff/lib/time-tracking/projectCode.ts +221 -0
  693. package/src/modules/staff/lib/time-tracking/reapplyRounding.ts +313 -0
  694. package/src/modules/staff/lib/time-tracking/recalculationRunner.ts +118 -0
  695. package/src/modules/staff/lib/time-tracking/recalculations.ts +135 -0
  696. package/src/modules/staff/lib/time-tracking/registries/invoke.ts +122 -0
  697. package/src/modules/staff/lib/time-tracking/registries/registry.ts +124 -0
  698. package/src/modules/staff/lib/time-tracking/registries/scope.ts +56 -0
  699. package/src/modules/staff/lib/time-tracking/rollup.ts +59 -0
  700. package/src/modules/staff/lib/time-tracking/rounding.ts +126 -0
  701. package/src/modules/staff/lib/time-tracking/roundingImpact.ts +75 -0
  702. package/src/modules/staff/lib/time-tracking/settingKeys.ts +274 -0
  703. package/src/modules/staff/lib/time-tracking/settings.ts +168 -0
  704. package/src/modules/staff/lib/time-tracking/sqlInClause.ts +22 -0
  705. package/src/modules/staff/lib/time-tracking/timeEntrySources.ts +85 -0
  706. package/src/modules/staff/lib/time-tracking-ui/BoardFilterChips.tsx +360 -0
  707. package/src/modules/staff/lib/time-tracking-ui/CustomerPicker.tsx +427 -0
  708. package/src/modules/staff/lib/time-tracking-ui/DurationInput.tsx +192 -0
  709. package/src/modules/staff/lib/time-tracking-ui/EntryDetailsFields.tsx +224 -0
  710. package/src/modules/staff/lib/time-tracking-ui/EntryFilterBar.tsx +144 -0
  711. package/src/modules/staff/lib/time-tracking-ui/KanbanBoard.tsx +1065 -0
  712. package/src/modules/staff/lib/time-tracking-ui/KanbanCard.tsx +435 -0
  713. package/src/modules/staff/lib/time-tracking-ui/KanbanColumn.tsx +316 -0
  714. package/src/modules/staff/lib/time-tracking-ui/NewTaskDialog.tsx +291 -0
  715. package/src/modules/staff/lib/time-tracking-ui/NoProjectAccess.tsx +162 -0
  716. package/src/modules/staff/lib/time-tracking-ui/PeriodSelector.tsx +149 -0
  717. package/src/modules/staff/lib/time-tracking-ui/PhasePlaceholder.tsx +31 -0
  718. package/src/modules/staff/lib/time-tracking-ui/ProjectCodeField.tsx +230 -0
  719. package/src/modules/staff/lib/time-tracking-ui/ProjectCurrencyField.tsx +432 -0
  720. package/src/modules/staff/lib/time-tracking-ui/ProjectFormSections.tsx +323 -0
  721. package/src/modules/staff/lib/time-tracking-ui/ProjectTeamDrawer.tsx +930 -0
  722. package/src/modules/staff/lib/time-tracking-ui/ReportSheet.tsx +357 -0
  723. package/src/modules/staff/lib/time-tracking-ui/TagPicker.tsx +195 -0
  724. package/src/modules/staff/lib/time-tracking-ui/TaskBoardScreen.tsx +243 -0
  725. package/src/modules/staff/lib/time-tracking-ui/TaskCommentThread.tsx +137 -0
  726. package/src/modules/staff/lib/time-tracking-ui/TaskDrawer.tsx +1405 -0
  727. package/src/modules/staff/lib/time-tracking-ui/TaskListView.tsx +260 -0
  728. package/src/modules/staff/lib/time-tracking-ui/TaskPicker.tsx +435 -0
  729. package/src/modules/staff/lib/time-tracking-ui/TaskQuickLog.tsx +296 -0
  730. package/src/modules/staff/lib/time-tracking-ui/TimeEntriesSummaryFooter.tsx +97 -0
  731. package/src/modules/staff/lib/time-tracking-ui/TimeEntryDialog.tsx +1929 -0
  732. package/src/modules/staff/lib/time-tracking-ui/TimeEntryDurationCell.tsx +126 -0
  733. package/src/modules/staff/lib/time-tracking-ui/TimesheetCalendar.tsx +265 -0
  734. package/src/modules/staff/lib/time-tracking-ui/TimesheetPeriodFooter.tsx +78 -0
  735. package/src/modules/staff/lib/time-tracking-ui/TimesheetViewSwitch.tsx +70 -0
  736. package/src/modules/staff/lib/time-tracking-ui/boardDirectory.ts +231 -0
  737. package/src/modules/staff/lib/time-tracking-ui/boardFilters.ts +128 -0
  738. package/src/modules/staff/lib/time-tracking-ui/boardSummary.ts +20 -0
  739. package/src/modules/staff/lib/time-tracking-ui/kanbanBoardData.ts +228 -0
  740. package/src/modules/staff/lib/time-tracking-ui/projectTeamAssignment.ts +143 -0
  741. package/src/modules/staff/lib/time-tracking-ui/taskDrawerData.ts +194 -0
  742. package/src/modules/staff/lib/time-tracking-ui/timeEntryDialogState.ts +400 -0
  743. package/src/modules/staff/lib/time-tracking-ui/timeEntryListData.ts +271 -0
  744. package/src/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.ts +168 -0
  745. package/src/modules/staff/lib/time-tracking-ui/timesheetData.ts +225 -0
  746. package/src/modules/staff/lib/time-tracking-ui/timesheetPeriod.ts +278 -0
  747. package/src/modules/staff/lib/time-tracking-ui/timesheetTargets.ts +93 -0
  748. package/src/modules/staff/lib/time-tracking-ui/useBoardFilters.ts +107 -0
  749. package/src/modules/staff/lib/time-tracking-ui/useTimesheetPreferences.ts +245 -0
  750. package/src/modules/staff/lib/timeTrackingSeeds.ts +1037 -0
  751. package/src/modules/staff/lib/timesheets/timeEntryCacheInvalidation.ts +11 -10
  752. package/src/modules/staff/lib/timesheets/timeEntryDecoration.ts +256 -0
  753. package/src/modules/staff/lib/timesheets-projects/budgetBurn.ts +60 -0
  754. package/src/modules/staff/lib/timesheets-projects/budgetThreshold.ts +135 -0
  755. package/src/modules/staff/lib/timesheets-projects/budgetThresholdState.ts +137 -0
  756. package/src/modules/staff/lib/timesheets-projects/computeProjectFinancials.ts +142 -0
  757. package/src/modules/staff/lib/timesheets-projects/reportSelection.ts +82 -0
  758. package/src/modules/staff/lib/timesheets-projects-ui/AssignMembersDialog.tsx +237 -0
  759. package/src/modules/staff/lib/timesheets-projects-ui/ProjectBudgetCell.tsx +33 -0
  760. package/src/modules/staff/lib/timesheets-projects-ui/ProjectCard.tsx +56 -1
  761. package/src/modules/staff/lib/timesheets-projects-ui/ProjectsBulkActionsBar.tsx +90 -0
  762. package/src/modules/staff/lib/timesheets-reports/buildReportSheet.ts +125 -0
  763. package/src/modules/staff/lib/timesheets-reports/loadReportData.ts +251 -0
  764. package/src/modules/staff/lib/timesheets-reports/pdf.ts +263 -0
  765. package/src/modules/staff/lib/timesheets-reports/reportApprovalPolicies.ts +137 -0
  766. package/src/modules/staff/lib/timesheets-reports/reportConfigData.ts +247 -0
  767. package/src/modules/staff/lib/timesheets-reports/reportConfigState.ts +89 -0
  768. package/src/modules/staff/lib/timesheets-reports/reportExport.ts +373 -0
  769. package/src/modules/staff/lib/timesheets-reports/reportExportFormats.ts +71 -0
  770. package/src/modules/staff/lib/timesheets-reports/reportGroupings.ts +153 -0
  771. package/src/modules/staff/lib/timesheets-reports/reportLabels.ts +23 -0
  772. package/src/modules/staff/lib/timesheets-reports/reportReference.ts +146 -0
  773. package/src/modules/staff/lib/timesheets-reports/reportRows.ts +89 -0
  774. package/src/modules/staff/lib/timesheets-reports/reportSheetData.ts +196 -0
  775. package/src/modules/staff/lib/timesheets-reports/reportTotals.ts +544 -0
  776. package/src/modules/staff/lib/timesheets-reports/xlsx.ts +207 -0
  777. package/src/modules/staff/lib/timesheets-tasks/computeTaskRollups.ts +238 -0
  778. package/src/modules/staff/lib/timesheets-tasks/defaultStatusTemplate.ts +90 -0
  779. package/src/modules/staff/lib/timesheets-tasks/seedProjectStatuses.ts +43 -0
  780. package/src/modules/staff/lib/timesheets-tasks/statusPositions.ts +132 -0
  781. package/src/modules/staff/lib/timesheets-tasks/statusSlug.ts +43 -0
  782. package/src/modules/staff/lib/timesheets-tasks/taskHierarchy.ts +99 -0
  783. package/src/modules/staff/lib/timesheets-tasks/taskHoursTotals.ts +42 -0
  784. package/src/modules/staff/lib/timesheets-tasks/taskReference.ts +108 -0
  785. package/src/modules/staff/lib/timesheets-ui/CreateProjectDialog.tsx +18 -4
  786. package/src/modules/staff/lib/timesheets-ui/ListView.tsx +504 -149
  787. package/src/modules/staff/lib/timesheets-ui/TimerBar.tsx +50 -2
  788. package/src/modules/staff/migrations/.snapshot-open-mercato.json +3244 -228
  789. package/src/modules/staff/migrations/Migration20260813073131_staff.ts +94 -0
  790. package/src/modules/staff/migrations/Migration20260824143357_staff.ts +17 -0
  791. package/src/modules/staff/notifications.client.ts +16 -0
  792. package/src/modules/staff/notifications.handlers.ts +88 -0
  793. package/src/modules/staff/notifications.ts +163 -0
  794. package/src/modules/staff/search.ts +191 -1
  795. package/src/modules/staff/setup.ts +22 -0
  796. package/src/modules/staff/subscribers/time-project-access-requested-notification.ts +95 -0
  797. package/src/modules/staff/subscribers/time-project-budget-threshold-notification.ts +226 -0
  798. package/src/modules/staff/subscribers/time-report-approved-notification.ts +116 -0
  799. package/src/modules/staff/subscribers/time-report-portal-broadcast.ts +120 -0
  800. package/src/modules/staff/translations.ts +17 -0
  801. package/src/modules/staff/widgets/components.ts +34 -0
  802. package/src/modules/staff/widgets/injection/timer-sidebar-indicator/widget.tsx +6 -5
  803. package/src/modules/staff/widgets/notifications/TimeProjectAccessRequestedRenderer.tsx +138 -0
  804. package/src/modules/staff/widgets/notifications/index.ts +1 -0
  805. package/src/modules/staff/workers/timesheets-reapply-rounding.ts +59 -0
  806. package/dist/modules/staff/backend/staff/timesheets/projects/projectFormConfig.js +0 -123
  807. package/dist/modules/staff/backend/staff/timesheets/projects/projectFormConfig.js.map +0 -7
  808. package/src/modules/staff/backend/staff/timesheets/projects/projectFormConfig.ts +0 -138
@@ -0,0 +1,981 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { extensionPoints } from "@open-mercato/core/modules/staff/extension-points";
4
+ import * as React from "react";
5
+ import { usePathname, useRouter, useSearchParams } from "next/navigation";
6
+ import { Copy, Lock, Plus } from "lucide-react";
7
+ import { Page, PageBody } from "@open-mercato/ui/backend/Page";
8
+ import { DataTable } from "@open-mercato/ui/backend/DataTable";
9
+ import { RowActions } from "@open-mercato/ui/backend/RowActions";
10
+ import { Button } from "@open-mercato/ui/primitives/button";
11
+ import { Checkbox } from "@open-mercato/ui/primitives/checkbox";
12
+ import { StatusBadge } from "@open-mercato/ui/primitives/status-badge";
13
+ import {
14
+ EntryFilterChips,
15
+ EntryFilterPresets,
16
+ matchActivePreset
17
+ } from "../../../../lib/time-tracking-ui/EntryFilterBar.js";
18
+ import {
19
+ apiCall,
20
+ apiCallOrThrow,
21
+ readApiResultOrThrow,
22
+ withScopedApiRequestHeaders
23
+ } from "@open-mercato/ui/backend/utils/apiCall";
24
+ import { deleteCrud, updateCrud } from "@open-mercato/ui/backend/utils/crud";
25
+ import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimisticLock";
26
+ import { surfaceRecordConflict } from "@open-mercato/ui/backend/conflicts";
27
+ import { useGuardedMutation } from "@open-mercato/ui/backend/injection/useGuardedMutation";
28
+ import { useBackendChrome } from "@open-mercato/ui/backend/BackendChromeProvider";
29
+ import { useConfirmDialog } from "@open-mercato/ui/backend/confirm-dialog";
30
+ import { flash } from "@open-mercato/ui/backend/FlashMessages";
31
+ import { useOperationStore } from "@open-mercato/ui/backend/operations/store";
32
+ import { formatCurrency } from "@open-mercato/ui/utils/format";
33
+ import { deserializeOperationMetadata } from "@open-mercato/shared/lib/commands/operationMetadata";
34
+ import { hasFeature } from "@open-mercato/shared/security/features";
35
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
36
+ import { useOrganizationScopeVersion } from "@open-mercato/shared/lib/frontend/useOrganizationScope";
37
+ import { createLogger } from "@open-mercato/shared/lib/logger";
38
+ import { TimeEntryDialog } from "../../../../lib/time-tracking-ui/TimeEntryDialog.js";
39
+ import { TimeEntryDurationCell } from "../../../../lib/time-tracking-ui/TimeEntryDurationCell.js";
40
+ import { TimeEntriesSummaryFooter } from "../../../../lib/time-tracking-ui/TimeEntriesSummaryFooter.js";
41
+ import {
42
+ collectDirectoryIds,
43
+ currentWeekRange,
44
+ formatEntryClockRange,
45
+ formatEntryDay,
46
+ isEntryLockedError,
47
+ readCopyDayTargetConflict,
48
+ summarizeTimeEntries,
49
+ toTimeEntryListRow
50
+ } from "../../../../lib/time-tracking-ui/timeEntryListData.js";
51
+ import {
52
+ readRowItems,
53
+ shiftIsoDate,
54
+ todayIsoDate,
55
+ toProjectOption,
56
+ toTaskOption
57
+ } from "../../../../lib/time-tracking-ui/timeEntryDialogState.js";
58
+ import { formatDuration } from "../../../../lib/time-tracking/duration.js";
59
+ const logger = createLogger("staff").child({ component: "time-tracking/entries" });
60
+ const PAGE_SIZE = 50;
61
+ const DIRECTORY_PAGE_SIZE = 100;
62
+ const ENTRIES_API_PATH = "staff/timesheets/time-entries";
63
+ const ENTRIES_API = `/api/${ENTRIES_API_PATH}`;
64
+ const RATES_FEATURE = "staff.timesheets.rates.view";
65
+ const MANAGE_OWN_FEATURE = "staff.timesheets.manage_own";
66
+ const MANAGE_ALL_FEATURE = "staff.timesheets.manage_all";
67
+ const DEEP_LINK_PARAMS = ["taskId", "ids"];
68
+ const REPORTS_PATH = "/backend/staff/time-tracking/reports";
69
+ const MUTATION_CONTEXT_ID = "staff.time_tracking.entriesList";
70
+ const RESOURCE_KIND = "staff.timesheets.time_entry";
71
+ function readUndoToken(response) {
72
+ const header = response?.headers?.get?.("x-om-operation") ?? null;
73
+ return deserializeOperationMetadata(header)?.undoToken ?? null;
74
+ }
75
+ async function loadDirectory(taskIds, projectIds) {
76
+ const taskTitles = /* @__PURE__ */ new Map();
77
+ const projectLabels = /* @__PURE__ */ new Map();
78
+ const requests = [];
79
+ if (taskIds.length > 0) {
80
+ const params = new URLSearchParams({ page: "1", pageSize: String(DIRECTORY_PAGE_SIZE), ids: taskIds.join(",") });
81
+ requests.push(
82
+ readApiResultOrThrow(`/api/staff/timesheets/tasks?${params.toString()}`, void 0, {
83
+ allowNullResult: true
84
+ }).then((payload) => {
85
+ for (const row of readRowItems(payload)) {
86
+ const option = toTaskOption(row);
87
+ if (option) taskTitles.set(option.id, option.title);
88
+ }
89
+ })
90
+ );
91
+ }
92
+ if (projectIds.length > 0) {
93
+ const params = new URLSearchParams({
94
+ page: "1",
95
+ pageSize: String(DIRECTORY_PAGE_SIZE),
96
+ ids: projectIds.join(",")
97
+ });
98
+ requests.push(
99
+ readApiResultOrThrow(
100
+ `/api/staff/timesheets/time-projects?${params.toString()}`,
101
+ void 0,
102
+ { allowNullResult: true }
103
+ ).then((payload) => {
104
+ for (const row of readRowItems(payload)) {
105
+ const option = toProjectOption(row);
106
+ if (!option) continue;
107
+ projectLabels.set(option.id, option.customerName ? `${option.customerName} \u2014 ${option.name}` : option.name);
108
+ }
109
+ })
110
+ );
111
+ }
112
+ await Promise.all(requests);
113
+ return { taskTitles, projectLabels };
114
+ }
115
+ function TimeTrackingEntriesPage() {
116
+ const t = useT();
117
+ const router = useRouter();
118
+ const pathname = usePathname();
119
+ const searchParams = useSearchParams();
120
+ const scopeVersion = useOrganizationScopeVersion();
121
+ const { payload } = useBackendChrome();
122
+ const canSeeMoney = hasFeature(payload?.grantedFeatures, RATES_FEATURE);
123
+ const canManage = hasFeature(payload?.grantedFeatures, MANAGE_OWN_FEATURE);
124
+ const canManageAll = hasFeature(payload?.grantedFeatures, MANAGE_ALL_FEATURE);
125
+ const { confirm, ConfirmDialogElement } = useConfirmDialog();
126
+ const deepLinkTaskId = searchParams?.get("taskId")?.trim() ?? "";
127
+ const deepLinkEntryIds = searchParams?.get("ids")?.trim() ?? "";
128
+ const defaultRange = React.useMemo(() => currentWeekRange(), []);
129
+ const [filterValues, setFilterValues] = React.useState(() => {
130
+ if (deepLinkTaskId) return { taskId: deepLinkTaskId };
131
+ if (deepLinkEntryIds) return { ids: deepLinkEntryIds };
132
+ return { period: { from: defaultRange.from, to: defaultRange.to } };
133
+ });
134
+ const [selfStaffMemberId, setSelfStaffMemberId] = React.useState(null);
135
+ const [projectOptions, setProjectOptions] = React.useState([]);
136
+ const [customerOptions, setCustomerOptions] = React.useState([]);
137
+ const [tagOptions, setTagOptions] = React.useState([]);
138
+ const [peopleOptions, setPeopleOptions] = React.useState([]);
139
+ const personSeededRef = React.useRef(Boolean(deepLinkTaskId || deepLinkEntryIds));
140
+ const [page, setPage] = React.useState(1);
141
+ const [sorting, setSorting] = React.useState([{ id: "date", desc: true }]);
142
+ const [rows, setRows] = React.useState([]);
143
+ const [total, setTotal] = React.useState(0);
144
+ const [totalIsCapped, setTotalIsCapped] = React.useState(false);
145
+ const [totalPages, setTotalPages] = React.useState(1);
146
+ const [isLoading, setIsLoading] = React.useState(true);
147
+ const [isRefreshing, setIsRefreshing] = React.useState(false);
148
+ const [reloadToken, setReloadToken] = React.useState(0);
149
+ const [selectedIds, setSelectedIds] = React.useState([]);
150
+ const [savingEntryId, setSavingEntryId] = React.useState(null);
151
+ const [dialogOpen, setDialogOpen] = React.useState(false);
152
+ const [dialogEntryId, setDialogEntryId] = React.useState(null);
153
+ const hasLoadedOnceRef = React.useRef(false);
154
+ const labels = React.useMemo(
155
+ () => ({
156
+ title: t("staff.time_tracking.entries.title", "Time entries"),
157
+ add: t("staff.time_tracking.entries.actions.add", "Add entry"),
158
+ copyDay: t("staff.time_tracking.entries.actions.copyDay", "Copy yesterday"),
159
+ duplicate: t("staff.time_tracking.entries.actions.duplicate", "Duplicate"),
160
+ delete: t("staff.time_tracking.entries.actions.delete", "Delete"),
161
+ showReport: t("staff.time_tracking.entries.actions.showReport", "Show the report"),
162
+ refresh: t("staff.time_tracking.entries.actions.refresh", "Refresh"),
163
+ columns: {
164
+ date: t("staff.time_tracking.entries.columns.date", "Date"),
165
+ task: t("staff.time_tracking.entries.columns.task", "Task / description"),
166
+ project: t("staff.time_tracking.entries.columns.project", "Project"),
167
+ clock: t("staff.time_tracking.entries.columns.clock", "Hours"),
168
+ duration: t("staff.time_tracking.entries.columns.duration", "Time"),
169
+ cost: t("staff.time_tracking.entries.columns.cost", "Cost")
170
+ },
171
+ selectAll: t("staff.time_tracking.entries.table.selectAll", "Select all entries"),
172
+ selectRow: t("staff.time_tracking.entries.table.selectRow", "Select entry"),
173
+ durationAria: t("staff.time_tracking.entries.table.durationAria", "Entry duration"),
174
+ noTask: t("staff.time_tracking.entries.table.noTask", "No task"),
175
+ empty: t("staff.time_tracking.entries.empty", "No time entries in this period."),
176
+ badges: {
177
+ locked: t("staff.time_tracking.entries.badges.locked", "locked"),
178
+ nonBillable: t("staff.time_tracking.entries.badges.nonBillable", "non-billable")
179
+ },
180
+ filters: {
181
+ period: t("staff.time_tracking.entries.filters.period", "Period"),
182
+ project: t("staff.time_tracking.entries.filters.project", "Project"),
183
+ customer: t("staff.time_tracking.entries.filters.customer", "Customer"),
184
+ person: t("staff.time_tracking.entries.filters.person", "Person"),
185
+ tag: t("staff.time_tracking.entries.filters.tag", "Tag"),
186
+ billable: t("staff.time_tracking.entries.filters.billable", "Billable"),
187
+ billableYes: t("staff.time_tracking.entries.filters.billableYes", "Billable only"),
188
+ billableNo: t("staff.time_tracking.entries.filters.billableNo", "Non-billable only"),
189
+ locked: t("staff.time_tracking.entries.filters.locked", "Report status"),
190
+ lockedYes: t("staff.time_tracking.entries.filters.lockedYes", "Locked in a report"),
191
+ lockedNo: t("staff.time_tracking.entries.filters.lockedNo", "Not yet reported"),
192
+ text: t("staff.time_tracking.entries.filters.text", "Description contains"),
193
+ task: t("staff.time_tracking.entries.filters.task", "Task"),
194
+ entry: t("staff.time_tracking.entries.filters.entry", "Entry"),
195
+ entrySelection: t("staff.time_tracking.entries.filters.entrySelection", "{count} entries"),
196
+ clearAll: t("staff.time_tracking.entries.filters.clearAll", "Clear all"),
197
+ remove: t("staff.time_tracking.entries.filters.remove", "Remove filter {name}")
198
+ },
199
+ presets: {
200
+ mineWeek: t("staff.time_tracking.entries.presets.mineWeek", "Mine, this week"),
201
+ unbilled: t("staff.time_tracking.entries.presets.unbilled", "Unbilled"),
202
+ nonBillable: t("staff.time_tracking.entries.presets.nonBillable", "Non-billable"),
203
+ thisMonth: t("staff.time_tracking.entries.presets.thisMonth", "This month")
204
+ },
205
+ errors: {
206
+ load: t("staff.time_tracking.entries.errors.load", "Could not load the time entries."),
207
+ save: t("staff.time_tracking.entries.errors.save", "Could not save the time entry."),
208
+ delete: t("staff.time_tracking.entries.errors.delete", "Could not delete the time entry."),
209
+ duplicate: t("staff.time_tracking.entries.errors.duplicate", "Could not duplicate the time entry."),
210
+ copyDay: t("staff.time_tracking.entries.errors.copyDay", "Could not copy the day."),
211
+ locked: t(
212
+ "staff.time_tracking.entries.errors.entryLocked",
213
+ "This time entry is locked in a closed report and cannot be changed. Unlock the report first."
214
+ )
215
+ }
216
+ }),
217
+ [t]
218
+ );
219
+ const handleRefresh = React.useCallback(() => {
220
+ setReloadToken((token) => token + 1);
221
+ }, []);
222
+ const reportFailure = React.useCallback(
223
+ (error, fallbackMessage, logTag) => {
224
+ if (surfaceRecordConflict(error, t)) return;
225
+ if (isEntryLockedError(error)) {
226
+ flash(labels.errors.locked, "error");
227
+ return;
228
+ }
229
+ logger.error(logTag, { err: error });
230
+ flash(error instanceof Error && error.message ? error.message : fallbackMessage, "error");
231
+ },
232
+ [labels.errors.locked, t]
233
+ );
234
+ const period = filterValues.period ?? {};
235
+ const projectFilter = typeof filterValues.projectId === "string" ? filterValues.projectId : "";
236
+ React.useEffect(() => {
237
+ let cancelled = false;
238
+ void (async () => {
239
+ const safeCall = async (url) => {
240
+ try {
241
+ return await Promise.resolve(apiCall(url)) ?? null;
242
+ } catch {
243
+ return null;
244
+ }
245
+ };
246
+ const [selfRes, projectsRes, tagsRes, peopleRes] = await Promise.all([
247
+ safeCall("/api/staff/team-members/self"),
248
+ safeCall("/api/staff/timesheets/time-projects?page=1&pageSize=100"),
249
+ safeCall("/api/staff/timesheets/tags?page=1&pageSize=100"),
250
+ safeCall("/api/staff/team-members?page=1&pageSize=100")
251
+ ]);
252
+ if (cancelled) return;
253
+ const selfId = selfRes?.ok ? selfRes.result?.member?.id ?? null : null;
254
+ if (selfId) {
255
+ setSelfStaffMemberId(selfId);
256
+ if (!personSeededRef.current) {
257
+ personSeededRef.current = true;
258
+ setFilterValues((prev) => ({ ...prev, staffMemberId: selfId }));
259
+ }
260
+ }
261
+ const projects = projectsRes?.ok && Array.isArray(projectsRes.result?.items) ? projectsRes.result.items : [];
262
+ const customers = /* @__PURE__ */ new Map();
263
+ setProjectOptions(
264
+ projects.map((row) => {
265
+ const id = typeof row.id === "string" ? row.id : null;
266
+ if (!id) return null;
267
+ const name = typeof row.name === "string" ? row.name : id;
268
+ const code = typeof row.code === "string" ? row.code : null;
269
+ const customerId = typeof row.customer_id === "string" ? row.customer_id : null;
270
+ const snapshot = row.customer_snapshot;
271
+ if (customerId && typeof snapshot?.name === "string") customers.set(customerId, snapshot.name);
272
+ return { value: id, label: code ? `${code} \xB7 ${name}` : name };
273
+ }).filter((option) => option !== null)
274
+ );
275
+ setCustomerOptions([...customers].map(([value, label]) => ({ value, label })));
276
+ const tags = tagsRes?.ok && Array.isArray(tagsRes.result?.items) ? tagsRes.result.items : [];
277
+ setTagOptions(
278
+ tags.map((row) => {
279
+ const id = typeof row.id === "string" ? row.id : null;
280
+ const label = typeof row.label === "string" ? row.label : null;
281
+ return id && label ? { value: id, label } : null;
282
+ }).filter((option) => option !== null)
283
+ );
284
+ const people = peopleRes?.ok && Array.isArray(peopleRes.result?.items) ? peopleRes.result.items : [];
285
+ setPeopleOptions(
286
+ people.map((row) => {
287
+ const id = typeof row.id === "string" ? row.id : null;
288
+ const label = typeof row.display_name === "string" ? row.display_name : typeof row.displayName === "string" ? row.displayName : null;
289
+ return id && label ? { value: id, label } : null;
290
+ }).filter((option) => option !== null)
291
+ );
292
+ })();
293
+ return () => {
294
+ cancelled = true;
295
+ };
296
+ }, [scopeVersion]);
297
+ const presets = React.useMemo(
298
+ () => [
299
+ {
300
+ id: "mine-week",
301
+ label: labels.presets.mineWeek,
302
+ build: ({ staffMemberId }) => ({
303
+ period: { from: defaultRange.from, to: defaultRange.to },
304
+ ...staffMemberId ? { staffMemberId } : {}
305
+ })
306
+ },
307
+ {
308
+ id: "unbilled",
309
+ label: labels.presets.unbilled,
310
+ build: () => ({ locked: "false", billable: "true" })
311
+ },
312
+ { id: "non-billable", label: labels.presets.nonBillable, build: () => ({ billable: "false" }) },
313
+ {
314
+ id: "this-month",
315
+ label: labels.presets.thisMonth,
316
+ build: ({ today }) => {
317
+ const start = `${today.slice(0, 7)}-01`;
318
+ return { period: { from: start, to: today } };
319
+ }
320
+ }
321
+ ],
322
+ [defaultRange.from, defaultRange.to, labels.presets]
323
+ );
324
+ const presetContext = React.useMemo(
325
+ () => ({ staffMemberId: selfStaffMemberId, today: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10) }),
326
+ [selfStaffMemberId]
327
+ );
328
+ const activePresetId = React.useMemo(
329
+ () => matchActivePreset(filterValues, presets, presetContext),
330
+ [filterValues, presetContext, presets]
331
+ );
332
+ const applyPreset = React.useCallback(
333
+ (preset) => {
334
+ setFilterValues((current) => ({ ...current, ...preset.build(presetContext) }));
335
+ setPage(1);
336
+ },
337
+ [presetContext]
338
+ );
339
+ const dropDeepLinkParams = React.useCallback(
340
+ (ids) => {
341
+ if (!searchParams) return;
342
+ const next = new URLSearchParams(searchParams.toString());
343
+ let changed = false;
344
+ for (const id of ids) {
345
+ if (!next.has(id)) continue;
346
+ next.delete(id);
347
+ changed = true;
348
+ }
349
+ if (!changed) return;
350
+ const query = next.toString();
351
+ router.replace(query ? `${pathname}?${query}` : pathname);
352
+ },
353
+ [pathname, router, searchParams]
354
+ );
355
+ const removeChip = React.useCallback(
356
+ (id) => {
357
+ setFilterValues((current) => {
358
+ const next = { ...current };
359
+ delete next[id];
360
+ return next;
361
+ });
362
+ setPage(1);
363
+ dropDeepLinkParams([id]);
364
+ },
365
+ [dropDeepLinkParams]
366
+ );
367
+ const clearAllFilters = React.useCallback(() => {
368
+ setFilterValues({});
369
+ setPage(1);
370
+ dropDeepLinkParams(DEEP_LINK_PARAMS);
371
+ }, [dropDeepLinkParams]);
372
+ const loadEntries = React.useCallback(async () => {
373
+ if (hasLoadedOnceRef.current) setIsRefreshing(true);
374
+ else setIsLoading(true);
375
+ try {
376
+ const params = new URLSearchParams({ page: String(page), pageSize: String(PAGE_SIZE) });
377
+ const sort = sorting[0];
378
+ params.set("sortField", sort?.id ?? "date");
379
+ params.set("sortDir", sort?.desc === false ? "asc" : "desc");
380
+ if (period.from) params.set("from", period.from);
381
+ if (period.to) params.set("to", period.to);
382
+ if (projectFilter) params.set("projectId", projectFilter);
383
+ const readFilter = (key) => typeof filterValues[key] === "string" ? filterValues[key] : "";
384
+ const person = readFilter("staffMemberId");
385
+ if (person) params.set("staffMemberId", person);
386
+ const billable = readFilter("billable");
387
+ if (billable) params.set("billable", billable);
388
+ const lockedFilter = readFilter("locked");
389
+ if (lockedFilter) params.set("locked", lockedFilter);
390
+ const customer = readFilter("customerId");
391
+ if (customer) params.set("customerId", customer);
392
+ const tag = readFilter("tagIds");
393
+ if (tag) params.set("tagIds", tag);
394
+ const text = readFilter("q");
395
+ if (text.trim()) params.set("q", text.trim());
396
+ const taskFilter = readFilter("taskId");
397
+ if (taskFilter) params.set("taskId", taskFilter);
398
+ const entryIdsFilter = readFilter("ids");
399
+ if (entryIdsFilter) params.set("ids", entryIdsFilter);
400
+ const listPayload = await readApiResultOrThrow(
401
+ `${ENTRIES_API}?${params.toString()}`,
402
+ void 0,
403
+ { errorMessage: labels.errors.load, fallback: { items: [], total: 0, totalPages: 1 } }
404
+ );
405
+ const items = Array.isArray(listPayload.items) ? listPayload.items : [];
406
+ const bare = items.map((item) => toTimeEntryListRow(item)).filter((row) => row !== null);
407
+ const { taskIds, projectIds } = collectDirectoryIds(bare);
408
+ let directory = { taskTitles: /* @__PURE__ */ new Map(), projectLabels: /* @__PURE__ */ new Map() };
409
+ try {
410
+ directory = await loadDirectory(taskIds, projectIds);
411
+ } catch (error) {
412
+ logger.warn("staff.time_tracking.entries directory load failed", { err: error });
413
+ }
414
+ setRows(
415
+ items.map((item) => toTimeEntryListRow(item, directory)).filter((row) => row !== null)
416
+ );
417
+ setTotal(typeof listPayload.total === "number" ? listPayload.total : items.length);
418
+ setTotalIsCapped(listPayload.totalIsCapped === true);
419
+ setTotalPages(
420
+ typeof listPayload.totalPages === "number" ? listPayload.totalPages : Math.max(1, Math.ceil(items.length / PAGE_SIZE))
421
+ );
422
+ } catch (error) {
423
+ logger.error("staff.time_tracking.entries list failed", { err: error });
424
+ flash(labels.errors.load, "error");
425
+ } finally {
426
+ setIsLoading(false);
427
+ setIsRefreshing(false);
428
+ hasLoadedOnceRef.current = true;
429
+ }
430
+ }, [labels.errors.load, page, period.from, period.to, projectFilter, sorting, filterValues]);
431
+ React.useEffect(() => {
432
+ void loadEntries();
433
+ }, [loadEntries, scopeVersion, reloadToken]);
434
+ React.useEffect(() => {
435
+ setSelectedIds([]);
436
+ }, [page, period.from, period.to, projectFilter, scopeVersion]);
437
+ const undoneTokens = useOperationStore((state) => state.undone.map((entry) => entry.undoToken).join("|"));
438
+ const pendingUndoTokensRef = React.useRef(/* @__PURE__ */ new Set());
439
+ React.useEffect(() => {
440
+ if (pendingUndoTokensRef.current.size === 0) return;
441
+ const undone = new Set(undoneTokens.split("|").filter(Boolean));
442
+ let restored = false;
443
+ for (const token of Array.from(pendingUndoTokensRef.current)) {
444
+ if (!undone.has(token)) continue;
445
+ pendingUndoTokensRef.current.delete(token);
446
+ restored = true;
447
+ }
448
+ if (restored) handleRefresh();
449
+ }, [handleRefresh, undoneTokens]);
450
+ const { runMutation, retryLastMutation } = useGuardedMutation({
451
+ contextId: MUTATION_CONTEXT_ID,
452
+ blockedMessage: labels.errors.save
453
+ });
454
+ const mutationContext = React.useCallback(
455
+ (resourceId) => ({
456
+ formId: MUTATION_CONTEXT_ID,
457
+ resourceKind: RESOURCE_KIND,
458
+ resourceId,
459
+ retryLastMutation
460
+ }),
461
+ [retryLastMutation]
462
+ );
463
+ const handleDurationCommit = React.useCallback(
464
+ async (entry, durationMinutes) => {
465
+ setSavingEntryId(entry.id);
466
+ try {
467
+ await runMutation({
468
+ operation: () => withScopedApiRequestHeaders(
469
+ buildOptimisticLockHeader(entry.updatedAt),
470
+ () => updateCrud(
471
+ ENTRIES_API_PATH,
472
+ { id: entry.id, durationMinutes },
473
+ { errorMessage: labels.errors.save }
474
+ )
475
+ ),
476
+ context: mutationContext(entry.id),
477
+ mutationPayload: { id: entry.id, durationMinutes }
478
+ });
479
+ handleRefresh();
480
+ } catch (error) {
481
+ reportFailure(error, labels.errors.save, "staff.time_tracking.entries inline duration save failed");
482
+ handleRefresh();
483
+ } finally {
484
+ setSavingEntryId(null);
485
+ }
486
+ },
487
+ [handleRefresh, labels.errors.save, mutationContext, reportFailure, runMutation]
488
+ );
489
+ const handleDelete = React.useCallback(
490
+ async (entry) => {
491
+ const previousRows = rows;
492
+ setRows((current) => current.filter((row) => row.id !== entry.id));
493
+ setTotal((current) => Math.max(0, current - 1));
494
+ setSelectedIds((current) => current.filter((id) => id !== entry.id));
495
+ try {
496
+ const call = await runMutation({
497
+ operation: () => withScopedApiRequestHeaders(
498
+ buildOptimisticLockHeader(entry.updatedAt),
499
+ () => deleteCrud(ENTRIES_API_PATH, entry.id, { errorMessage: labels.errors.delete })
500
+ ),
501
+ context: mutationContext(entry.id),
502
+ mutationPayload: { id: entry.id }
503
+ });
504
+ const undoToken = readUndoToken(call.response);
505
+ if (undoToken) pendingUndoTokensRef.current.add(undoToken);
506
+ flash(
507
+ t("staff.time_tracking.entries.messages.deleted", "Deleted \u201C{name}\u201D ({duration}). Use Undo to restore it.", {
508
+ name: entry.taskTitle ?? entry.description ?? labels.noTask,
509
+ duration: formatDuration(entry.durationMinutes, "clock")
510
+ }),
511
+ "success"
512
+ );
513
+ } catch (error) {
514
+ setRows(previousRows);
515
+ setTotal((current) => current + 1);
516
+ reportFailure(error, labels.errors.delete, "staff.time_tracking.entries delete failed");
517
+ }
518
+ },
519
+ [labels.errors.delete, labels.noTask, mutationContext, reportFailure, rows, runMutation, t]
520
+ );
521
+ const handleDuplicate = React.useCallback(
522
+ async (entry) => {
523
+ try {
524
+ await runMutation({
525
+ operation: () => apiCallOrThrow(
526
+ `${ENTRIES_API}/${encodeURIComponent(entry.id)}/duplicate`,
527
+ {
528
+ method: "POST",
529
+ headers: { "content-type": "application/json" },
530
+ body: JSON.stringify({ tagIds: entry.tagIds })
531
+ },
532
+ { errorMessage: labels.errors.duplicate }
533
+ ),
534
+ context: mutationContext(entry.id),
535
+ mutationPayload: { id: entry.id }
536
+ });
537
+ flash(t("staff.time_tracking.entries.messages.duplicated", "Entry duplicated."), "success");
538
+ handleRefresh();
539
+ } catch (error) {
540
+ reportFailure(error, labels.errors.duplicate, "staff.time_tracking.entries duplicate failed");
541
+ }
542
+ },
543
+ [handleRefresh, labels.errors.duplicate, mutationContext, reportFailure, runMutation, t]
544
+ );
545
+ const runCopyDay = React.useCallback(
546
+ async (fromDate, toDate, allowDuplicates) => runMutation({
547
+ operation: () => apiCallOrThrow(
548
+ `${ENTRIES_API}/copy-day`,
549
+ {
550
+ method: "POST",
551
+ headers: { "content-type": "application/json" },
552
+ body: JSON.stringify({ fromDate, toDate, allowDuplicates })
553
+ },
554
+ { errorMessage: labels.errors.copyDay }
555
+ ),
556
+ context: mutationContext(toDate),
557
+ mutationPayload: { fromDate, toDate, allowDuplicates }
558
+ }),
559
+ [labels.errors.copyDay, mutationContext, runMutation]
560
+ );
561
+ const handleCopyDay = React.useCallback(async () => {
562
+ const toDate = todayIsoDate();
563
+ const fromDate = shiftIsoDate(toDate, -1);
564
+ const announce = (result) => {
565
+ const copied = typeof result?.copied === "number" ? result.copied : 0;
566
+ const skipped = Array.isArray(result?.skipped) ? result.skipped.length : 0;
567
+ if (copied === 0) {
568
+ flash(t("staff.time_tracking.entries.copyDay.nothing", "Yesterday has no entries to copy."), "info");
569
+ } else {
570
+ flash(
571
+ t("staff.time_tracking.entries.copyDay.success", "{count} entries copied as drafts \u2014 review them.", {
572
+ count: copied
573
+ }),
574
+ "success"
575
+ );
576
+ setFilterValues((current) => ({ ...current, period: { from: toDate, to: toDate } }));
577
+ setPage(1);
578
+ }
579
+ if (skipped > 0) {
580
+ flash(
581
+ t("staff.time_tracking.entries.copyDay.skipped", "{count} entries were skipped because they are locked.", {
582
+ count: skipped
583
+ }),
584
+ "warning"
585
+ );
586
+ }
587
+ handleRefresh();
588
+ };
589
+ try {
590
+ const call = await runCopyDay(fromDate, toDate, false);
591
+ announce(call.result);
592
+ } catch (error) {
593
+ const conflict = readCopyDayTargetConflict(error);
594
+ if (!conflict) {
595
+ reportFailure(error, labels.errors.copyDay, "staff.time_tracking.entries copy-day failed");
596
+ return;
597
+ }
598
+ const confirmed = await confirm({
599
+ title: labels.copyDay,
600
+ text: t(
601
+ "staff.time_tracking.entries.copyDay.conflict",
602
+ "Today already has {count} entries. Add yesterday\u2019s copies on top of them?",
603
+ { count: conflict.existingEntryCount }
604
+ ),
605
+ confirmText: t("staff.time_tracking.entries.copyDay.confirmDuplicates", "Add copies anyway")
606
+ });
607
+ if (!confirmed) return;
608
+ try {
609
+ const retry = await runCopyDay(fromDate, toDate, true);
610
+ announce(retry.result);
611
+ } catch (retryError) {
612
+ reportFailure(retryError, labels.errors.copyDay, "staff.time_tracking.entries copy-day retry failed");
613
+ }
614
+ }
615
+ }, [confirm, handleRefresh, labels.copyDay, labels.errors.copyDay, reportFailure, runCopyDay, t]);
616
+ const openCreate = React.useCallback(() => {
617
+ setDialogEntryId(null);
618
+ setDialogOpen(true);
619
+ }, []);
620
+ const openEdit = React.useCallback((entryId) => {
621
+ setDialogEntryId(entryId);
622
+ setDialogOpen(true);
623
+ }, []);
624
+ const selectableRows = React.useMemo(() => rows.filter((row) => !row.isLocked), [rows]);
625
+ const allSelected = selectableRows.length > 0 && selectedIds.length === selectableRows.length;
626
+ const someSelected = selectedIds.length > 0 && !allSelected;
627
+ const toggleRowSelection = React.useCallback((id, checked) => {
628
+ setSelectedIds((current) => checked ? Array.from(/* @__PURE__ */ new Set([...current, id])) : current.filter((value) => value !== id));
629
+ }, []);
630
+ const toggleAllSelection = React.useCallback(
631
+ (checked) => {
632
+ setSelectedIds(checked ? selectableRows.map((row) => row.id) : []);
633
+ },
634
+ [selectableRows]
635
+ );
636
+ const filters = React.useMemo(
637
+ () => [
638
+ { id: "period", label: labels.filters.period, type: "dateRange" },
639
+ { id: "projectId", label: labels.filters.project, type: "select", options: projectOptions },
640
+ { id: "customerId", label: labels.filters.customer, type: "select", options: customerOptions },
641
+ // Only offered when the caller can actually see somebody else's time; for
642
+ // everyone else the route already scopes to their own entries and the
643
+ // control would be a lever attached to nothing.
644
+ ...canManageAll && peopleOptions.length > 1 ? [{ id: "staffMemberId", label: labels.filters.person, type: "select", options: peopleOptions }] : [],
645
+ { id: "tagIds", label: labels.filters.tag, type: "select", options: tagOptions },
646
+ {
647
+ id: "billable",
648
+ label: labels.filters.billable,
649
+ type: "select",
650
+ options: [
651
+ { value: "true", label: labels.filters.billableYes },
652
+ { value: "false", label: labels.filters.billableNo }
653
+ ]
654
+ },
655
+ {
656
+ id: "locked",
657
+ label: labels.filters.locked,
658
+ type: "select",
659
+ options: [
660
+ { value: "true", label: labels.filters.lockedYes },
661
+ { value: "false", label: labels.filters.lockedNo }
662
+ ]
663
+ },
664
+ { id: "q", label: labels.filters.text, type: "text" }
665
+ ],
666
+ [labels.filters, canManageAll, projectOptions, customerOptions, peopleOptions, tagOptions]
667
+ );
668
+ const unlistedFilters = React.useMemo(
669
+ () => [
670
+ { id: "staffMemberId", label: labels.filters.person, type: "select", options: peopleOptions },
671
+ { id: "taskId", label: labels.filters.task, type: "text" },
672
+ { id: "ids", label: labels.filters.entry, type: "text" }
673
+ ],
674
+ [labels.filters, peopleOptions]
675
+ );
676
+ const appliedChips = React.useMemo(() => {
677
+ const defOf = (id) => filters.find((filter) => filter.id === id) ?? unlistedFilters.find((filter) => filter.id === id);
678
+ const label = (id) => defOf(id)?.label ?? id;
679
+ const optionLabel = (id, value) => defOf(id)?.options?.find((option) => option.value === value)?.label ?? value;
680
+ const chips = [];
681
+ for (const [id, raw] of Object.entries(filterValues)) {
682
+ if (raw === void 0 || raw === null || raw === "") continue;
683
+ if (id === "period") {
684
+ const range = raw;
685
+ if (!range?.from && !range?.to) continue;
686
+ chips.push({ id, label: label(id), value: `${range.from ?? "\u2026"} \u2192 ${range.to ?? "\u2026"}` });
687
+ continue;
688
+ }
689
+ if (typeof raw !== "string") continue;
690
+ if (id === "taskId") {
691
+ const first = raw.split(",")[0] ?? raw;
692
+ const match = rows.find((row) => row.taskId === first);
693
+ chips.push({ id, label: label(id), value: match?.taskTitle ?? first });
694
+ continue;
695
+ }
696
+ if (id === "ids") {
697
+ const list = raw.split(",").map((value) => value.trim()).filter(Boolean);
698
+ if (list.length === 0) continue;
699
+ const single = list.length === 1 ? rows.find((row) => row.id === list[0]) : void 0;
700
+ chips.push({
701
+ id,
702
+ label: label(id),
703
+ value: single ? single.taskTitle ?? single.description ?? labels.noTask : labels.filters.entrySelection.replace("{count}", String(list.length))
704
+ });
705
+ continue;
706
+ }
707
+ chips.push({ id, label: label(id), value: optionLabel(id, raw) });
708
+ }
709
+ return chips;
710
+ }, [filterValues, filters, labels.filters.entrySelection, labels.noTask, rows, unlistedFilters]);
711
+ const columns = React.useMemo(() => {
712
+ const rightHeader = (label) => () => /* @__PURE__ */ jsx("span", { className: "block text-right", children: label });
713
+ const defs = [];
714
+ if (canManage) {
715
+ defs.push({
716
+ id: "select",
717
+ accessorKey: "id",
718
+ header: () => /* @__PURE__ */ jsx(
719
+ Checkbox,
720
+ {
721
+ checked: allSelected ? true : someSelected ? "indeterminate" : false,
722
+ onCheckedChange: (checked) => toggleAllSelection(Boolean(checked)),
723
+ "aria-label": labels.selectAll
724
+ }
725
+ ),
726
+ enableSorting: false,
727
+ meta: { priority: 1 },
728
+ cell: ({ row }) => row.original.isLocked ? null : /* @__PURE__ */ jsx(
729
+ Checkbox,
730
+ {
731
+ checked: selectedIds.includes(row.original.id),
732
+ onCheckedChange: (checked) => toggleRowSelection(row.original.id, Boolean(checked)),
733
+ onClick: (event) => event.stopPropagation(),
734
+ "aria-label": labels.selectRow
735
+ }
736
+ )
737
+ });
738
+ }
739
+ defs.push({
740
+ accessorKey: "date",
741
+ header: labels.columns.date,
742
+ meta: { priority: 1 },
743
+ cell: ({ row }) => /* @__PURE__ */ jsx("span", { className: "whitespace-nowrap text-sm text-muted-foreground", children: formatEntryDay(row.original.date) })
744
+ });
745
+ defs.push({
746
+ id: "task",
747
+ accessorKey: "taskTitle",
748
+ header: labels.columns.task,
749
+ enableSorting: false,
750
+ // `taskTitle` matches none of DataTable's wide-column keys, so it fell to the
751
+ // 150px default and truncated to "Consulting / Worksh…" while the nowrap
752
+ // numeric columns kept their slack. This is the row's primary content.
753
+ meta: { priority: 1, maxWidth: "520px" },
754
+ cell: ({ row }) => {
755
+ const entry = row.original;
756
+ const rateOverrideLabel = canSeeMoney && entry.rateOverrideAmount !== null ? formatCurrency(entry.rateOverrideAmount, entry.currencyCode) ?? String(entry.rateOverrideAmount) : null;
757
+ return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-0.5", children: [
758
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [
759
+ /* @__PURE__ */ jsx("span", { className: "truncate text-sm font-medium text-foreground", children: entry.taskTitle ?? labels.noTask }),
760
+ !entry.isBillable ? /* @__PURE__ */ jsx(StatusBadge, { variant: "neutral", children: labels.badges.nonBillable }) : null,
761
+ rateOverrideLabel ? /* @__PURE__ */ jsx("span", { "data-testid": "entry-rate-override", children: /* @__PURE__ */ jsx(StatusBadge, { variant: "info", children: t("staff.time_tracking.entries.badges.rateOverride", "{amount}/h", { amount: rateOverrideLabel }) }) }) : null,
762
+ entry.isLocked ? /* @__PURE__ */ jsx("span", { "data-testid": "entry-locked-badge", children: /* @__PURE__ */ jsxs(StatusBadge, { variant: "neutral", children: [
763
+ /* @__PURE__ */ jsx(Lock, { className: "h-3 w-3", "aria-hidden": "true" }),
764
+ labels.badges.locked
765
+ ] }) }) : null
766
+ ] }),
767
+ entry.description ? /* @__PURE__ */ jsx("span", { className: "truncate text-xs text-muted-foreground", children: entry.description }) : null
768
+ ] });
769
+ }
770
+ });
771
+ defs.push({
772
+ id: "project",
773
+ accessorKey: "projectLabel",
774
+ header: labels.columns.project,
775
+ enableSorting: false,
776
+ meta: { priority: 2, maxWidth: "240px" },
777
+ cell: ({ row }) => row.original.projectLabel ? /* @__PURE__ */ jsx("span", { className: "truncate text-sm text-muted-foreground", children: row.original.projectLabel }) : /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground/70", children: "\u2014" })
778
+ });
779
+ defs.push({
780
+ id: "clock",
781
+ accessorKey: "startText",
782
+ header: labels.columns.clock,
783
+ enableSorting: false,
784
+ meta: { priority: 3, maxWidth: "160px" },
785
+ cell: ({ row }) => {
786
+ const range = formatEntryClockRange(row.original);
787
+ return range ? /* @__PURE__ */ jsx("span", { className: "whitespace-nowrap font-mono text-sm tabular-nums text-muted-foreground", children: range }) : /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground/70", children: "\u2014" });
788
+ }
789
+ });
790
+ defs.push({
791
+ id: "durationMinutes",
792
+ accessorKey: "durationMinutes",
793
+ header: rightHeader(labels.columns.duration),
794
+ meta: { priority: 1, maxWidth: "120px" },
795
+ cell: ({ row }) => /* @__PURE__ */ jsx(
796
+ TimeEntryDurationCell,
797
+ {
798
+ value: row.original.durationMinutes,
799
+ readOnly: row.original.isLocked || !canManage,
800
+ saving: savingEntryId === row.original.id,
801
+ ariaLabel: labels.durationAria,
802
+ lockedTitle: row.original.isLocked ? labels.errors.locked : void 0,
803
+ onCommit: (minutes) => handleDurationCommit(row.original, minutes)
804
+ }
805
+ )
806
+ });
807
+ if (canSeeMoney) {
808
+ defs.push({
809
+ id: "cost",
810
+ accessorKey: "cost",
811
+ header: rightHeader(labels.columns.cost),
812
+ enableSorting: false,
813
+ meta: { priority: 4, maxWidth: "140px" },
814
+ cell: ({ row }) => {
815
+ const formatted = row.original.cost === null ? null : formatCurrency(row.original.cost, row.original.currencyCode);
816
+ return formatted ? /* @__PURE__ */ jsx(
817
+ "span",
818
+ {
819
+ className: "block text-right font-mono text-sm tabular-nums text-foreground",
820
+ "data-testid": "entry-cost",
821
+ children: formatted
822
+ }
823
+ ) : /* @__PURE__ */ jsx("span", { className: "block text-right text-xs text-muted-foreground/70", "data-testid": "entry-cost-empty", children: "\u2014" });
824
+ }
825
+ });
826
+ }
827
+ return defs;
828
+ }, [
829
+ allSelected,
830
+ canManage,
831
+ canSeeMoney,
832
+ handleDurationCommit,
833
+ labels,
834
+ savingEntryId,
835
+ selectedIds,
836
+ someSelected,
837
+ t,
838
+ toggleAllSelection,
839
+ toggleRowSelection
840
+ ]);
841
+ const summary = React.useMemo(() => summarizeTimeEntries(rows), [rows]);
842
+ return /* @__PURE__ */ jsxs(Page, { children: [
843
+ /* @__PURE__ */ jsxs(PageBody, { children: [
844
+ /* @__PURE__ */ jsx(
845
+ DataTable,
846
+ {
847
+ extensionTableId: extensionPoints.hosts.timeEntriesTable.tableId,
848
+ title: labels.title,
849
+ titleHeadingLevel: 1,
850
+ data: rows,
851
+ columns,
852
+ isLoading,
853
+ filters,
854
+ filterValues,
855
+ onFiltersApply: (values) => {
856
+ setFilterValues(values);
857
+ setPage(1);
858
+ dropDeepLinkParams(DEEP_LINK_PARAMS.filter((id) => !values[id]));
859
+ },
860
+ onFiltersClear: clearAllFilters,
861
+ activeFilterChips: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
862
+ /* @__PURE__ */ jsx(
863
+ EntryFilterPresets,
864
+ {
865
+ presets,
866
+ activePresetId,
867
+ onApplyPreset: applyPreset
868
+ }
869
+ ),
870
+ /* @__PURE__ */ jsx(
871
+ EntryFilterChips,
872
+ {
873
+ chips: appliedChips,
874
+ onRemove: removeChip,
875
+ onClearAll: clearAllFilters,
876
+ clearAllLabel: labels.filters.clearAll,
877
+ removeLabel: (name) => labels.filters.remove.replace("{name}", name)
878
+ }
879
+ )
880
+ ] }),
881
+ filterAwareEmptyState: {
882
+ active: appliedChips.length > 0,
883
+ entityNamePlural: labels.title,
884
+ canRemoveLast: appliedChips.length > 0,
885
+ onClearAll: clearAllFilters,
886
+ onRemoveLast: () => {
887
+ const last = appliedChips[appliedChips.length - 1];
888
+ if (last) removeChip(last.id);
889
+ }
890
+ },
891
+ emptyState: /* @__PURE__ */ jsx("div", { className: "py-12 text-center text-sm text-muted-foreground", children: labels.empty }),
892
+ actions: canManage ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
893
+ /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "outline", onClick: () => void handleCopyDay(), children: [
894
+ /* @__PURE__ */ jsx(Copy, { className: "h-4 w-4", "aria-hidden": "true" }),
895
+ labels.copyDay
896
+ ] }),
897
+ /* @__PURE__ */ jsxs(Button, { size: "sm", onClick: openCreate, children: [
898
+ /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4", "aria-hidden": "true" }),
899
+ labels.add
900
+ ] })
901
+ ] }) : void 0,
902
+ refreshButton: {
903
+ label: labels.refresh,
904
+ onRefresh: handleRefresh,
905
+ isRefreshing: isLoading || isRefreshing
906
+ },
907
+ sortable: true,
908
+ manualSorting: true,
909
+ sorting,
910
+ onSortingChange: setSorting,
911
+ pagination: {
912
+ page,
913
+ pageSize: PAGE_SIZE,
914
+ total,
915
+ totalIsCapped,
916
+ totalPages,
917
+ onPageChange: setPage
918
+ },
919
+ stickyActionsColumn: true,
920
+ rowActions: (row) => row.isLocked ? /* @__PURE__ */ jsx(
921
+ RowActions,
922
+ {
923
+ items: [
924
+ {
925
+ id: "show-report",
926
+ label: labels.showReport,
927
+ href: row.lockedReportId ? `${REPORTS_PATH}?id=${encodeURIComponent(row.lockedReportId)}` : REPORTS_PATH
928
+ }
929
+ ]
930
+ }
931
+ ) : canManage ? /* @__PURE__ */ jsx(
932
+ RowActions,
933
+ {
934
+ items: [
935
+ {
936
+ id: "duplicate",
937
+ label: labels.duplicate,
938
+ onSelect: () => {
939
+ void handleDuplicate(row);
940
+ }
941
+ },
942
+ {
943
+ id: "delete",
944
+ label: labels.delete,
945
+ destructive: true,
946
+ onSelect: () => {
947
+ void handleDelete(row);
948
+ }
949
+ }
950
+ ]
951
+ }
952
+ ) : null,
953
+ onRowClick: (row) => {
954
+ if (row.isLocked) return;
955
+ openEdit(row.id);
956
+ }
957
+ }
958
+ ),
959
+ /* @__PURE__ */ jsx(TimeEntriesSummaryFooter, { summary, totalCount: total, canSeeMoney }),
960
+ !canManage ? /* @__PURE__ */ jsx("p", { className: "mt-2 text-xs text-muted-foreground", children: t("staff.time_tracking.entries.readOnlyNotice", "You can view these entries but not change them.") }) : null
961
+ ] }),
962
+ /* @__PURE__ */ jsx(
963
+ TimeEntryDialog,
964
+ {
965
+ open: dialogOpen,
966
+ onOpenChange: setDialogOpen,
967
+ entryId: dialogEntryId,
968
+ onSaved: ({ keptOpen }) => {
969
+ handleRefresh();
970
+ if (!keptOpen) setDialogOpen(false);
971
+ },
972
+ onShowEntry: (entryId) => openEdit(entryId)
973
+ }
974
+ ),
975
+ ConfirmDialogElement
976
+ ] });
977
+ }
978
+ export {
979
+ TimeTrackingEntriesPage as default
980
+ };
981
+ //# sourceMappingURL=page.js.map