@hed-hog/operations 0.0.330 → 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 (281) 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 +34 -9
  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 +182 -268
  146. package/dist/operations.service.d.ts.map +1 -1
  147. package/dist/operations.service.js +2147 -1337
  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_item.yaml +25 -25
  153. package/hedhog/data/route.yaml +61 -0
  154. package/hedhog/frontend/app/_components/collaborator-form-screen.tsx.ejs +39 -99
  155. package/hedhog/frontend/app/_components/collaborator-picker.tsx.ejs +158 -0
  156. package/hedhog/frontend/app/_components/my-project-summary-screen.tsx.ejs +314 -116
  157. package/hedhog/frontend/app/_components/project-assignments-tab.tsx.ejs +434 -449
  158. package/hedhog/frontend/app/_components/project-details-screen.tsx.ejs +289 -412
  159. package/hedhog/frontend/app/_components/project-file-attachments.tsx.ejs +371 -0
  160. package/hedhog/frontend/app/_components/project-form-screen.tsx.ejs +426 -374
  161. package/hedhog/frontend/app/_components/task-detail-sheet.tsx.ejs +803 -581
  162. package/hedhog/frontend/app/_components/task-file-attachments.tsx.ejs +4 -1
  163. package/hedhog/frontend/app/_components/task-form-fields.tsx.ejs +406 -0
  164. package/hedhog/frontend/app/_components/task-form-sheet.tsx.ejs +629 -784
  165. package/hedhog/frontend/app/_components/task-info-display.tsx.ejs +137 -0
  166. package/hedhog/frontend/app/_components/timesheet-entry-create-sheet.tsx.ejs +306 -0
  167. package/hedhog/frontend/app/_lib/api.ts.ejs +480 -476
  168. package/hedhog/frontend/app/_lib/types.ts.ejs +66 -5
  169. package/hedhog/frontend/app/_lib/utils/format.ts.ejs +0 -2
  170. package/hedhog/frontend/app/_lib/utils/task-ui.ts.ejs +43 -0
  171. package/hedhog/frontend/app/approvals/page.tsx.ejs +6 -1
  172. package/hedhog/frontend/app/collaborator-types/page.tsx.ejs +6 -1
  173. package/hedhog/frontend/app/collaborators/page.tsx.ejs +59 -8
  174. package/hedhog/frontend/app/contracts/page.tsx.ejs +29 -8
  175. package/hedhog/frontend/app/dashboard/widgets/CapacityDistribution.tsx.ejs +84 -0
  176. package/hedhog/frontend/app/dashboard/widgets/EffortByProject.tsx.ejs +85 -0
  177. package/hedhog/frontend/app/dashboard/widgets/HeadcountByArea.tsx.ejs +101 -0
  178. package/hedhog/frontend/app/dashboard/widgets/ManagedProjectsStatus.tsx.ejs +113 -0
  179. package/hedhog/frontend/app/dashboard/widgets/MyHoursPeriodKpi.tsx.ejs +87 -0
  180. package/hedhog/frontend/app/dashboard/widgets/MyOpenRequestsKpi.tsx.ejs +97 -0
  181. package/hedhog/frontend/app/dashboard/widgets/MyPendingRequestsList.tsx.ejs +99 -0
  182. package/hedhog/frontend/app/dashboard/widgets/MyProjectAllocationsKpi.tsx.ejs +78 -0
  183. package/hedhog/frontend/app/dashboard/widgets/MyQuickActions.tsx.ejs +130 -0
  184. package/hedhog/frontend/app/dashboard/widgets/MyRelevantDeadlines.tsx.ejs +144 -0
  185. package/hedhog/frontend/app/dashboard/widgets/MyTimesheetStatusKpi.tsx.ejs +78 -0
  186. package/hedhog/frontend/app/dashboard/widgets/MyWeeklyJourney.tsx.ejs +99 -0
  187. package/hedhog/frontend/app/dashboard/widgets/PortfolioCostsKpi.tsx.ejs +112 -0
  188. package/hedhog/frontend/app/dashboard/widgets/PortfolioEffortKpi.tsx.ejs +93 -0
  189. package/hedhog/frontend/app/dashboard/widgets/PortfolioProjectsKpi.tsx.ejs +96 -0
  190. package/hedhog/frontend/app/dashboard/widgets/PortfolioRiskKpi.tsx.ejs +115 -0
  191. package/hedhog/frontend/app/dashboard/widgets/ProjectStatusOverview.tsx.ejs +120 -0
  192. package/hedhog/frontend/app/dashboard/widgets/StrategicDeadlines.tsx.ejs +146 -0
  193. package/hedhog/frontend/app/dashboard/widgets/TeamApprovalQueue.tsx.ejs +108 -0
  194. package/hedhog/frontend/app/dashboard/widgets/TeamCapacityKpi.tsx.ejs +97 -0
  195. package/hedhog/frontend/app/dashboard/widgets/TeamHeadcountKpi.tsx.ejs +100 -0
  196. package/hedhog/frontend/app/dashboard/widgets/TeamHoursKpi.tsx.ejs +104 -0
  197. package/hedhog/frontend/app/dashboard/widgets/TeamPendingApprovalsKpi.tsx.ejs +110 -0
  198. package/hedhog/frontend/app/dashboard/widgets/TeamUtilizationOverview.tsx.ejs +115 -0
  199. package/hedhog/frontend/app/dashboard/widgets/TeamWorkloadAlerts.tsx.ejs +117 -0
  200. package/hedhog/frontend/app/dashboard/widgets/index.ts.ejs +26 -0
  201. package/hedhog/frontend/app/departments/page.tsx.ejs +6 -1
  202. package/hedhog/frontend/app/my-projects/page.tsx.ejs +14 -10
  203. package/hedhog/frontend/app/my-tasks/page.tsx.ejs +328 -105
  204. package/hedhog/frontend/app/project-cost-categories/page.tsx.ejs +58 -52
  205. package/hedhog/frontend/app/project-cost-types/page.tsx.ejs +58 -51
  206. package/hedhog/frontend/app/projects/page.tsx.ejs +376 -30
  207. package/hedhog/frontend/app/schedule-adjustments/page.tsx.ejs +6 -1
  208. package/hedhog/frontend/app/time-off/page.tsx.ejs +6 -1
  209. package/hedhog/frontend/app/timesheets/page.tsx.ejs +10 -4
  210. package/hedhog/frontend/messages/en.json +238 -46
  211. package/hedhog/frontend/messages/operations/en.json +61 -52
  212. package/hedhog/frontend/messages/operations/pt.json +59 -43
  213. package/hedhog/frontend/messages/pt.json +238 -46
  214. package/hedhog/frontend/widgets/capacity-distribution.tsx.ejs +17 -0
  215. package/hedhog/frontend/widgets/effort-by-project.tsx.ejs +17 -0
  216. package/hedhog/frontend/widgets/headcount-by-area.tsx.ejs +17 -0
  217. package/hedhog/frontend/widgets/index.ts.ejs +25 -0
  218. package/hedhog/frontend/widgets/managed-projects-status.tsx.ejs +17 -0
  219. package/hedhog/frontend/widgets/my-hours-period-kpi.tsx.ejs +17 -0
  220. package/hedhog/frontend/widgets/my-open-requests-kpi.tsx.ejs +17 -0
  221. package/hedhog/frontend/widgets/my-pending-requests-list.tsx.ejs +17 -0
  222. package/hedhog/frontend/widgets/my-project-allocations-kpi.tsx.ejs +17 -0
  223. package/hedhog/frontend/widgets/my-quick-actions.tsx.ejs +17 -0
  224. package/hedhog/frontend/widgets/my-relevant-deadlines.tsx.ejs +17 -0
  225. package/hedhog/frontend/widgets/my-timesheet-status-kpi.tsx.ejs +17 -0
  226. package/hedhog/frontend/widgets/my-weekly-journey.tsx.ejs +17 -0
  227. package/hedhog/frontend/widgets/portfolio-costs-kpi.tsx.ejs +17 -0
  228. package/hedhog/frontend/widgets/portfolio-effort-kpi.tsx.ejs +17 -0
  229. package/hedhog/frontend/widgets/portfolio-projects-kpi.tsx.ejs +17 -0
  230. package/hedhog/frontend/widgets/portfolio-risk-kpi.tsx.ejs +17 -0
  231. package/hedhog/frontend/widgets/project-status-overview.tsx.ejs +17 -0
  232. package/hedhog/frontend/widgets/shared-operations-widget.tsx.ejs +170 -0
  233. package/hedhog/frontend/widgets/strategic-deadlines.tsx.ejs +17 -0
  234. package/hedhog/frontend/widgets/team-approval-queue.tsx.ejs +17 -0
  235. package/hedhog/frontend/widgets/team-capacity-kpi.tsx.ejs +17 -0
  236. package/hedhog/frontend/widgets/team-headcount-kpi.tsx.ejs +17 -0
  237. package/hedhog/frontend/widgets/team-hours-kpi.tsx.ejs +17 -0
  238. package/hedhog/frontend/widgets/team-pending-approvals-kpi.tsx.ejs +17 -0
  239. package/hedhog/frontend/widgets/team-utilization-overview.tsx.ejs +17 -0
  240. package/hedhog/frontend/widgets/team-workload-alerts.tsx.ejs +17 -0
  241. package/hedhog/table/operations_collaborator.yaml +8 -13
  242. package/hedhog/table/operations_project.yaml +1 -1
  243. package/hedhog/table/operations_project_file.yaml +23 -0
  244. package/hedhog/table/operations_task.yaml +76 -69
  245. package/hedhog/table/operations_task_activity.yaml +51 -0
  246. package/package.json +6 -5
  247. package/src/controllers/operations-projects.controller.ts +41 -8
  248. package/src/controllers/operations-tasks.controller.ts +156 -166
  249. package/src/dashboard/README.md +214 -0
  250. package/src/dashboard/components/DashboardLayout.tsx +131 -0
  251. package/src/dashboard/components/widget-registry.ts +255 -0
  252. package/src/dashboard/hooks/useDashboardData.ts +29 -0
  253. package/src/dashboard/types/widgets.types.ts +237 -0
  254. package/src/dashboard/widgets/CapacityDistribution.tsx +56 -0
  255. package/src/dashboard/widgets/EffortByProject.tsx +51 -0
  256. package/src/dashboard/widgets/HeadcountByArea.tsx +57 -0
  257. package/src/dashboard/widgets/ManagedProjectsStatus.tsx +53 -0
  258. package/src/dashboard/widgets/MyHoursPeriodKpi.tsx +87 -0
  259. package/src/dashboard/widgets/MyOpenRequestsKpi.tsx +51 -0
  260. package/src/dashboard/widgets/MyPendingRequestsList.tsx +63 -0
  261. package/src/dashboard/widgets/MyProjectAllocationsKpi.tsx +57 -0
  262. package/src/dashboard/widgets/MyQuickActions.tsx +62 -0
  263. package/src/dashboard/widgets/MyRelevantDeadlines.tsx +84 -0
  264. package/src/dashboard/widgets/MyTimesheetStatusKpi.tsx +65 -0
  265. package/src/dashboard/widgets/MyWeeklyJourney.tsx +57 -0
  266. package/src/dashboard/widgets/PortfolioCostsKpi.tsx +48 -0
  267. package/src/dashboard/widgets/PortfolioEffortKpi.tsx +41 -0
  268. package/src/dashboard/widgets/PortfolioRiskKpi.tsx +50 -0
  269. package/src/dashboard/widgets/ProjectStatusOverview.tsx +52 -0
  270. package/src/dashboard/widgets/StrategicDeadlines.tsx +93 -0
  271. package/src/dashboard/widgets/TeamApprovalQueue.tsx +70 -0
  272. package/src/dashboard/widgets/TeamCapacityKpi.tsx +50 -0
  273. package/src/dashboard/widgets/TeamHoursKpi.tsx +51 -0
  274. package/src/dashboard/widgets/TeamPendingApprovalsKpi.tsx +53 -0
  275. package/src/dashboard/widgets/TeamUtilizationOverview.tsx +62 -0
  276. package/src/dashboard/widgets/TeamWorkloadAlerts.tsx +81 -0
  277. package/src/dashboard/widgets/index.ts +26 -0
  278. package/src/dto/create-collaborator.dto.ts +4 -11
  279. package/src/index.ts +3 -0
  280. package/src/operations.service.spec.ts +988 -764
  281. package/src/operations.service.ts +4277 -2535
