@burdenoff/microfe-planmagnet 2026.928.2 → 2026.928.4

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 (85) hide show
  1. package/dist/planmagnet/PlanMagnetRoot.d.ts.map +1 -1
  2. package/dist/planmagnet/PlanMagnetRoot.js +102 -84
  3. package/dist/planmagnet/PlanMagnetRoot.js.map +1 -1
  4. package/dist/planmagnet/PlanMagnetRoutes.d.ts.map +1 -1
  5. package/dist/planmagnet/PlanMagnetRoutes.js +103 -55
  6. package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
  7. package/dist/planmagnet/controls/CompetitorControls.d.ts +20 -0
  8. package/dist/planmagnet/controls/CompetitorControls.d.ts.map +1 -0
  9. package/dist/planmagnet/controls/CompetitorControls.js +172 -0
  10. package/dist/planmagnet/controls/CompetitorControls.js.map +1 -0
  11. package/dist/planmagnet/controls/FeatureControls.js +29 -29
  12. package/dist/planmagnet/controls/FeatureTriage.js +11 -11
  13. package/dist/planmagnet/controls/ObjectiveControls.js +24 -24
  14. package/dist/planmagnet/controls/Pickers.d.ts +17 -2
  15. package/dist/planmagnet/controls/Pickers.d.ts.map +1 -1
  16. package/dist/planmagnet/controls/Pickers.js +100 -9
  17. package/dist/planmagnet/controls/Pickers.js.map +1 -1
  18. package/dist/planmagnet/controls/PortfolioControls.d.ts +13 -0
  19. package/dist/planmagnet/controls/PortfolioControls.d.ts.map +1 -0
  20. package/dist/planmagnet/controls/PortfolioControls.js +114 -0
  21. package/dist/planmagnet/controls/PortfolioControls.js.map +1 -0
  22. package/dist/planmagnet/controls/ProgramControls.d.ts +25 -0
  23. package/dist/planmagnet/controls/ProgramControls.d.ts.map +1 -0
  24. package/dist/planmagnet/controls/ProgramControls.js +187 -0
  25. package/dist/planmagnet/controls/ProgramControls.js.map +1 -0
  26. package/dist/planmagnet/pages/CompetitorsCompetitorDetailPagePage.d.ts +2 -0
  27. package/dist/planmagnet/pages/CompetitorsCompetitorDetailPagePage.d.ts.map +1 -0
  28. package/dist/planmagnet/pages/CompetitorsCompetitorDetailPagePage.js +127 -0
  29. package/dist/planmagnet/pages/CompetitorsCompetitorDetailPagePage.js.map +1 -0
  30. package/dist/planmagnet/pages/CompetitorsCompetitorsPagePage.d.ts +2 -0
  31. package/dist/planmagnet/pages/CompetitorsCompetitorsPagePage.d.ts.map +1 -0
  32. package/dist/planmagnet/pages/CompetitorsCompetitorsPagePage.js +129 -0
  33. package/dist/planmagnet/pages/CompetitorsCompetitorsPagePage.js.map +1 -0
  34. package/dist/planmagnet/pages/CompetitorsCreateCompetitorPagePage.d.ts +2 -0
  35. package/dist/planmagnet/pages/CompetitorsCreateCompetitorPagePage.d.ts.map +1 -0
  36. package/dist/planmagnet/pages/CompetitorsCreateCompetitorPagePage.js +132 -0
  37. package/dist/planmagnet/pages/CompetitorsCreateCompetitorPagePage.js.map +1 -0
  38. package/dist/planmagnet/pages/CompetitorsEditCompetitorPagePage.d.ts +2 -0
  39. package/dist/planmagnet/pages/CompetitorsEditCompetitorPagePage.d.ts.map +1 -0
  40. package/dist/planmagnet/pages/CompetitorsEditCompetitorPagePage.js +181 -0
  41. package/dist/planmagnet/pages/CompetitorsEditCompetitorPagePage.js.map +1 -0
  42. package/dist/planmagnet/pages/PortfoliosCreatePortfolioPagePage.d.ts +2 -0
  43. package/dist/planmagnet/pages/PortfoliosCreatePortfolioPagePage.d.ts.map +1 -0
  44. package/dist/planmagnet/pages/PortfoliosCreatePortfolioPagePage.js +242 -0
  45. package/dist/planmagnet/pages/PortfoliosCreatePortfolioPagePage.js.map +1 -0
  46. package/dist/planmagnet/pages/PortfoliosEditPortfolioPagePage.d.ts +2 -0
  47. package/dist/planmagnet/pages/PortfoliosEditPortfolioPagePage.d.ts.map +1 -0
  48. package/dist/planmagnet/pages/PortfoliosEditPortfolioPagePage.js +302 -0
  49. package/dist/planmagnet/pages/PortfoliosEditPortfolioPagePage.js.map +1 -0
  50. package/dist/planmagnet/pages/PortfoliosPortfolioDetailPagePage.d.ts +2 -0
  51. package/dist/planmagnet/pages/PortfoliosPortfolioDetailPagePage.d.ts.map +1 -0
  52. package/dist/planmagnet/pages/PortfoliosPortfolioDetailPagePage.js +335 -0
  53. package/dist/planmagnet/pages/PortfoliosPortfolioDetailPagePage.js.map +1 -0
  54. package/dist/planmagnet/pages/PortfoliosPortfoliosPagePage.d.ts +2 -0
  55. package/dist/planmagnet/pages/PortfoliosPortfoliosPagePage.d.ts.map +1 -0
  56. package/dist/planmagnet/pages/PortfoliosPortfoliosPagePage.js +154 -0
  57. package/dist/planmagnet/pages/PortfoliosPortfoliosPagePage.js.map +1 -0
  58. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.d.ts.map +1 -1
  59. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js +124 -138
  60. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js.map +1 -1
  61. package/dist/planmagnet/pages/ProgramsCreateProgramPagePage.d.ts +2 -0
  62. package/dist/planmagnet/pages/ProgramsCreateProgramPagePage.d.ts.map +1 -0
  63. package/dist/planmagnet/pages/ProgramsCreateProgramPagePage.js +221 -0
  64. package/dist/planmagnet/pages/ProgramsCreateProgramPagePage.js.map +1 -0
  65. package/dist/planmagnet/pages/ProgramsEditProgramPagePage.d.ts +2 -0
  66. package/dist/planmagnet/pages/ProgramsEditProgramPagePage.d.ts.map +1 -0
  67. package/dist/planmagnet/pages/ProgramsEditProgramPagePage.js +279 -0
  68. package/dist/planmagnet/pages/ProgramsEditProgramPagePage.js.map +1 -0
  69. package/dist/planmagnet/pages/ProgramsProgramDetailPagePage.d.ts +2 -0
  70. package/dist/planmagnet/pages/ProgramsProgramDetailPagePage.d.ts.map +1 -0
  71. package/dist/planmagnet/pages/ProgramsProgramDetailPagePage.js +178 -0
  72. package/dist/planmagnet/pages/ProgramsProgramDetailPagePage.js.map +1 -0
  73. package/dist/planmagnet/pages/ProgramsProgramsPagePage.d.ts +2 -0
  74. package/dist/planmagnet/pages/ProgramsProgramsPagePage.d.ts.map +1 -0
  75. package/dist/planmagnet/pages/ProgramsProgramsPagePage.js +157 -0
  76. package/dist/planmagnet/pages/ProgramsProgramsPagePage.js.map +1 -0
  77. package/dist/planmagnet/pages/ProjectsEditProjectPagePage.d.ts.map +1 -1
  78. package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js +130 -103
  79. package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js.map +1 -1
  80. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.d.ts.map +1 -1
  81. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js +156 -136
  82. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js.map +1 -1
  83. package/dist/planmagnet/pages/TasksImportPagePage.js +5 -5
  84. package/dist/planmagnet/types/index.d.ts.map +1 -1
  85. package/package.json +1 -1
