@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.
- package/dist/planmagnet/PlanMagnetRoot.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoot.js +90 -79
- package/dist/planmagnet/PlanMagnetRoot.js.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.js +124 -127
- package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
- package/dist/planmagnet/create/CreateDialogs.d.ts.map +1 -1
- package/dist/planmagnet/create/CreateDialogs.js +149 -124
- package/dist/planmagnet/create/CreateDialogs.js.map +1 -1
- package/dist/planmagnet/pages/NotFoundPage.d.ts +6 -0
- package/dist/planmagnet/pages/NotFoundPage.d.ts.map +1 -0
- package/dist/planmagnet/pages/NotFoundPage.js +18 -0
- package/dist/planmagnet/pages/NotFoundPage.js.map +1 -0
- package/dist/planmagnet/pages/ProductsNewFeaturePagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js +103 -87
- package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsCreateProjectPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsCreateProjectPagePage.js +111 -91
- package/dist/planmagnet/pages/ProjectsCreateProjectPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsEditProjectPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js +117 -97
- package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.js +133 -107
- package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksCreateTaskPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksCreateTaskPagePage.js +161 -115
- package/dist/planmagnet/pages/TasksCreateTaskPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksEditTaskPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksEditTaskPagePage.js +117 -102
- package/dist/planmagnet/pages/TasksEditTaskPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TeamInviteMemberPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TeamInviteMemberPagePage.js +147 -147
- package/dist/planmagnet/pages/TeamInviteMemberPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TeamTeamPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TeamTeamPagePage.js +77 -67
- package/dist/planmagnet/pages/TeamTeamPagePage.js.map +1 -1
- package/dist/planmagnet/sprints/SprintControls.d.ts.map +1 -1
- package/dist/planmagnet/sprints/SprintControls.js +48 -29
- package/dist/planmagnet/sprints/SprintControls.js.map +1 -1
- package/dist/planmagnet/utils/email.d.ts +9 -0
- package/dist/planmagnet/utils/email.d.ts.map +1 -0
- package/dist/planmagnet/utils/email.js +15 -0
- package/dist/planmagnet/utils/email.js.map +1 -0
- package/dist/planmagnet/utils/formValidation.d.ts +18 -0
- package/dist/planmagnet/utils/formValidation.d.ts.map +1 -0
- package/dist/planmagnet/utils/formValidation.js +17 -0
- package/dist/planmagnet/utils/formValidation.js.map +1 -0
- 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 {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
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
|
|
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
|
-
`,
|
|
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
|
|
45
|
-
let { workspaceId:
|
|
45
|
+
function C() {
|
|
46
|
+
let { workspaceId: u } = e(), C = i("sprintId"), { data: w, loading: T, error: E } = f(x, {
|
|
46
47
|
variables: {
|
|
47
|
-
id:
|
|
48
|
-
workspaceId:
|
|
48
|
+
id: C,
|
|
49
|
+
workspaceId: u ?? "default"
|
|
49
50
|
},
|
|
50
|
-
skip: !
|
|
51
|
-
}), [
|
|
52
|
-
name:
|
|
53
|
-
startDate:
|
|
54
|
-
endDate:
|
|
55
|
-
goal:
|
|
56
|
-
capacity:
|
|
57
|
-
}), [
|
|
58
|
-
...
|
|
59
|
-
...
|
|
60
|
-
},
|
|
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 !==
|
|
63
|
+
for (let [t, r] of Object.entries(e)) r !== P[t] && (n[t] = r);
|
|
63
64
|
return n;
|
|
64
|
-
}), [
|
|
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
|
|
71
|
+
return C ? T && !w ? /* @__PURE__ */ p("div", {
|
|
71
72
|
className: "flex items-center justify-center p-12",
|
|
72
|
-
children: /* @__PURE__ */
|
|
73
|
-
}) :
|
|
74
|
-
className: "p-6 text-
|
|
75
|
-
children: ["Error loading sprint: ",
|
|
76
|
-
}) :
|
|
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__ */
|
|
80
|
+
/* @__PURE__ */ m("div", {
|
|
80
81
|
className: "flex items-center justify-between",
|
|
81
|
-
children: [/* @__PURE__ */
|
|
82
|
+
children: [/* @__PURE__ */ m("div", {
|
|
82
83
|
className: "flex items-center gap-3",
|
|
83
|
-
children: [/* @__PURE__ */
|
|
84
|
+
children: [/* @__PURE__ */ p(h, {
|
|
84
85
|
variant: "ghost",
|
|
85
86
|
size: "sm",
|
|
86
|
-
children: /* @__PURE__ */
|
|
87
|
-
}), /* @__PURE__ */
|
|
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__ */
|
|
91
|
+
}), /* @__PURE__ */ p("p", {
|
|
91
92
|
className: "text-sm text-muted-foreground",
|
|
92
|
-
children:
|
|
93
|
+
children: k.name
|
|
93
94
|
})] })]
|
|
94
|
-
}), /* @__PURE__ */
|
|
95
|
+
}), /* @__PURE__ */ m(h, {
|
|
95
96
|
size: "sm",
|
|
96
97
|
onClick: async () => {
|
|
97
|
-
if (!
|
|
98
|
-
|
|
98
|
+
if (!k || R || z.invalid) return;
|
|
99
|
+
L(null), O(null);
|
|
99
100
|
let e = {
|
|
100
|
-
...
|
|
101
|
-
...
|
|
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(
|
|
105
|
-
id:
|
|
105
|
+
await t(B({ variables: {
|
|
106
|
+
id: k.id,
|
|
106
107
|
input: {
|
|
107
|
-
name:
|
|
108
|
+
name: P.name || void 0,
|
|
108
109
|
...e,
|
|
109
|
-
goal:
|
|
110
|
-
capacity:
|
|
110
|
+
goal: P.goal || void 0,
|
|
111
|
+
capacity: z.value
|
|
111
112
|
}
|
|
112
|
-
} })),
|
|
113
|
+
} })), O("Sprint updated successfully."), N({});
|
|
113
114
|
} catch (e) {
|
|
114
|
-
|
|
115
|
+
L(e instanceof Error ? e.message : "The sprint could not be saved.");
|
|
115
116
|
}
|
|
116
117
|
},
|
|
117
|
-
disabled:
|
|
118
|
-
children: [/* @__PURE__ */
|
|
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
|
-
|
|
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:
|
|
125
|
+
children: D
|
|
125
126
|
}),
|
|
126
|
-
|
|
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: ",
|
|
130
|
+
children: ["Error: ", I]
|
|
130
131
|
}),
|
|
131
|
-
/* @__PURE__ */
|
|
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__ */
|
|
135
|
+
/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
135
136
|
className: "text-sm font-medium",
|
|
136
137
|
children: "Name"
|
|
137
|
-
}), /* @__PURE__ */
|
|
138
|
-
value:
|
|
139
|
-
onChange: (e) =>
|
|
140
|
-
...
|
|
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__ */
|
|
146
|
+
/* @__PURE__ */ m("div", {
|
|
146
147
|
className: "grid grid-cols-2 gap-4",
|
|
147
|
-
children: [/* @__PURE__ */
|
|
148
|
+
children: [/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
148
149
|
className: "text-sm font-medium",
|
|
149
150
|
children: "Project"
|
|
150
|
-
}), /* @__PURE__ */
|
|
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:
|
|
153
|
-
})] }), /* @__PURE__ */
|
|
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__ */
|
|
157
|
+
}), /* @__PURE__ */ m("div", {
|
|
157
158
|
className: "mt-1 flex items-start justify-between gap-2",
|
|
158
|
-
children: [/* @__PURE__ */
|
|
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:
|
|
161
|
-
}), /* @__PURE__ */
|
|
162
|
-
sprintId:
|
|
163
|
-
sprintName:
|
|
164
|
-
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__ */
|
|
169
|
+
/* @__PURE__ */ m("div", {
|
|
169
170
|
className: "grid grid-cols-2 gap-4",
|
|
170
|
-
children: [/* @__PURE__ */
|
|
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__ */
|
|
175
|
+
}), /* @__PURE__ */ p(b, {
|
|
176
|
+
id: "sprint-start",
|
|
174
177
|
type: "date",
|
|
175
|
-
value:
|
|
176
|
-
|
|
177
|
-
|
|
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__ */
|
|
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__ */
|
|
189
|
+
}), /* @__PURE__ */ p(b, {
|
|
190
|
+
id: "sprint-end",
|
|
185
191
|
type: "date",
|
|
186
|
-
value:
|
|
187
|
-
|
|
188
|
-
|
|
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
|
-
|
|
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__ */
|
|
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:
|
|
200
|
-
onChange: (e) =>
|
|
201
|
-
...
|
|
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__ */
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
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
|
-
|
|
217
|
-
|
|
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__ */
|
|
248
|
+
}) : /* @__PURE__ */ p("div", {
|
|
223
249
|
className: "p-6 text-muted-foreground",
|
|
224
250
|
children: "Planning session not found."
|
|
225
|
-
}) : /* @__PURE__ */
|
|
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 {
|
|
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":"
|
|
1
|
+
{"version":3,"file":"TasksCreateTaskPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/TasksCreateTaskPagePage.tsx"],"names":[],"mappings":"AAkDA,wBAAgB,uBAAuB,4CAkQtC"}
|