@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
@@ -1,7 +1,7 @@
1
1
  import { usePlanMagnet as e } from "../providers/PlanMagnetProvider.js";
2
2
  import { throwOnError as t } from "../utils/mutationResult.js";
3
- import { ProjectSelect as n } from "./Pickers.js";
4
- import { ErrorLine as r } from "./ConfirmButton.js";
3
+ import { ErrorLine as n } from "./ConfirmButton.js";
4
+ import { ProjectSelect as r } from "./Pickers.js";
5
5
  import { useDeferredValue as i, useState as a } from "react";
6
6
  import { AlarmClock as o, Check as s, GitMerge as c, Sun as l, X as u } from "lucide-react";
7
7
  import { gql as d } from "@apollo/client";
@@ -66,7 +66,7 @@ var E = {
66
66
  }
67
67
  }
68
68
  `, M = 2e3, N = ["SUBMITTED", "UNDER_REVIEW"], P = (e) => N.includes(e), F = (e, t) => !!e && new Date(e).getTime() > t, I = (e, t) => e instanceof Error ? e.message : t;
69
- function L({ trigger: e, testId: t, title: n, description: i, children: a, confirmLabel: o, canConfirm: s, busy: c, onConfirm: l, error: u, onOpenChange: d, open: f }) {
69
+ function L({ trigger: e, testId: t, title: r, description: i, children: a, confirmLabel: o, canConfirm: s, busy: c, onConfirm: l, error: u, onOpenChange: d, open: f }) {
70
70
  return /* @__PURE__ */ g(y, {
71
71
  open: f,
72
72
  onOpenChange: d,
@@ -83,10 +83,10 @@ function L({ trigger: e, testId: t, title: n, description: i, children: a, confi
83
83
  }), /* @__PURE__ */ g(b, {
84
84
  className: "max-w-lg",
85
85
  children: [
86
- /* @__PURE__ */ g(C, { children: [/* @__PURE__ */ h(w, { children: n }), /* @__PURE__ */ h(x, { children: i })] }),
86
+ /* @__PURE__ */ g(C, { children: [/* @__PURE__ */ h(w, { children: r }), /* @__PURE__ */ h(x, { children: i })] }),
87
87
  /* @__PURE__ */ g("div", {
88
88
  className: "space-y-3",
89
- children: [a, u && /* @__PURE__ */ h(r, { message: u })]
89
+ children: [a, u && /* @__PURE__ */ h(n, { message: u })]
90
90
  }),
91
91
  /* @__PURE__ */ g(S, { children: [/* @__PURE__ */ h(_, {
92
92
  variant: "outline",
@@ -102,7 +102,7 @@ function L({ trigger: e, testId: t, title: n, description: i, children: a, confi
102
102
  });
103
103
  }
104
104
  function R({ feature: e }) {
105
- let [r, i] = a(!1), [o, c] = a("PLANNED"), [l, u] = a(e.projectId ?? ""), [d, p] = a(null), [_, v] = f(D, E), y = async () => {
105
+ let [n, i] = a(!1), [o, c] = a("PLANNED"), [l, u] = a(e.projectId ?? ""), [d, p] = a(null), [_, v] = f(D, E), y = async () => {
106
106
  p(null);
107
107
  try {
108
108
  await t(_({ variables: {
@@ -117,7 +117,7 @@ function R({ feature: e }) {
117
117
  }
118
118
  };
119
119
  return /* @__PURE__ */ g(L, {
120
- open: r,
120
+ open: n,
121
121
  onOpenChange: (e) => {
122
122
  i(e), e || p(null);
123
123
  },
@@ -152,7 +152,7 @@ function R({ feature: e }) {
152
152
  children: "Project that will deliver it"
153
153
  }), /* @__PURE__ */ h("div", {
154
154
  className: "mt-1",
155
- children: /* @__PURE__ */ h(n, {
155
+ children: /* @__PURE__ */ h(r, {
156
156
  id: `triage-accept-project-${e.id}`,
157
157
  value: l,
158
158
  noneLabel: "No project yet",
@@ -354,10 +354,10 @@ function H({ feature: n }) {
354
354
  });
355
355
  }
356
356
  function U({ feature: e }) {
357
- let [n, i] = f(k, E), [o, s] = a(null), c = async () => {
357
+ let [r, i] = f(k, E), [o, s] = a(null), c = async () => {
358
358
  s(null);
359
359
  try {
360
- await t(n({ variables: {
360
+ await t(r({ variables: {
361
361
  id: e.id,
362
362
  until: null
363
363
  } }));
@@ -374,7 +374,7 @@ function U({ feature: e }) {
374
374
  e.stopPropagation(), c();
375
375
  },
376
376
  children: [/* @__PURE__ */ h(l, { className: "mr-1 h-4 w-4" }), "Back to triage"]
377
- }), o && /* @__PURE__ */ h(r, { message: o })] });
377
+ }), o && /* @__PURE__ */ h(n, { message: o })] });
378
378
  }
379
379
  function W({ feature: e, now: t }) {
380
380
  if (!P(e.status)) return null;
@@ -1,8 +1,8 @@
1
1
  import { throwOnError as e } from "../utils/mutationResult.js";
2
- import { WorkItemSearchSelect as t } from "./Pickers.js";
3
- import { ErrorLine as n } from "./ConfirmButton.js";
4
- import { endBeforeStart as r } from "../utils/formValidation.js";
5
- import { enumLabel as i } from "./WorkItemControls.js";
2
+ import { ErrorLine as t } from "./ConfirmButton.js";
3
+ import { WorkItemSearchSelect as n } from "./Pickers.js";
4
+ import { enumLabel as r } from "./WorkItemControls.js";
5
+ import { endBeforeStart as i } from "../utils/formValidation.js";
6
6
  import { useState as a } from "react";
7
7
  import { Link2 as o, Pencil as s, X as c } from "lucide-react";
8
8
  import { gql as l } from "@apollo/client";
@@ -41,13 +41,13 @@ var S = [
41
41
  refetchQueries: C,
42
42
  awaitRefetchQueries: !0
43
43
  };
44
- function O({ objective: t }) {
45
- let [r, o] = u(w, D), [s, c] = a(null), l = S.includes(t.status) ? S : [t.status, ...S], p = async (n) => {
44
+ function O({ objective: n }) {
45
+ let [i, o] = u(w, D), [s, c] = a(null), l = S.includes(n.status) ? S : [n.status, ...S], p = async (t) => {
46
46
  c(null);
47
47
  try {
48
- await e(r({ variables: {
49
- id: t.id,
50
- input: { status: n }
48
+ await e(i({ variables: {
49
+ id: n.id,
50
+ input: { status: t }
51
51
  } }));
52
52
  } catch (e) {
53
53
  c(e instanceof Error ? e.message : "The status could not be changed.");
@@ -61,38 +61,38 @@ function O({ objective: t }) {
61
61
  "aria-label": "Objective status",
62
62
  "data-testid": "objective-status",
63
63
  className: "rounded-md border border-input bg-background px-2 py-1 text-sm disabled:opacity-60",
64
- value: t.status,
64
+ value: n.status,
65
65
  disabled: o.loading,
66
66
  onChange: (e) => {
67
- e.target.value !== t.status && p(e.target.value);
67
+ e.target.value !== n.status && p(e.target.value);
68
68
  },
69
69
  children: l.map((e) => /* @__PURE__ */ d("option", {
70
70
  value: e,
71
- children: i(e)
71
+ children: r(e)
72
72
  }, e))
73
- }), /* @__PURE__ */ d(A, { objective: t })]
74
- }), s && /* @__PURE__ */ d(n, { message: s })]
73
+ }), /* @__PURE__ */ d(A, { objective: n })]
74
+ }), s && /* @__PURE__ */ d(t, { message: s })]
75
75
  });
76
76
  }
77
77
  var k = (e) => e ? e.slice(0, 10) : "";
78
- function A({ objective: t }) {
79
- let i = {
80
- title: t.title,
81
- description: t.description ?? "",
82
- periodLabel: t.periodLabel,
83
- startDate: k(t.startDate),
84
- endDate: k(t.endDate)
85
- }, [o, c] = a(!1), [l, S] = a(i), [C, T] = a(null), [E, O] = u(w, D), A = r(l.startDate, l.endDate), j = l.title.trim() !== "" && l.periodLabel.trim() !== "" && !A && !O.loading, M = async () => {
78
+ function A({ objective: n }) {
79
+ let r = {
80
+ title: n.title,
81
+ description: n.description ?? "",
82
+ periodLabel: n.periodLabel,
83
+ startDate: k(n.startDate),
84
+ endDate: k(n.endDate)
85
+ }, [o, c] = a(!1), [l, S] = a(r), [C, T] = a(null), [E, O] = u(w, D), A = i(l.startDate, l.endDate), j = l.title.trim() !== "" && l.periodLabel.trim() !== "" && !A && !O.loading, M = async () => {
86
86
  T(null);
87
- let n = {};
88
- if (l.title.trim() !== i.title && (n.title = l.title.trim()), l.periodLabel.trim() !== i.periodLabel && (n.periodLabel = l.periodLabel.trim()), l.description.trim() !== i.description.trim() && (n.description = l.description.trim() || null), l.startDate !== i.startDate && (n.startDate = l.startDate || null), l.endDate !== i.endDate && (n.endDate = l.endDate || null), Object.keys(n).length === 0) {
87
+ let t = {};
88
+ if (l.title.trim() !== r.title && (t.title = l.title.trim()), l.periodLabel.trim() !== r.periodLabel && (t.periodLabel = l.periodLabel.trim()), l.description.trim() !== r.description.trim() && (t.description = l.description.trim() || null), l.startDate !== r.startDate && (t.startDate = l.startDate || null), l.endDate !== r.endDate && (t.endDate = l.endDate || null), Object.keys(t).length === 0) {
89
89
  c(!1);
90
90
  return;
91
91
  }
92
92
  try {
93
93
  await e(E({ variables: {
94
- id: t.id,
95
- input: n
94
+ id: n.id,
95
+ input: t
96
96
  } })), c(!1);
97
97
  } catch (e) {
98
98
  T(e instanceof Error ? e.message : "The objective could not be saved.");
@@ -101,7 +101,7 @@ function A({ objective: t }) {
101
101
  return /* @__PURE__ */ f(h, {
102
102
  open: o,
103
103
  onOpenChange: (e) => {
104
- c(e), e ? S(i) : T(null);
104
+ c(e), e ? S(r) : T(null);
105
105
  },
106
106
  children: [/* @__PURE__ */ d(x, {
107
107
  asChild: !0,
@@ -177,7 +177,7 @@ function A({ objective: t }) {
177
177
  })
178
178
  })] })]
179
179
  }),
180
- A && /* @__PURE__ */ d(n, { message: "The end date is before the start date." }),
180
+ A && /* @__PURE__ */ d(t, { message: "The end date is before the start date." }),
181
181
  /* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("label", {
182
182
  htmlFor: "objective-edit-description",
183
183
  className: N,
@@ -191,7 +191,7 @@ function A({ objective: t }) {
191
191
  description: e.target.value
192
192
  })
193
193
  })] }),
194
- C && /* @__PURE__ */ d(n, { message: C })
194
+ C && /* @__PURE__ */ d(t, { message: C })
195
195
  ]
196
196
  }),
197
197
  /* @__PURE__ */ f(v, { children: [/* @__PURE__ */ d(p, {
@@ -207,14 +207,14 @@ function A({ objective: t }) {
207
207
  })]
208
208
  });
209
209
  }
210
- function j({ keyResultId: r, keyResultTitle: s, linked: l }) {
211
- let [m, h] = u(T, D), [g, _] = u(E, D), [v, y] = a(!1), [b, x] = a(""), [S, C] = a(null), w = h.loading || _.loading, O = async (t, n, i) => {
210
+ function j({ keyResultId: i, keyResultTitle: s, linked: l }) {
211
+ let [m, h] = u(T, D), [g, _] = u(E, D), [v, y] = a(!1), [b, x] = a(""), [S, C] = a(null), w = h.loading || _.loading, O = async (t, n, r) => {
212
212
  C(null);
213
213
  try {
214
214
  await e(t({ variables: {
215
- keyResultId: r,
215
+ keyResultId: i,
216
216
  workItemId: n
217
- } })), i?.();
217
+ } })), r?.();
218
218
  } catch (e) {
219
219
  C(e instanceof Error ? e.message : "The link could not be changed.");
220
220
  }
@@ -241,7 +241,7 @@ function j({ keyResultId: r, keyResultTitle: s, linked: l }) {
241
241
  className: "text-muted-foreground",
242
242
  children: [
243
243
  "(",
244
- i(e.status),
244
+ r(e.status),
245
245
  ")"
246
246
  ]
247
247
  })
@@ -259,8 +259,8 @@ function j({ keyResultId: r, keyResultTitle: s, linked: l }) {
259
259
  }),
260
260
  v ? /* @__PURE__ */ f("div", {
261
261
  className: "space-y-2 rounded-md border border-input p-2",
262
- children: [/* @__PURE__ */ d(t, {
263
- id: `kr-link-${r}`,
262
+ children: [/* @__PURE__ */ d(n, {
263
+ id: `kr-link-${i}`,
264
264
  value: b,
265
265
  onChange: x,
266
266
  exclude: l.map((e) => e.id)
@@ -286,7 +286,7 @@ function j({ keyResultId: r, keyResultTitle: s, linked: l }) {
286
286
  onClick: () => y(!0),
287
287
  children: [/* @__PURE__ */ d(o, { className: "mr-1 h-4 w-4" }), "Link work item"]
288
288
  }),
289
- S && /* @__PURE__ */ d(n, { message: S })
289
+ S && /* @__PURE__ */ d(t, { message: S })
290
290
  ]
291
291
  });
292
292
  }
@@ -1,9 +1,10 @@
1
- /** A project select. '' means "no project" when `noneLabel` is given. */
2
- export declare function ProjectSelect({ id, value, onChange, noneLabel, }: {
1
+ /** A project select. '' means "no project" when `noneLabel` is given. `exclude` hides ids already spoken for. */
2
+ export declare function ProjectSelect({ id, value, onChange, noneLabel, exclude, }: {
3
3
  id?: string;
4
4
  value: string;
5
5
  onChange: (projectId: string) => void;
6
6
  noneLabel?: string;
7
+ exclude?: string[];
7
8
  }): import("react/jsx-runtime").JSX.Element;
8
9
  /**
9
10
  * Search, then pick one work item. The server matches the key, title and description. `exclude` hides items that are
@@ -23,4 +24,18 @@ export declare function DocSearchSelect({ id, value, onChange, exclude, }: {
23
24
  onChange: (docId: string) => void;
24
25
  exclude?: string[];
25
26
  }): import("react/jsx-runtime").JSX.Element;
27
+ /** A program select. '' means "no program" when `noneLabel` is given. */
28
+ export declare function ProgramSelect({ id, value, onChange, noneLabel, }: {
29
+ id?: string;
30
+ value: string;
31
+ onChange: (programId: string) => void;
32
+ noneLabel?: string;
33
+ }): import("react/jsx-runtime").JSX.Element;
34
+ /** Search, then pick one competitor. `exclude` hides competitors already linked. */
35
+ export declare function CompetitorSearchSelect({ id, value, onChange, exclude, }: {
36
+ id: string;
37
+ value: string;
38
+ onChange: (competitorId: string) => void;
39
+ exclude?: string[];
40
+ }): import("react/jsx-runtime").JSX.Element;
26
41
  //# sourceMappingURL=Pickers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Pickers.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/controls/Pickers.tsx"],"names":[],"mappings":"AA2BA,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,EAC5B,EAAE,EACF,KAAK,EACL,QAAQ,EACR,SAAS,GACV,EAAE;IACD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,2CA8BA;AAeD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,EAAE,EACF,SAAS,EACT,KAAK,EACL,QAAQ,EACR,OAAY,GACb,EAAE;IACD,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,2CAqDA;AAcD,iCAAiC;AACjC,wBAAgB,eAAe,CAAC,EAC9B,EAAE,EACF,KAAK,EACL,QAAQ,EACR,OAAY,GACb,EAAE;IACD,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,2CA8CA"}
1
+ {"version":3,"file":"Pickers.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/controls/Pickers.tsx"],"names":[],"mappings":"AA2BA,iHAAiH;AACjH,wBAAgB,aAAa,CAAC,EAC5B,EAAE,EACF,KAAK,EACL,QAAQ,EACR,SAAS,EACT,OAAY,GACb,EAAE;IACD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,2CA8BA;AAeD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,EAAE,EACF,SAAS,EACT,KAAK,EACL,QAAQ,EACR,OAAY,GACb,EAAE;IACD,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,2CAqDA;AAcD,iCAAiC;AACjC,wBAAgB,eAAe,CAAC,EAC9B,EAAE,EACF,KAAK,EACL,QAAQ,EACR,OAAY,GACb,EAAE;IACD,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,2CA8CA;AAcD,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,EAC5B,EAAE,EACF,KAAK,EACL,QAAQ,EACR,SAAS,GACV,EAAE;IACD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,2CA8BA;AAcD,oFAAoF;AACpF,wBAAgB,sBAAsB,CAAC,EACrC,EAAE,EACF,KAAK,EACL,QAAQ,EACR,OAAY,GACb,EAAE;IACD,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,2CAkDA"}
@@ -16,11 +16,11 @@ var c = "w-full rounded-md border border-input bg-background px-3 py-2 text-sm d
16
16
  }
17
17
  }
18
18
  `;
