@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,23 @@
1
+ /**
2
+ * Automation rule controls (BOFF-8047): enable/disable, delete and "run now". Every automation rule row and its
3
+ * detail page carry these — before this, `planmagnetToggleAutomationRule`, `planmagnetDeleteAutomationRule` and
4
+ * `planmagnetExecuteAutomationRule` were real, prod-verified mutations with no UI trigger anywhere.
5
+ */
6
+ export declare const AUTOMATION_RULE_QUERIES: string[];
7
+ /** ACTIVE <-> PAUSED. A rule stuck in DISABLED or ERROR is re-activated by turning this on; the raw status is
8
+ * shown alongside so a paused-by-error rule is never confused with a manually paused one. */
9
+ export declare function AutomationRuleStatusSwitch({ ruleId, status }: {
10
+ ruleId: string;
11
+ status: string;
12
+ }): import("react/jsx-runtime").JSX.Element;
13
+ export declare function AutomationRuleDeleteButton({ ruleId, name }: {
14
+ ruleId: string;
15
+ name: string;
16
+ }): import("react/jsx-runtime").JSX.Element;
17
+ /** Runs a rule against one chosen work item — works for a rule of ANY trigger type, including the ones that
18
+ * cannot fire on their own (see automationRuleTypes.ts). Always records an outcome, including a non-match. */
19
+ export declare function RunAutomationRuleDialog({ ruleId, projectId, }: {
20
+ ruleId: string;
21
+ projectId?: string;
22
+ }): import("react/jsx-runtime").JSX.Element;
23
+ //# sourceMappingURL=AutomationRuleControls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AutomationRuleControls.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/controls/AutomationRuleControls.tsx"],"names":[],"mappings":"AAqBA;;;;GAIG;AAEH,eAAO,MAAM,uBAAuB,UAA+C,CAAC;AA0BpF;6FAC6F;AAC7F,wBAAgB,0BAA0B,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,2CAqChG;AAED,wBAAgB,0BAA0B,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,2CAkC5F;AAcD;8GAC8G;AAC9G,wBAAgB,uBAAuB,CAAC,EACtC,MAAM,EACN,SAAS,GACV,EAAE;IACD,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,2CAmGA"}
@@ -0,0 +1,172 @@
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 { WorkItemSearchSelect as a } from "./Pickers.js";
5
+ import { useState as o } from "react";
6
+ import { Play as s, Trash2 as c } from "lucide-react";
7
+ import { gql as l } from "@apollo/client";
8
+ import { useMutation as u } from "@apollo/client/react";
9
+ import { jsx as d, jsxs as f } from "react/jsx-runtime";
10
+ import { Badge as p, Button as m, ResponsiveDialog as h, ResponsiveDialogContent as g, ResponsiveDialogDescription as _, ResponsiveDialogFooter as v, ResponsiveDialogHeader as y, ResponsiveDialogTitle as b, ResponsiveDialogTrigger as x, Switch as S } from "@burdenoff/fe-libs/ui";
11
+ //#region src/planmagnet/controls/AutomationRuleControls.tsx
12
+ var C = ["AutomationRulesList", "GetAutomationRule"], w = l`
13
+ mutation AutomationRuleControlsToggle($id: ID!, $status: PlanmagnetAutomationStatus!) {
14
+ planmagnetToggleAutomationRule(id: $id, status: $status) {
15
+ id
16
+ status
17
+ }
18
+ }
19
+ `, T = l`
20
+ mutation AutomationRuleControlsDelete($id: ID!) {
21
+ planmagnetDeleteAutomationRule(id: $id)
22
+ }
23
+ `, E = l`
24
+ mutation AutomationRuleControlsExecute($id: ID!, $triggerData: JSON) {
25
+ planmagnetExecuteAutomationRule(id: $id, triggerData: $triggerData) {
26
+ id
27
+ status
28
+ errorMessage
29
+ result
30
+ }
31
+ }
32
+ `;
33
+ function D({ ruleId: e, status: t }) {
34
+ let [r, { loading: a }] = u(w, { refetchQueries: C }), [s, c] = o(null), l = t === "ACTIVE", m = async (t) => {
35
+ c(null);
36
+ try {
37
+ await n(r({ variables: {
38
+ id: e,
39
+ status: t ? "ACTIVE" : "PAUSED"
40
+ } }));
41
+ } catch (e) {
42
+ c(e instanceof Error ? e.message : "The rule could not be changed.");
43
+ }
44
+ };
45
+ return /* @__PURE__ */ f("div", {
46
+ className: "flex flex-col items-end gap-1",
47
+ children: [/* @__PURE__ */ f("div", {
48
+ className: "flex items-center gap-2",
49
+ children: [t !== "ACTIVE" && t !== "PAUSED" && /* @__PURE__ */ d(p, {
50
+ variant: t === "ERROR" ? "destructive" : "secondary",
51
+ children: t.toLowerCase()
52
+ }), /* @__PURE__ */ d(S, {
53
+ "aria-label": l ? "Active — turn off to pause" : "Paused — turn on to activate",
54
+ "data-testid": "automation-rule-toggle",
55
+ checked: l,
56
+ disabled: a,
57
+ onCheckedChange: (e) => void m(e)
58
+ })]
59
+ }), s && /* @__PURE__ */ d(i, { message: s })]
60
+ });
61
+ }
62
+ function O({ ruleId: a, name: s }) {
63
+ let l = e(), [p, { loading: m }] = u(T, {
64
+ refetchQueries: C.filter((e) => e !== "GetAutomationRule"),
65
+ context: t
66
+ }), [h, g] = o(null), _ = async () => {
67
+ g(null);
68
+ try {
69
+ await n(p({ variables: { id: a } })), l("/automation/automation-rules-page");
70
+ } catch (e) {
71
+ g(e instanceof Error ? e.message : "The rule could not be deleted.");
72
+ }
73
+ };
74
+ return /* @__PURE__ */ f("div", {
75
+ className: "flex flex-col items-end gap-1",
76
+ children: [/* @__PURE__ */ d(r, {
77
+ label: "Delete",
78
+ variant: "outline",
79
+ icon: /* @__PURE__ */ d(c, { className: "mr-1 h-4 w-4" }),
80
+ title: `Delete "${s}"?`,
81
+ description: "The rule stops running and its history stays as a record. This cannot be undone here.",
82
+ confirmLabel: "Delete rule",
83
+ destructive: !0,
84
+ disabled: m,
85
+ onConfirm: () => void _()
86
+ }), h && /* @__PURE__ */ d(i, { message: h })]
87
+ });
88
+ }
89
+ var k = {
90
+ SUCCESS: "success",
91
+ PARTIAL_FAILURE: "warning",
92
+ FAILURE: "destructive",
93
+ SKIPPED: "secondary"
94
+ };
95
+ function A({ ruleId: e, projectId: t }) {
96
+ let [r, c] = o(!1), [l, S] = o(""), [w, T] = o(null), [D, O] = o(null), [A, { loading: j }] = u(E, {
97
+ refetchQueries: ["AutomationExecutionsForRule", ...C],
98
+ awaitRefetchQueries: !0
99
+ }), M = async () => {
100
+ if (l) {
101
+ T(null), O(null);
102
+ try {
103
+ O((await n(A({ variables: {
104
+ id: e,
105
+ triggerData: { workItemId: l }
106
+ } }))).data?.planmagnetExecuteAutomationRule ?? null);
107
+ } catch (e) {
108
+ T(e instanceof Error ? e.message : "The rule could not be run.");
109
+ }
110
+ }
111
+ };
112
+ return /* @__PURE__ */ f(h, {
113
+ open: r,
114
+ onOpenChange: (e) => {
115
+ c(e), e && (S(""), T(null), O(null));
116
+ },
117
+ children: [/* @__PURE__ */ d(x, {
118
+ asChild: !0,
119
+ children: /* @__PURE__ */ f(m, {
120
+ size: "sm",
121
+ variant: "outline",
122
+ "data-testid": "automation-run-now",
123
+ children: [/* @__PURE__ */ d(s, { className: "mr-1 h-4 w-4" }), "Run now"]
124
+ })
125
+ }), /* @__PURE__ */ f(g, {
126
+ className: "max-w-lg",
127
+ children: [
128
+ /* @__PURE__ */ f(y, { children: [/* @__PURE__ */ d(b, { children: "Run this rule now" }), /* @__PURE__ */ d(_, { children: "Evaluates the rule's conditions against one work item and, if they match, dispatches its actions for real. The outcome is recorded below and in Recent executions either way." })] }),
129
+ /* @__PURE__ */ f("div", {
130
+ className: "space-y-3",
131
+ children: [
132
+ /* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("label", {
133
+ htmlFor: "automation-run-work-item",
134
+ className: "text-sm font-medium",
135
+ children: "Work item"
136
+ }), /* @__PURE__ */ d("div", {
137
+ className: "mt-1",
138
+ children: /* @__PURE__ */ d(a, {
139
+ id: "automation-run-work-item",
140
+ projectId: t,
141
+ value: l,
142
+ onChange: S
143
+ })
144
+ })] }),
145
+ w && /* @__PURE__ */ d(i, { message: w }),
146
+ D && /* @__PURE__ */ f("div", {
147
+ role: "status",
148
+ className: "rounded-md border p-3 text-sm space-y-1",
149
+ children: [/* @__PURE__ */ d(p, {
150
+ variant: k[D.status] ?? "secondary",
151
+ children: D.status.toLowerCase().replace("_", " ")
152
+ }), D.errorMessage && /* @__PURE__ */ d("p", {
153
+ className: D.status === "SUCCESS" ? "text-muted-foreground" : "text-destructive",
154
+ children: D.errorMessage
155
+ })]
156
+ })
157
+ ]
158
+ }),
159
+ /* @__PURE__ */ d(v, { children: /* @__PURE__ */ d(m, {
160
+ onClick: () => void M(),
161
+ disabled: !l || j,
162
+ "data-testid": "automation-run-submit",
163
+ children: j ? "Running…" : "Run"
164
+ }) })
165
+ ]
166
+ })]
167
+ });
168
+ }
169
+ //#endregion
170
+ export { C as AUTOMATION_RULE_QUERIES, O as AutomationRuleDeleteButton, D as AutomationRuleStatusSwitch, A as RunAutomationRuleDialog };
171
+
172
+ //# sourceMappingURL=AutomationRuleControls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AutomationRuleControls.js","names":[],"sources":["../../../src/planmagnet/controls/AutomationRuleControls.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation } from '@apollo/client/react';\nimport {\n Badge,\n Button,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogTrigger,\n Switch,\n} from '@burdenoff/fe-libs/ui';\nimport { Play, Trash2 } from 'lucide-react';\nimport { WorkItemSearchSelect } from './Pickers';\nimport { ConfirmButton, ErrorLine } from './ConfirmButton';\nimport { throwOnError, LEAVES_PAGE_CONTEXT } from '../utils/mutationResult';\nimport { usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\n\n/**\n * Automation rule controls (BOFF-8047): enable/disable, delete and \"run now\". Every automation rule row and its\n * detail page carry these — before this, `planmagnetToggleAutomationRule`, `planmagnetDeleteAutomationRule` and\n * `planmagnetExecuteAutomationRule` were real, prod-verified mutations with no UI trigger anywhere.\n */\n\nexport const AUTOMATION_RULE_QUERIES = ['AutomationRulesList', 'GetAutomationRule'];\n\nconst TOGGLE = gql`\n mutation AutomationRuleControlsToggle($id: ID!, $status: PlanmagnetAutomationStatus!) {\n planmagnetToggleAutomationRule(id: $id, status: $status) {\n id\n status\n }\n }\n`;\nconst DELETE = gql`\n mutation AutomationRuleControlsDelete($id: ID!) {\n planmagnetDeleteAutomationRule(id: $id)\n }\n`;\nconst EXECUTE = gql`\n mutation AutomationRuleControlsExecute($id: ID!, $triggerData: JSON) {\n planmagnetExecuteAutomationRule(id: $id, triggerData: $triggerData) {\n id\n status\n errorMessage\n result\n }\n }\n`;\n\n/** ACTIVE <-> PAUSED. A rule stuck in DISABLED or ERROR is re-activated by turning this on; the raw status is\n * shown alongside so a paused-by-error rule is never confused with a manually paused one. */\nexport function AutomationRuleStatusSwitch({ ruleId, status }: { ruleId: string; status: string }) {\n const [toggle, { loading }] = useMutation(TOGGLE, {\n refetchQueries: AUTOMATION_RULE_QUERIES,\n });\n const [error, setError] = useState<string | null>(null);\n const active = status === 'ACTIVE';\n\n const onChange = async (checked: boolean) => {\n setError(null);\n try {\n await throwOnError(\n toggle({ variables: { id: ruleId, status: checked ? 'ACTIVE' : 'PAUSED' } })\n );\n } catch (e) {\n setError(e instanceof Error ? e.message : 'The rule could not be changed.');\n }\n };\n\n return (\n <div className=\"flex flex-col items-end gap-1\">\n <div className=\"flex items-center gap-2\">\n {status !== 'ACTIVE' && status !== 'PAUSED' && (\n <Badge variant={status === 'ERROR' ? 'destructive' : 'secondary'}>\n {status.toLowerCase()}\n </Badge>\n )}\n <Switch\n aria-label={active ? 'Active — turn off to pause' : 'Paused — turn on to activate'}\n data-testid=\"automation-rule-toggle\"\n checked={active}\n disabled={loading}\n onCheckedChange={(checked) => void onChange(checked)}\n />\n </div>\n {error && <ErrorLine message={error} />}\n </div>\n );\n}\n\nexport function AutomationRuleDeleteButton({ ruleId, name }: { ruleId: string; name: string }) {\n const navigate = usePlanMagnetNavigate();\n const [remove, { loading }] = useMutation(DELETE, {\n refetchQueries: AUTOMATION_RULE_QUERIES.filter((q) => q !== 'GetAutomationRule'),\n context: LEAVES_PAGE_CONTEXT,\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: ruleId } }));\n navigate('/automation/automation-rules-page');\n } catch (e) {\n setError(e instanceof Error ? e.message : 'The rule could not be deleted.');\n }\n };\n\n return (\n <div className=\"flex flex-col items-end gap-1\">\n <ConfirmButton\n label=\"Delete\"\n variant=\"outline\"\n icon={<Trash2 className=\"mr-1 h-4 w-4\" />}\n title={`Delete \"${name}\"?`}\n description=\"The rule stops running and its history stays as a record. This cannot be undone here.\"\n confirmLabel=\"Delete rule\"\n destructive\n disabled={loading}\n onConfirm={() => void onDelete()}\n />\n {error && <ErrorLine message={error} />}\n </div>\n );\n}\n\ninterface ExecuteResult {\n status: string;\n errorMessage: string | null;\n}\n\nconst OUTCOME_VARIANT: Record<string, 'success' | 'warning' | 'destructive' | 'secondary'> = {\n SUCCESS: 'success',\n PARTIAL_FAILURE: 'warning',\n FAILURE: 'destructive',\n SKIPPED: 'secondary',\n};\n\n/** Runs a rule against one chosen work item — works for a rule of ANY trigger type, including the ones that\n * cannot fire on their own (see automationRuleTypes.ts). Always records an outcome, including a non-match. */\nexport function RunAutomationRuleDialog({\n ruleId,\n projectId,\n}: {\n ruleId: string;\n projectId?: string;\n}) {\n const [open, setOpen] = useState(false);\n const [workItemId, setWorkItemId] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [outcome, setOutcome] = useState<ExecuteResult | null>(null);\n const [execute, { loading }] = useMutation<{ planmagnetExecuteAutomationRule: ExecuteResult }>(\n EXECUTE,\n {\n refetchQueries: ['AutomationExecutionsForRule', ...AUTOMATION_RULE_QUERIES],\n awaitRefetchQueries: true,\n }\n );\n\n const run = async () => {\n if (!workItemId) return;\n setError(null);\n setOutcome(null);\n try {\n const result = await throwOnError(\n execute({ variables: { id: ruleId, triggerData: { workItemId } } })\n );\n const execution = result.data?.planmagnetExecuteAutomationRule ?? null;\n setOutcome(execution);\n } catch (e) {\n setError(e instanceof Error ? e.message : 'The rule could not be run.');\n }\n };\n\n return (\n <ResponsiveDialog\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (next) {\n setWorkItemId('');\n setError(null);\n setOutcome(null);\n }\n }}\n >\n <ResponsiveDialogTrigger asChild>\n <Button size=\"sm\" variant=\"outline\" data-testid=\"automation-run-now\">\n <Play className=\"mr-1 h-4 w-4\" />\n Run now\n </Button>\n </ResponsiveDialogTrigger>\n <ResponsiveDialogContent className=\"max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Run this rule now</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Evaluates the rule&apos;s conditions against one work item and, if they match,\n dispatches its actions for real. The outcome is recorded below and in Recent executions\n either way.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3\">\n <div>\n <label htmlFor=\"automation-run-work-item\" className=\"text-sm font-medium\">\n Work item\n </label>\n <div className=\"mt-1\">\n <WorkItemSearchSelect\n id=\"automation-run-work-item\"\n projectId={projectId}\n value={workItemId}\n onChange={setWorkItemId}\n />\n </div>\n </div>\n {error && <ErrorLine message={error} />}\n {outcome && (\n <div role=\"status\" className=\"rounded-md border p-3 text-sm space-y-1\">\n <Badge variant={OUTCOME_VARIANT[outcome.status] ?? 'secondary'}>\n {outcome.status.toLowerCase().replace('_', ' ')}\n </Badge>\n {outcome.errorMessage && (\n <p\n className={\n outcome.status === 'SUCCESS' ? 'text-muted-foreground' : 'text-destructive'\n }\n >\n {outcome.errorMessage}\n </p>\n )}\n </div>\n )}\n </div>\n <ResponsiveDialogFooter>\n <Button\n onClick={() => void run()}\n disabled={!workItemId || loading}\n data-testid=\"automation-run-submit\"\n >\n {loading ? 'Running…' : 'Run'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ export declare function CompetitorHeaderActions({ competitorId, name, }: {
2
+ competitorId: string;
3
+ name: string;
4
+ }): import("react/jsx-runtime").JSX.Element;
5
+ interface CompetitorNode {
6
+ id: string;
7
+ name: string;
8
+ description: string | null;
9
+ website: string | null;
10
+ }
11
+ /**
12
+ * The feature request detail page's competitor section: list what is linked, remove any of them, and add
13
+ * another from the workspace's competitor directory (or create a new one there).
14
+ */
15
+ export declare function CompetitorLinkCard({ featureRequestId, competitors, }: {
16
+ featureRequestId: string;
17
+ competitors: CompetitorNode[];
18
+ }): import("react/jsx-runtime").JSX.Element;
19
+ export {};
20
+ //# sourceMappingURL=CompetitorControls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CompetitorControls.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/controls/CompetitorControls.tsx"],"names":[],"mappings":"AAyBA,wBAAgB,uBAAuB,CAAC,EACtC,YAAY,EACZ,IAAI,GACL,EAAE;IACD,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;CACd,2CA6CA;AA6BD,UAAU,cAAc;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,gBAAgB,EAChB,WAAW,GACZ,EAAE;IACD,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,cAAc,EAAE,CAAC;CAC/B,2CAyFA"}
@@ -0,0 +1,172 @@
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 { CompetitorSearchSelect as a } from "./Pickers.js";
5
+ import { detailPath as o } from "../utils/rowNavigation.js";
6
+ import { useState as s } from "react";
7
+ import { Pencil as c, Plus as l, Trash2 as u, X as d } from "lucide-react";
8
+ import { gql as f } from "@apollo/client";
9
+ import { useMutation as p } from "@apollo/client/react";
10
+ import { jsx as m, jsxs as h } from "react/jsx-runtime";
11
+ import { Button as g } from "@burdenoff/fe-libs/ui";
12
+ //#region src/planmagnet/controls/CompetitorControls.tsx
13
+ var _ = [
14
+ "ListCompetitors",
15
+ "GetCompetitor",
16
+ "GetCompetitorForEdit"
17
+ ], v = f`
18
+ mutation CompetitorControlsDelete($id: ID!) {
19
+ planmagnetDeleteCompetitor(id: $id)
20
+ }
21
+ `;
22
+ function y({ competitorId: a, name: l }) {
23
+ let d = e(), [f, y] = p(v, {
24
+ refetchQueries: _.filter((e) => e !== "GetCompetitor"),
25
+ context: t
26
+ }), [b, x] = s(null), S = async () => {
27
+ x(null);
28
+ try {
29
+ await n(f({ variables: { id: a } })), d("/products/competitors-page");
30
+ } catch (e) {
31
+ x(e instanceof Error ? e.message : "The competitor could not be deleted.");
32
+ }
33
+ };
34
+ return /* @__PURE__ */ h("div", {
35
+ className: "flex flex-col items-end gap-2",
36
+ children: [/* @__PURE__ */ h("div", {
37
+ className: "flex flex-wrap items-center justify-end gap-2",
38
+ children: [/* @__PURE__ */ h(g, {
39
+ size: "sm",
40
+ variant: "outline",
41
+ "data-testid": "competitor-edit",
42
+ onClick: () => d(o("/products/edit-competitor-page", a)),
43
+ children: [/* @__PURE__ */ m(c, { className: "mr-1 h-4 w-4" }), "Edit"]
44
+ }), /* @__PURE__ */ m(r, {
45
+ label: "Delete",
46
+ variant: "outline",
47
+ icon: /* @__PURE__ */ m(u, { className: "mr-1 h-4 w-4" }),
48
+ title: `Delete ${l}?`,
49
+ description: "The competitor is deleted and unlinked from every feature request that referenced it. This cannot be undone here.",
50
+ confirmLabel: "Delete competitor",
51
+ destructive: !0,
52
+ disabled: y.loading,
53
+ onConfirm: () => void S()
54
+ })]
55
+ }), b && /* @__PURE__ */ m(i, { message: b })]
56
+ });
57
+ }
58
+ var b = f`
59
+ mutation CompetitorLinkCardLink($input: PlanmagnetLinkCompetitorInput!) {
60
+ planmagnetLinkCompetitorToFeature(input: $input) {
61
+ id
62
+ competitors {
63
+ id
64
+ name
65
+ description
66
+ website
67
+ }
68
+ }
69
+ }
70
+ `, x = f`
71
+ mutation CompetitorLinkCardUnlink($input: PlanmagnetLinkCompetitorInput!) {
72
+ planmagnetUnlinkCompetitorFromFeature(input: $input) {
73
+ id
74
+ competitors {
75
+ id
76
+ name
77
+ description
78
+ website
79
+ }
80
+ }
81
+ }
82
+ `;
83
+ function S({ featureRequestId: t, competitors: r }) {
84
+ let c = e(), [u, f] = s(""), [_, v] = p(b), [y, S] = p(x), [C, w] = s(null), T = v.loading || S.loading, E = async () => {
85
+ if (u) {
86
+ w(null);
87
+ try {
88
+ await n(_({ variables: { input: {
89
+ featureRequestId: t,
90
+ competitorId: u
91
+ } } })), f("");
92
+ } catch (e) {
93
+ w(e instanceof Error ? e.message : "The competitor could not be linked.");
94
+ }
95
+ }
96
+ }, D = async (e) => {
97
+ w(null);
98
+ try {
99
+ await n(y({ variables: { input: {
100
+ featureRequestId: t,
101
+ competitorId: e
102
+ } } }));
103
+ } catch (e) {
104
+ w(e instanceof Error ? e.message : "The competitor could not be removed.");
105
+ }
106
+ };
107
+ return /* @__PURE__ */ h("div", {
108
+ className: "space-y-3",
109
+ children: [
110
+ r.length === 0 && /* @__PURE__ */ m("p", {
111
+ className: "text-sm text-muted-foreground",
112
+ children: "No competitors linked yet."
113
+ }),
114
+ r.map((e) => /* @__PURE__ */ h("div", {
115
+ className: "flex items-start justify-between gap-2 rounded-md border p-3",
116
+ children: [/* @__PURE__ */ h("button", {
117
+ type: "button",
118
+ className: "flex-1 text-left",
119
+ onClick: () => c(o("/products/competitor-detail-page", e.id)),
120
+ children: [/* @__PURE__ */ h("div", {
121
+ className: "flex items-center gap-2",
122
+ children: [/* @__PURE__ */ m("span", {
123
+ className: "text-sm font-medium hover:underline underline-offset-2",
124
+ children: e.name
125
+ }), e.website && /* @__PURE__ */ m("span", {
126
+ className: "text-xs text-primary",
127
+ children: e.website
128
+ })]
129
+ }), e.description && /* @__PURE__ */ m("p", {
130
+ className: "text-xs text-muted-foreground mt-1",
131
+ children: e.description
132
+ })]
133
+ }), /* @__PURE__ */ m(g, {
134
+ size: "sm",
135
+ variant: "ghost",
136
+ "aria-label": `Remove ${e.name} from this feature`,
137
+ disabled: T,
138
+ onClick: () => void D(e.id),
139
+ children: /* @__PURE__ */ m(d, { className: "h-4 w-4" })
140
+ })]
141
+ }, e.id)),
142
+ /* @__PURE__ */ h("div", {
143
+ className: "flex items-start gap-2 pt-2 border-t",
144
+ children: [/* @__PURE__ */ m("div", {
145
+ className: "flex-1",
146
+ children: /* @__PURE__ */ m(a, {
147
+ id: "feature-add-competitor",
148
+ value: u,
149
+ onChange: f,
150
+ exclude: r.map((e) => e.id)
151
+ })
152
+ }), /* @__PURE__ */ h(g, {
153
+ size: "sm",
154
+ disabled: !u || T,
155
+ onClick: () => void E(),
156
+ children: [/* @__PURE__ */ m(l, { className: "mr-1 h-4 w-4" }), "Add"]
157
+ })]
158
+ }),
159
+ /* @__PURE__ */ h(g, {
160
+ size: "sm",
161
+ variant: "ghost",
162
+ onClick: () => c("/products/create-competitor-page"),
163
+ children: [/* @__PURE__ */ m(l, { className: "mr-1 h-4 w-4" }), "New competitor"]
164
+ }),
165
+ C && /* @__PURE__ */ m(i, { message: C })
166
+ ]
167
+ });
168
+ }
169
+ //#endregion
170
+ export { y as CompetitorHeaderActions, S as CompetitorLinkCard };
171
+
172
+ //# sourceMappingURL=CompetitorControls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CompetitorControls.js","names":[],"sources":["../../../src/planmagnet/controls/CompetitorControls.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, X, Plus } 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 { CompetitorSearchSelect } from './Pickers';\n\n/**\n * Competitor controls (BOFF-8047). Competitors were `api-only` — full CRUD plus link/unlink onto a feature\n * request existed in the service, bundled with `planmagnet-feature` RBAC (CORRECTIONS.md B), but had zero\n * routes and no write UI: the feature request detail page could only ever display what was already linked.\n */\n\nconst COMPETITOR_QUERIES = ['ListCompetitors', 'GetCompetitor', 'GetCompetitorForEdit'];\n\nconst DELETE = gql`\n mutation CompetitorControlsDelete($id: ID!) {\n planmagnetDeleteCompetitor(id: $id)\n }\n`;\n\nexport function CompetitorHeaderActions({\n competitorId,\n name,\n}: {\n competitorId: string;\n name: string;\n}) {\n const navigate = usePlanMagnetNavigate();\n const [remove, removeState] = useMutation(DELETE, {\n refetchQueries: COMPETITOR_QUERIES.filter((q) => q !== 'GetCompetitor'),\n context: LEAVES_PAGE_CONTEXT,\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: competitorId } }));\n navigate('/products/competitors-page');\n } catch (e) {\n setError(e instanceof Error ? e.message : 'The competitor 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 <Button\n size=\"sm\"\n variant=\"outline\"\n data-testid=\"competitor-edit\"\n onClick={() => navigate(detailPath('/products/edit-competitor-page', competitorId))}\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 ${name}?`}\n description=\"The competitor is deleted and unlinked from every feature request that referenced it. This cannot be undone here.\"\n confirmLabel=\"Delete competitor\"\n destructive\n disabled={removeState.loading}\n onConfirm={() => void onDelete()}\n />\n </div>\n {error && <ErrorLine message={error} />}\n </div>\n );\n}\n\nconst LINK = gql`\n mutation CompetitorLinkCardLink($input: PlanmagnetLinkCompetitorInput!) {\n planmagnetLinkCompetitorToFeature(input: $input) {\n id\n competitors {\n id\n name\n description\n website\n }\n }\n }\n`;\nconst UNLINK = gql`\n mutation CompetitorLinkCardUnlink($input: PlanmagnetLinkCompetitorInput!) {\n planmagnetUnlinkCompetitorFromFeature(input: $input) {\n id\n competitors {\n id\n name\n description\n website\n }\n }\n }\n`;\n\ninterface CompetitorNode {\n id: string;\n name: string;\n description: string | null;\n website: string | null;\n}\n\n/**\n * The feature request detail page's competitor section: list what is linked, remove any of them, and add\n * another from the workspace's competitor directory (or create a new one there).\n */\nexport function CompetitorLinkCard({\n featureRequestId,\n competitors,\n}: {\n featureRequestId: string;\n competitors: CompetitorNode[];\n}) {\n const navigate = usePlanMagnetNavigate();\n const [addCompetitorId, setAddCompetitorId] = useState('');\n const [link, linkState] = useMutation(LINK);\n const [unlink, unlinkState] = useMutation(UNLINK);\n const [error, setError] = useState<string | null>(null);\n const busy = linkState.loading || unlinkState.loading;\n\n const onAdd = async () => {\n if (!addCompetitorId) return;\n setError(null);\n try {\n await throwOnError(\n link({\n variables: { input: { featureRequestId, competitorId: addCompetitorId } },\n })\n );\n setAddCompetitorId('');\n } catch (e) {\n setError(e instanceof Error ? e.message : 'The competitor could not be linked.');\n }\n };\n const onRemove = async (competitorId: string) => {\n setError(null);\n try {\n await throwOnError(unlink({ variables: { input: { featureRequestId, competitorId } } }));\n } catch (e) {\n setError(e instanceof Error ? e.message : 'The competitor could not be removed.');\n }\n };\n\n return (\n <div className=\"space-y-3\">\n {competitors.length === 0 && (\n <p className=\"text-sm text-muted-foreground\">No competitors linked yet.</p>\n )}\n {competitors.map((comp) => (\n <div key={comp.id} className=\"flex items-start justify-between gap-2 rounded-md border p-3\">\n <button\n type=\"button\"\n className=\"flex-1 text-left\"\n onClick={() => navigate(detailPath('/products/competitor-detail-page', comp.id))}\n >\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium hover:underline underline-offset-2\">\n {comp.name}\n </span>\n {comp.website && <span className=\"text-xs text-primary\">{comp.website}</span>}\n </div>\n {comp.description && (\n <p className=\"text-xs text-muted-foreground mt-1\">{comp.description}</p>\n )}\n </button>\n <Button\n size=\"sm\"\n variant=\"ghost\"\n aria-label={`Remove ${comp.name} from this feature`}\n disabled={busy}\n onClick={() => void onRemove(comp.id)}\n >\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n ))}\n <div className=\"flex items-start gap-2 pt-2 border-t\">\n <div className=\"flex-1\">\n <CompetitorSearchSelect\n id=\"feature-add-competitor\"\n value={addCompetitorId}\n onChange={setAddCompetitorId}\n exclude={competitors.map((c) => c.id)}\n />\n </div>\n <Button size=\"sm\" disabled={!addCompetitorId || busy} onClick={() => void onAdd()}>\n <Plus className=\"mr-1 h-4 w-4\" />\n Add\n </Button>\n </div>\n <Button\n size=\"sm\"\n variant=\"ghost\"\n onClick={() => navigate('/products/create-competitor-page')}\n >\n <Plus className=\"mr-1 h-4 w-4\" />\n New competitor\n </Button>\n {error && <ErrorLine message={error} />}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Custom fields (BOFF-8047, BUILD_PLAN capability register `api-only` → UI). Definitions describe extra,
3
+ * project-specific data on a work item; values are what a task actually holds for each definition. The register
4
+ * warns value writes skip type validation server-side — this UI still asks for the right shaped input per type
5
+ * (a number field, a date picker, the definition's own options, …), it just cannot rely on the server to refuse a
6
+ * malformed one, so a raw JSON editor is offered only for the JSON type, where "whatever the admin entered" is the
7
+ * point.
8
+ */
9
+ export declare const CUSTOM_FIELD_TYPES: readonly ["TEXT", "NUMBER", "DATE", "BOOLEAN", "SELECT", "MULTI_SELECT", "URL", "EMAIL", "USER", "LABEL", "JSON"];
10
+ export type CustomFieldType = (typeof CUSTOM_FIELD_TYPES)[number];
11
+ export declare const customFieldTypeLabel: (type: string) => string;
12
+ /** Types whose definition needs a fixed list of choices. */
13
+ export declare const OPTION_TYPES: Set<string>;
14
+ export interface CustomFieldDefinitionSummary {
15
+ id: string;
16
+ projectId: string;
17
+ name: string;
18
+ description: string | null;
19
+ fieldType: string;
20
+ isRequired: boolean;
21
+ options: unknown;
22
+ sortOrder: number;
23
+ }
24
+ export interface CustomFieldValueSummary {
25
+ id: string;
26
+ definitionId: string;
27
+ value: unknown;
28
+ }
29
+ /** Every query that lists a project's custom field definitions, or a work item's values. */
30
+ export declare const CUSTOM_FIELD_QUERIES: string[];
31
+ export declare const PROJECT_CUSTOM_FIELD_DEFINITIONS: import('graphql').DocumentNode;
32
+ export declare const CREATE_CUSTOM_FIELD_DEFINITION: import('graphql').DocumentNode;
33
+ export declare const UPDATE_CUSTOM_FIELD_DEFINITION: import('graphql').DocumentNode;
34
+ export declare const DELETE_CUSTOM_FIELD_DEFINITION: import('graphql').DocumentNode;
35
+ export declare const SET_CUSTOM_FIELD_VALUE: import('graphql').DocumentNode;
36
+ export declare const REMOVE_CUSTOM_FIELD_VALUE: import('graphql').DocumentNode;
37
+ /** `options` is stored as free-form JSON; this UI always writes a plain string array, but reads defensively in
38
+ * case something else ever wrote a list of {label,value}-shaped objects. */
39
+ export declare function optionStrings(options: unknown): string[];
40
+ /** Parses the "one per line" textarea used to edit a SELECT/MULTI_SELECT definition's options. */
41
+ export declare function parseOptionLines(text: string): string[];
42
+ //# sourceMappingURL=CustomFieldControls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CustomFieldControls.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/controls/CustomFieldControls.tsx"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AAEH,eAAO,MAAM,kBAAkB,mHAYrB,CAAC;AACX,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAElE,eAAO,MAAM,oBAAoB,GAAI,MAAM,MAAM,KAAG,MAAyB,CAAC;AAE9E,4DAA4D;AAC5D,eAAO,MAAM,YAAY,aAAsC,CAAC;AAEhE,MAAM,WAAW,4BAA4B;IAC3C,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,4FAA4F;AAC5F,eAAO,MAAM,oBAAoB,UAAyD,CAAC;AAE3F,eAAO,MAAM,gCAAgC,gCAoB5C,CAAC;AAEF,eAAO,MAAM,8BAA8B,gCAM1C,CAAC;AAEF,eAAO,MAAM,8BAA8B,gCAS1C,CAAC;AAEF,eAAO,MAAM,8BAA8B,gCAI1C,CAAC;AAEF,eAAO,MAAM,sBAAsB,gCAQlC,CAAC;AAEF,eAAO,MAAM,yBAAyB,gCAIrC,CAAC;AAEF;4EAC4E;AAC5E,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,EAAE,CAWxD;AAED,kGAAkG;AAClG,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CASvD"}
@@ -0,0 +1,84 @@
1
+ import { enumLabel as e } from "./WorkItemControls.js";
2
+ import { gql as t } from "@apollo/client";
3
+ //#region src/planmagnet/controls/CustomFieldControls.tsx
4
+ var n = [
5
+ "TEXT",
6
+ "NUMBER",
7
+ "DATE",
8
+ "BOOLEAN",
9
+ "SELECT",
10
+ "MULTI_SELECT",
11
+ "URL",
12
+ "EMAIL",
13
+ "USER",
14
+ "LABEL",
15
+ "JSON"
16
+ ], r = (t) => e(t), i = new Set(["SELECT", "MULTI_SELECT"]), a = ["ProjectCustomFieldDefinitions", "GetWorkItemDetail"], o = t`
17
+ query ProjectCustomFieldDefinitions($workspaceId: ID!, $projectId: String) {
18
+ planmagnetCustomFieldDefinitions(
19
+ workspaceId: $workspaceId
20
+ filter: { projectId: $projectId }
21
+ pagination: { first: 100 }
22
+ ) {
23
+ items {
24
+ id
25
+ projectId
26
+ name
27
+ description
28
+ fieldType
29
+ isRequired
30
+ options
31
+ sortOrder
32
+ }
33
+ totalCount
34
+ }
35
+ }
36
+ `, s = t`
37
+ mutation CustomFieldDefinitionCreate($input: PlanmagnetCreateCustomFieldDefinitionInput!) {
38
+ planmagnetCreateCustomFieldDefinition(input: $input) {
39
+ id
40
+ }
41
+ }
42
+ `, c = t`
43
+ mutation CustomFieldDefinitionUpdate(
44
+ $id: ID!
45
+ $input: PlanmagnetUpdateCustomFieldDefinitionInput!
46
+ ) {
47
+ planmagnetUpdateCustomFieldDefinition(id: $id, input: $input) {
48
+ id
49
+ }
50
+ }
51
+ `, l = t`
52
+ mutation CustomFieldDefinitionDelete($id: ID!) {
53
+ planmagnetDeleteCustomFieldDefinition(id: $id)
54
+ }
55
+ `, u = t`
56
+ mutation CustomFieldValueSet($input: PlanmagnetSetCustomFieldValueInput!) {
57
+ planmagnetSetCustomFieldValue(input: $input) {
58
+ id
59
+ definitionId
60
+ value
61
+ }
62
+ }
63
+ `, d = t`
64
+ mutation CustomFieldValueRemove($definitionId: ID!, $workItemId: ID!) {
65
+ planmagnetRemoveCustomFieldValue(definitionId: $definitionId, workItemId: $workItemId)
66
+ }
67
+ `;
68
+ function f(e) {
69
+ return Array.isArray(e) ? e.map((e) => {
70
+ if (typeof e == "string") return e;
71
+ if (e && typeof e == "object") {
72
+ let t = e, n = t.label ?? t.value ?? t.name ?? t.id;
73
+ if (typeof n == "string") return n;
74
+ }
75
+ return String(e);
76
+ }) : [];
77
+ }
78
+ function p(e) {
79
+ return [...new Set(e.split("\n").map((e) => e.trim()).filter(Boolean))];
80
+ }
81
+ //#endregion
82
+ export { s as CREATE_CUSTOM_FIELD_DEFINITION, a as CUSTOM_FIELD_QUERIES, n as CUSTOM_FIELD_TYPES, l as DELETE_CUSTOM_FIELD_DEFINITION, i as OPTION_TYPES, o as PROJECT_CUSTOM_FIELD_DEFINITIONS, d as REMOVE_CUSTOM_FIELD_VALUE, u as SET_CUSTOM_FIELD_VALUE, c as UPDATE_CUSTOM_FIELD_DEFINITION, r as customFieldTypeLabel, f as optionStrings, p as parseOptionLines };
83
+
84
+ //# sourceMappingURL=CustomFieldControls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CustomFieldControls.js","names":[],"sources":["../../../src/planmagnet/controls/CustomFieldControls.tsx"],"sourcesContent":["import { gql } from '@apollo/client';\nimport { enumLabel } from './WorkItemControls';\n\n/**\n * Custom fields (BOFF-8047, BUILD_PLAN capability register `api-only` → UI). Definitions describe extra,\n * project-specific data on a work item; values are what a task actually holds for each definition. The register\n * warns value writes skip type validation server-side — this UI still asks for the right shaped input per type\n * (a number field, a date picker, the definition's own options, …), it just cannot rely on the server to refuse a\n * malformed one, so a raw JSON editor is offered only for the JSON type, where \"whatever the admin entered\" is the\n * point.\n */\n\nexport const CUSTOM_FIELD_TYPES = [\n 'TEXT',\n 'NUMBER',\n 'DATE',\n 'BOOLEAN',\n 'SELECT',\n 'MULTI_SELECT',\n 'URL',\n 'EMAIL',\n 'USER',\n 'LABEL',\n 'JSON',\n] as const;\nexport type CustomFieldType = (typeof CUSTOM_FIELD_TYPES)[number];\n\nexport const customFieldTypeLabel = (type: string): string => enumLabel(type);\n\n/** Types whose definition needs a fixed list of choices. */\nexport const OPTION_TYPES = new Set(['SELECT', 'MULTI_SELECT']);\n\nexport interface CustomFieldDefinitionSummary {\n id: string;\n projectId: string;\n name: string;\n description: string | null;\n fieldType: string;\n isRequired: boolean;\n options: unknown;\n sortOrder: number;\n}\n\nexport interface CustomFieldValueSummary {\n id: string;\n definitionId: string;\n value: unknown;\n}\n\n/** Every query that lists a project's custom field definitions, or a work item's values. */\nexport const CUSTOM_FIELD_QUERIES = ['ProjectCustomFieldDefinitions', 'GetWorkItemDetail'];\n\nexport const PROJECT_CUSTOM_FIELD_DEFINITIONS = gql`\n query ProjectCustomFieldDefinitions($workspaceId: ID!, $projectId: String) {\n planmagnetCustomFieldDefinitions(\n workspaceId: $workspaceId\n filter: { projectId: $projectId }\n pagination: { first: 100 }\n ) {\n items {\n id\n projectId\n name\n description\n fieldType\n isRequired\n options\n sortOrder\n }\n totalCount\n }\n }\n`;\n\nexport const CREATE_CUSTOM_FIELD_DEFINITION = gql`\n mutation CustomFieldDefinitionCreate($input: PlanmagnetCreateCustomFieldDefinitionInput!) {\n planmagnetCreateCustomFieldDefinition(input: $input) {\n id\n }\n }\n`;\n\nexport const UPDATE_CUSTOM_FIELD_DEFINITION = gql`\n mutation CustomFieldDefinitionUpdate(\n $id: ID!\n $input: PlanmagnetUpdateCustomFieldDefinitionInput!\n ) {\n planmagnetUpdateCustomFieldDefinition(id: $id, input: $input) {\n id\n }\n }\n`;\n\nexport const DELETE_CUSTOM_FIELD_DEFINITION = gql`\n mutation CustomFieldDefinitionDelete($id: ID!) {\n planmagnetDeleteCustomFieldDefinition(id: $id)\n }\n`;\n\nexport const SET_CUSTOM_FIELD_VALUE = gql`\n mutation CustomFieldValueSet($input: PlanmagnetSetCustomFieldValueInput!) {\n planmagnetSetCustomFieldValue(input: $input) {\n id\n definitionId\n value\n }\n }\n`;\n\nexport const REMOVE_CUSTOM_FIELD_VALUE = gql`\n mutation CustomFieldValueRemove($definitionId: ID!, $workItemId: ID!) {\n planmagnetRemoveCustomFieldValue(definitionId: $definitionId, workItemId: $workItemId)\n }\n`;\n\n/** `options` is stored as free-form JSON; this UI always writes a plain string array, but reads defensively in\n * case something else ever wrote a list of {label,value}-shaped objects. */\nexport function optionStrings(options: unknown): string[] {\n if (!Array.isArray(options)) return [];\n return options.map((o) => {\n if (typeof o === 'string') return o;\n if (o && typeof o === 'object') {\n const rec = o as Record<string, unknown>;\n const candidate = rec.label ?? rec.value ?? rec.name ?? rec.id;\n if (typeof candidate === 'string') return candidate;\n }\n return String(o);\n });\n}\n\n/** Parses the \"one per line\" textarea used to edit a SELECT/MULTI_SELECT definition's options. */\nexport function parseOptionLines(text: string): string[] {\n return [\n ...new Set(\n text\n .split('\\n')\n .map((line) => line.trim())\n .filter(Boolean)\n ),\n ];\n}\n"],"mappings":";;;AAYA,IAAa,IAAqB;CAChC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,EAGY,KAAwB,MAAyB,EAAU,EAAK,EAGhE,IAAe,IAAI,IAAI,CAAC,UAAU,eAAe,CAAC,EAoBlD,IAAuB,CAAC,iCAAiC,oBAAoB,EAE7E,IAAmC,CAAG;;;;;;;;;;;;;;;;;;;;GAsBtC,IAAiC,CAAG;;;;;;GAQpC,IAAiC,CAAG;;;;;;;;;GAWpC,IAAiC,CAAG;;;;GAMpC,IAAyB,CAAG;;;;;;;;GAU5B,IAA4B,CAAG;;;;;AAQ5C,SAAgB,EAAc,GAA4B;AAExD,QADK,MAAM,QAAQ,EAAQ,GACpB,EAAQ,KAAK,MAAM;AACxB,MAAI,OAAO,KAAM,SAAU,QAAO;AAClC,MAAI,KAAK,OAAO,KAAM,UAAU;GAC9B,IAAM,IAAM,GACN,IAAY,EAAI,SAAS,EAAI,SAAS,EAAI,QAAQ,EAAI;AAC5D,OAAI,OAAO,KAAc,SAAU,QAAO;;AAE5C,SAAO,OAAO,EAAE;GAChB,GATkC,EAAE;;AAaxC,SAAgB,EAAiB,GAAwB;AACvD,QAAO,CACL,GAAG,IAAI,IACL,EACG,MAAM,KAAK,CACX,KAAK,MAAS,EAAK,MAAM,CAAC,CAC1B,OAAO,QAAQ,CACnB,CACF"}
@@ -0,0 +1,8 @@
1
+ import { CustomFieldValueSummary } from './CustomFieldControls';
2
+
3
+ export declare function CustomFieldsPanel({ workItemId, projectId, values, }: {
4
+ workItemId: string;
5
+ projectId: string;
6
+ values: CustomFieldValueSummary[];
7
+ }): import("react/jsx-runtime").JSX.Element;
8
+ //# sourceMappingURL=CustomFieldValuesPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CustomFieldValuesPanel.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/controls/CustomFieldValuesPanel.tsx"],"names":[],"mappings":"AAUA,OAAO,EAOL,KAAK,uBAAuB,EAC7B,MAAM,uBAAuB,CAAC;AAyZ/B,wBAAgB,iBAAiB,CAAC,EAChC,UAAU,EACV,SAAS,EACT,MAAM,GACP,EAAE;IACD,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,uBAAuB,EAAE,CAAC;CACnC,2CA+CA"}