@@ -1,18 +1,19 @@
1
1
  import { usePlanMagnetNavigate as e } from "../providers/PlanMagnetProvider.js";
2
2
  import { throwOnError as t } from "../utils/mutationResult.js";
3
3
  import { detailPath as n } from "../utils/rowNavigation.js";
4
- import { endBeforeStart as r } from "../utils/formValidation.js";
5
- import { enumLabel as i } from "../controls/WorkItemControls.js";
6
- import { useEntityId as a } from "../hooks/useEntityId.js";
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
7
  import { PROJECT_STATUSES as o } from "../controls/ProjectControls.js";
8
- import { useMemo as s, useState as c } from "react";
9
- import { ArrowLeft as l, Save as u } from "lucide-react";
10
- import { gql as d } from "@apollo/client";
11
- import { useMutation as f, useQuery as p } from "@apollo/client/react";
12
- import { jsx as m, jsxs as h } from "react/jsx-runtime";
13
- import { Button as g, Card as _, CardContent as v, CardHeader as y, CardTitle as b, Input as x } from "@burdenoff/fe-libs/ui";
8
+ import { useEntityId as s } from "../hooks/useEntityId.js";
9
+ import { useMemo as c, useState as l } from "react";
10
+ import { ArrowLeft as u, Save as d } from "lucide-react";
11
+ import { gql as f } from "@apollo/client";
12
+ import { useMutation as p, useQuery as m } from "@apollo/client/react";
13
+ import { jsx as h, jsxs as g } from "react/jsx-runtime";
14
+ import { Button as _, Card as v, CardContent as y, CardHeader as b, CardTitle as x, Input as S } from "@burdenoff/fe-libs/ui";
14
15
  //#region src/planmagnet/pages/ProjectsEditProjectPagePage.tsx
15
- var S = d`
16
+ var C = f`
16
17
  query GetProjectsForEdit($id: ID!) {
17
18
  planmagnetProject(id: $id) {
18
19
  id
@@ -25,9 +26,10 @@ var S = d`
25
26
  startDate
26
27
  endDate
27
28
  tags
29
+ programId
28
30
  }
29
31
  }
30
- `, C = d`
32
+ `, w = f`
31
33
  mutation UpdateProject($id: ID!, $input: PlanmagnetUpdateProjectInput!) {
32
34
  planmagnetUpdateProject(id: $id, input: $input) {
33
35
  id
@@ -40,128 +42,137 @@ var S = d`
40
42
  startDate
41
43
  endDate
42
44
  tags
45
+ programId
46
+ program {
47
+ id
48
+ name
49
+ }
43
50
  }
44
51
  }
