@hed-hog/operations 0.0.329 → 0.0.331

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 (290) hide show
  1. package/README.md +5 -5
  2. package/dist/controllers/operations-collaborators.controller.d.ts +7 -216
  3. package/dist/controllers/operations-collaborators.controller.d.ts.map +1 -1
  4. package/dist/controllers/operations-contracts.controller.d.ts +6 -6
  5. package/dist/controllers/operations-projects.controller.d.ts +25 -0
  6. package/dist/controllers/operations-projects.controller.d.ts.map +1 -1
  7. package/dist/controllers/operations-projects.controller.js +48 -0
  8. package/dist/controllers/operations-projects.controller.js.map +1 -1
  9. package/dist/controllers/operations-reports.controller.d.ts +1 -1
  10. package/dist/controllers/operations-tasks.controller.d.ts +30 -5
  11. package/dist/controllers/operations-tasks.controller.d.ts.map +1 -1
  12. package/dist/controllers/operations-tasks.controller.js +43 -32
  13. package/dist/controllers/operations-tasks.controller.js.map +1 -1
  14. package/dist/controllers/operations-timesheets.controller.d.ts +9 -9
  15. package/dist/dashboard/components/DashboardLayout.d.ts +30 -0
  16. package/dist/dashboard/components/DashboardLayout.d.ts.map +1 -0
  17. package/dist/dashboard/components/DashboardLayout.js +87 -0
  18. package/dist/dashboard/components/DashboardLayout.js.map +1 -0
  19. package/dist/dashboard/components/widget-registry.d.ts +23 -0
  20. package/dist/dashboard/components/widget-registry.d.ts.map +1 -0
  21. package/dist/dashboard/components/widget-registry.js +245 -0
  22. package/dist/dashboard/components/widget-registry.js.map +1 -0
  23. package/dist/dashboard/hooks/useDashboardData.d.ts +20 -0
  24. package/dist/dashboard/hooks/useDashboardData.d.ts.map +1 -0
  25. package/dist/dashboard/hooks/useDashboardData.js +24 -0
  26. package/dist/dashboard/hooks/useDashboardData.js.map +1 -0
  27. package/dist/dashboard/types/widgets.types.d.ts +233 -0
  28. package/dist/dashboard/types/widgets.types.d.ts.map +1 -0
  29. package/dist/dashboard/types/widgets.types.js +6 -0
  30. package/dist/dashboard/types/widgets.types.js.map +1 -0
  31. package/dist/dashboard/widgets/CapacityDistribution.d.ts +23 -0
  32. package/dist/dashboard/widgets/CapacityDistribution.d.ts.map +1 -0
  33. package/dist/dashboard/widgets/CapacityDistribution.js +11 -0
  34. package/dist/dashboard/widgets/CapacityDistribution.js.map +1 -0
  35. package/dist/dashboard/widgets/EffortByProject.d.ts +22 -0
  36. package/dist/dashboard/widgets/EffortByProject.d.ts.map +1 -0
  37. package/dist/dashboard/widgets/EffortByProject.js +11 -0
  38. package/dist/dashboard/widgets/EffortByProject.js.map +1 -0
  39. package/dist/dashboard/widgets/HeadcountByArea.d.ts +24 -0
  40. package/dist/dashboard/widgets/HeadcountByArea.d.ts.map +1 -0
  41. package/dist/dashboard/widgets/HeadcountByArea.js +11 -0
  42. package/dist/dashboard/widgets/HeadcountByArea.js.map +1 -0
  43. package/dist/dashboard/widgets/ManagedProjectsStatus.d.ts +18 -0
  44. package/dist/dashboard/widgets/ManagedProjectsStatus.d.ts.map +1 -0
  45. package/dist/dashboard/widgets/ManagedProjectsStatus.js +12 -0
  46. package/dist/dashboard/widgets/ManagedProjectsStatus.js.map +1 -0
  47. package/dist/dashboard/widgets/MyHoursPeriodKpi.d.ts +22 -0
  48. package/dist/dashboard/widgets/MyHoursPeriodKpi.d.ts.map +1 -0
  49. package/dist/dashboard/widgets/MyHoursPeriodKpi.js +12 -0
  50. package/dist/dashboard/widgets/MyHoursPeriodKpi.js.map +1 -0
  51. package/dist/dashboard/widgets/MyOpenRequestsKpi.d.ts +19 -0
  52. package/dist/dashboard/widgets/MyOpenRequestsKpi.d.ts.map +1 -0
  53. package/dist/dashboard/widgets/MyOpenRequestsKpi.js +17 -0
  54. package/dist/dashboard/widgets/MyOpenRequestsKpi.js.map +1 -0
  55. package/dist/dashboard/widgets/MyPendingRequestsList.d.ts +23 -0
  56. package/dist/dashboard/widgets/MyPendingRequestsList.d.ts.map +1 -0
  57. package/dist/dashboard/widgets/MyPendingRequestsList.js +14 -0
  58. package/dist/dashboard/widgets/MyPendingRequestsList.js.map +1 -0
  59. package/dist/dashboard/widgets/MyProjectAllocationsKpi.d.ts +22 -0
  60. package/dist/dashboard/widgets/MyProjectAllocationsKpi.d.ts.map +1 -0
  61. package/dist/dashboard/widgets/MyProjectAllocationsKpi.js +11 -0
  62. package/dist/dashboard/widgets/MyProjectAllocationsKpi.js.map +1 -0
  63. package/dist/dashboard/widgets/MyQuickActions.d.ts +23 -0
  64. package/dist/dashboard/widgets/MyQuickActions.d.ts.map +1 -0
  65. package/dist/dashboard/widgets/MyQuickActions.js +18 -0
  66. package/dist/dashboard/widgets/MyQuickActions.js.map +1 -0
  67. package/dist/dashboard/widgets/MyRelevantDeadlines.d.ts +23 -0
  68. package/dist/dashboard/widgets/MyRelevantDeadlines.d.ts.map +1 -0
  69. package/dist/dashboard/widgets/MyRelevantDeadlines.js +22 -0
  70. package/dist/dashboard/widgets/MyRelevantDeadlines.js.map +1 -0
  71. package/dist/dashboard/widgets/MyTimesheetStatusKpi.d.ts +17 -0
  72. package/dist/dashboard/widgets/MyTimesheetStatusKpi.d.ts.map +1 -0
  73. package/dist/dashboard/widgets/MyTimesheetStatusKpi.js +11 -0
  74. package/dist/dashboard/widgets/MyTimesheetStatusKpi.js.map +1 -0
  75. package/dist/dashboard/widgets/MyWeeklyJourney.d.ts +21 -0
  76. package/dist/dashboard/widgets/MyWeeklyJourney.d.ts.map +1 -0
  77. package/dist/dashboard/widgets/MyWeeklyJourney.js +19 -0
  78. package/dist/dashboard/widgets/MyWeeklyJourney.js.map +1 -0
  79. package/dist/dashboard/widgets/PortfolioCostsKpi.d.ts +19 -0
  80. package/dist/dashboard/widgets/PortfolioCostsKpi.d.ts.map +1 -0
  81. package/dist/dashboard/widgets/PortfolioCostsKpi.js +12 -0
  82. package/dist/dashboard/widgets/PortfolioCostsKpi.js.map +1 -0
  83. package/dist/dashboard/widgets/PortfolioEffortKpi.d.ts +18 -0
  84. package/dist/dashboard/widgets/PortfolioEffortKpi.d.ts.map +1 -0
  85. package/dist/dashboard/widgets/PortfolioEffortKpi.js +8 -0
  86. package/dist/dashboard/widgets/PortfolioEffortKpi.js.map +1 -0
  87. package/dist/dashboard/widgets/PortfolioProjectsKpi.d.ts +22 -0
  88. package/dist/dashboard/widgets/PortfolioProjectsKpi.d.ts.map +1 -0
  89. package/dist/dashboard/widgets/PortfolioProjectsKpi.js +56 -0
  90. package/dist/dashboard/widgets/PortfolioProjectsKpi.js.map +1 -0
  91. package/dist/dashboard/widgets/PortfolioRiskKpi.d.ts +19 -0
  92. package/dist/dashboard/widgets/PortfolioRiskKpi.d.ts.map +1 -0
  93. package/dist/dashboard/widgets/PortfolioRiskKpi.js +11 -0
  94. package/dist/dashboard/widgets/PortfolioRiskKpi.js.map +1 -0
  95. package/dist/dashboard/widgets/ProjectStatusOverview.d.ts +19 -0
  96. package/dist/dashboard/widgets/ProjectStatusOverview.d.ts.map +1 -0
  97. package/dist/dashboard/widgets/ProjectStatusOverview.js +18 -0
  98. package/dist/dashboard/widgets/ProjectStatusOverview.js.map +1 -0
  99. package/dist/dashboard/widgets/StrategicDeadlines.d.ts +24 -0
  100. package/dist/dashboard/widgets/StrategicDeadlines.d.ts.map +1 -0
  101. package/dist/dashboard/widgets/StrategicDeadlines.js +22 -0
  102. package/dist/dashboard/widgets/StrategicDeadlines.js.map +1 -0
  103. package/dist/dashboard/widgets/TeamApprovalQueue.d.ts +24 -0
  104. package/dist/dashboard/widgets/TeamApprovalQueue.d.ts.map +1 -0
  105. package/dist/dashboard/widgets/TeamApprovalQueue.js +12 -0
  106. package/dist/dashboard/widgets/TeamApprovalQueue.js.map +1 -0
  107. package/dist/dashboard/widgets/TeamCapacityKpi.d.ts +18 -0
  108. package/dist/dashboard/widgets/TeamCapacityKpi.d.ts.map +1 -0
  109. package/dist/dashboard/widgets/TeamCapacityKpi.js +19 -0
  110. package/dist/dashboard/widgets/TeamCapacityKpi.js.map +1 -0
  111. package/dist/dashboard/widgets/TeamHeadcountKpi.d.ts +22 -0
  112. package/dist/dashboard/widgets/TeamHeadcountKpi.d.ts.map +1 -0
  113. package/dist/dashboard/widgets/TeamHeadcountKpi.js +56 -0
  114. package/dist/dashboard/widgets/TeamHeadcountKpi.js.map +1 -0
  115. package/dist/dashboard/widgets/TeamHoursKpi.d.ts +19 -0
  116. package/dist/dashboard/widgets/TeamHoursKpi.d.ts.map +1 -0
  117. package/dist/dashboard/widgets/TeamHoursKpi.js +13 -0
  118. package/dist/dashboard/widgets/TeamHoursKpi.js.map +1 -0
  119. package/dist/dashboard/widgets/TeamPendingApprovalsKpi.d.ts +20 -0
  120. package/dist/dashboard/widgets/TeamPendingApprovalsKpi.d.ts.map +1 -0
  121. package/dist/dashboard/widgets/TeamPendingApprovalsKpi.js +11 -0
  122. package/dist/dashboard/widgets/TeamPendingApprovalsKpi.js.map +1 -0
  123. package/dist/dashboard/widgets/TeamUtilizationOverview.d.ts +18 -0
  124. package/dist/dashboard/widgets/TeamUtilizationOverview.d.ts.map +1 -0
  125. package/dist/dashboard/widgets/TeamUtilizationOverview.js +17 -0
  126. package/dist/dashboard/widgets/TeamUtilizationOverview.js.map +1 -0
  127. package/dist/dashboard/widgets/TeamWorkloadAlerts.d.ts +24 -0
  128. package/dist/dashboard/widgets/TeamWorkloadAlerts.d.ts.map +1 -0
  129. package/dist/dashboard/widgets/TeamWorkloadAlerts.js +19 -0
  130. package/dist/dashboard/widgets/TeamWorkloadAlerts.js.map +1 -0
  131. package/dist/dashboard/widgets/index.d.ts +24 -0
  132. package/dist/dashboard/widgets/index.d.ts.map +1 -0
  133. package/dist/dashboard/widgets/index.js +54 -0
  134. package/dist/dashboard/widgets/index.js.map +1 -0
  135. package/dist/dto/create-collaborator.dto.d.ts +0 -1
  136. package/dist/dto/create-collaborator.dto.d.ts.map +1 -1
  137. package/dist/dto/create-collaborator.dto.js +0 -6
  138. package/dist/dto/create-collaborator.dto.js.map +1 -1
  139. package/dist/index.d.ts +2 -0
  140. package/dist/index.d.ts.map +1 -1
  141. package/dist/index.js +2 -0
  142. package/dist/index.js.map +1 -1
  143. package/dist/operations.controller.d.ts +42 -0
  144. package/dist/operations.controller.d.ts.map +1 -1
  145. package/dist/operations.service.d.ts +178 -264
  146. package/dist/operations.service.d.ts.map +1 -1
  147. package/dist/operations.service.js +2170 -1340
  148. package/dist/operations.service.js.map +1 -1
  149. package/dist/operations.service.spec.js +345 -174
  150. package/dist/operations.service.spec.js.map +1 -1
  151. package/hedhog/data/dashboard_component.yaml +66 -0
  152. package/hedhog/data/dashboard_component_role.yaml +8 -8
  153. package/hedhog/data/dashboard_item.yaml +25 -25
  154. package/hedhog/data/dashboard_role.yaml +1 -1
  155. package/hedhog/data/menu.yaml +6 -16
  156. package/hedhog/data/role.yaml +1 -1
  157. package/hedhog/data/route.yaml +116 -55
  158. package/hedhog/frontend/app/_components/async-options-combobox.tsx.ejs +15 -9
  159. package/hedhog/frontend/app/_components/collaborator-form-screen.tsx.ejs +39 -99
  160. package/hedhog/frontend/app/_components/collaborator-picker.tsx.ejs +158 -0
  161. package/hedhog/frontend/app/_components/my-project-summary-screen.tsx.ejs +314 -116
  162. package/hedhog/frontend/app/_components/project-assignments-tab.tsx.ejs +434 -449
  163. package/hedhog/frontend/app/_components/project-costs-section.tsx.ejs +51 -81
  164. package/hedhog/frontend/app/_components/project-details-screen.tsx.ejs +328 -423
  165. package/hedhog/frontend/app/_components/project-file-attachments.tsx.ejs +371 -0
  166. package/hedhog/frontend/app/_components/project-form-screen.tsx.ejs +446 -377
  167. package/hedhog/frontend/app/_components/task-detail-sheet.tsx.ejs +803 -581
  168. package/hedhog/frontend/app/_components/task-file-attachments.tsx.ejs +14 -9
  169. package/hedhog/frontend/app/_components/task-form-fields.tsx.ejs +406 -0
  170. package/hedhog/frontend/app/_components/task-form-sheet.tsx.ejs +629 -784
  171. package/hedhog/frontend/app/_components/task-info-display.tsx.ejs +137 -0
  172. package/hedhog/frontend/app/_components/timesheet-entry-create-sheet.tsx.ejs +306 -0
  173. package/hedhog/frontend/app/_lib/api.ts.ejs +480 -476
  174. package/hedhog/frontend/app/_lib/hooks/use-values-visibility.ts.ejs +61 -0
  175. package/hedhog/frontend/app/_lib/types.ts.ejs +66 -5
  176. package/hedhog/frontend/app/_lib/utils/format.ts.ejs +0 -2
  177. package/hedhog/frontend/app/_lib/utils/task-ui.ts.ejs +43 -0
  178. package/hedhog/frontend/app/approvals/page.tsx.ejs +11 -2
  179. package/hedhog/frontend/app/collaborator-types/page.tsx.ejs +6 -1
  180. package/hedhog/frontend/app/collaborators/page.tsx.ejs +127 -42
  181. package/hedhog/frontend/app/contracts/page.tsx.ejs +29 -8
  182. package/hedhog/frontend/app/dashboard/widgets/CapacityDistribution.tsx.ejs +84 -0
  183. package/hedhog/frontend/app/dashboard/widgets/EffortByProject.tsx.ejs +85 -0
  184. package/hedhog/frontend/app/dashboard/widgets/HeadcountByArea.tsx.ejs +101 -0
  185. package/hedhog/frontend/app/dashboard/widgets/ManagedProjectsStatus.tsx.ejs +113 -0
  186. package/hedhog/frontend/app/dashboard/widgets/MyHoursPeriodKpi.tsx.ejs +87 -0
  187. package/hedhog/frontend/app/dashboard/widgets/MyOpenRequestsKpi.tsx.ejs +97 -0
  188. package/hedhog/frontend/app/dashboard/widgets/MyPendingRequestsList.tsx.ejs +99 -0
  189. package/hedhog/frontend/app/dashboard/widgets/MyProjectAllocationsKpi.tsx.ejs +78 -0
  190. package/hedhog/frontend/app/dashboard/widgets/MyQuickActions.tsx.ejs +130 -0
  191. package/hedhog/frontend/app/dashboard/widgets/MyRelevantDeadlines.tsx.ejs +144 -0
  192. package/hedhog/frontend/app/dashboard/widgets/MyTimesheetStatusKpi.tsx.ejs +78 -0
  193. package/hedhog/frontend/app/dashboard/widgets/MyWeeklyJourney.tsx.ejs +99 -0
  194. package/hedhog/frontend/app/dashboard/widgets/PortfolioCostsKpi.tsx.ejs +112 -0
  195. package/hedhog/frontend/app/dashboard/widgets/PortfolioEffortKpi.tsx.ejs +93 -0
  196. package/hedhog/frontend/app/dashboard/widgets/PortfolioProjectsKpi.tsx.ejs +96 -0
  197. package/hedhog/frontend/app/dashboard/widgets/PortfolioRiskKpi.tsx.ejs +115 -0
  198. package/hedhog/frontend/app/dashboard/widgets/ProjectStatusOverview.tsx.ejs +120 -0
  199. package/hedhog/frontend/app/dashboard/widgets/StrategicDeadlines.tsx.ejs +146 -0
  200. package/hedhog/frontend/app/dashboard/widgets/TeamApprovalQueue.tsx.ejs +108 -0
  201. package/hedhog/frontend/app/dashboard/widgets/TeamCapacityKpi.tsx.ejs +97 -0
  202. package/hedhog/frontend/app/dashboard/widgets/TeamHeadcountKpi.tsx.ejs +100 -0
  203. package/hedhog/frontend/app/dashboard/widgets/TeamHoursKpi.tsx.ejs +104 -0
  204. package/hedhog/frontend/app/dashboard/widgets/TeamPendingApprovalsKpi.tsx.ejs +110 -0
  205. package/hedhog/frontend/app/dashboard/widgets/TeamUtilizationOverview.tsx.ejs +115 -0
  206. package/hedhog/frontend/app/dashboard/widgets/TeamWorkloadAlerts.tsx.ejs +117 -0
  207. package/hedhog/frontend/app/dashboard/widgets/index.ts.ejs +26 -0
  208. package/hedhog/frontend/app/departments/page.tsx.ejs +6 -1
  209. package/hedhog/frontend/app/my-projects/page.tsx.ejs +59 -16
  210. package/hedhog/frontend/app/my-tasks/page.tsx.ejs +329 -106
  211. package/hedhog/frontend/app/project-cost-categories/page.tsx.ejs +58 -52
  212. package/hedhog/frontend/app/project-cost-types/page.tsx.ejs +58 -51
  213. package/hedhog/frontend/app/projects/page.tsx.ejs +436 -35
  214. package/hedhog/frontend/app/reports/collaborators/page.tsx.ejs +65 -52
  215. package/hedhog/frontend/app/reports/projects/page.tsx.ejs +80 -82
  216. package/hedhog/frontend/app/schedule-adjustments/page.tsx.ejs +13 -2
  217. package/hedhog/frontend/app/time-off/page.tsx.ejs +6 -1
  218. package/hedhog/frontend/app/timesheets/page.tsx.ejs +10 -4
  219. package/hedhog/frontend/messages/en.json +460 -61
  220. package/hedhog/frontend/messages/operations/en.json +61 -52
  221. package/hedhog/frontend/messages/operations/pt.json +59 -43
  222. package/hedhog/frontend/messages/pt.json +460 -61
  223. package/hedhog/frontend/widgets/capacity-distribution.tsx.ejs +17 -0
  224. package/hedhog/frontend/widgets/effort-by-project.tsx.ejs +17 -0
  225. package/hedhog/frontend/widgets/headcount-by-area.tsx.ejs +17 -0
  226. package/hedhog/frontend/widgets/index.ts.ejs +25 -0
  227. package/hedhog/frontend/widgets/managed-projects-status.tsx.ejs +17 -0
  228. package/hedhog/frontend/widgets/my-hours-period-kpi.tsx.ejs +17 -0
  229. package/hedhog/frontend/widgets/my-open-requests-kpi.tsx.ejs +17 -0
  230. package/hedhog/frontend/widgets/my-pending-requests-list.tsx.ejs +17 -0
  231. package/hedhog/frontend/widgets/my-project-allocations-kpi.tsx.ejs +17 -0
  232. package/hedhog/frontend/widgets/my-quick-actions.tsx.ejs +17 -0
  233. package/hedhog/frontend/widgets/my-relevant-deadlines.tsx.ejs +17 -0
  234. package/hedhog/frontend/widgets/my-timesheet-status-kpi.tsx.ejs +17 -0
  235. package/hedhog/frontend/widgets/my-weekly-journey.tsx.ejs +17 -0
  236. package/hedhog/frontend/widgets/portfolio-costs-kpi.tsx.ejs +17 -0
  237. package/hedhog/frontend/widgets/portfolio-effort-kpi.tsx.ejs +17 -0
  238. package/hedhog/frontend/widgets/portfolio-projects-kpi.tsx.ejs +17 -0
  239. package/hedhog/frontend/widgets/portfolio-risk-kpi.tsx.ejs +17 -0
  240. package/hedhog/frontend/widgets/project-status-overview.tsx.ejs +17 -0
  241. package/hedhog/frontend/widgets/shared-operations-widget.tsx.ejs +170 -0
  242. package/hedhog/frontend/widgets/strategic-deadlines.tsx.ejs +17 -0
  243. package/hedhog/frontend/widgets/team-approval-queue.tsx.ejs +17 -0
  244. package/hedhog/frontend/widgets/team-capacity-kpi.tsx.ejs +17 -0
  245. package/hedhog/frontend/widgets/team-headcount-kpi.tsx.ejs +17 -0
  246. package/hedhog/frontend/widgets/team-hours-kpi.tsx.ejs +17 -0
  247. package/hedhog/frontend/widgets/team-pending-approvals-kpi.tsx.ejs +17 -0
  248. package/hedhog/frontend/widgets/team-utilization-overview.tsx.ejs +17 -0
  249. package/hedhog/frontend/widgets/team-workload-alerts.tsx.ejs +17 -0
  250. package/hedhog/table/operations_collaborator.yaml +8 -13
  251. package/hedhog/table/operations_project.yaml +1 -1
  252. package/hedhog/table/operations_project_file.yaml +23 -0
  253. package/hedhog/table/operations_task.yaml +76 -69
  254. package/hedhog/table/operations_task_activity.yaml +51 -0
  255. package/package.json +7 -6
  256. package/src/controllers/operations-projects.controller.ts +41 -8
  257. package/src/controllers/operations-tasks.controller.ts +156 -166
  258. package/src/dashboard/README.md +214 -0
  259. package/src/dashboard/components/DashboardLayout.tsx +131 -0
  260. package/src/dashboard/components/widget-registry.ts +255 -0
  261. package/src/dashboard/hooks/useDashboardData.ts +29 -0
  262. package/src/dashboard/types/widgets.types.ts +237 -0
  263. package/src/dashboard/widgets/CapacityDistribution.tsx +56 -0
  264. package/src/dashboard/widgets/EffortByProject.tsx +51 -0
  265. package/src/dashboard/widgets/HeadcountByArea.tsx +57 -0
  266. package/src/dashboard/widgets/ManagedProjectsStatus.tsx +53 -0
  267. package/src/dashboard/widgets/MyHoursPeriodKpi.tsx +87 -0
  268. package/src/dashboard/widgets/MyOpenRequestsKpi.tsx +51 -0
  269. package/src/dashboard/widgets/MyPendingRequestsList.tsx +63 -0
  270. package/src/dashboard/widgets/MyProjectAllocationsKpi.tsx +57 -0
  271. package/src/dashboard/widgets/MyQuickActions.tsx +62 -0
  272. package/src/dashboard/widgets/MyRelevantDeadlines.tsx +84 -0
  273. package/src/dashboard/widgets/MyTimesheetStatusKpi.tsx +65 -0
  274. package/src/dashboard/widgets/MyWeeklyJourney.tsx +57 -0
  275. package/src/dashboard/widgets/PortfolioCostsKpi.tsx +48 -0
  276. package/src/dashboard/widgets/PortfolioEffortKpi.tsx +41 -0
  277. package/src/dashboard/widgets/PortfolioRiskKpi.tsx +50 -0
  278. package/src/dashboard/widgets/ProjectStatusOverview.tsx +52 -0
  279. package/src/dashboard/widgets/StrategicDeadlines.tsx +93 -0
  280. package/src/dashboard/widgets/TeamApprovalQueue.tsx +70 -0
  281. package/src/dashboard/widgets/TeamCapacityKpi.tsx +50 -0
  282. package/src/dashboard/widgets/TeamHoursKpi.tsx +51 -0
  283. package/src/dashboard/widgets/TeamPendingApprovalsKpi.tsx +53 -0
  284. package/src/dashboard/widgets/TeamUtilizationOverview.tsx +62 -0
  285. package/src/dashboard/widgets/TeamWorkloadAlerts.tsx +81 -0
  286. package/src/dashboard/widgets/index.ts +26 -0
  287. package/src/dto/create-collaborator.dto.ts +4 -11
  288. package/src/index.ts +3 -0
  289. package/src/operations.service.spec.ts +988 -764
  290. package/src/operations.service.ts +4300 -2538