19
- function u({ id: t, value: n, onChange: r, noneLabel: s }) {
20
- let { workspaceId: u } = e(), { data: d, loading: f, error: p } = i(l, {
21
- variables: { workspaceId: u ?? "" },
22
- skip: !u
23
- }), m = d?.planmagnetProjects.items ?? [];
19
+ function u({ id: t, value: n, onChange: r, noneLabel: s, exclude: u = [] }) {
20
+ let { workspaceId: d } = e(), { data: f, loading: p, error: m } = i(l, {
21
+ variables: { workspaceId: d ?? "" },
22
+ skip: !d
23
+ }), h = (f?.planmagnetProjects.items ?? []).filter((e) => !u.includes(e.id));
24
24
  return /* @__PURE__ */ o("select", {
25
25
  id: t,
26
26
  className: c,
@@ -31,11 +31,11 @@ function u({ id: t, value: n, onChange: r, noneLabel: s }) {
31
31
  value: "",
32
32
  children: s
33
33
  }),
34
- m.length === 0 && s === void 0 && /* @__PURE__ */ a("option", {
34
+ h.length === 0 && s === void 0 && /* @__PURE__ */ a("option", {
35
35
  value: "",
36
- children: f && !d ? "Loading projects…" : p ? "Projects could not be loaded" : "No projects yet"
36
+ children: p && !f ? "Loading projects…" : m ? "Projects could not be loaded" : "No projects yet"
37
37
  }),
38
- m.map((e) => /* @__PURE__ */ a("option", {
38
+ h.map((e) => /* @__PURE__ */ a("option", {
39
39
  value: e.id,
40
40
  children: e.name
41
41
  }, e.id))
@@ -165,7 +165,98 @@ function m({ id: r, value: l, onChange: u, exclude: d = [] }) {
165
165
  ]
166
166
  });
167
167
  }
168
+ var h = r`
169
+ query PickerPrograms($workspaceId: ID!) {
170
+ planmagnetPrograms(workspaceId: $workspaceId, pagination: { first: 100 }) {
171
+ items {
172
+ id
173
+ name
174
+ }
175
+ totalCount
176
+ }
177
+ }
178
+ `;
179
+ function g({ id: t, value: n, onChange: r, noneLabel: s }) {
180
+ let { workspaceId: l } = e(), { data: u, loading: d, error: f } = i(h, {
181
+ variables: { workspaceId: l ?? "" },
182
+ skip: !l
183
+ }), p = u?.planmagnetPrograms.items ?? [];
184
+ return /* @__PURE__ */ o("select", {
185
+ id: t,
186
+ className: c,
187
+ value: n,
188
+ onChange: (e) => r(e.target.value),
189
+ children: [
190
+ s !== void 0 && /* @__PURE__ */ a("option", {
191
+ value: "",
192
+ children: s
193
+ }),
194
+ p.length === 0 && s === void 0 && /* @__PURE__ */ a("option", {
195
+ value: "",
196
+ children: d && !u ? "Loading programs…" : f ? "Programs could not be loaded" : "No programs yet"
197
+ }),
198
+ p.map((e) => /* @__PURE__ */ a("option", {
199
+ value: e.id,
200
+ children: e.name
201
+ }, e.id))
202
+ ]
203
+ });
204
+ }
205
+ var _ = r`
206
+ query PickerCompetitors($workspaceId: ID!, $filter: PlanmagnetCompetitorFilter) {
207
+ planmagnetCompetitors(workspaceId: $workspaceId, filter: $filter, pagination: { first: 20 }) {
208
+ items {
209
+ id
210
+ name
211
+ }
212
+ totalCount
213
+ }
214
+ }
215
+ `;
216
+ function v({ id: r, value: l, onChange: u, exclude: d = [] }) {
217
+ let { workspaceId: f } = e(), [p, m] = n(""), h = t(p.trim()), { data: g, loading: v } = i(_, {
218
+ variables: {
219
+ workspaceId: f ?? "",
220
+ filter: h ? { search: h } : void 0
221
+ },
222
+ skip: !f
223
+ }), y = g?.planmagnetCompetitors.items ?? [], b = y.filter((e) => !d.includes(e.id)), x = g?.planmagnetCompetitors.totalCount ?? 0;
224
+ return /* @__PURE__ */ o("div", {
225
+ className: "space-y-1",
226
+ children: [
227
+ /* @__PURE__ */ a(s, {
228
+ "aria-label": "Search competitors",
229
+ placeholder: "Search competitors by name",
230
+ value: p,
231
+ onChange: (e) => m(e.target.value)
232
+ }),
233
+ /* @__PURE__ */ o("select", {
234
+ id: r,
235
+ className: c,
236
+ value: l,
237
+ onChange: (e) => u(e.target.value),
238
+ children: [/* @__PURE__ */ a("option", {
239
+ value: "",
240
+ children: v && !g ? "Searching…" : b.length ? "Choose a competitor" : "No match"
241
+ }), b.map((e) => /* @__PURE__ */ a("option", {
242
+ value: e.id,
243
+ children: e.name
244
+ }, e.id))]
245
+ }),
246
+ x > y.length && /* @__PURE__ */ o("p", {
247
+ className: "text-xs text-muted-foreground",
248
+ children: [
249
+ "Showing ",
250
+ y.length,
251
+ " of ",
252
+ x,
253
+ " — type to narrow the list."
254
+ ]
255
+ })
256
+ ]
257
+ });
258
+ }
168
259
  //#endregion
169
- export { m as DocSearchSelect, u as ProjectSelect, f as WorkItemSearchSelect };
260
+ export { v as CompetitorSearchSelect, m as DocSearchSelect, g as ProgramSelect, u as ProjectSelect, f as WorkItemSearchSelect };
170
261
 
171
262
  //# sourceMappingURL=Pickers.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Pickers.js","names":[],"sources":["../../../src/planmagnet/controls/Pickers.tsx"],"sourcesContent":["import { useDeferredValue, useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Input } from '@burdenoff/fe-libs/ui';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\n\n/**\n * Record pickers shared by forms and dialogs: a project select, and search-then-pick selects for work items and\n * docs. Values are record ids. Search runs on the server (never \"the first page, filtered in the browser\"), so a\n * record past the first page can still be found.\n */\n\nconst selectClass =\n 'w-full rounded-md border border-input bg-background px-3 py-2 text-sm disabled:opacity-60';\n\nconst PICKER_PROJECTS = gql`\n query PickerProjects($workspaceId: ID!) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n }\n totalCount\n }\n }\n`;\n\n/** A project select. '' means \"no project\" when `noneLabel` is given. */\nexport function ProjectSelect({\n id,\n value,\n onChange,\n noneLabel,\n}: {\n id?: string;\n value: string;\n onChange: (projectId: string) => void;\n noneLabel?: string;\n}) {\n const { workspaceId } = usePlanMagnet();\n const { data, loading, error } = useQuery<{\n planmagnetProjects: { items: { id: string; name: string }[]; totalCount: number };\n }>(PICKER_PROJECTS, { variables: { workspaceId: workspaceId ?? '' }, skip: !workspaceId });\n const projects = data?.planmagnetProjects.items ?? [];\n return (\n <select\n id={id}\n className={selectClass}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n >\n {noneLabel !== undefined && <option value=\"\">{noneLabel}</option>}\n {projects.length === 0 && noneLabel === undefined && (\n <option value=\"\">\n {loading && !data\n ? 'Loading projects…'\n : error\n ? 'Projects could not be loaded'\n : 'No projects yet'}\n </option>\n )}\n {projects.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n </select>\n );\n}\n\nconst PICKER_WORK_ITEMS = gql`\n query PickerWorkItems($workspaceId: ID!, $filter: PlanmagnetWorkItemFilter) {\n planmagnetWorkItems(workspaceId: $workspaceId, filter: $filter, pagination: { first: 20 }) {\n items {\n id\n key\n title\n }\n totalCount\n }\n }\n`;\n\n/**\n * Search, then pick one work item. The server matches the key, title and description. `exclude` hides items that are\n * already linked (the result says how many more exist, so an empty list never claims \"nothing left\" falsely).\n */\nexport function WorkItemSearchSelect({\n id,\n projectId,\n value,\n onChange,\n exclude = [],\n}: {\n id: string;\n projectId?: string;\n value: string;\n onChange: (workItemId: string) => void;\n exclude?: string[];\n}) {\n const { workspaceId } = usePlanMagnet();\n const [search, setSearch] = useState('');\n const deferred = useDeferredValue(search.trim());\n const { data, loading } = useQuery<{\n planmagnetWorkItems: {\n items: { id: string; key: string; title: string }[];\n totalCount: number;\n };\n }>(PICKER_WORK_ITEMS, {\n variables: {\n workspaceId: workspaceId ?? '',\n filter: { ...(deferred && { search: deferred }), ...(projectId && { projectId }) },\n },\n skip: !workspaceId,\n });\n const found = data?.planmagnetWorkItems.items ?? [];\n const items = found.filter((w) => !exclude.includes(w.id));\n const total = data?.planmagnetWorkItems.totalCount ?? 0;\n return (\n <div className=\"space-y-1\">\n <Input\n aria-label=\"Search work items\"\n placeholder=\"Search by key or title\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n <select\n id={id}\n className={selectClass}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n >\n <option value=\"\">\n {loading && !data ? 'Searching…' : items.length ? 'Choose a work item' : 'No match'}\n </option>\n {/* The current value stays selectable (and visible) when it is not in this page of results. */}\n {value && !items.some((w) => w.id === value) && (\n <option value={value}>Currently linked work item</option>\n )}\n {items.map((w) => (\n <option key={w.id} value={w.id}>\n {w.key} — {w.title}\n </option>\n ))}\n </select>\n {total > found.length && (\n <p className=\"text-xs text-muted-foreground\">\n Showing {found.length} of {total} — type to narrow the list.\n </p>\n )}\n </div>\n );\n}\n\nconst PICKER_DOCS = gql`\n query PickerDocs($workspaceId: String, $filter: PlanmagnetDocFilter) {\n planmagnetDocs(workspaceId: $workspaceId, filter: $filter, pagination: { first: 20 }) {\n items {\n id\n title\n }\n totalCount\n }\n }\n`;\n\n/** Search, then pick one doc. */\nexport function DocSearchSelect({\n id,\n value,\n onChange,\n exclude = [],\n}: {\n id: string;\n value: string;\n onChange: (docId: string) => void;\n exclude?: string[];\n}) {\n const { workspaceId } = usePlanMagnet();\n const [search, setSearch] = useState('');\n const deferred = useDeferredValue(search.trim());\n const { data, loading } = useQuery<{\n planmagnetDocs: { items: { id: string; title: string }[]; totalCount: number };\n }>(PICKER_DOCS, {\n variables: {\n workspaceId: workspaceId ?? '',\n filter: deferred ? { search: deferred } : undefined,\n },\n skip: !workspaceId,\n });\n const found = data?.planmagnetDocs.items ?? [];\n const docs = found.filter((d) => !exclude.includes(d.id));\n const total = data?.planmagnetDocs.totalCount ?? 0;\n return (\n <div className=\"space-y-1\">\n <Input\n aria-label=\"Search docs\"\n placeholder=\"Search docs by title\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n <select\n id={id}\n className={selectClass}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n >\n <option value=\"\">\n {loading && !data ? 'Searching…' : docs.length ? 'Choose a doc' : 'No match'}\n </option>\n {docs.map((d) => (\n <option key={d.id} value={d.id}>\n {d.title}\n </option>\n ))}\n </select>\n {total > found.length && (\n <p className=\"text-xs text-muted-foreground\">\n Showing {found.length} of {total} — type to narrow the list.\n </p>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Pickers.js","names":[],"sources":["../../../src/planmagnet/controls/Pickers.tsx"],"sourcesContent":["import { useDeferredValue, useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Input } from '@burdenoff/fe-libs/ui';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\n\n/**\n * Record pickers shared by forms and dialogs: a project select, and search-then-pick selects for work items and\n * docs. Values are record ids. Search runs on the server (never \"the first page, filtered in the browser\"), so a\n * record past the first page can still be found.\n */\n\nconst selectClass =\n 'w-full rounded-md border border-input bg-background px-3 py-2 text-sm disabled:opacity-60';\n\nconst PICKER_PROJECTS = gql`\n query PickerProjects($workspaceId: ID!) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n }\n totalCount\n }\n }\n`;\n\n/** A project select. '' means \"no project\" when `noneLabel` is given. `exclude` hides ids already spoken for. */\nexport function ProjectSelect({\n id,\n value,\n onChange,\n noneLabel,\n exclude = [],\n}: {\n id?: string;\n value: string;\n onChange: (projectId: string) => void;\n noneLabel?: string;\n exclude?: string[];\n}) {\n const { workspaceId } = usePlanMagnet();\n const { data, loading, error } = useQuery<{\n planmagnetProjects: { items: { id: string; name: string }[]; totalCount: number };\n }>(PICKER_PROJECTS, { variables: { workspaceId: workspaceId ?? '' }, skip: !workspaceId });\n const projects = (data?.planmagnetProjects.items ?? []).filter((p) => !exclude.includes(p.id));\n return (\n <select\n id={id}\n className={selectClass}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n >\n {noneLabel !== undefined && <option value=\"\">{noneLabel}</option>}\n {projects.length === 0 && noneLabel === undefined && (\n <option value=\"\">\n {loading && !data\n ? 'Loading projects…'\n : error\n ? 'Projects could not be loaded'\n : 'No projects yet'}\n </option>\n )}\n {projects.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n </select>\n );\n}\n\nconst PICKER_WORK_ITEMS = gql`\n query PickerWorkItems($workspaceId: ID!, $filter: PlanmagnetWorkItemFilter) {\n planmagnetWorkItems(workspaceId: $workspaceId, filter: $filter, pagination: { first: 20 }) {\n items {\n id\n key\n title\n }\n totalCount\n }\n }\n`;\n\n/**\n * Search, then pick one work item. The server matches the key, title and description. `exclude` hides items that are\n * already linked (the result says how many more exist, so an empty list never claims \"nothing left\" falsely).\n */\nexport function WorkItemSearchSelect({\n id,\n projectId,\n value,\n onChange,\n exclude = [],\n}: {\n id: string;\n projectId?: string;\n value: string;\n onChange: (workItemId: string) => void;\n exclude?: string[];\n}) {\n const { workspaceId } = usePlanMagnet();\n const [search, setSearch] = useState('');\n const deferred = useDeferredValue(search.trim());\n const { data, loading } = useQuery<{\n planmagnetWorkItems: {\n items: { id: string; key: string; title: string }[];\n totalCount: number;\n };\n }>(PICKER_WORK_ITEMS, {\n variables: {\n workspaceId: workspaceId ?? '',\n filter: { ...(deferred && { search: deferred }), ...(projectId && { projectId }) },\n },\n skip: !workspaceId,\n });\n const found = data?.planmagnetWorkItems.items ?? [];\n const items = found.filter((w) => !exclude.includes(w.id));\n const total = data?.planmagnetWorkItems.totalCount ?? 0;\n return (\n <div className=\"space-y-1\">\n <Input\n aria-label=\"Search work items\"\n placeholder=\"Search by key or title\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n <select\n id={id}\n className={selectClass}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n >\n <option value=\"\">\n {loading && !data ? 'Searching…' : items.length ? 'Choose a work item' : 'No match'}\n </option>\n {/* The current value stays selectable (and visible) when it is not in this page of results. */}\n {value && !items.some((w) => w.id === value) && (\n <option value={value}>Currently linked work item</option>\n )}\n {items.map((w) => (\n <option key={w.id} value={w.id}>\n {w.key} — {w.title}\n </option>\n ))}\n </select>\n {total > found.length && (\n <p className=\"text-xs text-muted-foreground\">\n Showing {found.length} of {total} — type to narrow the list.\n </p>\n )}\n </div>\n );\n}\n\nconst PICKER_DOCS = gql`\n query PickerDocs($workspaceId: String, $filter: PlanmagnetDocFilter) {\n planmagnetDocs(workspaceId: $workspaceId, filter: $filter, pagination: { first: 20 }) {\n items {\n id\n title\n }\n totalCount\n }\n }\n`;\n\n/** Search, then pick one doc. */\nexport function DocSearchSelect({\n id,\n value,\n onChange,\n exclude = [],\n}: {\n id: string;\n value: string;\n onChange: (docId: string) => void;\n exclude?: string[];\n}) {\n const { workspaceId } = usePlanMagnet();\n const [search, setSearch] = useState('');\n const deferred = useDeferredValue(search.trim());\n const { data, loading } = useQuery<{\n planmagnetDocs: { items: { id: string; title: string }[]; totalCount: number };\n }>(PICKER_DOCS, {\n variables: {\n workspaceId: workspaceId ?? '',\n filter: deferred ? { search: deferred } : undefined,\n },\n skip: !workspaceId,\n });\n const found = data?.planmagnetDocs.items ?? [];\n const docs = found.filter((d) => !exclude.includes(d.id));\n const total = data?.planmagnetDocs.totalCount ?? 0;\n return (\n <div className=\"space-y-1\">\n <Input\n aria-label=\"Search docs\"\n placeholder=\"Search docs by title\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n <select\n id={id}\n className={selectClass}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n >\n <option value=\"\">\n {loading && !data ? 'Searching…' : docs.length ? 'Choose a doc' : 'No match'}\n </option>\n {docs.map((d) => (\n <option key={d.id} value={d.id}>\n {d.title}\n </option>\n ))}\n </select>\n {total > found.length && (\n <p className=\"text-xs text-muted-foreground\">\n Showing {found.length} of {total} — type to narrow the list.\n </p>\n )}\n </div>\n );\n}\n\nconst PICKER_PROGRAMS = gql`\n query PickerPrograms($workspaceId: ID!) {\n planmagnetPrograms(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n }\n totalCount\n }\n }\n`;\n\n/** A program select. '' means \"no program\" when `noneLabel` is given. */\nexport function ProgramSelect({\n id,\n value,\n onChange,\n noneLabel,\n}: {\n id?: string;\n value: string;\n onChange: (programId: string) => void;\n noneLabel?: string;\n}) {\n const { workspaceId } = usePlanMagnet();\n const { data, loading, error } = useQuery<{\n planmagnetPrograms: { items: { id: string; name: string }[]; totalCount: number };\n }>(PICKER_PROGRAMS, { variables: { workspaceId: workspaceId ?? '' }, skip: !workspaceId });\n const programs = data?.planmagnetPrograms.items ?? [];\n return (\n <select\n id={id}\n className={selectClass}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n >\n {noneLabel !== undefined && <option value=\"\">{noneLabel}</option>}\n {programs.length === 0 && noneLabel === undefined && (\n <option value=\"\">\n {loading && !data\n ? 'Loading programs…'\n : error\n ? 'Programs could not be loaded'\n : 'No programs yet'}\n </option>\n )}\n {programs.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n </select>\n );\n}\n\nconst PICKER_COMPETITORS = gql`\n query PickerCompetitors($workspaceId: ID!, $filter: PlanmagnetCompetitorFilter) {\n planmagnetCompetitors(workspaceId: $workspaceId, filter: $filter, pagination: { first: 20 }) {\n items {\n id\n name\n }\n totalCount\n }\n }\n`;\n\n/** Search, then pick one competitor. `exclude` hides competitors already linked. */\nexport function CompetitorSearchSelect({\n id,\n value,\n onChange,\n exclude = [],\n}: {\n id: string;\n value: string;\n onChange: (competitorId: string) => void;\n exclude?: string[];\n}) {\n const { workspaceId } = usePlanMagnet();\n const [search, setSearch] = useState('');\n const deferred = useDeferredValue(search.trim());\n const { data, loading } = useQuery<{\n planmagnetCompetitors: { items: { id: string; name: string }[]; totalCount: number };\n }>(PICKER_COMPETITORS, {\n variables: {\n workspaceId: workspaceId ?? '',\n filter: deferred ? { search: deferred } : undefined,\n },\n skip: !workspaceId,\n });\n const found = data?.planmagnetCompetitors.items ?? [];\n const competitors = found.filter((c) => !exclude.includes(c.id));\n const total = data?.planmagnetCompetitors.totalCount ?? 0;\n return (\n <div className=\"space-y-1\">\n <Input\n aria-label=\"Search competitors\"\n placeholder=\"Search competitors by name\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n <select\n id={id}\n className={selectClass}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n >\n <option value=\"\">\n {loading && !data\n ? 'Searching…'\n : competitors.length\n ? 'Choose a competitor'\n : 'No match'}\n </option>\n {competitors.map((c) => (\n <option key={c.id} value={c.id}>\n {c.name}\n </option>\n ))}\n </select>\n {total > found.length && (\n <p className=\"text-xs text-muted-foreground\">\n Showing {found.length} of {total} — type to narrow the list.\n </p>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Portfolio controls (BOFF-8047). Portfolios were `api-only` — full CRUD and the overview roll-up existed in
3
+ * the service (BOFF-7704, BOFF-7934) but had zero routes anywhere in the UI.
4
+ */
5
+ export declare const PORTFOLIO_STATUSES: readonly ["ACTIVE", "ON_HOLD", "CLOSED", "ARCHIVED"];
6
+ /** Every StrategicAlignment value. CUSTOM requires `alignmentLabel` — the service refuses CUSTOM without one. */
7
+ export declare const STRATEGIC_ALIGNMENTS: readonly ["REVENUE_GROWTH", "COST_REDUCTION", "CUSTOMER_SATISFACTION", "INNOVATION", "COMPLIANCE", "OPERATIONAL_EXCELLENCE", "MARKET_EXPANSION", "RISK_MITIGATION", "CUSTOM"];
8
+ export declare function PortfolioHeaderActions({ portfolioId, name, status, }: {
9
+ portfolioId: string;
10
+ name: string;
11
+ status: string;
12
+ }): import("react/jsx-runtime").JSX.Element;
13
+ //# sourceMappingURL=PortfolioControls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PortfolioControls.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/controls/PortfolioControls.tsx"],"names":[],"mappings":"AAWA;;;GAGG;AAEH,eAAO,MAAM,kBAAkB,sDAAuD,CAAC;AAEvF,iHAAiH;AACjH,eAAO,MAAM,oBAAoB,+KAUvB,CAAC;AAuBX,wBAAgB,sBAAsB,CAAC,EACrC,WAAW,EACX,IAAI,EACJ,MAAM,GACP,EAAE;IACD,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB,2CA+EA"}
@@ -0,0 +1,114 @@
1
+ import { usePlanMagnetNavigate as e } from "../providers/PlanMagnetProvider.js";
2
+ import { LEAVES_PAGE_CONTEXT as t, throwOnError as n } from "../utils/mutationResult.js";
3
+ import { ConfirmButton as r, ErrorLine as i } from "./ConfirmButton.js";
4
+ import { enumLabel as a } from "./WorkItemControls.js";
5
+ import { detailPath as o } from "../utils/rowNavigation.js";
6
+ import { useState as s } from "react";
7
+ import { Pencil as c, Trash2 as l } from "lucide-react";
8
+ import { gql as u } from "@apollo/client";
9
+ import { useMutation as d } from "@apollo/client/react";
10
+ import { jsx as f, jsxs as p } from "react/jsx-runtime";
11
+ import { Button as m } from "@burdenoff/fe-libs/ui";
12
+ //#region src/planmagnet/controls/PortfolioControls.tsx
13
+ var h = [
14
+ "ACTIVE",
15
+ "ON_HOLD",
16
+ "CLOSED",
17
+ "ARCHIVED"
18
+ ], g = [
19
+ "REVENUE_GROWTH",
20
+ "COST_REDUCTION",
21
+ "CUSTOMER_SATISFACTION",
22
+ "INNOVATION",
23
+ "COMPLIANCE",
24
+ "OPERATIONAL_EXCELLENCE",
25
+ "MARKET_EXPANSION",
26
+ "RISK_MITIGATION",
27
+ "CUSTOM"
28
+ ], _ = [
29
+ "ListPortfolios",
30
+ "GetPortfolio",
31
+ "GetPortfolioForEdit",
32
+ "GetPortfolioOverview"
33
+ ], v = u`
34
+ mutation PortfolioControlsStatus($id: ID!, $input: PlanmagnetUpdatePortfolioInput!) {
35
+ planmagnetUpdatePortfolio(id: $id, input: $input) {
36
+ id
37
+ status
38
+ }
39
+ }
40
+ `, y = u`
41
+ mutation PortfolioControlsDelete($id: ID!) {
42
+ planmagnetDeletePortfolio(id: $id)
43
+ }
44
+ `;
45
+ function b({ portfolioId: u, name: g, status: b }) {
46
+ let x = e(), [S, C] = d(v, {
47
+ refetchQueries: _,
48
+ awaitRefetchQueries: !0
49
+ }), [w, T] = d(y, {
50
+ refetchQueries: _.filter((e) => e !== "GetPortfolio" && e !== "GetPortfolioOverview"),
51
+ context: t
52
+ }), [E, D] = s(null), O = C.loading || T.loading, k = h.includes(b) ? h : [b, ...h], A = async (e) => {
53
+ D(null);
54
+ try {
55
+ await n(S({ variables: {
56
+ id: u,
57
+ input: { status: e }
58
+ } }));
59
+ } catch (e) {
60
+ D(e instanceof Error ? e.message : "The status could not be changed.");
61
+ }
62
+ }, j = async () => {
63
+ D(null);
64
+ try {
65
+ await n(w({ variables: { id: u } })), x("/products/portfolios-page");
66
+ } catch (e) {
67
+ D(e instanceof Error ? e.message : "The portfolio could not be deleted.");
68
+ }
69
+ };
70
+ return /* @__PURE__ */ p("div", {
71
+ className: "flex flex-col items-end gap-2",
72
+ children: [/* @__PURE__ */ p("div", {
73
+ className: "flex flex-wrap items-center justify-end gap-2",
74
+ children: [
75
+ /* @__PURE__ */ f("select", {
76
+ "aria-label": "Portfolio status",
77
+ "data-testid": "portfolio-status",
78
+ className: "rounded-md border border-input bg-background px-2 py-1 text-sm disabled:opacity-60",
79
+ value: b,
80
+ disabled: O,
81
+ onChange: (e) => {
82
+ e.target.value !== b && A(e.target.value);
83
+ },
84
+ children: k.map((e) => /* @__PURE__ */ f("option", {
85
+ value: e,
86
+ children: a(e)
87
+ }, e))
88
+ }),
89
+ /* @__PURE__ */ p(m, {
90
+ size: "sm",
91
+ variant: "outline",
92
+ "data-testid": "portfolio-edit",
93
+ onClick: () => x(o("/products/edit-portfolio-page", u)),
94
+ children: [/* @__PURE__ */ f(c, { className: "mr-1 h-4 w-4" }), "Edit"]
95
+ }),
96
+ /* @__PURE__ */ f(r, {
97
+ label: "Delete",
98
+ variant: "outline",
99
+ icon: /* @__PURE__ */ f(l, { className: "mr-1 h-4 w-4" }),
100
+ title: `Delete portfolio ${g}?`,
101
+ description: "The portfolio is deleted. Programs and projects it groups are not deleted. This cannot be undone here.",
102
+ confirmLabel: "Delete portfolio",
103
+ destructive: !0,
104
+ disabled: O,
105
+ onConfirm: () => void j()
106
+ })
107
+ ]
108
+ }), E && /* @__PURE__ */ f(i, { message: E })]
109
+ });
110
+ }
111
+ //#endregion
112
+ export { h as PORTFOLIO_STATUSES, b as PortfolioHeaderActions, g as STRATEGIC_ALIGNMENTS };
113
+
114
+ //# sourceMappingURL=PortfolioControls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PortfolioControls.js","names":[],"sources":["../../../src/planmagnet/controls/PortfolioControls.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation } from '@apollo/client/react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Pencil, Trash2 } from 'lucide-react';\nimport { usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { detailPath } from '../utils/rowNavigation';\nimport { throwOnError, LEAVES_PAGE_CONTEXT } from '../utils/mutationResult';\nimport { ConfirmButton, ErrorLine } from './ConfirmButton';\nimport { enumLabel } from './WorkItemControls';\n\n/**\n * Portfolio controls (BOFF-8047). Portfolios were `api-only` — full CRUD and the overview roll-up existed in\n * the service (BOFF-7704, BOFF-7934) but had zero routes anywhere in the UI.\n */\n\nexport const PORTFOLIO_STATUSES = ['ACTIVE', 'ON_HOLD', 'CLOSED', 'ARCHIVED'] as const;\n\n/** Every StrategicAlignment value. CUSTOM requires `alignmentLabel` — the service refuses CUSTOM without one. */\nexport const STRATEGIC_ALIGNMENTS = [\n 'REVENUE_GROWTH',\n 'COST_REDUCTION',\n 'CUSTOMER_SATISFACTION',\n 'INNOVATION',\n 'COMPLIANCE',\n 'OPERATIONAL_EXCELLENCE',\n 'MARKET_EXPANSION',\n 'RISK_MITIGATION',\n 'CUSTOM',\n] as const;\n\nconst PORTFOLIO_QUERIES = [\n 'ListPortfolios',\n 'GetPortfolio',\n 'GetPortfolioForEdit',\n 'GetPortfolioOverview',\n];\n\nconst UPDATE_STATUS = gql`\n mutation PortfolioControlsStatus($id: ID!, $input: PlanmagnetUpdatePortfolioInput!) {\n planmagnetUpdatePortfolio(id: $id, input: $input) {\n id\n status\n }\n }\n`;\nconst DELETE = gql`\n mutation PortfolioControlsDelete($id: ID!) {\n planmagnetDeletePortfolio(id: $id)\n }\n`;\n\nexport function PortfolioHeaderActions({\n portfolioId,\n name,\n status,\n}: {\n portfolioId: string;\n name: string;\n status: string;\n}) {\n const navigate = usePlanMagnetNavigate();\n const [updateStatus, statusState] = useMutation(UPDATE_STATUS, {\n refetchQueries: PORTFOLIO_QUERIES,\n awaitRefetchQueries: true,\n });\n const [remove, removeState] = useMutation(DELETE, {\n refetchQueries: PORTFOLIO_QUERIES.filter(\n (q) => q !== 'GetPortfolio' && q !== 'GetPortfolioOverview'\n ),\n context: LEAVES_PAGE_CONTEXT,\n });\n const [error, setError] = useState<string | null>(null);\n const busy = statusState.loading || removeState.loading;\n const statuses = (PORTFOLIO_STATUSES as readonly string[]).includes(status)\n ? PORTFOLIO_STATUSES\n : [status, ...PORTFOLIO_STATUSES];\n\n const onStatus = async (next: string) => {\n setError(null);\n try {\n await throwOnError(updateStatus({ variables: { id: portfolioId, input: { status: next } } }));\n } catch (e) {\n setError(e instanceof Error ? e.message : 'The status could not be changed.');\n }\n };\n const onDelete = async () => {\n setError(null);\n try {\n await throwOnError(remove({ variables: { id: portfolioId } }));\n navigate('/products/portfolios-page');\n } catch (e) {\n setError(e instanceof Error ? e.message : 'The portfolio could not be deleted.');\n }\n };\n\n return (\n <div className=\"flex flex-col items-end gap-2\">\n <div className=\"flex flex-wrap items-center justify-end gap-2\">\n <select\n aria-label=\"Portfolio status\"\n data-testid=\"portfolio-status\"\n className=\"rounded-md border border-input bg-background px-2 py-1 text-sm disabled:opacity-60\"\n value={status}\n disabled={busy}\n onChange={(e) => {\n if (e.target.value !== status) void onStatus(e.target.value);\n }}\n >\n {statuses.map((s) => (\n <option key={s} value={s}>\n {enumLabel(s)}\n </option>\n ))}\n </select>\n <Button\n size=\"sm\"\n variant=\"outline\"\n data-testid=\"portfolio-edit\"\n onClick={() => navigate(detailPath('/products/edit-portfolio-page', portfolioId))}\n >\n <Pencil className=\"mr-1 h-4 w-4\" />\n Edit\n </Button>\n <ConfirmButton\n label=\"Delete\"\n variant=\"outline\"\n icon={<Trash2 className=\"mr-1 h-4 w-4\" />}\n title={`Delete portfolio ${name}?`}\n description=\"The portfolio is deleted. Programs and projects it groups are not deleted. This cannot be undone here.\"\n confirmLabel=\"Delete portfolio\"\n destructive\n disabled={busy}\n onConfirm={() => void onDelete()}\n />\n </div>\n {error && <ErrorLine message={error} />}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;AAgBA,IAAa,IAAqB;CAAC;CAAU;CAAW;CAAU;CAAW,EAGhE,IAAuB;CAClC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,EAEK,IAAoB;CACxB;CACA;CACA;CACA;CACD,EAEK,IAAgB,CAAG;;;;;;;GAQnB,IAAS,CAAG;;;;;AAMlB,SAAgB,EAAuB,EACrC,gBACA,SACA,aAKC;CACD,IAAM,IAAW,GAAuB,EAClC,CAAC,GAAc,KAAe,EAAY,GAAe;EAC7D,gBAAgB;EAChB,qBAAqB;EACtB,CAAC,EACI,CAAC,GAAQ,KAAe,EAAY,GAAQ;EAChD,gBAAgB,EAAkB,QAC/B,MAAM,MAAM,kBAAkB,MAAM,uBACtC;EACD,SAAS;EACV,CAAC,EACI,CAAC,GAAO,KAAY,EAAwB,KAAK,EACjD,IAAO,EAAY,WAAW,EAAY,SAC1C,IAAY,EAAyC,SAAS,EAAO,GACvE,IACA,CAAC,GAAQ,GAAG,EAAmB,EAE7B,IAAW,OAAO,MAAiB;AACvC,IAAS,KAAK;AACd,MAAI;AACF,SAAM,EAAa,EAAa,EAAE,WAAW;IAAE,IAAI;IAAa,OAAO,EAAE,QAAQ,GAAM;IAAE,EAAE,CAAC,CAAC;WACtF,GAAG;AACV,KAAS,aAAa,QAAQ,EAAE,UAAU,mCAAmC;;IAG3E,IAAW,YAAY;AAC3B,IAAS,KAAK;AACd,MAAI;AAEF,GADA,MAAM,EAAa,EAAO,EAAE,WAAW,EAAE,IAAI,GAAa,EAAE,CAAC,CAAC,EAC9D,EAAS,4BAA4B;WAC9B,GAAG;AACV,KAAS,aAAa,QAAQ,EAAE,UAAU,sCAAsC;;;AAIpF,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,UAAD;KACE,cAAW;KACX,eAAY;KACZ,WAAU;KACV,OAAO;KACP,UAAU;KACV,WAAW,MAAM;AACf,MAAI,EAAE,OAAO,UAAU,KAAa,EAAS,EAAE,OAAO,MAAM;;eAG7D,EAAS,KAAK,MACb,kBAAC,UAAD;MAAgB,OAAO;gBACpB,EAAU,EAAE;MACN,EAFI,EAEJ,CACT;KACK,CAAA;IACT,kBAAC,GAAD;KACE,MAAK;KACL,SAAQ;KACR,eAAY;KACZ,eAAe,EAAS,EAAW,iCAAiC,EAAY,CAAC;eAJnF,CAME,kBAAC,GAAD,EAAQ,WAAU,gBAAiB,CAAA,EAAA,OAE5B;;IACT,kBAAC,GAAD;KACE,OAAM;KACN,SAAQ;KACR,MAAM,kBAAC,GAAD,EAAQ,WAAU,gBAAiB,CAAA;KACzC,OAAO,oBAAoB,EAAK;KAChC,aAAY;KACZ,cAAa;KACb,aAAA;KACA,UAAU;KACV,iBAAiB,KAAK,GAAU;KAChC,CAAA;IACE;MACL,KAAS,kBAAC,GAAD,EAAW,SAAS,GAAS,CAAA,CACnC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Program controls (BOFF-8047). Programs were `api-only` — full CRUD and project attachment existed in the
3
+ * service (BOFF-7704) but had zero routes anywhere in the UI. `Program.status` reuses `PlanmagnetProjectStatus`
4
+ * (the SDL declares it that way), so the status list is the same as a project's.
5
+ */
6
+ export declare const PROGRAM_STATUSES: readonly ["PLANNING", "ACTIVE", "ON_HOLD", "COMPLETED", "CANCELLED", "ARCHIVED"];
7
+ export declare function ProgramHeaderActions({ programId, name, status, }: {
8
+ programId: string;
9
+ name: string;
10
+ status: string;
11
+ }): import("react/jsx-runtime").JSX.Element;
12
+ /**
13
+ * Add / remove projects on a program. `Program.projects` reads `Project.programId` (BOFF-7704); the only
14
+ * mutation that writes it is `planmagnetUpdateProject`, so attaching happens from the project side even
15
+ * though this card lives on the program.
16
+ */
17
+ export declare function ProgramProjectsCard({ programId, projects, }: {
18
+ programId: string;
19
+ projects: {
20
+ id: string;
21
+ name: string;
22
+ status: string;
23
+ }[];
24
+ }): import("react/jsx-runtime").JSX.Element;
25
+ //# sourceMappingURL=ProgramControls.d.ts.map