@burdenoff/microfe-planmagnet 2026.925.7 → 2026.925.9

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 (32) hide show
  1. package/dist/generated/wspace-types.d.ts +49 -0
  2. package/dist/generated/wspace-types.d.ts.map +1 -1
  3. package/dist/planmagnet/board/ProjectBoard.d.ts.map +1 -1
  4. package/dist/planmagnet/board/ProjectBoard.js +159 -158
  5. package/dist/planmagnet/board/ProjectBoard.js.map +1 -1
  6. package/dist/planmagnet/comments/WorkItemComments.d.ts +4 -0
  7. package/dist/planmagnet/comments/WorkItemComments.d.ts.map +1 -0
  8. package/dist/planmagnet/comments/WorkItemComments.js +260 -0
  9. package/dist/planmagnet/comments/WorkItemComments.js.map +1 -0
  10. package/dist/planmagnet/create/CreateDialogs.d.ts.map +1 -1
  11. package/dist/planmagnet/create/CreateDialogs.js +118 -117
  12. package/dist/planmagnet/create/CreateDialogs.js.map +1 -1
  13. package/dist/planmagnet/pages/GoalsCreateObjectivePagePage.d.ts.map +1 -1
  14. package/dist/planmagnet/pages/GoalsCreateObjectivePagePage.js.map +1 -1
  15. package/dist/planmagnet/pages/GoalsObjectiveDetailPagePage.d.ts.map +1 -1
  16. package/dist/planmagnet/pages/GoalsObjectiveDetailPagePage.js +322 -280
  17. package/dist/planmagnet/pages/GoalsObjectiveDetailPagePage.js.map +1 -1
  18. package/dist/planmagnet/pages/TasksCreateTaskPagePage.d.ts.map +1 -1
  19. package/dist/planmagnet/pages/TasksCreateTaskPagePage.js.map +1 -1
  20. package/dist/planmagnet/pages/TasksEditTaskPagePage.d.ts.map +1 -1
  21. package/dist/planmagnet/pages/TasksEditTaskPagePage.js.map +1 -1
  22. package/dist/planmagnet/pages/TasksTaskDetailPagePage.d.ts.map +1 -1
  23. package/dist/planmagnet/pages/TasksTaskDetailPagePage.js +166 -143
  24. package/dist/planmagnet/pages/TasksTaskDetailPagePage.js.map +1 -1
  25. package/dist/planmagnet/sprints/SprintControls.d.ts.map +1 -1
  26. package/dist/planmagnet/sprints/SprintControls.js +202 -201
  27. package/dist/planmagnet/sprints/SprintControls.js.map +1 -1
  28. package/dist/planmagnet/utils/mutationResult.d.ts +16 -0
  29. package/dist/planmagnet/utils/mutationResult.d.ts.map +1 -0
  30. package/dist/planmagnet/utils/mutationResult.js +10 -0
  31. package/dist/planmagnet/utils/mutationResult.js.map +1 -0
  32. package/package.json +3 -2
@@ -1,12 +1,13 @@
1
1
  import { usePlanMagnet as e } from "../providers/PlanMagnetProvider.js";
2
- import { useState as t } from "react";
3
- import { Plus as n } from "lucide-react";
4
- import { gql as r } from "@apollo/client";
5
- import { useMutation as i, useQuery as a } from "@apollo/client/react";
6
- import { jsx as o, jsxs as s } from "react/jsx-runtime";
7
- import { Button as c, Input as l, ResponsiveDialog as u, ResponsiveDialogContent as d, ResponsiveDialogDescription as f, ResponsiveDialogFooter as p, ResponsiveDialogHeader as m, ResponsiveDialogTitle as h, ResponsiveDialogTrigger as g } from "@burdenoff/fe-libs/ui";
2
+ import { throwOnError as t } from "../utils/mutationResult.js";
3
+ import { useState as n } from "react";
4
+ import { Plus as r } from "lucide-react";
5
+ import { gql as i } from "@apollo/client";
6
+ import { useMutation as a, useQuery as o } from "@apollo/client/react";
7
+ import { jsx as s, jsxs as c } from "react/jsx-runtime";
8
+ import { Button as l, Input as u, ResponsiveDialog as d, ResponsiveDialogContent as f, ResponsiveDialogDescription as p, ResponsiveDialogFooter as m, ResponsiveDialogHeader as h, ResponsiveDialogTitle as g, ResponsiveDialogTrigger as _ } from "@burdenoff/fe-libs/ui";
8
9
  //#region src/planmagnet/create/CreateDialogs.tsx
