@burdenoff/microfe-planmagnet 2026.930.22 → 2026.930.24

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 (68) hide show
  1. package/dist/index.js +6 -5
  2. package/dist/planmagnet/PlanMagnetRoot.d.ts.map +1 -1
  3. package/dist/planmagnet/PlanMagnetRoot.js +154 -147
  4. package/dist/planmagnet/PlanMagnetRoot.js.map +1 -1
  5. package/dist/planmagnet/PlanMagnetRoutes.d.ts.map +1 -1
  6. package/dist/planmagnet/PlanMagnetRoutes.js +66 -62
  7. package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
  8. package/dist/planmagnet/controls/FeatureControls.d.ts +11 -0
  9. package/dist/planmagnet/controls/FeatureControls.d.ts.map +1 -1
  10. package/dist/planmagnet/controls/FeatureControls.js +305 -135
  11. package/dist/planmagnet/controls/FeatureControls.js.map +1 -1
  12. package/dist/planmagnet/controls/Pickers.d.ts +18 -0
  13. package/dist/planmagnet/controls/Pickers.d.ts.map +1 -1
  14. package/dist/planmagnet/controls/Pickers.js +78 -1
  15. package/dist/planmagnet/controls/Pickers.js.map +1 -1
  16. package/dist/planmagnet/controls/PrioritizationControls.d.ts +72 -0
  17. package/dist/planmagnet/controls/PrioritizationControls.d.ts.map +1 -0
  18. package/dist/planmagnet/controls/PrioritizationControls.js +246 -0
  19. package/dist/planmagnet/controls/PrioritizationControls.js.map +1 -0
  20. package/dist/planmagnet/dependency/DependencyGraph.d.ts.map +1 -1
  21. package/dist/planmagnet/dependency/DependencyGraph.js +5 -2
  22. package/dist/planmagnet/dependency/DependencyGraph.js.map +1 -1
  23. package/dist/planmagnet/dependency/GanttChart.d.ts.map +1 -1
  24. package/dist/planmagnet/dependency/GanttChart.js +11 -5
  25. package/dist/planmagnet/dependency/GanttChart.js.map +1 -1
  26. package/dist/planmagnet/index.d.ts +1 -0
  27. package/dist/planmagnet/index.d.ts.map +1 -1
  28. package/dist/planmagnet/index.js +1 -0
  29. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.d.ts.map +1 -1
  30. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js +131 -125
  31. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js.map +1 -1
  32. package/dist/planmagnet/pages/ProductsFeaturesPagePage.d.ts.map +1 -1
  33. package/dist/planmagnet/pages/ProductsFeaturesPagePage.js +183 -99
  34. package/dist/planmagnet/pages/ProductsFeaturesPagePage.js.map +1 -1
  35. package/dist/planmagnet/pages/ProductsNewFeaturePagePage.d.ts.map +1 -1
  36. package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js +113 -97
  37. package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js.map +1 -1
  38. package/dist/planmagnet/pages/ProductsPrioritizationPagePage.d.ts +2 -0
  39. package/dist/planmagnet/pages/ProductsPrioritizationPagePage.d.ts.map +1 -0
  40. package/dist/planmagnet/pages/ProductsPrioritizationPagePage.js +363 -0
  41. package/dist/planmagnet/pages/ProductsPrioritizationPagePage.js.map +1 -0
  42. package/dist/planmagnet/pages/ProductsProductDetailPagePage.d.ts.map +1 -1
  43. package/dist/planmagnet/pages/ProductsProductDetailPagePage.js +96 -79
  44. package/dist/planmagnet/pages/ProductsProductDetailPagePage.js.map +1 -1
  45. package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.d.ts.map +1 -1
  46. package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js +133 -123
  47. package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js.map +1 -1
  48. package/dist/planmagnet/pages/analytics/StatusFlowCard.js +5 -2
  49. package/dist/planmagnet/pages/analytics/StatusFlowCard.js.map +1 -1
  50. package/dist/planmagnet/pages/analytics/WorkBreakdownCard.js +5 -2
  51. package/dist/planmagnet/pages/analytics/WorkBreakdownCard.js.map +1 -1
  52. package/dist/planmagnet/product/ProductControls.d.ts +33 -0
  53. package/dist/planmagnet/product/ProductControls.d.ts.map +1 -1
  54. package/dist/planmagnet/product/ProductControls.js +593 -268
  55. package/dist/planmagnet/product/ProductControls.js.map +1 -1
  56. package/dist/planmagnet/product/routes.d.ts +10 -0
  57. package/dist/planmagnet/product/routes.d.ts.map +1 -0
  58. package/dist/planmagnet/product/routes.js +6 -0
  59. package/dist/planmagnet/product/routes.js.map +1 -0
  60. package/dist/planmagnet/roadmaps/RoadmapControls.d.ts +10 -0
  61. package/dist/planmagnet/roadmaps/RoadmapControls.d.ts.map +1 -1
  62. package/dist/planmagnet/roadmaps/RoadmapControls.js +235 -184
  63. package/dist/planmagnet/roadmaps/RoadmapControls.js.map +1 -1
  64. package/dist/planmagnet/utils/statusColor.d.ts +8 -9
  65. package/dist/planmagnet/utils/statusColor.d.ts.map +1 -1
  66. package/dist/planmagnet/utils/statusColor.js +8 -40
  67. package/dist/planmagnet/utils/statusColor.js.map +1 -1
  68. package/package.json +1 -1
@@ -2,30 +2,32 @@ import { usePlanMagnet as e, usePlanMagnetNavigate as t } from "../providers/Pla
2
2
  import { LEAVES_PAGE_CONTEXT as n, throwOnError as r } from "../utils/mutationResult.js";
3
3
  import { ConfirmButton as i, ErrorLine as a } from "../controls/ConfirmButton.js";
4
4
  import { enumLabel as o } from "../controls/WorkItemControls.js";
5
- import { detailPath as s } from "../utils/rowNavigation.js";
6
- import { useState as c } from "react";
7
- import { Archive as l, ArchiveRestore as u, Plus as d, Trash2 as f, X as p } from "lucide-react";
8
- import { gql as m } from "@apollo/client";
9
- import { useMutation as h, useQuery as g } from "@apollo/client/react";
10
- import { jsx as _, jsxs as v } from "react/jsx-runtime";
11
- import { Badge as y, Button as b, Checkbox as x, ResponsiveDialog as S, ResponsiveDialogContent as C, ResponsiveDialogDescription as w, ResponsiveDialogFooter as T, ResponsiveDialogHeader as E, ResponsiveDialogTitle as D, ResponsiveDialogTrigger as O } from "@burdenoff/fe-libs/ui";
5
+ import { mutationErrorMessage as s } from "../utils/graphqlErrors.js";
6
+ import { detailPath as c } from "../utils/rowNavigation.js";
7
+ import { CompetitorSearchSelect as l } from "../controls/Pickers.js";
8
+ import { useState as u } from "react";
9
+ import { Archive as d, ArchiveRestore as f, Pencil as p, Plus as m, Trash2 as h, X as g } from "lucide-react";
10
+ import { gql as _ } from "@apollo/client";
11
+ import { useMutation as v, useQuery as y } from "@apollo/client/react";
12
+ import { Fragment as b, jsx as x, jsxs as S } from "react/jsx-runtime";
13
+ import { Badge as C, Button as w, Card as T, CardContent as E, CardHeader as ee, CardTitle as te, Checkbox as D, Input as ne, ResponsiveDialog as O, ResponsiveDialogContent as k, ResponsiveDialogDescription as A, ResponsiveDialogFooter as j, ResponsiveDialogHeader as M, ResponsiveDialogTitle as N, ResponsiveDialogTrigger as P } from "@burdenoff/fe-libs/ui";
12
14
  //#region src/planmagnet/product/ProductControls.tsx
