@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,315 @@
1
+ import { usePlanMagnet as e, usePlanMagnetNavigate as t } from "../providers/PlanMagnetProvider.js";
2
+ import { PersonName as n } from "../people/People.js";
3
+ import { throwOnError as r } from "../utils/mutationResult.js";
4
+ import { ErrorLine as i } from "./ConfirmButton.js";
5
+ import { useAssigneeOptions as a } from "./WorkItemControls.js";
6
+ import { detailPath as o } from "../utils/rowNavigation.js";
7
+ import { CUSTOM_FIELD_QUERIES as s, PROJECT_CUSTOM_FIELD_DEFINITIONS as c, REMOVE_CUSTOM_FIELD_VALUE as l, SET_CUSTOM_FIELD_VALUE as u, optionStrings as d } from "./CustomFieldControls.js";
8
+ import { useState as f } from "react";
9
+ import { ListPlus as p } from "lucide-react";
10
+ import { useMutation as m, useQuery as h } from "@apollo/client/react";
11
+ import { jsx as g, jsxs as _ } from "react/jsx-runtime";
12
+ import { Button as v, Card as y, CardContent as b, CardHeader as x, CardTitle as S, Input as C } from "@burdenoff/fe-libs/ui";
13
+ //#region src/planmagnet/controls/CustomFieldValuesPanel.tsx
14
+ var w = {
15
+ refetchQueries: s,
16
+ awaitRefetchQueries: !0
17
+ };
18
+ function T(e) {
19
+ let [t, n] = m(u, w), [i, a] = m(l, w), [o, s] = f(null);
20
+ return {
21
+ save: async (n, i) => {
22
+ s(null);
23
+ try {
24
+ return await r(t({ variables: { input: {
25
+ definitionId: n,
26
+ workItemId: e,
27
+ value: i
28
+ } } })), !0;
29
+ } catch (e) {
30
+ return s(e instanceof Error ? e.message : "The value could not be saved."), !1;
31
+ }
32
+ },
33
+ clear: async (t) => {
34
+ s(null);
35
+ try {
36
+ return await r(i({ variables: {
37
+ definitionId: t,
38
+ workItemId: e
39
+ } })), !0;
40
+ } catch (e) {
41
+ return s(e instanceof Error ? e.message : "The value could not be cleared."), !1;
42
+ }
43
+ },
44
+ saving: n.loading || a.loading,
45
+ error: o
46
+ };
47
+ }
48
+ var E = "w-full rounded-md border border-input bg-background px-3 py-2 text-sm disabled:opacity-60";
49
+ function D({ workItemId: e, definition: t, value: n }) {
50
+ let { save: r, clear: a, saving: o, error: s } = T(e), c = n !== void 0, l = `custom-field-value-${t.id}`;
51
+ return /* @__PURE__ */ _("div", {
52
+ className: "space-y-1.5 border-b pb-3 last:border-0 last:pb-0",
53
+ "data-testid": l,
54
+ children: [
55
+ /* @__PURE__ */ _("div", {
56
+ className: "flex items-center justify-between gap-2",
57
+ children: [/* @__PURE__ */ _("label", {
58
+ htmlFor: l,
59
+ className: "text-sm font-medium",
60
+ children: [t.name, t.isRequired && /* @__PURE__ */ g("span", {
61
+ className: "text-destructive",
62
+ children: " *"
63
+ })]
64
+ }), c && /* @__PURE__ */ g("button", {
65
+ type: "button",
66
+ className: "text-xs text-muted-foreground hover:underline disabled:opacity-60",
67
+ disabled: o,
68
+ onClick: () => void a(t.id),
69
+ children: "Clear"
70
+ })]
71
+ }),
72
+ t.description && /* @__PURE__ */ g("p", {
73
+ className: "text-xs text-muted-foreground",
74
+ children: t.description
75
+ }),
76
+ /* @__PURE__ */ g(O, {
77
+ id: l,
78
+ definition: t,
79
+ value: n?.value,
80
+ saving: o,
81
+ onSave: (e) => e == null ? c ? a(t.id) : Promise.resolve(!0) : r(t.id, e)
82
+ }),
83
+ !c && /* @__PURE__ */ g("p", {
84
+ className: "text-xs text-muted-foreground",
85
+ children: "Not set."
86
+ }),
87
+ s && /* @__PURE__ */ g(i, { message: s })
88
+ ]
89
+ });
90
+ }
91
+ function O({ id: e, definition: t, value: n, saving: r, onSave: i }) {
92
+ let a = t.fieldType;
93
+ if (a === "BOOLEAN") {
94
+ let t = n === !0;
95
+ return /* @__PURE__ */ _("label", {
96
+ className: "flex items-center gap-2 text-sm",
97
+ children: [/* @__PURE__ */ g("input", {
98
+ id: e,
99
+ type: "checkbox",
100
+ checked: t,
101
+ disabled: r,
102
+ onChange: (e) => void i(e.target.checked)
103
+ }), t ? "Yes" : "No"]
104
+ });
105
+ }
106
+ if (a === "SELECT") {
107
+ let a = d(t.options), o = typeof n == "string" ? n : "", s = o && !a.includes(o) ? [o, ...a] : a;
108
+ return /* @__PURE__ */ _("select", {
109
+ id: e,
110
+ className: E,
111
+ value: o,
112
+ disabled: r,
113
+ onChange: (e) => {
114
+ e.target.value && i(e.target.value);
115
+ },
116
+ children: [/* @__PURE__ */ g("option", {
117
+ value: "",
118
+ children: "Choose…"
119
+ }), s.map((e) => /* @__PURE__ */ g("option", {
120
+ value: e,
121
+ children: e
122
+ }, e))]
123
+ });
124
+ }
125
+ if (a === "MULTI_SELECT") {
126
+ let e = d(t.options), a = Array.isArray(n) ? n.filter((e) => typeof e == "string") : [], o = [...new Set([...e, ...a])], s = (e) => {
127
+ i(a.includes(e) ? a.filter((t) => t !== e) : [...a, e]);
128
+ };
129
+ return /* @__PURE__ */ _("div", {
130
+ className: "flex flex-wrap gap-x-4 gap-y-1",
131
+ children: [o.map((e) => /* @__PURE__ */ _("label", {
132
+ className: "flex items-center gap-1.5 text-sm",
133
+ children: [/* @__PURE__ */ g("input", {
134
+ type: "checkbox",
135
+ checked: a.includes(e),
136
+ disabled: r,
137
+ onChange: () => s(e)
138
+ }), e]
139
+ }, e)), o.length === 0 && /* @__PURE__ */ g("span", {
140
+ className: "text-sm text-muted-foreground",
141
+ children: "No options configured."
142
+ })]
143
+ });
144
+ }
145
+ return a === "USER" ? /* @__PURE__ */ g(k, {
146
+ id: e,
147
+ value: typeof n == "string" ? n : "",
148
+ disabled: r,
149
+ onSave: i
150
+ }) : a === "DATE" ? /* @__PURE__ */ g(C, {
151
+ id: e,
152
+ type: "date",
153
+ disabled: r,
154
+ value: typeof n == "string" ? n.slice(0, 10) : "",
155
+ onChange: (e) => void i(e.target.value || null)
156
+ }) : a === "NUMBER" ? /* @__PURE__ */ g(A, {
157
+ id: e,
158
+ inputType: "number",
159
+ initial: typeof n == "number" ? String(n) : "",
160
+ saving: r,
161
+ onSave: (e) => {
162
+ let t = e.trim();
163
+ if (t === "") return i(null);
164
+ let n = Number(t);
165
+ return Number.isFinite(n) ? i(n) : Promise.resolve(!1);
166
+ },
167
+ invalid: (e) => e.trim() !== "" && !Number.isFinite(Number(e.trim())),
168
+ invalidMessage: "Enter a number."
169
+ }) : a === "JSON" ? /* @__PURE__ */ g(A, {
170
+ id: e,
171
+ multiline: !0,
172
+ initial: n === void 0 ? "" : JSON.stringify(n, null, 2),
173
+ saving: r,
174
+ onSave: (e) => {
175
+ let t = e.trim();
176
+ if (t === "") return i(null);
177
+ try {
178
+ return i(JSON.parse(t));
179
+ } catch {
180
+ return Promise.resolve(!1);
181
+ }
182
+ },
183
+ invalid: (e) => {
184
+ let t = e.trim();
185
+ if (t === "") return !1;
186
+ try {
187
+ return JSON.parse(t), !1;
188
+ } catch {
189
+ return !0;
190
+ }
191
+ },
192
+ invalidMessage: "That is not valid JSON."
193
+ }) : /* @__PURE__ */ g(A, {
194
+ id: e,
195
+ inputType: a === "URL" ? "url" : a === "EMAIL" ? "email" : "text",
196
+ initial: typeof n == "string" ? n : "",
197
+ saving: r,
198
+ onSave: (e) => i(e.trim() === "" ? null : e.trim()),
199
+ invalid: () => !1,
200
+ invalidMessage: ""
201
+ });
202
+ }
203
+ function k({ id: e, value: t, disabled: r, onSave: i }) {
204
+ let { options: o, loading: s } = a(t || null);
205
+ return /* @__PURE__ */ _("div", {
206
+ className: "flex flex-col gap-1",
207
+ children: [
208
+ /* @__PURE__ */ _("select", {
209
+ id: e,
210
+ className: E,
211
+ value: t,
212
+ disabled: r,
213
+ onChange: (e) => {
214
+ e.target.value && i(e.target.value);
215
+ },
216
+ children: [/* @__PURE__ */ g("option", {
217
+ value: "",
218
+ children: "Choose a member…"
219
+ }), o.map((e) => /* @__PURE__ */ g("option", {
220
+ value: e.id,
221
+ children: e.name
222
+ }, e.id))]
223
+ }),
224
+ t && /* @__PURE__ */ _("p", {
225
+ className: "text-xs text-muted-foreground",
226
+ children: ["Currently ", /* @__PURE__ */ g(n, { id: t })]
227
+ }),
228
+ s && o.length === 0 && /* @__PURE__ */ g("span", {
229
+ className: "text-xs text-muted-foreground",
230
+ children: "Loading members…"
231
+ })
232
+ ]
233
+ });
234
+ }
235
+ function A({ id: e, initial: t, saving: n, onSave: r, invalid: a, invalidMessage: o, multiline: s = !1, inputType: c = "text" }) {
236
+ let [l, u] = f(t), [d, p] = f(t), [m, h] = f(!1);
237
+ t !== d && l === d && (u(t), p(t));
238
+ let y = l !== d, b = a(l), x = async () => {
239
+ if (!(!y || b || m)) {
240
+ h(!0);
241
+ try {
242
+ await r(l) && p(l);
243
+ } finally {
244
+ h(!1);
245
+ }
246
+ }
247
+ };
248
+ return /* @__PURE__ */ _("div", {
249
+ className: "flex flex-col gap-1",
250
+ children: [/* @__PURE__ */ _("div", {
251
+ className: "flex gap-2",
252
+ children: [s ? /* @__PURE__ */ g("textarea", {
253
+ id: e,
254
+ className: `${E} min-h-[96px] font-mono text-xs`,
255
+ value: l,
256
+ disabled: n,
257
+ onChange: (e) => u(e.target.value)
258
+ }) : /* @__PURE__ */ g(C, {
259
+ id: e,
260
+ type: c,
261
+ className: "flex-1",
262
+ value: l,
263
+ disabled: n,
264
+ onChange: (e) => u(e.target.value)
265
+ }), /* @__PURE__ */ g(v, {
266
+ size: "sm",
267
+ variant: "outline",
268
+ disabled: !y || b || n || m,
269
+ onClick: () => void x(),
270
+ children: n || m ? "Saving…" : "Save"
271
+ })]
272
+ }), b && /* @__PURE__ */ g(i, { message: o })]
273
+ });
274
+ }
275
+ function j({ workItemId: n, projectId: r, values: a }) {
276
+ let { workspaceId: s } = e(), l = t(), { data: u, loading: d, error: f } = h(c, {
277
+ variables: {
278
+ workspaceId: s ?? "",
279
+ projectId: r
280
+ },
281
+ skip: !s || !r
282
+ }), m = [...u?.planmagnetCustomFieldDefinitions.items ?? []].sort((e, t) => e.sortOrder - t.sortOrder || e.name.localeCompare(t.name)), C = new Map(a.map((e) => [e.definitionId, e]));
283
+ return /* @__PURE__ */ _(y, { children: [/* @__PURE__ */ _(x, {
284
+ className: "flex flex-row items-center justify-between space-y-0",
285
+ children: [/* @__PURE__ */ g(S, { children: "Custom Fields" }), /* @__PURE__ */ _(v, {
286
+ size: "sm",
287
+ variant: "outline",
288
+ onClick: () => l(o("/projects/project-custom-fields-page", r)),
289
+ children: [/* @__PURE__ */ g(p, { className: "mr-1 h-4 w-4" }), "Manage fields"]
290
+ })]
291
+ }), /* @__PURE__ */ _(b, {
292
+ className: "space-y-4",
293
+ children: [
294
+ d && !u && /* @__PURE__ */ g("p", {
295
+ className: "text-sm text-muted-foreground",
296
+ children: "Loading…"
297
+ }),
298
+ f && /* @__PURE__ */ g(i, { message: f.message }),
299
+ u && m.length === 0 && /* @__PURE__ */ g("p", {
300
+ className: "text-sm text-muted-foreground",
301
+ "data-testid": "custom-fields-panel-empty",
302
+ children: "This project has no custom fields yet."
303
+ }),
304
+ m.map((e) => /* @__PURE__ */ g(D, {
305
+ workItemId: n,
306
+ definition: e,
307
+ value: C.get(e.id)
308
+ }, e.id))
309
+ ]
310
+ })] });
311
+ }
312
+ //#endregion
313
+ export { j as CustomFieldsPanel };
314
+
315
+ //# sourceMappingURL=CustomFieldValuesPanel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CustomFieldValuesPanel.js","names":[],"sources":["../../../src/planmagnet/controls/CustomFieldValuesPanel.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { Button, Card, CardContent, CardHeader, CardTitle, Input } from '@burdenoff/fe-libs/ui';\nimport { ListPlus } from 'lucide-react';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { detailPath } from '../utils/rowNavigation';\nimport { throwOnError } from '../utils/mutationResult';\nimport { ErrorLine } from './ConfirmButton';\nimport { useAssigneeOptions } from './WorkItemControls';\nimport { PersonName } from '../people/People';\nimport {\n CUSTOM_FIELD_QUERIES,\n PROJECT_CUSTOM_FIELD_DEFINITIONS,\n REMOVE_CUSTOM_FIELD_VALUE,\n SET_CUSTOM_FIELD_VALUE,\n optionStrings,\n type CustomFieldDefinitionSummary,\n type CustomFieldValueSummary,\n} from './CustomFieldControls';\n\n/**\n * A task's custom field values (BOFF-8047, capability register: Custom fields, `api-only`). The definitions come\n * from the task's own project; a value is only ever shown/edited for a definition the project still has. Every\n * write goes through `planmagnetSetCustomFieldValue` / `planmagnetRemoveCustomFieldValue` — the same fields\n * `WorkItem.customFieldValues` reads back (BOFF-7704/7839 follow-up) — and a refusal is shown, never swallowed\n * (fe-libs `errorPolicy: 'all'` resolves a failed mutation instead of rejecting it).\n */\n\nconst mutationOptions = {\n refetchQueries: CUSTOM_FIELD_QUERIES,\n awaitRefetchQueries: true,\n} as const;\n\nfunction useValueMutations(workItemId: string) {\n const [set, setState] = useMutation(SET_CUSTOM_FIELD_VALUE, mutationOptions);\n const [remove, removeState] = useMutation(REMOVE_CUSTOM_FIELD_VALUE, mutationOptions);\n const [error, setError] = useState<string | null>(null);\n\n // Returns whether the write actually landed: fe-libs `errorPolicy: 'all'` resolves a refused mutation\n // instead of rejecting it, so callers that need to know \"did this really save\" (not just \"did we ask\n // the server\") must read this return value rather than assume the awaited promise settling means success.\n const save = async (definitionId: string, value: unknown): Promise<boolean> => {\n setError(null);\n try {\n await throwOnError(set({ variables: { input: { definitionId, workItemId, value } } }));\n return true;\n } catch (e) {\n setError(e instanceof Error ? e.message : 'The value could not be saved.');\n return false;\n }\n };\n const clear = async (definitionId: string): Promise<boolean> => {\n setError(null);\n try {\n await throwOnError(remove({ variables: { definitionId, workItemId } }));\n return true;\n } catch (e) {\n setError(e instanceof Error ? e.message : 'The value could not be cleared.');\n return false;\n }\n };\n return { save, clear, saving: setState.loading || removeState.loading, error };\n}\n\nconst fieldClass =\n 'w-full rounded-md border border-input bg-background px-3 py-2 text-sm disabled:opacity-60';\n\n/** A single definition's row: its current value (if any) and the control to change it. */\nfunction CustomFieldRow({\n workItemId,\n definition,\n value,\n}: {\n workItemId: string;\n definition: CustomFieldDefinitionSummary;\n value: CustomFieldValueSummary | undefined;\n}) {\n const { save, clear, saving, error } = useValueMutations(workItemId);\n const isSet = value !== undefined;\n const testId = `custom-field-value-${definition.id}`;\n\n return (\n <div className=\"space-y-1.5 border-b pb-3 last:border-0 last:pb-0\" data-testid={testId}>\n <div className=\"flex items-center justify-between gap-2\">\n <label htmlFor={testId} className=\"text-sm font-medium\">\n {definition.name}\n {definition.isRequired && <span className=\"text-destructive\"> *</span>}\n </label>\n {isSet && (\n <button\n type=\"button\"\n className=\"text-xs text-muted-foreground hover:underline disabled:opacity-60\"\n disabled={saving}\n onClick={() => void clear(definition.id)}\n >\n Clear\n </button>\n )}\n </div>\n {definition.description && (\n <p className=\"text-xs text-muted-foreground\">{definition.description}</p>\n )}\n <CustomFieldControl\n id={testId}\n definition={definition}\n value={value?.value}\n saving={saving}\n onSave={(next) => {\n // `PlanmagnetSetCustomFieldValueInput.value` is `JSON!` (non-null) in production — a control\n // clearing itself back to empty (the DATE input's native × button with no Save gate, or Save on\n // an emptied text/number/JSON field) must route through the REMOVE mutation instead, exactly\n // like the \"Clear\" link above. Nothing to remove when the row was never set — a no-op, not a\n // delete-not-found, and there was nothing to fail, so it reports success.\n if (next === null || next === undefined) {\n return isSet ? clear(definition.id) : Promise.resolve(true);\n }\n return save(definition.id, next);\n }}\n />\n {!isSet && <p className=\"text-xs text-muted-foreground\">Not set.</p>}\n {error && <ErrorLine message={error} />}\n </div>\n );\n}\n\n/** The input for one field, shaped by `fieldType`. Selects/booleans/users save on change; free text needs a\n * Save button so a keystroke never fires a request. */\nfunction CustomFieldControl({\n id,\n definition,\n value,\n saving,\n onSave,\n}: {\n id: string;\n definition: CustomFieldDefinitionSummary;\n value: unknown;\n saving: boolean;\n onSave: (value: unknown) => Promise<boolean>;\n}) {\n const type = definition.fieldType;\n\n if (type === 'BOOLEAN') {\n const checked = value === true;\n return (\n <label className=\"flex items-center gap-2 text-sm\">\n <input\n id={id}\n type=\"checkbox\"\n checked={checked}\n disabled={saving}\n onChange={(e) => void onSave(e.target.checked)}\n />\n {checked ? 'Yes' : 'No'}\n </label>\n );\n }\n\n if (type === 'SELECT') {\n const options = optionStrings(definition.options);\n const current = typeof value === 'string' ? value : '';\n const all = current && !options.includes(current) ? [current, ...options] : options;\n return (\n <select\n id={id}\n className={fieldClass}\n value={current}\n disabled={saving}\n onChange={(e) => {\n if (e.target.value) void onSave(e.target.value);\n }}\n >\n <option value=\"\">Choose…</option>\n {all.map((o) => (\n <option key={o} value={o}>\n {o}\n </option>\n ))}\n </select>\n );\n }\n\n if (type === 'MULTI_SELECT') {\n const options = optionStrings(definition.options);\n const current = Array.isArray(value)\n ? value.filter((v): v is string => typeof v === 'string')\n : [];\n const all = [...new Set([...options, ...current])];\n const toggle = (option: string) => {\n const next = current.includes(option)\n ? current.filter((o) => o !== option)\n : [...current, option];\n void onSave(next);\n };\n return (\n <div className=\"flex flex-wrap gap-x-4 gap-y-1\">\n {all.map((o) => (\n <label key={o} className=\"flex items-center gap-1.5 text-sm\">\n <input\n type=\"checkbox\"\n checked={current.includes(o)}\n disabled={saving}\n onChange={() => toggle(o)}\n />\n {o}\n </label>\n ))}\n {all.length === 0 && (\n <span className=\"text-sm text-muted-foreground\">No options configured.</span>\n )}\n </div>\n );\n }\n\n if (type === 'USER') {\n const current = typeof value === 'string' ? value : '';\n return <UserFieldControl id={id} value={current} disabled={saving} onSave={onSave} />;\n }\n\n if (type === 'DATE') {\n // Value is stored raw (the register: value writes skip type validation) — this UI always writes an\n // ISO date-only string, the shape every other date field in this app sends.\n const current = typeof value === 'string' ? value.slice(0, 10) : '';\n return (\n <Input\n id={id}\n type=\"date\"\n disabled={saving}\n value={current}\n onChange={(e) => void onSave(e.target.value || null)}\n />\n );\n }\n\n if (type === 'NUMBER') {\n return (\n <FreeTextControl\n id={id}\n inputType=\"number\"\n initial={typeof value === 'number' ? String(value) : ''}\n saving={saving}\n onSave={(text) => {\n const trimmed = text.trim();\n if (trimmed === '') return onSave(null);\n const n = Number(trimmed);\n return Number.isFinite(n) ? onSave(n) : Promise.resolve(false);\n }}\n invalid={(text) => text.trim() !== '' && !Number.isFinite(Number(text.trim()))}\n invalidMessage=\"Enter a number.\"\n />\n );\n }\n\n if (type === 'JSON') {\n return (\n <FreeTextControl\n id={id}\n multiline\n initial={value === undefined ? '' : JSON.stringify(value, null, 2)}\n saving={saving}\n onSave={(text) => {\n const trimmed = text.trim();\n if (trimmed === '') return onSave(null);\n try {\n return onSave(JSON.parse(trimmed));\n } catch {\n return Promise.resolve(false);\n }\n }}\n invalid={(text) => {\n const trimmed = text.trim();\n if (trimmed === '') return false;\n try {\n JSON.parse(trimmed);\n return false;\n } catch {\n return true;\n }\n }}\n invalidMessage=\"That is not valid JSON.\"\n />\n );\n }\n\n // TEXT, URL, EMAIL, LABEL and anything future: a plain line of text.\n return (\n <FreeTextControl\n id={id}\n inputType={type === 'URL' ? 'url' : type === 'EMAIL' ? 'email' : 'text'}\n initial={typeof value === 'string' ? value : ''}\n saving={saving}\n onSave={(text) => onSave(text.trim() === '' ? null : text.trim())}\n invalid={() => false}\n invalidMessage=\"\"\n />\n );\n}\n\n/** A user-id value: the workspace directory picker used elsewhere (BOFF-7946), '' clears the value. */\nfunction UserFieldControl({\n id,\n value,\n disabled,\n onSave,\n}: {\n id: string;\n value: string;\n disabled: boolean;\n onSave: (value: unknown) => Promise<boolean>;\n}) {\n const { options, loading } = useAssigneeOptions(value || null);\n return (\n <div className=\"flex flex-col gap-1\">\n <select\n id={id}\n className={fieldClass}\n value={value}\n disabled={disabled}\n onChange={(e) => {\n if (e.target.value) void onSave(e.target.value);\n }}\n >\n <option value=\"\">Choose a member…</option>\n {options.map((o) => (\n <option key={o.id} value={o.id}>\n {o.name}\n </option>\n ))}\n </select>\n {value && (\n <p className=\"text-xs text-muted-foreground\">\n Currently <PersonName id={value} />\n </p>\n )}\n {loading && options.length === 0 && (\n <span className=\"text-xs text-muted-foreground\">Loading members…</span>\n )}\n </div>\n );\n}\n\n/** Text/number/JSON entry: local draft state so typing never fires a request, an explicit Save button so\n * one does fire exactly once. */\nfunction FreeTextControl({\n id,\n initial,\n saving,\n onSave,\n invalid,\n invalidMessage,\n multiline = false,\n inputType = 'text',\n}: {\n id: string;\n initial: string;\n saving: boolean;\n onSave: (text: string) => Promise<boolean>;\n invalid: (text: string) => boolean;\n invalidMessage: string;\n multiline?: boolean;\n inputType?: string;\n}) {\n const [draft, setDraft] = useState(initial);\n const [lastSaved, setLastSaved] = useState(initial);\n // Tracks the in-flight commit separately from the parent's `saving` (the mutation's own loading state):\n // it covers the gap between clicking Save and that loading flag actually flipping true, so a second click\n // can never fire a duplicate request.\n const [committing, setCommitting] = useState(false);\n // The definition's own value changed under us (a save completed, or another editor's did): pick it up,\n // but only while this control has no unsaved edit of its own.\n if (initial !== lastSaved && draft === lastSaved) {\n setDraft(initial);\n setLastSaved(initial);\n }\n const dirty = draft !== lastSaved;\n const bad = invalid(draft);\n\n const commit = async () => {\n if (!dirty || bad || committing) return;\n setCommitting(true);\n try {\n // Only a CONFIRMED success may mark the draft as saved. fe-libs resolves a refused mutation instead\n // of rejecting it (errorPolicy: 'all'), so `await onSave(draft)` alone settling is not success — the\n // Save button must stay enabled (and the draft stay in the box) until `onSave` reports `true`, or a\n // refusal would look saved while the write never landed.\n const ok = await onSave(draft);\n if (ok) setLastSaved(draft);\n } finally {\n setCommitting(false);\n }\n };\n\n return (\n <div className=\"flex flex-col gap-1\">\n <div className=\"flex gap-2\">\n {multiline ? (\n <textarea\n id={id}\n className={`${fieldClass} min-h-[96px] font-mono text-xs`}\n value={draft}\n disabled={saving}\n onChange={(e) => setDraft(e.target.value)}\n />\n ) : (\n <Input\n id={id}\n type={inputType}\n className=\"flex-1\"\n value={draft}\n disabled={saving}\n onChange={(e) => setDraft(e.target.value)}\n />\n )}\n <Button\n size=\"sm\"\n variant=\"outline\"\n disabled={!dirty || bad || saving || committing}\n onClick={() => void commit()}\n >\n {saving || committing ? 'Saving…' : 'Save'}\n </Button>\n </div>\n {bad && <ErrorLine message={invalidMessage} />}\n </div>\n );\n}\n\nexport function CustomFieldsPanel({\n workItemId,\n projectId,\n values,\n}: {\n workItemId: string;\n projectId: string;\n values: CustomFieldValueSummary[];\n}) {\n const { workspaceId } = usePlanMagnet();\n const navigate = usePlanMagnetNavigate();\n const { data, loading, error } = useQuery<{\n planmagnetCustomFieldDefinitions: { items: CustomFieldDefinitionSummary[] };\n }>(PROJECT_CUSTOM_FIELD_DEFINITIONS, {\n variables: { workspaceId: workspaceId ?? '', projectId },\n skip: !workspaceId || !projectId,\n });\n const definitions = [...(data?.planmagnetCustomFieldDefinitions.items ?? [])].sort(\n (a, b) => a.sortOrder - b.sortOrder || a.name.localeCompare(b.name)\n );\n const byDefinition = new Map(values.map((v) => [v.definitionId, v]));\n\n return (\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0\">\n <CardTitle>Custom Fields</CardTitle>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => navigate(detailPath('/projects/project-custom-fields-page', projectId))}\n >\n <ListPlus className=\"mr-1 h-4 w-4\" />\n Manage fields\n </Button>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {/* Only before the first load: a refetch (any value save) must not blank every other field's state. */}\n {loading && !data && <p className=\"text-sm text-muted-foreground\">Loading…</p>}\n {error && <ErrorLine message={error.message} />}\n {data && definitions.length === 0 && (\n <p className=\"text-sm text-muted-foreground\" data-testid=\"custom-fields-panel-empty\">\n This project has no custom fields yet.\n </p>\n )}\n {definitions.map((def) => (\n <CustomFieldRow\n key={def.id}\n workItemId={workItemId}\n definition={def}\n value={byDefinition.get(def.id)}\n />\n ))}\n </CardContent>\n </Card>\n );\n}\n"],"mappings":"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"}
@@ -1,10 +1,10 @@
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 { ProjectSelect as o, WorkItemSearchSelect as s } from "./Pickers.js";
6
- import { parseIntField as c } from "../utils/formValidation.js";
7
- import { enumLabel as l } from "./WorkItemControls.js";
3
+ import { ConfirmButton as r, ErrorLine as i } from "./ConfirmButton.js";
4
+ import { ProjectSelect as a, WorkItemSearchSelect as o } from "./Pickers.js";
5
+ import { enumLabel as s } from "./WorkItemControls.js";
6
+ import { detailPath as c } from "../utils/rowNavigation.js";
7
+ import { parseIntField as l } from "../utils/formValidation.js";
8
8
  import { useState as u } from "react";
