@burdenoff/microfe-planmagnet 2026.928.4 → 2026.928.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/dist/planmagnet/PlanMagnetRoot.d.ts.map +1 -1
  2. package/dist/planmagnet/PlanMagnetRoot.js +117 -93
  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 +156 -76
  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/PortfolioControls.js +7 -7
  58. package/dist/planmagnet/controls/ProgramControls.js +19 -19
  59. package/dist/planmagnet/controls/ProjectControls.d.ts.map +1 -1
  60. package/dist/planmagnet/controls/ProjectControls.js +54 -47
  61. package/dist/planmagnet/controls/ProjectControls.js.map +1 -1
  62. package/dist/planmagnet/controls/ReleaseControls.js +7 -7
  63. package/dist/planmagnet/controls/RiskControls.d.ts +27 -0
  64. package/dist/planmagnet/controls/RiskControls.d.ts.map +1 -0
  65. package/dist/planmagnet/controls/RiskControls.js +346 -0
  66. package/dist/planmagnet/controls/RiskControls.js.map +1 -0
  67. package/dist/planmagnet/controls/TemplateControls.d.ts +15 -0
  68. package/dist/planmagnet/controls/TemplateControls.d.ts.map +1 -0
  69. package/dist/planmagnet/controls/TemplateControls.js +55 -0
  70. package/dist/planmagnet/controls/TemplateControls.js.map +1 -0
  71. package/dist/planmagnet/controls/WorkItemControls.js +1 -1
  72. package/dist/planmagnet/create/CreateDialogs.d.ts +20 -0
  73. package/dist/planmagnet/create/CreateDialogs.d.ts.map +1 -1
  74. package/dist/planmagnet/create/CreateDialogs.js +455 -116
  75. package/dist/planmagnet/create/CreateDialogs.js.map +1 -1
  76. package/dist/planmagnet/dependency/DependencyPanel.d.ts +6 -0
  77. package/dist/planmagnet/dependency/DependencyPanel.d.ts.map +1 -0
  78. package/dist/planmagnet/dependency/DependencyPanel.js +310 -0
  79. package/dist/planmagnet/dependency/DependencyPanel.js.map +1 -0
  80. package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.d.ts +2 -0
  81. package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.d.ts.map +1 -0
  82. package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.js +171 -0
  83. package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.js.map +1 -0
  84. package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.d.ts +2 -0
  85. package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.d.ts.map +1 -0
  86. package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.js +232 -0
  87. package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.js.map +1 -0
  88. package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.d.ts +2 -0
  89. package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.d.ts.map +1 -0
  90. package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.js +93 -0
  91. package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.js.map +1 -0
  92. package/dist/planmagnet/pages/PortfoliosEditPortfolioPagePage.js +5 -5
  93. package/dist/planmagnet/pages/PortfoliosPortfolioDetailPagePage.js +9 -9
  94. package/dist/planmagnet/pages/PortfoliosPortfoliosPagePage.js +6 -6
  95. package/dist/planmagnet/pages/ProgramsCreateProgramPagePage.js +4 -4
  96. package/dist/planmagnet/pages/ProgramsEditProgramPagePage.js +6 -6
  97. package/dist/planmagnet/pages/ProgramsProgramsPagePage.js +5 -5
  98. package/dist/planmagnet/pages/ProjectsBudgetDetailPagePage.d.ts +2 -0
  99. package/dist/planmagnet/pages/ProjectsBudgetDetailPagePage.d.ts.map +1 -0
  100. package/dist/planmagnet/pages/ProjectsBudgetDetailPagePage.js +315 -0
  101. package/dist/planmagnet/pages/ProjectsBudgetDetailPagePage.js.map +1 -0
  102. package/dist/planmagnet/pages/ProjectsBudgetsPagePage.d.ts +2 -0
  103. package/dist/planmagnet/pages/ProjectsBudgetsPagePage.d.ts.map +1 -0
  104. package/dist/planmagnet/pages/ProjectsBudgetsPagePage.js +186 -0
  105. package/dist/planmagnet/pages/ProjectsBudgetsPagePage.js.map +1 -0
  106. package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.d.ts +2 -0
  107. package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.d.ts.map +1 -0
  108. package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.js +164 -0
  109. package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.js.map +1 -0
  110. package/dist/planmagnet/pages/ProjectsCustomFieldsPagePage.d.ts +2 -0
  111. package/dist/planmagnet/pages/ProjectsCustomFieldsPagePage.d.ts.map +1 -0
  112. package/dist/planmagnet/pages/ProjectsCustomFieldsPagePage.js +348 -0
  113. package/dist/planmagnet/pages/ProjectsCustomFieldsPagePage.js.map +1 -0
  114. package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js +10 -10
  115. package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.js +4 -4
  116. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js +4 -4
  117. package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.js +6 -6
  118. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.d.ts.map +1 -1
  119. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js +319 -203
  120. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js.map +1 -1
  121. package/dist/planmagnet/pages/ProjectsProjectsPagePage.d.ts.map +1 -1
  122. package/dist/planmagnet/pages/ProjectsProjectsPagePage.js +81 -72
  123. package/dist/planmagnet/pages/ProjectsProjectsPagePage.js.map +1 -1
  124. package/dist/planmagnet/pages/RisksRiskDetailPagePage.d.ts +2 -0
  125. package/dist/planmagnet/pages/RisksRiskDetailPagePage.d.ts.map +1 -0
  126. package/dist/planmagnet/pages/RisksRiskDetailPagePage.js +278 -0
  127. package/dist/planmagnet/pages/RisksRiskDetailPagePage.js.map +1 -0
  128. package/dist/planmagnet/pages/RisksRiskRegisterPagePage.d.ts +2 -0
  129. package/dist/planmagnet/pages/RisksRiskRegisterPagePage.d.ts.map +1 -0
  130. package/dist/planmagnet/pages/RisksRiskRegisterPagePage.js +191 -0
  131. package/dist/planmagnet/pages/RisksRiskRegisterPagePage.js.map +1 -0
  132. package/dist/planmagnet/pages/TasksCreateTaskPagePage.js +5 -5
  133. package/dist/planmagnet/pages/TasksEditTaskPagePage.js +4 -4
  134. package/dist/planmagnet/pages/TasksTaskDetailPagePage.d.ts.map +1 -1
  135. package/dist/planmagnet/pages/TasksTaskDetailPagePage.js +161 -137
  136. package/dist/planmagnet/pages/TasksTaskDetailPagePage.js.map +1 -1
  137. package/dist/planmagnet/pages/TasksTasksPagePage.d.ts.map +1 -1
  138. package/dist/planmagnet/pages/TasksTasksPagePage.js +124 -113
  139. package/dist/planmagnet/pages/TasksTasksPagePage.js.map +1 -1
  140. package/dist/planmagnet/pages/TasksTimeEntriesPagePage.d.ts +2 -0
  141. package/dist/planmagnet/pages/TasksTimeEntriesPagePage.d.ts.map +1 -0
  142. package/dist/planmagnet/pages/TasksTimeEntriesPagePage.js +263 -0
  143. package/dist/planmagnet/pages/TasksTimeEntriesPagePage.js.map +1 -0
  144. package/dist/planmagnet/pages/TasksTimesheetDetailPagePage.d.ts +2 -0
  145. package/dist/planmagnet/pages/TasksTimesheetDetailPagePage.d.ts.map +1 -0
  146. package/dist/planmagnet/pages/TasksTimesheetDetailPagePage.js +254 -0
  147. package/dist/planmagnet/pages/TasksTimesheetDetailPagePage.js.map +1 -0
  148. package/dist/planmagnet/pages/TasksTimesheetsPagePage.d.ts +2 -0
  149. package/dist/planmagnet/pages/TasksTimesheetsPagePage.d.ts.map +1 -0
  150. package/dist/planmagnet/pages/TasksTimesheetsPagePage.js +165 -0
  151. package/dist/planmagnet/pages/TasksTimesheetsPagePage.js.map +1 -0
  152. package/dist/planmagnet/pages/TemplatesEditTemplatePagePage.d.ts +2 -0
  153. package/dist/planmagnet/pages/TemplatesEditTemplatePagePage.d.ts.map +1 -0
  154. package/dist/planmagnet/pages/TemplatesEditTemplatePagePage.js +316 -0
  155. package/dist/planmagnet/pages/TemplatesEditTemplatePagePage.js.map +1 -0
  156. package/dist/planmagnet/pages/TemplatesTemplatesPagePage.d.ts +2 -0
  157. package/dist/planmagnet/pages/TemplatesTemplatesPagePage.d.ts.map +1 -0
  158. package/dist/planmagnet/pages/TemplatesTemplatesPagePage.js +208 -0
  159. package/dist/planmagnet/pages/TemplatesTemplatesPagePage.js.map +1 -0
  160. package/dist/planmagnet/pages/analytics/DeliveryHealthCards.d.ts +0 -5
  161. package/dist/planmagnet/pages/analytics/DeliveryHealthCards.d.ts.map +1 -1
  162. package/dist/planmagnet/pages/analytics/DeliveryHealthCards.js +47 -89
  163. package/dist/planmagnet/pages/analytics/DeliveryHealthCards.js.map +1 -1
  164. package/dist/planmagnet/roadmaps/RoadmapControls.js +24 -24
  165. package/dist/planmagnet/time/TaskTimePanel.d.ts +7 -0
  166. package/dist/planmagnet/time/TaskTimePanel.d.ts.map +1 -0
  167. package/dist/planmagnet/time/TaskTimePanel.js +104 -0
  168. package/dist/planmagnet/time/TaskTimePanel.js.map +1 -0
  169. package/dist/planmagnet/time/TimeEntryControls.d.ts +37 -0
  170. package/dist/planmagnet/time/TimeEntryControls.d.ts.map +1 -0
  171. package/dist/planmagnet/time/TimeEntryControls.js +338 -0
  172. package/dist/planmagnet/time/TimeEntryControls.js.map +1 -0
  173. package/dist/planmagnet/time/TimesheetControls.d.ts +18 -0
  174. package/dist/planmagnet/time/TimesheetControls.d.ts.map +1 -0
  175. package/dist/planmagnet/time/TimesheetControls.js +244 -0
  176. package/dist/planmagnet/time/TimesheetControls.js.map +1 -0
  177. package/dist/planmagnet/time/timeShared.d.ts +29 -0
  178. package/dist/planmagnet/time/timeShared.d.ts.map +1 -0
  179. package/dist/planmagnet/time/timeShared.js +34 -0
  180. package/dist/planmagnet/time/timeShared.js.map +1 -0
  181. package/dist/planmagnet/utils/rowNavigation.js +5 -2
  182. package/dist/planmagnet/utils/rowNavigation.js.map +1 -1
  183. package/package.json +1 -1