13
- var k = [
15
+ var F = [
14
16
  "GetProducts",
15
17
  "GetProductForEdit",
16
18
  "GetProductDetail"
17
- ], A = m`
19
+ ], re = _`
18
20
  mutation ProductControlsDelete($id: ID!) {
19
21
  planmagnetDeleteProduct(id: $id)
20
22
  }
21
- `, j = m`
23
+ `, ie = _`
22
24
  mutation ProductControlsArchive($id: ID!) {
23
25
  planmagnetArchiveProduct(id: $id) {
24
26
  id
25
27
  archivedAt
26
28
  }
27
29
  }
28
- `, M = m`
30
+ `, I = _`
29
31
  mutation ProductControlsUnarchive($id: ID!) {
30
32
  planmagnetUnarchiveProduct(id: $id) {
31
33
  id
@@ -33,69 +35,69 @@ var k = [
33
35
  }
34
36
  }
35
37
  `;
36
- function N({ productId: e, name: o, archivedAt: s }) {
37
- let d = t(), [p, m] = h(A, {
38
- refetchQueries: k,
38
+ function L({ productId: e, name: o, archivedAt: s }) {
39
+ let c = t(), [l, p] = v(re, {
40
+ refetchQueries: F,
39
41
  context: n
40
- }), [g, y] = h(j, {
41
- refetchQueries: k,
42
+ }), [m, g] = v(ie, {
43
+ refetchQueries: F,
42
44
  awaitRefetchQueries: !0
43
- }), [x, S] = h(M, {
44
- refetchQueries: k,
45
+ }), [_, y] = v(I, {
46
+ refetchQueries: F,
45
47
  awaitRefetchQueries: !0
46
- }), [C, w] = c(null), T = async () => {
47
- w(null);
48
+ }), [b, C] = u(null), T = async () => {
49
+ C(null);
48
50
  try {
49
- await r(p({ variables: { id: e } })), d("/products/products-page");
51
+ await r(l({ variables: { id: e } })), c("/products/products-page");
50
52
  } catch (e) {
51
- w(e instanceof Error ? e.message : "The product could not be deleted.");
53
+ C(e instanceof Error ? e.message : "The product could not be deleted.");
52
54
  }
53
55
  }, E = async () => {
54
- w(null);
56
+ C(null);
55
57
  try {
56
- s ? await r(x({ variables: { id: e } })) : await r(g({ variables: { id: e } }));
58
+ s ? await r(_({ variables: { id: e } })) : await r(m({ variables: { id: e } }));
57
59
  } catch (e) {
58
- w(e instanceof Error ? e.message : "The product could not be updated.");
60
+ C(e instanceof Error ? e.message : "The product could not be updated.");
59
61
  }
60
62
  };
61
- return /* @__PURE__ */ v("div", {
63
+ return /* @__PURE__ */ S("div", {
62
64
  className: "flex flex-col items-end gap-2",
63
- children: [/* @__PURE__ */ v("div", {
65
+ children: [/* @__PURE__ */ S("div", {
64
66
  className: "flex gap-2",
65
- children: [/* @__PURE__ */ v(b, {
67
+ children: [/* @__PURE__ */ S(w, {
66
68
  size: "sm",
67
69
  variant: "outline",
68
70
  "data-testid": "product-toggle-archive",
69
- disabled: y.loading || S.loading,
71
+ disabled: g.loading || y.loading,
70
72
  onClick: () => void E(),
71
- children: [_(s ? u : l, { className: "mr-1 h-4 w-4" }), s ? "Unarchive" : "Archive"]
72
- }), /* @__PURE__ */ _(i, {
73
+ children: [x(s ? f : d, { className: "mr-1 h-4 w-4" }), s ? "Unarchive" : "Archive"]
74
+ }), /* @__PURE__ */ x(i, {
73
75
  label: "Delete",
74
76
  variant: "outline",
75
- icon: /* @__PURE__ */ _(f, { className: "mr-1 h-4 w-4" }),
77
+ icon: /* @__PURE__ */ x(h, { className: "mr-1 h-4 w-4" }),
76
78
  title: `Delete ${o}?`,
77
79
  description: "Every linked roadmap, release and feature request stays intact — only its link to this product is cleared. This cannot be undone here.",
78
80
  confirmLabel: "Delete product",
79
81
  destructive: !0,
80
- disabled: m.loading,
82
+ disabled: p.loading,
81
83
  onConfirm: () => void T()
82
84
  })]
83
- }), C && /* @__PURE__ */ _(a, { message: C })]
85
+ }), b && /* @__PURE__ */ x(a, { message: b })]
84
86
  });
85
87
  }
86
- var P = m`
88
+ var R = _`
87
89
  mutation ProductControlsLinkRoadmap($productId: ID!, $roadmapId: ID!) {
88
90
  planmagnetLinkProductRoadmap(productId: $productId, roadmapId: $roadmapId) {
89
91
  id
90
92
  }
91
93
  }
92
- `, F = m`
94
+ `, z = _`
93
95
  mutation ProductControlsUnlinkRoadmap($productId: ID!, $roadmapId: ID!) {
94
96
  planmagnetUnlinkProductRoadmap(productId: $productId, roadmapId: $roadmapId) {
95
97
  id
96
98
  }
97
99
  }
98
- `, I = m`
100
+ `, B = _`
99
101
  query ProductControlsCandidateRoadmaps($workspaceId: ID!) {
100
102
  planmagnetRoadmaps(workspaceId: $workspaceId, pagination: { first: 100 }) {
101
103
  items {
@@ -106,12 +108,12 @@ var P = m`
106
108
  }
107
109
  }
