@burdenoff/microfe-planmagnet 2026.928.3 → 2026.928.5

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 (245) hide show
  1. package/dist/planmagnet/PlanMagnetRoot.d.ts.map +1 -1
  2. package/dist/planmagnet/PlanMagnetRoot.js +126 -84
  3. package/dist/planmagnet/PlanMagnetRoot.js.map +1 -1
  4. package/dist/planmagnet/PlanMagnetRoutes.d.ts.map +1 -1
  5. package/dist/planmagnet/PlanMagnetRoutes.js +192 -64
  6. package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
  7. package/dist/planmagnet/automation/AutomationExecutionsPanel.d.ts +5 -0
  8. package/dist/planmagnet/automation/AutomationExecutionsPanel.d.ts.map +1 -0
  9. package/dist/planmagnet/automation/AutomationExecutionsPanel.js +107 -0
  10. package/dist/planmagnet/automation/AutomationExecutionsPanel.js.map +1 -0
  11. package/dist/planmagnet/automation/AutomationRuleFields.d.ts +29 -0
  12. package/dist/planmagnet/automation/AutomationRuleFields.d.ts.map +1 -0
  13. package/dist/planmagnet/automation/AutomationRuleFields.js +308 -0
  14. package/dist/planmagnet/automation/AutomationRuleFields.js.map +1 -0
  15. package/dist/planmagnet/automation/automationRuleTypes.d.ts +60 -0
  16. package/dist/planmagnet/automation/automationRuleTypes.d.ts.map +1 -0
  17. package/dist/planmagnet/automation/automationRuleTypes.js +113 -0
  18. package/dist/planmagnet/automation/automationRuleTypes.js.map +1 -0
  19. package/dist/planmagnet/board/BulkActions.d.ts +11 -0
  20. package/dist/planmagnet/board/BulkActions.d.ts.map +1 -0
  21. package/dist/planmagnet/board/BulkActions.js +182 -0
  22. package/dist/planmagnet/board/BulkActions.js.map +1 -0
  23. package/dist/planmagnet/board/ProjectBoard.d.ts.map +1 -1
  24. package/dist/planmagnet/board/ProjectBoard.js +289 -254
  25. package/dist/planmagnet/board/ProjectBoard.js.map +1 -1
  26. package/dist/planmagnet/budgets/BudgetControls.d.ts +30 -0
  27. package/dist/planmagnet/budgets/BudgetControls.d.ts.map +1 -0
  28. package/dist/planmagnet/budgets/BudgetControls.js +470 -0
  29. package/dist/planmagnet/budgets/BudgetControls.js.map +1 -0
  30. package/dist/planmagnet/budgets/ExpenseControls.d.ts +27 -0
  31. package/dist/planmagnet/budgets/ExpenseControls.d.ts.map +1 -0
  32. package/dist/planmagnet/budgets/ExpenseControls.js +366 -0
  33. package/dist/planmagnet/budgets/ExpenseControls.js.map +1 -0
  34. package/dist/planmagnet/budgets/ProjectBudgetsSummary.d.ts +5 -0
  35. package/dist/planmagnet/budgets/ProjectBudgetsSummary.d.ts.map +1 -0
  36. package/dist/planmagnet/budgets/ProjectBudgetsSummary.js +112 -0
  37. package/dist/planmagnet/budgets/ProjectBudgetsSummary.js.map +1 -0
  38. package/dist/planmagnet/budgets/budgetMath.d.ts +26 -0
  39. package/dist/planmagnet/budgets/budgetMath.d.ts.map +1 -0
  40. package/dist/planmagnet/budgets/budgetMath.js +49 -0
  41. package/dist/planmagnet/budgets/budgetMath.js.map +1 -0
  42. package/dist/planmagnet/controls/AutomationRuleControls.d.ts +23 -0
  43. package/dist/planmagnet/controls/AutomationRuleControls.d.ts.map +1 -0
  44. package/dist/planmagnet/controls/AutomationRuleControls.js +172 -0
  45. package/dist/planmagnet/controls/AutomationRuleControls.js.map +1 -0
  46. package/dist/planmagnet/controls/CompetitorControls.d.ts +20 -0
  47. package/dist/planmagnet/controls/CompetitorControls.d.ts.map +1 -0
  48. package/dist/planmagnet/controls/CompetitorControls.js +172 -0
  49. package/dist/planmagnet/controls/CompetitorControls.js.map +1 -0
  50. package/dist/planmagnet/controls/CustomFieldControls.d.ts +42 -0
  51. package/dist/planmagnet/controls/CustomFieldControls.d.ts.map +1 -0
  52. package/dist/planmagnet/controls/CustomFieldControls.js +84 -0
  53. package/dist/planmagnet/controls/CustomFieldControls.js.map +1 -0
  54. package/dist/planmagnet/controls/CustomFieldValuesPanel.d.ts +8 -0
  55. package/dist/planmagnet/controls/CustomFieldValuesPanel.d.ts.map +1 -0
  56. package/dist/planmagnet/controls/CustomFieldValuesPanel.js +315 -0
  57. package/dist/planmagnet/controls/CustomFieldValuesPanel.js.map +1 -0
  58. package/dist/planmagnet/controls/FeatureControls.js +53 -53
  59. package/dist/planmagnet/controls/FeatureTriage.js +11 -11
  60. package/dist/planmagnet/controls/ObjectiveControls.js +37 -37
  61. package/dist/planmagnet/controls/Pickers.d.ts +17 -2
  62. package/dist/planmagnet/controls/Pickers.d.ts.map +1 -1
  63. package/dist/planmagnet/controls/Pickers.js +100 -9
  64. package/dist/planmagnet/controls/Pickers.js.map +1 -1
  65. package/dist/planmagnet/controls/PortfolioControls.d.ts +13 -0
  66. package/dist/planmagnet/controls/PortfolioControls.d.ts.map +1 -0
  67. package/dist/planmagnet/controls/PortfolioControls.js +114 -0
  68. package/dist/planmagnet/controls/PortfolioControls.js.map +1 -0
  69. package/dist/planmagnet/controls/ProgramControls.d.ts +25 -0
  70. package/dist/planmagnet/controls/ProgramControls.d.ts.map +1 -0
  71. package/dist/planmagnet/controls/ProgramControls.js +187 -0
  72. package/dist/planmagnet/controls/ProgramControls.js.map +1 -0
  73. package/dist/planmagnet/controls/ProjectControls.d.ts.map +1 -1
  74. package/dist/planmagnet/controls/ProjectControls.js +54 -47
  75. package/dist/planmagnet/controls/ProjectControls.js.map +1 -1
  76. package/dist/planmagnet/controls/ReleaseControls.js +7 -7
  77. package/dist/planmagnet/controls/RiskControls.d.ts +27 -0
  78. package/dist/planmagnet/controls/RiskControls.d.ts.map +1 -0
  79. package/dist/planmagnet/controls/RiskControls.js +346 -0
  80. package/dist/planmagnet/controls/RiskControls.js.map +1 -0
  81. package/dist/planmagnet/controls/TemplateControls.d.ts +15 -0
  82. package/dist/planmagnet/controls/TemplateControls.d.ts.map +1 -0
  83. package/dist/planmagnet/controls/TemplateControls.js +55 -0
  84. package/dist/planmagnet/controls/TemplateControls.js.map +1 -0
  85. package/dist/planmagnet/controls/WorkItemControls.js +1 -1
  86. package/dist/planmagnet/create/CreateDialogs.d.ts +20 -0
  87. package/dist/planmagnet/create/CreateDialogs.d.ts.map +1 -1
  88. package/dist/planmagnet/create/CreateDialogs.js +455 -116
  89. package/dist/planmagnet/create/CreateDialogs.js.map +1 -1
  90. package/dist/planmagnet/dependency/DependencyPanel.d.ts +6 -0
  91. package/dist/planmagnet/dependency/DependencyPanel.d.ts.map +1 -0
  92. package/dist/planmagnet/dependency/DependencyPanel.js +310 -0
  93. package/dist/planmagnet/dependency/DependencyPanel.js.map +1 -0
  94. package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.d.ts +2 -0
  95. package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.d.ts.map +1 -0
  96. package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.js +171 -0
  97. package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.js.map +1 -0
  98. package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.d.ts +2 -0
  99. package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.d.ts.map +1 -0
  100. package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.js +232 -0
  101. package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.js.map +1 -0
  102. package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.d.ts +2 -0
  103. package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.d.ts.map +1 -0
  104. package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.js +93 -0
  105. package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.js.map +1 -0
  106. package/dist/planmagnet/pages/CompetitorsCompetitorDetailPagePage.d.ts +2 -0
  107. package/dist/planmagnet/pages/CompetitorsCompetitorDetailPagePage.d.ts.map +1 -0
  108. package/dist/planmagnet/pages/CompetitorsCompetitorDetailPagePage.js +127 -0
  109. package/dist/planmagnet/pages/CompetitorsCompetitorDetailPagePage.js.map +1 -0
  110. package/dist/planmagnet/pages/CompetitorsCompetitorsPagePage.d.ts +2 -0
  111. package/dist/planmagnet/pages/CompetitorsCompetitorsPagePage.d.ts.map +1 -0
  112. package/dist/planmagnet/pages/CompetitorsCompetitorsPagePage.js +129 -0
  113. package/dist/planmagnet/pages/CompetitorsCompetitorsPagePage.js.map +1 -0
  114. package/dist/planmagnet/pages/CompetitorsCreateCompetitorPagePage.d.ts +2 -0
  115. package/dist/planmagnet/pages/CompetitorsCreateCompetitorPagePage.d.ts.map +1 -0
  116. package/dist/planmagnet/pages/CompetitorsCreateCompetitorPagePage.js +132 -0
  117. package/dist/planmagnet/pages/CompetitorsCreateCompetitorPagePage.js.map +1 -0
  118. package/dist/planmagnet/pages/CompetitorsEditCompetitorPagePage.d.ts +2 -0
  119. package/dist/planmagnet/pages/CompetitorsEditCompetitorPagePage.d.ts.map +1 -0
  120. package/dist/planmagnet/pages/CompetitorsEditCompetitorPagePage.js +181 -0
  121. package/dist/planmagnet/pages/CompetitorsEditCompetitorPagePage.js.map +1 -0
  122. package/dist/planmagnet/pages/PortfoliosCreatePortfolioPagePage.d.ts +2 -0
  123. package/dist/planmagnet/pages/PortfoliosCreatePortfolioPagePage.d.ts.map +1 -0
  124. package/dist/planmagnet/pages/PortfoliosCreatePortfolioPagePage.js +242 -0
  125. package/dist/planmagnet/pages/PortfoliosCreatePortfolioPagePage.js.map +1 -0
  126. package/dist/planmagnet/pages/PortfoliosEditPortfolioPagePage.d.ts +2 -0
  127. package/dist/planmagnet/pages/PortfoliosEditPortfolioPagePage.d.ts.map +1 -0
  128. package/dist/planmagnet/pages/PortfoliosEditPortfolioPagePage.js +302 -0
  129. package/dist/planmagnet/pages/PortfoliosEditPortfolioPagePage.js.map +1 -0
  130. package/dist/planmagnet/pages/PortfoliosPortfolioDetailPagePage.d.ts +2 -0
  131. package/dist/planmagnet/pages/PortfoliosPortfolioDetailPagePage.d.ts.map +1 -0
  132. package/dist/planmagnet/pages/PortfoliosPortfolioDetailPagePage.js +335 -0
  133. package/dist/planmagnet/pages/PortfoliosPortfolioDetailPagePage.js.map +1 -0
  134. package/dist/planmagnet/pages/PortfoliosPortfoliosPagePage.d.ts +2 -0
  135. package/dist/planmagnet/pages/PortfoliosPortfoliosPagePage.d.ts.map +1 -0
  136. package/dist/planmagnet/pages/PortfoliosPortfoliosPagePage.js +154 -0
  137. package/dist/planmagnet/pages/PortfoliosPortfoliosPagePage.js.map +1 -0
  138. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.d.ts.map +1 -1
  139. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js +124 -138
  140. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js.map +1 -1
  141. package/dist/planmagnet/pages/ProgramsCreateProgramPagePage.d.ts +2 -0
  142. package/dist/planmagnet/pages/ProgramsCreateProgramPagePage.d.ts.map +1 -0
  143. package/dist/planmagnet/pages/ProgramsCreateProgramPagePage.js +221 -0
  144. package/dist/planmagnet/pages/ProgramsCreateProgramPagePage.js.map +1 -0
  145. package/dist/planmagnet/pages/ProgramsEditProgramPagePage.d.ts +2 -0
  146. package/dist/planmagnet/pages/ProgramsEditProgramPagePage.d.ts.map +1 -0
  147. package/dist/planmagnet/pages/ProgramsEditProgramPagePage.js +279 -0
  148. package/dist/planmagnet/pages/ProgramsEditProgramPagePage.js.map +1 -0
  149. package/dist/planmagnet/pages/ProgramsProgramDetailPagePage.d.ts +2 -0
  150. package/dist/planmagnet/pages/ProgramsProgramDetailPagePage.d.ts.map +1 -0
  151. package/dist/planmagnet/pages/ProgramsProgramDetailPagePage.js +178 -0
  152. package/dist/planmagnet/pages/ProgramsProgramDetailPagePage.js.map +1 -0
  153. package/dist/planmagnet/pages/ProgramsProgramsPagePage.d.ts +2 -0
  154. package/dist/planmagnet/pages/ProgramsProgramsPagePage.d.ts.map +1 -0
  155. package/dist/planmagnet/pages/ProgramsProgramsPagePage.js +157 -0
  156. package/dist/planmagnet/pages/ProgramsProgramsPagePage.js.map +1 -0
  157. package/dist/planmagnet/pages/ProjectsBudgetDetailPagePage.d.ts +2 -0
  158. package/dist/planmagnet/pages/ProjectsBudgetDetailPagePage.d.ts.map +1 -0
  159. package/dist/planmagnet/pages/ProjectsBudgetDetailPagePage.js +315 -0
  160. package/dist/planmagnet/pages/ProjectsBudgetDetailPagePage.js.map +1 -0
  161. package/dist/planmagnet/pages/ProjectsBudgetsPagePage.d.ts +2 -0
  162. package/dist/planmagnet/pages/ProjectsBudgetsPagePage.d.ts.map +1 -0
  163. package/dist/planmagnet/pages/ProjectsBudgetsPagePage.js +186 -0
  164. package/dist/planmagnet/pages/ProjectsBudgetsPagePage.js.map +1 -0
  165. package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.d.ts +2 -0
  166. package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.d.ts.map +1 -0
  167. package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.js +164 -0
  168. package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.js.map +1 -0
  169. package/dist/planmagnet/pages/ProjectsCustomFieldsPagePage.d.ts +2 -0
  170. package/dist/planmagnet/pages/ProjectsCustomFieldsPagePage.d.ts.map +1 -0
  171. package/dist/planmagnet/pages/ProjectsCustomFieldsPagePage.js +348 -0
  172. package/dist/planmagnet/pages/ProjectsCustomFieldsPagePage.js.map +1 -0
  173. package/dist/planmagnet/pages/ProjectsEditProjectPagePage.d.ts.map +1 -1
  174. package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js +130 -103
  175. package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js.map +1 -1
  176. package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.js +4 -4
  177. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js +4 -4
  178. package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.js +6 -6
  179. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.d.ts.map +1 -1
  180. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js +325 -189
  181. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js.map +1 -1
  182. package/dist/planmagnet/pages/ProjectsProjectsPagePage.d.ts.map +1 -1
  183. package/dist/planmagnet/pages/ProjectsProjectsPagePage.js +81 -72
  184. package/dist/planmagnet/pages/ProjectsProjectsPagePage.js.map +1 -1
  185. package/dist/planmagnet/pages/RisksRiskDetailPagePage.d.ts +2 -0
  186. package/dist/planmagnet/pages/RisksRiskDetailPagePage.d.ts.map +1 -0
  187. package/dist/planmagnet/pages/RisksRiskDetailPagePage.js +278 -0
  188. package/dist/planmagnet/pages/RisksRiskDetailPagePage.js.map +1 -0
  189. package/dist/planmagnet/pages/RisksRiskRegisterPagePage.d.ts +2 -0
  190. package/dist/planmagnet/pages/RisksRiskRegisterPagePage.d.ts.map +1 -0
  191. package/dist/planmagnet/pages/RisksRiskRegisterPagePage.js +191 -0
  192. package/dist/planmagnet/pages/RisksRiskRegisterPagePage.js.map +1 -0
  193. package/dist/planmagnet/pages/TasksCreateTaskPagePage.js +5 -5
  194. package/dist/planmagnet/pages/TasksEditTaskPagePage.js +4 -4
  195. package/dist/planmagnet/pages/TasksImportPagePage.js +5 -5
  196. package/dist/planmagnet/pages/TasksTaskDetailPagePage.d.ts.map +1 -1
  197. package/dist/planmagnet/pages/TasksTaskDetailPagePage.js +161 -137
  198. package/dist/planmagnet/pages/TasksTaskDetailPagePage.js.map +1 -1
  199. package/dist/planmagnet/pages/TasksTasksPagePage.d.ts.map +1 -1
  200. package/dist/planmagnet/pages/TasksTasksPagePage.js +124 -113
  201. package/dist/planmagnet/pages/TasksTasksPagePage.js.map +1 -1
  202. package/dist/planmagnet/pages/TasksTimeEntriesPagePage.d.ts +2 -0
  203. package/dist/planmagnet/pages/TasksTimeEntriesPagePage.d.ts.map +1 -0
  204. package/dist/planmagnet/pages/TasksTimeEntriesPagePage.js +263 -0
  205. package/dist/planmagnet/pages/TasksTimeEntriesPagePage.js.map +1 -0
  206. package/dist/planmagnet/pages/TasksTimesheetDetailPagePage.d.ts +2 -0
  207. package/dist/planmagnet/pages/TasksTimesheetDetailPagePage.d.ts.map +1 -0
  208. package/dist/planmagnet/pages/TasksTimesheetDetailPagePage.js +254 -0
  209. package/dist/planmagnet/pages/TasksTimesheetDetailPagePage.js.map +1 -0
  210. package/dist/planmagnet/pages/TasksTimesheetsPagePage.d.ts +2 -0
  211. package/dist/planmagnet/pages/TasksTimesheetsPagePage.d.ts.map +1 -0
  212. package/dist/planmagnet/pages/TasksTimesheetsPagePage.js +165 -0
  213. package/dist/planmagnet/pages/TasksTimesheetsPagePage.js.map +1 -0
  214. package/dist/planmagnet/pages/TemplatesEditTemplatePagePage.d.ts +2 -0
  215. package/dist/planmagnet/pages/TemplatesEditTemplatePagePage.d.ts.map +1 -0
  216. package/dist/planmagnet/pages/TemplatesEditTemplatePagePage.js +316 -0
  217. package/dist/planmagnet/pages/TemplatesEditTemplatePagePage.js.map +1 -0
  218. package/dist/planmagnet/pages/TemplatesTemplatesPagePage.d.ts +2 -0
  219. package/dist/planmagnet/pages/TemplatesTemplatesPagePage.d.ts.map +1 -0
  220. package/dist/planmagnet/pages/TemplatesTemplatesPagePage.js +208 -0
  221. package/dist/planmagnet/pages/TemplatesTemplatesPagePage.js.map +1 -0
  222. package/dist/planmagnet/pages/analytics/DeliveryHealthCards.d.ts +0 -5
  223. package/dist/planmagnet/pages/analytics/DeliveryHealthCards.d.ts.map +1 -1
  224. package/dist/planmagnet/pages/analytics/DeliveryHealthCards.js +47 -89
  225. package/dist/planmagnet/pages/analytics/DeliveryHealthCards.js.map +1 -1
  226. package/dist/planmagnet/roadmaps/RoadmapControls.js +24 -24
  227. package/dist/planmagnet/time/TaskTimePanel.d.ts +7 -0
  228. package/dist/planmagnet/time/TaskTimePanel.d.ts.map +1 -0
  229. package/dist/planmagnet/time/TaskTimePanel.js +104 -0
  230. package/dist/planmagnet/time/TaskTimePanel.js.map +1 -0
  231. package/dist/planmagnet/time/TimeEntryControls.d.ts +37 -0
  232. package/dist/planmagnet/time/TimeEntryControls.d.ts.map +1 -0
  233. package/dist/planmagnet/time/TimeEntryControls.js +338 -0
  234. package/dist/planmagnet/time/TimeEntryControls.js.map +1 -0
  235. package/dist/planmagnet/time/TimesheetControls.d.ts +18 -0
  236. package/dist/planmagnet/time/TimesheetControls.d.ts.map +1 -0
  237. package/dist/planmagnet/time/TimesheetControls.js +244 -0
  238. package/dist/planmagnet/time/TimesheetControls.js.map +1 -0
  239. package/dist/planmagnet/time/timeShared.d.ts +29 -0
  240. package/dist/planmagnet/time/timeShared.d.ts.map +1 -0
  241. package/dist/planmagnet/time/timeShared.js +34 -0
  242. package/dist/planmagnet/time/timeShared.js.map +1 -0
  243. package/dist/planmagnet/utils/rowNavigation.js +5 -2
  244. package/dist/planmagnet/utils/rowNavigation.js.map +1 -1
  245. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TimeEntryControls.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/time/TimeEntryControls.tsx"],"names":[],"mappings":"AAiFA,iHAAiH;AACjH,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,mGAAmG;IACnG,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,cAAc,EACd,QAAQ,EACR,YAAyB,EACzB,WAAkB,GACnB,EAAE;IACD,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,4GAA4G;IAC5G,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;CAChC,2CAyLA;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,sGAAsG;AACtG,wBAAgB,mBAAmB,CAAC,EAClC,KAAK,EACL,cAAc,GACf,EAAE;IACD,KAAK,EAAE,eAAe,CAAC;IACvB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B,2CAuIA;AAED,8CAA8C;AAC9C,wBAAgB,qBAAqB,CAAC,EACpC,EAAE,EACF,cAAc,GACf,EAAE;IACD,EAAE,EAAE,MAAM,CAAC;IACX,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B,2CAiCA"}