45
52
  `;
46
- function w() {
47
- let d = a("projectId"), w = e(), { data: T, loading: E, error: D } = p(S, {
48
- variables: { id: d },
49
- skip: !d
50
- }), [O, k] = c(null), A = T?.planmagnetProject, j = s(() => ({
51
- name: A?.name ?? "",
52
- description: A?.description ?? "",
53
- methodology: A?.methodology ?? "SCRUM",
54
- status: A?.status ?? "PLANNING",
55
- startDate: A?.startDate ? A.startDate.split("T")[0] : "",
56
- endDate: A?.endDate ? A.endDate.split("T")[0] : ""
57
- }), [A]), [M, N] = c({}), P = {
58
- ...j,
59
- ...M
60
- }, F = (e) => N(e), [I, { loading: L }] = f(C, { refetchQueries: [
53
+ function T() {
54
+ let f = s("projectId"), T = e(), { data: E, loading: D, error: O } = m(C, {
55
+ variables: { id: f },
56
+ skip: !f
57
+ }), [k, A] = l(null), j = E?.planmagnetProject, M = c(() => ({
58
+ name: j?.name ?? "",
59
+ description: j?.description ?? "",
60
+ methodology: j?.methodology ?? "SCRUM",
61
+ status: j?.status ?? "PLANNING",
62
+ startDate: j?.startDate ? j.startDate.split("T")[0] : "",
63
+ endDate: j?.endDate ? j.endDate.split("T")[0] : "",
64
+ programId: j?.programId ?? ""
65
+ }), [j]), [N, P] = l({}), F = {
66
+ ...M,
67
+ ...N
68
+ }, I = (e) => P(e), [L, { loading: R }] = p(w, { refetchQueries: [
61
69
  "GetProjects",
62
70
  "GetActiveProjects",
63
71
  "GetDashboardData",
64
72
  "GetProjectsForEdit",
65
73
  "GetProjectDetail",
66
- "AdminPlanmagnetProjects"
67
- ] }), [R, z] = c(null), B = r(P.startDate, P.endDate);
68
- return d ? E && !T ? /* @__PURE__ */ m("div", {
74
+ "AdminPlanmagnetProjects",
75
+ "GetProgram",
76
+ "ListPrograms"
77
+ ] }), [z, B] = l(null), V = i(F.startDate, F.endDate);
78
+ return f ? D && !E ? /* @__PURE__ */ h("div", {
69
79
  className: "flex items-center justify-center p-12",
70
- children: /* @__PURE__ */ m("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
71
- }) : D ? /* @__PURE__ */ h("div", {
80
+ children: /* @__PURE__ */ h("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
81
+ }) : O ? /* @__PURE__ */ g("div", {
72
82
  className: "p-6 text-destructive",
73
- children: ["Error loading project: ", D.message]
74
- }) : A ? /* @__PURE__ */ h("div", {
83
+ children: ["Error loading project: ", O.message]
84
+ }) : j ? /* @__PURE__ */ g("div", {
75
85
  className: "space-y-6 p-6 max-w-4xl",
76
86
  children: [
77
- /* @__PURE__ */ h("div", {
87
+ /* @__PURE__ */ g("div", {
78
88
  className: "flex items-center justify-between",
79
- children: [/* @__PURE__ */ h("div", {
89
+ children: [/* @__PURE__ */ g("div", {
80
90
  className: "flex items-center gap-3",
81
- children: [/* @__PURE__ */ m(g, {
91
+ children: [/* @__PURE__ */ h(_, {
82
92
  variant: "ghost",
83
93
  size: "sm",
84
94
  "aria-label": "Back to the project",
85
- onClick: () => w(n("/projects/project-detail-page", d)),
86
- children: /* @__PURE__ */ m(l, { className: "h-4 w-4" })
87
- }), /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("h1", {
95
+ onClick: () => T(n("/projects/project-detail-page", f)),
96
+ children: /* @__PURE__ */ h(u, { className: "h-4 w-4" })
97
+ }), /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("h1", {
88
98
  className: "text-2xl font-semibold",
89
99
  children: "Edit Project"
90
- }), /* @__PURE__ */ h("p", {
100
+ }), /* @__PURE__ */ g("p", {
91
101
  className: "text-sm text-muted-foreground",
92
- children: ["Editing ", A.name]
102
+ children: ["Editing ", j.name]
93
103
  })] })]
94
- }), /* @__PURE__ */ h(g, {
104
+ }), /* @__PURE__ */ g(_, {
95
105
  size: "sm",
96
106
  onClick: async () => {
97
- if (!A || B) return;
98
- z(null), k(null);
107
+ if (!j || V) return;
108
+ B(null), A(null);
99
109
  let e = {
100
- ...P.startDate !== j.startDate && { startDate: P.startDate || void 0 },
101
- ...P.endDate !== j.endDate && { endDate: P.endDate || void 0 }
110
+ ...F.startDate !== M.startDate && { startDate: F.startDate || void 0 },
111
+ ...F.endDate !== M.endDate && { endDate: F.endDate || void 0 }
102
112
  };
103
113
  try {
104
- await t(I({ variables: {
105
- id: A.id,
114
+ await t(L({ variables: {
115
+ id: j.id,
106
116
  input: {
107
- name: P.name || void 0,
108
- description: P.description || void 0,
109
- methodology: P.methodology || void 0,
110
- ...P.status !== j.status && { status: P.status },
111
- ...e
117
+ name: F.name || void 0,
118
+ description: F.description || void 0,
119
+ methodology: F.methodology || void 0,
120
+ ...F.status !== M.status && { status: F.status },
121
+ ...e,
122
+ ...F.programId !== M.programId && { programId: F.programId || null }
112
123
  }
113
- } })), k("Project updated successfully.");
124
+ } })), A("Project updated successfully.");
114
125
  } catch (e) {
115
- z(e instanceof Error ? e.message : "The project could not be saved.");
126
+ B(e instanceof Error ? e.message : "The project could not be saved.");
116
127
  }
117
128
  },
118
- disabled: L || B,
119
- children: [/* @__PURE__ */ m(u, { className: "mr-1 h-4 w-4" }), L ? "Saving..." : "Save Changes"]
129
+ disabled: R || V,
130
+ children: [/* @__PURE__ */ h(d, { className: "mr-1 h-4 w-4" }), R ? "Saving..." : "Save Changes"]
120
131
  })]
121
132
  }),
122
- O && /* @__PURE__ */ m("div", {
133
+ k && /* @__PURE__ */ h("div", {
123
134
  role: "status",
124
135
  className: "p-3 bg-muted text-status-success-text rounded-md text-sm",
125
- children: O
136
+ children: k
126
137
  }),
127
- R && /* @__PURE__ */ m("div", {
138
+ z && /* @__PURE__ */ h("div", {
128
139
  role: "alert",
129
140
  className: "p-3 bg-destructive/10 text-destructive rounded-md text-sm",
130
- children: R
141
+ children: z
131
142
  }),
132
- /* @__PURE__ */ h(_, { children: [/* @__PURE__ */ m(y, { children: /* @__PURE__ */ m(b, { children: "Project Details" }) }), /* @__PURE__ */ h(v, {
143
+ /* @__PURE__ */ g(v, { children: [/* @__PURE__ */ h(b, { children: /* @__PURE__ */ h(x, { children: "Project Details" }) }), /* @__PURE__ */ g(y, {
133
144
  className: "space-y-4",
134
145
  children: [
135
- /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("label", {
146
+ /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
136
147
  className: "text-sm font-medium",
137
148
  children: "Project Name"
138
- }), /* @__PURE__ */ m(x, {
139
- value: P.name,
140
- onChange: (e) => F({
141
- ...P,
149
+ }), /* @__PURE__ */ h(S, {
150
+ value: F.name,
151
+ onChange: (e) => I({
152
+ ...F,
142
153
  name: e.target.value
143
154
  }),
144
155
  className: "mt-1"
145
156
  })] }),
146
- /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("label", {
157
+ /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
147
158
  className: "text-sm font-medium",
148
159
  children: "Description"
149
- }), /* @__PURE__ */ m("textarea", {
160
+ }), /* @__PURE__ */ h("textarea", {
150
161
  className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[80px]",
151
- value: P.description,
152
- onChange: (e) => F({
153
- ...P,
162
+ value: F.description,
163
+ onChange: (e) => I({
164
+ ...F,
154
165
  description: e.target.value
155
166
  })
156
167
  })] }),
157
- /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("label", {
168
+ /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
158
169
  className: "text-sm font-medium",
159
170
  children: "Methodology"
160
- }), /* @__PURE__ */ m("select", {
171
+ }), /* @__PURE__ */ h("select", {
161
172
  className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm capitalize",
162
- value: P.methodology,
163
- onChange: (e) => F({
164
- ...P,
173
+ value: F.methodology,
174
+ onChange: (e) => I({
175
+ ...F,
165
176
  methodology: e.target.value
166
177
  }),
167
178
  children: [
@@ -171,62 +182,78 @@ function w() {
171
182
  "HYBRID",
172
183
  "AGILE",
173
184
  "CUSTOM"
174
- ].map((e) => /* @__PURE__ */ m("option", {
185
+ ].map((e) => /* @__PURE__ */ h("option", {
175
186
  value: e,
176
187
  children: e.toLowerCase()
177
188
  }, e))
178
189
  })] }),
179
- /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("label", {
190
+ /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
191
+ htmlFor: "project-program",
192
+ className: "text-sm font-medium",
193
+ children: "Program"
194
+ }), /* @__PURE__ */ h("div", {
195
+ className: "mt-1",
196
+ children: /* @__PURE__ */ h(r, {
197
+ id: "project-program",
198
+ value: F.programId,
199
+ onChange: (e) => I({
200
+ ...F,
201
+ programId: e
202
+ }),
203
+ noneLabel: "No program"
204
+ })
205
+ })] }),
206
+ /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
180
207
  htmlFor: "project-status",
181
208
  className: "text-sm font-medium",
182
209
  children: "Status"
183
- }), /* @__PURE__ */ m("select", {
210
+ }), /* @__PURE__ */ h("select", {
184
211
  id: "project-status",
185
212
  className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm",
186
- value: P.status,
187
- onChange: (e) => F({
188
- ...P,
213
+ value: F.status,
214
+ onChange: (e) => I({
215
+ ...F,
189
216
  status: e.target.value
190
217
  }),
191
- children: (o.includes(P.status) ? o : [P.status, ...o]).map((e) => /* @__PURE__ */ m("option", {
218
+ children: (o.includes(F.status) ? o : [F.status, ...o]).map((e) => /* @__PURE__ */ h("option", {
192
219
  value: e,
193
- children: i(e)
220
+ children: a(e)
194
221
  }, e))
195
222
  })] }),
196
- /* @__PURE__ */ h("div", {
223
+ /* @__PURE__ */ g("div", {
197
224
  className: "grid grid-cols-2 gap-4",
198
- children: [/* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("label", {
225
+ children: [/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
199
226
  htmlFor: "project-start",
200
227
  className: "text-sm font-medium",
201
228
  children: "Start Date"
202
- }), /* @__PURE__ */ m(x, {
229
+ }), /* @__PURE__ */ h(S, {
203
230
  id: "project-start",
204
231
  type: "date",
205
- value: P.startDate,
206
- max: P.endDate || void 0,
207
- onChange: (e) => F({
208
- ...P,
232
+ value: F.startDate,
233
+ max: F.endDate || void 0,
234
+ onChange: (e) => I({
235
+ ...F,
209
236
  startDate: e.target.value
210
237
  }),
211
238
  className: "mt-1"
212
- })] }), /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("label", {
239
+ })] }), /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
213
240
  htmlFor: "project-end",
214
241
  className: "text-sm font-medium",
215
242
  children: "End Date"
216
- }), /* @__PURE__ */ m(x, {
243
+ }), /* @__PURE__ */ h(S, {
217
244
  id: "project-end",
218
245
  type: "date",
219
- value: P.endDate,
220
- min: P.startDate || void 0,
221
- onChange: (e) => F({
222
- ...P,
246
+ value: F.endDate,
247
+ min: F.startDate || void 0,
248
+ onChange: (e) => I({
249
+ ...F,
223
250
  endDate: e.target.value
224
251
  }),
225
- "aria-invalid": B,
252
+ "aria-invalid": V,
226
253
  className: "mt-1"
227
254
  })] })]
228
255
  }),
229
- B && /* @__PURE__ */ m("p", {
256
+ V && /* @__PURE__ */ h("p", {
230
257
  role: "alert",
231
258
  className: "text-sm text-destructive",
232
259
  children: "The end date is before the start date."
@@ -234,15 +261,15 @@ function w() {
234
261
  ]
235
262
  })] })
236
263
  ]
237
- }) : /* @__PURE__ */ m("div", {
264
+ }) : /* @__PURE__ */ h("div", {
238
265
  className: "p-6 text-muted-foreground",
239
266
  children: "Project not found."
240
- }) : /* @__PURE__ */ m("div", {
267
+ }) : /* @__PURE__ */ h("div", {
241
268
  className: "p-6 text-muted-foreground",
242
269
  children: "No project selected. Open one from the list."
243
270
  });
244
271
  }
245
272
  //#endregion
246
- export { w as ProjectsEditProjectPagePage };
273
+ export { T as ProjectsEditProjectPagePage };
247
274
 
248
275
  //# sourceMappingURL=ProjectsEditProjectPagePage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ProjectsEditProjectPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProjectsEditProjectPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState, useMemo } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery, useMutation } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Button, Input } from '@burdenoff/fe-libs/ui';\nimport { Save, ArrowLeft } from 'lucide-react';\nimport { useEntityId } from '../hooks/useEntityId';\nimport { usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { detailPath } from '../utils/rowNavigation';\nimport { throwOnError } from '../utils/mutationResult';\nimport { endBeforeStart } from '../utils/formValidation';\nimport { PROJECT_STATUSES } from '../controls/ProjectControls';\nimport { enumLabel } from '../controls/WorkItemControls';\n\nconst GET_PROJECTS = gql`\n query GetProjectsForEdit($id: ID!) {\n planmagnetProject(id: $id) {\n id\n name\n key\n description\n status\n methodology\n ownerId\n startDate\n endDate\n tags\n }\n }\n`;\n\nconst UPDATE_PROJECT = gql`\n mutation UpdateProject($id: ID!, $input: PlanmagnetUpdateProjectInput!) {\n planmagnetUpdateProject(id: $id, input: $input) {\n id\n name\n key\n description\n status\n methodology\n ownerId\n startDate\n endDate\n tags\n }\n }\n`;\n\nexport function ProjectsEditProjectPagePage() {\n const projectId = useEntityId('projectId');\n const navigate = usePlanMagnetNavigate();\n\n const {\n data,\n loading,\n error,\n } = // eslint-disable-next-line @typescript-eslint/no-explicit-any\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n useQuery<Record<string, any>>(GET_PROJECTS, {\n variables: { id: projectId },\n skip: !projectId,\n });\n\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n\n const project = data?.planmagnetProject;\n\n const defaultForm = useMemo(\n () => ({\n name: project?.name ?? '',\n description: project?.description ?? '',\n methodology: project?.methodology ?? 'SCRUM',\n status: project?.status ?? 'PLANNING',\n startDate: project?.startDate ? project.startDate.split('T')[0] : '',\n endDate: project?.endDate ? project.endDate.split('T')[0] : '',\n }),\n [project]\n );\n\n const [formOverrides, setFormOverrides] = useState<Record<string, string>>({});\n const form = { ...defaultForm, ...formOverrides };\n const setForm = (updates: Record<string, string>) => setFormOverrides(updates);\n\n // Success only after the service accepted the change (errorPolicy 'all' resolves refused mutations).\n const [updateProject, { loading: saving }] = useMutation(UPDATE_PROJECT, {\n refetchQueries: [\n 'GetProjects',\n 'GetActiveProjects',\n 'GetDashboardData',\n 'GetProjectsForEdit',\n 'GetProjectDetail',\n 'AdminPlanmagnetProjects',\n ],\n });\n const [saveError, setSaveError] = useState<string | null>(null);\n const invalidDates = endBeforeStart(form.startDate, form.endDate);\n\n const methodologies = ['SCRUM', 'KANBAN', 'WATERFALL', 'HYBRID', 'AGILE', 'CUSTOM'] as const;\n\n const handleSave = async () => {\n if (!project || invalidDates) return;\n setSaveError(null);\n setSuccessMessage(null);\n // Dates are sent only when they were changed: the service checks the pair the project would end up\n // with, so re-sending untouched dates of an older project stored with inverted dates would refuse a\n // plain rename (BOFF-7833).\n const dateChanges = {\n ...(form.startDate !== defaultForm.startDate && { startDate: form.startDate || undefined }),\n ...(form.endDate !== defaultForm.endDate && { endDate: form.endDate || undefined }),\n };\n try {\n await throwOnError(\n updateProject({\n variables: {\n id: project.id,\n input: {\n name: form.name || undefined,\n description: form.description || undefined,\n methodology: form.methodology || undefined,\n // Only when changed: a status set elsewhere meanwhile (the detail page's select) is not overwritten.\n ...(form.status !== defaultForm.status && { status: form.status }),\n ...dateChanges,\n },\n },\n })\n );\n setSuccessMessage('Project updated successfully.');\n } catch (e) {\n setSaveError(e instanceof Error ? e.message : 'The project could not be saved.');\n }\n };\n\n if (!projectId)\n return (\n <div className=\"p-6 text-muted-foreground\">No project selected. Open one from the list.</div>\n );\n // Only before the first load: a refetch must not blank the page (it\n // unmounts every component on it and loses their state).\n if (loading && !data)\n return (\n <div className=\"flex items-center justify-center p-12\">\n <div className=\"animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full\" />\n </div>\n );\n if (error)\n return <div className=\"p-6 text-destructive\">Error loading project: {error.message}</div>;\n if (!project) return <div className=\"p-6 text-muted-foreground\">Project not found.</div>;\n\n return (\n <div className=\"space-y-6 p-6 max-w-4xl\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label=\"Back to the project\"\n onClick={() => navigate(detailPath('/projects/project-detail-page', projectId))}\n >\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n <div>\n <h1 className=\"text-2xl font-semibold\">Edit Project</h1>\n <p className=\"text-sm text-muted-foreground\">Editing {project.name}</p>\n </div>\n </div>\n <Button size=\"sm\" onClick={handleSave} disabled={saving || invalidDates}>\n <Save className=\"mr-1 h-4 w-4\" />\n {saving ? 'Saving...' : 'Save Changes'}\n </Button>\n </div>\n\n {successMessage && (\n <div role=\"status\" className=\"p-3 bg-muted text-status-success-text rounded-md text-sm\">\n {successMessage}\n </div>\n )}\n {saveError && (\n <div role=\"alert\" className=\"p-3 bg-destructive/10 text-destructive rounded-md text-sm\">\n {saveError}\n </div>\n )}\n\n <Card>\n <CardHeader>\n <CardTitle>Project Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label className=\"text-sm font-medium\">Project Name</label>\n <Input\n value={form.name}\n onChange={(e) => setForm({ ...form, name: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Description</label>\n <textarea\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[80px]\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Methodology</label>\n <select\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm capitalize\"\n value={form.methodology}\n onChange={(e) => setForm({ ...form, methodology: e.target.value })}\n >\n {methodologies.map((m) => (\n <option key={m} value={m}>\n {m.toLowerCase()}\n </option>\n ))}\n </select>\n </div>\n <div>\n {/* BOFF-7940: the form had no Status, so a project could never leave PLANNING. */}\n <label htmlFor=\"project-status\" className=\"text-sm font-medium\">\n Status\n </label>\n <select\n id=\"project-status\"\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm\"\n value={form.status}\n onChange={(e) => setForm({ ...form, status: e.target.value })}\n >\n {((PROJECT_STATUSES as readonly string[]).includes(form.status)\n ? PROJECT_STATUSES\n : [form.status, ...PROJECT_STATUSES]\n ).map((s) => (\n <option key={s} value={s}>\n {enumLabel(s)}\n </option>\n ))}\n </select>\n </div>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label htmlFor=\"project-start\" className=\"text-sm font-medium\">\n Start Date\n </label>\n <Input\n id=\"project-start\"\n type=\"date\"\n value={form.startDate}\n max={form.endDate || undefined}\n onChange={(e) => setForm({ ...form, startDate: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n <div>\n <label htmlFor=\"project-end\" className=\"text-sm font-medium\">\n End Date\n </label>\n <Input\n id=\"project-end\"\n type=\"date\"\n value={form.endDate}\n min={form.startDate || undefined}\n onChange={(e) => setForm({ ...form, endDate: e.target.value })}\n aria-invalid={invalidDates}\n className=\"mt-1\"\n />\n </div>\n </div>\n {invalidDates && (\n <p role=\"alert\" className=\"text-sm text-destructive\">\n The end date is before the start date.\n </p>\n )}\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ProjectsEditProjectPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProjectsEditProjectPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState, useMemo } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery, useMutation } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Button, Input } from '@burdenoff/fe-libs/ui';\nimport { Save, ArrowLeft } from 'lucide-react';\nimport { useEntityId } from '../hooks/useEntityId';\nimport { usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { detailPath } from '../utils/rowNavigation';\nimport { throwOnError } from '../utils/mutationResult';\nimport { endBeforeStart } from '../utils/formValidation';\nimport { PROJECT_STATUSES } from '../controls/ProjectControls';\nimport { enumLabel } from '../controls/WorkItemControls';\nimport { ProgramSelect } from '../controls/Pickers';\n\nconst GET_PROJECTS = gql`\n query GetProjectsForEdit($id: ID!) {\n planmagnetProject(id: $id) {\n id\n name\n key\n description\n status\n methodology\n ownerId\n startDate\n endDate\n tags\n programId\n }\n }\n`;\n\nconst UPDATE_PROJECT = gql`\n mutation UpdateProject($id: ID!, $input: PlanmagnetUpdateProjectInput!) {\n planmagnetUpdateProject(id: $id, input: $input) {\n id\n name\n key\n description\n status\n methodology\n ownerId\n startDate\n endDate\n tags\n programId\n program {\n id\n name\n }\n }\n }\n`;\n\nexport function ProjectsEditProjectPagePage() {\n const projectId = useEntityId('projectId');\n const navigate = usePlanMagnetNavigate();\n\n const {\n data,\n loading,\n error,\n } = // eslint-disable-next-line @typescript-eslint/no-explicit-any\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n useQuery<Record<string, any>>(GET_PROJECTS, {\n variables: { id: projectId },\n skip: !projectId,\n });\n\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n\n const project = data?.planmagnetProject;\n\n const defaultForm = useMemo(\n () => ({\n name: project?.name ?? '',\n description: project?.description ?? '',\n methodology: project?.methodology ?? 'SCRUM',\n status: project?.status ?? 'PLANNING',\n startDate: project?.startDate ? project.startDate.split('T')[0] : '',\n endDate: project?.endDate ? project.endDate.split('T')[0] : '',\n programId: project?.programId ?? '',\n }),\n [project]\n );\n\n const [formOverrides, setFormOverrides] = useState<Record<string, string>>({});\n const form = { ...defaultForm, ...formOverrides };\n const setForm = (updates: Record<string, string>) => setFormOverrides(updates);\n\n // Success only after the service accepted the change (errorPolicy 'all' resolves refused mutations).\n const [updateProject, { loading: saving }] = useMutation(UPDATE_PROJECT, {\n refetchQueries: [\n 'GetProjects',\n 'GetActiveProjects',\n 'GetDashboardData',\n 'GetProjectsForEdit',\n 'GetProjectDetail',\n 'AdminPlanmagnetProjects',\n 'GetProgram',\n 'ListPrograms',\n ],\n });\n const [saveError, setSaveError] = useState<string | null>(null);\n const invalidDates = endBeforeStart(form.startDate, form.endDate);\n\n const methodologies = ['SCRUM', 'KANBAN', 'WATERFALL', 'HYBRID', 'AGILE', 'CUSTOM'] as const;\n\n const handleSave = async () => {\n if (!project || invalidDates) return;\n setSaveError(null);\n setSuccessMessage(null);\n // Dates are sent only when they were changed: the service checks the pair the project would end up\n // with, so re-sending untouched dates of an older project stored with inverted dates would refuse a\n // plain rename (BOFF-7833).\n const dateChanges = {\n ...(form.startDate !== defaultForm.startDate && { startDate: form.startDate || undefined }),\n ...(form.endDate !== defaultForm.endDate && { endDate: form.endDate || undefined }),\n };\n try {\n await throwOnError(\n updateProject({\n variables: {\n id: project.id,\n input: {\n name: form.name || undefined,\n description: form.description || undefined,\n methodology: form.methodology || undefined,\n // Only when changed: a status set elsewhere meanwhile (the detail page's select) is not overwritten.\n ...(form.status !== defaultForm.status && { status: form.status }),\n ...dateChanges,\n // Only when changed: '' clears it, so an unattached project stays unattached rather than being\n // re-sent as undefined (which the service would leave alone, not clear).\n ...(form.programId !== defaultForm.programId && {\n programId: form.programId || null,\n }),\n },\n },\n })\n );\n setSuccessMessage('Project updated successfully.');\n } catch (e) {\n setSaveError(e instanceof Error ? e.message : 'The project could not be saved.');\n }\n };\n\n if (!projectId)\n return (\n <div className=\"p-6 text-muted-foreground\">No project selected. Open one from the list.</div>\n );\n // Only before the first load: a refetch must not blank the page (it\n // unmounts every component on it and loses their state).\n if (loading && !data)\n return (\n <div className=\"flex items-center justify-center p-12\">\n <div className=\"animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full\" />\n </div>\n );\n if (error)\n return <div className=\"p-6 text-destructive\">Error loading project: {error.message}</div>;\n if (!project) return <div className=\"p-6 text-muted-foreground\">Project not found.</div>;\n\n return (\n <div className=\"space-y-6 p-6 max-w-4xl\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label=\"Back to the project\"\n onClick={() => navigate(detailPath('/projects/project-detail-page', projectId))}\n >\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n <div>\n <h1 className=\"text-2xl font-semibold\">Edit Project</h1>\n <p className=\"text-sm text-muted-foreground\">Editing {project.name}</p>\n </div>\n </div>\n <Button size=\"sm\" onClick={handleSave} disabled={saving || invalidDates}>\n <Save className=\"mr-1 h-4 w-4\" />\n {saving ? 'Saving...' : 'Save Changes'}\n </Button>\n </div>\n\n {successMessage && (\n <div role=\"status\" className=\"p-3 bg-muted text-status-success-text rounded-md text-sm\">\n {successMessage}\n </div>\n )}\n {saveError && (\n <div role=\"alert\" className=\"p-3 bg-destructive/10 text-destructive rounded-md text-sm\">\n {saveError}\n </div>\n )}\n\n <Card>\n <CardHeader>\n <CardTitle>Project Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label className=\"text-sm font-medium\">Project Name</label>\n <Input\n value={form.name}\n onChange={(e) => setForm({ ...form, name: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Description</label>\n <textarea\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[80px]\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Methodology</label>\n <select\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm capitalize\"\n value={form.methodology}\n onChange={(e) => setForm({ ...form, methodology: e.target.value })}\n >\n {methodologies.map((m) => (\n <option key={m} value={m}>\n {m.toLowerCase()}\n </option>\n ))}\n </select>\n </div>\n <div>\n {/* BOFF-8047: attach or detach this project's program. Programs were `api-only` before this. */}\n <label htmlFor=\"project-program\" className=\"text-sm font-medium\">\n Program\n </label>\n <div className=\"mt-1\">\n <ProgramSelect\n id=\"project-program\"\n value={form.programId}\n onChange={(programId) => setForm({ ...form, programId })}\n noneLabel=\"No program\"\n />\n </div>\n </div>\n <div>\n {/* BOFF-7940: the form had no Status, so a project could never leave PLANNING. */}\n <label htmlFor=\"project-status\" className=\"text-sm font-medium\">\n Status\n </label>\n <select\n id=\"project-status\"\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm\"\n value={form.status}\n onChange={(e) => setForm({ ...form, status: e.target.value })}\n >\n {((PROJECT_STATUSES as readonly string[]).includes(form.status)\n ? PROJECT_STATUSES\n : [form.status, ...PROJECT_STATUSES]\n ).map((s) => (\n <option key={s} value={s}>\n {enumLabel(s)}\n </option>\n ))}\n </select>\n </div>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label htmlFor=\"project-start\" className=\"text-sm font-medium\">\n Start Date\n </label>\n <Input\n id=\"project-start\"\n type=\"date\"\n value={form.startDate}\n max={form.endDate || undefined}\n onChange={(e) => setForm({ ...form, startDate: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n <div>\n <label htmlFor=\"project-end\" className=\"text-sm font-medium\">\n End Date\n </label>\n <Input\n id=\"project-end\"\n type=\"date\"\n value={form.endDate}\n min={form.startDate || undefined}\n onChange={(e) => setForm({ ...form, endDate: e.target.value })}\n aria-invalid={invalidDates}\n className=\"mt-1\"\n />\n </div>\n </div>\n {invalidDates && (\n <p role=\"alert\" className=\"text-sm text-destructive\">\n The end date is before the start date.\n </p>\n )}\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ProjectsProjectDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProjectsProjectDetailPagePage.tsx"],"names":[],"mappings":"AA2EA,wBAAgB,6BAA6B,4CAwV5C"}
1
+ {"version":3,"file":"ProjectsProjectDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProjectsProjectDetailPagePage.tsx"],"names":[],"mappings":"AAgFA,wBAAgB,6BAA6B,4CAwW5C"}