108
110
  `;
109
- function L({ productId: e, roadmaps: n }) {
110
- let i = t(), [o, l] = h(F, {
111
- refetchQueries: k,
111
+ function V({ productId: e, roadmaps: n }) {
112
+ let i = t(), [o, s] = v(z, {
113
+ refetchQueries: F,
112
114
  awaitRefetchQueries: !0
113
- }), [u, d] = c(null), [f, m] = c(null), g = async (t) => {
114
- d(null), m(t);
115
+ }), [l, d] = u(null), [f, p] = u(null), m = async (t) => {
116
+ d(null), p(t);
115
117
  try {
116
118
  await r(o({ variables: {
117
119
  productId: e,
@@ -120,115 +122,115 @@ function L({ productId: e, roadmaps: n }) {
120
122
  } catch (e) {
121
123
  d(e instanceof Error ? e.message : "The roadmap could not be unlinked.");
122
124
  } finally {
123
- m(null);
125
+ p(null);
124
126
  }
125
127
  };
126
- return /* @__PURE__ */ v("div", {
128
+ return /* @__PURE__ */ S("div", {
127
129
  className: "space-y-3",
128
130
  "data-testid": "product-roadmaps",
129
131
  children: [
130
- /* @__PURE__ */ v("div", {
132
+ /* @__PURE__ */ S("div", {
131
133
  className: "flex items-center justify-between",
132
- children: [/* @__PURE__ */ v("p", {
134
+ children: [/* @__PURE__ */ S("p", {
133
135
  className: "text-sm text-muted-foreground",
134
136
  children: [
135
137
  n.length,
136
138
  " roadmap",
137
139
  n.length === 1 ? "" : "s"
138
140
  ]
139
- }), /* @__PURE__ */ _(R, {
141
+ }), /* @__PURE__ */ x(H, {
140
142
  productId: e,
141
143
  existingIds: n.map((e) => e.id)
142
144
  })]
143
145
  }),
144
- u && /* @__PURE__ */ _(a, { message: u }),
145
- n.length === 0 ? /* @__PURE__ */ _("p", {
146
+ l && /* @__PURE__ */ x(a, { message: l }),
147
+ n.length === 0 ? /* @__PURE__ */ x("p", {
146
148
  className: "text-sm text-muted-foreground text-center py-4",
147
149
  children: "No roadmaps linked to this product yet."
148
- }) : /* @__PURE__ */ _("ul", {
150
+ }) : /* @__PURE__ */ x("ul", {
149
151
  className: "space-y-1",
150
- children: n.map((e) => /* @__PURE__ */ v("li", {
152
+ children: n.map((e) => /* @__PURE__ */ S("li", {
151
153
  className: "flex items-center justify-between gap-2 border rounded-md p-2 text-sm",
152
- children: [/* @__PURE__ */ _("button", {
154
+ children: [/* @__PURE__ */ x("button", {
153
155
  type: "button",
154
156
  className: "min-w-0 truncate text-left hover:underline",
155
- onClick: () => i(s("/products/roadmap-detail-page", e.id)),
157
+ onClick: () => i(c("/products/roadmap-detail-page", e.id)),
156
158
  children: e.name
157
- }), /* @__PURE__ */ _(b, {
159
+ }), /* @__PURE__ */ x(w, {
158
160
  size: "sm",
159
161
  variant: "ghost",
160
162
  "aria-label": `Unlink ${e.name} from product`,
161
- disabled: l.loading,
162
- onClick: () => void g(e.id),
163
- children: f === e.id ? "…" : /* @__PURE__ */ _(p, { className: "h-4 w-4" })
163
+ disabled: s.loading,
164
+ onClick: () => void m(e.id),
165
+ children: f === e.id ? "…" : /* @__PURE__ */ x(g, { className: "h-4 w-4" })
164
166
  })]
165
167
  }, e.id))
166
168
  })
167
169
  ]
168
170
  });
169
171
  }
170
- function R({ productId: t, existingIds: n }) {
171
- let { workspaceId: i } = e(), [o, s] = c(!1), [l, u] = c(/* @__PURE__ */ new Set()), [f, p] = c(null), { data: m, loading: y } = g(I, {
172
+ function H({ productId: t, existingIds: n }) {
173
+ let { workspaceId: i } = e(), [o, s] = u(!1), [c, l] = u(/* @__PURE__ */ new Set()), [d, f] = u(null), { data: p, loading: h } = y(B, {
172
174
  variables: { workspaceId: i ?? "" },
173
175
  skip: !o || !i
174
- }), A = (m?.planmagnetRoadmaps.items ?? []).filter((e) => !n.includes(e.id)), [j, M] = h(P, {
175
- refetchQueries: k,
176
+ }), g = (p?.planmagnetRoadmaps.items ?? []).filter((e) => !n.includes(e.id)), [_, b] = v(R, {
177
+ refetchQueries: F,
176
178
  awaitRefetchQueries: !0
177
- }), N = (e, t) => u((n) => {
179
+ }), C = (e, t) => l((n) => {
178
180
  let r = new Set(n);
179
181
  return t ? r.add(e) : r.delete(e), r;
180
- }), F = () => {
181
- u(/* @__PURE__ */ new Set()), p(null);
182
- }, L = async () => {
183
- p(null);
182
+ }), T = () => {
183
+ l(/* @__PURE__ */ new Set()), f(null);
184
+ }, E = async () => {
185
+ f(null);
184
186
  try {
185
- await Promise.all([...l].map((e) => r(j({ variables: {
187
+ await Promise.all([...c].map((e) => r(_({ variables: {
186
188
  productId: t,
187
189
  roadmapId: e
188
- } })))), F(), s(!1);
190
+ } })))), T(), s(!1);
189
191
  } catch (e) {
190
- p(e instanceof Error ? e.message : "The roadmaps could not be linked.");
192
+ f(e instanceof Error ? e.message : "The roadmaps could not be linked.");
191
193
  }
192
194
  };
193
- return /* @__PURE__ */ v(S, {
195
+ return /* @__PURE__ */ S(O, {
194
196
  open: o,
195
197
  onOpenChange: (e) => {
196
- s(e), e || F();
198
+ s(e), e || T();
197
199
  },
198
- children: [/* @__PURE__ */ _(O, {
200
+ children: [/* @__PURE__ */ x(P, {
199
201
  asChild: !0,
200
- children: /* @__PURE__ */ v(b, {
202
+ children: /* @__PURE__ */ S(w, {
201
203
  size: "sm",
202
204
  variant: "outline",
203
205
  "data-testid": "product-add-roadmaps",
204
- children: [/* @__PURE__ */ _(d, { className: "mr-1 h-4 w-4" }), "Add roadmap"]
206
+ children: [/* @__PURE__ */ x(m, { className: "mr-1 h-4 w-4" }), "Add roadmap"]
205
207
  })
206
- }), /* @__PURE__ */ v(C, {
208
+ }), /* @__PURE__ */ S(k, {
207
209
  className: "max-w-lg",
208
210
  children: [
209
- /* @__PURE__ */ v(E, { children: [/* @__PURE__ */ _(D, { children: "Link roadmaps" }), /* @__PURE__ */ _(w, { children: "Linking a roadmap does not move or copy it — it stays exactly where it is, now also reachable from this product." })] }),
210
- /* @__PURE__ */ v("div", {
211
+ /* @__PURE__ */ S(M, { children: [/* @__PURE__ */ x(N, { children: "Link roadmaps" }), /* @__PURE__ */ x(A, { children: "Linking a roadmap does not move or copy it — it stays exactly where it is, now also reachable from this product." })] }),
212
+ /* @__PURE__ */ S("div", {
211
213
  className: "max-h-80 overflow-y-auto space-y-1",
212
214
  "data-testid": "product-add-roadmap-candidates",
213
215
  children: [
214
- y && /* @__PURE__ */ _("p", {
216
+ h && /* @__PURE__ */ x("p", {
215
217
  className: "text-sm text-muted-foreground py-4 text-center",
216
218
  children: "Loading…"
217
219
  }),
218
- !y && A.length === 0 && /* @__PURE__ */ _("p", {
220
+ !h && g.length === 0 && /* @__PURE__ */ x("p", {
219
221
  className: "text-sm text-muted-foreground py-4 text-center",
220
222
  children: "Every roadmap in this workspace is already linked to this product."
221
223
  }),
222
- A.map((e) => {
224
+ g.map((e) => {
223
225
  let t = `product-add-roadmap-${e.id}`;
224
- return /* @__PURE__ */ v("label", {
226
+ return /* @__PURE__ */ S("label", {
225
227
  htmlFor: t,
226
228
  className: "flex items-center gap-3 border rounded-md p-2 text-sm cursor-pointer hover:bg-muted",
227
- children: [/* @__PURE__ */ _(x, {
229
+ children: [/* @__PURE__ */ x(D, {
228
230
  id: t,
229
- checked: l.has(e.id),
230
- onCheckedChange: (t) => N(e.id, t === !0)
231
- }), /* @__PURE__ */ _("span", {
231
+ checked: c.has(e.id),
232
+ onCheckedChange: (t) => C(e.id, t === !0)
233
+ }), /* @__PURE__ */ x("span", {
232
234
  className: "min-w-0 flex-1 truncate",
233
235
  children: e.name
234
236
  })]
@@ -236,30 +238,30 @@ function R({ productId: t, existingIds: n }) {
236
238
  })
237
239
  ]
238
240
  }),
239
- f && /* @__PURE__ */ _(a, { message: f }),
240
- /* @__PURE__ */ _(T, { children: /* @__PURE__ */ _(b, {
241
- onClick: () => void L(),
242
- disabled: l.size === 0 || M.loading,
241
+ d && /* @__PURE__ */ x(a, { message: d }),
242
+ /* @__PURE__ */ x(j, { children: /* @__PURE__ */ x(w, {
243
+ onClick: () => void E(),
244
+ disabled: c.size === 0 || b.loading,
243
245
  "data-testid": "product-add-roadmaps-confirm",
244
- children: M.loading ? "Linking…" : `Link ${l.size} roadmap${l.size === 1 ? "" : "s"}`
246
+ children: b.loading ? "Linking…" : `Link ${c.size} roadmap${c.size === 1 ? "" : "s"}`
245
247
  }) })
246
248
  ]
247
249
  })]
248
250
  });
249
251
  }
250
- var z = m`
252
+ var U = _`
251
253
  mutation ProductControlsLinkRelease($productId: ID!, $releaseId: ID!) {
252
254
  planmagnetLinkProductRelease(productId: $productId, releaseId: $releaseId) {
253
255
  id
254
256
  }
255
257
  }
256
- `, B = m`
258
+ `, W = _`
257
259
  mutation ProductControlsUnlinkRelease($productId: ID!, $releaseId: ID!) {
258
260
  planmagnetUnlinkProductRelease(productId: $productId, releaseId: $releaseId) {
259
261
  id
260
262
  }
261
263
  }
262
- `, V = m`
264
+ `, G = _`
263
265
  query ProductControlsCandidateReleases($workspaceId: ID!) {
264
266
  planmagnetReleases(workspaceId: $workspaceId, pagination: { first: 100 }) {
265
267
  items {
@@ -272,70 +274,70 @@ var z = m`
272
274
  }
273
275
  }