9
9
  import { BarChart3 as d, Pencil as f, ThumbsUp as p, Trash2 as m } from "lucide-react";
10
10
  import { gql as h } from "@apollo/client";
@@ -60,7 +60,7 @@ var O = [
60
60
  awaitRefetchQueries: !0
61
61
  };
62
62
  function F({ featureId: e, voted: t }) {
63
- let [r, i] = g(A, P), [o, s] = g(j, P), [c, l] = u(null), d = i.loading || s.loading, f = async () => {
63
+ let [r, a] = g(A, P), [o, s] = g(j, P), [c, l] = u(null), d = a.loading || s.loading, f = async () => {
64
64
  l(null);
65
65
  try {
66
66
  await n((t ? o : r)({ variables: { id: e } }));
@@ -78,18 +78,18 @@ function F({ featureId: e, voted: t }) {
78
78
  disabled: d,
79
79
  onClick: () => void f(),
80
80
  children: [/* @__PURE__ */ _(p, { className: "mr-1 h-4 w-4" }), t ? "Voted" : "Vote"]
81
- }), c && /* @__PURE__ */ _(a, { message: c })]
81
+ }), c && /* @__PURE__ */ _(i, { message: c })]
82
82
  });
83
83
  }
84
- function I({ feature: o }) {
85
- let s = e(), [c, f] = g(M, P), [p, h] = g(N, {
84
+ function I({ feature: a }) {
85
+ let o = e(), [l, f] = g(M, P), [p, h] = g(N, {
86
86
  refetchQueries: k.filter((e) => e !== "GetFeatureRequest"),
87
87
  context: t
88
- }), [b, x] = u(null), S = f.loading || h.loading, C = O.includes(o.status) ? O : [o.status, ...O], w = async (e) => {
88
+ }), [b, x] = u(null), S = f.loading || h.loading, C = O.includes(a.status) ? O : [a.status, ...O], w = async (e) => {
89
89
  x(null);
90
90
  try {
91
- await n(c({ variables: {
92
- id: o.id,
91
+ await n(l({ variables: {
92
+ id: a.id,
93
93
  input: { status: e }
94
94
  } }));
95
95
  } catch (e) {
@@ -98,7 +98,7 @@ function I({ feature: o }) {
98
98
  }, T = async () => {
99
99
  x(null);
100
100
  try {
101
- await n(p({ variables: { id: o.id } })), s("/products/features-page");
101
+ await n(p({ variables: { id: a.id } })), o("/products/features-page");
102
102
  } catch (e) {
103
103
  x(e instanceof Error ? e.message : "The request could not be deleted.");
104
104
  }
@@ -112,29 +112,29 @@ function I({ feature: o }) {
112
112
  "aria-label": "Status",
113
113
  "data-testid": "feature-status",
114
114
  className: "rounded-md border border-input bg-background px-2 py-1 text-sm disabled:opacity-60",
115
- value: o.status,
115
+ value: a.status,
116
116
  disabled: S,
117
117
  onChange: (e) => {
118
- e.target.value !== o.status && w(e.target.value);
118
+ e.target.value !== a.status && w(e.target.value);
119
119
  },
120
120
  children: C.map((e) => /* @__PURE__ */ _("option", {
121
121
  value: e,
122
- children: l(e)
122
+ children: s(e)
123
123
  }, e))
124
124
  }),
125
- /* @__PURE__ */ _(L, { feature: o }),
125
+ /* @__PURE__ */ _(L, { feature: a }),
126
126
  /* @__PURE__ */ v(y, {
127
127
  size: "sm",
128
128
  variant: "outline",
129
129
  "data-testid": "feature-analytics",
130
- onClick: () => s(r("/products/feature-analytics-page", o.id)),
130
+ onClick: () => o(c("/products/feature-analytics-page", a.id)),
131
131
  children: [/* @__PURE__ */ _(d, { className: "mr-1 h-4 w-4" }), "Analytics"]
132
132
  }),
133
- /* @__PURE__ */ _(i, {
133
+ /* @__PURE__ */ _(r, {
134
134
  label: "Delete",
135
135
  variant: "outline",
136
136
  icon: /* @__PURE__ */ _(m, { className: "mr-1 h-4 w-4" }),
137
- title: `Delete "${o.title}"?`,
137
+ title: `Delete "${a.title}"?`,
138
138
  description: "The request and its votes are deleted. This cannot be undone here.",
139
139
  confirmLabel: "Delete request",
140
140
  destructive: !0,
@@ -142,7 +142,7 @@ function I({ feature: o }) {
142
142
  onConfirm: () => void T()
143
143
  })
144
144
  ]
145
- }), b && /* @__PURE__ */ _(a, { message: b })]
145
+ }), b && /* @__PURE__ */ _(i, { message: b })]
146
146
  });
147
147
  }
148
148
  function L({ feature: e }) {
@@ -153,35 +153,35 @@ function L({ feature: e }) {
153
153
  effortEstimate: e.effortEstimate ?? "",
154
154
  projectId: e.projectId ?? "",
155
155
  workItemId: e.workItemId ?? ""
156
- }, [r, i] = u(!1), [l, d] = u(t), [p, m] = u(null), [h, O] = g(M, P), k = c(l.businessValue, {
156
+ }, [r, s] = u(!1), [c, d] = u(t), [p, m] = u(null), [h, O] = g(M, P), k = l(c.businessValue, {
157
157
  min: 0,
158
158
  max: 100
159
- }), A = l.title.trim() !== "" && !k.invalid && !O.loading, j = async () => {
159
+ }), A = c.title.trim() !== "" && !k.invalid && !O.loading, j = async () => {
160
160
  m(null);
161
- let r = (e) => e.trim() ? e.trim() : null, a = {
162
- title: l.title.trim(),
163
- description: r(l.description),
161
+ let r = (e) => e.trim() ? e.trim() : null, i = {
162
+ title: c.title.trim(),
163
+ description: r(c.description),
164
164
  businessValue: k.value ?? null,
165
- effortEstimate: r(l.effortEstimate),
166
- projectId: l.projectId || null,
167
- workItemId: l.workItemId || null
168
- }, o = {
165
+ effortEstimate: r(c.effortEstimate),
166
+ projectId: c.projectId || null,
167
+ workItemId: c.workItemId || null
168
+ }, a = {
169
169
  title: t.title,
170
170
  description: r(t.description),
171
171
  businessValue: t.businessValue === "" ? null : Number(t.businessValue),
172
172
  effortEstimate: r(t.effortEstimate),
173
173
  projectId: t.projectId || null,
174
174
  workItemId: t.workItemId || null
175
- }, s = Object.fromEntries(Object.entries(a).filter(([e, t]) => t !== o[e]));
176
- if (Object.keys(s).length === 0) {
177
- i(!1);
175
+ }, o = Object.fromEntries(Object.entries(i).filter(([e, t]) => t !== a[e]));
176
+ if (Object.keys(o).length === 0) {
177
+ s(!1);
178
178
  return;
179
179
  }
180
180
  try {
181
181
  await n(h({ variables: {
182
182
  id: e.id,
183
- input: s
184
- } })), i(!1);
183
+ input: o
184
+ } })), s(!1);
185
185
  } catch (e) {
186
186
  m(e instanceof Error ? e.message : "The request could not be saved.");
187
187
  }
@@ -189,7 +189,7 @@ function L({ feature: e }) {
189
189
  return /* @__PURE__ */ v(x, {
190
190
  open: r,
191
191
  onOpenChange: (e) => {
192
- i(e), e ? d(t) : m(null);
192
+ s(e), e ? d(t) : m(null);
193
193
  },
194
194
  children: [/* @__PURE__ */ _(D, {
195
195
  asChild: !0,
@@ -213,9 +213,9 @@ function L({ feature: e }) {
213
213
  }), /* @__PURE__ */ _(b, {
214
214
  id: "feature-edit-title",
215
215
  className: "mt-1",
216
- value: l.title,
216
+ value: c.title,
217
217
  onChange: (e) => d({
218
- ...l,
218
+ ...c,
219
219
  title: e.target.value
220
220
  })
221
221
  })] }),
@@ -226,9 +226,9 @@ function L({ feature: e }) {
226
226
  }), /* @__PURE__ */ _("textarea", {
227
227
  id: "feature-edit-description",
228
228
  className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[72px]",
229
- value: l.description,
229
+ value: c.description,
230
230
  onChange: (e) => d({
231
- ...l,
231
+ ...c,
232
232
  description: e.target.value
233
233
  })
234
234
  })] }),
