@burdenoff/microfe-planmagnet 2026.926.1 → 2026.926.2

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 (49) hide show
  1. package/dist/planmagnet/PlanMagnetRoot.d.ts.map +1 -1
  2. package/dist/planmagnet/PlanMagnetRoot.js +90 -79
  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 +124 -127
  6. package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
  7. package/dist/planmagnet/create/CreateDialogs.d.ts.map +1 -1
  8. package/dist/planmagnet/create/CreateDialogs.js +149 -124
  9. package/dist/planmagnet/create/CreateDialogs.js.map +1 -1
  10. package/dist/planmagnet/pages/NotFoundPage.d.ts +6 -0
  11. package/dist/planmagnet/pages/NotFoundPage.d.ts.map +1 -0
  12. package/dist/planmagnet/pages/NotFoundPage.js +18 -0
  13. package/dist/planmagnet/pages/NotFoundPage.js.map +1 -0
  14. package/dist/planmagnet/pages/ProductsNewFeaturePagePage.d.ts.map +1 -1
  15. package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js +103 -87
  16. package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js.map +1 -1
  17. package/dist/planmagnet/pages/ProjectsCreateProjectPagePage.d.ts.map +1 -1
  18. package/dist/planmagnet/pages/ProjectsCreateProjectPagePage.js +111 -91
  19. package/dist/planmagnet/pages/ProjectsCreateProjectPagePage.js.map +1 -1
  20. package/dist/planmagnet/pages/ProjectsEditProjectPagePage.d.ts.map +1 -1
  21. package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js +117 -97
  22. package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js.map +1 -1
  23. package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.d.ts.map +1 -1
  24. package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.js +133 -107
  25. package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.js.map +1 -1
  26. package/dist/planmagnet/pages/TasksCreateTaskPagePage.d.ts.map +1 -1
  27. package/dist/planmagnet/pages/TasksCreateTaskPagePage.js +161 -115
  28. package/dist/planmagnet/pages/TasksCreateTaskPagePage.js.map +1 -1
  29. package/dist/planmagnet/pages/TasksEditTaskPagePage.d.ts.map +1 -1
  30. package/dist/planmagnet/pages/TasksEditTaskPagePage.js +117 -102
  31. package/dist/planmagnet/pages/TasksEditTaskPagePage.js.map +1 -1
  32. package/dist/planmagnet/pages/TeamInviteMemberPagePage.d.ts.map +1 -1
  33. package/dist/planmagnet/pages/TeamInviteMemberPagePage.js +147 -147
  34. package/dist/planmagnet/pages/TeamInviteMemberPagePage.js.map +1 -1
  35. package/dist/planmagnet/pages/TeamTeamPagePage.d.ts.map +1 -1
  36. package/dist/planmagnet/pages/TeamTeamPagePage.js +77 -67
  37. package/dist/planmagnet/pages/TeamTeamPagePage.js.map +1 -1
  38. package/dist/planmagnet/sprints/SprintControls.d.ts.map +1 -1
  39. package/dist/planmagnet/sprints/SprintControls.js +48 -29
  40. package/dist/planmagnet/sprints/SprintControls.js.map +1 -1
  41. package/dist/planmagnet/utils/email.d.ts +9 -0
  42. package/dist/planmagnet/utils/email.d.ts.map +1 -0
  43. package/dist/planmagnet/utils/email.js +15 -0
  44. package/dist/planmagnet/utils/email.js.map +1 -0
  45. package/dist/planmagnet/utils/formValidation.d.ts +18 -0
  46. package/dist/planmagnet/utils/formValidation.d.ts.map +1 -0
  47. package/dist/planmagnet/utils/formValidation.js +17 -0
  48. package/dist/planmagnet/utils/formValidation.js.map +1 -0
  49. package/package.json +1 -1
@@ -1,15 +1,16 @@
1
1
  import { usePlanMagnet as e } from "../providers/PlanMagnetProvider.js";
2
2
  import { throwOnError as t } from "../utils/mutationResult.js";