274
276
  `;
275
- function H({ productId: e, releases: n }) {
276
- let i = t(), [l, u] = h(B, {
277
- refetchQueries: k,
277
+ function K({ productId: e, releases: n }) {
278
+ let i = t(), [s, l] = v(W, {
279
+ refetchQueries: F,
278
280
  awaitRefetchQueries: !0
279
- }), [d, f] = c(null), [m, g] = c(null), x = async (t) => {
280
- f(null), g(t);
281
+ }), [d, f] = u(null), [p, m] = u(null), h = async (t) => {
282
+ f(null), m(t);
281
283
  try {
282
- await r(l({ variables: {
284
+ await r(s({ variables: {
283
285
  productId: e,
284
286
  releaseId: t
285
287
  } }));
286
288
  } catch (e) {
287
289
  f(e instanceof Error ? e.message : "The release could not be unlinked.");
288
290
  } finally {
289
- g(null);
291
+ m(null);
290
292
  }
291
293
  };
292
- return /* @__PURE__ */ v("div", {
294
+ return /* @__PURE__ */ S("div", {
293
295
  className: "space-y-3",
294
296
  "data-testid": "product-releases",
295
297
  children: [
296
- /* @__PURE__ */ v("div", {
298
+ /* @__PURE__ */ S("div", {
297
299
  className: "flex items-center justify-between",
298
- children: [/* @__PURE__ */ v("p", {
300
+ children: [/* @__PURE__ */ S("p", {
299
301
  className: "text-sm text-muted-foreground",
300
302
  children: [
301
303
  n.length,
302
304
  " release",
303
305
  n.length === 1 ? "" : "s"
304
306
  ]
305
- }), /* @__PURE__ */ _(U, {
307
+ }), /* @__PURE__ */ x(q, {
306
308
  productId: e,
307
309
  existingIds: n.map((e) => e.id)
308
310
  })]
309
311
  }),
310
- d && /* @__PURE__ */ _(a, { message: d }),
311
- n.length === 0 ? /* @__PURE__ */ _("p", {
312
+ d && /* @__PURE__ */ x(a, { message: d }),
313
+ n.length === 0 ? /* @__PURE__ */ x("p", {
312
314
  className: "text-sm text-muted-foreground text-center py-4",
313
315
  children: "No releases linked to this product yet."
314
- }) : /* @__PURE__ */ _("ul", {
316
+ }) : /* @__PURE__ */ x("ul", {
315
317
  className: "space-y-1",
316
- children: n.map((e) => /* @__PURE__ */ v("li", {
318
+ children: n.map((e) => /* @__PURE__ */ S("li", {
317
319
  className: "flex items-center justify-between gap-2 border rounded-md p-2 text-sm",
318
- children: [/* @__PURE__ */ v("button", {
320
+ children: [/* @__PURE__ */ S("button", {
319
321
  type: "button",
320
322
  className: "min-w-0 truncate text-left hover:underline",
321
- onClick: () => i(s("/products/release-detail-page", e.id)),
322
- children: [/* @__PURE__ */ _("span", {
323
+ onClick: () => i(c("/products/release-detail-page", e.id)),
324
+ children: [/* @__PURE__ */ x("span", {
323
325
  className: "text-muted-foreground mr-2",
324
326
  children: e.version
325
327
  }), e.name]
326
- }), /* @__PURE__ */ v("div", {
328
+ }), /* @__PURE__ */ S("div", {
327
329
  className: "flex items-center gap-2 shrink-0",
328
- children: [/* @__PURE__ */ _(y, {
330
+ children: [/* @__PURE__ */ x(C, {
329
331
  variant: "outline",
330
332
  className: "text-xs capitalize",
331
333
  children: o(e.status)
332
- }), /* @__PURE__ */ _(b, {
334
+ }), /* @__PURE__ */ x(w, {
333
335
  size: "sm",
334
336
  variant: "ghost",
335
337
  "aria-label": `Unlink ${e.name} from product`,
336
- disabled: u.loading,
337
- onClick: () => void x(e.id),
338
- children: m === e.id ? "…" : /* @__PURE__ */ _(p, { className: "h-4 w-4" })
338
+ disabled: l.loading,
339
+ onClick: () => void h(e.id),
340
+ children: p === e.id ? "…" : /* @__PURE__ */ x(g, { className: "h-4 w-4" })
339
341
  })]
340
342
  })]
341
343
  }, e.id))
@@ -343,70 +345,70 @@ function H({ productId: e, releases: n }) {
343
345
  ]
344
346
  });
345
347
  }
346
- function U({ productId: t, existingIds: n }) {
347
- let { workspaceId: i } = e(), [o, s] = c(!1), [l, u] = c(/* @__PURE__ */ new Set()), [f, p] = c(null), { data: m, loading: y } = g(V, {
348
+ function q({ productId: t, existingIds: n }) {
349
+ let { workspaceId: i } = e(), [o, s] = u(!1), [c, l] = u(/* @__PURE__ */ new Set()), [d, f] = u(null), { data: p, loading: h } = y(G, {
348
350
  variables: { workspaceId: i ?? "" },
349
351
  skip: !o || !i
350
- }), A = (m?.planmagnetReleases.items ?? []).filter((e) => !n.includes(e.id)), [j, M] = h(z, {
351
- refetchQueries: k,
352
+ }), g = (p?.planmagnetReleases.items ?? []).filter((e) => !n.includes(e.id)), [_, b] = v(U, {
353
+ refetchQueries: F,
352
354
  awaitRefetchQueries: !0
353
- }), N = (e, t) => u((n) => {
355
+ }), C = (e, t) => l((n) => {
354
356
  let r = new Set(n);
355
357
  return t ? r.add(e) : r.delete(e), r;
356
- }), P = () => {
357
- u(/* @__PURE__ */ new Set()), p(null);
358
- }, F = async () => {
359
- p(null);
358
+ }), T = () => {
359
+ l(/* @__PURE__ */ new Set()), f(null);
360
+ }, E = async () => {
361
+ f(null);
360
362
  try {
361
- await Promise.all([...l].map((e) => r(j({ variables: {
363
+ await Promise.all([...c].map((e) => r(_({ variables: {
362
364
  productId: t,
363
365
  releaseId: e
364
- } })))), P(), s(!1);
366
+ } })))), T(), s(!1);
365
367
  } catch (e) {
366
- p(e instanceof Error ? e.message : "The releases could not be linked.");
368
+ f(e instanceof Error ? e.message : "The releases could not be linked.");
367
369
  }
368
370
  };
369
- return /* @__PURE__ */ v(S, {
371
+ return /* @__PURE__ */ S(O, {
370
372
  open: o,
371
373
  onOpenChange: (e) => {
372
- s(e), e || P();
374
+ s(e), e || T();
373
375
  },
374
- children: [/* @__PURE__ */ _(O, {
376
+ children: [/* @__PURE__ */ x(P, {
375
377
  asChild: !0,
376
- children: /* @__PURE__ */ v(b, {
378
+ children: /* @__PURE__ */ S(w, {
377
379
  size: "sm",
378
380
  variant: "outline",
379
381
  "data-testid": "product-add-releases",
380
- children: [/* @__PURE__ */ _(d, { className: "mr-1 h-4 w-4" }), "Add release"]
382
+ children: [/* @__PURE__ */ x(m, { className: "mr-1 h-4 w-4" }), "Add release"]
381
383
  })
382
- }), /* @__PURE__ */ v(C, {
384
+ }), /* @__PURE__ */ S(k, {
383
385
  className: "max-w-lg",
384
386
  children: [
385
- /* @__PURE__ */ v(E, { children: [/* @__PURE__ */ _(D, { children: "Link releases" }), /* @__PURE__ */ _(w, { children: "Linking a release does not move or copy it — it stays exactly where it is, now also reachable from this product." })] }),
386
- /* @__PURE__ */ v("div", {
387
+ /* @__PURE__ */ S(M, { children: [/* @__PURE__ */ x(N, { children: "Link releases" }), /* @__PURE__ */ x(A, { children: "Linking a release does not move or copy it — it stays exactly where it is, now also reachable from this product." })] }),
388
+ /* @__PURE__ */ S("div", {
387
389
  className: "max-h-80 overflow-y-auto space-y-1",
388
390
  "data-testid": "product-add-release-candidates",
389
391
  children: [
390
- y && /* @__PURE__ */ _("p", {
392
+ h && /* @__PURE__ */ x("p", {
391
393
  className: "text-sm text-muted-foreground py-4 text-center",
392
394
  children: "Loading…"
393
395
  }),
394
- !y && A.length === 0 && /* @__PURE__ */ _("p", {
396
+ !h && g.length === 0 && /* @__PURE__ */ x("p", {
395
397
  className: "text-sm text-muted-foreground py-4 text-center",
396
398
  children: "Every release in this workspace is already linked to this product."
397
399
  }),
398
- A.map((e) => {
400
+ g.map((e) => {
399
401
  let t = `product-add-release-${e.id}`;
400
- return /* @__PURE__ */ v("label", {
402
+ return /* @__PURE__ */ S("label", {
401
403
  htmlFor: t,
402
404
  className: "flex items-center gap-3 border rounded-md p-2 text-sm cursor-pointer hover:bg-muted",
403
- children: [/* @__PURE__ */ _(x, {
405
+ children: [/* @__PURE__ */ x(D, {
404
406
  id: t,
405
- checked: l.has(e.id),
406
- onCheckedChange: (t) => N(e.id, t === !0)
407
- }), /* @__PURE__ */ v("span", {
407
+ checked: c.has(e.id),
408
+ onCheckedChange: (t) => C(e.id, t === !0)
409
+ }), /* @__PURE__ */ S("span", {
408
410
  className: "min-w-0 flex-1 truncate",
409
- children: [/* @__PURE__ */ _("span", {
411
+ children: [/* @__PURE__ */ x("span", {
410
412
  className: "text-muted-foreground mr-2",
411
413
  children: e.version
412
414
  }), e.name]
@@ -415,18 +417,18 @@ function U({ productId: t, existingIds: n }) {
415
417
  })
416
418
  ]
417
419
  }),
418
- f && /* @__PURE__ */ _(a, { message: f }),
419
- /* @__PURE__ */ _(T, { children: /* @__PURE__ */ _(b, {
420
- onClick: () => void F(),
421
- disabled: l.size === 0 || M.loading,
420
+ d && /* @__PURE__ */ x(a, { message: d }),
421
+ /* @__PURE__ */ x(j, { children: /* @__PURE__ */ x(w, {
422
+ onClick: () => void E(),
423
+ disabled: c.size === 0 || b.loading,
422
424
  "data-testid": "product-add-releases-confirm",
423
- children: M.loading ? "Linking…" : `Link ${l.size} release${l.size === 1 ? "" : "s"}`
425
+ children: b.loading ? "Linking…" : `Link ${c.size} release${c.size === 1 ? "" : "s"}`
424
426
  }) })
425
427
  ]
426
428
  })]
427
429
  });
428
430
  }
429
- var W = m`
431
+ var J = _`
430
432
  mutation ProductControlsLinkFeatureRequest($productId: ID!, $featureRequestId: ID!) {
431
433
  planmagnetLinkProductFeatureRequest(
432
434
  productId: $productId
@@ -435,7 +437,7 @@ var W = m`
435
437
  id
436
438
  }
437
439
  }
438
- `, G = m`
440
+ `, ae = _`
439
441
  mutation ProductControlsUnlinkFeatureRequest($productId: ID!, $featureRequestId: ID!) {
440
442
  planmagnetUnlinkProductFeatureRequest(
441
443
  productId: $productId
@@ -444,7 +446,7 @@ var W = m`
444
446
  id
445
447
  }
446
448
  }
447
- `, K = m`
449
+ `, oe = _`
448
450
  query ProductControlsCandidateFeatureRequests($workspaceId: ID!) {
449
451
  planmagnetFeatureRequests(workspaceId: $workspaceId, pagination: { first: 100 }) {
450
452
  items {
@@ -456,67 +458,67 @@ var W = m`
456
458
  }
457
459
  }
