@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,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/modules/staff/lib/timesheets-tasks/computeTaskRollups.ts"],
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { loggedMinutes, type RollupEntry, type RollupTask, type TaskRollup } from '../time-tracking/rollup'\n\n/**\n * Per-task hours for the board, the drawer and the subtask checklist.\n *\n * D-2 fixes one rule for every surface: a parent always shows the inclusive rollup,\n * `own entries + \u03A3 children's entries`. The arithmetic itself belongs to\n * `lib/time-tracking/rollup.ts` and is not repeated here \u2014 this module's job is to\n * hand that helper a complete, access-scoped picture of the page in a single round\n * trip.\n *\n * Two properties matter and are easy to get wrong:\n *\n * 1. **Off-page children still count.** The board asks for top-level cards only, so\n * a parent's children are, by construction, absent from the page. Rolling up only\n * the children that happen to share the page would make a card's hours depend on\n * the current filter \u2014 indistinguishable from flakiness. The query therefore\n * widens from the page's ids to `id IN (page) OR parent_task_id IN (page)`.\n * 2. **One aggregate for the whole page.** A 100-card board must not issue 100\n * queries; minutes come back pre-summed per (task, entry project) group, exactly\n * as the project aggregates do.\n *\n * Raw `duration_minutes` is what feeds these numbers. Rounded minutes exist only for\n * money and stay inside `cost.ts` (D-7).\n */\n\nexport type TaskRollupTaskRow = {\n id: string\n parentTaskId?: string | null\n timeProjectId?: string | null\n /** The task sits in a column flagged `is_done` \u2014 the only definition of a done subtask (D-2). */\n isDone?: boolean | null\n deletedAt?: Date | string | null\n}\n\n/** Entry minutes pre-summed by the database, one group per (task, entry project). */\nexport type TaskRollupEntryGroup = {\n taskId: string\n timeProjectId?: string | null\n minutes: number\n deletedAt?: Date | string | null\n}\n\nexport type TaskRollupInput = {\n /** The page's task ids \u2014 already filtered to what the caller may see. */\n taskIds: readonly string[]\n /** The page's tasks plus every child of them, on-page or not. */\n tasks: readonly TaskRollupTaskRow[]\n entryGroups: readonly TaskRollupEntryGroup[]\n}\n\nexport type { TaskRollup }\n\n/**\n * The rollup as the API publishes it: the minutes contract of\n * `lib/time-tracking/rollup.ts` plus the done tally of the same children\n * `childCount` counts.\n *\n * `doneChildCount` exists so a surface can render `3/5` from the row it already\n * has. Without it the only way to say how many subtasks are finished is to fetch\n * a page of children and count them, which turns opening a task into a second\n * round trip for a number this aggregate already knows.\n */\nexport type TaskPageRollup = TaskRollup & { doneChildCount: number }\n\nexport const EMPTY_TASK_ROLLUP: TaskPageRollup = {\n ownMinutes: 0,\n loggedMinutes: 0,\n childCount: 0,\n doneChildCount: 0,\n}\n\nfunction toMinutes(value: string | number | null | undefined): number {\n if (value === null || value === undefined) return 0\n const parsed = typeof value === 'number' ? value : Number(value)\n return Number.isFinite(parsed) ? parsed : 0\n}\n\n/**\n * The projects the caller provably sees on this page.\n *\n * The list route has already intersected the page with `resolveProjectAccess`, so the\n * projects of the page's own tasks are an authoritative allow-list. An entry pointing\n * at any other project is dropped rather than trusted: nothing here can prove the\n * caller may see it, and a rollup is a client-facing number.\n */\nfunction allowedProjectIds(input: TaskRollupInput): Set<string> {\n const pageIds = new Set(input.taskIds)\n const allowed = new Set<string>()\n for (const task of input.tasks) {\n if (!pageIds.has(task.id) || task.deletedAt) continue\n if (task.timeProjectId) allowed.add(task.timeProjectId)\n }\n return allowed\n}\n\n/**\n * How many of a task's live children sit in a done column.\n *\n * The child set is derived exactly as `loggedMinutes` derives it \u2014 same parent\n * test, same soft-delete exclusion, same self-reference guard \u2014 so a subtask can\n * never be done without also being counted, which is the only way `3/5` can read\n * as `3/4`.\n */\nfunction countDoneChildren(\n taskId: string,\n allTasks: readonly RollupTask[],\n doneByTaskId: ReadonlyMap<string, boolean>,\n): number {\n let done = 0\n for (const candidate of allTasks) {\n if (candidate.parentTaskId !== taskId || candidate.id === taskId || candidate.deletedAt) continue\n if (doneByTaskId.get(candidate.id) === true) done += 1\n }\n return done\n}\n\nexport function summarizeTaskRollups(input: TaskRollupInput): Map<string, TaskPageRollup> {\n const allowed = allowedProjectIds(input)\n\n // The grouped query returns one row per (task, entry project), so a task with\n // entries in two projects arrives twice. Deduplicating is not cosmetic: a repeated\n // child row would be counted twice by `childCount`.\n const taskById = new Map<string, RollupTask>()\n const doneByTaskId = new Map<string, boolean>()\n for (const task of input.tasks) {\n if (taskById.has(task.id)) continue\n taskById.set(task.id, { id: task.id, parentTaskId: task.parentTaskId ?? null, deletedAt: task.deletedAt ?? null })\n doneByTaskId.set(task.id, task.isDone === true)\n }\n const allTasks = [...taskById.values()]\n\n const entriesByTaskId = new Map<string, RollupEntry[]>()\n for (const group of input.entryGroups) {\n if (group.timeProjectId && !allowed.has(group.timeProjectId)) continue\n const bucket = entriesByTaskId.get(group.taskId) ?? []\n bucket.push({ durationMinutes: toMinutes(group.minutes), deletedAt: group.deletedAt ?? null })\n entriesByTaskId.set(group.taskId, bucket)\n }\n\n const result = new Map<string, TaskPageRollup>()\n for (const taskId of input.taskIds) {\n const task = taskById.get(taskId) ?? { id: taskId, parentTaskId: null }\n result.set(taskId, {\n ...loggedMinutes(task, allTasks, entriesByTaskId),\n doneChildCount: countDoneChildren(taskId, allTasks, doneByTaskId),\n })\n }\n return result\n}\n\nexport type TaskRollupScope = {\n em: EntityManager\n tenantId: string\n organizationId: string\n taskIds: readonly string[]\n}\n\ntype TaskRollupRow = {\n task_id: string\n parent_task_id: string | null\n task_project_id: string | null\n task_is_done: boolean | string | null\n entry_project_id: string | null\n minutes: string | number | null\n}\n\nfunction toDoneFlag(value: boolean | string | null | undefined): boolean {\n if (typeof value === 'boolean') return value\n return value === 't' || value === 'true'\n}\n\n/**\n * One grouped aggregate per page.\n *\n * The `OR` in the predicate is served by two indexes \u2014 the task primary key for the\n * page's own ids and `staff_time_tasks_parent_idx` for their children \u2014 so widening\n * to off-page children costs no extra round trip.\n */\nexport async function computeTaskRollups(scope: TaskRollupScope): Promise<Map<string, TaskPageRollup>> {\n const taskIds = [...new Set(scope.taskIds)].filter((id) => typeof id === 'string' && id.length > 0)\n if (taskIds.length === 0) return new Map<string, TaskPageRollup>()\n\n const placeholders = taskIds.map(() => '?').join(', ')\n const params: unknown[] = [scope.tenantId, scope.organizationId, ...taskIds, ...taskIds]\n\n // The status join is what makes `doneChildCount` free: done-ness is a property\n // of the column a task sits in (D-2), and the aggregate already walks every\n // child of the page.\n const sql = `\n SELECT\n t.id AS task_id,\n t.parent_task_id,\n t.time_project_id AS task_project_id,\n COALESCE(s.is_done, false) AS task_is_done,\n e.time_project_id AS entry_project_id,\n COALESCE(SUM(e.duration_minutes), 0)::bigint AS minutes\n FROM staff_time_tasks t\n LEFT JOIN staff_time_task_statuses s\n ON s.id = t.task_status_id\n AND s.tenant_id = t.tenant_id\n AND s.organization_id = t.organization_id\n AND s.deleted_at IS NULL\n LEFT JOIN staff_time_entries e\n ON e.task_id = t.id\n AND e.tenant_id = t.tenant_id\n AND e.organization_id = t.organization_id\n AND e.deleted_at IS NULL\n WHERE t.tenant_id = ?\n AND t.organization_id = ?\n AND t.deleted_at IS NULL\n AND (t.id IN (${placeholders}) OR t.parent_task_id IN (${placeholders}))\n GROUP BY 1, 2, 3, 4, 5\n `\n\n const rows = (await scope.em.getConnection().execute(sql, params)) as TaskRollupRow[]\n\n const tasks: TaskRollupTaskRow[] = []\n const entryGroups: TaskRollupEntryGroup[] = []\n for (const row of rows) {\n tasks.push({\n id: row.task_id,\n parentTaskId: row.parent_task_id,\n timeProjectId: row.task_project_id,\n isDone: toDoneFlag(row.task_is_done),\n deletedAt: null,\n })\n entryGroups.push({\n taskId: row.task_id,\n timeProjectId: row.entry_project_id,\n minutes: toMinutes(row.minutes),\n deletedAt: null,\n })\n }\n\n return summarizeTaskRollups({ taskIds, tasks, entryGroups })\n}\n"],
5
+ "mappings": "AACA,SAAS,qBAAyE;AAiE3E,MAAM,oBAAoC;AAAA,EAC/C,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,gBAAgB;AAClB;AAEA,SAAS,UAAU,OAAmD;AACpE,MAAI,UAAU,QAAQ,UAAU,OAAW,QAAO;AAClD,QAAM,SAAS,OAAO,UAAU,WAAW,QAAQ,OAAO,KAAK;AAC/D,SAAO,OAAO,SAAS,MAAM,IAAI,SAAS;AAC5C;AAUA,SAAS,kBAAkB,OAAqC;AAC9D,QAAM,UAAU,IAAI,IAAI,MAAM,OAAO;AACrC,QAAM,UAAU,oBAAI,IAAY;AAChC,aAAW,QAAQ,MAAM,OAAO;AAC9B,QAAI,CAAC,QAAQ,IAAI,KAAK,EAAE,KAAK,KAAK,UAAW;AAC7C,QAAI,KAAK,cAAe,SAAQ,IAAI,KAAK,aAAa;AAAA,EACxD;AACA,SAAO;AACT;AAUA,SAAS,kBACP,QACA,UACA,cACQ;AACR,MAAI,OAAO;AACX,aAAW,aAAa,UAAU;AAChC,QAAI,UAAU,iBAAiB,UAAU,UAAU,OAAO,UAAU,UAAU,UAAW;AACzF,QAAI,aAAa,IAAI,UAAU,EAAE,MAAM,KAAM,SAAQ;AAAA,EACvD;AACA,SAAO;AACT;AAEO,SAAS,qBAAqB,OAAqD;AACxF,QAAM,UAAU,kBAAkB,KAAK;AAKvC,QAAM,WAAW,oBAAI,IAAwB;AAC7C,QAAM,eAAe,oBAAI,IAAqB;AAC9C,aAAW,QAAQ,MAAM,OAAO;AAC9B,QAAI,SAAS,IAAI,KAAK,EAAE,EAAG;AAC3B,aAAS,IAAI,KAAK,IAAI,EAAE,IAAI,KAAK,IAAI,cAAc,KAAK,gBAAgB,MAAM,WAAW,KAAK,aAAa,KAAK,CAAC;AACjH,iBAAa,IAAI,KAAK,IAAI,KAAK,WAAW,IAAI;AAAA,EAChD;AACA,QAAM,WAAW,CAAC,GAAG,SAAS,OAAO,CAAC;AAEtC,QAAM,kBAAkB,oBAAI,IAA2B;AACvD,aAAW,SAAS,MAAM,aAAa;AACrC,QAAI,MAAM,iBAAiB,CAAC,QAAQ,IAAI,MAAM,aAAa,EAAG;AAC9D,UAAM,SAAS,gBAAgB,IAAI,MAAM,MAAM,KAAK,CAAC;AACrD,WAAO,KAAK,EAAE,iBAAiB,UAAU,MAAM,OAAO,GAAG,WAAW,MAAM,aAAa,KAAK,CAAC;AAC7F,oBAAgB,IAAI,MAAM,QAAQ,MAAM;AAAA,EAC1C;AAEA,QAAM,SAAS,oBAAI,IAA4B;AAC/C,aAAW,UAAU,MAAM,SAAS;AAClC,UAAM,OAAO,SAAS,IAAI,MAAM,KAAK,EAAE,IAAI,QAAQ,cAAc,KAAK;AACtE,WAAO,IAAI,QAAQ;AAAA,MACjB,GAAG,cAAc,MAAM,UAAU,eAAe;AAAA,MAChD,gBAAgB,kBAAkB,QAAQ,UAAU,YAAY;AAAA,IAClE,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAkBA,SAAS,WAAW,OAAqD;AACvE,MAAI,OAAO,UAAU,UAAW,QAAO;AACvC,SAAO,UAAU,OAAO,UAAU;AACpC;AASA,eAAsB,mBAAmB,OAA8D;AACrG,QAAM,UAAU,CAAC,GAAG,IAAI,IAAI,MAAM,OAAO,CAAC,EAAE,OAAO,CAAC,OAAO,OAAO,OAAO,YAAY,GAAG,SAAS,CAAC;AAClG,MAAI,QAAQ,WAAW,EAAG,QAAO,oBAAI,IAA4B;AAEjE,QAAM,eAAe,QAAQ,IAAI,MAAM,GAAG,EAAE,KAAK,IAAI;AACrD,QAAM,SAAoB,CAAC,MAAM,UAAU,MAAM,gBAAgB,GAAG,SAAS,GAAG,OAAO;AAKvF,QAAM,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAsBQ,YAAY,6BAA6B,YAAY;AAAA;AAAA;AAIzE,QAAM,OAAQ,MAAM,MAAM,GAAG,cAAc,EAAE,QAAQ,KAAK,MAAM;AAEhE,QAAM,QAA6B,CAAC;AACpC,QAAM,cAAsC,CAAC;AAC7C,aAAW,OAAO,MAAM;AACtB,UAAM,KAAK;AAAA,MACT,IAAI,IAAI;AAAA,MACR,cAAc,IAAI;AAAA,MAClB,eAAe,IAAI;AAAA,MACnB,QAAQ,WAAW,IAAI,YAAY;AAAA,MACnC,WAAW;AAAA,IACb,CAAC;AACD,gBAAY,KAAK;AAAA,MACf,QAAQ,IAAI;AAAA,MACZ,eAAe,IAAI;AAAA,MACnB,SAAS,UAAU,IAAI,OAAO;AAAA,MAC9B,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,SAAO,qBAAqB,EAAE,SAAS,OAAO,YAAY,CAAC;AAC7D;",
6
+ "names": []
7
+ }
@@ -0,0 +1,50 @@
1
+ import { STATUS_POSITION_GAP } from "./statusPositions.js";
2
+ const DEFAULT_TASK_STATUS_TEMPLATE = [
3
+ {
4
+ slug: "backlog",
5
+ labelKey: "staff.time_tracking.taskStatuses.defaults.backlog",
6
+ defaultLabel: "Backlog",
7
+ color: "indigo",
8
+ isDefault: true,
9
+ isDone: false
10
+ },
11
+ {
12
+ slug: "in-progress",
13
+ labelKey: "staff.time_tracking.taskStatuses.defaults.inProgress",
14
+ defaultLabel: "In progress",
15
+ color: "blue",
16
+ isDefault: false,
17
+ isDone: false
18
+ },
19
+ {
20
+ slug: "in-review",
21
+ labelKey: "staff.time_tracking.taskStatuses.defaults.inReview",
22
+ defaultLabel: "In review",
23
+ color: "orange",
24
+ isDefault: false,
25
+ isDone: false
26
+ },
27
+ {
28
+ slug: "done",
29
+ labelKey: "staff.time_tracking.taskStatuses.defaults.done",
30
+ defaultLabel: "Done",
31
+ color: "emerald",
32
+ isDefault: false,
33
+ isDone: true
34
+ }
35
+ ];
36
+ function buildDefaultTaskStatusRows(translate) {
37
+ return DEFAULT_TASK_STATUS_TEMPLATE.map((entry, index) => ({
38
+ slug: entry.slug,
39
+ name: translate(entry.labelKey, entry.defaultLabel),
40
+ color: entry.color,
41
+ position: (index + 1) * STATUS_POSITION_GAP,
42
+ isDefault: entry.isDefault,
43
+ isDone: entry.isDone
44
+ }));
45
+ }
46
+ export {
47
+ DEFAULT_TASK_STATUS_TEMPLATE,
48
+ buildDefaultTaskStatusRows
49
+ };
50
+ //# sourceMappingURL=defaultStatusTemplate.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/modules/staff/lib/timesheets-tasks/defaultStatusTemplate.ts"],
4
+ "sourcesContent": ["/**\n * The tenant default Kanban template a project is seeded with (D-1).\n *\n * D-1 makes columns per-project so an audit project and a migration project can\n * look nothing alike, which only works if every project starts from something\n * usable \u2014 there is no board without columns, and no UI that repairs an empty\n * one. This template is that starting point: the four columns screen 6 draws,\n * with the entry point (`isDefault`) and the terminal column (`isDone`) already\n * marked so a task can be created and closed the moment the project exists.\n *\n * Labels are i18n keys with an English fallback, resolved through the same\n * `translate(key, fallback)` seam the rest of the module uses, so a Polish tenant\n * gets the mockup's \"W toku\" rather than a hardcoded English string. Colours are\n * DS chart token keys from `PROJECT_COLOR_KEYS`, never raw hex \u2014 the board reads\n * the key back through `resolveProjectColorHex` to paint `kcol-accent`.\n */\n\nimport type { ProjectColorKey } from '../timesheets-ui/colors'\nimport { STATUS_POSITION_GAP } from './statusPositions'\n\nexport type DefaultTaskStatusTemplateEntry = {\n slug: string\n labelKey: string\n defaultLabel: string\n color: ProjectColorKey\n isDefault: boolean\n isDone: boolean\n}\n\nexport const DEFAULT_TASK_STATUS_TEMPLATE: readonly DefaultTaskStatusTemplateEntry[] = [\n {\n slug: 'backlog',\n labelKey: 'staff.time_tracking.taskStatuses.defaults.backlog',\n defaultLabel: 'Backlog',\n color: 'indigo',\n isDefault: true,\n isDone: false,\n },\n {\n slug: 'in-progress',\n labelKey: 'staff.time_tracking.taskStatuses.defaults.inProgress',\n defaultLabel: 'In progress',\n color: 'blue',\n isDefault: false,\n isDone: false,\n },\n {\n slug: 'in-review',\n labelKey: 'staff.time_tracking.taskStatuses.defaults.inReview',\n defaultLabel: 'In review',\n color: 'orange',\n isDefault: false,\n isDone: false,\n },\n {\n slug: 'done',\n labelKey: 'staff.time_tracking.taskStatuses.defaults.done',\n defaultLabel: 'Done',\n color: 'emerald',\n isDefault: false,\n isDone: true,\n },\n] as const\n\nexport type DefaultTaskStatusRow = {\n slug: string\n name: string\n color: ProjectColorKey\n position: number\n isDefault: boolean\n isDone: boolean\n}\n\nexport type TaskStatusLabelTranslate = (key: string, fallback: string) => string\n\n/**\n * Materialises the template into insertable rows: localized names and positions\n * already on the gap grid, so the first drag on a fresh board is a single-row\n * write rather than an immediate compaction.\n */\nexport function buildDefaultTaskStatusRows(translate: TaskStatusLabelTranslate): DefaultTaskStatusRow[] {\n return DEFAULT_TASK_STATUS_TEMPLATE.map((entry, index) => ({\n slug: entry.slug,\n name: translate(entry.labelKey, entry.defaultLabel),\n color: entry.color,\n position: (index + 1) * STATUS_POSITION_GAP,\n isDefault: entry.isDefault,\n isDone: entry.isDone,\n }))\n}\n"],
5
+ "mappings": "AAkBA,SAAS,2BAA2B;AAW7B,MAAM,+BAA0E;AAAA,EACrF;AAAA,IACE,MAAM;AAAA,IACN,UAAU;AAAA,IACV,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,EACV;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,UAAU;AAAA,IACV,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,EACV;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,UAAU;AAAA,IACV,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,EACV;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,UAAU;AAAA,IACV,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,EACV;AACF;AAkBO,SAAS,2BAA2B,WAA6D;AACtG,SAAO,6BAA6B,IAAI,CAAC,OAAO,WAAW;AAAA,IACzD,MAAM,MAAM;AAAA,IACZ,MAAM,UAAU,MAAM,UAAU,MAAM,YAAY;AAAA,IAClD,OAAO,MAAM;AAAA,IACb,WAAW,QAAQ,KAAK;AAAA,IACxB,WAAW,MAAM;AAAA,IACjB,QAAQ,MAAM;AAAA,EAChB,EAAE;AACJ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,27 @@
1
+ import { StaffTimeTaskStatus } from "../../data/entities.js";
2
+ import { buildDefaultTaskStatusRows } from "./defaultStatusTemplate.js";
3
+ function seedProjectTaskStatuses(em, scope, translate) {
4
+ const now = /* @__PURE__ */ new Date();
5
+ return buildDefaultTaskStatusRows(translate).map((row) => {
6
+ const status = em.create(StaffTimeTaskStatus, {
7
+ tenantId: scope.tenantId,
8
+ organizationId: scope.organizationId,
9
+ timeProjectId: scope.timeProjectId,
10
+ name: row.name,
11
+ slug: row.slug,
12
+ color: row.color,
13
+ position: row.position,
14
+ isDefault: row.isDefault,
15
+ isDone: row.isDone,
16
+ createdAt: now,
17
+ updatedAt: now,
18
+ deletedAt: null
19
+ });
20
+ em.persist(status);
21
+ return status;
22
+ });
23
+ }
24
+ export {
25
+ seedProjectTaskStatuses
26
+ };
27
+ //# sourceMappingURL=seedProjectStatuses.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/modules/staff/lib/timesheets-tasks/seedProjectStatuses.ts"],
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { StaffTimeTaskStatus } from '../../data/entities'\nimport { buildDefaultTaskStatusRows, type TaskStatusLabelTranslate } from './defaultStatusTemplate'\n\nexport type SeedProjectTaskStatusesScope = {\n tenantId: string\n organizationId: string\n timeProjectId: string\n}\n\n/**\n * Materialises the default template onto a freshly created project.\n *\n * Persist-only, deliberately: it issues no query and never flushes, so the caller\n * can run it as a mutation phase of the same transaction that inserted the\n * project. That is the whole point \u2014 a project that exists without columns is a\n * board nothing can be filed on, and there is no UI that repairs one.\n */\nexport function seedProjectTaskStatuses(\n em: EntityManager,\n scope: SeedProjectTaskStatusesScope,\n translate: TaskStatusLabelTranslate,\n): StaffTimeTaskStatus[] {\n const now = new Date()\n return buildDefaultTaskStatusRows(translate).map((row) => {\n const status = em.create(StaffTimeTaskStatus, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n timeProjectId: scope.timeProjectId,\n name: row.name,\n slug: row.slug,\n color: row.color,\n position: row.position,\n isDefault: row.isDefault,\n isDone: row.isDone,\n createdAt: now,\n updatedAt: now,\n deletedAt: null,\n })\n em.persist(status)\n return status\n })\n}\n"],
5
+ "mappings": "AACA,SAAS,2BAA2B;AACpC,SAAS,kCAAiE;AAgBnE,SAAS,wBACd,IACA,OACA,WACuB;AACvB,QAAM,MAAM,oBAAI,KAAK;AACrB,SAAO,2BAA2B,SAAS,EAAE,IAAI,CAAC,QAAQ;AACxD,UAAM,SAAS,GAAG,OAAO,qBAAqB;AAAA,MAC5C,UAAU,MAAM;AAAA,MAChB,gBAAgB,MAAM;AAAA,MACtB,eAAe,MAAM;AAAA,MACrB,MAAM,IAAI;AAAA,MACV,MAAM,IAAI;AAAA,MACV,OAAO,IAAI;AAAA,MACX,UAAU,IAAI;AAAA,MACd,WAAW,IAAI;AAAA,MACf,QAAQ,IAAI;AAAA,MACZ,WAAW;AAAA,MACX,WAAW;AAAA,MACX,WAAW;AAAA,IACb,CAAC;AACD,OAAG,QAAQ,MAAM;AACjB,WAAO;AAAA,EACT,CAAC;AACH;",
6
+ "names": []
7
+ }
@@ -0,0 +1,65 @@
1
+ const STATUS_POSITION_GAP = 1e3;
2
+ const MAX_STATUS_POSITION = 1e6;
3
+ function nextStatusPosition(positions) {
4
+ const finite = positions.filter((value) => Number.isFinite(value));
5
+ if (finite.length === 0) return STATUS_POSITION_GAP;
6
+ const highest = Math.max(...finite);
7
+ const next = highest + STATUS_POSITION_GAP;
8
+ if (next <= MAX_STATUS_POSITION) return next;
9
+ return Math.min(highest + 1, MAX_STATUS_POSITION);
10
+ }
11
+ function compactStatusPositions(ids) {
12
+ return ids.map((id, index) => ({ id, position: (index + 1) * STATUS_POSITION_GAP }));
13
+ }
14
+ function isUsablePosition(value) {
15
+ return Number.isInteger(value) && value >= 0 && value <= MAX_STATUS_POSITION;
16
+ }
17
+ function planStatusReorder(current, requested) {
18
+ const currentById = new Map(current.map((row) => [row.id, row.position]));
19
+ const unknownIds = [];
20
+ const requestedById = /* @__PURE__ */ new Map();
21
+ for (const row of requested) {
22
+ if (!currentById.has(row.id)) {
23
+ if (!unknownIds.includes(row.id)) unknownIds.push(row.id);
24
+ continue;
25
+ }
26
+ requestedById.set(row.id, row.position);
27
+ }
28
+ const desired = current.map((row) => ({
29
+ id: row.id,
30
+ currentPosition: row.position,
31
+ targetPosition: requestedById.get(row.id) ?? row.position,
32
+ requested: requestedById.has(row.id)
33
+ }));
34
+ desired.sort((left, right) => {
35
+ if (left.targetPosition !== right.targetPosition) return left.targetPosition - right.targetPosition;
36
+ if (left.requested !== right.requested) return left.requested ? -1 : 1;
37
+ if (left.currentPosition !== right.currentPosition) return left.currentPosition - right.currentPosition;
38
+ return left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
39
+ });
40
+ const fitsOnGrid = desired.every(
41
+ (row, index) => isUsablePosition(row.targetPosition) && (index === 0 || row.targetPosition > desired[index - 1].targetPosition)
42
+ );
43
+ if (fitsOnGrid) {
44
+ return {
45
+ updates: desired.filter((row) => row.targetPosition !== row.currentPosition).map((row) => ({ id: row.id, position: row.targetPosition })),
46
+ compacted: false,
47
+ unknownIds
48
+ };
49
+ }
50
+ const compactedPositions = compactStatusPositions(desired.map((row) => row.id));
51
+ const currentPositionById = new Map(desired.map((row) => [row.id, row.currentPosition]));
52
+ return {
53
+ updates: compactedPositions.filter((row) => currentPositionById.get(row.id) !== row.position),
54
+ compacted: true,
55
+ unknownIds
56
+ };
57
+ }
58
+ export {
59
+ MAX_STATUS_POSITION,
60
+ STATUS_POSITION_GAP,
61
+ compactStatusPositions,
62
+ nextStatusPosition,
63
+ planStatusReorder
64
+ };
65
+ //# sourceMappingURL=statusPositions.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/modules/staff/lib/timesheets-tasks/statusPositions.ts"],
4
+ "sourcesContent": ["/**\n * Gap-based ordering arithmetic for the Kanban columns of screen 6.\n *\n * Positions are integers spaced `STATUS_POSITION_GAP` apart rather than a dense\n * 0..n-1 sequence. That is what keeps a drag cheap: the board hands the server a\n * midpoint between the two columns the pointer was released over, so moving one\n * column writes exactly one row instead of renumbering every column on the board.\n *\n * The dense renumber still exists, but only as the fallback for the one case the\n * midpoint scheme cannot express \u2014 a gap narrow enough that no integer fits\n * between two neighbours. Then the whole board is compacted back onto the gap\n * grid, which restores room for the next few thousand drags.\n */\n\nexport const STATUS_POSITION_GAP = 1000\n\n/**\n * Mirrors the ceiling `positionSchema` accepts in `data/validators.ts`, so a\n * server-computed position can always be round-tripped back through the API.\n */\nexport const MAX_STATUS_POSITION = 1_000_000\n\nexport type StatusPosition = {\n id: string\n position: number\n}\n\nexport type StatusReorderPlan = {\n /** Only the rows whose stored position actually has to change. */\n updates: StatusPosition[]\n /** True when the gap ran out and the whole board was re-spaced. */\n compacted: boolean\n /** Requested ids that do not belong to the project \u2014 the caller rejects these. */\n unknownIds: string[]\n}\n\n/**\n * Position for a column appended to the right-hand end of the board (the\n * mockup's \"Nowa kolumna / Dodaj status\" affordance).\n */\nexport function nextStatusPosition(positions: readonly number[]): number {\n const finite = positions.filter((value) => Number.isFinite(value))\n if (finite.length === 0) return STATUS_POSITION_GAP\n const highest = Math.max(...finite)\n const next = highest + STATUS_POSITION_GAP\n if (next <= MAX_STATUS_POSITION) return next\n // Past the ceiling the board is out of headroom; fall back to the tightest\n // step that still preserves ordering. A reorder will compact it back later.\n return Math.min(highest + 1, MAX_STATUS_POSITION)\n}\n\n/** Re-spaces an ordered id list back onto the gap grid. */\nexport function compactStatusPositions(ids: readonly string[]): StatusPosition[] {\n return ids.map((id, index) => ({ id, position: (index + 1) * STATUS_POSITION_GAP }))\n}\n\ntype DesiredRow = {\n id: string\n currentPosition: number\n targetPosition: number\n requested: boolean\n}\n\nfunction isUsablePosition(value: number): boolean {\n return Number.isInteger(value) && value >= 0 && value <= MAX_STATUS_POSITION\n}\n\n/**\n * Turns a reorder request into the minimal set of position writes.\n *\n * `current` is every live column of the project; `requested` is the subset the\n * client moved, carrying its intended sort key. Columns absent from the request\n * keep the position they already have, so a board can be reordered one column at\n * a time without the client having to restate the rest.\n */\nexport function planStatusReorder(\n current: readonly StatusPosition[],\n requested: readonly StatusPosition[],\n): StatusReorderPlan {\n const currentById = new Map(current.map((row) => [row.id, row.position]))\n const unknownIds: string[] = []\n const requestedById = new Map<string, number>()\n for (const row of requested) {\n if (!currentById.has(row.id)) {\n if (!unknownIds.includes(row.id)) unknownIds.push(row.id)\n continue\n }\n requestedById.set(row.id, row.position)\n }\n\n const desired: DesiredRow[] = current.map((row) => ({\n id: row.id,\n currentPosition: row.position,\n targetPosition: requestedById.get(row.id) ?? row.position,\n requested: requestedById.has(row.id),\n }))\n\n desired.sort((left, right) => {\n if (left.targetPosition !== right.targetPosition) return left.targetPosition - right.targetPosition\n // A dragged column dropped exactly onto a settled column's key lands ahead of\n // it, which is where the pointer was released. Two settled columns keep their\n // previous relative order, then sort by id \u2014 so the outcome never depends on\n // the order rows happened to arrive in.\n if (left.requested !== right.requested) return left.requested ? -1 : 1\n if (left.currentPosition !== right.currentPosition) return left.currentPosition - right.currentPosition\n return left.id < right.id ? -1 : left.id > right.id ? 1 : 0\n })\n\n const fitsOnGrid = desired.every(\n (row, index) =>\n isUsablePosition(row.targetPosition) &&\n (index === 0 || row.targetPosition > desired[index - 1].targetPosition),\n )\n\n if (fitsOnGrid) {\n return {\n updates: desired\n .filter((row) => row.targetPosition !== row.currentPosition)\n .map((row) => ({ id: row.id, position: row.targetPosition })),\n compacted: false,\n unknownIds,\n }\n }\n\n const compactedPositions = compactStatusPositions(desired.map((row) => row.id))\n const currentPositionById = new Map(desired.map((row) => [row.id, row.currentPosition]))\n return {\n updates: compactedPositions.filter((row) => currentPositionById.get(row.id) !== row.position),\n compacted: true,\n unknownIds,\n }\n}\n"],
5
+ "mappings": "AAcO,MAAM,sBAAsB;AAM5B,MAAM,sBAAsB;AAoB5B,SAAS,mBAAmB,WAAsC;AACvE,QAAM,SAAS,UAAU,OAAO,CAAC,UAAU,OAAO,SAAS,KAAK,CAAC;AACjE,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,QAAM,UAAU,KAAK,IAAI,GAAG,MAAM;AAClC,QAAM,OAAO,UAAU;AACvB,MAAI,QAAQ,oBAAqB,QAAO;AAGxC,SAAO,KAAK,IAAI,UAAU,GAAG,mBAAmB;AAClD;AAGO,SAAS,uBAAuB,KAA0C;AAC/E,SAAO,IAAI,IAAI,CAAC,IAAI,WAAW,EAAE,IAAI,WAAW,QAAQ,KAAK,oBAAoB,EAAE;AACrF;AASA,SAAS,iBAAiB,OAAwB;AAChD,SAAO,OAAO,UAAU,KAAK,KAAK,SAAS,KAAK,SAAS;AAC3D;AAUO,SAAS,kBACd,SACA,WACmB;AACnB,QAAM,cAAc,IAAI,IAAI,QAAQ,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,IAAI,QAAQ,CAAC,CAAC;AACxE,QAAM,aAAuB,CAAC;AAC9B,QAAM,gBAAgB,oBAAI,IAAoB;AAC9C,aAAW,OAAO,WAAW;AAC3B,QAAI,CAAC,YAAY,IAAI,IAAI,EAAE,GAAG;AAC5B,UAAI,CAAC,WAAW,SAAS,IAAI,EAAE,EAAG,YAAW,KAAK,IAAI,EAAE;AACxD;AAAA,IACF;AACA,kBAAc,IAAI,IAAI,IAAI,IAAI,QAAQ;AAAA,EACxC;AAEA,QAAM,UAAwB,QAAQ,IAAI,CAAC,SAAS;AAAA,IAClD,IAAI,IAAI;AAAA,IACR,iBAAiB,IAAI;AAAA,IACrB,gBAAgB,cAAc,IAAI,IAAI,EAAE,KAAK,IAAI;AAAA,IACjD,WAAW,cAAc,IAAI,IAAI,EAAE;AAAA,EACrC,EAAE;AAEF,UAAQ,KAAK,CAAC,MAAM,UAAU;AAC5B,QAAI,KAAK,mBAAmB,MAAM,eAAgB,QAAO,KAAK,iBAAiB,MAAM;AAKrF,QAAI,KAAK,cAAc,MAAM,UAAW,QAAO,KAAK,YAAY,KAAK;AACrE,QAAI,KAAK,oBAAoB,MAAM,gBAAiB,QAAO,KAAK,kBAAkB,MAAM;AACxF,WAAO,KAAK,KAAK,MAAM,KAAK,KAAK,KAAK,KAAK,MAAM,KAAK,IAAI;AAAA,EAC5D,CAAC;AAED,QAAM,aAAa,QAAQ;AAAA,IACzB,CAAC,KAAK,UACJ,iBAAiB,IAAI,cAAc,MAClC,UAAU,KAAK,IAAI,iBAAiB,QAAQ,QAAQ,CAAC,EAAE;AAAA,EAC5D;AAEA,MAAI,YAAY;AACd,WAAO;AAAA,MACL,SAAS,QACN,OAAO,CAAC,QAAQ,IAAI,mBAAmB,IAAI,eAAe,EAC1D,IAAI,CAAC,SAAS,EAAE,IAAI,IAAI,IAAI,UAAU,IAAI,eAAe,EAAE;AAAA,MAC9D,WAAW;AAAA,MACX;AAAA,IACF;AAAA,EACF;AAEA,QAAM,qBAAqB,uBAAuB,QAAQ,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;AAC9E,QAAM,sBAAsB,IAAI,IAAI,QAAQ,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,IAAI,eAAe,CAAC,CAAC;AACvF,SAAO;AAAA,IACL,SAAS,mBAAmB,OAAO,CAAC,QAAQ,oBAAoB,IAAI,IAAI,EAAE,MAAM,IAAI,QAAQ;AAAA,IAC5F,WAAW;AAAA,IACX;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,31 @@
1
+ import { slugifyProjectName } from "../time-tracking/projectCode.js";
2
+ const TASK_STATUS_SLUG_MAX_LENGTH = 60;
3
+ const TASK_STATUS_SLUG_FALLBACK = "status";
4
+ function slugifyTaskStatusName(name) {
5
+ const slug = slugifyProjectName(name).toLowerCase();
6
+ if (slug.length <= TASK_STATUS_SLUG_MAX_LENGTH) return slug;
7
+ return slug.slice(0, TASK_STATUS_SLUG_MAX_LENGTH).replace(/-+$/g, "");
8
+ }
9
+ function withSuffix(base, suffix) {
10
+ const budget = TASK_STATUS_SLUG_MAX_LENGTH - suffix.length;
11
+ const stem = base.length <= budget ? base : base.slice(0, budget).replace(/-+$/g, "");
12
+ return `${stem || TASK_STATUS_SLUG_FALLBACK}${suffix}`;
13
+ }
14
+ function deriveTaskStatusSlug(name, taken = []) {
15
+ const base = slugifyTaskStatusName(name) || TASK_STATUS_SLUG_FALLBACK;
16
+ const reserved = new Set(Array.from(taken, (value) => String(value).toLowerCase()));
17
+ if (!reserved.has(base)) return base;
18
+ let candidate = base;
19
+ for (let counter = 2; counter < 1e4; counter += 1) {
20
+ candidate = withSuffix(base, `-${counter}`);
21
+ if (!reserved.has(candidate)) return candidate;
22
+ }
23
+ return candidate;
24
+ }
25
+ export {
26
+ TASK_STATUS_SLUG_FALLBACK,
27
+ TASK_STATUS_SLUG_MAX_LENGTH,
28
+ deriveTaskStatusSlug,
29
+ slugifyTaskStatusName
30
+ };
31
+ //# sourceMappingURL=statusSlug.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/modules/staff/lib/timesheets-tasks/statusSlug.ts"],
4
+ "sourcesContent": ["import { slugifyProjectName } from '../time-tracking/projectCode'\n\n/** Mirrors the `timeSlugSchema` ceiling in `data/validators.ts`. */\nexport const TASK_STATUS_SLUG_MAX_LENGTH = 60\n\nexport const TASK_STATUS_SLUG_FALLBACK = 'status'\n\n/**\n * A column's slug is the stable id filters and saved views hold onto, so it is\n * derived once from the name and then frozen \u2014 renaming \"W toku\" to \"In progress\"\n * must not break a filter that was saved against it. The derivation reuses the\n * project-code transliteration so `Do przegl\u0105du` becomes `do-przegladu` rather\n * than dropping the diacritics into nothing.\n */\nexport function slugifyTaskStatusName(name: string): string {\n const slug = slugifyProjectName(name).toLowerCase()\n if (slug.length <= TASK_STATUS_SLUG_MAX_LENGTH) return slug\n return slug.slice(0, TASK_STATUS_SLUG_MAX_LENGTH).replace(/-+$/g, '')\n}\n\nfunction withSuffix(base: string, suffix: string): string {\n const budget = TASK_STATUS_SLUG_MAX_LENGTH - suffix.length\n const stem = base.length <= budget ? base : base.slice(0, budget).replace(/-+$/g, '')\n return `${stem || TASK_STATUS_SLUG_FALLBACK}${suffix}`\n}\n\n/**\n * Derives a slug that does not collide with the ones already on the board. The\n * partial unique index is still the authority \u2014 this only keeps the common case\n * from reaching it as a constraint violation.\n */\nexport function deriveTaskStatusSlug(name: string, taken: Iterable<string> = []): string {\n const base = slugifyTaskStatusName(name) || TASK_STATUS_SLUG_FALLBACK\n const reserved = new Set(Array.from(taken, (value) => String(value).toLowerCase()))\n if (!reserved.has(base)) return base\n\n let candidate = base\n for (let counter = 2; counter < 10000; counter += 1) {\n candidate = withSuffix(base, `-${counter}`)\n if (!reserved.has(candidate)) return candidate\n }\n return candidate\n}\n"],
5
+ "mappings": "AAAA,SAAS,0BAA0B;AAG5B,MAAM,8BAA8B;AAEpC,MAAM,4BAA4B;AASlC,SAAS,sBAAsB,MAAsB;AAC1D,QAAM,OAAO,mBAAmB,IAAI,EAAE,YAAY;AAClD,MAAI,KAAK,UAAU,4BAA6B,QAAO;AACvD,SAAO,KAAK,MAAM,GAAG,2BAA2B,EAAE,QAAQ,QAAQ,EAAE;AACtE;AAEA,SAAS,WAAW,MAAc,QAAwB;AACxD,QAAM,SAAS,8BAA8B,OAAO;AACpD,QAAM,OAAO,KAAK,UAAU,SAAS,OAAO,KAAK,MAAM,GAAG,MAAM,EAAE,QAAQ,QAAQ,EAAE;AACpF,SAAO,GAAG,QAAQ,yBAAyB,GAAG,MAAM;AACtD;AAOO,SAAS,qBAAqB,MAAc,QAA0B,CAAC,GAAW;AACvF,QAAM,OAAO,sBAAsB,IAAI,KAAK;AAC5C,QAAM,WAAW,IAAI,IAAI,MAAM,KAAK,OAAO,CAAC,UAAU,OAAO,KAAK,EAAE,YAAY,CAAC,CAAC;AAClF,MAAI,CAAC,SAAS,IAAI,IAAI,EAAG,QAAO;AAEhC,MAAI,YAAY;AAChB,WAAS,UAAU,GAAG,UAAU,KAAO,WAAW,GAAG;AACnD,gBAAY,WAAW,MAAM,IAAI,OAAO,EAAE;AAC1C,QAAI,CAAC,SAAS,IAAI,SAAS,EAAG,QAAO;AAAA,EACvC;AACA,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -0,0 +1,31 @@
1
+ const SUBTASK_DEPTH_EXCEEDED_CODE = "subtask_depth_exceeded";
2
+ const MAX_TASK_DEPTH = 1;
3
+ function rejectTaskParent(parent, child) {
4
+ if (child.id && parent.id === child.id) return "self_parent";
5
+ if (parent.timeProjectId !== child.timeProjectId) return "parent_project_mismatch";
6
+ if (parent.parentTaskId != null) return "subtask_depth_exceeded";
7
+ if ((child.childCount ?? 0) > 0) return "subtask_depth_exceeded";
8
+ return null;
9
+ }
10
+ function canAcceptChildren(task) {
11
+ return task.parentTaskId == null;
12
+ }
13
+ function planTaskSoftDelete(task, children = []) {
14
+ const childIds = [];
15
+ const seen = /* @__PURE__ */ new Set([task.id]);
16
+ const candidates = canAcceptChildren(task) ? children : [];
17
+ for (const child of candidates) {
18
+ if (!child?.id || seen.has(child.id)) continue;
19
+ seen.add(child.id);
20
+ childIds.push(child.id);
21
+ }
22
+ return { taskId: task.id, childIds, allIds: [task.id, ...childIds] };
23
+ }
24
+ export {
25
+ MAX_TASK_DEPTH,
26
+ SUBTASK_DEPTH_EXCEEDED_CODE,
27
+ canAcceptChildren,
28
+ planTaskSoftDelete,
29
+ rejectTaskParent
30
+ };
31
+ //# sourceMappingURL=taskHierarchy.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/modules/staff/lib/timesheets-tasks/taskHierarchy.ts"],
4
+ "sourcesContent": ["/**\n * The depth-1 rule behind D-2, as pure predicates.\n *\n * A subtask is not a second kind of record \u2014 it is a task with `parent_task_id` set,\n * carrying its own status, assignee and time entries. What keeps that from turning\n * into an arbitrary tree (which the board, the drawer checklist and the report rollup\n * would each have to learn to walk) is a single invariant: **a parent may not itself\n * have a parent**. One level, no exceptions, enforced on create and on re-parent.\n *\n * The consequences the rest of the module relies on:\n * - the board can filter `parent_task_id IS NULL` and know it is showing every task\n * that is not already displayed inside some other task's drawer;\n * - the rollup is `own + \u03A3 children` with no recursion;\n * - a soft-delete cascade is one level deep, so it is a single extra write set rather\n * than a walk.\n */\n\nexport const SUBTASK_DEPTH_EXCEEDED_CODE = 'subtask_depth_exceeded'\n\n/** A parent may have children; a child may not. Depth is counted in edges. */\nexport const MAX_TASK_DEPTH = 1\n\nexport type TaskHierarchyNode = {\n id: string\n timeProjectId: string\n parentTaskId?: string | null\n}\n\n/** The task being parented. On create it has no id yet and no children. */\nexport type TaskHierarchyChild = {\n id?: string | null\n timeProjectId: string\n /** Live children the task already has. A task with children may not become one. */\n childCount?: number\n}\n\nexport type TaskParentRejection =\n /** The task was pointed at itself. */\n | 'self_parent'\n /** Either the intended parent is already a child, or the task itself has children. */\n | 'subtask_depth_exceeded'\n /** \u00A72 \u2014 a task lives in exactly one project, and so does its parent. */\n | 'parent_project_mismatch'\n\n/**\n * Answers \"may `child` be parented to `parent`?\" \u2014 `null` means yes.\n *\n * A missing parent is the caller's to report (it is a 404/422 about an unreachable\n * record, not a shape violation), so this function is only handed a parent that was\n * actually loaded inside the caller's scope.\n */\nexport function rejectTaskParent(\n parent: TaskHierarchyNode,\n child: TaskHierarchyChild,\n): TaskParentRejection | null {\n if (child.id && parent.id === child.id) return 'self_parent'\n if (parent.timeProjectId !== child.timeProjectId) return 'parent_project_mismatch'\n // The intended parent is itself a subtask \u2014 accepting this would make a grandchild.\n if (parent.parentTaskId != null) return 'subtask_depth_exceeded'\n // The task being moved already holds children, so it cannot also become one.\n if ((child.childCount ?? 0) > 0) return 'subtask_depth_exceeded'\n return null\n}\n\n/** True when the task may still gain children (i.e. it is not itself a child). */\nexport function canAcceptChildren(task: Pick<TaskHierarchyNode, 'parentTaskId'>): boolean {\n return task.parentTaskId == null\n}\n\nexport type TaskSoftDeletePlan = {\n taskId: string\n /** Live children that go with the parent, in the order they were read. */\n childIds: string[]\n /** Everything the delete transaction stamps `deleted_at` on. */\n allIds: string[]\n}\n\n/**\n * Soft-deleting a parent takes its children with it, in the same transaction.\n *\n * Time entries are deliberately absent from the plan: they keep pointing at the\n * deleted task so a closed report still resolves its line labels months later. The\n * cascade is one level because the depth rule guarantees the children have none.\n */\nexport function planTaskSoftDelete(\n task: TaskHierarchyNode,\n children: readonly Pick<TaskHierarchyNode, 'id'>[] = [],\n): TaskSoftDeletePlan {\n const childIds: string[] = []\n const seen = new Set<string>([task.id])\n // A child task can never bring a cascade of its own, so the list is empty for one.\n const candidates = canAcceptChildren(task) ? children : []\n for (const child of candidates) {\n if (!child?.id || seen.has(child.id)) continue\n seen.add(child.id)\n childIds.push(child.id)\n }\n return { taskId: task.id, childIds, allIds: [task.id, ...childIds] }\n}\n"],
5
+ "mappings": "AAiBO,MAAM,8BAA8B;AAGpC,MAAM,iBAAiB;AA+BvB,SAAS,iBACd,QACA,OAC4B;AAC5B,MAAI,MAAM,MAAM,OAAO,OAAO,MAAM,GAAI,QAAO;AAC/C,MAAI,OAAO,kBAAkB,MAAM,cAAe,QAAO;AAEzD,MAAI,OAAO,gBAAgB,KAAM,QAAO;AAExC,OAAK,MAAM,cAAc,KAAK,EAAG,QAAO;AACxC,SAAO;AACT;AAGO,SAAS,kBAAkB,MAAwD;AACxF,SAAO,KAAK,gBAAgB;AAC9B;AAiBO,SAAS,mBACd,MACA,WAAqD,CAAC,GAClC;AACpB,QAAM,WAAqB,CAAC;AAC5B,QAAM,OAAO,oBAAI,IAAY,CAAC,KAAK,EAAE,CAAC;AAEtC,QAAM,aAAa,kBAAkB,IAAI,IAAI,WAAW,CAAC;AACzD,aAAW,SAAS,YAAY;AAC9B,QAAI,CAAC,OAAO,MAAM,KAAK,IAAI,MAAM,EAAE,EAAG;AACtC,SAAK,IAAI,MAAM,EAAE;AACjB,aAAS,KAAK,MAAM,EAAE;AAAA,EACxB;AACA,SAAO,EAAE,QAAQ,KAAK,IAAI,UAAU,QAAQ,CAAC,KAAK,IAAI,GAAG,QAAQ,EAAE;AACrE;",
6
+ "names": []
7
+ }
@@ -0,0 +1,17 @@
1
+ function toMinutes(value) {
2
+ if (value === null || value === void 0 || !Number.isFinite(value)) return 0;
3
+ return value;
4
+ }
5
+ function sumTaskLoggedMinutes(rows) {
6
+ const presentIds = new Set(rows.map((row) => row.id));
7
+ let total = 0;
8
+ for (const row of rows) {
9
+ if (row.parentTaskId && presentIds.has(row.parentTaskId)) continue;
10
+ total += toMinutes(row.loggedMinutes);
11
+ }
12
+ return total;
13
+ }
14
+ export {
15
+ sumTaskLoggedMinutes
16
+ };
17
+ //# sourceMappingURL=taskHoursTotals.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/modules/staff/lib/timesheets-tasks/taskHoursTotals.ts"],
4
+ "sourcesContent": ["/**\n * Column totals for the board (screen 6, `kcol-hours`).\n *\n * Every card already carries the inclusive rollup (D-2), which makes a column total a\n * client-side sum of rows the board is holding anyway \u2014 no second endpoint, and no way\n * for the header to disagree with the cards under it.\n *\n * It also makes the total the one place risk R10 can bite: adding a parent's\n * `loggedMinutes` to its child's adds the child twice, because the parent's figure\n * already contains it. The board never renders a child as its own card, so in practice\n * the set is parent-only \u2014 but \"in practice\" is not a guarantee a caller can rely on,\n * so this helper drops any row whose parent is present in the same set instead of\n * trusting the caller to have filtered it.\n */\n\nexport type TaskHoursRow = {\n id: string\n parentTaskId?: string | null\n loggedMinutes?: number | null\n}\n\nfunction toMinutes(value: number | null | undefined): number {\n if (value === null || value === undefined || !Number.isFinite(value)) return 0\n return value\n}\n\n/**\n * Sums `loggedMinutes` across a set of tasks without double-counting.\n *\n * Never sum the raw field yourself \u2014 use this, or sum `ownMinutes` instead. Those are\n * the only two ways to total a mixed set correctly.\n */\nexport function sumTaskLoggedMinutes(rows: readonly TaskHoursRow[]): number {\n const presentIds = new Set(rows.map((row) => row.id))\n let total = 0\n for (const row of rows) {\n // The parent's rollup already contains this row's minutes.\n if (row.parentTaskId && presentIds.has(row.parentTaskId)) continue\n total += toMinutes(row.loggedMinutes)\n }\n return total\n}\n"],
5
+ "mappings": "AAqBA,SAAS,UAAU,OAA0C;AAC3D,MAAI,UAAU,QAAQ,UAAU,UAAa,CAAC,OAAO,SAAS,KAAK,EAAG,QAAO;AAC7E,SAAO;AACT;AAQO,SAAS,qBAAqB,MAAuC;AAC1E,QAAM,aAAa,IAAI,IAAI,KAAK,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;AACpD,MAAI,QAAQ;AACZ,aAAW,OAAO,MAAM;AAEtB,QAAI,IAAI,gBAAgB,WAAW,IAAI,IAAI,YAAY,EAAG;AAC1D,aAAS,UAAU,IAAI,aAAa;AAAA,EACtC;AACA,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -0,0 +1,51 @@
1
+ import { isUniqueViolation } from "@open-mercato/shared/lib/crud/errors";
2
+ const TASK_REFERENCE_FALLBACK_CODE = "TASK";
3
+ const FIRST_TASK_SEQUENCE_NUMBER = 1;
4
+ const TASK_REFERENCE_MAX_ATTEMPTS = 5;
5
+ function normalizeProjectCodeForReference(code) {
6
+ const trimmed = typeof code === "string" ? code.trim() : "";
7
+ return trimmed.length > 0 ? trimmed : TASK_REFERENCE_FALLBACK_CODE;
8
+ }
9
+ function nextTaskSequenceNumber(highestSequenceNumber) {
10
+ if (typeof highestSequenceNumber !== "number" || !Number.isFinite(highestSequenceNumber)) {
11
+ return FIRST_TASK_SEQUENCE_NUMBER;
12
+ }
13
+ const next = Math.floor(highestSequenceNumber) + 1;
14
+ return next < FIRST_TASK_SEQUENCE_NUMBER ? FIRST_TASK_SEQUENCE_NUMBER : next;
15
+ }
16
+ function formatTaskReference(code, sequenceNumber) {
17
+ return `${normalizeProjectCodeForReference(code)}-${sequenceNumber}`;
18
+ }
19
+ function allocateTaskReference(code, highestSequenceNumber) {
20
+ const sequenceNumber = nextTaskSequenceNumber(highestSequenceNumber);
21
+ return { sequenceNumber, reference: formatTaskReference(code, sequenceNumber) };
22
+ }
23
+ function isTaskReferenceConflict(err) {
24
+ return isUniqueViolation(err);
25
+ }
26
+ async function withTaskReferenceRetry(runAttempt, options = {}) {
27
+ const maxAttempts = Math.max(1, options.maxAttempts ?? TASK_REFERENCE_MAX_ATTEMPTS);
28
+ const isConflict = options.isConflict ?? isTaskReferenceConflict;
29
+ let lastError = null;
30
+ for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
31
+ try {
32
+ return await runAttempt(attempt);
33
+ } catch (err) {
34
+ if (!isConflict(err)) throw err;
35
+ lastError = err;
36
+ }
37
+ }
38
+ throw lastError;
39
+ }
40
+ export {
41
+ FIRST_TASK_SEQUENCE_NUMBER,
42
+ TASK_REFERENCE_FALLBACK_CODE,
43
+ TASK_REFERENCE_MAX_ATTEMPTS,
44
+ allocateTaskReference,
45
+ formatTaskReference,
46
+ isTaskReferenceConflict,
47
+ nextTaskSequenceNumber,
48
+ normalizeProjectCodeForReference,
49
+ withTaskReferenceRetry
50
+ };
51
+ //# sourceMappingURL=taskReference.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/modules/staff/lib/timesheets-tasks/taskReference.ts"],
4
+ "sourcesContent": ["/**\n * Per-project task numbering \u2014 the `TT-142` on the card, the drawer title and every\n * report line that names a task.\n *\n * The reference is denormalized (`<project.code>-<sequence_number>`) because it is\n * quoted in places the task row is no longer joined: a closed report keeps its line\n * labels after the task is gone, and a client-facing sheet must keep showing the same\n * number it showed last month. Renaming the project's code therefore does not\n * retro-number existing tasks \u2014 the reference is allocated once and frozen.\n *\n * Allocation is the interesting part. Two people creating a task in the same project\n * at the same moment must not both get `TT-142`, and reading `MAX(sequence_number)`\n * up front does not prevent that \u2014 it only narrows the window. The database is the\n * arbiter instead: the partial unique index on\n * `(organization_id, tenant_id, time_project_id, sequence_number) WHERE deleted_at IS NULL`\n * makes the loser's insert fail, and the loser retries the whole transaction, reading\n * a max that now includes the winner's row. A gap left by a rolled-back attempt is\n * cosmetic and deliberately not reclaimed (spec risk R6).\n */\n\nimport { isUniqueViolation } from '@open-mercato/shared/lib/crud/errors'\n\n/** Used when a project somehow has no usable code, so a task can still be numbered. */\nexport const TASK_REFERENCE_FALLBACK_CODE = 'TASK'\n\nexport const FIRST_TASK_SEQUENCE_NUMBER = 1\n\n/**\n * Attempts before the conflict is surfaced to the caller. Each retry costs one\n * aborted transaction, and a project would need this many simultaneous creates\n * landing on the same number for the last one to give up.\n */\nexport const TASK_REFERENCE_MAX_ATTEMPTS = 5\n\nexport type TaskReferenceAllocation = {\n sequenceNumber: number\n reference: string\n}\n\nexport function normalizeProjectCodeForReference(code: string | null | undefined): string {\n const trimmed = typeof code === 'string' ? code.trim() : ''\n return trimmed.length > 0 ? trimmed : TASK_REFERENCE_FALLBACK_CODE\n}\n\nexport function nextTaskSequenceNumber(highestSequenceNumber: number | null | undefined): number {\n if (typeof highestSequenceNumber !== 'number' || !Number.isFinite(highestSequenceNumber)) {\n return FIRST_TASK_SEQUENCE_NUMBER\n }\n const next = Math.floor(highestSequenceNumber) + 1\n return next < FIRST_TASK_SEQUENCE_NUMBER ? FIRST_TASK_SEQUENCE_NUMBER : next\n}\n\nexport function formatTaskReference(code: string | null | undefined, sequenceNumber: number): string {\n return `${normalizeProjectCodeForReference(code)}-${sequenceNumber}`\n}\n\n/**\n * The candidate one attempt writes. It is a plain function of what that attempt read\n * inside its own transaction, so nothing is carried between attempts.\n */\nexport function allocateTaskReference(\n code: string | null | undefined,\n highestSequenceNumber: number | null | undefined,\n): TaskReferenceAllocation {\n const sequenceNumber = nextTaskSequenceNumber(highestSequenceNumber)\n return { sequenceNumber, reference: formatTaskReference(code, sequenceNumber) }\n}\n\n/**\n * A losing race shows up as a unique violation on either of the task's two partial\n * indexes \u2014 the `(project, sequence_number)` pair or the denormalized `reference`.\n * Both mean the same thing here: someone else took this number, take the next one.\n */\nexport function isTaskReferenceConflict(err: unknown): boolean {\n return isUniqueViolation(err)\n}\n\nexport type TaskReferenceRetryOptions = {\n maxAttempts?: number\n isConflict?: (err: unknown) => boolean\n}\n\n/**\n * Runs the create attempt until it wins the number or the budget runs out.\n *\n * `runAttempt` MUST re-read the project's highest sequence number inside its own\n * transaction \u2014 that is the whole point of retrying rather than pre-reading. A\n * non-conflict error is rethrown immediately: only a lost race is worth repeating.\n */\nexport async function withTaskReferenceRetry<T>(\n runAttempt: (attempt: number) => Promise<T>,\n options: TaskReferenceRetryOptions = {},\n): Promise<T> {\n const maxAttempts = Math.max(1, options.maxAttempts ?? TASK_REFERENCE_MAX_ATTEMPTS)\n const isConflict = options.isConflict ?? isTaskReferenceConflict\n let lastError: unknown = null\n\n for (let attempt = 0; attempt < maxAttempts; attempt += 1) {\n try {\n return await runAttempt(attempt)\n } catch (err) {\n if (!isConflict(err)) throw err\n lastError = err\n }\n }\n\n throw lastError\n}\n"],
5
+ "mappings": "AAoBA,SAAS,yBAAyB;AAG3B,MAAM,+BAA+B;AAErC,MAAM,6BAA6B;AAOnC,MAAM,8BAA8B;AAOpC,SAAS,iCAAiC,MAAyC;AACxF,QAAM,UAAU,OAAO,SAAS,WAAW,KAAK,KAAK,IAAI;AACzD,SAAO,QAAQ,SAAS,IAAI,UAAU;AACxC;AAEO,SAAS,uBAAuB,uBAA0D;AAC/F,MAAI,OAAO,0BAA0B,YAAY,CAAC,OAAO,SAAS,qBAAqB,GAAG;AACxF,WAAO;AAAA,EACT;AACA,QAAM,OAAO,KAAK,MAAM,qBAAqB,IAAI;AACjD,SAAO,OAAO,6BAA6B,6BAA6B;AAC1E;AAEO,SAAS,oBAAoB,MAAiC,gBAAgC;AACnG,SAAO,GAAG,iCAAiC,IAAI,CAAC,IAAI,cAAc;AACpE;AAMO,SAAS,sBACd,MACA,uBACyB;AACzB,QAAM,iBAAiB,uBAAuB,qBAAqB;AACnE,SAAO,EAAE,gBAAgB,WAAW,oBAAoB,MAAM,cAAc,EAAE;AAChF;AAOO,SAAS,wBAAwB,KAAuB;AAC7D,SAAO,kBAAkB,GAAG;AAC9B;AAcA,eAAsB,uBACpB,YACA,UAAqC,CAAC,GAC1B;AACZ,QAAM,cAAc,KAAK,IAAI,GAAG,QAAQ,eAAe,2BAA2B;AAClF,QAAM,aAAa,QAAQ,cAAc;AACzC,MAAI,YAAqB;AAEzB,WAAS,UAAU,GAAG,UAAU,aAAa,WAAW,GAAG;AACzD,QAAI;AACF,aAAO,MAAM,WAAW,OAAO;AAAA,IACjC,SAAS,KAAK;AACZ,UAAI,CAAC,WAAW,GAAG,EAAG,OAAM;AAC5B,kBAAY;AAAA,IACd;AAAA,EACF;AAEA,QAAM;AACR;",
6
+ "names": []
7
+ }
@@ -15,13 +15,20 @@ import {
15
15
  createProjectFormFields,
16
16
  createProjectFormGroups,
17
17
  createProjectFormSchema
18
- } from "../../backend/staff/timesheets/projects/projectFormConfig.js";
18
+ } from "../../backend/staff/time-tracking/projects/projectFormConfig.js";
19
19
  function CreateProjectDialog({ open, onOpenChange, onProjectCreated }) {
20
20
  const t = useT();
21
21
  const formSchema = React.useMemo(() => createProjectFormSchema(), []);
22
22
  const fields = React.useMemo(() => createProjectFormFields(t), [t]);
23
- const groups = React.useMemo(() => createProjectFormGroups(t), [t]);
24
- return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-lg", children: [
23
+ const groups = React.useMemo(() => createProjectFormGroups(t, { compact: true }), [t]);
24
+ const handleKeyDown = React.useCallback((event) => {
25
+ if (!((event.metaKey || event.ctrlKey) && event.key === "Enter")) return;
26
+ const form = event.currentTarget.querySelector("form");
27
+ if (!form) return;
28
+ event.preventDefault();
29
+ form.requestSubmit();
30
+ }, []);
31
+ return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-lg", "data-testid": "create-project-dialog", onKeyDown: handleKeyDown, children: [
25
32
  /* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: t("staff.timesheets.projects.form.createTitle", "Create project") }) }),
26
33
  /* @__PURE__ */ jsx(
27
34
  CrudForm,
@@ -30,7 +37,7 @@ function CreateProjectDialog({ open, onOpenChange, onProjectCreated }) {
30
37
  fields,
31
38
  groups,
32
39
  schema: formSchema,
33
- initialValues: {},
40
+ initialValues: { status: "active", billableByDefault: true, codeManual: false },
34
41
  entityIds: [E.staff.staff_time_project],
35
42
  submitLabel: t("staff.timesheets.projects.form.actions.create", "Create"),
36
43
  extraActions: /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", onClick: () => onOpenChange(false), children: t("staff.timesheets.projects.form.actions.cancel", "Cancel") }),
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/staff/lib/timesheets-ui/CreateProjectDialog.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Dialog, DialogContent, DialogHeader, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { CrudForm } from '@open-mercato/ui/backend/CrudForm'\nimport { createCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { E } from '#generated/entities.ids.generated'\nimport {\n buildProjectPayload,\n createProjectFormFields,\n createProjectFormGroups,\n createProjectFormSchema,\n type ProjectFormValues,\n} from '../../backend/staff/timesheets/projects/projectFormConfig'\n\ntype CreateProjectDialogProps = {\n open: boolean\n onOpenChange: (open: boolean) => void\n onProjectCreated: (project: { id: string; name: string; code: string | null }) => void\n}\n\nexport function CreateProjectDialog({ open, onOpenChange, onProjectCreated }: CreateProjectDialogProps) {\n const t = useT()\n\n const formSchema = React.useMemo(() => createProjectFormSchema(), [])\n const fields = React.useMemo(() => createProjectFormFields(t), [t])\n const groups = React.useMemo(() => createProjectFormGroups(t), [t])\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"sm:max-w-lg\">\n <DialogHeader>\n <DialogTitle>\n {t('staff.timesheets.projects.form.createTitle', 'Create project')}\n </DialogTitle>\n </DialogHeader>\n <CrudForm<ProjectFormValues>\n embedded\n fields={fields}\n groups={groups}\n schema={formSchema}\n initialValues={{}}\n entityIds={[E.staff.staff_time_project]}\n submitLabel={t('staff.timesheets.projects.form.actions.create', 'Create')}\n extraActions={(\n <Button type=\"button\" variant=\"ghost\" onClick={() => onOpenChange(false)}>\n {t('staff.timesheets.projects.form.actions.cancel', 'Cancel')}\n </Button>\n )}\n onSubmit={async (values) => {\n const payload = buildProjectPayload(values)\n\n const { result: created } = await createCrud<{ id?: string; name?: string; code?: string | null }>(\n 'staff/timesheets/time-projects',\n payload,\n { errorMessage: t('staff.timesheets.projects.errors.save', 'Failed to save project.') },\n )\n\n const newId = created?.id\n if (!newId) {\n throw createCrudFormError(\n t('staff.timesheets.projects.errors.save', 'Failed to save project.'),\n )\n }\n\n // Auto-assign creator to the project (best-effort)\n try {\n const selfRes = await apiCall<{ member?: { id?: string } | null }>('/api/staff/team-members/self')\n const staffMemberId = selfRes.result?.member?.id\n if (staffMemberId) {\n await createCrud('staff/timesheets/time-projects/' + newId + '/employees', {\n staffMemberId,\n assignedStartDate: new Date().toISOString().slice(0, 10),\n status: 'active',\n }, { errorMessage: '' })\n }\n } catch {\n // non-critical \u2014 project created, self-assignment is best-effort\n }\n\n onProjectCreated({\n id: newId,\n name: created?.name ?? values.name.trim(),\n code: created?.code ?? values.code?.trim() ?? null,\n })\n\n flash(t('staff.timesheets.projects.messages.saved', 'Project saved.'), 'success')\n onOpenChange(false)\n }}\n />\n </DialogContent>\n </Dialog>\n )\n}\n"],
5
- "mappings": ";AAmCM,SAEI,KAFJ;AAjCN,YAAY,WAAW;AACvB,SAAS,QAAQ,eAAe,cAAc,mBAAmB;AACjE,SAAS,cAAc;AACvB,SAAS,gBAAgB;AACzB,SAAS,kBAAkB;AAC3B,SAAS,eAAe;AACxB,SAAS,2BAA2B;AACpC,SAAS,aAAa;AACtB,SAAS,YAAY;AACrB,SAAS,SAAS;AAClB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAQA,SAAS,oBAAoB,EAAE,MAAM,cAAc,iBAAiB,GAA6B;AACtG,QAAM,IAAI,KAAK;AAEf,QAAM,aAAa,MAAM,QAAQ,MAAM,wBAAwB,GAAG,CAAC,CAAC;AACpE,QAAM,SAAS,MAAM,QAAQ,MAAM,wBAAwB,CAAC,GAAG,CAAC,CAAC,CAAC;AAClE,QAAM,SAAS,MAAM,QAAQ,MAAM,wBAAwB,CAAC,GAAG,CAAC,CAAC,CAAC;AAElE,SACE,oBAAC,UAAO,MAAY,cAClB,+BAAC,iBAAc,WAAU,eACvB;AAAA,wBAAC,gBACC,8BAAC,eACE,YAAE,8CAA8C,gBAAgB,GACnE,GACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,UAAQ;AAAA,QACR;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,QACR,eAAe,CAAC;AAAA,QAChB,WAAW,CAAC,EAAE,MAAM,kBAAkB;AAAA,QACtC,aAAa,EAAE,iDAAiD,QAAQ;AAAA,QACxE,cACE,oBAAC,UAAO,MAAK,UAAS,SAAQ,SAAQ,SAAS,MAAM,aAAa,KAAK,GACpE,YAAE,iDAAiD,QAAQ,GAC9D;AAAA,QAEF,UAAU,OAAO,WAAW;AAC1B,gBAAM,UAAU,oBAAoB,MAAM;AAE1C,gBAAM,EAAE,QAAQ,QAAQ,IAAI,MAAM;AAAA,YAChC;AAAA,YACA;AAAA,YACA,EAAE,cAAc,EAAE,yCAAyC,yBAAyB,EAAE;AAAA,UACxF;AAEA,gBAAM,QAAQ,SAAS;AACvB,cAAI,CAAC,OAAO;AACV,kBAAM;AAAA,cACJ,EAAE,yCAAyC,yBAAyB;AAAA,YACtE;AAAA,UACF;AAGA,cAAI;AACF,kBAAM,UAAU,MAAM,QAA6C,8BAA8B;AACjG,kBAAM,gBAAgB,QAAQ,QAAQ,QAAQ;AAC9C,gBAAI,eAAe;AACjB,oBAAM,WAAW,oCAAoC,QAAQ,cAAc;AAAA,gBACzE;AAAA,gBACA,oBAAmB,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE;AAAA,gBACvD,QAAQ;AAAA,cACV,GAAG,EAAE,cAAc,GAAG,CAAC;AAAA,YACzB;AAAA,UACF,QAAQ;AAAA,UAER;AAEA,2BAAiB;AAAA,YACf,IAAI;AAAA,YACJ,MAAM,SAAS,QAAQ,OAAO,KAAK,KAAK;AAAA,YACxC,MAAM,SAAS,QAAQ,OAAO,MAAM,KAAK,KAAK;AAAA,UAChD,CAAC;AAED,gBAAM,EAAE,4CAA4C,gBAAgB,GAAG,SAAS;AAChF,uBAAa,KAAK;AAAA,QACpB;AAAA;AAAA,IACF;AAAA,KACF,GACF;AAEJ;",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Dialog, DialogContent, DialogHeader, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { CrudForm } from '@open-mercato/ui/backend/CrudForm'\nimport { createCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { E } from '#generated/entities.ids.generated'\nimport {\n buildProjectPayload,\n createProjectFormFields,\n createProjectFormGroups,\n createProjectFormSchema,\n type ProjectFormValues,\n} from '../../backend/staff/time-tracking/projects/projectFormConfig'\n\ntype CreateProjectDialogProps = {\n open: boolean\n onOpenChange: (open: boolean) => void\n onProjectCreated: (project: { id: string; name: string; code: string | null }) => void\n}\n\nexport function CreateProjectDialog({ open, onOpenChange, onProjectCreated }: CreateProjectDialogProps) {\n const t = useT()\n\n const formSchema = React.useMemo(() => createProjectFormSchema(), [])\n const fields = React.useMemo(() => createProjectFormFields(t), [t])\n const groups = React.useMemo(() => createProjectFormGroups(t, { compact: true }), [t])\n\n /**\n * `CrudForm` bails out of its own Enter-to-submit handling as soon as a\n * modifier is held, so the shortcut every other dialog in this feature offers\n * has to be wired here \u2014 on the dialog, submitting the embedded form directly.\n * Escape stays with Radix's dismissable layer, which this never intercepts.\n */\n const handleKeyDown = React.useCallback((event: React.KeyboardEvent<HTMLDivElement>) => {\n if (!((event.metaKey || event.ctrlKey) && event.key === 'Enter')) return\n const form = event.currentTarget.querySelector('form')\n if (!form) return\n event.preventDefault()\n form.requestSubmit()\n }, [])\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"sm:max-w-lg\" data-testid=\"create-project-dialog\" onKeyDown={handleKeyDown}>\n <DialogHeader>\n <DialogTitle>\n {t('staff.timesheets.projects.form.createTitle', 'Create project')}\n </DialogTitle>\n </DialogHeader>\n <CrudForm<ProjectFormValues>\n embedded\n fields={fields}\n groups={groups}\n schema={formSchema}\n initialValues={{ status: 'active', billableByDefault: true, codeManual: false }}\n entityIds={[E.staff.staff_time_project]}\n submitLabel={t('staff.timesheets.projects.form.actions.create', 'Create')}\n extraActions={(\n <Button type=\"button\" variant=\"ghost\" onClick={() => onOpenChange(false)}>\n {t('staff.timesheets.projects.form.actions.cancel', 'Cancel')}\n </Button>\n )}\n onSubmit={async (values) => {\n const payload = buildProjectPayload(values)\n\n const { result: created } = await createCrud<{ id?: string; name?: string; code?: string | null }>(\n 'staff/timesheets/time-projects',\n payload,\n { errorMessage: t('staff.timesheets.projects.errors.save', 'Failed to save project.') },\n )\n\n const newId = created?.id\n if (!newId) {\n throw createCrudFormError(\n t('staff.timesheets.projects.errors.save', 'Failed to save project.'),\n )\n }\n\n // Auto-assign creator to the project (best-effort)\n try {\n const selfRes = await apiCall<{ member?: { id?: string } | null }>('/api/staff/team-members/self')\n const staffMemberId = selfRes.result?.member?.id\n if (staffMemberId) {\n await createCrud('staff/timesheets/time-projects/' + newId + '/employees', {\n staffMemberId,\n assignedStartDate: new Date().toISOString().slice(0, 10),\n status: 'active',\n }, { errorMessage: '' })\n }\n } catch {\n // non-critical \u2014 project created, self-assignment is best-effort\n }\n\n onProjectCreated({\n id: newId,\n name: created?.name ?? values.name.trim(),\n code: created?.code ?? values.code?.trim() ?? null,\n })\n\n flash(t('staff.timesheets.projects.messages.saved', 'Project saved.'), 'success')\n onOpenChange(false)\n }}\n />\n </DialogContent>\n </Dialog>\n )\n}\n"],
5
+ "mappings": ";AAiDM,SAEI,KAFJ;AA/CN,YAAY,WAAW;AACvB,SAAS,QAAQ,eAAe,cAAc,mBAAmB;AACjE,SAAS,cAAc;AACvB,SAAS,gBAAgB;AACzB,SAAS,kBAAkB;AAC3B,SAAS,eAAe;AACxB,SAAS,2BAA2B;AACpC,SAAS,aAAa;AACtB,SAAS,YAAY;AACrB,SAAS,SAAS;AAClB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAQA,SAAS,oBAAoB,EAAE,MAAM,cAAc,iBAAiB,GAA6B;AACtG,QAAM,IAAI,KAAK;AAEf,QAAM,aAAa,MAAM,QAAQ,MAAM,wBAAwB,GAAG,CAAC,CAAC;AACpE,QAAM,SAAS,MAAM,QAAQ,MAAM,wBAAwB,CAAC,GAAG,CAAC,CAAC,CAAC;AAClE,QAAM,SAAS,MAAM,QAAQ,MAAM,wBAAwB,GAAG,EAAE,SAAS,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;AAQrF,QAAM,gBAAgB,MAAM,YAAY,CAAC,UAA+C;AACtF,QAAI,GAAG,MAAM,WAAW,MAAM,YAAY,MAAM,QAAQ,SAAU;AAClE,UAAM,OAAO,MAAM,cAAc,cAAc,MAAM;AACrD,QAAI,CAAC,KAAM;AACX,UAAM,eAAe;AACrB,SAAK,cAAc;AAAA,EACrB,GAAG,CAAC,CAAC;AAEL,SACE,oBAAC,UAAO,MAAY,cAClB,+BAAC,iBAAc,WAAU,eAAc,eAAY,yBAAwB,WAAW,eACpF;AAAA,wBAAC,gBACC,8BAAC,eACE,YAAE,8CAA8C,gBAAgB,GACnE,GACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,UAAQ;AAAA,QACR;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,QACR,eAAe,EAAE,QAAQ,UAAU,mBAAmB,MAAM,YAAY,MAAM;AAAA,QAC9E,WAAW,CAAC,EAAE,MAAM,kBAAkB;AAAA,QACtC,aAAa,EAAE,iDAAiD,QAAQ;AAAA,QACxE,cACE,oBAAC,UAAO,MAAK,UAAS,SAAQ,SAAQ,SAAS,MAAM,aAAa,KAAK,GACpE,YAAE,iDAAiD,QAAQ,GAC9D;AAAA,QAEF,UAAU,OAAO,WAAW;AAC1B,gBAAM,UAAU,oBAAoB,MAAM;AAE1C,gBAAM,EAAE,QAAQ,QAAQ,IAAI,MAAM;AAAA,YAChC;AAAA,YACA;AAAA,YACA,EAAE,cAAc,EAAE,yCAAyC,yBAAyB,EAAE;AAAA,UACxF;AAEA,gBAAM,QAAQ,SAAS;AACvB,cAAI,CAAC,OAAO;AACV,kBAAM;AAAA,cACJ,EAAE,yCAAyC,yBAAyB;AAAA,YACtE;AAAA,UACF;AAGA,cAAI;AACF,kBAAM,UAAU,MAAM,QAA6C,8BAA8B;AACjG,kBAAM,gBAAgB,QAAQ,QAAQ,QAAQ;AAC9C,gBAAI,eAAe;AACjB,oBAAM,WAAW,oCAAoC,QAAQ,cAAc;AAAA,gBACzE;AAAA,gBACA,oBAAmB,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE;AAAA,gBACvD,QAAQ;AAAA,cACV,GAAG,EAAE,cAAc,GAAG,CAAC;AAAA,YACzB;AAAA,UACF,QAAQ;AAAA,UAER;AAEA,2BAAiB;AAAA,YACf,IAAI;AAAA,YACJ,MAAM,SAAS,QAAQ,OAAO,KAAK,KAAK;AAAA,YACxC,MAAM,SAAS,QAAQ,OAAO,MAAM,KAAK,KAAK;AAAA,UAChD,CAAC;AAED,gBAAM,EAAE,4CAA4C,gBAAgB,GAAG,SAAS;AAChF,uBAAa,KAAK;AAAA,QACpB;AAAA;AAAA,IACF;AAAA,KACF,GACF;AAEJ;",
6
6
  "names": []
7
7
  }