@@ -0,0 +1,338 @@
1
+ import { throwOnError as e } from "../utils/mutationResult.js";
2
+ import { ConfirmButton as t, ErrorLine as n } from "../controls/ConfirmButton.js";
3
+ import { ProjectSelect as r, WorkItemSearchSelect as i } from "../controls/Pickers.js";
4
+ import { enumLabel as a } from "../controls/WorkItemControls.js";
5
+ import { BILLING_TYPES as o, hoursInputToMinutes as s, minutesToHoursInput as c, toDateInputValue as l, todayInputValue as u } from "./timeShared.js";
6
+ import { useState as d } from "react";
7
+ import { Clock as f, Pencil as p, Trash2 as m } from "lucide-react";
8
+ import { gql as h } from "@apollo/client";
9
+ import { useMutation as g } from "@apollo/client/react";
10
+ import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
11
+ import { Button as b, Input as x, ResponsiveDialog as S, ResponsiveDialogContent as C, ResponsiveDialogDescription as w, ResponsiveDialogFooter as T, ResponsiveDialogHeader as E, ResponsiveDialogTitle as D, ResponsiveDialogTrigger as O } from "@burdenoff/fe-libs/ui";
12
+ //#region src/planmagnet/time/TimeEntryControls.tsx
13
+ var k = h`
14
+ mutation TimeEntryControlsLogTime($input: PlanmagnetLogTimeInput!) {
15
+ planmagnetLogTime(input: $input) {
16
+ id
17
+ workItemId
18
+ projectId
19
+ timesheetId
20
+ description
21
+ durationMinutes
22
+ date
23
+ status
24
+ billingType
25
+ createdAt
26
+ }
27
+ }
28
+ `, A = h`
29
+ mutation TimeEntryControlsUpdate($id: ID!, $input: PlanmagnetUpdateTimeEntryInput!) {
30
+ planmagnetUpdateTimeEntry(id: $id, input: $input) {
31
+ id
32
+ description
33
+ durationMinutes
34
+ date
35
+ billingType
36
+ updatedAt
37
+ }
38
+ }
39
+ `, j = h`
40
+ mutation TimeEntryControlsDelete($id: ID!) {
41
+ planmagnetDeleteTimeEntry(id: $id)
42
+ }
43
+ `, M = "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm disabled:opacity-60", N = (e, t) => e instanceof Error ? e.message : t;
44
+ function P({ lock: t, refetchQueries: c, onLogged: l, triggerLabel: p = "Log time", triggerSize: m = "sm" }) {
45
+ let [h, A] = d(!1), [j, P] = d(""), [F, I] = d(""), [L, R] = d(""), [z, B] = d(u()), [V, H] = d("NON_BILLABLE"), [U, W] = d(""), [G, K] = d(null), [q, { loading: J }] = g(k, {
46
+ refetchQueries: c,
47
+ awaitRefetchQueries: !0
48
+ }), Y = () => {
49
+ P(""), I(""), R(""), B(u()), H("NON_BILLABLE"), W(""), K(null);
50
+ }, X = t?.workItemId ?? F, Z = t?.projectId ?? j, Q = s(L), $ = !J && !!X && !!Z && Q > 0 && !!z, ee = async () => {
51
+ K(null);
52
+ try {
53
+ let t = (await e(q({ variables: { input: {
54
+ workItemId: X,
55
+ projectId: Z,
56
+ durationMinutes: Q,
57
+ date: z,
58
+ billingType: V,
59
+ ...U.trim() ? { description: U.trim() } : {}
60
+ } } }))).data?.planmagnetLogTime.id;
61
+ A(!1), Y(), t && l?.(t);
62
+ } catch (e) {
63
+ K(N(e, "The time could not be logged."));
64
+ }
65
+ };
66
+ return /* @__PURE__ */ y(S, {
67
+ open: h,
68
+ onOpenChange: (e) => {
69
+ A(e), e ? Y() : K(null);
70
+ },
71
+ children: [/* @__PURE__ */ v(O, {
72
+ asChild: !0,
73
+ children: /* @__PURE__ */ y(b, {
74
+ size: m,
75
+ "data-testid": "log-time-open",
76
+ children: [/* @__PURE__ */ v(f, { className: "mr-1 h-4 w-4" }), p]
77
+ })
78
+ }), /* @__PURE__ */ y(C, {
79
+ className: "max-w-lg",
80
+ children: [
81
+ /* @__PURE__ */ y(E, { children: [/* @__PURE__ */ v(D, { children: "Log time" }), /* @__PURE__ */ v(w, { children: t ? `Against ${t.label}.` : "Pick a project and a work item, then the time spent." })] }),
82
+ /* @__PURE__ */ y("div", {
83
+ className: "space-y-3",
84
+ children: [
85
+ !t && /* @__PURE__ */ y(_, { children: [/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
86
+ htmlFor: "log-time-project",
87
+ className: "text-sm font-medium",
88
+ children: "Project"
89
+ }), /* @__PURE__ */ v("div", {
90
+ className: "mt-1",
91
+ children: /* @__PURE__ */ v(r, {
92
+ id: "log-time-project",
93
+ value: j,
94
+ onChange: (e) => {
95
+ P(e), I("");
96
+ }
97
+ })
98
+ })] }), /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
99
+ htmlFor: "log-time-work-item",
100
+ className: "text-sm font-medium",
101
+ children: "Work item"
102
+ }), /* @__PURE__ */ v("div", {
103
+ className: "mt-1",
104
+ children: /* @__PURE__ */ v(i, {
105
+ id: "log-time-work-item",
106
+ projectId: j || void 0,
107
+ value: F,
108
+ onChange: I
109
+ })
110
+ })] })] }),
111
+ /* @__PURE__ */ y("div", {
112
+ className: "grid grid-cols-2 gap-3",
113
+ children: [/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
114
+ htmlFor: "log-time-hours",
115
+ className: "text-sm font-medium",
116
+ children: "Hours"
117
+ }), /* @__PURE__ */ v(x, {
118
+ id: "log-time-hours",
119
+ className: "mt-1",
120
+ type: "number",
121
+ min: "0",
122
+ step: "0.25",
123
+ inputMode: "decimal",
124
+ placeholder: "e.g. 1.5",
125
+ value: L,
126
+ onChange: (e) => R(e.target.value)
127
+ })] }), /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
128
+ htmlFor: "log-time-date",
129
+ className: "text-sm font-medium",
130
+ children: "Date"
131
+ }), /* @__PURE__ */ v(x, {
132
+ id: "log-time-date",
133
+ className: "mt-1",
134
+ type: "date",
135
+ value: z,
136
+ onChange: (e) => B(e.target.value)
137
+ })] })]
138
+ }),
139
+ /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
140
+ htmlFor: "log-time-billing",
141
+ className: "text-sm font-medium",
142
+ children: "Billing type"
143
+ }), /* @__PURE__ */ v("select", {
144
+ id: "log-time-billing",
145
+ className: M,
146
+ value: V,
147
+ onChange: (e) => H(e.target.value),
148
+ children: o.map((e) => /* @__PURE__ */ v("option", {
149
+ value: e,
150
+ children: a(e)
151
+ }, e))
152
+ })] }),
153
+ /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
154
+ htmlFor: "log-time-description",
155
+ className: "text-sm font-medium",
156
+ children: "Description"
157
+ }), /* @__PURE__ */ v("textarea", {
158
+ id: "log-time-description",
159
+ className: `${M} min-h-[64px]`,
160
+ placeholder: "What did you work on? (optional)",
161
+ value: U,
162
+ onChange: (e) => W(e.target.value)
163
+ })] }),
164
+ G && /* @__PURE__ */ v(n, { message: G })
165
+ ]
166
+ }),
167
+ /* @__PURE__ */ y(T, { children: [/* @__PURE__ */ v(b, {
168
+ variant: "outline",
169
+ onClick: () => A(!1),
170
+ children: "Cancel"
171
+ }), /* @__PURE__ */ v(b, {
172
+ onClick: () => void ee(),
173
+ disabled: !$,
174
+ "data-testid": "log-time-submit",
175
+ children: J ? "Logging…" : "Log time"
176
+ })] })
177
+ ]
178
+ })]
179
+ });
180
+ }
181
+ function F({ entry: t, refetchQueries: r }) {
182
+ let i = {
183
+ description: t.description ?? "",
184
+ hours: c(t.durationMinutes),
185
+ date: l(t.date),
186
+ billingType: t.billingType
187
+ }, [u, f] = d(!1), [m, h] = d(i), [_, k] = d(null), [j, { loading: P }] = g(A, {
188
+ refetchQueries: r,
189
+ awaitRefetchQueries: !0
190
+ }), F = s(m.hours), I = !P && F > 0 && !!m.date, L = async () => {
191
+ k(null);
192
+ let n = {};
193
+ if (m.description.trim() !== i.description.trim() && (n.description = m.description.trim() || null), F !== t.durationMinutes && (n.durationMinutes = F), m.date !== i.date && (n.date = m.date), m.billingType !== i.billingType && (n.billingType = m.billingType), Object.keys(n).length === 0) {
194
+ f(!1);
195
+ return;
196
+ }
197
+ try {
198
+ await e(j({ variables: {
199
+ id: t.id,
200
+ input: n
201
+ } })), f(!1);
202
+ } catch (e) {
203
+ k(N(e, "The time entry could not be saved."));
204
+ }
205
+ };
206
+ return /* @__PURE__ */ y(S, {
207
+ open: u,
208
+ onOpenChange: (e) => {
209
+ f(e), e ? h(i) : k(null);
210
+ },
211
+ children: [/* @__PURE__ */ v(O, {
212
+ asChild: !0,
213
+ children: /* @__PURE__ */ v(b, {
214
+ size: "sm",
215
+ variant: "outline",
216
+ "aria-label": "Edit time entry",
217
+ "data-testid": "time-entry-edit",
218
+ children: /* @__PURE__ */ v(p, { className: "h-4 w-4" })
219
+ })
220
+ }), /* @__PURE__ */ y(C, {
221
+ className: "max-w-lg",
222
+ children: [
223
+ /* @__PURE__ */ y(E, { children: [/* @__PURE__ */ v(D, { children: "Edit time entry" }), /* @__PURE__ */ v(w, { children: "Change the hours, date, billing type or description." })] }),
224
+ /* @__PURE__ */ y("div", {
225
+ className: "space-y-3",
226
+ children: [
227
+ /* @__PURE__ */ y("div", {
228
+ className: "grid grid-cols-2 gap-3",
229
+ children: [/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
230
+ htmlFor: "edit-time-hours",
231
+ className: "text-sm font-medium",
232
+ children: "Hours"
233
+ }), /* @__PURE__ */ v(x, {
234
+ id: "edit-time-hours",
235
+ className: "mt-1",
236
+ type: "number",
237
+ min: "0",
238
+ step: "0.25",
239
+ inputMode: "decimal",
240
+ value: m.hours,
241
+ onChange: (e) => h({
242
+ ...m,
243
+ hours: e.target.value
244
+ })
245
+ })] }), /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
246
+ htmlFor: "edit-time-date",
247
+ className: "text-sm font-medium",
248
+ children: "Date"
249
+ }), /* @__PURE__ */ v(x, {
250
+ id: "edit-time-date",
251
+ className: "mt-1",
252
+ type: "date",
253
+ value: m.date,
254
+ onChange: (e) => h({
255
+ ...m,
256
+ date: e.target.value
257
+ })
258
+ })] })]
259
+ }),
260
+ /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
261
+ htmlFor: "edit-time-billing",
262
+ className: "text-sm font-medium",
263
+ children: "Billing type"
264
+ }), /* @__PURE__ */ v("select", {
265
+ id: "edit-time-billing",
266
+ className: M,
267
+ value: m.billingType,
268
+ onChange: (e) => h({
269
+ ...m,
270
+ billingType: e.target.value
271
+ }),
272
+ children: o.map((e) => /* @__PURE__ */ v("option", {
273
+ value: e,
274
+ children: a(e)
275
+ }, e))
276
+ })] }),
277
+ /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
278
+ htmlFor: "edit-time-description",
279
+ className: "text-sm font-medium",
280
+ children: "Description"
281
+ }), /* @__PURE__ */ v("textarea", {
282
+ id: "edit-time-description",
283
+ className: `${M} min-h-[64px]`,
284
+ value: m.description,
285
+ onChange: (e) => h({
286
+ ...m,
287
+ description: e.target.value
288
+ })
289
+ })] }),
290
+ _ && /* @__PURE__ */ v(n, { message: _ })
291
+ ]
292
+ }),
293
+ /* @__PURE__ */ y(T, { children: [/* @__PURE__ */ v(b, {
294
+ variant: "outline",
295
+ onClick: () => f(!1),
296
+ children: "Cancel"
297
+ }), /* @__PURE__ */ v(b, {
298
+ onClick: () => void L(),
299
+ disabled: !I,
300
+ "data-testid": "edit-time-save",
301
+ children: P ? "Saving…" : "Save"
302
+ })] })
303
+ ]
304
+ })]
305
+ });
306
+ }
307
+ function I({ id: r, refetchQueries: i }) {
308
+ let [a, { loading: o }] = g(j, {
309
+ refetchQueries: i,
310
+ awaitRefetchQueries: !0
311
+ }), [s, c] = d(null), l = async () => {
312
+ c(null);
313
+ try {
314
+ await e(a({ variables: { id: r } }));
315
+ } catch (e) {
316
+ c(N(e, "The time entry could not be deleted."));
317
+ }
318
+ };
319
+ return /* @__PURE__ */ y("div", {
320
+ className: "flex flex-col items-end gap-1",
321
+ children: [/* @__PURE__ */ v(t, {
322
+ label: "",
323
+ ariaLabel: "Delete time entry",
324
+ variant: "outline",
325
+ icon: /* @__PURE__ */ v(m, { className: "h-4 w-4" }),
326
+ title: "Delete this time entry?",
327
+ description: "The logged time is removed. This cannot be undone here.",
328
+ confirmLabel: "Delete entry",
329
+ destructive: !0,
330
+ disabled: o,
331
+ onConfirm: () => void l()
332
+ }), s && /* @__PURE__ */ v(n, { message: s })]
333
+ });
334
+ }
335
+ //#endregion
336
+ export { I as DeleteTimeEntryButton, F as EditTimeEntryDialog, P as LogTimeDialog };
337
+
338
+ //# sourceMappingURL=TimeEntryControls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TimeEntryControls.js","names":[],"sources":["../../../src/planmagnet/time/TimeEntryControls.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation } from '@apollo/client/react';\nimport {\n Button,\n Input,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogTrigger,\n} from '@burdenoff/fe-libs/ui';\nimport { Clock, Pencil, Trash2 } from 'lucide-react';\nimport { ProjectSelect, WorkItemSearchSelect } from '../controls/Pickers';\nimport { throwOnError } from '../utils/mutationResult';\nimport { ConfirmButton, ErrorLine } from '../controls/ConfirmButton';\nimport {\n BILLING_TYPES,\n type BillingType,\n enumLabel,\n hoursInputToMinutes,\n minutesToHoursInput,\n todayInputValue,\n toDateInputValue,\n} from './timeShared';\n\n/**\n * Time entry controls (BOFF-8047): logging time, editing an entry, deleting one.\n *\n * `planmagnetLogTime` (not the lower-level `planmagnetCreateTimeEntry`) is the write path here — it is the\n * \"quick log time\" mutation the schema documents for this exact purpose, and it does not accept a billable\n * rate. That is deliberate, not a missing feature: \"A Delivery Contributor with EDITOR can read every time\n * entry in the workspace, including colleagues' billable rate and currency\" is a known, still-open RBAC gap\n * (planmagnet-specs/CORRECTIONS.md §B) — the resolver does not scope `billingRate` by role. Keeping rate\n * capture and display out of this UI entirely means this screen cannot become a new way to see it; fixing\n * the gap itself is a backend RBAC change, out of scope here (recorded as a backend gap).\n */\n\nconst LOG_TIME = gql`\n mutation TimeEntryControlsLogTime($input: PlanmagnetLogTimeInput!) {\n planmagnetLogTime(input: $input) {\n id\n workItemId\n projectId\n timesheetId\n description\n durationMinutes\n date\n status\n billingType\n createdAt\n }\n }\n`;\n\nconst UPDATE_TIME_ENTRY = gql`\n mutation TimeEntryControlsUpdate($id: ID!, $input: PlanmagnetUpdateTimeEntryInput!) {\n planmagnetUpdateTimeEntry(id: $id, input: $input) {\n id\n description\n durationMinutes\n date\n billingType\n updatedAt\n }\n }\n`;\n\nconst DELETE_TIME_ENTRY = gql`\n mutation TimeEntryControlsDelete($id: ID!) {\n planmagnetDeleteTimeEntry(id: $id)\n }\n`;\n\nconst FIELD =\n 'mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm disabled:opacity-60';\n\nconst messageOf = (e: unknown, fallback: string) => (e instanceof Error ? e.message : fallback);\n\n/** The work item a \"Log time\" dialog logs against, when the caller already knows it (e.g. a task's own page). */\nexport interface TimeEntryLock {\n workItemId: string;\n projectId: string;\n /** Shown in the dialog instead of the project/work-item pickers, e.g. \"PM-42 — Ship the thing\". */\n label: string;\n}\n\n/**\n * Log time against a work item. With `lock`, the work item is fixed (the task-detail entry point); otherwise\n * the dialog offers a project picker and a work-item search, for logging time from the Time Entries page.\n */\nexport function LogTimeDialog({\n lock,\n refetchQueries,\n onLogged,\n triggerLabel = 'Log time',\n triggerSize = 'sm',\n}: {\n lock?: TimeEntryLock;\n /** Every query that must re-run after a successful log, e.g. ['TimeEntriesList'] or ['TaskTimeEntries']. */\n refetchQueries: string[];\n onLogged?: (id: string) => void;\n triggerLabel?: string;\n triggerSize?: 'sm' | 'default';\n}) {\n const [open, setOpen] = useState(false);\n const [projectId, setProjectId] = useState('');\n const [workItemId, setWorkItemId] = useState('');\n const [hours, setHours] = useState('');\n const [date, setDate] = useState(todayInputValue());\n const [billingType, setBillingType] = useState<BillingType>('NON_BILLABLE');\n const [description, setDescription] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [log, { loading }] = useMutation<{ planmagnetLogTime: { id: string } }>(LOG_TIME, {\n refetchQueries,\n awaitRefetchQueries: true,\n });\n\n const reset = () => {\n setProjectId('');\n setWorkItemId('');\n setHours('');\n setDate(todayInputValue());\n setBillingType('NON_BILLABLE');\n setDescription('');\n setError(null);\n };\n\n const effectiveWorkItemId = lock?.workItemId ?? workItemId;\n const effectiveProjectId = lock?.projectId ?? projectId;\n const minutes = hoursInputToMinutes(hours);\n const canSubmit =\n !loading && !!effectiveWorkItemId && !!effectiveProjectId && minutes > 0 && !!date;\n\n const submit = async () => {\n setError(null);\n try {\n const result = await throwOnError(\n log({\n variables: {\n input: {\n workItemId: effectiveWorkItemId,\n projectId: effectiveProjectId,\n durationMinutes: minutes,\n date,\n billingType,\n ...(description.trim() ? { description: description.trim() } : {}),\n },\n },\n })\n );\n const id = result.data?.planmagnetLogTime.id;\n setOpen(false);\n reset();\n if (id) onLogged?.(id);\n } catch (e) {\n setError(messageOf(e, 'The time could not be logged.'));\n }\n };\n\n return (\n <ResponsiveDialog\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (next) reset();\n else setError(null);\n }}\n >\n <ResponsiveDialogTrigger asChild>\n <Button size={triggerSize} data-testid=\"log-time-open\">\n <Clock className=\"mr-1 h-4 w-4\" />\n {triggerLabel}\n </Button>\n </ResponsiveDialogTrigger>\n <ResponsiveDialogContent className=\"max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Log time</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n {lock\n ? `Against ${lock.label}.`\n : 'Pick a project and a work item, then the time spent.'}\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3\">\n {!lock && (\n <>\n <div>\n <label htmlFor=\"log-time-project\" className=\"text-sm font-medium\">\n Project\n </label>\n <div className=\"mt-1\">\n <ProjectSelect\n id=\"log-time-project\"\n value={projectId}\n onChange={(next) => {\n setProjectId(next);\n setWorkItemId('');\n }}\n />\n </div>\n </div>\n <div>\n <label htmlFor=\"log-time-work-item\" className=\"text-sm font-medium\">\n Work item\n </label>\n <div className=\"mt-1\">\n <WorkItemSearchSelect\n id=\"log-time-work-item\"\n projectId={projectId || undefined}\n value={workItemId}\n onChange={setWorkItemId}\n />\n </div>\n </div>\n </>\n )}\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <label htmlFor=\"log-time-hours\" className=\"text-sm font-medium\">\n Hours\n </label>\n <Input\n id=\"log-time-hours\"\n className=\"mt-1\"\n type=\"number\"\n min=\"0\"\n step=\"0.25\"\n inputMode=\"decimal\"\n placeholder=\"e.g. 1.5\"\n value={hours}\n onChange={(e) => setHours(e.target.value)}\n />\n </div>\n <div>\n <label htmlFor=\"log-time-date\" className=\"text-sm font-medium\">\n Date\n </label>\n <Input\n id=\"log-time-date\"\n className=\"mt-1\"\n type=\"date\"\n value={date}\n onChange={(e) => setDate(e.target.value)}\n />\n </div>\n </div>\n <div>\n <label htmlFor=\"log-time-billing\" className=\"text-sm font-medium\">\n Billing type\n </label>\n <select\n id=\"log-time-billing\"\n className={FIELD}\n value={billingType}\n onChange={(e) => setBillingType(e.target.value as BillingType)}\n >\n {BILLING_TYPES.map((b) => (\n <option key={b} value={b}>\n {enumLabel(b)}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label htmlFor=\"log-time-description\" className=\"text-sm font-medium\">\n Description\n </label>\n <textarea\n id=\"log-time-description\"\n className={`${FIELD} min-h-[64px]`}\n placeholder=\"What did you work on? (optional)\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n />\n </div>\n {error && <ErrorLine message={error} />}\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setOpen(false)}>\n Cancel\n </Button>\n <Button onClick={() => void submit()} disabled={!canSubmit} data-testid=\"log-time-submit\">\n {loading ? 'Logging…' : 'Log time'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\nexport interface TimeEntryValues {\n id: string;\n description: string | null;\n durationMinutes: number;\n date: string;\n billingType: string;\n}\n\n/** Edit a time entry's description, duration, date and billing type. Only changed fields are sent. */\nexport function EditTimeEntryDialog({\n entry,\n refetchQueries,\n}: {\n entry: TimeEntryValues;\n refetchQueries: string[];\n}) {\n const initial = {\n description: entry.description ?? '',\n hours: minutesToHoursInput(entry.durationMinutes),\n date: toDateInputValue(entry.date),\n billingType: entry.billingType,\n };\n const [open, setOpen] = useState(false);\n const [form, setForm] = useState(initial);\n const [error, setError] = useState<string | null>(null);\n const [update, { loading }] = useMutation(UPDATE_TIME_ENTRY, {\n refetchQueries,\n awaitRefetchQueries: true,\n });\n\n const minutes = hoursInputToMinutes(form.hours);\n const canSubmit = !loading && minutes > 0 && !!form.date;\n\n const save = async () => {\n setError(null);\n const input: Record<string, unknown> = {};\n if (form.description.trim() !== initial.description.trim())\n input.description = form.description.trim() || null;\n if (minutes !== entry.durationMinutes) input.durationMinutes = minutes;\n if (form.date !== initial.date) input.date = form.date;\n if (form.billingType !== initial.billingType) input.billingType = form.billingType;\n if (Object.keys(input).length === 0) {\n setOpen(false);\n return;\n }\n try {\n await throwOnError(update({ variables: { id: entry.id, input } }));\n setOpen(false);\n } catch (e) {\n setError(messageOf(e, 'The time entry could not be saved.'));\n }\n };\n\n return (\n <ResponsiveDialog\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (next) setForm(initial);\n else setError(null);\n }}\n >\n <ResponsiveDialogTrigger asChild>\n <Button\n size=\"sm\"\n variant=\"outline\"\n aria-label=\"Edit time entry\"\n data-testid=\"time-entry-edit\"\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n </ResponsiveDialogTrigger>\n <ResponsiveDialogContent className=\"max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Edit time entry</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Change the hours, date, billing type or description.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3\">\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <label htmlFor=\"edit-time-hours\" className=\"text-sm font-medium\">\n Hours\n </label>\n <Input\n id=\"edit-time-hours\"\n className=\"mt-1\"\n type=\"number\"\n min=\"0\"\n step=\"0.25\"\n inputMode=\"decimal\"\n value={form.hours}\n onChange={(e) => setForm({ ...form, hours: e.target.value })}\n />\n </div>\n <div>\n <label htmlFor=\"edit-time-date\" className=\"text-sm font-medium\">\n Date\n </label>\n <Input\n id=\"edit-time-date\"\n className=\"mt-1\"\n type=\"date\"\n value={form.date}\n onChange={(e) => setForm({ ...form, date: e.target.value })}\n />\n </div>\n </div>\n <div>\n <label htmlFor=\"edit-time-billing\" className=\"text-sm font-medium\">\n Billing type\n </label>\n <select\n id=\"edit-time-billing\"\n className={FIELD}\n value={form.billingType}\n onChange={(e) => setForm({ ...form, billingType: e.target.value })}\n >\n {BILLING_TYPES.map((b) => (\n <option key={b} value={b}>\n {enumLabel(b)}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label htmlFor=\"edit-time-description\" className=\"text-sm font-medium\">\n Description\n </label>\n <textarea\n id=\"edit-time-description\"\n className={`${FIELD} min-h-[64px]`}\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n />\n </div>\n {error && <ErrorLine message={error} />}\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setOpen(false)}>\n Cancel\n </Button>\n <Button onClick={() => void save()} disabled={!canSubmit} data-testid=\"edit-time-save\">\n {loading ? 'Saving…' : 'Save'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\n/** Delete a time entry, with confirmation. */\nexport function DeleteTimeEntryButton({\n id,\n refetchQueries,\n}: {\n id: string;\n refetchQueries: string[];\n}) {\n const [remove, { loading }] = useMutation(DELETE_TIME_ENTRY, {\n refetchQueries,\n awaitRefetchQueries: true,\n });\n const [error, setError] = useState<string | null>(null);\n\n const onDelete = async () => {\n setError(null);\n try {\n await throwOnError(remove({ variables: { id } }));\n } catch (e) {\n setError(messageOf(e, 'The time entry could not be deleted.'));\n }\n };\n\n return (\n <div className=\"flex flex-col items-end gap-1\">\n <ConfirmButton\n label=\"\"\n ariaLabel=\"Delete time entry\"\n variant=\"outline\"\n icon={<Trash2 className=\"h-4 w-4\" />}\n title=\"Delete this time entry?\"\n description=\"The logged time is removed. This cannot be undone here.\"\n confirmLabel=\"Delete entry\"\n destructive\n disabled={loading}\n onConfirm={() => void onDelete()}\n />\n {error && <ErrorLine message={error} />}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /** Create a timesheet for a period. Entries the caller already logged inside that period are claimed by it. */
2
+ export declare function CreateTimesheetDialog({ refetchQueries, onCreated, }: {
3
+ refetchQueries: string[];
4
+ onCreated?: (id: string) => void;
5
+ }): import("react/jsx-runtime").JSX.Element;
6
+ /** Submit a DRAFT or REJECTED timesheet for approval. Its totals are snapshotted at that instant (service). */
7
+ export declare function SubmitTimesheetButton({ id, status, refetchQueries, }: {
8
+ id: string;
9
+ status: string;
10
+ refetchQueries: string[];
11
+ }): import("react/jsx-runtime").JSX.Element | null;
12
+ /** Approve / Reject, shown for a SUBMITTED timesheet. Reject asks for an optional reason. */
13
+ export declare function TimesheetApprovalActions({ id, status, refetchQueries, }: {
14
+ id: string;
15
+ status: string;
16
+ refetchQueries: string[];
17
+ }): import("react/jsx-runtime").JSX.Element | null;
18
+ //# sourceMappingURL=TimesheetControls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TimesheetControls.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/time/TimesheetControls.tsx"],"names":[],"mappings":"AA+EA,+GAA+G;AAC/G,wBAAgB,qBAAqB,CAAC,EACpC,cAAc,EACd,SAAS,GACV,EAAE;IACD,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,SAAS,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC,2CAyGA;AAED,+GAA+G;AAC/G,wBAAgB,qBAAqB,CAAC,EACpC,EAAE,EACF,MAAM,EACN,cAAc,GACf,EAAE;IACD,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B,kDA+BA;AAED,6FAA6F;AAC7F,wBAAgB,wBAAwB,CAAC,EACvC,EAAE,EACF,MAAM,EACN,cAAc,GACf,EAAE;IACD,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B,kDA+FA"}
@@ -0,0 +1,244 @@
1
+ import { throwOnError as e } from "../utils/mutationResult.js";
2
+ import { ConfirmButton as t, ErrorLine as n } from "../controls/ConfirmButton.js";
3
+ import { SUBMITTABLE_TIMESHEET_STATUSES as r, todayInputValue as i } from "./timeShared.js";
4
+ import { useState as a } from "react";
5
+ import { CalendarPlus as o, Check as s, X as c } from "lucide-react";
6
+ import { gql as l } from "@apollo/client";
7
+ import { useMutation as u } from "@apollo/client/react";
8
+ import { jsx as d, jsxs as f } from "react/jsx-runtime";
9
+ import { Button as p, Input as m, ResponsiveDialog as h, ResponsiveDialogContent as g, ResponsiveDialogDescription as _, ResponsiveDialogFooter as v, ResponsiveDialogHeader as y, ResponsiveDialogTitle as b, ResponsiveDialogTrigger as x } from "@burdenoff/fe-libs/ui";
10
+ //#region src/planmagnet/time/TimesheetControls.tsx
11
+ var S = l`
12
+ mutation TimesheetControlsCreate($input: PlanmagnetCreateTimesheetInput!) {
13
+ planmagnetCreateTimesheet(input: $input) {
14
+ id
15
+ periodStart
16
+ periodEnd
17
+ status
18
+ totalMinutes
19
+ billableMinutes
20
+ }
21
+ }
22
+ `, C = l`
23
+ mutation TimesheetControlsSubmit($id: ID!) {
24
+ planmagnetSubmitTimesheet(id: $id) {
25
+ id
26
+ status
27
+ totalMinutes
28
+ billableMinutes
29
+ }
30
+ }
31
+ `, w = l`
32
+ mutation TimesheetControlsApprove($id: ID!) {
33
+ planmagnetApproveTimesheet(id: $id) {
34
+ id
35
+ status
36
+ approverId
37
+ approvedAt
38
+ }
39
+ }
40
+ `, T = l`
41
+ mutation TimesheetControlsReject($id: ID!, $reason: String) {
42
+ planmagnetRejectTimesheet(id: $id, reason: $reason) {
43
+ id
44
+ status
45
+ rejectionReason
46
+ }
47
+ }
48
+ `, E = (e, t) => e instanceof Error ? e.message : t;
49
+ function D({ refetchQueries: t, onCreated: r }) {
50
+ let [s, c] = a(!1), [l, C] = a(i()), [w, T] = a(i()), [D, O] = a(null), [k, { loading: A }] = u(S, {
51
+ refetchQueries: t,
52
+ awaitRefetchQueries: !0
53
+ }), j = () => {
54
+ C(i()), T(i()), O(null);
55
+ }, M = l && w && w < l, N = !A && !!l && !!w && !M, P = async () => {
56
+ O(null);
57
+ try {
58
+ let t = (await e(k({ variables: { input: {
59
+ periodStart: l,
60
+ periodEnd: w
61
+ } } }))).data?.planmagnetCreateTimesheet.id;
62
+ c(!1), j(), t && r?.(t);
63
+ } catch (e) {
64
+ O(E(e, "The timesheet could not be created."));
65
+ }
66
+ };
67
+ return /* @__PURE__ */ f(h, {
68
+ open: s,
69
+ onOpenChange: (e) => {
70
+ c(e), e ? j() : O(null);
71
+ },
72
+ children: [/* @__PURE__ */ d(x, {
73
+ asChild: !0,
74
+ children: /* @__PURE__ */ f(p, {
75
+ size: "sm",
76
+ "data-testid": "new-timesheet-open",
77
+ children: [/* @__PURE__ */ d(o, { className: "mr-1 h-4 w-4" }), "New timesheet"]
78
+ })
79
+ }), /* @__PURE__ */ f(g, {
80
+ className: "max-w-lg",
81
+ children: [
82
+ /* @__PURE__ */ f(y, { children: [/* @__PURE__ */ d(b, { children: "New timesheet" }), /* @__PURE__ */ d(_, { children: "Any of your own time entries already logged inside this period are added to it." })] }),
83
+ /* @__PURE__ */ f("div", {
84
+ className: "space-y-3",
85
+ children: [
86
+ /* @__PURE__ */ f("div", {
87
+ className: "grid grid-cols-2 gap-3",
88
+ children: [/* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("label", {
89
+ htmlFor: "new-timesheet-start",
90
+ className: "text-sm font-medium",
91
+ children: "Period start"
92
+ }), /* @__PURE__ */ d(m, {
93
+ id: "new-timesheet-start",
94
+ className: "mt-1",
95
+ type: "date",
96
+ value: l,
97
+ onChange: (e) => C(e.target.value)
98
+ })] }), /* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("label", {
99
+ htmlFor: "new-timesheet-end",
100
+ className: "text-sm font-medium",
101
+ children: "Period end"
102
+ }), /* @__PURE__ */ d(m, {
103
+ id: "new-timesheet-end",
104
+ className: "mt-1",
105
+ type: "date",
106
+ value: w,
107
+ onChange: (e) => T(e.target.value)
108
+ })] })]
109
+ }),
110
+ M && /* @__PURE__ */ d(n, { message: "The period end cannot be before the period start." }),
111
+ D && /* @__PURE__ */ d(n, { message: D })
112
+ ]
113
+ }),
114
+ /* @__PURE__ */ f(v, { children: [/* @__PURE__ */ d(p, {
115
+ variant: "outline",
116
+ onClick: () => c(!1),
117
+ children: "Cancel"
118
+ }), /* @__PURE__ */ d(p, {
119
+ onClick: () => void P(),
120
+ disabled: !N,
121
+ "data-testid": "new-timesheet-submit",
122
+ children: A ? "Creating…" : "Create timesheet"
123
+ })] })
124
+ ]
125
+ })]
126
+ });
127
+ }
128
+ function O({ id: i, status: o, refetchQueries: c }) {
129
+ let [l, { loading: p }] = u(C, {
130
+ refetchQueries: c,
131
+ awaitRefetchQueries: !0
132
+ }), [m, h] = a(null);
133
+ if (!r.has(o)) return null;
134
+ let g = async () => {
135
+ h(null);
136
+ try {
137
+ await e(l({ variables: { id: i } }));
138
+ } catch (e) {
139
+ h(E(e, "The timesheet could not be submitted."));
140
+ }
141
+ };
142
+ return /* @__PURE__ */ f("div", {
143
+ className: "flex flex-col items-end gap-1",
144
+ children: [/* @__PURE__ */ d(t, {
145
+ label: "Submit for approval",
146
+ icon: /* @__PURE__ */ d(s, { className: "mr-1 h-4 w-4" }),
147
+ title: "Submit this timesheet?",
148
+ description: "Its hours are locked for review. Entries in it can no longer be edited or deleted until it is approved or rejected.",
149
+ confirmLabel: "Submit",
150
+ disabled: p,
151
+ onConfirm: () => void g()
152
+ }), m && /* @__PURE__ */ d(n, { message: m })]
153
+ });
154
+ }
155
+ function k({ id: r, status: i, refetchQueries: o }) {
156
+ let [l, m] = u(w, {
157
+ refetchQueries: o,
158
+ awaitRefetchQueries: !0
159
+ }), [S, C] = u(T, {
160
+ refetchQueries: o,
161
+ awaitRefetchQueries: !0
162
+ }), [D, O] = a(!1), [k, A] = a(""), [j, M] = a(null);
163
+ if (i !== "SUBMITTED") return null;
164
+ let N = m.loading || C.loading, P = async () => {
165
+ M(null);
166
+ try {
167
+ await e(l({ variables: { id: r } }));
168
+ } catch (e) {
169
+ M(E(e, "The timesheet could not be approved."));
170
+ }
171
+ }, F = async () => {
172
+ M(null);
173
+ try {
174
+ await e(S({ variables: {
175
+ id: r,
176
+ reason: k.trim() || void 0
177
+ } })), O(!1), A("");
178
+ } catch (e) {
179
+ M(E(e, "The timesheet could not be rejected."));
180
+ }
181
+ };
182
+ return /* @__PURE__ */ f("div", {
183
+ className: "flex flex-col items-end gap-1",
184
+ children: [/* @__PURE__ */ f("div", {
185
+ className: "flex gap-2",
186
+ children: [/* @__PURE__ */ d(t, {
187
+ label: "Approve",
188
+ icon: /* @__PURE__ */ d(s, { className: "mr-1 h-4 w-4" }),
189
+ title: "Approve this timesheet?",
190
+ description: "This is a billing sign-off on the hours shown. It cannot be undone here.",
191
+ confirmLabel: "Approve",
192
+ disabled: N,
193
+ onConfirm: () => void P()
194
+ }), /* @__PURE__ */ f(h, {
195
+ open: D,
196
+ onOpenChange: (e) => {
197
+ O(e), e || A("");
198
+ },
199
+ children: [/* @__PURE__ */ d(x, {
200
+ asChild: !0,
201
+ children: /* @__PURE__ */ f(p, {
202
+ size: "sm",
203
+ variant: "outline",
204
+ disabled: N,
205
+ "data-testid": "reject-timesheet-open",
206
+ children: [/* @__PURE__ */ d(c, { className: "mr-1 h-4 w-4" }), "Reject"]
207
+ })
208
+ }), /* @__PURE__ */ f(g, {
209
+ className: "max-w-md",
210
+ children: [
211
+ /* @__PURE__ */ f(y, { children: [/* @__PURE__ */ d(b, { children: "Reject this timesheet?" }), /* @__PURE__ */ d(_, { children: "It goes back to the owner as Rejected. They can fix the entries and re-submit." })] }),
212
+ /* @__PURE__ */ f("div", {
213
+ className: "space-y-2",
214
+ children: [/* @__PURE__ */ d("label", {
215
+ htmlFor: "reject-timesheet-reason",
216
+ className: "text-sm font-medium",
217
+ children: "Reason (optional, shown to the owner)"
218
+ }), /* @__PURE__ */ d("textarea", {
219
+ id: "reject-timesheet-reason",
220
+ className: "w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[72px]",
221
+ value: k,
222
+ onChange: (e) => A(e.target.value)
223
+ })]
224
+ }),
225
+ /* @__PURE__ */ f(v, { children: [/* @__PURE__ */ d(p, {
226
+ variant: "outline",
227
+ onClick: () => O(!1),
228
+ children: "Cancel"
229
+ }), /* @__PURE__ */ d(p, {
230
+ onClick: () => void F(),
231
+ disabled: N,
232
+ "data-testid": "reject-timesheet-submit",
233
+ children: C.loading ? "Rejecting…" : "Reject"
234
+ })] })
235
+ ]
236
+ })]
237
+ })]
238
+ }), j && /* @__PURE__ */ d(n, { message: j })]
239
+ });
240
+ }
241
+ //#endregion
242
+ export { D as CreateTimesheetDialog, O as SubmitTimesheetButton, k as TimesheetApprovalActions };
243
+
244
+ //# sourceMappingURL=TimesheetControls.js.map