458
460
  `;
459
- function q({ productId: e, featureRequests: n }) {
460
- let i = t(), [l, u] = h(G, {
461
- refetchQueries: k,
461
+ function se({ productId: e, featureRequests: n }) {
462
+ let i = t(), [s, l] = v(ae, {
463
+ refetchQueries: F,
462
464
  awaitRefetchQueries: !0
463
- }), [d, f] = c(null), [m, g] = c(null), x = async (t) => {
464
- f(null), g(t);
465
+ }), [d, f] = u(null), [p, m] = u(null), h = async (t) => {
466
+ f(null), m(t);
465
467
  try {
466
- await r(l({ variables: {
468
+ await r(s({ variables: {
467
469
  productId: e,
468
470
  featureRequestId: t
469
471
  } }));
470
472
  } catch (e) {
471
473
  f(e instanceof Error ? e.message : "The feature request could not be unlinked.");
472
474
  } finally {
473
- g(null);
475
+ m(null);
474
476
  }
475
477
  };
476
- return /* @__PURE__ */ v("div", {
478
+ return /* @__PURE__ */ S("div", {
477
479
  className: "space-y-3",
478
480
  "data-testid": "product-feature-requests",
479
481
  children: [
480
- /* @__PURE__ */ v("div", {
482
+ /* @__PURE__ */ S("div", {
481
483
  className: "flex items-center justify-between",
482
- children: [/* @__PURE__ */ v("p", {
484
+ children: [/* @__PURE__ */ S("p", {
483
485
  className: "text-sm text-muted-foreground",
484
486
  children: [
485
487
  n.length,
486
488
  " feature request",
487
489
  n.length === 1 ? "" : "s"
488
490
  ]
489
- }), /* @__PURE__ */ _(J, {
491
+ }), /* @__PURE__ */ x(ce, {
490
492
  productId: e,
491
493
  existingIds: n.map((e) => e.id)
492
494
  })]
493
495
  }),
494
- d && /* @__PURE__ */ _(a, { message: d }),
495
- n.length === 0 ? /* @__PURE__ */ _("p", {
496
+ d && /* @__PURE__ */ x(a, { message: d }),
497
+ n.length === 0 ? /* @__PURE__ */ x("p", {
496
498
  className: "text-sm text-muted-foreground text-center py-4",
497
499
  children: "No feature requests linked to this product yet."
498
- }) : /* @__PURE__ */ _("ul", {
500
+ }) : /* @__PURE__ */ x("ul", {
499
501
  className: "space-y-1",
500
- children: n.map((e) => /* @__PURE__ */ v("li", {
502
+ children: n.map((e) => /* @__PURE__ */ S("li", {
501
503
  className: "flex items-center justify-between gap-2 border rounded-md p-2 text-sm",
502
- children: [/* @__PURE__ */ _("button", {
504
+ children: [/* @__PURE__ */ x("button", {
503
505
  type: "button",
504
506
  className: "min-w-0 truncate text-left hover:underline",
505
- onClick: () => i(s("/products/feature-detail-page", e.id)),
507
+ onClick: () => i(c("/products/feature-detail-page", e.id)),
506
508
  children: e.title
507
- }), /* @__PURE__ */ v("div", {
509
+ }), /* @__PURE__ */ S("div", {
508
510
  className: "flex items-center gap-2 shrink-0",
509
- children: [/* @__PURE__ */ _(y, {
511
+ children: [/* @__PURE__ */ x(C, {
510
512
  variant: "secondary",
511
513
  className: "text-xs capitalize",
512
514
  children: o(e.status)
513
- }), /* @__PURE__ */ _(b, {
515
+ }), /* @__PURE__ */ x(w, {
514
516
  size: "sm",
515
517
  variant: "ghost",
516
518
  "aria-label": `Unlink ${e.title} from product`,
517
- disabled: u.loading,
518
- onClick: () => void x(e.id),
519
- children: m === e.id ? "…" : /* @__PURE__ */ _(p, { className: "h-4 w-4" })
519
+ disabled: l.loading,
520
+ onClick: () => void h(e.id),
521
+ children: p === e.id ? "…" : /* @__PURE__ */ x(g, { className: "h-4 w-4" })
520
522
  })]
521
523
  })]
522
524
  }, e.id))
@@ -524,68 +526,68 @@ function q({ productId: e, featureRequests: n }) {
524
526
  ]
525
527
  });
526
528
  }
527
- function J({ productId: t, existingIds: n }) {
528
- let { workspaceId: i } = e(), [o, s] = c(!1), [l, u] = c(/* @__PURE__ */ new Set()), [f, p] = c(null), { data: m, loading: y } = g(K, {
529
+ function ce({ productId: t, existingIds: n }) {
530
+ let { workspaceId: i } = e(), [o, s] = u(!1), [c, l] = u(/* @__PURE__ */ new Set()), [d, f] = u(null), { data: p, loading: h } = y(oe, {
529
531
  variables: { workspaceId: i ?? "" },
530
532
  skip: !o || !i
531
- }), A = (m?.planmagnetFeatureRequests.items ?? []).filter((e) => !n.includes(e.id)), [j, M] = h(W, {
532
- refetchQueries: k,
533
+ }), g = (p?.planmagnetFeatureRequests.items ?? []).filter((e) => !n.includes(e.id)), [_, b] = v(J, {
534
+ refetchQueries: F,
533
535
  awaitRefetchQueries: !0
534
- }), N = (e, t) => u((n) => {
536
+ }), C = (e, t) => l((n) => {
535
537
  let r = new Set(n);
536
538
  return t ? r.add(e) : r.delete(e), r;
537
- }), P = () => {
538
- u(/* @__PURE__ */ new Set()), p(null);
539
- }, F = async () => {
540
- p(null);
539
+ }), T = () => {
540
+ l(/* @__PURE__ */ new Set()), f(null);
541
+ }, E = async () => {
542
+ f(null);
541
543
  try {
542
- await Promise.all([...l].map((e) => r(j({ variables: {
544
+ await Promise.all([...c].map((e) => r(_({ variables: {
543
545
  productId: t,
544
546
  featureRequestId: e
545
- } })))), P(), s(!1);
547
+ } })))), T(), s(!1);
546
548
  } catch (e) {
547
- p(e instanceof Error ? e.message : "The feature requests could not be linked.");
549
+ f(e instanceof Error ? e.message : "The feature requests could not be linked.");
548
550
  }
549
551
  };
550
- return /* @__PURE__ */ v(S, {
552
+ return /* @__PURE__ */ S(O, {
551
553
  open: o,
552
554
  onOpenChange: (e) => {
553
- s(e), e || P();
555
+ s(e), e || T();
554
556
  },
555
- children: [/* @__PURE__ */ _(O, {
557
+ children: [/* @__PURE__ */ x(P, {
556
558
  asChild: !0,
557
- children: /* @__PURE__ */ v(b, {
559
+ children: /* @__PURE__ */ S(w, {
558
560
  size: "sm",
559
561
  variant: "outline",
560
562
  "data-testid": "product-add-feature-requests",
561
- children: [/* @__PURE__ */ _(d, { className: "mr-1 h-4 w-4" }), "Add feature request"]
563
+ children: [/* @__PURE__ */ x(m, { className: "mr-1 h-4 w-4" }), "Add feature request"]
562
564
  })
563
- }), /* @__PURE__ */ v(C, {
565
+ }), /* @__PURE__ */ S(k, {
564
566
  className: "max-w-lg",
565
567
  children: [
566
- /* @__PURE__ */ v(E, { children: [/* @__PURE__ */ _(D, { children: "Link feature requests" }), /* @__PURE__ */ _(w, { children: "Linking a feature request does not move or copy it — it stays exactly where it is, now also reachable from this product." })] }),
567
- /* @__PURE__ */ v("div", {
568
+ /* @__PURE__ */ S(M, { children: [/* @__PURE__ */ x(N, { children: "Link feature requests" }), /* @__PURE__ */ x(A, { children: "Linking a feature request does not move or copy it — it stays exactly where it is, now also reachable from this product." })] }),
569
+ /* @__PURE__ */ S("div", {
568
570
  className: "max-h-80 overflow-y-auto space-y-1",
569
571
  "data-testid": "product-add-feature-request-candidates",
570
572
  children: [
571
- y && /* @__PURE__ */ _("p", {
573
+ h && /* @__PURE__ */ x("p", {
572
574
  className: "text-sm text-muted-foreground py-4 text-center",
573
575
  children: "Loading…"
574
576
  }),
575
- !y && A.length === 0 && /* @__PURE__ */ _("p", {
577
+ !h && g.length === 0 && /* @__PURE__ */ x("p", {
576
578
  className: "text-sm text-muted-foreground py-4 text-center",
577
579
  children: "Every feature request in this workspace is already linked to this product."
578
580
  }),
579
- A.map((e) => {
581
+ g.map((e) => {
580
582
  let t = `product-add-feature-${e.id}`;
581
- return /* @__PURE__ */ v("label", {
583
+ return /* @__PURE__ */ S("label", {
582
584
  htmlFor: t,
583
585
  className: "flex items-center gap-3 border rounded-md p-2 text-sm cursor-pointer hover:bg-muted",
584
- children: [/* @__PURE__ */ _(x, {
586
+ children: [/* @__PURE__ */ x(D, {
585
587
  id: t,
586
- checked: l.has(e.id),
587
- onCheckedChange: (t) => N(e.id, t === !0)
588
- }), /* @__PURE__ */ _("span", {
588
+ checked: c.has(e.id),
589
+ onCheckedChange: (t) => C(e.id, t === !0)
590
+ }), /* @__PURE__ */ x("span", {
589
591
  className: "min-w-0 flex-1 truncate",
590
592
  children: e.title
591
593
  })]
@@ -593,28 +595,28 @@ function J({ productId: t, existingIds: n }) {
593
595
  })
594
596
  ]
595
597
  }),
596
- f && /* @__PURE__ */ _(a, { message: f }),
597
- /* @__PURE__ */ _(T, { children: /* @__PURE__ */ _(b, {
598
- onClick: () => void F(),
599
- disabled: l.size === 0 || M.loading,
598
+ d && /* @__PURE__ */ x(a, { message: d }),
599
+ /* @__PURE__ */ x(j, { children: /* @__PURE__ */ x(w, {
600
+ onClick: () => void E(),
601
+ disabled: c.size === 0 || b.loading,
600
602
  "data-testid": "product-add-feature-requests-confirm",
601
- children: M.loading ? "Linking…" : `Link ${l.size} request${l.size === 1 ? "" : "s"}`
603
+ children: b.loading ? "Linking…" : `Link ${c.size} request${c.size === 1 ? "" : "s"}`
602
604
  }) })
603
605
  ]
604
606
  })]
605
607
  });
606
608
  }
607
- var Y = m`
609
+ var le = _`
608
610
  mutation ProductControlsLinkObjective($productId: ID!, $objectiveId: ID!) {
609
611
  planmagnetLinkProductObjective(productId: $productId, objectiveId: $objectiveId) {
610
612
  id
611
613
  }
612
614
  }
613
- `, X = m`
615
+ `, ue = _`
614
616
  mutation ProductControlsUnlinkObjective($productId: ID!, $objectiveId: ID!) {
615
617
  planmagnetUnlinkProductObjective(productId: $productId, objectiveId: $objectiveId)
616
618
  }
617
- `, Z = m`
619
+ `, de = _`
618
620
  query ProductControlsCandidateObjectives($workspaceId: ID!) {
619
621
  planmagnetObjectives(workspaceId: $workspaceId, pagination: { first: 100 }) {
620
622
  items {
@@ -626,12 +628,12 @@ var Y = m`
626
628
  }
