@burdenoff/microfe-planmagnet 2026.928.4 → 2026.928.6

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 (226) hide show
  1. package/dist/planmagnet/PlanMagnetRoot.d.ts.map +1 -1
  2. package/dist/planmagnet/PlanMagnetRoot.js +130 -97
  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 +256 -156
  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.js +15 -15
  47. package/dist/planmagnet/controls/CustomFieldControls.d.ts +42 -0
  48. package/dist/planmagnet/controls/CustomFieldControls.d.ts.map +1 -0
  49. package/dist/planmagnet/controls/CustomFieldControls.js +84 -0
  50. package/dist/planmagnet/controls/CustomFieldControls.js.map +1 -0
  51. package/dist/planmagnet/controls/CustomFieldValuesPanel.d.ts +8 -0
  52. package/dist/planmagnet/controls/CustomFieldValuesPanel.d.ts.map +1 -0
  53. package/dist/planmagnet/controls/CustomFieldValuesPanel.js +315 -0
  54. package/dist/planmagnet/controls/CustomFieldValuesPanel.js.map +1 -0
  55. package/dist/planmagnet/controls/FeatureControls.js +54 -54
  56. package/dist/planmagnet/controls/ObjectiveControls.js +15 -15
  57. package/dist/planmagnet/controls/Pickers.d.ts +7 -0
  58. package/dist/planmagnet/controls/Pickers.d.ts.map +1 -1
  59. package/dist/planmagnet/controls/Pickers.js +58 -20
  60. package/dist/planmagnet/controls/Pickers.js.map +1 -1
  61. package/dist/planmagnet/controls/PortfolioControls.js +7 -7
  62. package/dist/planmagnet/controls/ProgramControls.js +19 -19
  63. package/dist/planmagnet/controls/ProjectControls.d.ts.map +1 -1
  64. package/dist/planmagnet/controls/ProjectControls.js +54 -47
  65. package/dist/planmagnet/controls/ProjectControls.js.map +1 -1
  66. package/dist/planmagnet/controls/ReleaseControls.js +7 -7
  67. package/dist/planmagnet/controls/RiskControls.d.ts +27 -0
  68. package/dist/planmagnet/controls/RiskControls.d.ts.map +1 -0
  69. package/dist/planmagnet/controls/RiskControls.js +346 -0
  70. package/dist/planmagnet/controls/RiskControls.js.map +1 -0
  71. package/dist/planmagnet/controls/TemplateControls.d.ts +15 -0
  72. package/dist/planmagnet/controls/TemplateControls.d.ts.map +1 -0
  73. package/dist/planmagnet/controls/TemplateControls.js +55 -0
  74. package/dist/planmagnet/controls/TemplateControls.js.map +1 -0
  75. package/dist/planmagnet/controls/WorkItemControls.d.ts +6 -2
  76. package/dist/planmagnet/controls/WorkItemControls.d.ts.map +1 -1
  77. package/dist/planmagnet/controls/WorkItemControls.js +9 -9
  78. package/dist/planmagnet/controls/WorkItemControls.js.map +1 -1
  79. package/dist/planmagnet/create/CreateDialogs.d.ts +20 -0
  80. package/dist/planmagnet/create/CreateDialogs.d.ts.map +1 -1
  81. package/dist/planmagnet/create/CreateDialogs.js +455 -116
  82. package/dist/planmagnet/create/CreateDialogs.js.map +1 -1
  83. package/dist/planmagnet/dependency/DependencyPanel.d.ts +6 -0
  84. package/dist/planmagnet/dependency/DependencyPanel.d.ts.map +1 -0
  85. package/dist/planmagnet/dependency/DependencyPanel.js +310 -0
  86. package/dist/planmagnet/dependency/DependencyPanel.js.map +1 -0
  87. package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.d.ts +2 -0
  88. package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.d.ts.map +1 -0
  89. package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.js +171 -0
  90. package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.js.map +1 -0
  91. package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.d.ts +2 -0
  92. package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.d.ts.map +1 -0
  93. package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.js +232 -0
  94. package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.js.map +1 -0
  95. package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.d.ts +2 -0
  96. package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.d.ts.map +1 -0
  97. package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.js +93 -0
  98. package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.js.map +1 -0
  99. package/dist/planmagnet/pages/DashboardDashboardPagePage.d.ts.map +1 -1
  100. package/dist/planmagnet/pages/DashboardDashboardPagePage.js +11 -3
  101. package/dist/planmagnet/pages/DashboardDashboardPagePage.js.map +1 -1
  102. package/dist/planmagnet/pages/PortfoliosEditPortfolioPagePage.js +5 -5
  103. package/dist/planmagnet/pages/PortfoliosPortfolioDetailPagePage.js +9 -9
  104. package/dist/planmagnet/pages/PortfoliosPortfoliosPagePage.js +6 -6
  105. package/dist/planmagnet/pages/ProgramsCreateProgramPagePage.js +4 -4
  106. package/dist/planmagnet/pages/ProgramsEditProgramPagePage.js +6 -6
  107. package/dist/planmagnet/pages/ProgramsProgramsPagePage.js +5 -5
  108. package/dist/planmagnet/pages/ProjectsBudgetDetailPagePage.d.ts +2 -0
  109. package/dist/planmagnet/pages/ProjectsBudgetDetailPagePage.d.ts.map +1 -0
  110. package/dist/planmagnet/pages/ProjectsBudgetDetailPagePage.js +315 -0
  111. package/dist/planmagnet/pages/ProjectsBudgetDetailPagePage.js.map +1 -0
  112. package/dist/planmagnet/pages/ProjectsBudgetsPagePage.d.ts +2 -0
  113. package/dist/planmagnet/pages/ProjectsBudgetsPagePage.d.ts.map +1 -0
  114. package/dist/planmagnet/pages/ProjectsBudgetsPagePage.js +186 -0
  115. package/dist/planmagnet/pages/ProjectsBudgetsPagePage.js.map +1 -0
  116. package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.d.ts +2 -0
  117. package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.d.ts.map +1 -0
  118. package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.js +164 -0
  119. package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.js.map +1 -0
  120. package/dist/planmagnet/pages/ProjectsCustomFieldsPagePage.d.ts +2 -0
  121. package/dist/planmagnet/pages/ProjectsCustomFieldsPagePage.d.ts.map +1 -0
  122. package/dist/planmagnet/pages/ProjectsCustomFieldsPagePage.js +348 -0
  123. package/dist/planmagnet/pages/ProjectsCustomFieldsPagePage.js.map +1 -0
  124. package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js +10 -10
  125. package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.js +4 -4
  126. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.d.ts.map +1 -1
  127. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js +20 -10
  128. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js.map +1 -1
  129. package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.d.ts.map +1 -1
  130. package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.js +13 -8
  131. package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.js.map +1 -1
  132. package/dist/planmagnet/pages/ProjectsPlanningPagePage.d.ts.map +1 -1
  133. package/dist/planmagnet/pages/ProjectsPlanningPagePage.js +76 -56
  134. package/dist/planmagnet/pages/ProjectsPlanningPagePage.js.map +1 -1
  135. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.d.ts.map +1 -1
  136. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js +372 -203
  137. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js.map +1 -1
  138. package/dist/planmagnet/pages/ProjectsProjectsPagePage.d.ts.map +1 -1
  139. package/dist/planmagnet/pages/ProjectsProjectsPagePage.js +81 -72
  140. package/dist/planmagnet/pages/ProjectsProjectsPagePage.js.map +1 -1
  141. package/dist/planmagnet/pages/RisksRiskDetailPagePage.d.ts +2 -0
  142. package/dist/planmagnet/pages/RisksRiskDetailPagePage.d.ts.map +1 -0
  143. package/dist/planmagnet/pages/RisksRiskDetailPagePage.js +278 -0
  144. package/dist/planmagnet/pages/RisksRiskDetailPagePage.js.map +1 -0
  145. package/dist/planmagnet/pages/RisksRiskRegisterPagePage.d.ts +2 -0
  146. package/dist/planmagnet/pages/RisksRiskRegisterPagePage.d.ts.map +1 -0
  147. package/dist/planmagnet/pages/RisksRiskRegisterPagePage.js +191 -0
  148. package/dist/planmagnet/pages/RisksRiskRegisterPagePage.js.map +1 -0
  149. package/dist/planmagnet/pages/SprintsStartSprintPagePage.d.ts.map +1 -1
  150. package/dist/planmagnet/pages/SprintsStartSprintPagePage.js +168 -122
  151. package/dist/planmagnet/pages/SprintsStartSprintPagePage.js.map +1 -1
  152. package/dist/planmagnet/pages/TasksCreateTaskPagePage.js +5 -5
  153. package/dist/planmagnet/pages/TasksEditTaskPagePage.js +4 -4
  154. package/dist/planmagnet/pages/TasksTaskDetailPagePage.d.ts.map +1 -1
  155. package/dist/planmagnet/pages/TasksTaskDetailPagePage.js +161 -137
  156. package/dist/planmagnet/pages/TasksTaskDetailPagePage.js.map +1 -1
  157. package/dist/planmagnet/pages/TasksTasksPagePage.d.ts.map +1 -1
  158. package/dist/planmagnet/pages/TasksTasksPagePage.js +124 -113
  159. package/dist/planmagnet/pages/TasksTasksPagePage.js.map +1 -1
  160. package/dist/planmagnet/pages/TasksTimeEntriesPagePage.d.ts +2 -0
  161. package/dist/planmagnet/pages/TasksTimeEntriesPagePage.d.ts.map +1 -0
  162. package/dist/planmagnet/pages/TasksTimeEntriesPagePage.js +263 -0
  163. package/dist/planmagnet/pages/TasksTimeEntriesPagePage.js.map +1 -0
  164. package/dist/planmagnet/pages/TasksTimesheetDetailPagePage.d.ts +2 -0
  165. package/dist/planmagnet/pages/TasksTimesheetDetailPagePage.d.ts.map +1 -0
  166. package/dist/planmagnet/pages/TasksTimesheetDetailPagePage.js +254 -0
  167. package/dist/planmagnet/pages/TasksTimesheetDetailPagePage.js.map +1 -0
  168. package/dist/planmagnet/pages/TasksTimesheetsPagePage.d.ts +2 -0
  169. package/dist/planmagnet/pages/TasksTimesheetsPagePage.d.ts.map +1 -0
  170. package/dist/planmagnet/pages/TasksTimesheetsPagePage.js +165 -0
  171. package/dist/planmagnet/pages/TasksTimesheetsPagePage.js.map +1 -0
  172. package/dist/planmagnet/pages/TeamCreateTeamPagePage.d.ts.map +1 -1
  173. package/dist/planmagnet/pages/TeamCreateTeamPagePage.js +288 -91
  174. package/dist/planmagnet/pages/TeamCreateTeamPagePage.js.map +1 -1
  175. package/dist/planmagnet/pages/TeamTeamDetailPagePage.d.ts +2 -0
  176. package/dist/planmagnet/pages/TeamTeamDetailPagePage.d.ts.map +1 -0
  177. package/dist/planmagnet/pages/TeamTeamDetailPagePage.js +217 -0
  178. package/dist/planmagnet/pages/TeamTeamDetailPagePage.js.map +1 -0
  179. package/dist/planmagnet/pages/TeamTeamEditPagePage.d.ts +2 -0
  180. package/dist/planmagnet/pages/TeamTeamEditPagePage.d.ts.map +1 -0
  181. package/dist/planmagnet/pages/TeamTeamEditPagePage.js +211 -0
  182. package/dist/planmagnet/pages/TeamTeamEditPagePage.js.map +1 -0
  183. package/dist/planmagnet/pages/TeamTeamsListPagePage.d.ts +2 -0
  184. package/dist/planmagnet/pages/TeamTeamsListPagePage.d.ts.map +1 -0
  185. package/dist/planmagnet/pages/TeamTeamsListPagePage.js +118 -0
  186. package/dist/planmagnet/pages/TeamTeamsListPagePage.js.map +1 -0
  187. package/dist/planmagnet/pages/TemplatesEditTemplatePagePage.d.ts +2 -0
  188. package/dist/planmagnet/pages/TemplatesEditTemplatePagePage.d.ts.map +1 -0
  189. package/dist/planmagnet/pages/TemplatesEditTemplatePagePage.js +316 -0
  190. package/dist/planmagnet/pages/TemplatesEditTemplatePagePage.js.map +1 -0
  191. package/dist/planmagnet/pages/TemplatesTemplatesPagePage.d.ts +2 -0
  192. package/dist/planmagnet/pages/TemplatesTemplatesPagePage.d.ts.map +1 -0
  193. package/dist/planmagnet/pages/TemplatesTemplatesPagePage.js +208 -0
  194. package/dist/planmagnet/pages/TemplatesTemplatesPagePage.js.map +1 -0
  195. package/dist/planmagnet/pages/analytics/DeliveryHealthCards.d.ts +0 -5
  196. package/dist/planmagnet/pages/analytics/DeliveryHealthCards.d.ts.map +1 -1
  197. package/dist/planmagnet/pages/analytics/DeliveryHealthCards.js +47 -89
  198. package/dist/planmagnet/pages/analytics/DeliveryHealthCards.js.map +1 -1
  199. package/dist/planmagnet/roadmaps/RoadmapControls.js +24 -24
  200. package/dist/planmagnet/sprints/SprintControls.d.ts +15 -3
  201. package/dist/planmagnet/sprints/SprintControls.d.ts.map +1 -1
  202. package/dist/planmagnet/sprints/SprintControls.js +293 -190
  203. package/dist/planmagnet/sprints/SprintControls.js.map +1 -1
  204. package/dist/planmagnet/team/TeamControls.d.ts +31 -0
  205. package/dist/planmagnet/team/TeamControls.d.ts.map +1 -0
  206. package/dist/planmagnet/team/TeamControls.js +407 -0
  207. package/dist/planmagnet/team/TeamControls.js.map +1 -0
  208. package/dist/planmagnet/time/TaskTimePanel.d.ts +7 -0
  209. package/dist/planmagnet/time/TaskTimePanel.d.ts.map +1 -0
  210. package/dist/planmagnet/time/TaskTimePanel.js +104 -0
  211. package/dist/planmagnet/time/TaskTimePanel.js.map +1 -0
  212. package/dist/planmagnet/time/TimeEntryControls.d.ts +37 -0
  213. package/dist/planmagnet/time/TimeEntryControls.d.ts.map +1 -0
  214. package/dist/planmagnet/time/TimeEntryControls.js +338 -0
  215. package/dist/planmagnet/time/TimeEntryControls.js.map +1 -0
  216. package/dist/planmagnet/time/TimesheetControls.d.ts +18 -0
  217. package/dist/planmagnet/time/TimesheetControls.d.ts.map +1 -0
  218. package/dist/planmagnet/time/TimesheetControls.js +244 -0
  219. package/dist/planmagnet/time/TimesheetControls.js.map +1 -0
  220. package/dist/planmagnet/time/timeShared.d.ts +29 -0
  221. package/dist/planmagnet/time/timeShared.d.ts.map +1 -0
  222. package/dist/planmagnet/time/timeShared.js +34 -0
  223. package/dist/planmagnet/time/timeShared.js.map +1 -0
  224. package/dist/planmagnet/utils/rowNavigation.js +5 -2
  225. package/dist/planmagnet/utils/rowNavigation.js.map +1 -1
  226. 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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"}
