@hed-hog/operations 0.0.330 → 0.0.332

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 (320) hide show
  1. package/README.md +5 -5
  2. package/dist/controllers/operations-collaborators.controller.d.ts +58 -213
  3. package/dist/controllers/operations-collaborators.controller.d.ts.map +1 -1
  4. package/dist/controllers/operations-collaborators.controller.js +100 -0
  5. package/dist/controllers/operations-collaborators.controller.js.map +1 -1
  6. package/dist/controllers/operations-contracts.controller.d.ts +6 -6
  7. package/dist/controllers/operations-projects.controller.d.ts +25 -0
  8. package/dist/controllers/operations-projects.controller.d.ts.map +1 -1
  9. package/dist/controllers/operations-projects.controller.js +48 -0
  10. package/dist/controllers/operations-projects.controller.js.map +1 -1
  11. package/dist/controllers/operations-reports.controller.d.ts +1 -1
  12. package/dist/controllers/operations-tasks.controller.d.ts +34 -9
  13. package/dist/controllers/operations-tasks.controller.d.ts.map +1 -1
  14. package/dist/controllers/operations-tasks.controller.js +43 -32
  15. package/dist/controllers/operations-tasks.controller.js.map +1 -1
  16. package/dist/controllers/operations-timesheets.controller.d.ts +9 -9
  17. package/dist/dashboard/components/DashboardLayout.d.ts +30 -0
  18. package/dist/dashboard/components/DashboardLayout.d.ts.map +1 -0
  19. package/dist/dashboard/components/DashboardLayout.js +87 -0
  20. package/dist/dashboard/components/DashboardLayout.js.map +1 -0
  21. package/dist/dashboard/components/widget-registry.d.ts +23 -0
  22. package/dist/dashboard/components/widget-registry.d.ts.map +1 -0
  23. package/dist/dashboard/components/widget-registry.js +245 -0
  24. package/dist/dashboard/components/widget-registry.js.map +1 -0
  25. package/dist/dashboard/hooks/useDashboardData.d.ts +20 -0
  26. package/dist/dashboard/hooks/useDashboardData.d.ts.map +1 -0
  27. package/dist/dashboard/hooks/useDashboardData.js +24 -0
  28. package/dist/dashboard/hooks/useDashboardData.js.map +1 -0
  29. package/dist/dashboard/types/widgets.types.d.ts +233 -0
  30. package/dist/dashboard/types/widgets.types.d.ts.map +1 -0
  31. package/dist/dashboard/types/widgets.types.js +6 -0
  32. package/dist/dashboard/types/widgets.types.js.map +1 -0
  33. package/dist/dashboard/widgets/CapacityDistribution.d.ts +23 -0
  34. package/dist/dashboard/widgets/CapacityDistribution.d.ts.map +1 -0
  35. package/dist/dashboard/widgets/CapacityDistribution.js +11 -0
  36. package/dist/dashboard/widgets/CapacityDistribution.js.map +1 -0
  37. package/dist/dashboard/widgets/EffortByProject.d.ts +22 -0
  38. package/dist/dashboard/widgets/EffortByProject.d.ts.map +1 -0
  39. package/dist/dashboard/widgets/EffortByProject.js +11 -0
  40. package/dist/dashboard/widgets/EffortByProject.js.map +1 -0
  41. package/dist/dashboard/widgets/HeadcountByArea.d.ts +24 -0
  42. package/dist/dashboard/widgets/HeadcountByArea.d.ts.map +1 -0
  43. package/dist/dashboard/widgets/HeadcountByArea.js +11 -0
  44. package/dist/dashboard/widgets/HeadcountByArea.js.map +1 -0
  45. package/dist/dashboard/widgets/ManagedProjectsStatus.d.ts +18 -0
  46. package/dist/dashboard/widgets/ManagedProjectsStatus.d.ts.map +1 -0
  47. package/dist/dashboard/widgets/ManagedProjectsStatus.js +12 -0
  48. package/dist/dashboard/widgets/ManagedProjectsStatus.js.map +1 -0
  49. package/dist/dashboard/widgets/MyHoursPeriodKpi.d.ts +22 -0
  50. package/dist/dashboard/widgets/MyHoursPeriodKpi.d.ts.map +1 -0
  51. package/dist/dashboard/widgets/MyHoursPeriodKpi.js +12 -0
  52. package/dist/dashboard/widgets/MyHoursPeriodKpi.js.map +1 -0
  53. package/dist/dashboard/widgets/MyOpenRequestsKpi.d.ts +19 -0
  54. package/dist/dashboard/widgets/MyOpenRequestsKpi.d.ts.map +1 -0
  55. package/dist/dashboard/widgets/MyOpenRequestsKpi.js +17 -0
  56. package/dist/dashboard/widgets/MyOpenRequestsKpi.js.map +1 -0
  57. package/dist/dashboard/widgets/MyPendingRequestsList.d.ts +23 -0
  58. package/dist/dashboard/widgets/MyPendingRequestsList.d.ts.map +1 -0
  59. package/dist/dashboard/widgets/MyPendingRequestsList.js +14 -0
  60. package/dist/dashboard/widgets/MyPendingRequestsList.js.map +1 -0
  61. package/dist/dashboard/widgets/MyProjectAllocationsKpi.d.ts +22 -0
  62. package/dist/dashboard/widgets/MyProjectAllocationsKpi.d.ts.map +1 -0
  63. package/dist/dashboard/widgets/MyProjectAllocationsKpi.js +11 -0
  64. package/dist/dashboard/widgets/MyProjectAllocationsKpi.js.map +1 -0
  65. package/dist/dashboard/widgets/MyQuickActions.d.ts +23 -0
  66. package/dist/dashboard/widgets/MyQuickActions.d.ts.map +1 -0
  67. package/dist/dashboard/widgets/MyQuickActions.js +18 -0
  68. package/dist/dashboard/widgets/MyQuickActions.js.map +1 -0
  69. package/dist/dashboard/widgets/MyRelevantDeadlines.d.ts +23 -0
  70. package/dist/dashboard/widgets/MyRelevantDeadlines.d.ts.map +1 -0
  71. package/dist/dashboard/widgets/MyRelevantDeadlines.js +22 -0
  72. package/dist/dashboard/widgets/MyRelevantDeadlines.js.map +1 -0
  73. package/dist/dashboard/widgets/MyTimesheetStatusKpi.d.ts +17 -0
  74. package/dist/dashboard/widgets/MyTimesheetStatusKpi.d.ts.map +1 -0
  75. package/dist/dashboard/widgets/MyTimesheetStatusKpi.js +11 -0
  76. package/dist/dashboard/widgets/MyTimesheetStatusKpi.js.map +1 -0
  77. package/dist/dashboard/widgets/MyWeeklyJourney.d.ts +21 -0
  78. package/dist/dashboard/widgets/MyWeeklyJourney.d.ts.map +1 -0
  79. package/dist/dashboard/widgets/MyWeeklyJourney.js +19 -0
  80. package/dist/dashboard/widgets/MyWeeklyJourney.js.map +1 -0
  81. package/dist/dashboard/widgets/PortfolioCostsKpi.d.ts +19 -0
  82. package/dist/dashboard/widgets/PortfolioCostsKpi.d.ts.map +1 -0
  83. package/dist/dashboard/widgets/PortfolioCostsKpi.js +12 -0
  84. package/dist/dashboard/widgets/PortfolioCostsKpi.js.map +1 -0
  85. package/dist/dashboard/widgets/PortfolioEffortKpi.d.ts +18 -0
  86. package/dist/dashboard/widgets/PortfolioEffortKpi.d.ts.map +1 -0
  87. package/dist/dashboard/widgets/PortfolioEffortKpi.js +8 -0
  88. package/dist/dashboard/widgets/PortfolioEffortKpi.js.map +1 -0
  89. package/dist/dashboard/widgets/PortfolioProjectsKpi.d.ts +22 -0
  90. package/dist/dashboard/widgets/PortfolioProjectsKpi.d.ts.map +1 -0
  91. package/dist/dashboard/widgets/PortfolioProjectsKpi.js +56 -0
  92. package/dist/dashboard/widgets/PortfolioProjectsKpi.js.map +1 -0
  93. package/dist/dashboard/widgets/PortfolioRiskKpi.d.ts +19 -0
  94. package/dist/dashboard/widgets/PortfolioRiskKpi.d.ts.map +1 -0
  95. package/dist/dashboard/widgets/PortfolioRiskKpi.js +11 -0
  96. package/dist/dashboard/widgets/PortfolioRiskKpi.js.map +1 -0
  97. package/dist/dashboard/widgets/ProjectStatusOverview.d.ts +19 -0
  98. package/dist/dashboard/widgets/ProjectStatusOverview.d.ts.map +1 -0
  99. package/dist/dashboard/widgets/ProjectStatusOverview.js +18 -0
  100. package/dist/dashboard/widgets/ProjectStatusOverview.js.map +1 -0
  101. package/dist/dashboard/widgets/StrategicDeadlines.d.ts +24 -0
  102. package/dist/dashboard/widgets/StrategicDeadlines.d.ts.map +1 -0
  103. package/dist/dashboard/widgets/StrategicDeadlines.js +22 -0
  104. package/dist/dashboard/widgets/StrategicDeadlines.js.map +1 -0
  105. package/dist/dashboard/widgets/TeamApprovalQueue.d.ts +24 -0
  106. package/dist/dashboard/widgets/TeamApprovalQueue.d.ts.map +1 -0
  107. package/dist/dashboard/widgets/TeamApprovalQueue.js +12 -0
  108. package/dist/dashboard/widgets/TeamApprovalQueue.js.map +1 -0
  109. package/dist/dashboard/widgets/TeamCapacityKpi.d.ts +18 -0
  110. package/dist/dashboard/widgets/TeamCapacityKpi.d.ts.map +1 -0
  111. package/dist/dashboard/widgets/TeamCapacityKpi.js +19 -0
  112. package/dist/dashboard/widgets/TeamCapacityKpi.js.map +1 -0
  113. package/dist/dashboard/widgets/TeamHeadcountKpi.d.ts +22 -0
  114. package/dist/dashboard/widgets/TeamHeadcountKpi.d.ts.map +1 -0
  115. package/dist/dashboard/widgets/TeamHeadcountKpi.js +56 -0
  116. package/dist/dashboard/widgets/TeamHeadcountKpi.js.map +1 -0
  117. package/dist/dashboard/widgets/TeamHoursKpi.d.ts +19 -0
  118. package/dist/dashboard/widgets/TeamHoursKpi.d.ts.map +1 -0
  119. package/dist/dashboard/widgets/TeamHoursKpi.js +13 -0
  120. package/dist/dashboard/widgets/TeamHoursKpi.js.map +1 -0
  121. package/dist/dashboard/widgets/TeamPendingApprovalsKpi.d.ts +20 -0
  122. package/dist/dashboard/widgets/TeamPendingApprovalsKpi.d.ts.map +1 -0
  123. package/dist/dashboard/widgets/TeamPendingApprovalsKpi.js +11 -0
  124. package/dist/dashboard/widgets/TeamPendingApprovalsKpi.js.map +1 -0
  125. package/dist/dashboard/widgets/TeamUtilizationOverview.d.ts +18 -0
  126. package/dist/dashboard/widgets/TeamUtilizationOverview.d.ts.map +1 -0
  127. package/dist/dashboard/widgets/TeamUtilizationOverview.js +17 -0
  128. package/dist/dashboard/widgets/TeamUtilizationOverview.js.map +1 -0
  129. package/dist/dashboard/widgets/TeamWorkloadAlerts.d.ts +24 -0
  130. package/dist/dashboard/widgets/TeamWorkloadAlerts.d.ts.map +1 -0
  131. package/dist/dashboard/widgets/TeamWorkloadAlerts.js +19 -0
  132. package/dist/dashboard/widgets/TeamWorkloadAlerts.js.map +1 -0
  133. package/dist/dashboard/widgets/index.d.ts +24 -0
  134. package/dist/dashboard/widgets/index.d.ts.map +1 -0
  135. package/dist/dashboard/widgets/index.js +54 -0
  136. package/dist/dashboard/widgets/index.js.map +1 -0
  137. package/dist/dto/create-collaborator-invoice.dto.d.ts +11 -0
  138. package/dist/dto/create-collaborator-invoice.dto.d.ts.map +1 -0
  139. package/dist/dto/create-collaborator-invoice.dto.js +55 -0
  140. package/dist/dto/create-collaborator-invoice.dto.js.map +1 -0
  141. package/dist/dto/create-collaborator-payment.dto.d.ts +10 -0
  142. package/dist/dto/create-collaborator-payment.dto.d.ts.map +1 -0
  143. package/dist/dto/create-collaborator-payment.dto.js +50 -0
  144. package/dist/dto/create-collaborator-payment.dto.js.map +1 -0
  145. package/dist/dto/create-collaborator.dto.d.ts +0 -1
  146. package/dist/dto/create-collaborator.dto.d.ts.map +1 -1
  147. package/dist/dto/create-collaborator.dto.js +0 -6
  148. package/dist/dto/create-collaborator.dto.js.map +1 -1
  149. package/dist/dto/list-collaborator-invoice.dto.d.ts +4 -0
  150. package/dist/dto/list-collaborator-invoice.dto.d.ts.map +1 -0
  151. package/dist/dto/list-collaborator-invoice.dto.js +8 -0
  152. package/dist/dto/list-collaborator-invoice.dto.js.map +1 -0
  153. package/dist/dto/list-collaborator-payment.dto.d.ts +4 -0
  154. package/dist/dto/list-collaborator-payment.dto.d.ts.map +1 -0
  155. package/dist/dto/list-collaborator-payment.dto.js +8 -0
  156. package/dist/dto/list-collaborator-payment.dto.js.map +1 -0
  157. package/dist/dto/update-collaborator-invoice.dto.d.ts +6 -0
  158. package/dist/dto/update-collaborator-invoice.dto.d.ts.map +1 -0
  159. package/dist/dto/update-collaborator-invoice.dto.js +9 -0
  160. package/dist/dto/update-collaborator-invoice.dto.js.map +1 -0
  161. package/dist/dto/update-collaborator-payment.dto.d.ts +6 -0
  162. package/dist/dto/update-collaborator-payment.dto.d.ts.map +1 -0
  163. package/dist/dto/update-collaborator-payment.dto.js +9 -0
  164. package/dist/dto/update-collaborator-payment.dto.js.map +1 -0
  165. package/dist/index.d.ts +2 -0
  166. package/dist/index.d.ts.map +1 -1
  167. package/dist/index.js +2 -0
  168. package/dist/index.js.map +1 -1
  169. package/dist/operations.controller.d.ts +42 -0
  170. package/dist/operations.controller.d.ts.map +1 -1
  171. package/dist/operations.service.d.ts +258 -268
  172. package/dist/operations.service.d.ts.map +1 -1
  173. package/dist/operations.service.js +2381 -1341
  174. package/dist/operations.service.js.map +1 -1
  175. package/dist/operations.service.spec.js +345 -174
  176. package/dist/operations.service.spec.js.map +1 -1
  177. package/hedhog/data/dashboard_component.yaml +66 -0
  178. package/hedhog/data/dashboard_item.yaml +25 -25
  179. package/hedhog/data/menu.yaml +27 -8
  180. package/hedhog/data/route.yaml +133 -0
  181. package/hedhog/frontend/app/_components/collaborator-form-screen.tsx.ejs +78 -102
  182. package/hedhog/frontend/app/_components/collaborator-invoices-tab.tsx.ejs +443 -0
  183. package/hedhog/frontend/app/_components/collaborator-payment-history-tab.tsx.ejs +429 -0
  184. package/hedhog/frontend/app/_components/collaborator-picker.tsx.ejs +158 -0
  185. package/hedhog/frontend/app/_components/my-project-summary-screen.tsx.ejs +247 -50
  186. package/hedhog/frontend/app/_components/project-assignments-tab.tsx.ejs +643 -450
  187. package/hedhog/frontend/app/_components/project-details-screen.tsx.ejs +992 -431
  188. package/hedhog/frontend/app/_components/project-file-attachments.tsx.ejs +371 -0
  189. package/hedhog/frontend/app/_components/project-form-screen.tsx.ejs +558 -386
  190. package/hedhog/frontend/app/_components/task-detail-sheet.tsx.ejs +383 -157
  191. package/hedhog/frontend/app/_components/task-file-attachments.tsx.ejs +4 -1
  192. package/hedhog/frontend/app/_components/task-form-fields.tsx.ejs +406 -0
  193. package/hedhog/frontend/app/_components/task-form-sheet.tsx.ejs +629 -784
  194. package/hedhog/frontend/app/_components/task-info-display.tsx.ejs +137 -0
  195. package/hedhog/frontend/app/_components/timesheet-entry-create-sheet.tsx.ejs +306 -0
  196. package/hedhog/frontend/app/_lib/api.ts.ejs +155 -0
  197. package/hedhog/frontend/app/_lib/types.ts.ejs +62 -0
  198. package/hedhog/frontend/app/_lib/utils/format.ts.ejs +0 -2
  199. package/hedhog/frontend/app/_lib/utils/task-ui.ts.ejs +61 -0
  200. package/hedhog/frontend/app/approvals/page.tsx.ejs +6 -1
  201. package/hedhog/frontend/app/collaborator-types/page.tsx.ejs +6 -1
  202. package/hedhog/frontend/app/collaborators/page.tsx.ejs +59 -8
  203. package/hedhog/frontend/app/contracts/page.tsx.ejs +29 -8
  204. package/hedhog/frontend/app/dashboard/widgets/CapacityDistribution.tsx.ejs +84 -0
  205. package/hedhog/frontend/app/dashboard/widgets/EffortByProject.tsx.ejs +85 -0
  206. package/hedhog/frontend/app/dashboard/widgets/HeadcountByArea.tsx.ejs +101 -0
  207. package/hedhog/frontend/app/dashboard/widgets/ManagedProjectsStatus.tsx.ejs +113 -0
  208. package/hedhog/frontend/app/dashboard/widgets/MyHoursPeriodKpi.tsx.ejs +87 -0
  209. package/hedhog/frontend/app/dashboard/widgets/MyOpenRequestsKpi.tsx.ejs +97 -0
  210. package/hedhog/frontend/app/dashboard/widgets/MyPendingRequestsList.tsx.ejs +99 -0
  211. package/hedhog/frontend/app/dashboard/widgets/MyProjectAllocationsKpi.tsx.ejs +78 -0
  212. package/hedhog/frontend/app/dashboard/widgets/MyQuickActions.tsx.ejs +130 -0
  213. package/hedhog/frontend/app/dashboard/widgets/MyRelevantDeadlines.tsx.ejs +144 -0
  214. package/hedhog/frontend/app/dashboard/widgets/MyTimesheetStatusKpi.tsx.ejs +78 -0
  215. package/hedhog/frontend/app/dashboard/widgets/MyWeeklyJourney.tsx.ejs +99 -0
  216. package/hedhog/frontend/app/dashboard/widgets/PortfolioCostsKpi.tsx.ejs +112 -0
  217. package/hedhog/frontend/app/dashboard/widgets/PortfolioEffortKpi.tsx.ejs +93 -0
  218. package/hedhog/frontend/app/dashboard/widgets/PortfolioProjectsKpi.tsx.ejs +96 -0
  219. package/hedhog/frontend/app/dashboard/widgets/PortfolioRiskKpi.tsx.ejs +115 -0
  220. package/hedhog/frontend/app/dashboard/widgets/ProjectStatusOverview.tsx.ejs +120 -0
  221. package/hedhog/frontend/app/dashboard/widgets/StrategicDeadlines.tsx.ejs +146 -0
  222. package/hedhog/frontend/app/dashboard/widgets/TeamApprovalQueue.tsx.ejs +108 -0
  223. package/hedhog/frontend/app/dashboard/widgets/TeamCapacityKpi.tsx.ejs +97 -0
  224. package/hedhog/frontend/app/dashboard/widgets/TeamHeadcountKpi.tsx.ejs +100 -0
  225. package/hedhog/frontend/app/dashboard/widgets/TeamHoursKpi.tsx.ejs +104 -0
  226. package/hedhog/frontend/app/dashboard/widgets/TeamPendingApprovalsKpi.tsx.ejs +110 -0
  227. package/hedhog/frontend/app/dashboard/widgets/TeamUtilizationOverview.tsx.ejs +115 -0
  228. package/hedhog/frontend/app/dashboard/widgets/TeamWorkloadAlerts.tsx.ejs +117 -0
  229. package/hedhog/frontend/app/dashboard/widgets/index.ts.ejs +26 -0
  230. package/hedhog/frontend/app/departments/page.tsx.ejs +6 -1
  231. package/hedhog/frontend/app/my-projects/page.tsx.ejs +30 -12
  232. package/hedhog/frontend/app/my-tasks/page.tsx.ejs +286 -125
  233. package/hedhog/frontend/app/project-cost-categories/page.tsx.ejs +58 -52
  234. package/hedhog/frontend/app/project-cost-types/page.tsx.ejs +58 -51
  235. package/hedhog/frontend/app/projects/page.tsx.ejs +415 -33
  236. package/hedhog/frontend/app/schedule-adjustments/page.tsx.ejs +6 -1
  237. package/hedhog/frontend/app/tasks-gantt/page.tsx.ejs +953 -0
  238. package/hedhog/frontend/app/time-off/page.tsx.ejs +6 -1
  239. package/hedhog/frontend/app/timesheets/page.tsx.ejs +10 -4
  240. package/hedhog/frontend/messages/en.json +332 -46
  241. package/hedhog/frontend/messages/operations/en.json +61 -52
  242. package/hedhog/frontend/messages/operations/pt.json +59 -43
  243. package/hedhog/frontend/messages/pt.json +332 -46
  244. package/hedhog/frontend/widgets/capacity-distribution.tsx.ejs +17 -0
  245. package/hedhog/frontend/widgets/effort-by-project.tsx.ejs +17 -0
  246. package/hedhog/frontend/widgets/headcount-by-area.tsx.ejs +17 -0
  247. package/hedhog/frontend/widgets/index.ts.ejs +25 -0
  248. package/hedhog/frontend/widgets/managed-projects-status.tsx.ejs +17 -0
  249. package/hedhog/frontend/widgets/my-hours-period-kpi.tsx.ejs +17 -0
  250. package/hedhog/frontend/widgets/my-open-requests-kpi.tsx.ejs +17 -0
  251. package/hedhog/frontend/widgets/my-pending-requests-list.tsx.ejs +17 -0
  252. package/hedhog/frontend/widgets/my-project-allocations-kpi.tsx.ejs +17 -0
  253. package/hedhog/frontend/widgets/my-quick-actions.tsx.ejs +17 -0
  254. package/hedhog/frontend/widgets/my-relevant-deadlines.tsx.ejs +17 -0
  255. package/hedhog/frontend/widgets/my-timesheet-status-kpi.tsx.ejs +17 -0
  256. package/hedhog/frontend/widgets/my-weekly-journey.tsx.ejs +17 -0
  257. package/hedhog/frontend/widgets/portfolio-costs-kpi.tsx.ejs +17 -0
  258. package/hedhog/frontend/widgets/portfolio-effort-kpi.tsx.ejs +17 -0
  259. package/hedhog/frontend/widgets/portfolio-projects-kpi.tsx.ejs +17 -0
  260. package/hedhog/frontend/widgets/portfolio-risk-kpi.tsx.ejs +17 -0
  261. package/hedhog/frontend/widgets/project-status-overview.tsx.ejs +17 -0
  262. package/hedhog/frontend/widgets/shared-operations-widget.tsx.ejs +170 -0
  263. package/hedhog/frontend/widgets/strategic-deadlines.tsx.ejs +17 -0
  264. package/hedhog/frontend/widgets/team-approval-queue.tsx.ejs +17 -0
  265. package/hedhog/frontend/widgets/team-capacity-kpi.tsx.ejs +17 -0
  266. package/hedhog/frontend/widgets/team-headcount-kpi.tsx.ejs +17 -0
  267. package/hedhog/frontend/widgets/team-hours-kpi.tsx.ejs +17 -0
  268. package/hedhog/frontend/widgets/team-pending-approvals-kpi.tsx.ejs +17 -0
  269. package/hedhog/frontend/widgets/team-utilization-overview.tsx.ejs +17 -0
  270. package/hedhog/frontend/widgets/team-workload-alerts.tsx.ejs +17 -0
  271. package/hedhog/table/operations_collaborator.yaml +8 -13
  272. package/hedhog/table/operations_collaborator_invoice.yaml +35 -0
  273. package/hedhog/table/operations_collaborator_payment.yaml +32 -0
  274. package/hedhog/table/operations_project.yaml +1 -1
  275. package/hedhog/table/operations_project_file.yaml +23 -0
  276. package/hedhog/table/operations_task.yaml +76 -69
  277. package/hedhog/table/operations_task_activity.yaml +51 -0
  278. package/package.json +6 -5
  279. package/src/controllers/operations-collaborators.controller.ts +117 -8
  280. package/src/controllers/operations-projects.controller.ts +41 -8
  281. package/src/controllers/operations-tasks.controller.ts +156 -166
  282. package/src/dashboard/README.md +214 -0
  283. package/src/dashboard/components/DashboardLayout.tsx +131 -0
  284. package/src/dashboard/components/widget-registry.ts +255 -0
  285. package/src/dashboard/hooks/useDashboardData.ts +29 -0
  286. package/src/dashboard/types/widgets.types.ts +237 -0
  287. package/src/dashboard/widgets/CapacityDistribution.tsx +56 -0
  288. package/src/dashboard/widgets/EffortByProject.tsx +51 -0
  289. package/src/dashboard/widgets/HeadcountByArea.tsx +57 -0
  290. package/src/dashboard/widgets/ManagedProjectsStatus.tsx +53 -0
  291. package/src/dashboard/widgets/MyHoursPeriodKpi.tsx +87 -0
  292. package/src/dashboard/widgets/MyOpenRequestsKpi.tsx +51 -0
  293. package/src/dashboard/widgets/MyPendingRequestsList.tsx +63 -0
  294. package/src/dashboard/widgets/MyProjectAllocationsKpi.tsx +57 -0
  295. package/src/dashboard/widgets/MyQuickActions.tsx +62 -0
  296. package/src/dashboard/widgets/MyRelevantDeadlines.tsx +84 -0
  297. package/src/dashboard/widgets/MyTimesheetStatusKpi.tsx +65 -0
  298. package/src/dashboard/widgets/MyWeeklyJourney.tsx +57 -0
  299. package/src/dashboard/widgets/PortfolioCostsKpi.tsx +48 -0
  300. package/src/dashboard/widgets/PortfolioEffortKpi.tsx +41 -0
  301. package/src/dashboard/widgets/PortfolioRiskKpi.tsx +50 -0
  302. package/src/dashboard/widgets/ProjectStatusOverview.tsx +52 -0
  303. package/src/dashboard/widgets/StrategicDeadlines.tsx +93 -0
  304. package/src/dashboard/widgets/TeamApprovalQueue.tsx +70 -0
  305. package/src/dashboard/widgets/TeamCapacityKpi.tsx +50 -0
  306. package/src/dashboard/widgets/TeamHoursKpi.tsx +51 -0
  307. package/src/dashboard/widgets/TeamPendingApprovalsKpi.tsx +53 -0
  308. package/src/dashboard/widgets/TeamUtilizationOverview.tsx +62 -0
  309. package/src/dashboard/widgets/TeamWorkloadAlerts.tsx +81 -0
  310. package/src/dashboard/widgets/index.ts +26 -0
  311. package/src/dto/create-collaborator-invoice.dto.ts +39 -0
  312. package/src/dto/create-collaborator-payment.dto.ts +35 -0
  313. package/src/dto/create-collaborator.dto.ts +4 -11
  314. package/src/dto/list-collaborator-invoice.dto.ts +3 -0
  315. package/src/dto/list-collaborator-payment.dto.ts +3 -0
  316. package/src/dto/update-collaborator-invoice.dto.ts +6 -0
  317. package/src/dto/update-collaborator-payment.dto.ts +6 -0
  318. package/src/index.ts +3 -0
  319. package/src/operations.service.spec.ts +988 -764
  320. package/src/operations.service.ts +4689 -2624