@@ -6,52 +6,55 @@ import {
6
6
  PaginationFooter,
7
7
  SearchBar,
8
8
  } from '@/components/entity-list';
9
- import { RichTextEditor } from '@/components/rich-text-editor';
10
9
  import { Button } from '@/components/ui/button';
11
10
  import { Card, CardContent } from '@/components/ui/card';
12
- import {
13
- Dialog,
14
- DialogContent,
11
+ import {
12
+ Dialog,
13
+ DialogContent,
14
+ DialogDescription,
15
15
  DialogFooter,
16
16
  DialogHeader,
17
- DialogTitle,
18
- } from '@/components/ui/dialog';
19
- import { Input } from '@/components/ui/input';
20
- import { KpiCardsGrid } from '@/components/ui/kpi-cards-grid';
21
- import { Label } from '@/components/ui/label';
22
- import { Progress } from '@/components/ui/progress';
23
- import {
24
- Select,
25
- SelectContent,
26
- SelectItem,
27
- SelectTrigger,
28
- SelectValue,
29
- } from '@/components/ui/select';
30
- import {
31
- Sheet,
32
- SheetContent,
33
- SheetHeader,
34
- SheetTitle,
35
- } from '@/components/ui/sheet';
36
- import {
37
- Table,
38
- TableBody,
39
- TableCell,
17
+ DialogTitle,
18
+ } from '@/components/ui/dialog';
19
+ import { Input } from '@/components/ui/input';
20
+ import { KpiCardsGrid } from '@/components/ui/kpi-cards-grid';
21
+ import { Label } from '@/components/ui/label';
22
+ import { Progress } from '@/components/ui/progress';
23
+ import {
24
+ Select,
25
+ SelectContent,
26
+ SelectItem,
27
+ SelectTrigger,
28
+ SelectValue,
29
+ } from '@/components/ui/select';
30
+ import {
31
+ Sheet,
32
+ SheetContent,
33
+ SheetHeader,
34
+ SheetTitle,
35
+ } from '@/components/ui/sheet';
36
+ import {
37
+ Table,
38
+ TableBody,
39
+ TableCell,
40
40
  TableHead,
41
41
  TableHeader,
42
- TableRow,
43
- } from '@/components/ui/table';
44
- import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
45
- import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
42
+ TableRow,
43
+ } from '@/components/ui/table';
44
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
45
+ import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
46
+ import { RichTextEditor } from '@/components/rich-text-editor';
46
47
  import {
47
48
  closestCenter,
48
49
  DndContext,
50
+ DragOverlay,
49
51
  PointerSensor,
50
52
  useDraggable,
51
53
  useDroppable,
52
54
  useSensor,
53
55
  useSensors,
54
56
  type DragEndEvent,
57
+ type DragStartEvent,
55
58
  type UniqueIdentifier,
56
59
  } from '@dnd-kit/core';