@@ -1,8 +1,8 @@
1
1
  import { usePlanMagnetNavigate as e } from "../providers/PlanMagnetProvider.js";
2
2
  import { LEAVES_PAGE_CONTEXT as t, throwOnError as n } from "../utils/mutationResult.js";
3
- import { detailPath as r } from "../utils/rowNavigation.js";
4
- import { ConfirmButton as i, ErrorLine as a } from "./ConfirmButton.js";
5
- import { CompetitorSearchSelect as o } from "./Pickers.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
6
  import { useState as s } from "react";
7
7
  import { Pencil as c, Plus as l, Trash2 as u, X as d } from "lucide-react";
8
8
  import { gql as f } from "@apollo/client";
@@ -19,14 +19,14 @@ var _ = [
19
19
  planmagnetDeleteCompetitor(id: $id)
20
20
  }
21
21
  `;
22
- function y({ competitorId: o, name: l }) {
22
+ function y({ competitorId: a, name: l }) {
23
23
  let d = e(), [f, y] = p(v, {
24
24
  refetchQueries: _.filter((e) => e !== "GetCompetitor"),
25
25
  context: t
26
26
  }), [b, x] = s(null), S = async () => {
27
27
  x(null);
28
28
  try {
29
- await n(f({ variables: { id: o } })), d("/products/competitors-page");
29
+ await n(f({ variables: { id: a } })), d("/products/competitors-page");
30
30
  } catch (e) {
31
31
  x(e instanceof Error ? e.message : "The competitor could not be deleted.");
32
32
  }
@@ -39,9 +39,9 @@ function y({ competitorId: o, name: l }) {
39
39
  size: "sm",
40
40
  variant: "outline",
41
41
  "data-testid": "competitor-edit",
42
- onClick: () => d(r("/products/edit-competitor-page", o)),
42
+ onClick: () => d(o("/products/edit-competitor-page", a)),
43
43
  children: [/* @__PURE__ */ m(c, { className: "mr-1 h-4 w-4" }), "Edit"]
44
- }), /* @__PURE__ */ m(i, {
44
+ }), /* @__PURE__ */ m(r, {
45
45
  label: "Delete",
46
46
  variant: "outline",
47
47
  icon: /* @__PURE__ */ m(u, { className: "mr-1 h-4 w-4" }),
@@ -52,7 +52,7 @@ function y({ competitorId: o, name: l }) {
52
52
  disabled: y.loading,
53
53
  onConfirm: () => void S()
54
54
  })]
55
- }), b && /* @__PURE__ */ m(a, { message: b })]
55
+ }), b && /* @__PURE__ */ m(i, { message: b })]
56
56
  });
57
57
  }
58
58
  var b = f`