627
629
  }
628
630
  `;
629
- function Q({ productId: e, objectives: n }) {
630
- let i = t(), [s, l] = h(X, {
631
- refetchQueries: k,
631
+ function fe({ productId: e, objectives: n }) {
632
+ let i = t(), [s, c] = v(ue, {
633
+ refetchQueries: F,
632
634
  awaitRefetchQueries: !0
633
- }), [u, d] = c(null), [f, m] = c(null), g = async (t) => {
634
- d(null), m(t);
635
+ }), [l, d] = u(null), [f, p] = u(null), m = async (t) => {
636
+ d(null), p(t);
635
637
  try {
636
638
  await r(s({ variables: {
637
639
  productId: e,
@@ -640,53 +642,53 @@ function Q({ productId: e, objectives: n }) {
640
642
  } catch (e) {
641
643
  d(e instanceof Error ? e.message : "The objective could not be unlinked.");
642
644
  } finally {
643
- m(null);
645
+ p(null);
644
646
  }
645
647
  };
646
- return /* @__PURE__ */ v("div", {
648
+ return /* @__PURE__ */ S("div", {
647
649
  className: "space-y-3",
648
650
  "data-testid": "product-objectives",
649
651
  children: [
650
- /* @__PURE__ */ v("div", {
652
+ /* @__PURE__ */ S("div", {
651
653
  className: "flex items-center justify-between",
652
- children: [/* @__PURE__ */ v("p", {
654
+ children: [/* @__PURE__ */ S("p", {
653
655
  className: "text-sm text-muted-foreground",
654
656
  children: [
655
657
  n.length,
656
658
  " objective",
657
659
  n.length === 1 ? "" : "s"
658
660
  ]
659
- }), /* @__PURE__ */ _($, {
661
+ }), /* @__PURE__ */ x(pe, {
660
662
  productId: e,
661
663
  existingIds: n.map((e) => e.id)
662
664
  })]
663
665
  }),
664
- u && /* @__PURE__ */ _(a, { message: u }),
665
- n.length === 0 ? /* @__PURE__ */ _("p", {
666
+ l && /* @__PURE__ */ x(a, { message: l }),
667
+ n.length === 0 ? /* @__PURE__ */ x("p", {
666
668
  className: "text-sm text-muted-foreground text-center py-4",
667
669
  children: "No OKR objectives linked to this product yet."
668
- }) : /* @__PURE__ */ _("ul", {
670
+ }) : /* @__PURE__ */ x("ul", {
669
671
  className: "space-y-1",
670
- children: n.map((e) => /* @__PURE__ */ v("li", {
672
+ children: n.map((e) => /* @__PURE__ */ S("li", {
671
673
  className: "flex items-center justify-between gap-2 border rounded-md p-2 text-sm",
672
- children: [/* @__PURE__ */ _("button", {
674
+ children: [/* @__PURE__ */ x("button", {
673
675
  type: "button",
674
676
  className: "min-w-0 truncate text-left hover:underline",
675
677
  onClick: () => i(`/goals/objective-detail-page?objectiveId=${e.id}`),
676
678
  children: e.title
677
- }), /* @__PURE__ */ v("div", {
679
+ }), /* @__PURE__ */ S("div", {
678
680
  className: "flex items-center gap-2 shrink-0",
679
- children: [/* @__PURE__ */ _(y, {
681
+ children: [/* @__PURE__ */ x(C, {
680
682
  variant: "secondary",
681
683
  className: "text-xs capitalize",
682
684
  children: o(e.status)
683
- }), /* @__PURE__ */ _(b, {
685
+ }), /* @__PURE__ */ x(w, {
684
686
  size: "sm",
685
687
  variant: "ghost",
686
688
  "aria-label": `Unlink ${e.title} from product`,
687
- disabled: l.loading,
688
- onClick: () => void g(e.id),
689
- children: f === e.id ? "…" : /* @__PURE__ */ _(p, { className: "h-4 w-4" })
689
+ disabled: c.loading,
690
+ onClick: () => void m(e.id),
691
+ children: f === e.id ? "…" : /* @__PURE__ */ x(g, { className: "h-4 w-4" })
690
692
  })]
691
693
  })]
692
694
  }, e.id))
@@ -694,68 +696,68 @@ function Q({ productId: e, objectives: n }) {
694
696
  ]
695
697
  });
696
698
  }
697
- function $({ productId: t, existingIds: n }) {
698
- let { workspaceId: i } = e(), [o, s] = c(!1), [l, u] = c(/* @__PURE__ */ new Set()), [f, p] = c(null), { data: m, loading: y } = g(Z, {
699
+ function pe({ productId: t, existingIds: n }) {
700
+ let { workspaceId: i } = e(), [o, s] = u(!1), [c, l] = u(/* @__PURE__ */ new Set()), [d, f] = u(null), { data: p, loading: h } = y(de, {
699
701
  variables: { workspaceId: i ?? "" },
700
702
  skip: !o || !i
701
- }), A = (m?.planmagnetObjectives.items ?? []).filter((e) => !n.includes(e.id)), [j, M] = h(Y, {
702
- refetchQueries: k,
703
+ }), g = (p?.planmagnetObjectives.items ?? []).filter((e) => !n.includes(e.id)), [_, b] = v(le, {
704
+ refetchQueries: F,
703
705
  awaitRefetchQueries: !0
704
- }), N = (e, t) => u((n) => {
706
+ }), C = (e, t) => l((n) => {
705
707
  let r = new Set(n);
706
708
  return t ? r.add(e) : r.delete(e), r;
707
- }), P = () => {
708
- u(/* @__PURE__ */ new Set()), p(null);
709
- }, F = async () => {
710
- p(null);
709
+ }), T = () => {
710
+ l(/* @__PURE__ */ new Set()), f(null);
711
+ }, E = async () => {
712
+ f(null);
711
713
  try {
712
- await Promise.all([...l].map((e) => r(j({ variables: {
714
+ await Promise.all([...c].map((e) => r(_({ variables: {
713
715
  productId: t,
714
716
  objectiveId: e
715
- } })))), P(), s(!1);
717
+ } })))), T(), s(!1);
716
718
  } catch (e) {
717
- p(e instanceof Error ? e.message : "The objectives could not be linked.");
719
+ f(e instanceof Error ? e.message : "The objectives could not be linked.");
718
720
  }
719
721
  };
720
- return /* @__PURE__ */ v(S, {
722
+ return /* @__PURE__ */ S(O, {
721
723
  open: o,
722
724
  onOpenChange: (e) => {
723
- s(e), e || P();
725
+ s(e), e || T();
724
726
  },
725
- children: [/* @__PURE__ */ _(O, {
727
+ children: [/* @__PURE__ */ x(P, {
726
728
  asChild: !0,
727
- children: /* @__PURE__ */ v(b, {
729
+ children: /* @__PURE__ */ S(w, {
728
730
  size: "sm",
729
731
  variant: "outline",
730
732
  "data-testid": "product-add-objectives",
731
- children: [/* @__PURE__ */ _(d, { className: "mr-1 h-4 w-4" }), "Add objective"]
733
+ children: [/* @__PURE__ */ x(m, { className: "mr-1 h-4 w-4" }), "Add objective"]
732
734
  })
733
- }), /* @__PURE__ */ v(C, {
735
+ }), /* @__PURE__ */ S(k, {
734
736
  className: "max-w-lg",
735
737
  children: [
736
- /* @__PURE__ */ v(E, { children: [/* @__PURE__ */ _(D, { children: "Link OKR objectives" }), /* @__PURE__ */ _(w, { children: "Re-linking an objective that is already linked is a no-op, not an error." })] }),
737
- /* @__PURE__ */ v("div", {
738
+ /* @__PURE__ */ S(M, { children: [/* @__PURE__ */ x(N, { children: "Link OKR objectives" }), /* @__PURE__ */ x(A, { children: "Re-linking an objective that is already linked is a no-op, not an error." })] }),
739
+ /* @__PURE__ */ S("div", {
738
740
  className: "max-h-80 overflow-y-auto space-y-1",
739
741
  "data-testid": "product-add-objective-candidates",
740
742
  children: [
741
- y && /* @__PURE__ */ _("p", {
743
+ h && /* @__PURE__ */ x("p", {
742
744
  className: "text-sm text-muted-foreground py-4 text-center",
743
745
  children: "Loading…"
744
746
  }),
745
- !y && A.length === 0 && /* @__PURE__ */ _("p", {
747
+ !h && g.length === 0 && /* @__PURE__ */ x("p", {
746
748
  className: "text-sm text-muted-foreground py-4 text-center",
747
749
  children: "Every objective in this workspace is already linked to this product."
748
750
  }),
749
- A.map((e) => {
751
+ g.map((e) => {
750
752
  let t = `product-add-objective-${e.id}`;
751
- return /* @__PURE__ */ v("label", {
753
+ return /* @__PURE__ */ S("label", {
752
754
  htmlFor: t,
753
755
  className: "flex items-center gap-3 border rounded-md p-2 text-sm cursor-pointer hover:bg-muted",
754
- children: [/* @__PURE__ */ _(x, {
756
+ children: [/* @__PURE__ */ x(D, {
755
757
  id: t,
756
- checked: l.has(e.id),
757
- onCheckedChange: (t) => N(e.id, t === !0)
758
- }), /* @__PURE__ */ _("span", {
758
+ checked: c.has(e.id),
759
+ onCheckedChange: (t) => C(e.id, t === !0)
760
+ }), /* @__PURE__ */ x("span", {
759
761
  className: "min-w-0 flex-1 truncate",
760
762
  children: e.title
761
763
  })]
@@ -763,18 +765,341 @@ function $({ productId: t, existingIds: n }) {
763
765
  })
764
766
  ]
765
767
  }),
766
- f && /* @__PURE__ */ _(a, { message: f }),
767
- /* @__PURE__ */ _(T, { children: /* @__PURE__ */ _(b, {
768
- onClick: () => void F(),
769
- disabled: l.size === 0 || M.loading,
768
+ d && /* @__PURE__ */ x(a, { message: d }),
769
+ /* @__PURE__ */ x(j, { children: /* @__PURE__ */ x(w, {
770
+ onClick: () => void E(),
771
+ disabled: c.size === 0 || b.loading,
770
772
  "data-testid": "product-add-objectives-confirm",
771
- children: M.loading ? "Linking…" : `Link ${l.size} objective${l.size === 1 ? "" : "s"}`
773
+ children: b.loading ? "Linking…" : `Link ${c.size} objective${c.size === 1 ? "" : "s"}`
772
774
  }) })
773
775
  ]
774
776
  })]
775
777
  });
776
778
  }
779
+ var me = _`
780
+ mutation ProductControlsUpdateInfo($id: ID!, $input: PlanmagnetUpdateProductInput!) {
781
+ planmagnetUpdateProduct(id: $id, input: $input) {
782
+ id
783
+ mission
784
+ valueProposition
785
+ businessModel
786
+ targetSegments
787
+ }
788
+ }
789
+ `, Y = 2e3, X = 20, Z = 120;
790
+ function Q({ value: e, onChange: t, disabled: n }) {
791
+ let [r, i] = u(""), a = e.length >= X, o = r.trim(), s = !n && !a && o !== "" && o.length <= Z && !e.includes(o), c = () => {
792
+ s && (t([...e, o]), i(""));
793
+ }, l = (n) => t(e.filter((e) => e !== n));
794
+ return /* @__PURE__ */ S("div", {
795
+ className: "space-y-2",
796
+ "data-testid": "product-segments",
797
+ children: [
798
+ /* @__PURE__ */ S("div", {
799
+ className: "flex flex-wrap gap-1",
800
+ children: [e.length === 0 && /* @__PURE__ */ x("span", {
801
+ className: "text-xs text-muted-foreground",
802
+ children: "No target segments yet."
803
+ }), e.map((e) => /* @__PURE__ */ S(C, {
804
+ variant: "secondary",
805
+ className: "gap-1 pr-1",
806
+ children: [e, !n && /* @__PURE__ */ x("button", {
807
+ type: "button",
808
+ "aria-label": `Remove ${e}`,
809
+ onClick: () => l(e),
810
+ className: "rounded-full hover:bg-muted",
811
+ children: /* @__PURE__ */ x(g, { className: "h-3 w-3" })
812
+ })]
813
+ }, e))]
814
+ }),
815
+ !n && /* @__PURE__ */ S("div", {
816
+ className: "flex items-center gap-2",
817
+ children: [/* @__PURE__ */ x(ne, {
818
+ "aria-label": "Add a target segment",
819
+ placeholder: a ? `Limit reached (${X})` : "e.g. Mid-market SaaS teams",
820
+ value: r,
821
+ disabled: a,
822
+ maxLength: Z,
823
+ onChange: (e) => i(e.target.value),
824
+ onKeyDown: (e) => {
825
+ e.key === "Enter" && (e.preventDefault(), c());
826
+ }
827
+ }), /* @__PURE__ */ x(w, {
828
+ type: "button",
829
+ size: "sm",
830
+ variant: "outline",
831
+ "aria-label": "Add segment",
832
+ disabled: !s,
833
+ onClick: c,
834
+ children: /* @__PURE__ */ x(m, { className: "h-4 w-4" })
835
+ })]
836
+ }),
837
+ !n && /* @__PURE__ */ S("p", {
838
+ className: "text-xs text-muted-foreground",
839
+ children: [
840
+ e.length,
841
+ "/",
842
+ X,
843
+ " segments, up to ",
844
+ Z,
845
+ " characters each."
846
+ ]
847
+ })
848
+ ]
849
+ });
850
+ }
851
+ function he({ product: e }) {
852
+ let t = {
853
+ mission: e.mission ?? "",
854
+ valueProposition: e.valueProposition ?? "",
855
+ businessModel: e.businessModel ?? "",
856
+ targetSegments: e.targetSegments
857
+ }, [n, i] = u(!1), [o, c] = u(t), [l, d] = u(null), [f, m] = v(me, {
858
+ refetchQueries: F,
859
+ awaitRefetchQueries: !0
860
+ }), h = () => {
861
+ c(t), d(null), i(!0);
862
+ }, g = [
863
+ o.mission,
864
+ o.valueProposition,
865
+ o.businessModel
866
+ ].some((e) => e.length > Y), _ = o.targetSegments.length <= X && o.targetSegments.every((e) => e.length <= Z), y = !g && _ && !m.loading, C = async () => {
867
+ d(null);
868
+ let t = (e) => e.trim() ? e.trim() : null;
869
+ try {
870
+ await r(f({ variables: {
871
+ id: e.id,
872
+ input: {
873
+ mission: t(o.mission),
874
+ valueProposition: t(o.valueProposition),
875
+ businessModel: t(o.businessModel),
876
+ targetSegments: o.targetSegments
877
+ }
878
+ } })), i(!1);
879
+ } catch (e) {
880
+ d(s(e, "The product information could not be saved."));
881
+ }
882
+ }, D = "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[72px]";
883
+ return /* @__PURE__ */ S(T, {
884
+ "data-testid": "product-info",
885
+ children: [/* @__PURE__ */ S(ee, {
886
+ className: "flex flex-row items-center justify-between gap-2",
887
+ children: [/* @__PURE__ */ x(te, { children: "About this product" }), !n && /* @__PURE__ */ S(w, {
888
+ size: "sm",
889
+ variant: "outline",
890
+ "data-testid": "product-info-edit",
891
+ onClick: h,
892
+ children: [/* @__PURE__ */ x(p, { className: "mr-1 h-4 w-4" }), "Edit"]
893
+ })]
894
+ }), /* @__PURE__ */ x(E, {
895
+ className: "space-y-4",
896
+ children: n ? /* @__PURE__ */ S(b, { children: [
897
+ /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("label", {
898
+ htmlFor: "product-info-mission",
899
+ className: "text-sm font-medium",
900
+ children: "Mission"
901
+ }), /* @__PURE__ */ x("textarea", {
902
+ id: "product-info-mission",
903
+ className: D,
904
+ maxLength: Y,
905
+ value: o.mission,
906
+ onChange: (e) => c({
907
+ ...o,
908
+ mission: e.target.value
909
+ })
910
+ })] }),
911
+ /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("label", {
912
+ htmlFor: "product-info-value-proposition",
913
+ className: "text-sm font-medium",
914
+ children: "Value proposition"
915
+ }), /* @__PURE__ */ x("textarea", {
916
+ id: "product-info-value-proposition",
917
+ className: D,
918
+ maxLength: Y,
919
+ value: o.valueProposition,
920
+ onChange: (e) => c({
921
+ ...o,
922
+ valueProposition: e.target.value
923
+ })
924
+ })] }),
925
+ /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("label", {
926
+ htmlFor: "product-info-business-model",
927
+ className: "text-sm font-medium",
928
+ children: "Business model"
929
+ }), /* @__PURE__ */ x("textarea", {
930
+ id: "product-info-business-model",
931
+ className: D,
932
+ maxLength: Y,
933
+ value: o.businessModel,
934
+ onChange: (e) => c({
935
+ ...o,
936
+ businessModel: e.target.value
937
+ })
938
+ })] }),
939
+ /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("label", {
940
+ className: "text-sm font-medium",
941
+ children: "Target segments"
942
+ }), /* @__PURE__ */ x("div", {
943
+ className: "mt-1",
944
+ children: /* @__PURE__ */ x(Q, {
945
+ value: o.targetSegments,
946
+ onChange: (e) => c({
947
+ ...o,
948
+ targetSegments: e
949
+ })
950
+ })
951
+ })] }),
952
+ l && /* @__PURE__ */ x(a, { message: l }),
953
+ /* @__PURE__ */ S("div", {
954
+ className: "flex justify-end gap-2",
955
+ children: [/* @__PURE__ */ x(w, {
956
+ size: "sm",
957
+ variant: "outline",
958
+ onClick: () => i(!1),
959
+ children: "Cancel"
960
+ }), /* @__PURE__ */ x(w, {
961
+ size: "sm",
962
+ "data-testid": "product-info-save",
963
+ disabled: !y,
964
+ onClick: () => void C(),
965
+ children: m.loading ? "Saving…" : "Save"
966
+ })]
967
+ })
968
+ ] }) : /* @__PURE__ */ S(b, { children: [
969
+ /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
970
+ className: "text-xs font-medium text-muted-foreground",
971
+ children: "Mission"
972
+ }), /* @__PURE__ */ x("p", {
973
+ className: "text-sm whitespace-pre-wrap",
974
+ children: e.mission || "Not set"
975
+ })] }),
976
+ /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
977
+ className: "text-xs font-medium text-muted-foreground",
978
+ children: "Value proposition"
979
+ }), /* @__PURE__ */ x("p", {
980
+ className: "text-sm whitespace-pre-wrap",
981
+ children: e.valueProposition || "Not set"
982
+ })] }),
983
+ /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
984
+ className: "text-xs font-medium text-muted-foreground",
985
+ children: "Business model"
986
+ }), /* @__PURE__ */ x("p", {
987
+ className: "text-sm whitespace-pre-wrap",
988
+ children: e.businessModel || "Not set"
989
+ })] }),
990
+ /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
991
+ className: "text-xs font-medium text-muted-foreground",
992
+ children: "Target segments"
993
+ }), /* @__PURE__ */ x("div", {
994
+ className: "mt-1",
995
+ children: /* @__PURE__ */ x(Q, {
996
+ value: e.targetSegments,
997
+ onChange: () => {},
998
+ disabled: !0
999
+ })
1000
+ })] })
1001
+ ] })
1002
+ })]
1003
+ });
1004
+ }
1005
+ var ge = _`
1006
+ mutation ProductControlsLinkCompetitor($productId: ID!, $competitorId: ID!) {
1007
+ planmagnetLinkProductCompetitor(productId: $productId, competitorId: $competitorId) {
1008
+ id
1009
+ }
1010
+ }
1011
+ `, $ = _`
1012
+ mutation ProductControlsUnlinkCompetitor($productId: ID!, $competitorId: ID!) {
1013
+ planmagnetUnlinkProductCompetitor(productId: $productId, competitorId: $competitorId)
1014
+ }
1015
+ `;
1016
+ function _e({ productId: e, competitors: n }) {
1017
+ let o = t(), [d, f] = u(""), [p, h] = v(ge, {
1018
+ refetchQueries: F,
1019
+ awaitRefetchQueries: !0
1020
+ }), [_, y] = v($, {
1021
+ refetchQueries: F,
1022
+ awaitRefetchQueries: !0
1023
+ }), [b, C] = u(null), T = async () => {
1024
+ if (d) {
1025
+ C(null);
1026
+ try {
1027
+ await r(p({ variables: {
1028
+ productId: e,
1029
+ competitorId: d
1030
+ } })), f("");
1031
+ } catch (e) {
1032
+ C(s(e, "The competitor could not be linked."));
1033
+ }
1034
+ }
1035
+ }, E = async (t) => {
1036
+ C(null);
1037
+ try {
1038
+ await r(_({ variables: {
1039
+ productId: e,
1040
+ competitorId: t
1041
+ } }));
1042
+ } catch (e) {
1043
+ C(s(e, "The competitor could not be unlinked."));
1044
+ }
1045
+ };
1046
+ return /* @__PURE__ */ S("div", {
1047
+ className: "space-y-3",
1048
+ "data-testid": "product-competitors",
1049
+ children: [
1050
+ n.length === 0 ? /* @__PURE__ */ x("p", {
1051
+ className: "text-sm text-muted-foreground text-center py-4",
1052
+ children: "No competitors linked to this product yet."
1053
+ }) : /* @__PURE__ */ x("ul", {
1054
+ className: "space-y-1",
1055
+ children: n.map((e) => /* @__PURE__ */ S("li", {
1056
+ className: "flex items-center justify-between gap-2 border rounded-md p-2 text-sm",
1057
+ children: [/* @__PURE__ */ S("button", {
1058
+ type: "button",
1059
+ className: "min-w-0 flex-1 text-left truncate hover:underline",
1060
+ onClick: () => o(c("/products/competitor-detail-page", e.id)),
1061
+ children: [e.name, e.website && /* @__PURE__ */ x("span", {
1062
+ className: "ml-2 text-xs text-primary",
1063
+ children: e.website
1064
+ })]
1065
+ }), /* @__PURE__ */ x(i, {
1066
+ label: "",
1067
+ ariaLabel: `Unlink ${e.name} from this product`,
1068
+ testId: "product-competitor-unlink",
1069
+ variant: "outline",
1070
+ icon: /* @__PURE__ */ x(g, { className: "h-4 w-4" }),
1071
+ title: `Unlink ${e.name}?`,
1072
+ description: "The competitor stays in the workspace directory — only its link to this product is removed.",
1073
+ confirmLabel: "Unlink",
1074
+ destructive: !0,
1075
+ disabled: y.loading,
1076
+ onConfirm: () => void E(e.id)
1077
+ })]
1078
+ }, e.id))
1079
+ }),
1080
+ /* @__PURE__ */ S("div", {
1081
+ className: "flex items-start gap-2 pt-2 border-t",
1082
+ children: [/* @__PURE__ */ x("div", {
1083
+ className: "flex-1",
1084
+ children: /* @__PURE__ */ x(l, {
1085
+ id: "product-add-competitor",
1086
+ value: d,
1087
+ onChange: f,
1088
+ exclude: n.map((e) => e.id)
1089
+ })
1090
+ }), /* @__PURE__ */ S(w, {
1091
+ size: "sm",
1092
+ "data-testid": "product-competitor-link",
1093
+ disabled: !d || h.loading,
1094
+ onClick: () => void T(),
1095
+ children: [/* @__PURE__ */ x(m, { className: "mr-1 h-4 w-4" }), "Add"]
1096
+ })]
1097
+ }),
1098
+ b && /* @__PURE__ */ x(a, { message: b })
1099
+ ]
1100
+ });
1101
+ }
777
1102
  //#endregion
778
- export { q as ProductFeatureRequestsPanel, N as ProductHeaderActions, Q as ProductObjectivesPanel, H as ProductReleasesPanel, L as ProductRoadmapsPanel };
1103
+ export { he as ProductAboutPanel, _e as ProductCompetitorsPanel, se as ProductFeatureRequestsPanel, L as ProductHeaderActions, fe as ProductObjectivesPanel, K as ProductReleasesPanel, V as ProductRoadmapsPanel };
779
1104
 
780
1105
  //# sourceMappingURL=ProductControls.js.map