3
- import { useEntityId as n } from "../hooks/useEntityId.js";
4
- import { SprintLifecycleActions as r } from "../sprints/SprintControls.js";
5
- import { useMemo as i, useState as a } from "react";
6
- import { ArrowLeft as o, Save as s } from "lucide-react";
7
- import { gql as c } from "@apollo/client";
8
- import { useMutation as l, useQuery as u } from "@apollo/client/react";
9
- import { jsx as d, jsxs as f } from "react/jsx-runtime";
10
- import { Button as p, Card as m, CardContent as h, CardHeader as g, CardTitle as _, Input as v } from "@burdenoff/fe-libs/ui";
3
+ import { endBeforeStart as n, parseIntField as r } from "../utils/formValidation.js";
4
+ import { useEntityId as i } from "../hooks/useEntityId.js";
5
+ import { SprintLifecycleActions as a } from "../sprints/SprintControls.js";
6
+ import { useMemo as o, useState as s } from "react";
7
+ import { ArrowLeft as c, Save as l } from "lucide-react";
8
+ import { gql as u } from "@apollo/client";
9
+ import { useMutation as d, useQuery as f } from "@apollo/client/react";
10
+ import { jsx as p, jsxs as m } from "react/jsx-runtime";
11
+ import { Button as h, Card as g, CardContent as _, CardHeader as v, CardTitle as y, Input as b } from "@burdenoff/fe-libs/ui";
11
12
  //#region src/planmagnet/pages/ProjectsPlanningEditPagePage.tsx
12
- var y = c`
13
+ var x = u`
13
14
  query GetSprintForEdit($id: ID!, $workspaceId: ID!) {
14
15
  planmagnetSprint(id: $id) {
15
16
  id
@@ -28,7 +29,7 @@ var y = c`
28
29
  }
29
30
  }
30
31
  }
31
- `, b = c`
32
+ `, S = u`
32
33
  mutation UpdateSprint($id: ID!, $input: PlanmagnetUpdateSprintInput!) {
33
34
  planmagnetUpdateSprint(id: $id, input: $input) {
34
35
  id
@@ -41,193 +42,218 @@ var y = c`
41
42
  }
42
43
  }