@@ -80,7 +80,7 @@ var b = f`
80
80
  }
81
81
  }
82
82
  `;
83
- function S({ featureRequestId: t, competitors: i }) {
83
+ function S({ featureRequestId: t, competitors: r }) {
84
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
85
  if (u) {
86
86
  w(null);
@@ -107,16 +107,16 @@ function S({ featureRequestId: t, competitors: i }) {
107
107
  return /* @__PURE__ */ h("div", {
108
108
  className: "space-y-3",
109
109
  children: [
110
- i.length === 0 && /* @__PURE__ */ m("p", {
110
+ r.length === 0 && /* @__PURE__ */ m("p", {
111
111
  className: "text-sm text-muted-foreground",
112
112
  children: "No competitors linked yet."
113
113
  }),
114
- i.map((e) => /* @__PURE__ */ h("div", {
114
+ r.map((e) => /* @__PURE__ */ h("div", {
115
115
  className: "flex items-start justify-between gap-2 rounded-md border p-3",
116
116
  children: [/* @__PURE__ */ h("button", {
117
117
  type: "button",
118
118
  className: "flex-1 text-left",
119
- onClick: () => c(r("/products/competitor-detail-page", e.id)),
119
+ onClick: () => c(o("/products/competitor-detail-page", e.id)),
120
120
  children: [/* @__PURE__ */ h("div", {
121
121
  className: "flex items-center gap-2",
122
122
  children: [/* @__PURE__ */ m("span", {
@@ -143,11 +143,11 @@ function S({ featureRequestId: t, competitors: i }) {
143
143
  className: "flex items-start gap-2 pt-2 border-t",
144
144
  children: [/* @__PURE__ */ m("div", {
145
145
  className: "flex-1",
146
- children: /* @__PURE__ */ m(o, {
146
+ children: /* @__PURE__ */ m(a, {
147
147
  id: "feature-add-competitor",
148
148
  value: u,
149
149
  onChange: f,
150
- exclude: i.map((e) => e.id)
150
+ exclude: r.map((e) => e.id)
151
151
  })
152
152
  }), /* @__PURE__ */ h(g, {
153
153
  size: "sm",
@@ -162,7 +162,7 @@ function S({ featureRequestId: t, competitors: i }) {
162
162
  onClick: () => c("/products/create-competitor-page"),
163
163
  children: [/* @__PURE__ */ m(l, { className: "mr-1 h-4 w-4" }), "New competitor"]
164
164
  }),
165
- C && /* @__PURE__ */ m(a, { message: C })
165
+ C && /* @__PURE__ */ m(i, { message: C })
166
166
  ]
167
167
  });
168
168
  }
@@ -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"}