9
- var _ = r`
10
+ var v = i`
10
11
  query CreateDialogProjects($workspaceId: ID!) {
11
12
  planmagnetProjects(workspaceId: $workspaceId, pagination: { first: 100 }) {
12
13
  items {
@@ -15,16 +16,16 @@ var _ = r`
15
16
  }
16
17
  }
17
18
  }
18
- `, v = "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm";
19
- function y({ message: e }) {
20
- return /* @__PURE__ */ o("p", {
19
+ `, y = "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm";
20
+ function b({ message: e }) {
21
+ return /* @__PURE__ */ s("p", {
21
22
  role: "alert",
22
23
  className: "text-sm text-destructive",
23
24
  children: e
24
25
  });
25
26
  }
26
- function b(t) {
27
- let { workspaceId: n } = e(), { data: r, loading: i } = a(_, {
27
+ function x(t) {
28
+ let { workspaceId: n } = e(), { data: r, loading: i } = o(v, {
28
29
  variables: { workspaceId: n ?? "" },
29
30
  skip: !t || !n
30
31
  });
@@ -33,31 +34,31 @@ function b(t) {
33
34
  loading: i
34
35
  };
35
36
  }
36
- function x({ id: e, value: t, onChange: n, projects: r, loading: i }) {
37
- return /* @__PURE__ */ s("div", { children: [/* @__PURE__ */ o("label", {
37
+ function S({ id: e, value: t, onChange: n, projects: r, loading: i }) {
38
+ return /* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s("label", {
38
39
  htmlFor: e,
39
40
  className: "text-sm font-medium",
40
41
  children: "Project"
41
- }), /* @__PURE__ */ s("select", {
42
+ }), /* @__PURE__ */ c("select", {
42
43
  id: e,
43
- className: v,
44
+ className: y,
44
45
  value: t,
45
46
  onChange: (e) => n(e.target.value),
46
- children: [r.length === 0 && /* @__PURE__ */ o("option", {
47
+ children: [r.length === 0 && /* @__PURE__ */ s("option", {
47
48
  value: "",
48
49
  children: i ? "Loading…" : "No projects"
49
- }), r.map((e) => /* @__PURE__ */ o("option", {
50
+ }), r.map((e) => /* @__PURE__ */ s("option", {
50
51
  value: e.id,
51
52
  children: e.name
52
53
  }, e.id))]
53
54
  })] });
54
55
  }
55
- function S({ id: e, label: t, value: n, onChange: r, type: i = "text", placeholder: a }) {
56
- return /* @__PURE__ */ s("div", { children: [/* @__PURE__ */ o("label", {
56
+ function C({ id: e, label: t, value: n, onChange: r, type: i = "text", placeholder: a }) {
57
+ return /* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s("label", {
57
58
  htmlFor: e,
58
59
  className: "text-sm font-medium",
59
60
  children: t
60
- }), /* @__PURE__ */ o(l, {
61
+ }), /* @__PURE__ */ s(u, {
61
62
  id: e,
62
63
  type: i,
63
64
  className: "mt-1",
@@ -66,217 +67,217 @@ function S({ id: e, label: t, value: n, onChange: r, type: i = "text", placehold
66
67
  onChange: (e) => r(e.target.value)
67
68
  })] });
68
69
  }
69
- var C = (e, t) => e instanceof Error ? e.message : t, w = r`
70
+ var w = (e, t) => e instanceof Error ? e.message : t, T = i`
70
71
  mutation CreateDialogRelease($input: PlanmagnetCreateReleaseInput!) {
71
72
  planmagnetCreateRelease(input: $input) {
72
73
  id
73
74
  }
74
75
  }
75
- `, T = {
76
+ `, E = {
76
77
  name: "",
77
78
  version: "",
78
79
  projectId: "",
79
80
  plannedDate: "",
80
81
  description: ""
81
82
  };
82
- function E({ onCreated: e }) {
83
- let [r, a] = t(!1), [l, _] = t(T), [v, E] = t(null), { projects: D, loading: O } = b(r), k = l.projectId || D[0]?.id || "", [A, { loading: j }] = i(w, {
83
+ function D({ onCreated: e }) {
84
+ let [i, o] = n(!1), [u, v] = n(E), [y, D] = n(null), { projects: O, loading: k } = x(i), A = u.projectId || O[0]?.id || "", [j, { loading: M }] = a(T, {
84
85
  refetchQueries: ["ListReleases"],
85
86
  awaitRefetchQueries: !0
86
- }), M = l.name.trim() !== "" && l.version.trim() !== "" && k !== "" && !j;
87
- return /* @__PURE__ */ s(u, {
88
- open: r,
87
+ }), N = u.name.trim() !== "" && u.version.trim() !== "" && A !== "" && !M;
88
+ return /* @__PURE__ */ c(d, {
89
+ open: i,
89
90
  onOpenChange: (e) => {
90
- a(e), e || E(null);
91
+ o(e), e || D(null);
91
92
  },
92
- children: [/* @__PURE__ */ o(g, {
93
+ children: [/* @__PURE__ */ s(_, {
93
94
  asChild: !0,
94
- children: /* @__PURE__ */ s(c, {
95
+ children: /* @__PURE__ */ c(l, {
95
96
  size: "sm",
96
- children: [/* @__PURE__ */ o(n, { className: "mr-1 h-4 w-4" }), "New Release"]
97
+ children: [/* @__PURE__ */ s(r, { className: "mr-1 h-4 w-4" }), "New Release"]
97
98
  })
98
- }), /* @__PURE__ */ s(d, {
99
+ }), /* @__PURE__ */ c(f, {
99
100
  className: "max-w-lg",
100
101
  children: [
101
- /* @__PURE__ */ s(m, { children: [/* @__PURE__ */ o(h, { children: "New release" }), /* @__PURE__ */ o(f, { children: "The release starts in Planning." })] }),
102
- /* @__PURE__ */ s("div", {
102
+ /* @__PURE__ */ c(h, { children: [/* @__PURE__ */ s(g, { children: "New release" }), /* @__PURE__ */ s(p, { children: "The release starts in Planning." })] }),
103
+ /* @__PURE__ */ c("div", {
103
104
  className: "space-y-3",
104
105
  children: [
105
- /* @__PURE__ */ o(S, {
106
+ /* @__PURE__ */ s(C, {
106
107
  id: "new-release-name",
107
108
  label: "Name",
108
- value: l.name,
109
- onChange: (e) => _({
110
- ...l,
109
+ value: u.name,
110
+ onChange: (e) => v({
111
+ ...u,
111
112
  name: e
112
113
  })
113
114
  }),
114
- /* @__PURE__ */ o(S, {
115
+ /* @__PURE__ */ s(C, {
115
116
  id: "new-release-version",
116
117
  label: "Version",
117
118
  placeholder: "e.g. 1.4.0",
118
- value: l.version,
119
- onChange: (e) => _({
120
- ...l,
119
+ value: u.version,
120
+ onChange: (e) => v({
121
+ ...u,
121
122
  version: e
122
123
  })
123
124
  }),
124
- /* @__PURE__ */ o(x, {
125
+ /* @__PURE__ */ s(S, {
125
126
  id: "new-release-project",
126
- value: k,
127
- onChange: (e) => _({
128
- ...l,
127
+ value: A,
128
+ onChange: (e) => v({
129
+ ...u,
129
130
  projectId: e
130
131
  }),
131
- projects: D,
132
- loading: O
132
+ projects: O,
133
+ loading: k
133
134
  }),
134
- /* @__PURE__ */ o(S, {
135
+ /* @__PURE__ */ s(C, {
135
136
  id: "new-release-date",
136
137
  label: "Planned date",
137
138
  type: "date",
138
- value: l.plannedDate,
139
- onChange: (e) => _({
140
- ...l,
139
+ value: u.plannedDate,
140
+ onChange: (e) => v({
141
+ ...u,
141
142
  plannedDate: e
142
143
  })
143
144
  }),
144
- /* @__PURE__ */ o(S, {
145
+ /* @__PURE__ */ s(C, {
145
146
  id: "new-release-description",
146
147
  label: "Description",
147
- value: l.description,
148
- onChange: (e) => _({
149
- ...l,
148
+ value: u.description,
149
+ onChange: (e) => v({
150
+ ...u,
150
151
  description: e
151
152
  })
152
153
  })
153
154
  ]
154
155
  }),
155
- v && /* @__PURE__ */ o(y, { message: v }),
156
- /* @__PURE__ */ o(p, { children: /* @__PURE__ */ o(c, {
156
+ y && /* @__PURE__ */ s(b, { message: y }),
157
+ /* @__PURE__ */ s(m, { children: /* @__PURE__ */ s(l, {
157
158
  onClick: async () => {
158
- E(null);
159
+ D(null);
159
160
  try {
160
- let t = (await A({ variables: { input: {
161
- name: l.name.trim(),
162
- version: l.version.trim(),
163
- projectId: k,
164
- plannedDate: l.plannedDate || void 0,
165
- description: l.description.trim() || void 0
166
- } } })).data?.planmagnetCreateRelease.id;
167
- _(T), a(!1), t && e(t);
161
+ let n = (await t(j({ variables: { input: {
162
+ name: u.name.trim(),
163
+ version: u.version.trim(),
164
+ projectId: A,
165
+ plannedDate: u.plannedDate || void 0,
166
+ description: u.description.trim() || void 0
167
+ } } }))).data?.planmagnetCreateRelease.id;
168
+ v(E), o(!1), n && e(n);
168
169
  } catch (e) {
169
- E(C(e, "The release could not be created."));
170
+ D(w(e, "The release could not be created."));
170
171
  }
171
172
  },
172
- disabled: !M,
173
+ disabled: !N,
173
174
  "data-testid": "new-release-submit",
174
- children: j ? "Creating…" : "Create release"
175
+ children: M ? "Creating…" : "Create release"
175
176
  }) })
176
177
  ]
177
178
  })]
178
179
  });
179
180
  }
180
- var D = r`
181
+ var O = i`
181
182
  mutation CreateDialogMilestone($input: PlanmagnetCreateMilestoneInput!) {
182
183
  planmagnetCreateMilestone(input: $input) {
183
184
  id
184
185
  }
185
186
  }
186
- `, O = {
187
+ `, k = {
187
188
  name: "",
188
189
  projectId: "",
189
190
  dueDate: "",
190
191
  description: ""
191
192
  };
192
- function k({ onCreated: e }) {
193
- let [r, a] = t(!1), [l, _] = t(O), [v, w] = t(null), { projects: T, loading: E } = b(r), k = l.projectId || T[0]?.id || "", [A, { loading: j }] = i(D, {
193
+ function A({ onCreated: e }) {
194
+ let [i, o] = n(!1), [u, v] = n(k), [y, T] = n(null), { projects: E, loading: D } = x(i), A = u.projectId || E[0]?.id || "", [j, { loading: M }] = a(O, {
194
195
  refetchQueries: ["GetMilestones"],
195
196
  awaitRefetchQueries: !0
196
- }), M = l.name.trim() !== "" && k !== "" && !j;
197
- return /* @__PURE__ */ s(u, {
198
- open: r,
197
+ }), N = u.name.trim() !== "" && A !== "" && !M;
198
+ return /* @__PURE__ */ c(d, {
199
+ open: i,
199
200
  onOpenChange: (e) => {
200
- a(e), e || w(null);
201
+ o(e), e || T(null);
201
202
  },
202
- children: [/* @__PURE__ */ o(g, {
203
+ children: [/* @__PURE__ */ s(_, {
203
204
  asChild: !0,
204
- children: /* @__PURE__ */ s(c, {
205
+ children: /* @__PURE__ */ c(l, {
205
206
  size: "sm",
206
- children: [/* @__PURE__ */ o(n, { className: "mr-1 h-4 w-4" }), "New Milestone"]
207
+ children: [/* @__PURE__ */ s(r, { className: "mr-1 h-4 w-4" }), "New Milestone"]
207
208
  })
208
- }), /* @__PURE__ */ s(d, {
209
+ }), /* @__PURE__ */ c(f, {
209
210
  className: "max-w-lg",
210
211
  children: [
211
- /* @__PURE__ */ s(m, { children: [/* @__PURE__ */ o(h, { children: "New milestone" }), /* @__PURE__ */ o(f, { children: "The milestone starts as Pending." })] }),
212
- /* @__PURE__ */ s("div", {
212
+ /* @__PURE__ */ c(h, { children: [/* @__PURE__ */ s(g, { children: "New milestone" }), /* @__PURE__ */ s(p, { children: "The milestone starts as Pending." })] }),
213
+ /* @__PURE__ */ c("div", {
213
214
  className: "space-y-3",
214
215
  children: [
215
- /* @__PURE__ */ o(S, {
216
+ /* @__PURE__ */ s(C, {
216
217
  id: "new-milestone-name",
217
218
  label: "Name",
218
- value: l.name,
219
- onChange: (e) => _({
220
- ...l,
219
+ value: u.name,
220
+ onChange: (e) => v({
221
+ ...u,
221
222
  name: e
222
223
  })
223
224
  }),
224
- /* @__PURE__ */ o(x, {
225
+ /* @__PURE__ */ s(S, {
225
226
  id: "new-milestone-project",
226
- value: k,
227
- onChange: (e) => _({
228
- ...l,
227
+ value: A,
228
+ onChange: (e) => v({
229
+ ...u,
229
230
  projectId: e
230
231
  }),
231
- projects: T,
232
- loading: E
232
+ projects: E,
233
+ loading: D
233
234
  }),
234
- /* @__PURE__ */ o(S, {
235
+ /* @__PURE__ */ s(C, {
235
236
  id: "new-milestone-due",
236
237
  label: "Due date",
237
238
  type: "date",
238
- value: l.dueDate,
239
- onChange: (e) => _({
240
- ...l,
239
+ value: u.dueDate,
240
+ onChange: (e) => v({
241
+ ...u,
241
242
  dueDate: e
242
243
  })
243
244
  }),
244
- /* @__PURE__ */ o(S, {
245
+ /* @__PURE__ */ s(C, {
245
246
  id: "new-milestone-description",
246
247
  label: "Description",
247
- value: l.description,
248
- onChange: (e) => _({
249
- ...l,
248
+ value: u.description,
249
+ onChange: (e) => v({
250
+ ...u,
250
251
  description: e
251
252
  })
252
253
  })
253
254
  ]
254
255
  }),
255
- v && /* @__PURE__ */ o(y, { message: v }),
256
- /* @__PURE__ */ o(p, { children: /* @__PURE__ */ o(c, {
256
+ y && /* @__PURE__ */ s(b, { message: y }),
257
+ /* @__PURE__ */ s(m, { children: /* @__PURE__ */ s(l, {
257
258
  onClick: async () => {
258
- w(null);
259
+ T(null);
259
260
  try {
260
- let t = (await A({ variables: { input: {
261
- name: l.name.trim(),
262
- projectId: k,
263
- dueDate: l.dueDate || void 0,
264
- description: l.description.trim() || void 0
265
- } } })).data?.planmagnetCreateMilestone.id;
266
- _(O), a(!1), t && e(t);
261
+ let n = (await t(j({ variables: { input: {
262
+ name: u.name.trim(),
263
+ projectId: A,
264
+ dueDate: u.dueDate || void 0,
265
+ description: u.description.trim() || void 0
266
+ } } }))).data?.planmagnetCreateMilestone.id;
267
+ v(k), o(!1), n && e(n);
267
268
  } catch (e) {
268
- w(C(e, "The milestone could not be created."));
269
+ T(w(e, "The milestone could not be created."));
269
270
  }
270
271
  },
271
- disabled: !M,
272
+ disabled: !N,
272
273
  "data-testid": "new-milestone-submit",
273
- children: j ? "Creating…" : "Create milestone"
274
+ children: M ? "Creating…" : "Create milestone"
274
275
  }) })
275
276
  ]
276
277
  })]
277
278
  });
278
279
  }
279
280
  //#endregion
280
- export { k as NewMilestoneDialog, E as NewReleaseDialog };
281
+ export { A as NewMilestoneDialog, D as NewReleaseDialog };
281
282
 
282
283
  //# sourceMappingURL=CreateDialogs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CreateDialogs.js","names":[],"sources":["../../../src/planmagnet/create/CreateDialogs.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport {\n Button,\n Input,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogTrigger,\n} from '@burdenoff/fe-libs/ui';\nimport { Plus } from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\n\n/**\n * Create dialogs for records whose list pages had a dead \"New …\" button, or\n * none at all (QA report 2026-09-23: C4 New Release had no onClick; H7 there\n * was no way to create a milestone). Both mutations were already served and\n * verified in prod; only the UI trigger was missing.\n */\n\nconst DIALOG_PROJECTS = gql`\n query CreateDialogProjects($workspaceId: ID!) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n }\n }\n }\n`;\n\nconst FIELD = 'mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm';\n\nfunction ErrorLine({ message }: { message: string }) {\n return (\n <p role=\"alert\" className=\"text-sm text-destructive\">\n {message}\n </p>\n );\n}\n\nfunction useDialogProjects(open: boolean) {\n const { workspaceId } = usePlanMagnet();\n const { data, loading } = useQuery<{\n planmagnetProjects: { items: Array<{ id: string; name: string }> };\n }>(DIALOG_PROJECTS, {\n variables: { workspaceId: workspaceId ?? '' },\n skip: !open || !workspaceId,\n });\n return { projects: data?.planmagnetProjects.items ?? [], loading };\n}\n\nfunction ProjectField({\n id,\n value,\n onChange,\n projects,\n loading,\n}: {\n id: string;\n value: string;\n onChange: (id: string) => void;\n projects: Array<{ id: string; name: string }>;\n loading: boolean;\n}) {\n return (\n <div>\n <label htmlFor={id} className=\"text-sm font-medium\">\n Project\n </label>\n <select id={id} className={FIELD} value={value} onChange={(e) => onChange(e.target.value)}>\n {projects.length === 0 && <option value=\"\">{loading ? 'Loading…' : 'No projects'}</option>}\n {projects.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n </select>\n </div>\n );\n}\n\nfunction TextField({\n id,\n label,\n value,\n onChange,\n type = 'text',\n placeholder,\n}: {\n id: string;\n label: string;\n value: string;\n onChange: (value: string) => void;\n type?: string;\n placeholder?: string;\n}) {\n return (\n <div>\n <label htmlFor={id} className=\"text-sm font-medium\">\n {label}\n </label>\n <Input\n id={id}\n type={type}\n className=\"mt-1\"\n value={value}\n placeholder={placeholder}\n onChange={(e) => onChange(e.target.value)}\n />\n </div>\n );\n}\n\nconst messageOf = (e: unknown, fallback: string) => (e instanceof Error ? e.message : fallback);\n\n// ─── New release (C4) ────────────────────────────────────────────────────────\n\nconst CREATE_RELEASE = gql`\n mutation CreateDialogRelease($input: PlanmagnetCreateReleaseInput!) {\n planmagnetCreateRelease(input: $input) {\n id\n }\n }\n`;\n\nconst EMPTY_RELEASE = { name: '', version: '', projectId: '', plannedDate: '', description: '' };\n\nexport function NewReleaseDialog({ onCreated }: { onCreated: (releaseId: string) => void }) {\n const [open, setOpen] = useState(false);\n const [form, setForm] = useState(EMPTY_RELEASE);\n const [error, setError] = useState<string | null>(null);\n const { projects, loading: projectsLoading } = useDialogProjects(open);\n const projectId = form.projectId || projects[0]?.id || '';\n const [create, { loading }] = useMutation<{ planmagnetCreateRelease: { id: string } }>(\n CREATE_RELEASE,\n { refetchQueries: ['ListReleases'], awaitRefetchQueries: true }\n );\n\n const canSubmit =\n form.name.trim() !== '' && form.version.trim() !== '' && projectId !== '' && !loading;\n\n const handleCreate = async () => {\n setError(null);\n try {\n const result = await create({\n variables: {\n input: {\n name: form.name.trim(),\n version: form.version.trim(),\n projectId,\n plannedDate: form.plannedDate || undefined,\n description: form.description.trim() || undefined,\n },\n },\n });\n const id = result.data?.planmagnetCreateRelease.id;\n setForm(EMPTY_RELEASE);\n setOpen(false);\n if (id) onCreated(id);\n } catch (e) {\n setError(messageOf(e, 'The release could not be created.'));\n }\n };\n\n return (\n <ResponsiveDialog\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) setError(null);\n }}\n >\n <ResponsiveDialogTrigger asChild>\n <Button size=\"sm\">\n <Plus className=\"mr-1 h-4 w-4\" />\n New Release\n </Button>\n </ResponsiveDialogTrigger>\n <ResponsiveDialogContent className=\"max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New release</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>The release starts in Planning.</ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3\">\n <TextField\n id=\"new-release-name\"\n label=\"Name\"\n value={form.name}\n onChange={(name) => setForm({ ...form, name })}\n />\n <TextField\n id=\"new-release-version\"\n label=\"Version\"\n placeholder=\"e.g. 1.4.0\"\n value={form.version}\n onChange={(version) => setForm({ ...form, version })}\n />\n <ProjectField\n id=\"new-release-project\"\n value={projectId}\n onChange={(id) => setForm({ ...form, projectId: id })}\n projects={projects}\n loading={projectsLoading}\n />\n <TextField\n id=\"new-release-date\"\n label=\"Planned date\"\n type=\"date\"\n value={form.plannedDate}\n onChange={(plannedDate) => setForm({ ...form, plannedDate })}\n />\n <TextField\n id=\"new-release-description\"\n label=\"Description\"\n value={form.description}\n onChange={(description) => setForm({ ...form, description })}\n />\n </div>\n {error && <ErrorLine message={error} />}\n <ResponsiveDialogFooter>\n <Button onClick={handleCreate} disabled={!canSubmit} data-testid=\"new-release-submit\">\n {loading ? 'Creating…' : 'Create release'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\n// ─── New milestone (H7) ──────────────────────────────────────────────────────\n\nconst CREATE_MILESTONE = gql`\n mutation CreateDialogMilestone($input: PlanmagnetCreateMilestoneInput!) {\n planmagnetCreateMilestone(input: $input) {\n id\n }\n }\n`;\n\nconst EMPTY_MILESTONE = { name: '', projectId: '', dueDate: '', description: '' };\n\nexport function NewMilestoneDialog({ onCreated }: { onCreated: (milestoneId: string) => void }) {\n const [open, setOpen] = useState(false);\n const [form, setForm] = useState(EMPTY_MILESTONE);\n const [error, setError] = useState<string | null>(null);\n const { projects, loading: projectsLoading } = useDialogProjects(open);\n const projectId = form.projectId || projects[0]?.id || '';\n const [create, { loading }] = useMutation<{ planmagnetCreateMilestone: { id: string } }>(\n CREATE_MILESTONE,\n { refetchQueries: ['GetMilestones'], awaitRefetchQueries: true }\n );\n\n const canSubmit = form.name.trim() !== '' && projectId !== '' && !loading;\n\n const handleCreate = async () => {\n setError(null);\n try {\n const result = await create({\n variables: {\n input: {\n name: form.name.trim(),\n projectId,\n dueDate: form.dueDate || undefined,\n description: form.description.trim() || undefined,\n },\n },\n });\n const id = result.data?.planmagnetCreateMilestone.id;\n setForm(EMPTY_MILESTONE);\n setOpen(false);\n if (id) onCreated(id);\n } catch (e) {\n setError(messageOf(e, 'The milestone could not be created.'));\n }\n };\n\n return (\n <ResponsiveDialog\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) setError(null);\n }}\n >\n <ResponsiveDialogTrigger asChild>\n <Button size=\"sm\">\n <Plus className=\"mr-1 h-4 w-4\" />\n New Milestone\n </Button>\n </ResponsiveDialogTrigger>\n <ResponsiveDialogContent className=\"max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New milestone</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n The milestone starts as Pending.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3\">\n <TextField\n id=\"new-milestone-name\"\n label=\"Name\"\n value={form.name}\n onChange={(name) => setForm({ ...form, name })}\n />\n <ProjectField\n id=\"new-milestone-project\"\n value={projectId}\n onChange={(id) => setForm({ ...form, projectId: id })}\n projects={projects}\n loading={projectsLoading}\n />\n <TextField\n id=\"new-milestone-due\"\n label=\"Due date\"\n type=\"date\"\n value={form.dueDate}\n onChange={(dueDate) => setForm({ ...form, dueDate })}\n />\n <TextField\n id=\"new-milestone-description\"\n label=\"Description\"\n value={form.description}\n onChange={(description) => setForm({ ...form, description })}\n />\n </div>\n {error && <ErrorLine message={error} />}\n <ResponsiveDialogFooter>\n <Button onClick={handleCreate} disabled={!canSubmit} data-testid=\"new-milestone-submit\">\n {loading ? 'Creating…' : 'Create milestone'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n"],"mappings":";;;;;;;;AAwBA,IAAM,IAAkB,CAAG;;;;;;;;;GAWrB,IAAQ;AAEd,SAAS,EAAU,EAAE,cAAgC;AACnD,QACE,kBAAC,KAAD;EAAG,MAAK;EAAQ,WAAU;YACvB;EACC,CAAA;;AAIR,SAAS,EAAkB,GAAe;CACxC,IAAM,EAAE,mBAAgB,GAAe,EACjC,EAAE,SAAM,eAAY,EAEvB,GAAiB;EAClB,WAAW,EAAE,aAAa,KAAe,IAAI;EAC7C,MAAM,CAAC,KAAQ,CAAC;EACjB,CAAC;AACF,QAAO;EAAE,UAAU,GAAM,mBAAmB,SAAS,EAAE;EAAE;EAAS;;AAGpE,SAAS,EAAa,EACpB,OACA,UACA,aACA,aACA,cAOC;AACD,QACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;EAAO,SAAS;EAAI,WAAU;YAAsB;EAE5C,CAAA,EACR,kBAAC,UAAD;EAAY;EAAI,WAAW;EAAc;EAAO,WAAW,MAAM,EAAS,EAAE,OAAO,MAAM;YAAzF,CACG,EAAS,WAAW,KAAK,kBAAC,UAAD;GAAQ,OAAM;aAAI,IAAU,aAAa;GAAuB,CAAA,EACzF,EAAS,KAAK,MACb,kBAAC,UAAD;GAAmB,OAAO,EAAE;aACzB,EAAE;GACI,EAFI,EAAE,GAEN,CACT,CACK;IACL,EAAA,CAAA;;AAIV,SAAS,EAAU,EACjB,OACA,UACA,UACA,aACA,UAAO,QACP,kBAQC;AACD,QACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;EAAO,SAAS;EAAI,WAAU;YAC3B;EACK,CAAA,EACR,kBAAC,GAAD;EACM;EACE;EACN,WAAU;EACH;EACM;EACb,WAAW,MAAM,EAAS,EAAE,OAAO,MAAM;EACzC,CAAA,CACE,EAAA,CAAA;;AAIV,IAAM,KAAa,GAAY,MAAsB,aAAa,QAAQ,EAAE,UAAU,GAIhF,IAAiB,CAAG;;;;;;GAQpB,IAAgB;CAAE,MAAM;CAAI,SAAS;CAAI,WAAW;CAAI,aAAa;CAAI,aAAa;CAAI;AAEhG,SAAgB,EAAiB,EAAE,gBAAyD;CAC1F,IAAM,CAAC,GAAM,KAAW,EAAS,GAAM,EACjC,CAAC,GAAM,KAAW,EAAS,EAAc,EACzC,CAAC,GAAO,KAAY,EAAwB,KAAK,EACjD,EAAE,aAAU,SAAS,MAAoB,EAAkB,EAAK,EAChE,IAAY,EAAK,aAAa,EAAS,IAAI,MAAM,IACjD,CAAC,GAAQ,EAAE,gBAAa,EAC5B,GACA;EAAE,gBAAgB,CAAC,eAAe;EAAE,qBAAqB;EAAM,CAChE,EAEK,IACJ,EAAK,KAAK,MAAM,KAAK,MAAM,EAAK,QAAQ,MAAM,KAAK,MAAM,MAAc,MAAM,CAAC;AAyBhF,QACE,kBAAC,GAAD;EACQ;EACN,eAAe,MAAS;AAEtB,GADA,EAAQ,EAAK,EACR,KAAM,EAAS,KAAK;;YAJ7B,CAOE,kBAAC,GAAD;GAAyB,SAAA;aACvB,kBAAC,GAAD;IAAQ,MAAK;cAAb,CACE,kBAAC,GAAD,EAAM,WAAU,gBAAiB,CAAA,EAAA,cAE1B;;GACe,CAAA,EAC1B,kBAAC,GAAD;GAAyB,WAAU;aAAnC;IACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAuB,eAAmC,CAAA,EAC1D,kBAAC,GAAD,EAAA,UAA6B,mCAA6D,CAAA,CACnE,EAAA,CAAA;IACzB,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,GAAD;OACE,IAAG;OACH,OAAM;OACN,OAAO,EAAK;OACZ,WAAW,MAAS,EAAQ;QAAE,GAAG;QAAM;QAAM,CAAC;OAC9C,CAAA;MACF,kBAAC,GAAD;OACE,IAAG;OACH,OAAM;OACN,aAAY;OACZ,OAAO,EAAK;OACZ,WAAW,MAAY,EAAQ;QAAE,GAAG;QAAM;QAAS,CAAC;OACpD,CAAA;MACF,kBAAC,GAAD;OACE,IAAG;OACH,OAAO;OACP,WAAW,MAAO,EAAQ;QAAE,GAAG;QAAM,WAAW;QAAI,CAAC;OAC3C;OACV,SAAS;OACT,CAAA;MACF,kBAAC,GAAD;OACE,IAAG;OACH,OAAM;OACN,MAAK;OACL,OAAO,EAAK;OACZ,WAAW,MAAgB,EAAQ;QAAE,GAAG;QAAM;QAAa,CAAC;OAC5D,CAAA;MACF,kBAAC,GAAD;OACE,IAAG;OACH,OAAM;OACN,OAAO,EAAK;OACZ,WAAW,MAAgB,EAAQ;QAAE,GAAG;QAAM;QAAa,CAAC;OAC5D,CAAA;MACE;;IACL,KAAS,kBAAC,GAAD,EAAW,SAAS,GAAS,CAAA;IACvC,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;KAAQ,SA/EK,YAAY;AAC/B,QAAS,KAAK;AACd,UAAI;OAYF,IAAM,KAXS,MAAM,EAAO,EAC1B,WAAW,EACT,OAAO;QACL,MAAM,EAAK,KAAK,MAAM;QACtB,SAAS,EAAK,QAAQ,MAAM;QAC5B;QACA,aAAa,EAAK,eAAe,KAAA;QACjC,aAAa,EAAK,YAAY,MAAM,IAAI,KAAA;QACzC,EACF,EACF,CAAC,EACgB,MAAM,wBAAwB;AAGhD,OAFA,EAAQ,EAAc,EACtB,EAAQ,GAAM,EACV,KAAI,EAAU,EAAG;eACd,GAAG;AACV,SAAS,EAAU,GAAG,oCAAoC,CAAC;;;KA4DxB,UAAU,CAAC;KAAW,eAAY;eAC9D,IAAU,cAAc;KAClB,CAAA,EACc,CAAA;IACD;KACT;;;AAMvB,IAAM,IAAmB,CAAG;;;;;;GAQtB,IAAkB;CAAE,MAAM;CAAI,WAAW;CAAI,SAAS;CAAI,aAAa;CAAI;AAEjF,SAAgB,EAAmB,EAAE,gBAA2D;CAC9F,IAAM,CAAC,GAAM,KAAW,EAAS,GAAM,EACjC,CAAC,GAAM,KAAW,EAAS,EAAgB,EAC3C,CAAC,GAAO,KAAY,EAAwB,KAAK,EACjD,EAAE,aAAU,SAAS,MAAoB,EAAkB,EAAK,EAChE,IAAY,EAAK,aAAa,EAAS,IAAI,MAAM,IACjD,CAAC,GAAQ,EAAE,gBAAa,EAC5B,GACA;EAAE,gBAAgB,CAAC,gBAAgB;EAAE,qBAAqB;EAAM,CACjE,EAEK,IAAY,EAAK,KAAK,MAAM,KAAK,MAAM,MAAc,MAAM,CAAC;AAwBlE,QACE,kBAAC,GAAD;EACQ;EACN,eAAe,MAAS;AAEtB,GADA,EAAQ,EAAK,EACR,KAAM,EAAS,KAAK;;YAJ7B,CAOE,kBAAC,GAAD;GAAyB,SAAA;aACvB,kBAAC,GAAD;IAAQ,MAAK;cAAb,CACE,kBAAC,GAAD,EAAM,WAAU,gBAAiB,CAAA,EAAA,gBAE1B;;GACe,CAAA,EAC1B,kBAAC,GAAD;GAAyB,WAAU;aAAnC;IACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAuB,iBAAqC,CAAA,EAC5D,kBAAC,GAAD,EAAA,UAA6B,oCAEC,CAAA,CACP,EAAA,CAAA;IACzB,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,GAAD;OACE,IAAG;OACH,OAAM;OACN,OAAO,EAAK;OACZ,WAAW,MAAS,EAAQ;QAAE,GAAG;QAAM;QAAM,CAAC;OAC9C,CAAA;MACF,kBAAC,GAAD;OACE,IAAG;OACH,OAAO;OACP,WAAW,MAAO,EAAQ;QAAE,GAAG;QAAM,WAAW;QAAI,CAAC;OAC3C;OACV,SAAS;OACT,CAAA;MACF,kBAAC,GAAD;OACE,IAAG;OACH,OAAM;OACN,MAAK;OACL,OAAO,EAAK;OACZ,WAAW,MAAY,EAAQ;QAAE,GAAG;QAAM;QAAS,CAAC;OACpD,CAAA;MACF,kBAAC,GAAD;OACE,IAAG;OACH,OAAM;OACN,OAAO,EAAK;OACZ,WAAW,MAAgB,EAAQ;QAAE,GAAG;QAAM;QAAa,CAAC;OAC5D,CAAA;MACE;;IACL,KAAS,kBAAC,GAAD,EAAW,SAAS,GAAS,CAAA;IACvC,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;KAAQ,SAzEK,YAAY;AAC/B,QAAS,KAAK;AACd,UAAI;OAWF,IAAM,KAVS,MAAM,EAAO,EAC1B,WAAW,EACT,OAAO;QACL,MAAM,EAAK,KAAK,MAAM;QACtB;QACA,SAAS,EAAK,WAAW,KAAA;QACzB,aAAa,EAAK,YAAY,MAAM,IAAI,KAAA;QACzC,EACF,EACF,CAAC,EACgB,MAAM,0BAA0B;AAGlD,OAFA,EAAQ,EAAgB,EACxB,EAAQ,GAAM,EACV,KAAI,EAAU,EAAG;eACd,GAAG;AACV,SAAS,EAAU,GAAG,sCAAsC,CAAC;;;KAuD1B,UAAU,CAAC;KAAW,eAAY;eAC9D,IAAU,cAAc;KAClB,CAAA,EACc,CAAA;IACD;KACT"}
1
+ {"version":3,"file":"CreateDialogs.js","names":[],"sources":["../../../src/planmagnet/create/CreateDialogs.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport {\n Button,\n Input,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogTrigger,\n} from '@burdenoff/fe-libs/ui';\nimport { Plus } from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\nimport { throwOnError } from '../utils/mutationResult';\n\n/**\n * Create dialogs for records whose list pages had a dead \"New …\" button, or\n * none at all (QA report 2026-09-23: C4 New Release had no onClick; H7 there\n * was no way to create a milestone). Both mutations were already served and\n * verified in prod; only the UI trigger was missing.\n */\n\nconst DIALOG_PROJECTS = gql`\n query CreateDialogProjects($workspaceId: ID!) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n }\n }\n }\n`;\n\nconst FIELD = 'mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm';\n\nfunction ErrorLine({ message }: { message: string }) {\n return (\n <p role=\"alert\" className=\"text-sm text-destructive\">\n {message}\n </p>\n );\n}\n\nfunction useDialogProjects(open: boolean) {\n const { workspaceId } = usePlanMagnet();\n const { data, loading } = useQuery<{\n planmagnetProjects: { items: Array<{ id: string; name: string }> };\n }>(DIALOG_PROJECTS, {\n variables: { workspaceId: workspaceId ?? '' },\n skip: !open || !workspaceId,\n });\n return { projects: data?.planmagnetProjects.items ?? [], loading };\n}\n\nfunction ProjectField({\n id,\n value,\n onChange,\n projects,\n loading,\n}: {\n id: string;\n value: string;\n onChange: (id: string) => void;\n projects: Array<{ id: string; name: string }>;\n loading: boolean;\n}) {\n return (\n <div>\n <label htmlFor={id} className=\"text-sm font-medium\">\n Project\n </label>\n <select id={id} className={FIELD} value={value} onChange={(e) => onChange(e.target.value)}>\n {projects.length === 0 && <option value=\"\">{loading ? 'Loading…' : 'No projects'}</option>}\n {projects.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n </select>\n </div>\n );\n}\n\nfunction TextField({\n id,\n label,\n value,\n onChange,\n type = 'text',\n placeholder,\n}: {\n id: string;\n label: string;\n value: string;\n onChange: (value: string) => void;\n type?: string;\n placeholder?: string;\n}) {\n return (\n <div>\n <label htmlFor={id} className=\"text-sm font-medium\">\n {label}\n </label>\n <Input\n id={id}\n type={type}\n className=\"mt-1\"\n value={value}\n placeholder={placeholder}\n onChange={(e) => onChange(e.target.value)}\n />\n </div>\n );\n}\n\nconst messageOf = (e: unknown, fallback: string) => (e instanceof Error ? e.message : fallback);\n\n// ─── New release (C4) ────────────────────────────────────────────────────────\n\nconst CREATE_RELEASE = gql`\n mutation CreateDialogRelease($input: PlanmagnetCreateReleaseInput!) {\n planmagnetCreateRelease(input: $input) {\n id\n }\n }\n`;\n\nconst EMPTY_RELEASE = { name: '', version: '', projectId: '', plannedDate: '', description: '' };\n\nexport function NewReleaseDialog({ onCreated }: { onCreated: (releaseId: string) => void }) {\n const [open, setOpen] = useState(false);\n const [form, setForm] = useState(EMPTY_RELEASE);\n const [error, setError] = useState<string | null>(null);\n const { projects, loading: projectsLoading } = useDialogProjects(open);\n const projectId = form.projectId || projects[0]?.id || '';\n const [create, { loading }] = useMutation<{ planmagnetCreateRelease: { id: string } }>(\n CREATE_RELEASE,\n { refetchQueries: ['ListReleases'], awaitRefetchQueries: true }\n );\n\n const canSubmit =\n form.name.trim() !== '' && form.version.trim() !== '' && projectId !== '' && !loading;\n\n const handleCreate = async () => {\n setError(null);\n try {\n const result = await throwOnError(\n create({\n variables: {\n input: {\n name: form.name.trim(),\n version: form.version.trim(),\n projectId,\n plannedDate: form.plannedDate || undefined,\n description: form.description.trim() || undefined,\n },\n },\n })\n );\n const id = result.data?.planmagnetCreateRelease.id;\n setForm(EMPTY_RELEASE);\n setOpen(false);\n if (id) onCreated(id);\n } catch (e) {\n setError(messageOf(e, 'The release could not be created.'));\n }\n };\n\n return (\n <ResponsiveDialog\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) setError(null);\n }}\n >\n <ResponsiveDialogTrigger asChild>\n <Button size=\"sm\">\n <Plus className=\"mr-1 h-4 w-4\" />\n New Release\n </Button>\n </ResponsiveDialogTrigger>\n <ResponsiveDialogContent className=\"max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New release</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>The release starts in Planning.</ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3\">\n <TextField\n id=\"new-release-name\"\n label=\"Name\"\n value={form.name}\n onChange={(name) => setForm({ ...form, name })}\n />\n <TextField\n id=\"new-release-version\"\n label=\"Version\"\n placeholder=\"e.g. 1.4.0\"\n value={form.version}\n onChange={(version) => setForm({ ...form, version })}\n />\n <ProjectField\n id=\"new-release-project\"\n value={projectId}\n onChange={(id) => setForm({ ...form, projectId: id })}\n projects={projects}\n loading={projectsLoading}\n />\n <TextField\n id=\"new-release-date\"\n label=\"Planned date\"\n type=\"date\"\n value={form.plannedDate}\n onChange={(plannedDate) => setForm({ ...form, plannedDate })}\n />\n <TextField\n id=\"new-release-description\"\n label=\"Description\"\n value={form.description}\n onChange={(description) => setForm({ ...form, description })}\n />\n </div>\n {error && <ErrorLine message={error} />}\n <ResponsiveDialogFooter>\n <Button onClick={handleCreate} disabled={!canSubmit} data-testid=\"new-release-submit\">\n {loading ? 'Creating…' : 'Create release'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\n// ─── New milestone (H7) ──────────────────────────────────────────────────────\n\nconst CREATE_MILESTONE = gql`\n mutation CreateDialogMilestone($input: PlanmagnetCreateMilestoneInput!) {\n planmagnetCreateMilestone(input: $input) {\n id\n }\n }\n`;\n\nconst EMPTY_MILESTONE = { name: '', projectId: '', dueDate: '', description: '' };\n\nexport function NewMilestoneDialog({ onCreated }: { onCreated: (milestoneId: string) => void }) {\n const [open, setOpen] = useState(false);\n const [form, setForm] = useState(EMPTY_MILESTONE);\n const [error, setError] = useState<string | null>(null);\n const { projects, loading: projectsLoading } = useDialogProjects(open);\n const projectId = form.projectId || projects[0]?.id || '';\n const [create, { loading }] = useMutation<{ planmagnetCreateMilestone: { id: string } }>(\n CREATE_MILESTONE,\n { refetchQueries: ['GetMilestones'], awaitRefetchQueries: true }\n );\n\n const canSubmit = form.name.trim() !== '' && projectId !== '' && !loading;\n\n const handleCreate = async () => {\n setError(null);\n try {\n const result = await throwOnError(\n create({\n variables: {\n input: {\n name: form.name.trim(),\n projectId,\n dueDate: form.dueDate || undefined,\n description: form.description.trim() || undefined,\n },\n },\n })\n );\n const id = result.data?.planmagnetCreateMilestone.id;\n setForm(EMPTY_MILESTONE);\n setOpen(false);\n if (id) onCreated(id);\n } catch (e) {\n setError(messageOf(e, 'The milestone could not be created.'));\n }\n };\n\n return (\n <ResponsiveDialog\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) setError(null);\n }}\n >\n <ResponsiveDialogTrigger asChild>\n <Button size=\"sm\">\n <Plus className=\"mr-1 h-4 w-4\" />\n New Milestone\n </Button>\n </ResponsiveDialogTrigger>\n <ResponsiveDialogContent className=\"max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New milestone</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n The milestone starts as Pending.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3\">\n <TextField\n id=\"new-milestone-name\"\n label=\"Name\"\n value={form.name}\n onChange={(name) => setForm({ ...form, name })}\n />\n <ProjectField\n id=\"new-milestone-project\"\n value={projectId}\n onChange={(id) => setForm({ ...form, projectId: id })}\n projects={projects}\n loading={projectsLoading}\n />\n <TextField\n id=\"new-milestone-due\"\n label=\"Due date\"\n type=\"date\"\n value={form.dueDate}\n onChange={(dueDate) => setForm({ ...form, dueDate })}\n />\n <TextField\n id=\"new-milestone-description\"\n label=\"Description\"\n value={form.description}\n onChange={(description) => setForm({ ...form, description })}\n />\n </div>\n {error && <ErrorLine message={error} />}\n <ResponsiveDialogFooter>\n <Button onClick={handleCreate} disabled={!canSubmit} data-testid=\"new-milestone-submit\">\n {loading ? 'Creating…' : 'Create milestone'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"GoalsCreateObjectivePagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/GoalsCreateObjectivePagePage.tsx"],"names":[],"mappings":"AAiBA,wBAAgB,4BAA4B,4CA2G3C"}
1
+ {"version":3,"file":"GoalsCreateObjectivePagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/GoalsCreateObjectivePagePage.tsx"],"names":[],"mappings":"AAiBA,wBAAgB,4BAA4B,4CA4G3C"}
@@ -1 +1 @@
1
- {"version":3,"file":"GoalsCreateObjectivePagePage.js","names":[],"sources":["../../../src/planmagnet/pages/GoalsCreateObjectivePagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Button, Input } from '@burdenoff/fe-libs/ui';\nimport { Save, X, Flag } from 'lucide-react';\nimport { usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\n\nconst CREATE_OBJECTIVE = gql`\n mutation CreateObjective($input: PlanmagnetCreateObjectiveInput!) {\n planmagnetCreateObjective(input: $input) {\n id\n }\n }\n`;\n\nexport function GoalsCreateObjectivePagePage() {\n const navigate = usePlanMagnetNavigate();\n const [form, setForm] = useState({\n title: '',\n description: '',\n periodLabel: '',\n endDate: '',\n });\n\n const [createObjective, { loading: saving, error }] = useMutation(CREATE_OBJECTIVE);\n\n const handleCreate = async () => {\n if (!form.title.trim() || !form.periodLabel.trim()) return;\n const result = await createObjective({\n variables: {\n input: {\n title: form.title.trim(),\n description: form.description.trim() || undefined,\n periodLabel: form.periodLabel.trim(),\n endDate: form.endDate || undefined,\n },\n },\n });\n const newId = result.data?.planmagnetCreateObjective?.id;\n if (newId) {\n navigate(`/goals/objective-detail-page?objectiveId=${newId}`);\n } else {\n navigate('/goals/goals-page');\n }\n };\n\n return (\n <div className=\"space-y-6 p-6 max-w-4xl\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Create Objective</h1>\n <p className=\"text-sm text-muted-foreground\">\n Define a workspace goal for a time period, then add key results to make progress\n measurable.\n </p>\n </div>\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={() => navigate('/goals/goals-page')}>\n <X className=\"mr-1 h-4 w-4\" />\n Cancel\n </Button>\n <Button\n size=\"sm\"\n onClick={handleCreate}\n disabled={saving || !form.title.trim() || !form.periodLabel.trim()}\n >\n <Save className=\"mr-1 h-4 w-4\" />\n {saving ? 'Creating...' : 'Create Objective'}\n </Button>\n </div>\n </div>\n {error && <div className=\"p-6 text-red-500\">Error: {error.message}</div>}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Flag className=\"h-4 w-4\" />\n Objective Details\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label className=\"text-sm font-medium\">Title</label>\n <Input\n value={form.title}\n onChange={(e) => setForm({ ...form, title: e.target.value })}\n className=\"mt-1\"\n placeholder=\"e.g. Grow enterprise revenue\"\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-[100px]\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n placeholder=\"Why this objective matters this period...\"\n />\n </div>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"text-sm font-medium\">Time Period</label>\n <Input\n value={form.periodLabel}\n onChange={(e) => setForm({ ...form, periodLabel: e.target.value })}\n className=\"mt-1\"\n placeholder=\"e.g. Q3 2026\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Target 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 </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"GoalsCreateObjectivePagePage.js","names":[],"sources":["../../../src/planmagnet/pages/GoalsCreateObjectivePagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Button, Input } from '@burdenoff/fe-libs/ui';\nimport { Save, X, Flag } from 'lucide-react';\nimport { usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\n\nconst CREATE_OBJECTIVE = gql`\n mutation CreateObjective($input: PlanmagnetCreateObjectiveInput!) {\n planmagnetCreateObjective(input: $input) {\n id\n }\n }\n`;\n\nexport function GoalsCreateObjectivePagePage() {\n const navigate = usePlanMagnetNavigate();\n const [form, setForm] = useState({\n title: '',\n description: '',\n periodLabel: '',\n endDate: '',\n });\n\n const [createObjective, { loading: saving, error }] = useMutation(CREATE_OBJECTIVE);\n\n const handleCreate = async () => {\n if (!form.title.trim() || !form.periodLabel.trim()) return;\n // mutation-error: shown from the hook's `error`; it only navigates when an id came back.\n const result = await createObjective({\n variables: {\n input: {\n title: form.title.trim(),\n description: form.description.trim() || undefined,\n periodLabel: form.periodLabel.trim(),\n endDate: form.endDate || undefined,\n },\n },\n });\n const newId = result.data?.planmagnetCreateObjective?.id;\n if (newId) {\n navigate(`/goals/objective-detail-page?objectiveId=${newId}`);\n } else {\n navigate('/goals/goals-page');\n }\n };\n\n return (\n <div className=\"space-y-6 p-6 max-w-4xl\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Create Objective</h1>\n <p className=\"text-sm text-muted-foreground\">\n Define a workspace goal for a time period, then add key results to make progress\n measurable.\n </p>\n </div>\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={() => navigate('/goals/goals-page')}>\n <X className=\"mr-1 h-4 w-4\" />\n Cancel\n </Button>\n <Button\n size=\"sm\"\n onClick={handleCreate}\n disabled={saving || !form.title.trim() || !form.periodLabel.trim()}\n >\n <Save className=\"mr-1 h-4 w-4\" />\n {saving ? 'Creating...' : 'Create Objective'}\n </Button>\n </div>\n </div>\n {error && <div className=\"p-6 text-red-500\">Error: {error.message}</div>}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Flag className=\"h-4 w-4\" />\n Objective Details\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label className=\"text-sm font-medium\">Title</label>\n <Input\n value={form.title}\n onChange={(e) => setForm({ ...form, title: e.target.value })}\n className=\"mt-1\"\n placeholder=\"e.g. Grow enterprise revenue\"\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-[100px]\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n placeholder=\"Why this objective matters this period...\"\n />\n </div>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"text-sm font-medium\">Time Period</label>\n <Input\n value={form.periodLabel}\n onChange={(e) => setForm({ ...form, periodLabel: e.target.value })}\n className=\"mt-1\"\n placeholder=\"e.g. Q3 2026\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Target 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 </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"GoalsObjectiveDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/GoalsObjectiveDetailPagePage.tsx"],"names":[],"mappings":"AAgOA,wBAAgB,4BAA4B,4CAiP3C"}
1
+ {"version":3,"file":"GoalsObjectiveDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/GoalsObjectiveDetailPagePage.tsx"],"names":[],"mappings":"AAqPA,wBAAgB,4BAA4B,4CAqQ3C"}