@@ -0,0 +1,348 @@
1
+ import { usePlanMagnet as e, usePlanMagnetNavigate as t } from "../providers/PlanMagnetProvider.js";
2
+ import { throwOnError as n } from "../utils/mutationResult.js";
3
+ import { ConfirmButton as r, ErrorLine as i } from "../controls/ConfirmButton.js";
4
+ import { parseIntField as a } from "../utils/formValidation.js";
5
+ import { CREATE_CUSTOM_FIELD_DEFINITION as o, CUSTOM_FIELD_QUERIES as s, CUSTOM_FIELD_TYPES as c, DELETE_CUSTOM_FIELD_DEFINITION as l, OPTION_TYPES as u, PROJECT_CUSTOM_FIELD_DEFINITIONS as d, UPDATE_CUSTOM_FIELD_DEFINITION as f, customFieldTypeLabel as p, optionStrings as m, parseOptionLines as h } from "../controls/CustomFieldControls.js";
6
+ import { useState as g } from "react";
7
+ import { ArrowLeft as _, ListPlus as v, Loader2 as y, Pencil as b, Trash2 as x } from "lucide-react";
8
+ import { useParams as S } from "react-router";
9
+ import { gql as C } from "@apollo/client";
10
+ import { useMutation as w, useQuery as T } from "@apollo/client/react";
11
+ import { jsx as E, jsxs as D } from "react/jsx-runtime";
12
+ import { Button as O, Card as k, CardContent as A, CardHeader as j, CardTitle as M, Input as N, ResponsiveDialog as P, ResponsiveDialogContent as F, ResponsiveDialogDescription as I, ResponsiveDialogFooter as L, ResponsiveDialogHeader as R, ResponsiveDialogTitle as z, ResponsiveDialogTrigger as B } from "@burdenoff/fe-libs/ui";
13
+ //#region src/planmagnet/pages/ProjectsCustomFieldsPagePage.tsx
14
+ var V = C`
15
+ query CustomFieldsProjectName($id: ID!) {
16
+ planmagnetProject(id: $id) {
17
+ id
18
+ name
19
+ }
20
+ }
21
+ `, H = () => ({
22
+ name: "",
23
+ description: "",
24
+ fieldType: "TEXT",
25
+ isRequired: !1,
26
+ optionsText: "",
27
+ sortOrderText: ""
28
+ }), U = (e) => ({
29
+ name: e.name,
30
+ description: e.description ?? "",
31
+ fieldType: e.fieldType,
32
+ isRequired: e.isRequired,
33
+ optionsText: m(e.options).join("\n"),
34
+ sortOrderText: String(e.sortOrder ?? 0)
35
+ });
36
+ function W() {
37
+ let { workspaceId: n } = e(), r = t(), i = S().id ?? "", { data: a, loading: o, error: s } = T(d, {
38
+ variables: {
39
+ workspaceId: n ?? "",
40
+ projectId: i
41
+ },
42
+ skip: !n || !i
43
+ }), { data: c } = T(V, {
44
+ variables: { id: i },
45
+ skip: !i
46
+ });
47
+ if (!i) return /* @__PURE__ */ E("div", {
48
+ className: "p-6 text-muted-foreground",
49
+ children: "No project selected."
50
+ });
51
+ if (o && !a) return /* @__PURE__ */ E("div", {
52
+ className: "flex items-center justify-center p-12",
53
+ children: /* @__PURE__ */ E(y, { className: "h-8 w-8 animate-spin text-muted-foreground" })
54
+ });
55
+ if (s) return /* @__PURE__ */ D("div", {
56
+ className: "p-6 text-red-500",
57
+ children: ["Error: ", s.message]
58
+ });
59
+ let l = [...a?.planmagnetCustomFieldDefinitions.items ?? []].sort((e, t) => e.sortOrder - t.sortOrder || e.name.localeCompare(t.name));
60
+ return /* @__PURE__ */ D("div", {
61
+ className: "space-y-6 p-6",
62
+ children: [/* @__PURE__ */ D("div", {
63
+ className: "flex items-start gap-3",
64
+ children: [/* @__PURE__ */ E(O, {
65
+ variant: "ghost",
66
+ size: "icon",
67
+ "aria-label": "Back to the project",
68
+ onClick: () => r(`/projects/project-detail-page/${i}`),
69
+ children: /* @__PURE__ */ E(_, { className: "h-4 w-4" })
70
+ }), /* @__PURE__ */ D("div", { children: [/* @__PURE__ */ D("h1", {
71
+ className: "text-2xl font-semibold",
72
+ children: ["Custom Fields", c?.planmagnetProject ? ` — ${c.planmagnetProject.name}` : ""]
73
+ }), /* @__PURE__ */ E("p", {
74
+ className: "text-sm text-muted-foreground",
75
+ children: "Extra fields this project's tasks can carry. Each task's values are set from its own page."
76
+ })] })]
77
+ }), /* @__PURE__ */ D(k, { children: [/* @__PURE__ */ D(j, {
78
+ className: "flex flex-row items-center justify-between space-y-0",
79
+ children: [/* @__PURE__ */ D(M, { children: [
80
+ "Fields (",
81
+ l.length,
82
+ ")"
83
+ ] }), /* @__PURE__ */ E(K, { projectId: i })]
84
+ }), /* @__PURE__ */ E(A, { children: l.length === 0 ? /* @__PURE__ */ E("p", {
85
+ className: "py-4 text-center text-sm text-muted-foreground",
86
+ "data-testid": "custom-fields-empty",
87
+ children: "No custom fields yet. Add one to start collecting extra data on this project's tasks."
88
+ }) : /* @__PURE__ */ D("table", {
89
+ className: "w-full text-sm",
90
+ "data-testid": "custom-field-definitions",
91
+ children: [/* @__PURE__ */ E("thead", { children: /* @__PURE__ */ D("tr", {
92
+ className: "text-left text-muted-foreground",
93
+ children: [
94
+ /* @__PURE__ */ E("th", {
95
+ className: "py-1 pr-3 font-medium",
96
+ children: "Name"
97
+ }),
98
+ /* @__PURE__ */ E("th", {
99
+ className: "py-1 pr-3 font-medium",
100
+ children: "Type"
101
+ }),
102
+ /* @__PURE__ */ E("th", {
103
+ className: "py-1 pr-3 font-medium",
104
+ children: "Required"
105
+ }),
106
+ /* @__PURE__ */ E("th", {
107
+ className: "py-1 pr-3 font-medium",
108
+ children: "Options"
109
+ }),
110
+ /* @__PURE__ */ E("th", {
111
+ className: "py-1 font-medium",
112
+ children: "Actions"
113
+ })
114
+ ]
115
+ }) }), /* @__PURE__ */ E("tbody", { children: l.map((e) => /* @__PURE__ */ D("tr", {
116
+ className: "border-t",
117
+ "data-testid": `custom-field-row-${e.id}`,
118
+ children: [
119
+ /* @__PURE__ */ D("td", {
120
+ className: "py-2 pr-3",
121
+ children: [/* @__PURE__ */ E("p", {
122
+ className: "font-medium",
123
+ children: e.name
124
+ }), e.description && /* @__PURE__ */ E("p", {
125
+ className: "text-xs text-muted-foreground",
126
+ children: e.description
127
+ })]
128
+ }),
129
+ /* @__PURE__ */ E("td", {
130
+ className: "py-2 pr-3",
131
+ children: p(e.fieldType)
132
+ }),
133
+ /* @__PURE__ */ E("td", {
134
+ className: "py-2 pr-3",
135
+ children: e.isRequired ? "Yes" : "No"
136
+ }),
137
+ /* @__PURE__ */ E("td", {
138
+ className: "py-2 pr-3 text-xs text-muted-foreground",
139
+ children: u.has(e.fieldType) && m(e.options).join(", ") || "—"
140
+ }),
141
+ /* @__PURE__ */ E("td", {
142
+ className: "py-2",
143
+ children: /* @__PURE__ */ D("div", {
144
+ className: "flex gap-2",
145
+ children: [/* @__PURE__ */ E(K, {
146
+ projectId: i,
147
+ definition: e
148
+ }), /* @__PURE__ */ E(G, { definition: e })]
149
+ })
150
+ })
151
+ ]
152
+ }, e.id)) })]
153
+ }) })] })]
154
+ });
155
+ }
156
+ function G({ definition: e }) {
157
+ let [t, a] = w(l, {
158
+ refetchQueries: s,
159
+ awaitRefetchQueries: !0
160
+ }), [o, c] = g(null), u = async () => {
161
+ c(null);
162
+ try {
163
+ await n(t({ variables: { id: e.id } }));
164
+ } catch (e) {
165
+ c(e instanceof Error ? e.message : "The field could not be deleted.");
166
+ }
167
+ };
168
+ return /* @__PURE__ */ D("div", {
169
+ className: "flex flex-col items-start gap-1",
170
+ children: [/* @__PURE__ */ E(r, {
171
+ label: "",
172
+ ariaLabel: `Delete ${e.name}`,
173
+ variant: "outline",
174
+ icon: /* @__PURE__ */ E(x, { className: "h-4 w-4" }),
175
+ title: `Delete "${e.name}"?`,
176
+ description: "Its stored values on every task are deleted too. This cannot be undone here.",
177
+ confirmLabel: "Delete field",
178
+ destructive: !0,
179
+ disabled: a.loading,
180
+ onConfirm: () => void u()
181
+ }), o && /* @__PURE__ */ E(i, { message: o })]
182
+ });
183
+ }
184
+ function K({ projectId: e, definition: t }) {
185
+ let r = t !== void 0, l = t ? U(t) : H(), [d, m] = g(!1), [_, y] = g(l), [x, S] = g(null), [C, T] = w(o, {
186
+ refetchQueries: s,
187
+ awaitRefetchQueries: !0
188
+ }), [k, A] = w(f, {
189
+ refetchQueries: s,
190
+ awaitRefetchQueries: !0
191
+ }), j = T.loading || A.loading, M = a(_.sortOrderText, { min: 0 }), V = u.has(_.fieldType), W = V ? h(_.optionsText) : [], G = _.name.trim() === "" || M.invalid || V && W.length === 0, K = async () => {
192
+ S(null);
193
+ let i = {
194
+ name: _.name.trim(),
195
+ description: _.description.trim() || null,
196
+ fieldType: _.fieldType,
197
+ isRequired: _.isRequired,
198
+ options: V ? W : null,
199
+ sortOrder: M.value ?? 0
200
+ };
201
+ try {
202
+ r ? await n(k({ variables: {
203
+ id: t.id,
204
+ input: i
205
+ } })) : await n(C({ variables: { input: {
206
+ projectId: e,
207
+ ...i
208
+ } } })), m(!1);
209
+ } catch (e) {
210
+ S(e instanceof Error ? e.message : "The field could not be saved.");
211
+ }
212
+ }, q = r ? `custom-field-${t.id}` : "new-custom-field";
213
+ return /* @__PURE__ */ D(P, {
214
+ open: d,
215
+ onOpenChange: (e) => {
216
+ m(e), e && (y(t ? U(t) : H()), S(null));
217
+ },
218
+ children: [/* @__PURE__ */ E(B, {
219
+ asChild: !0,
220
+ children: r ? /* @__PURE__ */ E(O, {
221
+ size: "icon",
222
+ variant: "ghost",
223
+ "aria-label": `Edit ${t.name}`,
224
+ children: /* @__PURE__ */ E(b, { className: "h-4 w-4" })
225
+ }) : /* @__PURE__ */ D(O, {
226
+ size: "sm",
227
+ "data-testid": "custom-field-add",
228
+ children: [/* @__PURE__ */ E(v, { className: "mr-1 h-4 w-4" }), "Add field"]
229
+ })
230
+ }), /* @__PURE__ */ D(F, {
231
+ className: "max-w-lg",
232
+ children: [
233
+ /* @__PURE__ */ D(R, { children: [/* @__PURE__ */ E(z, { children: r ? `Edit ${t.name}` : "Add field" }), /* @__PURE__ */ E(I, { children: "Tasks in this project will be able to show and edit this value." })] }),
234
+ /* @__PURE__ */ D("div", {
235
+ className: "space-y-3",
236
+ children: [
237
+ /* @__PURE__ */ D("div", { children: [/* @__PURE__ */ E("label", {
238
+ htmlFor: `${q}-name`,
239
+ className: "text-sm font-medium",
240
+ children: "Name"
241
+ }), /* @__PURE__ */ E(N, {
242
+ id: `${q}-name`,
243
+ className: "mt-1",
244
+ value: _.name,
245
+ onChange: (e) => y({
246
+ ..._,
247
+ name: e.target.value
248
+ })
249
+ })] }),
250
+ /* @__PURE__ */ D("div", { children: [/* @__PURE__ */ E("label", {
251
+ htmlFor: `${q}-type`,
252
+ className: "text-sm font-medium",
253
+ children: "Type"
254
+ }), /* @__PURE__ */ E("select", {
255
+ id: `${q}-type`,
256
+ className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm",
257
+ value: _.fieldType,
258
+ onChange: (e) => y({
259
+ ..._,
260
+ fieldType: e.target.value
261
+ }),
262
+ children: c.map((e) => /* @__PURE__ */ E("option", {
263
+ value: e,
264
+ children: p(e)
265
+ }, e))
266
+ })] }),
267
+ V && /* @__PURE__ */ D("div", { children: [
268
+ /* @__PURE__ */ E("label", {
269
+ htmlFor: `${q}-options`,
270
+ className: "text-sm font-medium",
271
+ children: "Options (one per line)"
272
+ }),
273
+ /* @__PURE__ */ E("textarea", {
274
+ id: `${q}-options`,
275
+ className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[88px]",
276
+ value: _.optionsText,
277
+ onChange: (e) => y({
278
+ ..._,
279
+ optionsText: e.target.value
280
+ })
281
+ }),
282
+ W.length === 0 && /* @__PURE__ */ E(i, { message: "Add at least one option." })
283
+ ] }),
284
+ /* @__PURE__ */ D("div", { children: [/* @__PURE__ */ E("label", {
285
+ htmlFor: `${q}-description`,
286
+ className: "text-sm font-medium",
287
+ children: "Description (optional)"
288
+ }), /* @__PURE__ */ E("textarea", {
289
+ id: `${q}-description`,
290
+ className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[60px]",
291
+ value: _.description,
292
+ onChange: (e) => y({
293
+ ..._,
294
+ description: e.target.value
295
+ })
296
+ })] }),
297
+ /* @__PURE__ */ D("div", {
298
+ className: "flex items-end gap-4",
299
+ children: [/* @__PURE__ */ D("div", { children: [/* @__PURE__ */ E("label", {
300
+ htmlFor: `${q}-sort`,
301
+ className: "text-sm font-medium",
302
+ children: "Order (optional)"
303
+ }), /* @__PURE__ */ E(N, {
304
+ id: `${q}-sort`,
305
+ type: "number",
306
+ min: 0,
307
+ step: 1,
308
+ className: "mt-1 w-24",
309
+ value: _.sortOrderText,
310
+ onChange: (e) => y({
311
+ ..._,
312
+ sortOrderText: e.target.value
313
+ })
314
+ })] }), /* @__PURE__ */ D("label", {
315
+ className: "flex items-center gap-2 pb-2 text-sm",
316
+ children: [/* @__PURE__ */ E("input", {
317
+ type: "checkbox",
318
+ checked: _.isRequired,
319
+ onChange: (e) => y({
320
+ ..._,
321
+ isRequired: e.target.checked
322
+ })
323
+ }), "Required"]
324
+ })]
325
+ }),
326
+ M.invalid && /* @__PURE__ */ E(i, { message: "Order must be a whole number, 0 or more." }),
327
+ _.name.trim() === "" && /* @__PURE__ */ E(i, { message: "Give the field a name." }),
328
+ x && /* @__PURE__ */ E(i, { message: x })
329
+ ]
330
+ }),
331
+ /* @__PURE__ */ D(L, { children: [/* @__PURE__ */ E(O, {
332
+ variant: "outline",
333
+ onClick: () => m(!1),
334
+ children: "Cancel"
335
+ }), /* @__PURE__ */ E(O, {
336
+ onClick: () => void K(),
337
+ disabled: G || j,
338
+ "data-testid": `${q}-save`,
339
+ children: j ? "Saving…" : r ? "Save" : "Add field"
340
+ })] })
341
+ ]
342
+ })]
343
+ });
344
+ }
345
+ //#endregion
346
+ export { W as ProjectsCustomFieldsPagePage };
347
+
348
+ //# sourceMappingURL=ProjectsCustomFieldsPagePage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProjectsCustomFieldsPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProjectsCustomFieldsPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { useParams } from 'react-router';\nimport {\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Input,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogTrigger,\n} from '@burdenoff/fe-libs/ui';\nimport { ArrowLeft, ListPlus, Loader2, Pencil, Trash2 } from 'lucide-react';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { throwOnError } from '../utils/mutationResult';\nimport { parseIntField } from '../utils/formValidation';\nimport { ConfirmButton, ErrorLine } from '../controls/ConfirmButton';\nimport {\n CUSTOM_FIELD_QUERIES,\n CUSTOM_FIELD_TYPES,\n CREATE_CUSTOM_FIELD_DEFINITION,\n DELETE_CUSTOM_FIELD_DEFINITION,\n OPTION_TYPES,\n PROJECT_CUSTOM_FIELD_DEFINITIONS,\n UPDATE_CUSTOM_FIELD_DEFINITION,\n customFieldTypeLabel,\n optionStrings,\n parseOptionLines,\n type CustomFieldDefinitionSummary,\n} from '../controls/CustomFieldControls';\n\n/**\n * Per-project custom field definitions (BOFF-8047, capability register: Custom fields, `api-only`). The API has\n * created/read/updated/deleted these since 2026-09-23 (BOFF-7839); nothing in the UI reached any of it. Modeled on\n * the project Workflow page: a settings surface reached from the project detail header, not the global sidebar,\n * because it configures one project.\n */\n\nconst PROJECT_NAME = gql`\n query CustomFieldsProjectName($id: ID!) {\n planmagnetProject(id: $id) {\n id\n name\n }\n }\n`;\n\ninterface FormState {\n name: string;\n description: string;\n fieldType: string;\n isRequired: boolean;\n optionsText: string;\n sortOrderText: string;\n}\n\nconst emptyForm = (): FormState => ({\n name: '',\n description: '',\n fieldType: 'TEXT',\n isRequired: false,\n optionsText: '',\n sortOrderText: '',\n});\n\nconst formOf = (def: CustomFieldDefinitionSummary): FormState => ({\n name: def.name,\n description: def.description ?? '',\n fieldType: def.fieldType,\n isRequired: def.isRequired,\n optionsText: optionStrings(def.options).join('\\n'),\n sortOrderText: String(def.sortOrder ?? 0),\n});\n\nexport function ProjectsCustomFieldsPagePage() {\n const { workspaceId } = usePlanMagnet();\n const navigate = usePlanMagnetNavigate();\n const projectId = useParams<{ id: string }>().id ?? '';\n\n const { data, loading, error } = useQuery<{\n planmagnetCustomFieldDefinitions: { items: CustomFieldDefinitionSummary[]; totalCount: number };\n }>(PROJECT_CUSTOM_FIELD_DEFINITIONS, {\n variables: { workspaceId: workspaceId ?? '', projectId },\n skip: !workspaceId || !projectId,\n });\n const { data: project } = useQuery<{ planmagnetProject: { id: string; name: string } | null }>(\n PROJECT_NAME,\n { variables: { id: projectId }, skip: !projectId }\n );\n\n if (!projectId) {\n return <div className=\"p-6 text-muted-foreground\">No project selected.</div>;\n }\n // Only before the first load: a refetch must not blank the page (it unmounts every dialog's own state).\n if (loading && !data) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-muted-foreground\" />\n </div>\n );\n }\n if (error) {\n return <div className=\"p-6 text-red-500\">Error: {error.message}</div>;\n }\n\n const definitions = [...(data?.planmagnetCustomFieldDefinitions.items ?? [])].sort(\n (a, b) => a.sortOrder - b.sortOrder || a.name.localeCompare(b.name)\n );\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-start gap-3\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label=\"Back to the project\"\n onClick={() => navigate(`/projects/project-detail-page/${projectId}`)}\n >\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n <div>\n <h1 className=\"text-2xl font-semibold\">\n Custom Fields{project?.planmagnetProject ? ` — ${project.planmagnetProject.name}` : ''}\n </h1>\n <p className=\"text-sm text-muted-foreground\">\n Extra fields this project&apos;s tasks can carry. Each task&apos;s values are set from\n its own page.\n </p>\n </div>\n </div>\n\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0\">\n <CardTitle>Fields ({definitions.length})</CardTitle>\n <DefinitionDialog projectId={projectId} />\n </CardHeader>\n <CardContent>\n {definitions.length === 0 ? (\n <p\n className=\"py-4 text-center text-sm text-muted-foreground\"\n data-testid=\"custom-fields-empty\"\n >\n No custom fields yet. Add one to start collecting extra data on this project&apos;s\n tasks.\n </p>\n ) : (\n <table className=\"w-full text-sm\" data-testid=\"custom-field-definitions\">\n <thead>\n <tr className=\"text-left text-muted-foreground\">\n <th className=\"py-1 pr-3 font-medium\">Name</th>\n <th className=\"py-1 pr-3 font-medium\">Type</th>\n <th className=\"py-1 pr-3 font-medium\">Required</th>\n <th className=\"py-1 pr-3 font-medium\">Options</th>\n <th className=\"py-1 font-medium\">Actions</th>\n </tr>\n </thead>\n <tbody>\n {definitions.map((def) => (\n <tr key={def.id} className=\"border-t\" data-testid={`custom-field-row-${def.id}`}>\n <td className=\"py-2 pr-3\">\n <p className=\"font-medium\">{def.name}</p>\n {def.description && (\n <p className=\"text-xs text-muted-foreground\">{def.description}</p>\n )}\n </td>\n <td className=\"py-2 pr-3\">{customFieldTypeLabel(def.fieldType)}</td>\n <td className=\"py-2 pr-3\">{def.isRequired ? 'Yes' : 'No'}</td>\n <td className=\"py-2 pr-3 text-xs text-muted-foreground\">\n {OPTION_TYPES.has(def.fieldType)\n ? optionStrings(def.options).join(', ') || '—'\n : '—'}\n </td>\n <td className=\"py-2\">\n <div className=\"flex gap-2\">\n <DefinitionDialog projectId={projectId} definition={def} />\n <DeleteDefinitionButton definition={def} />\n </div>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n )}\n </CardContent>\n </Card>\n </div>\n );\n}\n\nfunction DeleteDefinitionButton({ definition }: { definition: CustomFieldDefinitionSummary }) {\n const [remove, state] = useMutation(DELETE_CUSTOM_FIELD_DEFINITION, {\n refetchQueries: CUSTOM_FIELD_QUERIES,\n awaitRefetchQueries: true,\n });\n const [error, setError] = useState<string | null>(null);\n\n const onDelete = async () => {\n setError(null);\n try {\n await throwOnError(remove({ variables: { id: definition.id } }));\n } catch (e) {\n setError(e instanceof Error ? e.message : 'The field could not be deleted.');\n }\n };\n\n return (\n <div className=\"flex flex-col items-start gap-1\">\n <ConfirmButton\n label=\"\"\n ariaLabel={`Delete ${definition.name}`}\n variant=\"outline\"\n icon={<Trash2 className=\"h-4 w-4\" />}\n title={`Delete \"${definition.name}\"?`}\n description=\"Its stored values on every task are deleted too. This cannot be undone here.\"\n confirmLabel=\"Delete field\"\n destructive\n disabled={state.loading}\n onConfirm={() => void onDelete()}\n />\n {error && <ErrorLine message={error} />}\n </div>\n );\n}\n\n/** Create when `definition` is omitted, edit otherwise. The mutations take no `workspaceId` argument — the\n * gateway derives it from the caller's own session, the same as every other write in this app. */\nfunction DefinitionDialog({\n projectId,\n definition,\n}: {\n projectId: string;\n definition?: CustomFieldDefinitionSummary;\n}) {\n const editing = definition !== undefined;\n const initial = definition ? formOf(definition) : emptyForm();\n const [open, setOpen] = useState(false);\n const [form, setForm] = useState<FormState>(initial);\n const [error, setError] = useState<string | null>(null);\n const [create, createState] = useMutation(CREATE_CUSTOM_FIELD_DEFINITION, {\n refetchQueries: CUSTOM_FIELD_QUERIES,\n awaitRefetchQueries: true,\n });\n const [update, updateState] = useMutation(UPDATE_CUSTOM_FIELD_DEFINITION, {\n refetchQueries: CUSTOM_FIELD_QUERIES,\n awaitRefetchQueries: true,\n });\n const busy = createState.loading || updateState.loading;\n\n const sortOrder = parseIntField(form.sortOrderText, { min: 0 });\n const needsOptions = OPTION_TYPES.has(form.fieldType);\n const options = needsOptions ? parseOptionLines(form.optionsText) : [];\n const invalid =\n form.name.trim() === '' || sortOrder.invalid || (needsOptions && options.length === 0);\n\n const save = async () => {\n setError(null);\n const shared = {\n name: form.name.trim(),\n description: form.description.trim() || null,\n fieldType: form.fieldType,\n isRequired: form.isRequired,\n options: needsOptions ? options : null,\n sortOrder: sortOrder.value ?? 0,\n };\n try {\n if (editing) {\n await throwOnError(update({ variables: { id: definition.id, input: shared } }));\n } else {\n await throwOnError(create({ variables: { input: { projectId, ...shared } } }));\n }\n setOpen(false);\n } catch (e) {\n setError(e instanceof Error ? e.message : 'The field could not be saved.');\n }\n };\n\n const idPrefix = editing ? `custom-field-${definition.id}` : 'new-custom-field';\n\n return (\n <ResponsiveDialog\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (next) {\n setForm(definition ? formOf(definition) : emptyForm());\n setError(null);\n }\n }}\n >\n <ResponsiveDialogTrigger asChild>\n {editing ? (\n <Button size=\"icon\" variant=\"ghost\" aria-label={`Edit ${definition.name}`}>\n <Pencil className=\"h-4 w-4\" />\n </Button>\n ) : (\n <Button size=\"sm\" data-testid=\"custom-field-add\">\n <ListPlus className=\"mr-1 h-4 w-4\" />\n Add field\n </Button>\n )}\n </ResponsiveDialogTrigger>\n <ResponsiveDialogContent className=\"max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>\n {editing ? `Edit ${definition.name}` : 'Add field'}\n </ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Tasks in this project will be able to show and edit this value.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3\">\n <div>\n <label htmlFor={`${idPrefix}-name`} className=\"text-sm font-medium\">\n Name\n </label>\n <Input\n id={`${idPrefix}-name`}\n className=\"mt-1\"\n value={form.name}\n onChange={(e) => setForm({ ...form, name: e.target.value })}\n />\n </div>\n <div>\n <label htmlFor={`${idPrefix}-type`} className=\"text-sm font-medium\">\n Type\n </label>\n <select\n id={`${idPrefix}-type`}\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm\"\n value={form.fieldType}\n onChange={(e) => setForm({ ...form, fieldType: e.target.value })}\n >\n {CUSTOM_FIELD_TYPES.map((t) => (\n <option key={t} value={t}>\n {customFieldTypeLabel(t)}\n </option>\n ))}\n </select>\n </div>\n {needsOptions && (\n <div>\n <label htmlFor={`${idPrefix}-options`} className=\"text-sm font-medium\">\n Options (one per line)\n </label>\n <textarea\n id={`${idPrefix}-options`}\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[88px]\"\n value={form.optionsText}\n onChange={(e) => setForm({ ...form, optionsText: e.target.value })}\n />\n {options.length === 0 && <ErrorLine message=\"Add at least one option.\" />}\n </div>\n )}\n <div>\n <label htmlFor={`${idPrefix}-description`} className=\"text-sm font-medium\">\n Description (optional)\n </label>\n <textarea\n id={`${idPrefix}-description`}\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[60px]\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n />\n </div>\n <div className=\"flex items-end gap-4\">\n <div>\n <label htmlFor={`${idPrefix}-sort`} className=\"text-sm font-medium\">\n Order (optional)\n </label>\n <Input\n id={`${idPrefix}-sort`}\n type=\"number\"\n min={0}\n step={1}\n className=\"mt-1 w-24\"\n value={form.sortOrderText}\n onChange={(e) => setForm({ ...form, sortOrderText: e.target.value })}\n />\n </div>\n <label className=\"flex items-center gap-2 pb-2 text-sm\">\n <input\n type=\"checkbox\"\n checked={form.isRequired}\n onChange={(e) => setForm({ ...form, isRequired: e.target.checked })}\n />\n Required\n </label>\n </div>\n {sortOrder.invalid && <ErrorLine message=\"Order must be a whole number, 0 or more.\" />}\n {form.name.trim() === '' && <ErrorLine message=\"Give the field a name.\" />}\n {error && <ErrorLine message={error} />}\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setOpen(false)}>\n Cancel\n </Button>\n <Button\n onClick={() => void save()}\n disabled={invalid || busy}\n data-testid={`${idPrefix}-save`}\n >\n {busy ? 'Saving…' : editing ? 'Save' : 'Add field'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n"],"mappings":"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"}
@@ -1,11 +1,11 @@
1
1
  import { usePlanMagnetNavigate as e } from "../providers/PlanMagnetProvider.js";