43
44
  `;
44
- function x() {
45
- let { workspaceId: c } = e(), x = n("sprintId"), { data: S, loading: C, error: w } = u(y, {
45
+ function C() {
46
+ let { workspaceId: u } = e(), C = i("sprintId"), { data: w, loading: T, error: E } = f(x, {
46
47
  variables: {
47
- id: x,
48
- workspaceId: c ?? "default"
48
+ id: C,
49
+ workspaceId: u ?? "default"
49
50
  },
50
- skip: !x
51
- }), [T, E] = a(null), D = S?.planmagnetSprint, O = S?.planmagnetProjects?.items ?? [], k = i(() => ({
52
- name: D?.name ?? "",
53
- startDate: D?.startDate ? D.startDate.split("T")[0] : "",
54
- endDate: D?.endDate ? D.endDate.split("T")[0] : "",
55
- goal: D?.goal ?? "",
56
- capacity: D?.capacity?.toString() ?? ""
57
- }), [D]), [A, j] = a({}), M = {
58
- ...k,
59
- ...A
60
- }, N = (e) => j((t) => {
51
+ skip: !C
52
+ }), [D, O] = s(null), k = w?.planmagnetSprint, A = w?.planmagnetProjects?.items ?? [], j = o(() => ({
53
+ name: k?.name ?? "",
54
+ startDate: k?.startDate ? k.startDate.split("T")[0] : "",
55
+ endDate: k?.endDate ? k.endDate.split("T")[0] : "",
56
+ goal: k?.goal ?? "",
57
+ capacity: k?.capacity?.toString() ?? ""
58
+ }), [k]), [M, N] = s({}), P = {
59
+ ...j,
60
+ ...M
61
+ }, F = (e) => N((t) => {
61
62
  let n = { ...t };
62
- for (let [t, r] of Object.entries(e)) r !== M[t] && (n[t] = r);
63
+ for (let [t, r] of Object.entries(e)) r !== P[t] && (n[t] = r);
63
64
  return n;
64
- }), [P, F] = a(null), [I, { loading: L }] = l(b, { refetchQueries: [
65
+ }), [I, L] = s(null), R = n(P.startDate, P.endDate), z = r(P.capacity, { min: 0 }), [B, { loading: V }] = d(S, { refetchQueries: [
65
66
  "GetSprints",
66
67
  "GetSprintDetail",
67
68
  "GetSprintForEdit",
68
69
  "GetDashboardData"
69
70
  ] });
70
- return x ? C && !S ? /* @__PURE__ */ d("div", {
71
+ return C ? T && !w ? /* @__PURE__ */ p("div", {
71
72
  className: "flex items-center justify-center p-12",
72
- children: /* @__PURE__ */ d("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
73
- }) : w ? /* @__PURE__ */ f("div", {
74
- className: "p-6 text-red-500",
75
- children: ["Error loading sprint: ", w.message]
76
- }) : D ? /* @__PURE__ */ f("div", {
73
+ children: /* @__PURE__ */ p("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
74
+ }) : E ? /* @__PURE__ */ m("div", {
75
+ className: "p-6 text-destructive",
76
+ children: ["Error loading sprint: ", E.message]
77
+ }) : k ? /* @__PURE__ */ m("div", {
77
78
  className: "space-y-6 p-6 max-w-4xl",
78
79
  children: [
79
- /* @__PURE__ */ f("div", {
80
+ /* @__PURE__ */ m("div", {
80
81
  className: "flex items-center justify-between",
81
- children: [/* @__PURE__ */ f("div", {
82
+ children: [/* @__PURE__ */ m("div", {
82
83
  className: "flex items-center gap-3",
83
- children: [/* @__PURE__ */ d(p, {
84
+ children: [/* @__PURE__ */ p(h, {
84
85
  variant: "ghost",
85
86
  size: "sm",
86
- children: /* @__PURE__ */ d(o, { className: "h-4 w-4" })
87
- }), /* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("h1", {
87
+ children: /* @__PURE__ */ p(c, { className: "h-4 w-4" })
88
+ }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("h1", {
88
89
  className: "text-2xl font-semibold",
89
90
  children: "Edit Planning Session"
90
- }), /* @__PURE__ */ d("p", {
91
+ }), /* @__PURE__ */ p("p", {
91
92
  className: "text-sm text-muted-foreground",
92
- children: D.name
93
+ children: k.name
93
94
  })] })]
94
- }), /* @__PURE__ */ f(p, {
95
+ }), /* @__PURE__ */ m(h, {
95
96
  size: "sm",
96
97
  onClick: async () => {
97
- if (!D) return;
98
- F(null), E(null);
98
+ if (!k || R || z.invalid) return;
99
+ L(null), O(null);
99
100
  let e = {
100
- ...M.startDate !== k.startDate && M.startDate ? { startDate: M.startDate } : {},
101
- ...M.endDate !== k.endDate && M.endDate ? { endDate: M.endDate } : {}
101
+ ...P.startDate !== j.startDate && P.startDate ? { startDate: P.startDate } : {},
102
+ ...P.endDate !== j.endDate && P.endDate ? { endDate: P.endDate } : {}
102
103
  };
103
104
  try {
104
- await t(I({ variables: {
105
- id: D.id,
105
+ await t(B({ variables: {
106
+ id: k.id,
106
107
  input: {
107
- name: M.name || void 0,
108
+ name: P.name || void 0,
108
109
  ...e,
109
- goal: M.goal || void 0,
110
- capacity: M.capacity ? parseInt(M.capacity, 10) : void 0
110
+ goal: P.goal || void 0,
111
+ capacity: z.value
111
112
  }
112
- } })), E("Sprint updated successfully."), j({});
113
+ } })), O("Sprint updated successfully."), N({});
113
114
  } catch (e) {
114
- F(e instanceof Error ? e.message : "The sprint could not be saved.");
115
+ L(e instanceof Error ? e.message : "The sprint could not be saved.");
115
116
  }
116
117
  },
117
- disabled: L,
118
- children: [/* @__PURE__ */ d(s, { className: "mr-1 h-4 w-4" }), L ? "Saving..." : "Save Changes"]
118
+ disabled: V || R || z.invalid,
119
+ children: [/* @__PURE__ */ p(l, { className: "mr-1 h-4 w-4" }), V ? "Saving..." : "Save Changes"]
119
120
  })]
120
121
  }),
121
- T && /* @__PURE__ */ d("div", {
122
+ D && /* @__PURE__ */ p("div", {
122
123
  role: "status",
123
124
  className: "p-3 rounded-md text-sm bg-muted text-status-success-text",
124
- children: T
125
+ children: D
125
126
  }),
126
- P && /* @__PURE__ */ f("div", {
127
+ I && /* @__PURE__ */ m("div", {
127
128
  role: "alert",
128
129
  className: "p-3 rounded-md text-sm bg-destructive/10 text-destructive",
129
- children: ["Error: ", P]
130
+ children: ["Error: ", I]
130
131
  }),
131
- /* @__PURE__ */ f(m, { children: [/* @__PURE__ */ d(g, { children: /* @__PURE__ */ d(_, { children: "Session Details" }) }), /* @__PURE__ */ f(h, {
132
+ /* @__PURE__ */ m(g, { children: [/* @__PURE__ */ p(v, { children: /* @__PURE__ */ p(y, { children: "Session Details" }) }), /* @__PURE__ */ m(_, {
132
133
  className: "space-y-4",
133
134
  children: [
134
- /* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("label", {
135
+ /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
135
136
  className: "text-sm font-medium",
136
137
  children: "Name"
137
- }), /* @__PURE__ */ d(v, {
138
- value: M.name,
139
- onChange: (e) => N({
140
- ...M,
138
+ }), /* @__PURE__ */ p(b, {
139
+ value: P.name,
140
+ onChange: (e) => F({
141
+ ...P,
141
142
  name: e.target.value
142
143
  }),
143
144
  className: "mt-1"
144
145
  })] }),
145
- /* @__PURE__ */ f("div", {
146
+ /* @__PURE__ */ m("div", {
146
147
  className: "grid grid-cols-2 gap-4",
147
- children: [/* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("label", {
148
+ children: [/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
148
149
  className: "text-sm font-medium",
149
150
  children: "Project"
150
- }), /* @__PURE__ */ d("div", {
151
+ }), /* @__PURE__ */ p("div", {
151
152
  className: "mt-1 w-full rounded-md border border-input bg-muted px-3 py-2 text-sm text-muted-foreground",
152
- children: O.find((e) => e.id === D.projectId)?.name ?? D.projectId
153
- })] }), /* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("label", {
153
+ children: A.find((e) => e.id === k.projectId)?.name ?? k.projectId
154
+ })] }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
154
155
  className: "text-sm font-medium",
155
156
  children: "Status"
156
- }), /* @__PURE__ */ f("div", {
157
+ }), /* @__PURE__ */ m("div", {
157
158
  className: "mt-1 flex items-start justify-between gap-2",
158
- children: [/* @__PURE__ */ d("span", {
159
+ children: [/* @__PURE__ */ p("span", {
159
160
  className: "rounded-md border border-input bg-muted px-3 py-2 text-sm text-muted-foreground capitalize",
160
- children: D.status.toLowerCase().replace(/_/g, " ")
161
- }), /* @__PURE__ */ d(r, {
162
- sprintId: D.id,
163
- sprintName: D.name,
164
- status: D.status
161
+ children: k.status.toLowerCase().replace(/_/g, " ")
162
+ }), /* @__PURE__ */ p(a, {
163
+ sprintId: k.id,
164
+ sprintName: k.name,
165
+ status: k.status
165
166
  })]
166
167
  })] })]
167
168
  }),
168
- /* @__PURE__ */ f("div", {
169
+ /* @__PURE__ */ m("div", {
169
170
  className: "grid grid-cols-2 gap-4",
170
- children: [/* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("label", {
171
+ children: [/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
172
+ htmlFor: "sprint-start",
171
173
  className: "text-sm font-medium",
172
174
  children: "Start Date"
173
- }), /* @__PURE__ */ d(v, {
175
+ }), /* @__PURE__ */ p(b, {
176
+ id: "sprint-start",
174
177
  type: "date",
175
- value: M.startDate,
176
- onChange: (e) => N({
177
- ...M,
178
+ value: P.startDate,
179
+ max: P.endDate || void 0,
180
+ onChange: (e) => F({
181
+ ...P,
178
182
  startDate: e.target.value
179
183
  }),
180
184
  className: "mt-1"
181
- })] }), /* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("label", {
185
+ })] }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
186
+ htmlFor: "sprint-end",
182
187
  className: "text-sm font-medium",
183
188
  children: "End Date"
184
- }), /* @__PURE__ */ d(v, {
189
+ }), /* @__PURE__ */ p(b, {
190
+ id: "sprint-end",
185
191
  type: "date",
186
- value: M.endDate,
187
- onChange: (e) => N({
188
- ...M,
192
+ value: P.endDate,
193
+ min: P.startDate || void 0,
194
+ onChange: (e) => F({
195
+ ...P,
189
196
  endDate: e.target.value
190
197
  }),
198
+ "aria-invalid": R,
191
199
  className: "mt-1"
192
200
  })] })]
193
201
  }),
194
- /* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("label", {
202
+ R && /* @__PURE__ */ p("p", {
203
+ role: "alert",
204
+ className: "text-sm text-destructive",
205
+ children: "The end date is before the start date."
206
+ }),
207
+ /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
195
208
  className: "text-sm font-medium",
196
209
  children: "Goal"
197
- }), /* @__PURE__ */ d("textarea", {
210
+ }), /* @__PURE__ */ p("textarea", {
198
211
  className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[60px]",
199
- value: M.goal,
200
- onChange: (e) => N({
201
- ...M,
212
+ value: P.goal,
213
+ onChange: (e) => F({
214
+ ...P,
202
215
  goal: e.target.value
203
216
  }),
204
217
  placeholder: "Sprint goal..."
205
218
  })] }),
206
- /* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("label", {
207
- className: "text-sm font-medium",
208
- children: "Capacity (story points)"
209
- }), /* @__PURE__ */ d(v, {
210
- type: "number",
211
- value: M.capacity,
212
- onChange: (e) => N({
213
- ...M,
214
- capacity: e.target.value
219
+ /* @__PURE__ */ m("div", { children: [
220
+ /* @__PURE__ */ p("label", {
221
+ htmlFor: "sprint-capacity",
222
+ className: "text-sm font-medium",
223
+ children: "Capacity (story points)"
224
+ }),
225
+ /* @__PURE__ */ p(b, {
226
+ id: "sprint-capacity",
227
+ type: "number",
228
+ min: 0,
229
+ step: 1,
230
+ value: P.capacity,
231
+ onChange: (e) => F({
232
+ ...P,
233
+ capacity: e.target.value
234
+ }),
235
+ "aria-invalid": z.invalid,
236
+ className: "mt-1",
237
+ placeholder: "e.g. 40"
215
238
  }),
216
- className: "mt-1",
217
- placeholder: "e.g. 40"
218
- })] })
239
+ z.invalid && /* @__PURE__ */ p("p", {
240
+ role: "alert",
241
+ className: "mt-1 text-xs text-destructive",
242
+ children: "Capacity must be a whole number, 0 or more."
243
+ })
244
+ ] })
219
245
  ]
220
246
  })] })
221
247
  ]
222
- }) : /* @__PURE__ */ d("div", {
248
+ }) : /* @__PURE__ */ p("div", {
223
249
  className: "p-6 text-muted-foreground",
224
250
  children: "Planning session not found."
225
- }) : /* @__PURE__ */ d("div", {
251
+ }) : /* @__PURE__ */ p("div", {
226
252
  className: "p-6 text-muted-foreground",
227
253
  children: "No planning session selected. Open one from the list."
228
254
  });
229
255
  }
230
256
  //#endregion
231
- export { x as ProjectsPlanningEditPagePage };
257
+ export { C as ProjectsPlanningEditPagePage };
232
258
 
233
259
  //# sourceMappingURL=ProjectsPlanningEditPagePage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ProjectsPlanningEditPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProjectsPlanningEditPagePage.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 { usePlanMagnet } from '../providers/PlanMagnetProvider';\nimport { useEntityId } from '../hooks/useEntityId';\nimport { SprintLifecycleActions } from '../sprints/SprintControls';\nimport { throwOnError } from '../utils/mutationResult';\n\nconst GET_SPRINT_FOR_EDIT = gql`\n query GetSprintForEdit($id: ID!, $workspaceId: ID!) {\n planmagnetSprint(id: $id) {\n id\n name\n projectId\n status\n startDate\n endDate\n goal\n capacity\n }\n planmagnetProjects(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n }\n }\n }\n`;\n\nconst UPDATE_SPRINT = gql`\n mutation UpdateSprint($id: ID!, $input: PlanmagnetUpdateSprintInput!) {\n planmagnetUpdateSprint(id: $id, input: $input) {\n id\n name\n status\n startDate\n endDate\n goal\n capacity\n }\n }\n`;\n\nexport function ProjectsPlanningEditPagePage() {\n const { workspaceId } = usePlanMagnet();\n const sprintId = useEntityId('sprintId');\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_SPRINT_FOR_EDIT, {\n variables: { id: sprintId, workspaceId: workspaceId ?? 'default' },\n skip: !sprintId,\n });\n\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n\n const sprint = data?.planmagnetSprint;\n const projects = data?.planmagnetProjects?.items ?? [];\n\n const defaultForm = useMemo(\n () => ({\n name: sprint?.name ?? '',\n startDate: sprint?.startDate ? sprint.startDate.split('T')[0] : '',\n endDate: sprint?.endDate ? sprint.endDate.split('T')[0] : '',\n goal: sprint?.goal ?? '',\n capacity: sprint?.capacity?.toString() ?? '',\n }),\n [sprint]\n );\n\n const [formOverrides, setFormOverrides] = useState<Record<string, string>>({});\n const form = { ...defaultForm, ...formOverrides };\n // Keep ONLY the fields the user actually edited. Callers pass the whole form\n // ({ ...form, field }); copying every field made untouched dates stale\n // snapshots, so after a refetch (e.g. a CONFLICT) a retry re-sent the old\n // dates and silently reverted a teammate's replan (BOFF-7918 review).\n const setForm = (updates: Record<string, string>) =>\n setFormOverrides((prev) => {\n const next = { ...prev };\n for (const [key, value] of Object.entries(updates)) {\n if (value !== form[key as keyof typeof form]) next[key] = value;\n }\n return next;\n });\n\n const [saveError, setSaveError] = useState<string | null>(null);\n const [updateSprint, { loading: saving }] = useMutation(UPDATE_SPRINT, {\n refetchQueries: ['GetSprints', 'GetSprintDetail', 'GetSprintForEdit', 'GetDashboardData'],\n });\n\n const handleSave = async () => {\n if (!sprint) return;\n setSaveError(null);\n setSuccessMessage(null);\n // Send the planned dates only when the user changed them (BOFF-7918).\n // Every change to a planned date is recorded in the sprint's plan history,\n // so re-sending unchanged dates on a rename must not look like a replan.\n const dateChanges = {\n ...(form.startDate !== defaultForm.startDate && form.startDate\n ? { startDate: form.startDate }\n : {}),\n ...(form.endDate !== defaultForm.endDate && form.endDate ? { endDate: form.endDate } : {}),\n };\n try {\n await throwOnError(\n updateSprint({\n variables: {\n id: sprint.id,\n input: {\n name: form.name || undefined,\n ...dateChanges,\n goal: form.goal || undefined,\n capacity: form.capacity ? parseInt(form.capacity, 10) : undefined,\n },\n },\n })\n );\n // Only after the service ACCEPTED it: under fe-libs' errorPolicy 'all' a\n // refused save resolves, and onCompleted reported success for it.\n setSuccessMessage('Sprint updated successfully.');\n setFormOverrides({});\n } catch (e) {\n setSaveError(e instanceof Error ? e.message : 'The sprint could not be saved.');\n }\n };\n\n if (!sprintId)\n return (\n <div className=\"p-6 text-muted-foreground\">\n No planning session selected. Open one from the list.\n </div>\n );\n // Only before the first load: a refetch after a sprint action must not blank\n // the page (it unmounted the controls mid-action).\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) return <div className=\"p-6 text-red-500\">Error loading sprint: {error.message}</div>;\n if (!sprint) return <div className=\"p-6 text-muted-foreground\">Planning session 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 variant=\"ghost\" size=\"sm\">\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n <div>\n <h1 className=\"text-2xl font-semibold\">Edit Planning Session</h1>\n <p className=\"text-sm text-muted-foreground\">{sprint.name}</p>\n </div>\n </div>\n <Button size=\"sm\" onClick={handleSave} disabled={saving}>\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 rounded-md text-sm bg-muted text-status-success-text\">\n {successMessage}\n </div>\n )}\n {saveError && (\n <div role=\"alert\" className=\"p-3 rounded-md text-sm bg-destructive/10 text-destructive\">\n Error: {saveError}\n </div>\n )}\n\n <Card>\n <CardHeader>\n <CardTitle>Session Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label className=\"text-sm font-medium\">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 className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"text-sm font-medium\">Project</label>\n <div className=\"mt-1 w-full rounded-md border border-input bg-muted px-3 py-2 text-sm text-muted-foreground\">\n {projects.find((p: { id: string; name: string }) => p.id === sprint.projectId)\n ?.name ?? sprint.projectId}\n </div>\n </div>\n <div>\n {/* Status is not an editable field: planmagnetUpdateSprint does not\n accept it, and sending it failed EVERY save on this page. It\n changes only through the guarded lifecycle actions. */}\n <label className=\"text-sm font-medium\">Status</label>\n <div className=\"mt-1 flex items-start justify-between gap-2\">\n <span className=\"rounded-md border border-input bg-muted px-3 py-2 text-sm text-muted-foreground capitalize\">\n {sprint.status.toLowerCase().replace(/_/g, ' ')}\n </span>\n <SprintLifecycleActions\n sprintId={sprint.id}\n sprintName={sprint.name}\n status={sprint.status}\n />\n </div>\n </div>\n </div>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"text-sm font-medium\">Start Date</label>\n <Input\n type=\"date\"\n value={form.startDate}\n onChange={(e) => setForm({ ...form, startDate: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">End Date</label>\n <Input\n type=\"date\"\n value={form.endDate}\n onChange={(e) => setForm({ ...form, endDate: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n </div>\n <div>\n <label className=\"text-sm font-medium\">Goal</label>\n <textarea\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.goal}\n onChange={(e) => setForm({ ...form, goal: e.target.value })}\n placeholder=\"Sprint goal...\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Capacity (story points)</label>\n <Input\n type=\"number\"\n value={form.capacity}\n onChange={(e) => setForm({ ...form, capacity: e.target.value })}\n className=\"mt-1\"\n placeholder=\"e.g. 40\"\n />\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ProjectsPlanningEditPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProjectsPlanningEditPagePage.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 { usePlanMagnet } from '../providers/PlanMagnetProvider';\nimport { useEntityId } from '../hooks/useEntityId';\nimport { SprintLifecycleActions } from '../sprints/SprintControls';\nimport { throwOnError } from '../utils/mutationResult';\nimport { endBeforeStart, parseIntField } from '../utils/formValidation';\n\nconst GET_SPRINT_FOR_EDIT = gql`\n query GetSprintForEdit($id: ID!, $workspaceId: ID!) {\n planmagnetSprint(id: $id) {\n id\n name\n projectId\n status\n startDate\n endDate\n goal\n capacity\n }\n planmagnetProjects(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n }\n }\n }\n`;\n\nconst UPDATE_SPRINT = gql`\n mutation UpdateSprint($id: ID!, $input: PlanmagnetUpdateSprintInput!) {\n planmagnetUpdateSprint(id: $id, input: $input) {\n id\n name\n status\n startDate\n endDate\n goal\n capacity\n }\n }\n`;\n\nexport function ProjectsPlanningEditPagePage() {\n const { workspaceId } = usePlanMagnet();\n const sprintId = useEntityId('sprintId');\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_SPRINT_FOR_EDIT, {\n variables: { id: sprintId, workspaceId: workspaceId ?? 'default' },\n skip: !sprintId,\n });\n\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n\n const sprint = data?.planmagnetSprint;\n const projects = data?.planmagnetProjects?.items ?? [];\n\n const defaultForm = useMemo(\n () => ({\n name: sprint?.name ?? '',\n startDate: sprint?.startDate ? sprint.startDate.split('T')[0] : '',\n endDate: sprint?.endDate ? sprint.endDate.split('T')[0] : '',\n goal: sprint?.goal ?? '',\n capacity: sprint?.capacity?.toString() ?? '',\n }),\n [sprint]\n );\n\n const [formOverrides, setFormOverrides] = useState<Record<string, string>>({});\n const form = { ...defaultForm, ...formOverrides };\n // Keep ONLY the fields the user actually edited. Callers pass the whole form\n // ({ ...form, field }); copying every field made untouched dates stale\n // snapshots, so after a refetch (e.g. a CONFLICT) a retry re-sent the old\n // dates and silently reverted a teammate's replan (BOFF-7918 review).\n const setForm = (updates: Record<string, string>) =>\n setFormOverrides((prev) => {\n const next = { ...prev };\n for (const [key, value] of Object.entries(updates)) {\n if (value !== form[key as keyof typeof form]) next[key] = value;\n }\n return next;\n });\n\n const [saveError, setSaveError] = useState<string | null>(null);\n // BOFF-7833: the merged form is the plan the sprint would end up with (one side edited is compared with\n // the stored other side); the service enforces the same rules.\n const invalidDates = endBeforeStart(form.startDate, form.endDate);\n const capacity = parseIntField(form.capacity, { min: 0 });\n const [updateSprint, { loading: saving }] = useMutation(UPDATE_SPRINT, {\n refetchQueries: ['GetSprints', 'GetSprintDetail', 'GetSprintForEdit', 'GetDashboardData'],\n });\n\n const handleSave = async () => {\n if (!sprint || invalidDates || capacity.invalid) return;\n setSaveError(null);\n setSuccessMessage(null);\n // Send the planned dates only when the user changed them (BOFF-7918).\n // Every change to a planned date is recorded in the sprint's plan history,\n // so re-sending unchanged dates on a rename must not look like a replan.\n const dateChanges = {\n ...(form.startDate !== defaultForm.startDate && form.startDate\n ? { startDate: form.startDate }\n : {}),\n ...(form.endDate !== defaultForm.endDate && form.endDate ? { endDate: form.endDate } : {}),\n };\n try {\n await throwOnError(\n updateSprint({\n variables: {\n id: sprint.id,\n input: {\n name: form.name || undefined,\n ...dateChanges,\n goal: form.goal || undefined,\n capacity: capacity.value,\n },\n },\n })\n );\n // Only after the service ACCEPTED it: under fe-libs' errorPolicy 'all' a\n // refused save resolves, and onCompleted reported success for it.\n setSuccessMessage('Sprint updated successfully.');\n setFormOverrides({});\n } catch (e) {\n setSaveError(e instanceof Error ? e.message : 'The sprint could not be saved.');\n }\n };\n\n if (!sprintId)\n return (\n <div className=\"p-6 text-muted-foreground\">\n No planning session selected. Open one from the list.\n </div>\n );\n // Only before the first load: a refetch after a sprint action must not blank\n // the page (it unmounted the controls mid-action).\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 sprint: {error.message}</div>;\n if (!sprint) return <div className=\"p-6 text-muted-foreground\">Planning session 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 variant=\"ghost\" size=\"sm\">\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n <div>\n <h1 className=\"text-2xl font-semibold\">Edit Planning Session</h1>\n <p className=\"text-sm text-muted-foreground\">{sprint.name}</p>\n </div>\n </div>\n <Button\n size=\"sm\"\n onClick={handleSave}\n disabled={saving || invalidDates || capacity.invalid}\n >\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 rounded-md text-sm bg-muted text-status-success-text\">\n {successMessage}\n </div>\n )}\n {saveError && (\n <div role=\"alert\" className=\"p-3 rounded-md text-sm bg-destructive/10 text-destructive\">\n Error: {saveError}\n </div>\n )}\n\n <Card>\n <CardHeader>\n <CardTitle>Session Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label className=\"text-sm font-medium\">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 className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"text-sm font-medium\">Project</label>\n <div className=\"mt-1 w-full rounded-md border border-input bg-muted px-3 py-2 text-sm text-muted-foreground\">\n {projects.find((p: { id: string; name: string }) => p.id === sprint.projectId)\n ?.name ?? sprint.projectId}\n </div>\n </div>\n <div>\n {/* Status is not an editable field: planmagnetUpdateSprint does not\n accept it, and sending it failed EVERY save on this page. It\n changes only through the guarded lifecycle actions. */}\n <label className=\"text-sm font-medium\">Status</label>\n <div className=\"mt-1 flex items-start justify-between gap-2\">\n <span className=\"rounded-md border border-input bg-muted px-3 py-2 text-sm text-muted-foreground capitalize\">\n {sprint.status.toLowerCase().replace(/_/g, ' ')}\n </span>\n <SprintLifecycleActions\n sprintId={sprint.id}\n sprintName={sprint.name}\n status={sprint.status}\n />\n </div>\n </div>\n </div>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label htmlFor=\"sprint-start\" className=\"text-sm font-medium\">\n Start Date\n </label>\n <Input\n id=\"sprint-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=\"sprint-end\" className=\"text-sm font-medium\">\n End Date\n </label>\n <Input\n id=\"sprint-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 <div>\n <label className=\"text-sm font-medium\">Goal</label>\n <textarea\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.goal}\n onChange={(e) => setForm({ ...form, goal: e.target.value })}\n placeholder=\"Sprint goal...\"\n />\n </div>\n <div>\n <label htmlFor=\"sprint-capacity\" className=\"text-sm font-medium\">\n Capacity (story points)\n </label>\n <Input\n id=\"sprint-capacity\"\n type=\"number\"\n min={0}\n step={1}\n value={form.capacity}\n onChange={(e) => setForm({ ...form, capacity: e.target.value })}\n aria-invalid={capacity.invalid}\n className=\"mt-1\"\n placeholder=\"e.g. 40\"\n />\n {capacity.invalid && (\n <p role=\"alert\" className=\"mt-1 text-xs text-destructive\">\n Capacity must be a whole number, 0 or more.\n </p>\n )}\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"TasksCreateTaskPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/TasksCreateTaskPagePage.tsx"],"names":[],"mappings":"AAgDA,wBAAgB,uBAAuB,4CAkMtC"}
1
+ {"version":3,"file":"TasksCreateTaskPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/TasksCreateTaskPagePage.tsx"],"names":[],"mappings":"AAkDA,wBAAgB,uBAAuB,4CAkQtC"}