@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
@@ -3,14 +3,15 @@ import { PersonName as n } from "../people/People.js";
3
3
  import { countLabel as r, useFeatureCounts as i } from "../hooks/useCounts.js";
4
4
  import { detailPath as a, rowLinkProps as o } from "../utils/rowNavigation.js";
5
5
  import { FeatureTriageActions as s, isSnoozed as c } from "../controls/FeatureTriage.js";
6
- import { useState as l } from "react";
7
- import { ArrowUpDown as u, Filter as d, Loader2 as f, Plus as p, Star as m, Target as h, ThumbsUp as g } from "lucide-react";
8
- import { gql as _ } from "@apollo/client";
9
- import { useQuery as v } from "@apollo/client/react";
10
- import { jsx as y, jsxs as b } from "react/jsx-runtime";
11
- import { Badge as x, Button as S, Card as C, CardContent as w } from "@burdenoff/fe-libs/ui";
6
+ import { KANO_META as l, KANO_VALUES as u, MOSCOW_META as d, MOSCOW_VALUES as f, QUADRANT_META as p, QUADRANT_VALUES as m, QuadrantBadge as h } from "../controls/PrioritizationControls.js";
7
+ import { useState as g } from "react";
8
+ import { ArrowUpDown as _, Filter as v, Loader2 as y, Plus as b, Star as x, Target as S, ThumbsUp as ee } from "lucide-react";
9
+ import { gql as C } from "@apollo/client";
10
+ import { useQuery as w } from "@apollo/client/react";
11
+ import { jsx as T, jsxs as E } from "react/jsx-runtime";
12
+ import { Badge as D, Button as O, Card as k, CardContent as A } from "@burdenoff/fe-libs/ui";
12
13
  //#region src/planmagnet/pages/ProductsFeaturesPagePage.tsx