57
60
  import { CSS } from '@dnd-kit/utilities';
@@ -73,6 +76,7 @@ import {
73
76
  Pencil,
74
77
  PlayCircle,
75
78
  Plus,
79
+ Send,
76
80
  Timer,
77
81
  Trash2,
78
82
  } from 'lucide-react';
@@ -81,15 +85,18 @@ import Link from 'next/link';
81
85
  import { useCallback, useMemo, useState } from 'react';
82
86
  import { OperationsHeader } from '../_components/operations-header';
83
87
  import { StatusBadge } from '../_components/status-badge';
84
- import {
85
- TaskCommentsSection,
86
- TaskDetailSheet,
87
- type TaskDetailSheetData,
88
- } from '../_components/task-detail-sheet';
89
- import { TaskFileAttachments } from '../_components/task-file-attachments';
90
- import { fetchOperations, mutateOperations } from '../_lib/api';
91
- import { useMentionItems } from '../_lib/hooks/use-mention-items';
88
+ import {
89
+ TaskDetailSheet,
90
+ TaskCommentsSection,
91
+ type TaskDetailSheetData,
92
+ } from '../_components/task-detail-sheet';
93
+ import { TaskFileAttachments } from '../_components/task-file-attachments';
94
+ import { TimesheetEntryCreateSheet } from '../_components/timesheet-entry-create-sheet';
95
+ import { fetchOperations, mutateOperations } from '../_lib/api';
96
+ import { useMentionItems } from '../_lib/hooks/use-mention-items';
97
+ import { usePersistedPageSize } from '@/hooks/use-persisted-page-size';
92
98
  import type {
99
+ OperationsCollaborator,
93
100
  OperationsProjectOption,
94
101
  OperationsTaskOption,
95
102
  PaginatedResponse,
@@ -114,11 +121,20 @@ type TaskFormState = {
114
121
  description: string;
115
122
  priority: 'low' | 'medium' | 'high';
116
123
  status: BoardColumnId;
124
+ assigneeCollaboratorId: string;
117
125
  dueDate: string;
118
126
  estimateHours: string;
119
127
  tags: string;
120
128
  };
121
129
 
130
+ type TimesheetEntryPrefill = {
131
+ projectId: number;
132
+ projectAssignmentId?: number | null;
133
+ projectLabel: string;
134
+ taskId: number;
135
+ taskLabel: string;
136
+ };
137
+
122
138
  const KANBAN_COLUMNS: Array<{ id: BoardColumnId; label: string }> = [
123
139
  { id: 'todo', label: 'Backlog' },
124
140
  { id: 'doing', label: 'Em execução' },
@@ -132,6 +148,7 @@ const EMPTY_TASK_FORM: TaskFormState = {
132
148
  description: '',
133
149
  priority: 'medium',
134
150
  status: 'todo',
151
+ assigneeCollaboratorId: 'none',
135
152
  dueDate: '',
136
153
  estimateHours: '',
137
154
  tags: '',
@@ -151,17 +168,25 @@ function parseTaskId(value: UniqueIdentifier | null | undefined) {
151
168
  return match ? Number(match[1]) : null;
152
169
  }
153
170
 
154
- function parseColumnId(
155
- value: UniqueIdentifier | null | undefined
156
- ): BoardColumnId | null {
157
- if (!value) return null;
158
- const match = String(value).match(/^col-(.+)$/);
159
- const id = match?.[1];
160
- return KANBAN_COLUMNS.some((c) => c.id === id) ? (id as BoardColumnId) : null;
161
- }
162
-
163
- function splitTasksByColumn(tasks: OperationsTaskOption[]): BoardColumns {
164
- return {
171
+ function parseColumnId(
172
+ value: UniqueIdentifier | null | undefined
173
+ ): BoardColumnId | null {
174
+ if (!value) return null;
175
+ const match = String(value).match(/^col-(.+)$/);
176
+ const id = match?.[1];
177
+ return KANBAN_COLUMNS.some((c) => c.id === id) ? (id as BoardColumnId) : null;
178
+ }
179
+
180
+ function normalizeDateInputValue(value?: string | null) {
181
+ if (!value) return '';
182
+ const match = String(value)
183
+ .trim()
184
+ .match(/^\d{4}-\d{2}-\d{2}/);
185
+ return match?.[0] ?? '';
186
+ }
187
+
188
+ function splitTasksByColumn(tasks: OperationsTaskOption[]): BoardColumns {
189
+ return {
165
190
  todo: tasks.filter((t) => t.status === 'todo'),
166
191
  doing: tasks.filter((t) => t.status === 'doing'),
167
192
  review: tasks.filter((t) => t.status === 'review'),
@@ -169,6 +194,30 @@ function splitTasksByColumn(tasks: OperationsTaskOption[]): BoardColumns {
169
194
  };
170
195
  }
171
196
 
197
+ function getTaskColumnId(status?: string | null): BoardColumnId {
198
+ return KANBAN_COLUMNS.some((column) => column.id === status)
199
+ ? (status as BoardColumnId)
200
+ : 'todo';
201
+ }
202
+
203
+ function replaceTaskInColumns(
204
+ columns: BoardColumns,
205
+ task: OperationsTaskOption
206
+ ): BoardColumns {
207
+ const targetColumn = getTaskColumnId(task.status);
208
+ const nextColumns = {
209
+ todo: columns.todo.filter((item) => item.id !== task.id),
210
+ doing: columns.doing.filter((item) => item.id !== task.id),
211
+ review: columns.review.filter((item) => item.id !== task.id),
212
+ done: columns.done.filter((item) => item.id !== task.id),
213
+ };
214
+
215
+ return {
216
+ ...nextColumns,
217
+ [targetColumn]: [task, ...nextColumns[targetColumn]],
218
+ };
219
+ }
220
+
172
221
  function getTaskPriorityLabel(value?: string | null) {
173
222
  const labels: Record<string, string> = {
174
223
  low: 'Baixa',
@@ -242,26 +291,6 @@ function getUserPhotoUrl(photoId?: number | null) {
242
291
  : null;
243
292
  }
244
293
 
245
- function normalizeDateInputValue(value?: string | null) {
246
- if (!value) {
247
- return '';
248
- }
249
-
250
- const normalizedValue = String(value).trim();
251
- const directMatch = normalizedValue.match(/^\d{4}-\d{2}-\d{2}/);
252
-
253
- if (directMatch?.[0]) {
254
- return directMatch[0];
255
- }
256
-
257
- const parsedDate = new Date(normalizedValue);
258
- if (Number.isNaN(parsedDate.getTime())) {
259
- return '';
260
- }
261
-
262
- return parsedDate.toISOString().slice(0, 10);
263
- }
264
-
265
294
  function DraggableTaskCard({
266
295
  task,
267
296
  children,
@@ -276,10 +305,12 @@ function DraggableTaskCard({
276
305
  return (
277
306
  <div
278
307
  ref={setNodeRef}
279
- style={{ transform: CSS.Translate.toString(transform) }}
308
+ style={{
309
+ transform: CSS.Translate.toString(transform),
310
+ ...(isDragging ? { opacity: 0, pointerEvents: 'none' } : {}),
311
+ }}
280
312
  {...listeners}
281
313
  {...attributes}
282
- className={isDragging ? 'z-20' : undefined}
283
314
  >
284
315
  {children(isDragging)}
285
316
  </div>
@@ -303,13 +334,17 @@ export default function OperationsMyTasksPage() {
303
334
  const t = useTranslations('operations.MyTasksPage');
304
335
  const commonT = useTranslations('operations.Common');
305
336
  const detailT = useTranslations('operations.ProjectDetailsPage');
306
-
307
- const { request, currentLocaleCode, getSettingValue } = useApp();
308
- const mentionItems = useMentionItems(request);
309
- const [search, setSearch] = useState('');
337
+
338
+ const { request, currentLocaleCode, getSettingValue } = useApp();
339
+ const mentionItems = useMentionItems(request);
340
+ const [search, setSearch] = useState('');
310
341
  const [statusFilter, setStatusFilter] = useState('all');
311
342
  const [page, setPage] = useState(1);
312
- const [pageSize, setPageSize] = useState(20);
343
+ const [pageSize, setPageSize] = usePersistedPageSize({
344
+ storageKey: 'pagination:operations-my-tasks:pageSize',
345
+ defaultValue: 20,
346
+ allowedValues: [10, 20, 50],
347
+ });
313
348
  const [taskCollection, setTaskCollection] =
314
349
  useState<TaskCollection>('active');
315
350
  const [viewMode, setViewMode] = useState<TaskViewMode>(() => {
@@ -331,11 +366,17 @@ export default function OperationsMyTasksPage() {
331
366
  const [deletePromptTask, setDeletePromptTask] =
332
367
  useState<OperationsTaskOption | null>(null);
333
368
  const [taskFormOpen, setTaskFormOpen] = useState(false);
334
- const [editingTaskId, setEditingTaskId] = useState<number | null>(null);
335
- const [taskFormLoading, setTaskFormLoading] = useState(false);
336
- const [archivingTaskId, setArchivingTaskId] = useState<number | null>(null);
337
- const [taskFormData, setTaskFormData] =
338
- useState<TaskFormState>(EMPTY_TASK_FORM);
369
+ const [editingTaskId, setEditingTaskId] = useState<number | null>(null);
370
+ const [archivingTaskId, setArchivingTaskId] = useState<number | null>(null);
371
+ const [taskFormLoading, setTaskFormLoading] = useState(false);
372
+ const [taskFormData, setTaskFormData] =
373
+ useState<TaskFormState>(EMPTY_TASK_FORM);
374
+ const [activeDragTask, setActiveDragTask] =
375
+ useState<OperationsTaskOption | null>(null);
376
+ const [isTimesheetEntrySheetOpen, setIsTimesheetEntrySheetOpen] =
377
+ useState(false);
378
+ const [timesheetPrefill, setTimesheetPrefill] =
379
+ useState<TimesheetEntryPrefill | null>(null);
339
380
  const [inlineCreateColumn, setInlineCreateColumn] =
340
381
  useState<BoardColumnId | null>(null);
341
382
  const [inlineCreateName, setInlineCreateName] = useState('');
@@ -396,16 +437,57 @@ export default function OperationsMyTasksPage() {
396
437
  ),
397
438
  placeholderData: (previous) => previous,
398
439
  });
440
+ const { data: collaboratorsResponse } = useQuery<
441
+ PaginatedResponse<OperationsCollaborator>
442
+ >({
443
+ queryKey: ['operations-my-task-collaborator-options', currentLocaleCode],
444
+ queryFn: () =>
445
+ fetchOperations<PaginatedResponse<OperationsCollaborator>>(
446
+ request,
447
+ '/operations/collaborators?pageSize=200&sortField=displayName&sortOrder=asc'
448
+ ),
449
+ placeholderData: (previous) => previous,
450
+ });
399
451
 
400
452
  const tasks = tasksResponse?.data ?? [];
401
453
  const boardApiTasks = boardTasksResponse?.data ?? [];
402
454
  const projectOptions = projectOptionsResponse?.data ?? [];
455
+ const assigneeOptions = useMemo(() => {
456
+ const seen = new Set<number>();
457
+ return (collaboratorsResponse?.data ?? [])
458
+ .filter((collaborator) => {
459
+ if (!collaborator.id || seen.has(collaborator.id)) {
460
+ return false;
461
+ }
462
+ seen.add(collaborator.id);
463
+ return true;
464
+ })
465
+ .map((collaborator) => ({
466
+ id: String(collaborator.id),
467
+ label:
468
+ collaborator.displayName ||
469
+ collaborator.personName ||
470
+ collaborator.code,
471
+ }));
472
+ }, [collaboratorsResponse]);
403
473
 
404
474
  const boardColumns: BoardColumns = useMemo(() => {
405
475
  if (boardOverride) return boardOverride.columns;
406
476
  return splitTasksByColumn(boardApiTasks);
407
477
  }, [boardOverride, boardApiTasks]);
408
478
 
479
+ const editingTask = useMemo(() => {
480
+ if (!editingTaskId) return null;
481
+ return (
482
+ Object.values(boardColumns)
483
+ .flat()
484
+ .find((task) => task.id === editingTaskId) ??
485
+ boardApiTasks.find((task) => task.id === editingTaskId) ??
486
+ tasks.find((task) => task.id === editingTaskId) ??
487
+ null
488
+ );
489
+ }, [boardApiTasks, boardColumns, editingTaskId, tasks]);
490
+
409
491
  const statsCards = useMemo(
410
492
  () => [
411
493
  {
@@ -494,23 +576,56 @@ export default function OperationsMyTasksPage() {
494
576
  },
495
577
  });
496
578
 
497
- mutateOperations(request, `/operations/tasks/${taskId}`, 'PATCH', {
498
- status: targetColumn,
499
- }).catch(() => {
500
- setBoardOverride(null);
501
- void refetchBoard();
502
- });
579
+ mutateOperations<OperationsTaskOption>(
580
+ request,
581
+ `/operations/tasks/${taskId}`,
582
+ 'PATCH',
583
+ {
584
+ status: targetColumn,
585
+ }
586
+ )
587
+ .then((updatedTask) => {
588
+ if (!updatedTask) {
589
+ return;
590
+ }
591
+
592
+ setBoardOverride((current) => ({
593
+ columns: replaceTaskInColumns(current?.columns ?? boardColumns, {
594
+ ...sourceTask,
595
+ ...updatedTask,
596
+ }),
597
+ }));
598
+ })
599
+ .catch(() => {
600
+ setBoardOverride(null);
601
+ void refetchBoard();
602
+ });
503
603
  },
504
604
  [boardColumns, findColumnByTask, request, refetchBoard]
505
605
  );
506
606
 
507
607
  const onBoardDragEnd = (event: DragEndEvent) => {
608
+ setActiveDragTask(null);
508
609
  const taskId = parseTaskId(event.active.id);
509
610
  const targetColumn = parseColumnId(event.over?.id);
510
611
  if (!taskId || !targetColumn) return;
511
612
  moveTaskToColumn(taskId, targetColumn);
512
613
  };
513
614
 
615
+ const onBoardDragStart = (event: DragStartEvent) => {
616
+ const taskId = parseTaskId(event.active.id);
617
+ if (!taskId) {
618
+ setActiveDragTask(null);
619
+ return;
620
+ }
621
+
622
+ const task = KANBAN_COLUMNS.map((column) => boardColumns[column.id])
623
+ .find((items) => items.some((item) => item.id === taskId))
624
+ ?.find((item) => item.id === taskId);
625
+
626
+ setActiveDragTask(task ?? null);
627
+ };
628
+
514
629
  const refetchAll = useCallback(async () => {
515
630
  await Promise.all([refetch(), refetchBoard()]);
516
631
  }, [refetch, refetchBoard]);
@@ -592,7 +707,6 @@ export default function OperationsMyTasksPage() {
592
707
 
593
708
  const openCreateTaskForm = useCallback(() => {
594
709
  setEditingTaskId(null);
595
- setTaskFormData(EMPTY_TASK_FORM);
596
710
  setSelectedTask(null);
597
711
  setTaskFormOpen(true);
598
712
  }, []);
@@ -607,6 +721,9 @@ export default function OperationsMyTasksPage() {
607
721
  status: KANBAN_COLUMNS.some((column) => column.id === task.status)
608
722
  ? (task.status as BoardColumnId)
609
723
  : 'todo',
724
+ assigneeCollaboratorId: task.assigneeCollaboratorId
725
+ ? String(task.assigneeCollaboratorId)
726
+ : 'none',
610
727
  dueDate: normalizeDateInputValue(task.dueDate),
611
728
  estimateHours:
612
729
  task.estimateHours != null ? String(task.estimateHours) : '',
@@ -628,6 +745,10 @@ export default function OperationsMyTasksPage() {
628
745
  const payload = {
629
746
  projectId: selectedProject.id,
630
747
  projectAssignmentId: selectedProject.projectAssignmentId ?? null,
748
+ assigneeCollaboratorId:
749
+ taskFormData.assigneeCollaboratorId !== 'none'
750
+ ? Number(taskFormData.assigneeCollaboratorId)
751
+ : null,
631
752
  name: normalizedName,
632
753
  description: taskFormData.description.trim() || null,
633
754
  priority: taskFormData.priority,
@@ -661,6 +782,29 @@ export default function OperationsMyTasksPage() {
661
782
  }
662
783
  }, [editingTaskId, projectOptions, request, refetchAll, taskFormData]);
663
784
 
785
+ const openTimesheetEntrySheet = useCallback(
786
+ (task: TaskDetailSheetData) => {
787
+ if (!task.projectId) {
788
+ return;
789
+ }
790
+
791
+ const projectLabel = [task.projectName, task.projectCode]
792
+ .filter(Boolean)
793
+ .join(' • ');
794
+
795
+ setTimesheetPrefill({
796
+ projectId: task.projectId,
797
+ projectAssignmentId: task.projectAssignmentId ?? null,
798
+ projectLabel: projectLabel || commonT('labels.notAssigned'),
799
+ taskId: task.id,
800
+ taskLabel: task.name,
801
+ });
802
+ setSelectedTask(null);
803
+ setIsTimesheetEntrySheetOpen(true);
804
+ },
805
+ [commonT]
806
+ );
807
+
664
808
  return (
665
809
  <Page>
666
810
  <OperationsHeader
@@ -779,6 +923,8 @@ export default function OperationsMyTasksPage() {
779
923
  <DndContext
780
924
  sensors={sensors}
781
925
  collisionDetection={closestCenter}
926
+ onDragStart={onBoardDragStart}
927
+ onDragCancel={() => setActiveDragTask(null)}
782
928
  onDragEnd={onBoardDragEnd}
783
929
  >
784
930
  <div className="grid gap-4 xl:grid-cols-4">
@@ -787,7 +933,7 @@ export default function OperationsMyTasksPage() {
787
933
  {(isOver) => (
788
934
  <div
789
935
  className={[
790
- 'flex min-h-[32rem] flex-col overflow-hidden rounded-3xl border bg-linear-to-b p-3 transition-all',
936
+ 'flex min-h-128 flex-col overflow-hidden rounded-3xl border bg-linear-to-b p-3 transition-all',
791
937
  getColumnClassName(column.id),
792
938
  isOver
793
939
  ? 'border-primary shadow-lg ring-2 ring-primary/15'
@@ -945,7 +1091,7 @@ export default function OperationsMyTasksPage() {
945
1091
 
946
1092
  <div className="mt-3 space-y-1.5">
947
1093
  <div className="flex items-center justify-between text-[11px] text-muted-foreground">
948
- <span>Progresso</span>
1094
+ <span>{t('labels.progress')}</span>
949
1095
  <span>
950
1096
  {getTaskProgress(task.status)}%
951
1097
  </span>
@@ -1080,6 +1226,19 @@ export default function OperationsMyTasksPage() {
1080
1226
  </DroppableColumn>
1081
1227
  ))}
1082
1228
  </div>
1229
+ <DragOverlay zIndex={1200}>
1230
+ {activeDragTask ? (
1231
+ <div className="w-76 cursor-grabbing rounded-2xl border border-primary/60 bg-card p-3 text-left shadow-2xl ring-2 ring-primary/20 opacity-95">
1232
+ <p className="line-clamp-2 text-sm font-semibold leading-snug">
1233
+ {activeDragTask.name}
1234
+ </p>
1235
+ <p className="mt-1 truncate text-xs text-muted-foreground">
1236
+ {activeDragTask.assigneeName ||
1237
+ commonT('labels.notAssigned')}
1238
+ </p>
1239
+ </div>
1240
+ ) : null}
1241
+ </DragOverlay>
1083
1242
  </DndContext>
1084
1243
  ) : (
1085
1244
  <EmptyState
@@ -1248,12 +1407,12 @@ export default function OperationsMyTasksPage() {
1248
1407
  }}
1249
1408
  footer={
1250
1409
  selectedTask ? (
1251
- <div className="grid grid-cols-2 gap-3">
1410
+ <div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
1252
1411
  {taskCollection === 'archived' ? (
1253
1412
  <>
1254
1413
  <Button
1255
1414
  variant="outline"
1256
- className="gap-2"
1415
+ className="gap-2 sm:col-span-2"
1257
1416
  onClick={() => void handleRestoreTask(selectedTask.id)}
1258
1417
  >
1259
1418
  <ArchiveRestore className="size-4" />
@@ -1272,6 +1431,15 @@ export default function OperationsMyTasksPage() {
1272
1431
  </>
1273
1432
  ) : (
1274
1433
  <>
1434
+ <Button
1435
+ variant="outline"
1436
+ className="gap-2"
1437
+ disabled={!selectedTask.projectId}
1438
+ onClick={() => openTimesheetEntrySheet(selectedTask)}
1439
+ >
1440
+ <Send className="size-4" />
1441
+ {commonT('actions.logHours')}
1442
+ </Button>
1275
1443
  <Button
1276
1444
  variant="outline"
1277
1445
  className="gap-2"
@@ -1297,6 +1465,36 @@ export default function OperationsMyTasksPage() {
1297
1465
  }
1298
1466
  />
1299
1467
 
1468
+ <TimesheetEntryCreateSheet
1469
+ open={isTimesheetEntrySheetOpen}
1470
+ onOpenChange={(open) => {
1471
+ setIsTimesheetEntrySheetOpen(open);
1472
+ if (!open) {
1473
+ setTimesheetPrefill(null);
1474
+ }
1475
+ }}
1476
+ project={
1477
+ timesheetPrefill
1478
+ ? {
1479
+ id: timesheetPrefill.projectId,
1480
+ label: timesheetPrefill.projectLabel,
1481
+ projectAssignmentId: timesheetPrefill.projectAssignmentId,
1482
+ }
1483
+ : null
1484
+ }
1485
+ task={
1486
+ timesheetPrefill
1487
+ ? {
1488
+ id: timesheetPrefill.taskId,
1489
+ label: timesheetPrefill.taskLabel,
1490
+ }
1491
+ : null
1492
+ }
1493
+ onCreated={() => {
1494
+ void refetchAll();
1495
+ }}
1496
+ />
1497
+
1300
1498
  <Dialog
1301
1499
  open={deletePromptTask !== null}
1302
1500
  onOpenChange={(open) => {
@@ -1306,10 +1504,10 @@ export default function OperationsMyTasksPage() {
1306
1504
  <DialogContent className="sm:max-w-sm">
1307
1505
  <DialogHeader>
1308
1506
  <DialogTitle>{t('dialogs.deleteTitle')}</DialogTitle>
1507
+ <DialogDescription>
1508
+ {t('dialogs.deleteDescription')}
1509
+ </DialogDescription>
1309
1510
  </DialogHeader>
1310
- <p className="text-sm text-muted-foreground">
1311
- {t('dialogs.deleteDescription')}
1312
- </p>
1313
1511
  <DialogFooter className="mt-4">
1314
1512
  <Button variant="outline" onClick={() => setDeletePromptTask(null)}>
1315
1513
  {commonT('actions.cancel')}
@@ -1328,16 +1526,12 @@ export default function OperationsMyTasksPage() {
1328
1526
  </DialogContent>
1329
1527
  </Dialog>
1330
1528
 
1331
- <Sheet
1332
- open={taskFormOpen}
1333
- onOpenChange={(open) => {
1334
- if (!taskFormLoading) {
1335
- setTaskFormOpen(open);
1336
- if (!open) {
1337
- setEditingTaskId(null);
1338
- setTaskFormData(EMPTY_TASK_FORM);
1339
- }
1340
- }
1529
+
1530
+ <Sheet
1531
+ open={taskFormOpen}
1532
+ onOpenChange={(open) => {
1533
+ setTaskFormOpen(open);
1534
+ if (!open) setEditingTaskId(null);
1341
1535
  }}
1342
1536
  >
1343
1537
  <SheetContent className="flex w-full flex-col overflow-hidden sm:max-w-xl">
@@ -1481,6 +1675,35 @@ export default function OperationsMyTasksPage() {
1481
1675
  </div>
1482
1676
  </div>
1483
1677
 
1678
+ <div className="space-y-2">
1679
+ <Label>{commonT('responsible')}</Label>
1680
+ <Select
1681
+ value={taskFormData.assigneeCollaboratorId}
1682
+ onValueChange={(value) =>
1683
+ setTaskFormData((prev) => ({
1684
+ ...prev,
1685
+ assigneeCollaboratorId: value,
1686
+ }))
1687
+ }
1688
+ >
1689
+ <SelectTrigger className="w-full">
1690
+ <SelectValue
1691
+ placeholder={commonT('labels.notAssigned')}
1692
+ />
1693
+ </SelectTrigger>
1694
+ <SelectContent>
1695
+ <SelectItem value="none">
1696
+ {commonT('labels.notAssigned')}
1697
+ </SelectItem>
1698
+ {assigneeOptions.map((option) => (
1699
+ <SelectItem key={option.id} value={option.id}>
1700
+ {option.label}
1701
+ </SelectItem>
1702
+ ))}
1703
+ </SelectContent>
1704
+ </Select>
1705
+ </div>
1706
+
1484
1707
  <div className="grid grid-cols-2 gap-3">
1485
1708
  <div className="space-y-2">
1486
1709
  <Label htmlFor="task-due-date">