2
2
  import { throwOnError as t } from "../utils/mutationResult.js";
3
- import { detailPath as n } from "../utils/rowNavigation.js";
3
+ import { useEntityId as n } from "../hooks/useEntityId.js";
4
4
  import { ProgramSelect as r } from "../controls/Pickers.js";
5
- import { endBeforeStart as i } from "../utils/formValidation.js";
6
- import { enumLabel as a } from "../controls/WorkItemControls.js";
7
- import { PROJECT_STATUSES as o } from "../controls/ProjectControls.js";
8
- import { useEntityId as s } from "../hooks/useEntityId.js";
5
+ import { enumLabel as i } from "../controls/WorkItemControls.js";
6
+ import { detailPath as a } from "../utils/rowNavigation.js";
7
+ import { endBeforeStart as o } from "../utils/formValidation.js";
8
+ import { PROJECT_STATUSES as s } from "../controls/ProjectControls.js";
9
9
  import { useMemo as c, useState as l } from "react";
10
10
  import { ArrowLeft as u, Save as d } from "lucide-react";
11
11
  import { gql as f } from "@apollo/client";
@@ -51,7 +51,7 @@ var C = f`
51
51
  }
52
52
  `;
53
53
  function T() {
54
- let f = s("projectId"), T = e(), { data: E, loading: D, error: O } = m(C, {
54
+ let f = n("projectId"), T = e(), { data: E, loading: D, error: O } = m(C, {
55
55
  variables: { id: f },
56
56
  skip: !f
57
57
  }), [k, A] = l(null), j = E?.planmagnetProject, M = c(() => ({
@@ -74,7 +74,7 @@ function T() {
74
74
  "AdminPlanmagnetProjects",
75
75
  "GetProgram",
76
76
  "ListPrograms"
77
- ] }), [z, B] = l(null), V = i(F.startDate, F.endDate);
77
+ ] }), [z, B] = l(null), V = o(F.startDate, F.endDate);
78
78
  return f ? D && !E ? /* @__PURE__ */ h("div", {
79
79
  className: "flex items-center justify-center p-12",
80
80
  children: /* @__PURE__ */ h("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
@@ -92,7 +92,7 @@ function T() {
92
92
  variant: "ghost",
93
93
  size: "sm",
94
94
  "aria-label": "Back to the project",
95
- onClick: () => T(n("/projects/project-detail-page", f)),
95
+ onClick: () => T(a("/projects/project-detail-page", f)),
96
96
  children: /* @__PURE__ */ h(u, { className: "h-4 w-4" })
97
97
  }), /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("h1", {
98
98
  className: "text-2xl font-semibold",
@@ -215,9 +215,9 @@ function T() {
215
215
  ...F,
216
216
  status: e.target.value
217
217
  }),
218
- children: (o.includes(F.status) ? o : [F.status, ...o]).map((e) => /* @__PURE__ */ h("option", {
218
+ children: (s.includes(F.status) ? s : [F.status, ...s]).map((e) => /* @__PURE__ */ h("option", {
219
219
  value: e,
220
- children: a(e)
220
+ children: i(e)
221
221
  }, e))
222
222
  })] }),
223
223
  /* @__PURE__ */ g("div", {
@@ -1,7 +1,7 @@
1
1
  import { usePlanMagnetNavigate as e } from "../providers/PlanMagnetProvider.js";
2
2
  import { PersonName as t } from "../people/People.js";
3
- import { detailPath as n } from "../utils/rowNavigation.js";
4
- import { useEntityId as r } from "../hooks/useEntityId.js";
3
+ import { useEntityId as n } from "../hooks/useEntityId.js";
4
+ import { detailPath as r } from "../utils/rowNavigation.js";
5
5
  import { MilestoneHeaderActions as i } from "../controls/MilestoneControls.js";
6
6
  import { Calendar as a, FolderKanban as o, Target as s, User as c } from "lucide-react";
7
7
  import { gql as l } from "@apollo/client";
@@ -29,7 +29,7 @@ var v = l`
29
29
  }
30
30
  `;
31
31
  function y() {
32
- let l = r("milestoneId"), y = e(), { data: b, loading: x, error: S } = u(v, {
32
+ let l = n("milestoneId"), y = e(), { data: b, loading: x, error: S } = u(v, {
33
33
  variables: { id: l },
34
34
  skip: !l
35
35
  });
@@ -135,7 +135,7 @@ function y() {
135
135
  C.project ? /* @__PURE__ */ d("button", {
136
136
  type: "button",
137
137
  className: "font-medium text-primary hover:underline",
138
- onClick: () => y(n("/projects/project-detail-page", C.project.id)),
138
+ onClick: () => y(r("/projects/project-detail-page", C.project.id)),
139
139
  children: C.project.name
140
140
  }) : /* @__PURE__ */ d("span", {
141
141
  className: "text-muted-foreground",
@@ -1,7 +1,7 @@
1
1
  import { usePlanMagnetNavigate as e } from "../providers/PlanMagnetProvider.js";
2
2
  import { PersonAvatar as t, PersonName as n, initialsOf as r } from "../people/People.js";
3
- import { detailPath as i } from "../utils/rowNavigation.js";
4
- import { useEntityId as a } from "../hooks/useEntityId.js";
3
+ import { useEntityId as i } from "../hooks/useEntityId.js";
4
+ import { detailPath as a } from "../utils/rowNavigation.js";
5
5
  import { SprintLifecycleActions as o, SprintWorkItemsPanel as s } from "../sprints/SprintControls.js";
6
6
  import { SprintDates as c } from "../sprints/SprintDates.js";
7
7
  import { BarChart3 as l, FolderKanban as u, Pencil as d, Users as f } from "lucide-react";
@@ -70,7 +70,7 @@ var C = p`
70
70
  }
71
71
  `;
72
72
  function T() {
73
- let p = a("sprintId"), T = e(), { data: E, loading: D, error: O } = m(C, {
73
+ let p = i("sprintId"), T = e(), { data: E, loading: D, error: O } = m(C, {
74
74
  variables: { id: p },
75
75
  skip: !p
76
76
  }), { data: k } = m(w, {
@@ -131,7 +131,7 @@ function T() {
131
131
  A.status !== "COMPLETED" && A.status !== "CANCELLED" && /* @__PURE__ */ g(v, {
132
132
  size: "sm",
133
133
  variant: "outline",
134
- onClick: () => T(i("/projects/planning-edit-page", A.id)),
134
+ onClick: () => T(a("/projects/planning-edit-page", A.id)),
135
135
  "data-testid": "sprint-edit",
136
136
  children: [/* @__PURE__ */ h(d, { className: "mr-1 h-4 w-4" }), " Edit"]
137
137
  }),
@@ -1,8 +1,8 @@
1
1
  import { usePlanMagnet as e, usePlanMagnetNavigate as t } from "../providers/PlanMagnetProvider.js";
2
2
  import { throwOnError as n } from "../utils/mutationResult.js";
3
- import { detailPath as r } from "../utils/rowNavigation.js";
4
- import { endBeforeStart as i, parseIntField as a } from "../utils/formValidation.js";
5
- import { useEntityId as o } from "../hooks/useEntityId.js";
3
+ import { useEntityId as r } from "../hooks/useEntityId.js";
4
+ import { detailPath as i } from "../utils/rowNavigation.js";
5
+ import { endBeforeStart as a, parseIntField as o } from "../utils/formValidation.js";
6
6
  import { SprintLifecycleActions as s } from "../sprints/SprintControls.js";
7
7
  import { useMemo as c, useState as l } from "react";
8
8
  import { ArrowLeft as u, Save as d } from "lucide-react";
@@ -44,7 +44,7 @@ var C = f`
44
44
  }
45
45
  `;
46
46
  function T() {
47
- let { workspaceId: f } = e(), T = o("sprintId"), E = t(), { data: D, loading: O, error: k } = m(C, {
47
+ let { workspaceId: f } = e(), T = r("sprintId"), E = t(), { data: D, loading: O, error: k } = m(C, {
48
48
  variables: {
49
49
  id: T,
50
50
  workspaceId: f ?? "default"
@@ -63,7 +63,7 @@ function T() {
63
63
  let n = { ...t };
64
64
  for (let [t, r] of Object.entries(e)) r !== L[t] && (n[t] = r);
65
65
  return n;
66
- }), [z, B] = l(null), V = i(L.startDate, L.endDate), H = a(L.capacity, { min: 0 }), [U, { loading: W }] = p(w, { refetchQueries: [
66
+ }), [z, B] = l(null), V = a(L.startDate, L.endDate), H = o(L.capacity, { min: 0 }), [U, { loading: W }] = p(w, { refetchQueries: [
67
67
  "GetSprints",
68
68
  "GetSprintDetail",
69
69
  "GetSprintForEdit",
@@ -86,7 +86,7 @@ function T() {
86
86
  variant: "ghost",
87
87
  size: "sm",
88
88
  "aria-label": "Back to the sprint",
89
- onClick: () => E(r("/projects/planning-detail-page", T)),
89
+ onClick: () => E(i("/projects/planning-detail-page", T)),
90
90
  children: /* @__PURE__ */ h(u, { className: "h-4 w-4" })
91
91
  }), /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("h1", {
92
92
  className: "text-2xl font-semibold",
@@ -1 +1 @@
1
- {"version":3,"file":"ProjectsProjectDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProjectsProjectDetailPagePage.tsx"],"names":[],"mappings":"AAgFA,wBAAgB,6BAA6B,4CAwW5C"}
1
+ {"version":3,"file":"ProjectsProjectDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProjectsProjectDetailPagePage.tsx"],"names":[],"mappings":"AA8GA,wBAAgB,6BAA6B,4CA+c5C"}