@@ -0,0 +1,371 @@
1
+ 'use client';
2
+
3
+ import { Button } from '@/components/ui/button';
4
+ import { useApp } from '@hed-hog/next-app-provider';
5
+ import {
6
+ Archive,
7
+ ExternalLink,
8
+ File,
9
+ FileAudio,
10
+ FileCode,
11
+ FileImage,
12
+ FileSpreadsheet,
13
+ FileText,
14
+ FileVideo,
15
+ Loader2,
16
+ Paperclip,
17
+ Trash2,
18
+ UploadCloud,
19
+ } from 'lucide-react';
20
+ import { useTranslations } from 'next-intl';
21
+ import { useCallback, useEffect, useRef, useState } from 'react';
22
+
23
+ // ─── Types ────────────────────────────────────────────────────────────────────
24
+
25
+ type ProjectFile = {
26
+ id: number;
27
+ file_id: number;
28
+ filename: string;
29
+ size: number;
30
+ mimetype: string;
31
+ created_at: string;
32
+ };
33
+
34
+ type UploadingFile = {
35
+ key: string;
36
+ filename: string;
37
+ progress: number;
38
+ error?: string;
39
+ };
40
+
41
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
42
+
43
+ function formatBytes(bytes: number) {
44
+ if (bytes === 0) return '0 B';
45
+ const k = 1024;
46
+ const sizes = ['B', 'KB', 'MB', 'GB'];
47
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
48
+ return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;
49
+ }
50
+
51
+ function getFileIcon(mimetype: string, filename: string) {
52
+ const ext = filename.split('.').pop()?.toLowerCase() ?? '';
53
+
54
+ if (mimetype.startsWith('image/')) return FileImage;
55
+ if (mimetype.startsWith('video/')) return FileVideo;
56
+ if (mimetype.startsWith('audio/')) return FileAudio;
57
+ if (
58
+ mimetype === 'application/pdf' ||
59
+ mimetype.includes('word') ||
60
+ mimetype.includes('document')
61
+ )
62
+ return FileText;
63
+ if (
64
+ mimetype.includes('spreadsheet') ||
65
+ mimetype.includes('excel') ||
66
+ ext === 'xlsx' ||
67
+ ext === 'xls'
68
+ )
69
+ return FileSpreadsheet;
70
+ if (ext === 'csv') return FileSpreadsheet;
71
+ if (
72
+ mimetype.includes('zip') ||
73
+ mimetype.includes('compressed') ||
74
+ mimetype.includes('archive') ||
75
+ ['zip', 'rar', '7z', 'tar', 'gz'].includes(ext)
76
+ )
77
+ return Archive;
78
+ if (
79
+ [
80
+ 'js', 'ts', 'tsx', 'jsx', 'py', 'java', 'cs', 'cpp', 'c', 'go',
81
+ 'rs', 'json', 'xml', 'html', 'css',
82
+ ].includes(ext) ||
83
+ mimetype.includes('javascript') ||
84
+ mimetype.includes('json') ||
85
+ mimetype.includes('xml') ||
86
+ mimetype.includes('html')
87
+ )
88
+ return FileCode;
89
+
90
+ return File;
91
+ }
92
+
93
+ function getFileOpenUrl(fileId: number) {
94
+ const base =
95
+ typeof process !== 'undefined'
96
+ ? (process.env.NEXT_PUBLIC_API_BASE_URL?.trim().replace(/\/$/, '') ?? '')
97
+ : '';
98
+ return `${base}/file/open/${fileId}`;
99
+ }
100
+
101
+ // ─── Component ────────────────────────────────────────────────────────────────
102
+
103
+ type Props = {
104
+ projectId: number;
105
+ };
106
+
107
+ export function ProjectFileAttachments({ projectId }: Props) {
108
+ const t = useTranslations('operations.ProjectFileAttachments');
109
+ const { request } = useApp();
110
+
111
+ const [files, setFiles] = useState<ProjectFile[]>([]);
112
+ const [uploading, setUploading] = useState<UploadingFile[]>([]);
113
+ const [loadingFiles, setLoadingFiles] = useState(false);
114
+ const [deletingId, setDeletingId] = useState<number | null>(null);
115
+ const [isDraggingOver, setIsDraggingOver] = useState(false);
116
+
117
+ const inputRef = useRef<HTMLInputElement>(null);
118
+
119
+ // ── Fetch existing files ──────────────────────────────────────────────────
120
+
121
+ const fetchFiles = useCallback(async () => {
122
+ setLoadingFiles(true);
123
+ try {
124
+ const res = await request<ProjectFile[]>({
125
+ url: `/operations/projects/${projectId}/files`,
126
+ method: 'GET',
127
+ });
128
+ setFiles((res.data as ProjectFile[]) ?? []);
129
+ } catch {
130
+ // ignore
131
+ } finally {
132
+ setLoadingFiles(false);
133
+ }
134
+ }, [projectId, request]);
135
+
136
+ useEffect(() => {
137
+ void fetchFiles();
138
+ }, [fetchFiles]);
139
+
140
+ // ── Upload handler ────────────────────────────────────────────────────────
141
+
142
+ const uploadFile = useCallback(
143
+ async (file: File) => {
144
+ const key = `${file.name}-${Date.now()}`;
145
+ setUploading((prev) => [
146
+ ...prev,
147
+ { key, filename: file.name, progress: 0 },
148
+ ]);
149
+
150
+ try {
151
+ const formData = new FormData();
152
+ formData.append('file', file);
153
+
154
+ const res = await (request as any)({
155
+ url: `/operations/projects/${projectId}/files`,
156
+ method: 'POST',
157
+ data: formData,
158
+ headers: { 'Content-Type': 'multipart/form-data' },
159
+ onUploadProgress: (e: { loaded: number; total?: number }) => {
160
+ if (!e.total) return;
161
+ const pct = Math.round((e.loaded * 100) / e.total);
162
+ setUploading((prev) =>
163
+ prev.map((u) => (u.key === key ? { ...u, progress: pct } : u))
164
+ );
165
+ },
166
+ });
167
+
168
+ if (res?.data) {
169
+ await fetchFiles();
170
+ }
171
+ } catch {
172
+ setUploading((prev) =>
173
+ prev.map((u) =>
174
+ u.key === key ? { ...u, error: t('uploadError') } : u
175
+ )
176
+ );
177
+ setTimeout(() => {
178
+ setUploading((prev) => prev.filter((u) => u.key !== key));
179
+ }, 3000);
180
+ return;
181
+ }
182
+
183
+ setUploading((prev) => prev.filter((u) => u.key !== key));
184
+ },
185
+ [projectId, request, fetchFiles, t]
186
+ );
187
+
188
+ const handleFiles = useCallback(
189
+ (fileList: FileList | null) => {
190
+ if (!fileList) return;
191
+ Array.from(fileList).forEach((f) => void uploadFile(f));
192
+ if (inputRef.current) inputRef.current.value = '';
193
+ },
194
+ [uploadFile]
195
+ );
196
+
197
+ // ── Delete handler ────────────────────────────────────────────────────────
198
+
199
+ const handleDelete = useCallback(
200
+ async (relationId: number) => {
201
+ setDeletingId(relationId);
202
+ try {
203
+ await request({
204
+ url: `/operations/projects/${projectId}/files/${relationId}`,
205
+ method: 'DELETE',
206
+ });
207
+ setFiles((prev) => prev.filter((f) => f.id !== relationId));
208
+ } catch {
209
+ // ignore
210
+ } finally {
211
+ setDeletingId(null);
212
+ }
213
+ },
214
+ [projectId, request]
215
+ );
216
+
217
+ // ── Drag and drop ─────────────────────────────────────────────────────────
218
+
219
+ const handleDragOver = (e: React.DragEvent) => {
220
+ e.preventDefault();
221
+ setIsDraggingOver(true);
222
+ };
223
+
224
+ const handleDragLeave = () => setIsDraggingOver(false);
225
+
226
+ const handleDrop = (e: React.DragEvent) => {
227
+ e.preventDefault();
228
+ setIsDraggingOver(false);
229
+ handleFiles(e.dataTransfer.files);
230
+ };
231
+
232
+ // ── Render ────────────────────────────────────────────────────────────────
233
+
234
+ const isEmpty = files.length === 0 && uploading.length === 0;
235
+
236
+ return (
237
+ <div className="space-y-3">
238
+ {/* Drop zone */}
239
+ <div
240
+ role="button"
241
+ tabIndex={0}
242
+ aria-label={t('dropzone.ariaLabel')}
243
+ className={[
244
+ 'flex cursor-pointer flex-col items-center justify-center gap-2 rounded-xl border-2 border-dashed px-4 py-5 text-sm transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50',
245
+ isDraggingOver
246
+ ? 'border-primary bg-primary/5 text-primary'
247
+ : 'border-border bg-muted/30 text-muted-foreground hover:border-primary/50 hover:bg-muted/50',
248
+ ].join(' ')}
249
+ onClick={() => inputRef.current?.click()}
250
+ onKeyDown={(e) => {
251
+ if (e.key === 'Enter' || e.key === ' ') {
252
+ e.preventDefault();
253
+ inputRef.current?.click();
254
+ }
255
+ }}
256
+ onDragOver={handleDragOver}
257
+ onDragLeave={handleDragLeave}
258
+ onDrop={handleDrop}
259
+ >
260
+ <UploadCloud className="size-6 shrink-0 opacity-60" />
261
+ <span className="text-center text-xs leading-relaxed">
262
+ {isDraggingOver ? t('dropzone.dragging') : t('dropzone.idle')}
263
+ </span>
264
+ <input
265
+ ref={inputRef}
266
+ type="file"
267
+ multiple
268
+ className="hidden"
269
+ onChange={(e) => handleFiles(e.target.files)}
270
+ />
271
+ </div>
272
+
273
+ {/* Upload progress items */}
274
+ {uploading.map((u) => (
275
+ <div
276
+ key={u.key}
277
+ className="flex items-center gap-3 rounded-xl border bg-muted/30 px-3 py-2"
278
+ >
279
+ <Loader2 className="size-4 shrink-0 animate-spin text-primary" />
280
+ <div className="min-w-0 flex-1">
281
+ <p className="truncate text-xs font-medium">{u.filename}</p>
282
+ {u.error ? (
283
+ <p className="text-[10px] text-destructive">{u.error}</p>
284
+ ) : (
285
+ <div className="mt-1 h-1 w-full overflow-hidden rounded-full bg-muted">
286
+ <div
287
+ className="h-full rounded-full bg-primary transition-all duration-200"
288
+ style={{ width: `${u.progress}%` }}
289
+ />
290
+ </div>
291
+ )}
292
+ </div>
293
+ <span className="shrink-0 text-[10px] tabular-nums text-muted-foreground">
294
+ {u.error ? t('error') : `${u.progress}%`}
295
+ </span>
296
+ </div>
297
+ ))}
298
+
299
+ {/* Loading skeleton */}
300
+ {loadingFiles && files.length === 0 && uploading.length === 0 ? (
301
+ <div className="space-y-2">
302
+ {[1, 2].map((i) => (
303
+ <div
304
+ key={i}
305
+ className="h-12 animate-pulse rounded-xl border bg-muted/30"
306
+ />
307
+ ))}
308
+ </div>
309
+ ) : null}
310
+
311
+ {/* Empty state */}
312
+ {!loadingFiles && isEmpty ? (
313
+ <div className="flex items-center gap-2 rounded-xl border border-dashed bg-muted/10 px-3 py-3 text-xs text-muted-foreground">
314
+ <Paperclip className="size-3.5 shrink-0" />
315
+ {t('empty')}
316
+ </div>
317
+ ) : null}
318
+
319
+ {/* File list */}
320
+ {files.map((file) => {
321
+ const Icon = getFileIcon(file.mimetype, file.filename);
322
+ const isDeleting = deletingId === file.id;
323
+ return (
324
+ <div
325
+ key={file.id}
326
+ className="group flex items-center gap-3 rounded-xl border bg-card px-3 py-2 transition hover:border-primary/30 hover:bg-muted/30"
327
+ >
328
+ <Icon className="size-5 shrink-0 text-muted-foreground" />
329
+ <div className="min-w-0 flex-1">
330
+ <p className="truncate text-xs font-medium leading-tight">
331
+ {file.filename}
332
+ </p>
333
+ <p className="text-[10px] text-muted-foreground">
334
+ {formatBytes(file.size)}
335
+ </p>
336
+ </div>
337
+ <div className="flex shrink-0 items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100">
338
+ <Button
339
+ type="button"
340
+ variant="ghost"
341
+ size="icon"
342
+ className="size-7 rounded-lg"
343
+ title={t('actions.openInNewTab')}
344
+ onClick={() =>
345
+ window.open(getFileOpenUrl(file.file_id), '_blank')
346
+ }
347
+ >
348
+ <ExternalLink className="size-3.5" />
349
+ </Button>
350
+ <Button
351
+ type="button"
352
+ variant="ghost"
353
+ size="icon"
354
+ className="size-7 rounded-lg text-destructive hover:bg-destructive/10 hover:text-destructive"
355
+ title={t('actions.removeFile')}
356
+ disabled={isDeleting}
357
+ onClick={() => void handleDelete(file.id)}
358
+ >
359
+ {isDeleting ? (
360
+ <Loader2 className="size-3.5 animate-spin" />
361
+ ) : (
362
+ <Trash2 className="size-3.5" />
363
+ )}
364
+ </Button>
365
+ </div>
366
+ </div>
367
+ );
368
+ })}
369
+ </div>
370
+ );
371
+ }