13
- var T = _`
14
+ var j = C`
14
15
  query ListFeatureRequests(
15
16
  $workspaceId: ID!
16
17
  $filter: PlanmagnetFeatureRequestFilter
@@ -36,13 +37,16 @@ var T = _`
36
37
  tags
37
38
  projectId
38
39
  snoozedUntil
40
+ moscow
41
+ kano
42
+ valueEffortQuadrant
39
43
  createdAt
40
44
  updatedAt
41
45
  }
42
46
  totalCount
43
47
  }
44
48
  }
45
- `, E = {
49
+ `, M = {
46
50
  SUBMITTED: "bg-gray-100 text-gray-800",
47
51
  UNDER_REVIEW: "bg-yellow-100 text-yellow-800",
48
52
  PLANNED: "bg-blue-100 text-blue-800",
@@ -51,25 +55,30 @@ var T = _`
51
55
  DECLINED: "bg-red-100 text-red-800",
52
56
  DUPLICATE: "bg-orange-100 text-orange-800"
53
57
  };
54
- function D() {
55
- let _ = t(), { workspaceId: D } = e(), [O, k] = l("all"), [A] = l(() => Date.now()), [j, M] = l("NEWEST"), N = i(), { data: P, loading: F, error: I } = v(T, {
58
+ function N() {
59
+ let C = t(), { workspaceId: N } = e(), [P, F] = g("all"), [I] = g(() => Date.now()), [L, te] = g("NEWEST"), [R, z] = g(""), [B, V] = g(""), [H, U] = g(""), W = i(), G = {
60
+ ...P === "TRIAGE" ? { triage: !0 } : P === "SNOOZED" ? { snoozed: !0 } : P === "all" ? {} : { status: P },
61
+ ...R ? { moscow: R } : {},
62
+ ...B ? { kano: B } : {},
63
+ ...H ? { quadrant: H } : {}
64
+ }, { data: K, loading: q, error: J } = w(j, {
56
65
  variables: {
57
- workspaceId: D,
58
- filter: O === "TRIAGE" ? { triage: !0 } : O === "SNOOZED" ? { snoozed: !0 } : O === "all" ? void 0 : { status: O },
66
+ workspaceId: N,
67
+ filter: Object.keys(G).length > 0 ? G : void 0,
59
68
  pagination: { first: 50 },
60
- orderBy: j
69
+ orderBy: L
61
70
  },
62
- skip: !D
71
+ skip: !N
63
72
  });
64
- if (F && !P) return /* @__PURE__ */ y("div", {
73
+ if (q && !K) return /* @__PURE__ */ T("div", {
65
74
  className: "flex items-center justify-center p-12",
66
- children: /* @__PURE__ */ y(f, { className: "h-8 w-8 animate-spin text-muted-foreground" })
75
+ children: /* @__PURE__ */ T(y, { className: "h-8 w-8 animate-spin text-muted-foreground" })
67
76
  });
68
- if (I) return /* @__PURE__ */ b("div", {
77
+ if (J) return /* @__PURE__ */ E("div", {
69
78
  className: "p-6 text-destructive",
70
- children: ["Failed to load features: ", I.message]
79
+ children: ["Failed to load features: ", J.message]
71
80
  });
72
- let L = P?.planmagnetFeatureRequests?.items ?? [], R = P?.planmagnetFeatureRequests?.totalCount ?? 0, z = L, B = [
81
+ let Y = K?.planmagnetFeatureRequests?.items ?? [], X = K?.planmagnetFeatureRequests?.totalCount ?? 0, Z = Y, Q = [
73
82
  "all",
74
83
  "TRIAGE",
75
84
  "SNOOZED",
@@ -80,180 +89,255 @@ function D() {
80
89
  "COMPLETED",
81
90
  "DECLINED",
82
91
  "DUPLICATE"
83
- ], V = {
84
- total: r(N?.all),
85
- open: r(N?.open),
86
- inProgress: r(N?.byStatus.IN_PROGRESS),
87
- completed: r(N?.byStatus.COMPLETED)
92
+ ], $ = {
93
+ total: r(W?.all),
94
+ open: r(W?.open),
95
+ inProgress: r(W?.byStatus.IN_PROGRESS),
96
+ completed: r(W?.byStatus.COMPLETED)
88
97
  };
89
- return /* @__PURE__ */ b("div", {
98
+ return /* @__PURE__ */ E("div", {
90
99
  className: "space-y-6 p-6",
91
100
  children: [
92
- /* @__PURE__ */ b("div", {
101
+ /* @__PURE__ */ E("div", {
93
102
  className: "flex items-center justify-between",
94
- children: [/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("h1", {
103
+ children: [/* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("h1", {
95
104
  className: "text-2xl font-semibold",
96
105
  children: "Features"
97
- }), /* @__PURE__ */ y("p", {
106
+ }), /* @__PURE__ */ T("p", {
98
107
  className: "text-sm text-muted-foreground",
99
- children: O === "all" ? `${V.total} feature requests` : O === "TRIAGE" ? `${R} waiting for triage` : `${R} ${O.toLowerCase().replace("_", " ")} match`
100
- })] }), /* @__PURE__ */ b(S, {
108
+ children: P === "all" ? `${$.total} feature requests` : P === "TRIAGE" ? `${X} waiting for triage` : `${X} ${P.toLowerCase().replace("_", " ")} match`
109
+ })] }), /* @__PURE__ */ E(O, {
101
110
  size: "sm",
102
- onClick: () => _("/products/new-feature-page"),
103
- children: [/* @__PURE__ */ y(p, { className: "mr-1 h-4 w-4" }), "New Feature"]
111
+ onClick: () => C("/products/new-feature-page"),
112
+ children: [/* @__PURE__ */ T(b, { className: "mr-1 h-4 w-4" }), "New Feature"]
104
113
  })]
105
114
  }),
106
- /* @__PURE__ */ b("div", {
115
+ /* @__PURE__ */ E("div", {
107
116
  className: "grid grid-cols-2 md:grid-cols-4 gap-4",
108
117
  children: [
109
- /* @__PURE__ */ y(C, { children: /* @__PURE__ */ b(w, {
118
+ /* @__PURE__ */ T(k, { children: /* @__PURE__ */ E(A, {
110
119
  className: "pt-4",
111
- children: [/* @__PURE__ */ y("p", {
120
+ children: [/* @__PURE__ */ T("p", {
112
121
  className: "text-xs text-muted-foreground",
113
122
  children: "Total Features"
114
- }), /* @__PURE__ */ y("p", {
123
+ }), /* @__PURE__ */ T("p", {
115
124
  className: "text-xl font-bold",
116
- children: V.total
125
+ children: $.total
117
126
  })]
118
127
  }) }),
119
- /* @__PURE__ */ y(C, { children: /* @__PURE__ */ b(w, {
128
+ /* @__PURE__ */ T(k, { children: /* @__PURE__ */ E(A, {
120
129
  className: "pt-4",
121
- children: [/* @__PURE__ */ y("p", {
130
+ children: [/* @__PURE__ */ T("p", {
122
131
  className: "text-xs text-muted-foreground",
123
132
  children: "In Progress"
124
- }), /* @__PURE__ */ y("p", {
133
+ }), /* @__PURE__ */ T("p", {
125
134
  className: "text-xl font-bold",
126
- children: V.inProgress
135
+ children: $.inProgress
127
136
  })]
128
137
  }) }),
129
- /* @__PURE__ */ y(C, { children: /* @__PURE__ */ b(w, {
138
+ /* @__PURE__ */ T(k, { children: /* @__PURE__ */ E(A, {
130
139
  className: "pt-4",
131
- children: [/* @__PURE__ */ y("p", {
140
+ children: [/* @__PURE__ */ T("p", {
132
141
  className: "text-xs text-muted-foreground",
133
142
  children: "Completed"
134
- }), /* @__PURE__ */ y("p", {
143
+ }), /* @__PURE__ */ T("p", {
135
144
  className: "text-xl font-bold",
136
- children: V.completed
145
+ children: $.completed
137
146
  })]
138
147
  }) }),
139
- /* @__PURE__ */ y(C, { children: /* @__PURE__ */ b(w, {
148
+ /* @__PURE__ */ T(k, { children: /* @__PURE__ */ E(A, {
140
149
  className: "pt-4",
141
- children: [/* @__PURE__ */ y("p", {
150
+ children: [/* @__PURE__ */ T("p", {
142
151
  className: "text-xs text-muted-foreground",
143
152
  children: "Open"
144
- }), /* @__PURE__ */ y("p", {
153
+ }), /* @__PURE__ */ T("p", {
145
154
  className: "text-xl font-bold",
146
- children: V.open
155
+ children: $.open
147
156
  })]
148
157
  }) })
149
158
  ]
150
159
  }),
151
- /* @__PURE__ */ b("div", {
160
+ /* @__PURE__ */ E("div", {
152
161
  className: "flex items-center justify-between flex-wrap gap-2",
153
- children: [/* @__PURE__ */ b("div", {
162
+ children: [/* @__PURE__ */ E("div", {
154
163
  className: "flex items-center gap-2",
155
- children: [/* @__PURE__ */ y(d, { className: "h-4 w-4 text-muted-foreground" }), B.map((e) => /* @__PURE__ */ y("button", {
156
- onClick: () => k(e),
157
- className: `px-2 py-1 text-xs rounded-md capitalize ${O === e ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground"}`,
158
- children: e === "all" ? "All" : e === "TRIAGE" ? `Triage (${r(N?.triage)})` : e === "SNOOZED" ? `Snoozed (${r(N?.snoozed)})` : e.toLowerCase().replace("_", " ")
164
+ children: [/* @__PURE__ */ T(v, { className: "h-4 w-4 text-muted-foreground" }), Q.map((e) => /* @__PURE__ */ T("button", {
165
+ onClick: () => F(e),
166
+ className: `px-2 py-1 text-xs rounded-md capitalize ${P === e ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground"}`,
167
+ children: e === "all" ? "All" : e === "TRIAGE" ? `Triage (${r(W?.triage)})` : e === "SNOOZED" ? `Snoozed (${r(W?.snoozed)})` : e.toLowerCase().replace("_", " ")
159
168
  }, e))]
160
- }), /* @__PURE__ */ b("div", {
169
+ }), /* @__PURE__ */ E("div", {
161
170
  className: "flex items-center gap-2",
162
- children: [/* @__PURE__ */ y(u, { className: "h-4 w-4 text-muted-foreground" }), ["NEWEST", "MOST_VOTED"].map((e) => /* @__PURE__ */ y("button", {
163
- onClick: () => M(e),
164
- className: `px-2 py-1 text-xs rounded-md ${j === e ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground"}`,
171
+ children: [/* @__PURE__ */ T(_, { className: "h-4 w-4 text-muted-foreground" }), ["NEWEST", "MOST_VOTED"].map((e) => /* @__PURE__ */ T("button", {
172
+ onClick: () => te(e),
173
+ className: `px-2 py-1 text-xs rounded-md ${L === e ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground"}`,
165
174
  children: e === "NEWEST" ? "Newest" : "Most voted"
166
175
  }, e))]
167
176
  })]
168
177
  }),
169
- /* @__PURE__ */ y("div", {
178
+ /* @__PURE__ */ E("div", {
179
+ className: "flex flex-wrap items-center gap-3",
180
+ children: [
181
+ /* @__PURE__ */ E("div", {
182
+ className: "flex items-center gap-1",
183
+ children: [/* @__PURE__ */ T("label", {
184
+ htmlFor: "feature-filter-moscow",
185
+ className: "text-xs text-muted-foreground",
186
+ children: "MoSCoW"
187
+ }), /* @__PURE__ */ E("select", {
188
+ id: "feature-filter-moscow",
189
+ "data-testid": "feature-filter-moscow",
190
+ className: "rounded-md border border-input bg-background px-2 py-1 text-xs",
191
+ value: R,
192
+ onChange: (e) => z(e.target.value),
193
+ children: [/* @__PURE__ */ T("option", {
194
+ value: "",
195
+ children: "All"
196
+ }), f.map((e) => /* @__PURE__ */ T("option", {
197
+ value: e,
198
+ children: d[e].label
199
+ }, e))]
200
+ })]
201
+ }),
202
+ /* @__PURE__ */ E("div", {
203
+ className: "flex items-center gap-1",
204
+ children: [/* @__PURE__ */ T("label", {
205
+ htmlFor: "feature-filter-kano",
206
+ className: "text-xs text-muted-foreground",
207
+ children: "Kano"
208
+ }), /* @__PURE__ */ E("select", {
209
+ id: "feature-filter-kano",
210
+ "data-testid": "feature-filter-kano",
211
+ className: "rounded-md border border-input bg-background px-2 py-1 text-xs",
212
+ value: B,
213
+ onChange: (e) => V(e.target.value),
214
+ children: [/* @__PURE__ */ T("option", {
215
+ value: "",
216
+ children: "All"
217
+ }), u.map((e) => /* @__PURE__ */ T("option", {
218
+ value: e,
219
+ children: l[e].label
220
+ }, e))]
221
+ })]
222
+ }),
223
+ /* @__PURE__ */ E("div", {
224
+ className: "flex items-center gap-1",
225
+ children: [/* @__PURE__ */ T("label", {
226
+ htmlFor: "feature-filter-quadrant",
227
+ className: "text-xs text-muted-foreground",
228
+ children: "Quadrant"
229
+ }), /* @__PURE__ */ E("select", {
230
+ id: "feature-filter-quadrant",
231
+ "data-testid": "feature-filter-quadrant",
232
+ className: "rounded-md border border-input bg-background px-2 py-1 text-xs",
233
+ value: H,
234
+ onChange: (e) => U(e.target.value),
235
+ children: [/* @__PURE__ */ T("option", {
236
+ value: "",
237
+ children: "All"
238
+ }), m.map((e) => /* @__PURE__ */ T("option", {
239
+ value: e,
240
+ children: p[e].label
241
+ }, e))]
242
+ })]
243
+ })
244
+ ]
245
+ }),
246
+ /* @__PURE__ */ T("div", {
170
247
  className: "space-y-3",
171
- children: z.map((e) => /* @__PURE__ */ y(C, {
172
- ...o(() => _(a("/products/feature-detail-page", e.id)), e.title),
173
- children: /* @__PURE__ */ y(w, {
248
+ children: Z.map((e) => /* @__PURE__ */ T(k, {
249
+ ...o(() => C(a("/products/feature-detail-page", e.id)), e.title),
250
+ children: /* @__PURE__ */ T(A, {
174
251
  className: "py-4",
175
- children: /* @__PURE__ */ b("div", {
252
+ children: /* @__PURE__ */ E("div", {
176
253
  className: "flex items-start justify-between gap-4",
177
- children: [/* @__PURE__ */ b("div", {
254
+ children: [/* @__PURE__ */ E("div", {
178
255
  className: "flex-1 space-y-2",
179
256
  children: [
180
- /* @__PURE__ */ b("div", {
257
+ /* @__PURE__ */ E("div", {
181
258
  className: "flex items-center gap-2",
182
- children: [/* @__PURE__ */ y("span", {
183
- className: "text-sm font-medium",
184
- children: e.title
185
- }), /* @__PURE__ */ y("span", {
186
- className: `text-[10px] px-1.5 py-0.5 rounded-full capitalize ${E[e.status] ?? "bg-gray-100"}`,
187
- children: e.status.toLowerCase().replace("_", " ")
188
- })]
259
+ children: [
260
+ /* @__PURE__ */ T("span", {
261
+ className: "text-sm font-medium",
262
+ children: e.title
263
+ }),
264
+ /* @__PURE__ */ T("span", {
265
+ className: `text-[10px] px-1.5 py-0.5 rounded-full capitalize ${M[e.status] ?? "bg-gray-100"}`,
266
+ children: e.status.toLowerCase().replace("_", " ")
267
+ }),
268
+ /* @__PURE__ */ T(h, {
269
+ quadrant: e.valueEffortQuadrant,
270
+ hideWhenUnscored: !0
271
+ })
272
+ ]
189
273
  }),
190
- /* @__PURE__ */ y("p", {
274
+ /* @__PURE__ */ T("p", {
191
275
  className: "text-xs text-muted-foreground",
192
276
  children: e.description
193
277
  }),
194
- /* @__PURE__ */ b("div", {
278
+ /* @__PURE__ */ E("div", {
195
279
  className: "flex items-center gap-4 text-xs text-muted-foreground",
196
280
  children: [
197
- /* @__PURE__ */ b("span", { children: ["Effort: ", e.effortEstimate ?? "N/A"] }),
198
- /* @__PURE__ */ b("span", { children: ["Submitted by: ", /* @__PURE__ */ y(n, { id: e.submittedBy })] }),
199
- /* @__PURE__ */ y("span", { children: new Date(e.updatedAt).toLocaleDateString() })
281
+ /* @__PURE__ */ E("span", { children: ["Effort: ", e.effortEstimate ?? "N/A"] }),
282
+ /* @__PURE__ */ E("span", { children: ["Submitted by: ", /* @__PURE__ */ T(n, { id: e.submittedBy })] }),
283
+ /* @__PURE__ */ T("span", { children: new Date(e.updatedAt).toLocaleDateString() })
200
284
  ]
201
285
  }),
202
- c(e.snoozedUntil, A) && /* @__PURE__ */ b("p", {
286
+ c(e.snoozedUntil, I) && /* @__PURE__ */ E("p", {
203
287
  className: "text-xs text-muted-foreground",
204
288
  children: ["Snoozed until ", new Date(e.snoozedUntil).toLocaleDateString()]
205
289
  }),
206
- /* @__PURE__ */ y(s, {
290
+ /* @__PURE__ */ T(s, {
207
291
  feature: e,
208
- now: A
292
+ now: I
209
293
  }),
210
- e.tags.length > 0 && /* @__PURE__ */ y("div", {
294
+ e.tags.length > 0 && /* @__PURE__ */ T("div", {
211
295
  className: "flex gap-1",
212
- children: e.tags.map((e) => /* @__PURE__ */ y(x, {
296
+ children: e.tags.map((e) => /* @__PURE__ */ T(D, {
213
297
  variant: "outline",
214
298
  className: "text-[10px]",
215
299
  children: e
216
300
  }, e))
217
301
  })
218
302
  ]
219
- }), /* @__PURE__ */ b("div", {
303
+ }), /* @__PURE__ */ E("div", {
220
304
  className: "flex items-center gap-4 shrink-0",
221
305
  children: [
222
- /* @__PURE__ */ b("div", {
306
+ /* @__PURE__ */ E("div", {
223
307
  className: "text-center",
224
- children: [/* @__PURE__ */ b("div", {
308
+ children: [/* @__PURE__ */ E("div", {
225
309
  className: "flex items-center gap-1",
226
- children: [/* @__PURE__ */ y(h, { className: "h-3 w-3 text-primary" }), /* @__PURE__ */ y("span", {
310
+ children: [/* @__PURE__ */ T(S, { className: "h-3 w-3 text-primary" }), /* @__PURE__ */ T("span", {
227
311
  className: "text-sm font-bold",
228
312
  children: e.priorityScore ?? 0
229
313
  })]
230
- }), /* @__PURE__ */ y("p", {
314
+ }), /* @__PURE__ */ T("p", {
231
315
  className: "text-[10px] text-muted-foreground",
232
316
  children: "Priority"
233
317
  })]
234
318
  }),
235
- /* @__PURE__ */ b("div", {
319
+ /* @__PURE__ */ E("div", {
236
320
  className: "text-center",
237
- children: [/* @__PURE__ */ b("div", {
321
+ children: [/* @__PURE__ */ E("div", {
238
322
  className: "flex items-center gap-1",
239
- children: [/* @__PURE__ */ y(g, { className: "h-3 w-3 text-green-500" }), /* @__PURE__ */ y("span", {
323
+ children: [/* @__PURE__ */ T(ee, { className: "h-3 w-3 text-green-500" }), /* @__PURE__ */ T("span", {
240
324
  className: "text-sm font-bold",
241
325
  children: e.voteCount
242
326
  })]
243
- }), /* @__PURE__ */ y("p", {
327
+ }), /* @__PURE__ */ T("p", {
244
328
  className: "text-[10px] text-muted-foreground",
245
329
  children: "Votes"
246
330
  })]
247
331
  }),
248
- /* @__PURE__ */ b("div", {
332
+ /* @__PURE__ */ E("div", {
249
333
  className: "text-center",
250
- children: [/* @__PURE__ */ b("div", {
334
+ children: [/* @__PURE__ */ E("div", {
251
335
  className: "flex items-center gap-1",
252
- children: [/* @__PURE__ */ y(m, { className: "h-3 w-3 text-yellow-500" }), /* @__PURE__ */ y("span", {
336
+ children: [/* @__PURE__ */ T(x, { className: "h-3 w-3 text-yellow-500" }), /* @__PURE__ */ T("span", {
253
337
  className: "text-sm font-bold",
254
338
  children: e.businessValue ?? 0
255
339
  })]
256
- }), /* @__PURE__ */ y("p", {
340
+ }), /* @__PURE__ */ T("p", {
257
341
  className: "text-[10px] text-muted-foreground",
258
342
  children: "Value"
259
343
  })]
@@ -264,14 +348,14 @@ function D() {
264
348
  })
265
349
  }, e.id))
266
350
  }),
267
- z.length === 0 && /* @__PURE__ */ y("p", {
351
+ Z.length === 0 && /* @__PURE__ */ T("p", {
268
352
  className: "text-center text-muted-foreground py-8",
269
- children: O === "TRIAGE" ? "Nothing waits for triage." : "No features match the selected filters."
353
+ children: P === "TRIAGE" ? "Nothing waits for triage." : "No features match the selected filters."
270
354
  })
271
355
  ]
272
356
  });
273
357
  }
274
358
  //#endregion
275
- export { D as ProductsFeaturesPagePage };
359
+ export { N as ProductsFeaturesPagePage };
276
360
 
277
361
  //# sourceMappingURL=ProductsFeaturesPagePage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ProductsFeaturesPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProductsFeaturesPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Badge, Button } from '@burdenoff/fe-libs/ui';\nimport {\n Star,\n Plus,\n ThumbsUp,\n MessageSquare,\n Target,\n Filter,\n ArrowUpDown,\n Loader2,\n} from 'lucide-react';\nimport { countLabel, useFeatureCounts } from '../hooks/useCounts';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { rowLinkProps, detailPath } from '../utils/rowNavigation';\nimport { PersonName } from '../people/People';\nimport { FeatureTriageActions, isSnoozed } from '../controls/FeatureTriage';\n\nconst LIST_FEATURE_REQUESTS = gql`\n query ListFeatureRequests(\n $workspaceId: ID!\n $filter: PlanmagnetFeatureRequestFilter\n $pagination: PlanmagnetPaginationInput\n $orderBy: PlanmagnetFeatureOrder\n ) {\n planmagnetFeatureRequests(\n workspaceId: $workspaceId\n filter: $filter\n pagination: $pagination\n orderBy: $orderBy\n ) {\n items {\n id\n title\n description\n status\n businessValue\n effortEstimate\n priorityScore\n voteCount\n submittedBy\n tags\n projectId\n snoozedUntil\n createdAt\n updatedAt\n }\n totalCount\n }\n }\n`;\n\ninterface FeatureRequestNode {\n id: string;\n title: string;\n description: string | null;\n status: string;\n businessValue: number | null;\n effortEstimate: string | null;\n priorityScore: number | null;\n voteCount: number;\n submittedBy: string;\n tags: string[];\n createdAt: string;\n updatedAt: string;\n}\n\nconst statusColor: Record<string, string> = {\n SUBMITTED: 'bg-gray-100 text-gray-800',\n UNDER_REVIEW: 'bg-yellow-100 text-yellow-800',\n PLANNED: 'bg-blue-100 text-blue-800',\n IN_PROGRESS: 'bg-purple-100 text-purple-800',\n COMPLETED: 'bg-green-100 text-green-800',\n DECLINED: 'bg-red-100 text-red-800',\n DUPLICATE: 'bg-orange-100 text-orange-800',\n};\n\nexport function ProductsFeaturesPagePage() {\n const navigate = usePlanMagnetNavigate();\n const { workspaceId } = usePlanMagnet();\n const [statusFilter, setStatusFilter] = useState<string>('all');\n // Snooze state is read against the moment the page opened (Date.now() may not run during render).\n const [now] = useState(() => Date.now());\n // Sorting happens on the server over every request (BOFF-7965: it re-sorted only the 50 loaded rows).\n const [sortBy, setSortBy] = useState<'NEWEST' | 'MOST_VOTED'>('NEWEST');\n const counts = useFeatureCounts();\n\n const {\n data,\n loading,\n error,\n } = // eslint-disable-next-line @typescript-eslint/no-explicit-any\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n useQuery<Record<string, any>>(LIST_FEATURE_REQUESTS, {\n variables: {\n workspaceId,\n // Triage (P1.3): the queue and the snoozed requests are server filters, like the status tabs.\n filter:\n statusFilter === 'TRIAGE'\n ? { triage: true }\n : statusFilter === 'SNOOZED'\n ? { snoozed: true }\n : statusFilter !== 'all'\n ? { status: statusFilter }\n : undefined,\n pagination: { first: 50 },\n orderBy: sortBy,\n },\n skip: !workspaceId,\n });\n\n // Only before the first load: a refetch must not blank the page (it\n\n // unmounts every component on it and loses their state).\n\n if (loading && !data) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-muted-foreground\" />\n </div>\n );\n }\n\n if (error) {\n return <div className=\"p-6 text-destructive\">Failed to load features: {error.message}</div>;\n }\n\n const features: FeatureRequestNode[] = data?.planmagnetFeatureRequests?.items ?? [];\n const totalCount = data?.planmagnetFeatureRequests?.totalCount ?? 0;\n\n const sorted = features;\n\n const statuses = [\n 'all',\n 'TRIAGE',\n 'SNOOZED',\n 'SUBMITTED',\n 'UNDER_REVIEW',\n 'PLANNED',\n 'IN_PROGRESS',\n 'COMPLETED',\n 'DECLINED',\n 'DUPLICATE',\n ];\n\n // Tiles are unfiltered server counts; the tabs change only the list (BOFF-7965).\n const stats = {\n total: countLabel(counts?.all),\n open: countLabel(counts?.open),\n inProgress: countLabel(counts?.byStatus.IN_PROGRESS),\n completed: countLabel(counts?.byStatus.COMPLETED),\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Features</h1>\n {/* Under a tab, the count is of what matches it (BOFF-7990). */}\n <p className=\"text-sm text-muted-foreground\">\n {statusFilter === 'all'\n ? `${stats.total} feature requests`\n : statusFilter === 'TRIAGE'\n ? `${totalCount} waiting for triage`\n : `${totalCount} ${statusFilter.toLowerCase().replace('_', ' ')} match`}\n </p>\n </div>\n <Button size=\"sm\" onClick={() => navigate('/products/new-feature-page')}>\n <Plus className=\"mr-1 h-4 w-4\" />\n New Feature\n </Button>\n </div>\n\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-xs text-muted-foreground\">Total Features</p>\n <p className=\"text-xl font-bold\">{stats.total}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-xs text-muted-foreground\">In Progress</p>\n <p className=\"text-xl font-bold\">{stats.inProgress}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-xs text-muted-foreground\">Completed</p>\n <p className=\"text-xl font-bold\">{stats.completed}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-xs text-muted-foreground\">Open</p>\n <p className=\"text-xl font-bold\">{stats.open}</p>\n </CardContent>\n </Card>\n </div>\n\n <div className=\"flex items-center justify-between flex-wrap gap-2\">\n <div className=\"flex items-center gap-2\">\n <Filter className=\"h-4 w-4 text-muted-foreground\" />\n {statuses.map((s) => (\n <button\n key={s}\n onClick={() => setStatusFilter(s)}\n className={`px-2 py-1 text-xs rounded-md capitalize ${statusFilter === s ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'}`}\n >\n {s === 'all'\n ? 'All'\n : s === 'TRIAGE'\n ? `Triage (${countLabel(counts?.triage)})`\n : s === 'SNOOZED'\n ? `Snoozed (${countLabel(counts?.snoozed)})`\n : s.toLowerCase().replace('_', ' ')}\n </button>\n ))}\n </div>\n <div className=\"flex items-center gap-2\">\n <ArrowUpDown className=\"h-4 w-4 text-muted-foreground\" />\n {(['NEWEST', 'MOST_VOTED'] as const).map((s) => (\n <button\n key={s}\n onClick={() => setSortBy(s)}\n className={`px-2 py-1 text-xs rounded-md ${sortBy === s ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'}`}\n >\n {s === 'NEWEST' ? 'Newest' : 'Most voted'}\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"space-y-3\">\n {sorted.map((feature) => (\n <Card\n key={feature.id}\n {...rowLinkProps(\n () => navigate(detailPath('/products/feature-detail-page', feature.id)),\n feature.title\n )}\n >\n <CardContent className=\"py-4\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"flex-1 space-y-2\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium\">{feature.title}</span>\n <span\n className={`text-[10px] px-1.5 py-0.5 rounded-full capitalize ${statusColor[feature.status] ?? 'bg-gray-100'}`}\n >\n {feature.status.toLowerCase().replace('_', ' ')}\n </span>\n </div>\n <p className=\"text-xs text-muted-foreground\">{feature.description}</p>\n <div className=\"flex items-center gap-4 text-xs text-muted-foreground\">\n <span>Effort: {feature.effortEstimate ?? 'N/A'}</span>\n {/* By name, not user UUID (BOFF-7950). */}\n <span>\n Submitted by: <PersonName id={feature.submittedBy} />\n </span>\n <span>{new Date(feature.updatedAt).toLocaleDateString()}</span>\n </div>\n {isSnoozed(feature.snoozedUntil, now) && (\n <p className=\"text-xs text-muted-foreground\">\n Snoozed until {new Date(feature.snoozedUntil).toLocaleDateString()}\n </p>\n )}\n <FeatureTriageActions feature={feature} now={now} />\n {feature.tags.length > 0 && (\n <div className=\"flex gap-1\">\n {feature.tags.map((tag) => (\n <Badge key={tag} variant=\"outline\" className=\"text-[10px]\">\n {tag}\n </Badge>\n ))}\n </div>\n )}\n </div>\n <div className=\"flex items-center gap-4 shrink-0\">\n <div className=\"text-center\">\n <div className=\"flex items-center gap-1\">\n <Target className=\"h-3 w-3 text-primary\" />\n <span className=\"text-sm font-bold\">{feature.priorityScore ?? 0}</span>\n </div>\n <p className=\"text-[10px] text-muted-foreground\">Priority</p>\n </div>\n <div className=\"text-center\">\n <div className=\"flex items-center gap-1\">\n <ThumbsUp className=\"h-3 w-3 text-green-500\" />\n <span className=\"text-sm font-bold\">{feature.voteCount}</span>\n </div>\n <p className=\"text-[10px] text-muted-foreground\">Votes</p>\n </div>\n <div className=\"text-center\">\n <div className=\"flex items-center gap-1\">\n <Star className=\"h-3 w-3 text-yellow-500\" />\n <span className=\"text-sm font-bold\">{feature.businessValue ?? 0}</span>\n </div>\n <p className=\"text-[10px] text-muted-foreground\">Value</p>\n </div>\n </div>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n {sorted.length === 0 && (\n <p className=\"text-center text-muted-foreground py-8\">\n {statusFilter === 'TRIAGE'\n ? 'Nothing waits for triage.'\n : 'No features match the selected filters.'}\n </p>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ProductsFeaturesPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProductsFeaturesPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Badge, Button } from '@burdenoff/fe-libs/ui';\nimport {\n Star,\n Plus,\n ThumbsUp,\n MessageSquare,\n Target,\n Filter,\n ArrowUpDown,\n Loader2,\n} from 'lucide-react';\nimport { countLabel, useFeatureCounts } from '../hooks/useCounts';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { rowLinkProps, detailPath } from '../utils/rowNavigation';\nimport { PersonName } from '../people/People';\nimport { FeatureTriageActions, isSnoozed } from '../controls/FeatureTriage';\nimport {\n MOSCOW_VALUES,\n MOSCOW_META,\n KANO_VALUES,\n KANO_META,\n QUADRANT_VALUES,\n QUADRANT_META,\n QuadrantBadge,\n} from '../controls/PrioritizationControls';\n\nconst LIST_FEATURE_REQUESTS = gql`\n query ListFeatureRequests(\n $workspaceId: ID!\n $filter: PlanmagnetFeatureRequestFilter\n $pagination: PlanmagnetPaginationInput\n $orderBy: PlanmagnetFeatureOrder\n ) {\n planmagnetFeatureRequests(\n workspaceId: $workspaceId\n filter: $filter\n pagination: $pagination\n orderBy: $orderBy\n ) {\n items {\n id\n title\n description\n status\n businessValue\n effortEstimate\n priorityScore\n voteCount\n submittedBy\n tags\n projectId\n snoozedUntil\n moscow\n kano\n valueEffortQuadrant\n createdAt\n updatedAt\n }\n totalCount\n }\n }\n`;\n\ninterface FeatureRequestNode {\n id: string;\n title: string;\n description: string | null;\n status: string;\n businessValue: number | null;\n effortEstimate: string | null;\n priorityScore: number | null;\n voteCount: number;\n submittedBy: string;\n tags: string[];\n createdAt: string;\n updatedAt: string;\n}\n\nconst statusColor: Record<string, string> = {\n SUBMITTED: 'bg-gray-100 text-gray-800',\n UNDER_REVIEW: 'bg-yellow-100 text-yellow-800',\n PLANNED: 'bg-blue-100 text-blue-800',\n IN_PROGRESS: 'bg-purple-100 text-purple-800',\n COMPLETED: 'bg-green-100 text-green-800',\n DECLINED: 'bg-red-100 text-red-800',\n DUPLICATE: 'bg-orange-100 text-orange-800',\n};\n\nexport function ProductsFeaturesPagePage() {\n const navigate = usePlanMagnetNavigate();\n const { workspaceId } = usePlanMagnet();\n const [statusFilter, setStatusFilter] = useState<string>('all');\n // Snooze state is read against the moment the page opened (Date.now() may not run during render).\n const [now] = useState(() => Date.now());\n // Sorting happens on the server over every request (BOFF-7965: it re-sorted only the 50 loaded rows).\n const [sortBy, setSortBy] = useState<'NEWEST' | 'MOST_VOTED'>('NEWEST');\n // PRM-27: MoSCoW/Kano/quadrant are server filters too, combined with the status tabs above — not a\n // client-side re-filter of the 50 loaded rows (same reasoning as BOFF-7965 for sorting).\n const [moscowFilter, setMoscowFilter] = useState('');\n const [kanoFilter, setKanoFilter] = useState('');\n const [quadrantFilter, setQuadrantFilter] = useState('');\n const counts = useFeatureCounts();\n\n const baseFilter =\n statusFilter === 'TRIAGE'\n ? { triage: true }\n : statusFilter === 'SNOOZED'\n ? { snoozed: true }\n : statusFilter !== 'all'\n ? { status: statusFilter }\n : {};\n const filter = {\n ...baseFilter,\n ...(moscowFilter ? { moscow: moscowFilter } : {}),\n ...(kanoFilter ? { kano: kanoFilter } : {}),\n ...(quadrantFilter ? { quadrant: quadrantFilter } : {}),\n };\n\n const {\n data,\n loading,\n error,\n } = // eslint-disable-next-line @typescript-eslint/no-explicit-any\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n useQuery<Record<string, any>>(LIST_FEATURE_REQUESTS, {\n variables: {\n workspaceId,\n filter: Object.keys(filter).length > 0 ? filter : undefined,\n pagination: { first: 50 },\n orderBy: sortBy,\n },\n skip: !workspaceId,\n });\n\n // Only before the first load: a refetch must not blank the page (it\n\n // unmounts every component on it and loses their state).\n\n if (loading && !data) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-muted-foreground\" />\n </div>\n );\n }\n\n if (error) {\n return <div className=\"p-6 text-destructive\">Failed to load features: {error.message}</div>;\n }\n\n const features: FeatureRequestNode[] = data?.planmagnetFeatureRequests?.items ?? [];\n const totalCount = data?.planmagnetFeatureRequests?.totalCount ?? 0;\n\n const sorted = features;\n\n const statuses = [\n 'all',\n 'TRIAGE',\n 'SNOOZED',\n 'SUBMITTED',\n 'UNDER_REVIEW',\n 'PLANNED',\n 'IN_PROGRESS',\n 'COMPLETED',\n 'DECLINED',\n 'DUPLICATE',\n ];\n\n // Tiles are unfiltered server counts; the tabs change only the list (BOFF-7965).\n const stats = {\n total: countLabel(counts?.all),\n open: countLabel(counts?.open),\n inProgress: countLabel(counts?.byStatus.IN_PROGRESS),\n completed: countLabel(counts?.byStatus.COMPLETED),\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Features</h1>\n {/* Under a tab, the count is of what matches it (BOFF-7990). */}\n <p className=\"text-sm text-muted-foreground\">\n {statusFilter === 'all'\n ? `${stats.total} feature requests`\n : statusFilter === 'TRIAGE'\n ? `${totalCount} waiting for triage`\n : `${totalCount} ${statusFilter.toLowerCase().replace('_', ' ')} match`}\n </p>\n </div>\n <Button size=\"sm\" onClick={() => navigate('/products/new-feature-page')}>\n <Plus className=\"mr-1 h-4 w-4\" />\n New Feature\n </Button>\n </div>\n\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-xs text-muted-foreground\">Total Features</p>\n <p className=\"text-xl font-bold\">{stats.total}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-xs text-muted-foreground\">In Progress</p>\n <p className=\"text-xl font-bold\">{stats.inProgress}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-xs text-muted-foreground\">Completed</p>\n <p className=\"text-xl font-bold\">{stats.completed}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-xs text-muted-foreground\">Open</p>\n <p className=\"text-xl font-bold\">{stats.open}</p>\n </CardContent>\n </Card>\n </div>\n\n <div className=\"flex items-center justify-between flex-wrap gap-2\">\n <div className=\"flex items-center gap-2\">\n <Filter className=\"h-4 w-4 text-muted-foreground\" />\n {statuses.map((s) => (\n <button\n key={s}\n onClick={() => setStatusFilter(s)}\n className={`px-2 py-1 text-xs rounded-md capitalize ${statusFilter === s ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'}`}\n >\n {s === 'all'\n ? 'All'\n : s === 'TRIAGE'\n ? `Triage (${countLabel(counts?.triage)})`\n : s === 'SNOOZED'\n ? `Snoozed (${countLabel(counts?.snoozed)})`\n : s.toLowerCase().replace('_', ' ')}\n </button>\n ))}\n </div>\n <div className=\"flex items-center gap-2\">\n <ArrowUpDown className=\"h-4 w-4 text-muted-foreground\" />\n {(['NEWEST', 'MOST_VOTED'] as const).map((s) => (\n <button\n key={s}\n onClick={() => setSortBy(s)}\n className={`px-2 py-1 text-xs rounded-md ${sortBy === s ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'}`}\n >\n {s === 'NEWEST' ? 'Newest' : 'Most voted'}\n </button>\n ))}\n </div>\n </div>\n\n {/* PRM-27: MoSCoW/Kano/Value-Effort quadrant filters — server-side, combined with the status tabs above. */}\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"flex items-center gap-1\">\n <label htmlFor=\"feature-filter-moscow\" className=\"text-xs text-muted-foreground\">\n MoSCoW\n </label>\n <select\n id=\"feature-filter-moscow\"\n data-testid=\"feature-filter-moscow\"\n className=\"rounded-md border border-input bg-background px-2 py-1 text-xs\"\n value={moscowFilter}\n onChange={(e) => setMoscowFilter(e.target.value)}\n >\n <option value=\"\">All</option>\n {MOSCOW_VALUES.map((v) => (\n <option key={v} value={v}>\n {MOSCOW_META[v].label}\n </option>\n ))}\n </select>\n </div>\n <div className=\"flex items-center gap-1\">\n <label htmlFor=\"feature-filter-kano\" className=\"text-xs text-muted-foreground\">\n Kano\n </label>\n <select\n id=\"feature-filter-kano\"\n data-testid=\"feature-filter-kano\"\n className=\"rounded-md border border-input bg-background px-2 py-1 text-xs\"\n value={kanoFilter}\n onChange={(e) => setKanoFilter(e.target.value)}\n >\n <option value=\"\">All</option>\n {KANO_VALUES.map((v) => (\n <option key={v} value={v}>\n {KANO_META[v].label}\n </option>\n ))}\n </select>\n </div>\n <div className=\"flex items-center gap-1\">\n <label htmlFor=\"feature-filter-quadrant\" className=\"text-xs text-muted-foreground\">\n Quadrant\n </label>\n <select\n id=\"feature-filter-quadrant\"\n data-testid=\"feature-filter-quadrant\"\n className=\"rounded-md border border-input bg-background px-2 py-1 text-xs\"\n value={quadrantFilter}\n onChange={(e) => setQuadrantFilter(e.target.value)}\n >\n <option value=\"\">All</option>\n {QUADRANT_VALUES.map((v) => (\n <option key={v} value={v}>\n {QUADRANT_META[v].label}\n </option>\n ))}\n </select>\n </div>\n </div>\n\n <div className=\"space-y-3\">\n {sorted.map((feature) => (\n <Card\n key={feature.id}\n {...rowLinkProps(\n () => navigate(detailPath('/products/feature-detail-page', feature.id)),\n feature.title\n )}\n >\n <CardContent className=\"py-4\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"flex-1 space-y-2\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium\">{feature.title}</span>\n <span\n className={`text-[10px] px-1.5 py-0.5 rounded-full capitalize ${statusColor[feature.status] ?? 'bg-gray-100'}`}\n >\n {feature.status.toLowerCase().replace('_', ' ')}\n </span>\n {/* PRM-27 — hidden when unscored so most cards (not yet prioritized) stay uncluttered. */}\n <QuadrantBadge quadrant={feature.valueEffortQuadrant} hideWhenUnscored />\n </div>\n <p className=\"text-xs text-muted-foreground\">{feature.description}</p>\n <div className=\"flex items-center gap-4 text-xs text-muted-foreground\">\n <span>Effort: {feature.effortEstimate ?? 'N/A'}</span>\n {/* By name, not user UUID (BOFF-7950). */}\n <span>\n Submitted by: <PersonName id={feature.submittedBy} />\n </span>\n <span>{new Date(feature.updatedAt).toLocaleDateString()}</span>\n </div>\n {isSnoozed(feature.snoozedUntil, now) && (\n <p className=\"text-xs text-muted-foreground\">\n Snoozed until {new Date(feature.snoozedUntil).toLocaleDateString()}\n </p>\n )}\n <FeatureTriageActions feature={feature} now={now} />\n {feature.tags.length > 0 && (\n <div className=\"flex gap-1\">\n {feature.tags.map((tag) => (\n <Badge key={tag} variant=\"outline\" className=\"text-[10px]\">\n {tag}\n </Badge>\n ))}\n </div>\n )}\n </div>\n <div className=\"flex items-center gap-4 shrink-0\">\n <div className=\"text-center\">\n <div className=\"flex items-center gap-1\">\n <Target className=\"h-3 w-3 text-primary\" />\n <span className=\"text-sm font-bold\">{feature.priorityScore ?? 0}</span>\n </div>\n <p className=\"text-[10px] text-muted-foreground\">Priority</p>\n </div>\n <div className=\"text-center\">\n <div className=\"flex items-center gap-1\">\n <ThumbsUp className=\"h-3 w-3 text-green-500\" />\n <span className=\"text-sm font-bold\">{feature.voteCount}</span>\n </div>\n <p className=\"text-[10px] text-muted-foreground\">Votes</p>\n </div>\n <div className=\"text-center\">\n <div className=\"flex items-center gap-1\">\n <Star className=\"h-3 w-3 text-yellow-500\" />\n <span className=\"text-sm font-bold\">{feature.businessValue ?? 0}</span>\n </div>\n <p className=\"text-[10px] text-muted-foreground\">Value</p>\n </div>\n </div>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n {sorted.length === 0 && (\n <p className=\"text-center text-muted-foreground py-8\">\n {statusFilter === 'TRIAGE'\n ? 'Nothing waits for triage.'\n : 'No features match the selected filters.'}\n </p>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ProductsNewFeaturePagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProductsNewFeaturePagePage.tsx"],"names":[],"mappings":"AAyBA,wBAAgB,0BAA0B,4CAiPzC"}
1
+ {"version":3,"file":"ProductsNewFeaturePagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProductsNewFeaturePagePage.tsx"],"names":[],"mappings":"AA+BA,wBAAgB,0BAA0B,4CAyQzC"}