@@ -244,10 +244,10 @@ function L({ feature: e }) {
244
244
  min: 0,
245
245
  max: 100,
246
246
  className: "mt-1",
247
- value: l.businessValue,
247
+ value: c.businessValue,
248
248
  "aria-invalid": k.invalid,
249
249
  onChange: (e) => d({
250
- ...l,
250
+ ...c,
251
251
  businessValue: e.target.value
252
252
  })
253
253
  })] }), /* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("label", {
@@ -258,26 +258,26 @@ function L({ feature: e }) {
258
258
  id: "feature-edit-effort",
259
259
  className: "mt-1",
260
260
  placeholder: "e.g. M",
261
- value: l.effortEstimate,
261
+ value: c.effortEstimate,
262
262
  onChange: (e) => d({
263
- ...l,
263
+ ...c,
264
264
  effortEstimate: e.target.value
265
265
  })
266
266
  })] })]
267
267
  }),
268
- k.invalid && /* @__PURE__ */ _(a, { message: "Business value is a whole number from 0 to 100." }),
268
+ k.invalid && /* @__PURE__ */ _(i, { message: "Business value is a whole number from 0 to 100." }),
269
269
  /* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("label", {
270
270
  htmlFor: "feature-edit-project",
271
271
  className: N,
272
272
  children: "Project"
273
273
  }), /* @__PURE__ */ _("div", {
274
274
  className: "mt-1",
275
- children: /* @__PURE__ */ _(o, {
275
+ children: /* @__PURE__ */ _(a, {
276
276
  id: "feature-edit-project",
277
- value: l.projectId,
277
+ value: c.projectId,
278
278
  noneLabel: "No project",
279
279
  onChange: (e) => d({
280
- ...l,
280
+ ...c,
281
281
  projectId: e,
282
282
  workItemId: ""
283
283
  })
@@ -289,22 +289,22 @@ function L({ feature: e }) {
289
289
  children: "Delivered by work item"
290
290
  }), /* @__PURE__ */ _("div", {
291
291
  className: "mt-1",
292
- children: /* @__PURE__ */ _(s, {
292
+ children: /* @__PURE__ */ _(o, {
293
293
  id: "feature-edit-workitem",
294
- projectId: l.projectId || void 0,
295
- value: l.workItemId,
294
+ projectId: c.projectId || void 0,
295
+ value: c.workItemId,
296
296
  onChange: (e) => d({
297
- ...l,
297
+ ...c,
298
298
  workItemId: e
299
299
  })
300
300
  })
301
301
  })] }),
302
- p && /* @__PURE__ */ _(a, { message: p })
302
+ p && /* @__PURE__ */ _(i, { message: p })
303
303
  ]
304
304
  }),
305
305
  /* @__PURE__ */ v(w, { children: [/* @__PURE__ */ _(y, {
306
306
  variant: "outline",
307
- onClick: () => i(!1),
307
+ onClick: () => s(!1),
308
308
  children: "Cancel"
309
309
  }), /* @__PURE__ */ _(y, {
310
310
  onClick: () => void j(),