@@ -1,476 +1,480 @@
1
- type RequestFn = (input: {
2
- url: string;
3
- method: string;
4
- data?: unknown;
5
- }) => Promise<{ data: unknown }>;
6
-
7
- export function getOperationsErrorMessage(error: unknown, fallback: string) {
8
- if (error && typeof error === 'object') {
9
- const requestError = error as {
10
- message?: string;
11
- response?: {
12
- data?: {
13
- message?: string | string[];
14
- };
15
- };
16
- };
17
-
18
- const message =
19
- requestError.response?.data?.message ?? requestError.message;
20
-
21
- if (Array.isArray(message)) {
22
- const combined = message.filter(Boolean).join(' ');
23
- if (combined.trim()) {
24
- return combined;
25
- }
26
- }
27
-
28
- if (typeof message === 'string' && message.trim()) {
29
- return message;
30
- }
31
- }
32
-
33
- return fallback;
34
- }
35
-
36
- export async function fetchOperations<T>(request: RequestFn, url: string) {
37
- const response = await request({
38
- url,
39
- method: 'GET',
40
- });
41
-
42
- return response.data as T;
43
- }
44
-
45
- export async function mutateOperations<T>(
46
- request: RequestFn,
47
- url: string,
48
- method: 'POST' | 'PATCH' | 'DELETE',
49
- data?: unknown
50
- ) {
51
- const response = await request({
52
- url,
53
- method,
54
- data,
55
- });
56
-
57
- return response.data as T;
58
- }
59
-
60
- // ─── Cost Types ───────────────────────────────────────────────────────────────
61
-
62
- export type CostType = {
63
- id: number;
64
- slug: string;
65
- name: string;
66
- code?: string | null;
67
- category?: string | null;
68
- description?: string | null;
69
- defaultRecurrence?: 'monthly' | 'one_time' | 'yearly' | null;
70
- isAllocatable?: boolean | null;
71
- isDepreciable?: boolean | null;
72
- isActive: boolean;
73
- };
74
-
75
- export function fetchCostTypes(
76
- request: RequestFn,
77
- args: {
78
- search?: string;
79
- active?: boolean;
80
- page?: number;
81
- pageSize?: number;
82
- } = {}
83
- ) {
84
- const { search, active, page, pageSize } = args;
85
- const params = new URLSearchParams();
86
- if (search?.trim()) {
87
- params.set('search', search.trim());
88
- }
89
- if (active !== undefined) {
90
- params.set('active', String(active));
91
- }
92
- if (page !== undefined) {
93
- params.set('page', String(page));
94
- }
95
- if (pageSize !== undefined) {
96
- params.set('pageSize', String(pageSize));
97
- }
98
- const qs = params.toString();
99
- return fetchOperations<CostType[]>(
100
- request,
101
- qs ? `/operations/cost-types?${qs}` : '/operations/cost-types'
102
- );
103
- }
104
-
105
- export function createCostType(
106
- request: RequestFn,
107
- data: {
108
- name: string;
109
- slug?: string | null;
110
- code?: string | null;
111
- category?: string | null;
112
- description?: string | null;
113
- defaultRecurrence?: string | null;
114
- isAllocatable?: boolean | null;
115
- isDepreciable?: boolean | null;
116
- isActive?: boolean;
117
- }
118
- ) {
119
- return mutateOperations<CostType>(
120
- request,
121
- '/operations/cost-types',
122
- 'POST',
123
- data
124
- );
125
- }
126
-
127
- // ─── Collaborators ────────────────────────────────────────────────────────────
128
-
129
- export function fetchCollaborators(request: RequestFn) {
130
- return fetchOperations<import('./types').OperationsCollaborator[]>(
131
- request,
132
- '/operations/collaborators'
133
- );
134
- }
135
-
136
- // ─── Collaborator Costs ───────────────────────────────────────────────────────
137
-
138
- export type CollaboratorCost = {
139
- id: number;
140
- collaboratorId: number;
141
- costTypeId: number;
142
- costTypeName: string;
143
- costTypeSlug: string;
144
- amount: string;
145
- currency: string;
146
- recurrence: 'one_time' | 'monthly' | 'yearly';
147
- allocatable?: boolean;
148
- /** ISO date string — mapped to startDate going forward */
149
- referenceDate: string | null;
150
- startDate?: string | null;
151
- endDate?: string | null;
152
- depreciationMonths?: number | null;
153
- description: string | null;
154
- notes?: string | null;
155
- createdAt: string;
156
- };
157
-
158
- export function fetchCollaboratorCosts(
159
- request: RequestFn,
160
- collaboratorId: number
161
- ) {
162
- return fetchOperations<CollaboratorCost[]>(
163
- request,
164
- `/operations/collaborators/${collaboratorId}/costs`
165
- );
166
- }
167
-
168
- export function createCollaboratorCost(
169
- request: RequestFn,
170
- collaboratorId: number,
171
- data: {
172
- costTypeId: number;
173
- amount: number;
174
- currency?: string;
175
- recurrence?: string;
176
- allocatable?: boolean;
177
- referenceDate?: string | null;
178
- startDate?: string | null;
179
- endDate?: string | null;
180
- depreciationMonths?: number | null;
181
- description?: string | null;
182
- notes?: string | null;
183
- }
184
- ) {
185
- return mutateOperations<CollaboratorCost>(
186
- request,
187
- `/operations/collaborators/${collaboratorId}/costs`,
188
- 'POST',
189
- data
190
- );
191
- }
192
-
193
- export function updateCollaboratorCost(
194
- request: RequestFn,
195
- collaboratorId: number,
196
- costId: number,
197
- data: Partial<{
198
- costTypeId: number;
199
- amount: number;
200
- currency: string;
201
- recurrence: string;
202
- allocatable: boolean;
203
- referenceDate: string | null;
204
- startDate: string | null;
205
- endDate: string | null;
206
- depreciationMonths: number | null;
207
- description: string | null;
208
- notes: string | null;
209
- }>
210
- ) {
211
- return mutateOperations<CollaboratorCost>(
212
- request,
213
- `/operations/collaborators/${collaboratorId}/costs/${costId}`,
214
- 'PATCH',
215
- data
216
- );
217
- }
218
-
219
- export function deleteCollaboratorCost(
220
- request: RequestFn,
221
- collaboratorId: number,
222
- costId: number
223
- ) {
224
- return mutateOperations<{ success: boolean }>(
225
- request,
226
- `/operations/collaborators/${collaboratorId}/costs/${costId}`,
227
- 'DELETE'
228
- );
229
- }
230
-
231
- // ─── Currencies ───────────────────────────────────────────────────────────────
232
-
233
- export type Currency = Record<string, unknown> & {
234
- id: number;
235
- code: string;
236
- name: string;
237
- symbol: string;
238
- status: 'active' | 'inactive';
239
- };
240
-
241
- export function listCurrencies(
242
- request: RequestFn,
243
- params?: Record<string, string>
244
- ) {
245
- const qs = params ? new URLSearchParams(params).toString() : '';
246
- return fetchOperations<Currency[]>(
247
- request,
248
- qs ? `/finance/currencies?${qs}` : '/finance/currencies'
249
- );
250
- }
251
-
252
- // ─── Project Cost Categories ──────────────────────────────────────────────────
253
-
254
- export function listProjectCostCategories(
255
- request: RequestFn,
256
- params?: Record<string, string>
257
- ) {
258
- const qs = params ? new URLSearchParams(params).toString() : '';
259
- return fetchOperations(
260
- request,
261
- qs
262
- ? `/operations/project-cost-categories?${qs}`
263
- : '/operations/project-cost-categories'
264
- );
265
- }
266
-
267
- export function createProjectCostCategory(request: RequestFn, data: unknown) {
268
- return mutateOperations(
269
- request,
270
- '/operations/project-cost-categories',
271
- 'POST',
272
- data
273
- );
274
- }
275
-
276
- export function updateProjectCostCategory(
277
- request: RequestFn,
278
- id: number,
279
- data: unknown
280
- ) {
281
- return mutateOperations(
282
- request,
283
- `/operations/project-cost-categories/${id}`,
284
- 'PATCH',
285
- data
286
- );
287
- }
288
-
289
- export function deleteProjectCostCategory(request: RequestFn, id: number) {
290
- return mutateOperations(
291
- request,
292
- `/operations/project-cost-categories/${id}`,
293
- 'DELETE'
294
- );
295
- }
296
-
297
- // ─── Project Cost Types ───────────────────────────────────────────────────────
298
-
299
- export function listProjectCostTypes(
300
- request: RequestFn,
301
- params?: Record<string, string>
302
- ) {
303
- const qs = params ? new URLSearchParams(params).toString() : '';
304
- return fetchOperations(
305
- request,
306
- qs
307
- ? `/operations/project-cost-types?${qs}`
308
- : '/operations/project-cost-types'
309
- );
310
- }
311
-
312
- export function createProjectCostType(request: RequestFn, data: unknown) {
313
- return mutateOperations(
314
- request,
315
- '/operations/project-cost-types',
316
- 'POST',
317
- data
318
- );
319
- }
320
-
321
- export function updateProjectCostType(
322
- request: RequestFn,
323
- id: number,
324
- data: unknown
325
- ) {
326
- return mutateOperations(
327
- request,
328
- `/operations/project-cost-types/${id}`,
329
- 'PATCH',
330
- data
331
- );
332
- }
333
-
334
- export function deleteProjectCostType(request: RequestFn, id: number) {
335
- return mutateOperations(
336
- request,
337
- `/operations/project-cost-types/${id}`,
338
- 'DELETE'
339
- );
340
- }
341
-
342
- // ─── Project Costs ────────────────────────────────────────────────────────────
343
-
344
- export function listProjectCosts(
345
- request: RequestFn,
346
- projectId: number,
347
- params?: Record<string, string>
348
- ) {
349
- const qs = params ? new URLSearchParams(params).toString() : '';
350
- return fetchOperations(
351
- request,
352
- qs
353
- ? `/operations/projects/${projectId}/costs?${qs}`
354
- : `/operations/projects/${projectId}/costs`
355
- );
356
- }
357
-
358
- export function getProjectCostsSummary(request: RequestFn, projectId: number) {
359
- return fetchOperations(
360
- request,
361
- `/operations/projects/${projectId}/costs/summary`
362
- );
363
- }
364
-
365
- export function getFullProjectCostSummary(
366
- request: RequestFn,
367
- projectId: number
368
- ) {
369
- return fetchOperations(
370
- request,
371
- `/operations/projects/${projectId}/cost-summary`
372
- );
373
- }
374
-
375
- export function createProjectCost(
376
- request: RequestFn,
377
- projectId: number,
378
- data: unknown
379
- ) {
380
- return mutateOperations(
381
- request,
382
- `/operations/projects/${projectId}/costs`,
383
- 'POST',
384
- data
385
- );
386
- }
387
-
388
- export function updateProjectCost(
389
- request: RequestFn,
390
- projectId: number,
391
- costId: number,
392
- data: unknown
393
- ) {
394
- return mutateOperations(
395
- request,
396
- `/operations/projects/${projectId}/costs/${costId}`,
397
- 'PATCH',
398
- data
399
- );
400
- }
401
-
402
- export function deleteProjectCost(
403
- request: RequestFn,
404
- projectId: number,
405
- costId: number
406
- ) {
407
- return mutateOperations(
408
- request,
409
- `/operations/projects/${projectId}/costs/${costId}`,
410
- 'DELETE'
411
- );
412
- }
413
-
414
- export function getProjectCostReport(
415
- request: RequestFn,
416
- projectId: number,
417
- filters?: Record<string, unknown>
418
- ) {
419
- const params = filters
420
- ? '?' +
421
- new URLSearchParams(
422
- Object.entries(filters)
423
- .filter(([, v]) => v !== undefined && v !== null)
424
- .map(([k, v]) => [k, String(v)])
425
- ).toString()
426
- : '';
427
- return fetchOperations(
428
- request,
429
- `/operations/projects/${projectId}/costs/report${params}`
430
- );
431
- }
432
-
433
- // ─── Task Comments ────────────────────────────────────────────────────────────
434
-
435
- export function fetchTaskComments(request: RequestFn, taskId: number) {
436
- return fetchOperations(request, `/operations/tasks/${taskId}/comments`);
437
- }
438
-
439
- export function createTaskComment(
440
- request: RequestFn,
441
- taskId: number,
442
- content: string
443
- ) {
444
- return mutateOperations(
445
- request,
446
- `/operations/tasks/${taskId}/comments`,
447
- 'POST',
448
- { content }
449
- );
450
- }
451
-
452
- export function updateTaskComment(
453
- request: RequestFn,
454
- taskId: number,
455
- commentId: number,
456
- content: string
457
- ) {
458
- return mutateOperations(
459
- request,
460
- `/operations/tasks/${taskId}/comments/${commentId}`,
461
- 'PATCH',
462
- { content }
463
- );
464
- }
465
-
466
- export function deleteTaskComment(
467
- request: RequestFn,
468
- taskId: number,
469
- commentId: number
470
- ) {
471
- return mutateOperations(
472
- request,
473
- `/operations/tasks/${taskId}/comments/${commentId}`,
474
- 'DELETE'
475
- );
476
- }
1
+ type RequestFn = (input: {
2
+ url: string;
3
+ method: string;
4
+ data?: unknown;
5
+ }) => Promise<{ data: unknown }>;
6
+
7
+ export function getOperationsErrorMessage(error: unknown, fallback: string) {
8
+ if (error && typeof error === 'object') {
9
+ const requestError = error as {
10
+ message?: string;
11
+ response?: {
12
+ data?: {
13
+ message?: string | string[];
14
+ };
15
+ };
16
+ };
17
+
18
+ const message =
19
+ requestError.response?.data?.message ?? requestError.message;
20
+
21
+ if (Array.isArray(message)) {
22
+ const combined = message.filter(Boolean).join(' ');
23
+ if (combined.trim()) {
24
+ return combined;
25
+ }
26
+ }
27
+
28
+ if (typeof message === 'string' && message.trim()) {
29
+ return message;
30
+ }
31
+ }
32
+
33
+ return fallback;
34
+ }
35
+
36
+ export async function fetchOperations<T>(request: RequestFn, url: string) {
37
+ const response = await request({
38
+ url,
39
+ method: 'GET',
40
+ });
41
+
42
+ return response.data as T;
43
+ }
44
+
45
+ export async function mutateOperations<T>(
46
+ request: RequestFn,
47
+ url: string,
48
+ method: 'POST' | 'PATCH' | 'DELETE',
49
+ data?: unknown
50
+ ) {
51
+ const response = await request({
52
+ url,
53
+ method,
54
+ data,
55
+ });
56
+
57
+ return response.data as T;
58
+ }
59
+
60
+ // ─── Cost Types ───────────────────────────────────────────────────────────────
61
+
62
+ export type CostType = {
63
+ id: number;
64
+ slug: string;
65
+ name: string;
66
+ code?: string | null;
67
+ category?: string | null;
68
+ description?: string | null;
69
+ defaultRecurrence?: 'monthly' | 'one_time' | 'yearly' | null;
70
+ isAllocatable?: boolean | null;
71
+ isDepreciable?: boolean | null;
72
+ isActive: boolean;
73
+ };
74
+
75
+ export function fetchCostTypes(
76
+ request: RequestFn,
77
+ args: {
78
+ search?: string;
79
+ active?: boolean;
80
+ page?: number;
81
+ pageSize?: number;
82
+ } = {}
83
+ ) {
84
+ const { search, active, page, pageSize } = args;
85
+ const params = new URLSearchParams();
86
+ if (search?.trim()) {
87
+ params.set('search', search.trim());
88
+ }
89
+ if (active !== undefined) {
90
+ params.set('active', String(active));
91
+ }
92
+ if (page !== undefined) {
93
+ params.set('page', String(page));
94
+ }
95
+ if (pageSize !== undefined) {
96
+ params.set('pageSize', String(pageSize));
97
+ }
98
+ const qs = params.toString();
99
+ return fetchOperations<CostType[]>(
100
+ request,
101
+ qs ? `/operations/cost-types?${qs}` : '/operations/cost-types'
102
+ );
103
+ }
104
+
105
+ export function createCostType(
106
+ request: RequestFn,
107
+ data: {
108
+ name: string;
109
+ slug?: string | null;
110
+ code?: string | null;
111
+ category?: string | null;
112
+ description?: string | null;
113
+ defaultRecurrence?: string | null;
114
+ isAllocatable?: boolean | null;
115
+ isDepreciable?: boolean | null;
116
+ isActive?: boolean;
117
+ }
118
+ ) {
119
+ return mutateOperations<CostType>(
120
+ request,
121
+ '/operations/cost-types',
122
+ 'POST',
123
+ data
124
+ );
125
+ }
126
+
127
+ // ─── Collaborators ────────────────────────────────────────────────────────────
128
+
129
+ export function fetchCollaborators(request: RequestFn) {
130
+ return fetchOperations<import('./types').OperationsCollaborator[]>(
131
+ request,
132
+ '/operations/collaborators'
133
+ );
134
+ }
135
+
136
+ // ─── Collaborator Costs ───────────────────────────────────────────────────────
137
+
138
+ export type CollaboratorCost = {
139
+ id: number;
140
+ collaboratorId: number;
141
+ costTypeId: number;
142
+ costTypeName: string;
143
+ costTypeSlug: string;
144
+ amount: string;
145
+ currency: string;
146
+ recurrence: 'one_time' | 'monthly' | 'yearly';
147
+ allocatable?: boolean;
148
+ /** ISO date string — mapped to startDate going forward */
149
+ referenceDate: string | null;
150
+ startDate?: string | null;
151
+ endDate?: string | null;
152
+ depreciationMonths?: number | null;
153
+ description: string | null;
154
+ notes?: string | null;
155
+ createdAt: string;
156
+ };
157
+
158
+ export function fetchCollaboratorCosts(
159
+ request: RequestFn,
160
+ collaboratorId: number
161
+ ) {
162
+ return fetchOperations<CollaboratorCost[]>(
163
+ request,
164
+ `/operations/collaborators/${collaboratorId}/costs`
165
+ );
166
+ }
167
+
168
+ export function createCollaboratorCost(
169
+ request: RequestFn,
170
+ collaboratorId: number,
171
+ data: {
172
+ costTypeId: number;
173
+ amount: number;
174
+ currency?: string;
175
+ recurrence?: string;
176
+ allocatable?: boolean;
177
+ referenceDate?: string | null;
178
+ startDate?: string | null;
179
+ endDate?: string | null;
180
+ depreciationMonths?: number | null;
181
+ description?: string | null;
182
+ notes?: string | null;
183
+ }
184
+ ) {
185
+ return mutateOperations<CollaboratorCost>(
186
+ request,
187
+ `/operations/collaborators/${collaboratorId}/costs`,
188
+ 'POST',
189
+ data
190
+ );
191
+ }
192
+
193
+ export function updateCollaboratorCost(
194
+ request: RequestFn,
195
+ collaboratorId: number,
196
+ costId: number,
197
+ data: Partial<{
198
+ costTypeId: number;
199
+ amount: number;
200
+ currency: string;
201
+ recurrence: string;
202
+ allocatable: boolean;
203
+ referenceDate: string | null;
204
+ startDate: string | null;
205
+ endDate: string | null;
206
+ depreciationMonths: number | null;
207
+ description: string | null;
208
+ notes: string | null;
209
+ }>
210
+ ) {
211
+ return mutateOperations<CollaboratorCost>(
212
+ request,
213
+ `/operations/collaborators/${collaboratorId}/costs/${costId}`,
214
+ 'PATCH',
215
+ data
216
+ );
217
+ }
218
+
219
+ export function deleteCollaboratorCost(
220
+ request: RequestFn,
221
+ collaboratorId: number,
222
+ costId: number
223
+ ) {
224
+ return mutateOperations<{ success: boolean }>(
225
+ request,
226
+ `/operations/collaborators/${collaboratorId}/costs/${costId}`,
227
+ 'DELETE'
228
+ );
229
+ }
230
+
231
+ // ─── Currencies ───────────────────────────────────────────────────────────────
232
+
233
+ export type Currency = Record<string, unknown> & {
234
+ id: number;
235
+ code: string;
236
+ name: string;
237
+ symbol: string;
238
+ status: 'active' | 'inactive';
239
+ };
240
+
241
+ export function listCurrencies(
242
+ request: RequestFn,
243
+ params?: Record<string, string>
244
+ ) {
245
+ const qs = params ? new URLSearchParams(params).toString() : '';
246
+ return fetchOperations<Currency[]>(
247
+ request,
248
+ qs ? `/finance/currencies?${qs}` : '/finance/currencies'
249
+ );
250
+ }
251
+
252
+ // ─── Project Cost Categories ──────────────────────────────────────────────────
253
+
254
+ export function listProjectCostCategories(
255
+ request: RequestFn,
256
+ params?: Record<string, string>
257
+ ) {
258
+ const qs = params ? new URLSearchParams(params).toString() : '';
259
+ return fetchOperations(
260
+ request,
261
+ qs
262
+ ? `/operations/project-cost-categories?${qs}`
263
+ : '/operations/project-cost-categories'
264
+ );
265
+ }
266
+
267
+ export function createProjectCostCategory(request: RequestFn, data: unknown) {
268
+ return mutateOperations(
269
+ request,
270
+ '/operations/project-cost-categories',
271
+ 'POST',
272
+ data
273
+ );
274
+ }
275
+
276
+ export function updateProjectCostCategory(
277
+ request: RequestFn,
278
+ id: number,
279
+ data: unknown
280
+ ) {
281
+ return mutateOperations(
282
+ request,
283
+ `/operations/project-cost-categories/${id}`,
284
+ 'PATCH',
285
+ data
286
+ );
287
+ }
288
+
289
+ export function deleteProjectCostCategory(request: RequestFn, id: number) {
290
+ return mutateOperations(
291
+ request,
292
+ `/operations/project-cost-categories/${id}`,
293
+ 'DELETE'
294
+ );
295
+ }
296
+
297
+ // ─── Project Cost Types ───────────────────────────────────────────────────────
298
+
299
+ export function listProjectCostTypes(
300
+ request: RequestFn,
301
+ params?: Record<string, string>
302
+ ) {
303
+ const qs = params ? new URLSearchParams(params).toString() : '';
304
+ return fetchOperations(
305
+ request,
306
+ qs
307
+ ? `/operations/project-cost-types?${qs}`
308
+ : '/operations/project-cost-types'
309
+ );
310
+ }
311
+
312
+ export function createProjectCostType(request: RequestFn, data: unknown) {
313
+ return mutateOperations(
314
+ request,
315
+ '/operations/project-cost-types',
316
+ 'POST',
317
+ data
318
+ );
319
+ }
320
+
321
+ export function updateProjectCostType(
322
+ request: RequestFn,
323
+ id: number,
324
+ data: unknown
325
+ ) {
326
+ return mutateOperations(
327
+ request,
328
+ `/operations/project-cost-types/${id}`,
329
+ 'PATCH',
330
+ data
331
+ );
332
+ }
333
+
334
+ export function deleteProjectCostType(request: RequestFn, id: number) {
335
+ return mutateOperations(
336
+ request,
337
+ `/operations/project-cost-types/${id}`,
338
+ 'DELETE'
339
+ );
340
+ }
341
+
342
+ // ─── Project Costs ────────────────────────────────────────────────────────────
343
+
344
+ export function listProjectCosts(
345
+ request: RequestFn,
346
+ projectId: number,
347
+ params?: Record<string, string>
348
+ ) {
349
+ const qs = params ? new URLSearchParams(params).toString() : '';
350
+ return fetchOperations(
351
+ request,
352
+ qs
353
+ ? `/operations/projects/${projectId}/costs?${qs}`
354
+ : `/operations/projects/${projectId}/costs`
355
+ );
356
+ }
357
+
358
+ export function getProjectCostsSummary(request: RequestFn, projectId: number) {
359
+ return fetchOperations(
360
+ request,
361
+ `/operations/projects/${projectId}/costs/summary`
362
+ );
363
+ }
364
+
365
+ export function getFullProjectCostSummary(
366
+ request: RequestFn,
367
+ projectId: number
368
+ ) {
369
+ return fetchOperations(
370
+ request,
371
+ `/operations/projects/${projectId}/cost-summary`
372
+ );
373
+ }
374
+
375
+ export function createProjectCost(
376
+ request: RequestFn,
377
+ projectId: number,
378
+ data: unknown
379
+ ) {
380
+ return mutateOperations(
381
+ request,
382
+ `/operations/projects/${projectId}/costs`,
383
+ 'POST',
384
+ data
385
+ );
386
+ }
387
+
388
+ export function updateProjectCost(
389
+ request: RequestFn,
390
+ projectId: number,
391
+ costId: number,
392
+ data: unknown
393
+ ) {
394
+ return mutateOperations(
395
+ request,
396
+ `/operations/projects/${projectId}/costs/${costId}`,
397
+ 'PATCH',
398
+ data
399
+ );
400
+ }
401
+
402
+ export function deleteProjectCost(
403
+ request: RequestFn,
404
+ projectId: number,
405
+ costId: number
406
+ ) {
407
+ return mutateOperations(
408
+ request,
409
+ `/operations/projects/${projectId}/costs/${costId}`,
410
+ 'DELETE'
411
+ );
412
+ }
413
+
414
+ export function getProjectCostReport(
415
+ request: RequestFn,
416
+ projectId: number,
417
+ filters?: Record<string, unknown>
418
+ ) {
419
+ const params = filters
420
+ ? '?' +
421
+ new URLSearchParams(
422
+ Object.entries(filters)
423
+ .filter(([, v]) => v !== undefined && v !== null)
424
+ .map(([k, v]) => [k, String(v)])
425
+ ).toString()
426
+ : '';
427
+ return fetchOperations(
428
+ request,
429
+ `/operations/projects/${projectId}/costs/report${params}`
430
+ );
431
+ }
432
+
433
+ // ─── Task Comments ────────────────────────────────────────────────────────────
434
+
435
+ export function fetchTaskActivities(request: RequestFn, taskId: number) {
436
+ return fetchOperations(request, `/operations/tasks/${taskId}/activities`);
437
+ }
438
+
439
+ export function fetchTaskComments(request: RequestFn, taskId: number) {
440
+ return fetchOperations(request, `/operations/tasks/${taskId}/comments`);
441
+ }
442
+
443
+ export function createTaskComment(
444
+ request: RequestFn,
445
+ taskId: number,
446
+ content: string
447
+ ) {
448
+ return mutateOperations(
449
+ request,
450
+ `/operations/tasks/${taskId}/comments`,
451
+ 'POST',
452
+ { content }
453
+ );
454
+ }
455
+
456
+ export function updateTaskComment(
457
+ request: RequestFn,
458
+ taskId: number,
459
+ commentId: number,
460
+ content: string
461
+ ) {
462
+ return mutateOperations(
463
+ request,
464
+ `/operations/tasks/${taskId}/comments/${commentId}`,
465
+ 'PATCH',
466
+ { content }
467
+ );
468
+ }
469
+
470
+ export function deleteTaskComment(
471
+ request: RequestFn,
472
+ taskId: number,
473
+ commentId: number
474
+ ) {
475
+ return mutateOperations(
476
+ request,
477
+ `/operations/tasks/${taskId}/comments/${commentId}`,
478
+ 'DELETE'
479
+ );
480
+ }