@burdenoff/microfe-planmagnet 2026.830.1 → 2026.923.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/planmagnet/PlanMagnetRoutes.d.ts.map +1 -1
  2. package/dist/planmagnet/PlanMagnetRoutes.js +52 -0
  3. package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
  4. package/dist/planmagnet/hooks/useEntityId.d.ts +14 -0
  5. package/dist/planmagnet/hooks/useEntityId.d.ts.map +1 -0
  6. package/dist/planmagnet/hooks/useEntityId.js +15 -0
  7. package/dist/planmagnet/hooks/useEntityId.js.map +1 -0
  8. package/dist/planmagnet/pages/ProductsFeaturesPagePage.d.ts.map +1 -1
  9. package/dist/planmagnet/pages/ProductsFeaturesPagePage.js +148 -144
  10. package/dist/planmagnet/pages/ProductsFeaturesPagePage.js.map +1 -1
  11. package/dist/planmagnet/pages/ProductsProductsPagePage.d.ts.map +1 -1
  12. package/dist/planmagnet/pages/ProductsProductsPagePage.js +85 -84
  13. package/dist/planmagnet/pages/ProductsProductsPagePage.js.map +1 -1
  14. package/dist/planmagnet/pages/ProductsReleasesPagePage.d.ts.map +1 -1
  15. package/dist/planmagnet/pages/ProductsReleasesPagePage.js +95 -91
  16. package/dist/planmagnet/pages/ProductsReleasesPagePage.js.map +1 -1
  17. package/dist/planmagnet/pages/ProductsRoadmapsPagePage.d.ts.map +1 -1
  18. package/dist/planmagnet/pages/ProductsRoadmapsPagePage.js +117 -113
  19. package/dist/planmagnet/pages/ProductsRoadmapsPagePage.js.map +1 -1
  20. package/dist/planmagnet/pages/ProjectsActiveProjectsPagePage.d.ts.map +1 -1
  21. package/dist/planmagnet/pages/ProjectsActiveProjectsPagePage.js +74 -70
  22. package/dist/planmagnet/pages/ProjectsActiveProjectsPagePage.js.map +1 -1
  23. package/dist/planmagnet/pages/ProjectsEditProjectPagePage.d.ts.map +1 -1
  24. package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js +21 -17
  25. package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js.map +1 -1
  26. package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.d.ts.map +1 -1
  27. package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.js +21 -16
  28. package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.js.map +1 -1
  29. package/dist/planmagnet/pages/ProjectsMilestonesPagePage.d.ts.map +1 -1
  30. package/dist/planmagnet/pages/ProjectsMilestonesPagePage.js +67 -63
  31. package/dist/planmagnet/pages/ProjectsMilestonesPagePage.js.map +1 -1
  32. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.d.ts.map +1 -1
  33. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js +61 -56
  34. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js.map +1 -1
  35. package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.d.ts.map +1 -1
  36. package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.js +107 -99
  37. package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.js.map +1 -1
  38. package/dist/planmagnet/pages/ProjectsPlanningPagePage.d.ts.map +1 -1
  39. package/dist/planmagnet/pages/ProjectsPlanningPagePage.js +94 -90
  40. package/dist/planmagnet/pages/ProjectsPlanningPagePage.js.map +1 -1
  41. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.d.ts.map +1 -1
  42. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js +46 -41
  43. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js.map +1 -1
  44. package/dist/planmagnet/pages/ProjectsProjectsPagePage.d.ts.map +1 -1
  45. package/dist/planmagnet/pages/ProjectsProjectsPagePage.js +110 -106
  46. package/dist/planmagnet/pages/ProjectsProjectsPagePage.js.map +1 -1
  47. package/dist/planmagnet/pages/TasksCreateTaskPagePage.js +2 -2
  48. package/dist/planmagnet/pages/TasksCreateTaskPagePage.js.map +1 -1
  49. package/dist/planmagnet/pages/TasksEditTaskPagePage.js +2 -2
  50. package/dist/planmagnet/pages/TasksEditTaskPagePage.js.map +1 -1
  51. package/dist/planmagnet/pages/TasksTasksPagePage.d.ts.map +1 -1
  52. package/dist/planmagnet/pages/TasksTasksPagePage.js +67 -66
  53. package/dist/planmagnet/pages/TasksTasksPagePage.js.map +1 -1
  54. package/dist/planmagnet/utils/rowNavigation.d.ts +29 -0
  55. package/dist/planmagnet/utils/rowNavigation.d.ts.map +1 -0
  56. package/dist/planmagnet/utils/rowNavigation.js +20 -0
  57. package/dist/planmagnet/utils/rowNavigation.js.map +1 -0
  58. package/package.json +1 -1
@@ -1,12 +1,13 @@
1
1
  import { usePlanMagnet as e, usePlanMagnetNavigate as t } from "../providers/PlanMagnetProvider.js";
2
- import { useState as n } from "react";
3
- import { ArrowUpDown as r, Filter as i, Loader2 as a, Plus as o, Star as s, Target as c, ThumbsUp as l } from "lucide-react";
4
- import { gql as u } from "@apollo/client";
5
- import { useQuery as d } from "@apollo/client/react";
6
- import { jsx as f, jsxs as p } from "react/jsx-runtime";
7
- import { Badge as m, Button as h, Card as g, CardContent as _ } from "@burdenoff/fe-libs/ui";
2
+ import { detailPath as n, rowLinkProps as r } from "../utils/rowNavigation.js";
3
+ import { useState as i } from "react";
4
+ import { ArrowUpDown as a, Filter as o, Loader2 as s, Plus as c, Star as l, Target as u, ThumbsUp as d } from "lucide-react";
5
+ import { gql as f } from "@apollo/client";
6
+ import { useQuery as p } from "@apollo/client/react";
7
+ import { jsx as m, jsxs as h } from "react/jsx-runtime";
8
+ import { Badge as g, Button as _, Card as v, CardContent as y } from "@burdenoff/fe-libs/ui";
8
9
  //#region src/planmagnet/pages/ProductsFeaturesPagePage.tsx
9
- var v = u`
10
+ var b = f`
10
11
  query ListFeatureRequests(
11
12
  $workspaceId: ID!
12
13
  $filter: PlanmagnetFeatureRequestFilter
@@ -30,7 +31,7 @@ var v = u`
30
31
  totalCount
31
32
  }
32
33
  }
33
- `, y = {
34
+ `, x = {
34
35
  SUBMITTED: "bg-gray-100 text-gray-800",
35
36
  UNDER_REVIEW: "bg-yellow-100 text-yellow-800",
36
37
  PLANNED: "bg-blue-100 text-blue-800",
@@ -39,27 +40,27 @@ var v = u`
39
40
  DECLINED: "bg-red-100 text-red-800",
40
41
  DUPLICATE: "bg-orange-100 text-orange-800"
41
42
  };
42
- function b() {
43
- let u = t(), { workspaceId: b } = e(), [x, S] = n("all"), [C, w] = n("priorityScore"), { data: T, loading: E, error: D } = d(v, {
43
+ function S() {
44
+ let f = t(), { workspaceId: S } = e(), [C, w] = i("all"), [T, E] = i("priorityScore"), { data: D, loading: O, error: k } = p(b, {
44
45
  variables: {
45
- workspaceId: b,
46
- filter: x === "all" ? void 0 : { status: x },
46
+ workspaceId: S,
47
+ filter: C === "all" ? void 0 : { status: C },
47
48
  pagination: { first: 50 }
48
49
  },
49
- skip: !b
50
+ skip: !S
50
51
  });
51
- if (E) return /* @__PURE__ */ f("div", {
52
+ if (O) return /* @__PURE__ */ m("div", {
52
53
  className: "flex items-center justify-center p-12",
53
- children: /* @__PURE__ */ f(a, { className: "h-8 w-8 animate-spin text-muted-foreground" })
54
+ children: /* @__PURE__ */ m(s, { className: "h-8 w-8 animate-spin text-muted-foreground" })
54
55
  });
55
- if (D) return /* @__PURE__ */ p("div", {
56
+ if (k) return /* @__PURE__ */ h("div", {
56
57
  className: "p-6 text-destructive",
57
- children: ["Failed to load features: ", D.message]
58
+ children: ["Failed to load features: ", k.message]
58
59
  });
59
- let O = T?.planmagnetFeatureRequests?.items ?? [], k = T?.planmagnetFeatureRequests?.totalCount ?? 0, A = [...O].sort((e, t) => {
60
- let n = e[C] ?? 0;
61
- return (t[C] ?? 0) - n;
62
- }), j = [
60
+ let A = D?.planmagnetFeatureRequests?.items ?? [], j = D?.planmagnetFeatureRequests?.totalCount ?? 0, M = [...A].sort((e, t) => {
61
+ let n = e[T] ?? 0;
62
+ return (t[T] ?? 0) - n;
63
+ }), N = [
63
64
  "all",
64
65
  "SUBMITTED",
65
66
  "UNDER_REVIEW",
@@ -68,184 +69,187 @@ function b() {
68
69
  "COMPLETED",
69
70
  "DECLINED",
70
71
  "DUPLICATE"
71
- ], M = {
72
- total: k,
73
- inProgress: O.filter((e) => e.status === "IN_PROGRESS").length,
74
- completed: O.filter((e) => e.status === "COMPLETED").length,
75
- avgPriority: O.length > 0 ? Math.round(O.reduce((e, t) => e + (t.priorityScore ?? 0), 0) / O.length) : 0
72
+ ], P = {
73
+ total: j,
74
+ inProgress: A.filter((e) => e.status === "IN_PROGRESS").length,
75
+ completed: A.filter((e) => e.status === "COMPLETED").length,
76
+ avgPriority: A.length > 0 ? Math.round(A.reduce((e, t) => e + (t.priorityScore ?? 0), 0) / A.length) : 0
76
77
  };
77
- return /* @__PURE__ */ p("div", {
78
+ return /* @__PURE__ */ h("div", {
78
79
  className: "space-y-6 p-6",
79
80
  children: [
80
- /* @__PURE__ */ p("div", {
81
+ /* @__PURE__ */ h("div", {
81
82
  className: "flex items-center justify-between",
82
- children: [/* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("h1", {
83
+ children: [/* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("h1", {
83
84
  className: "text-2xl font-semibold",
84
85
  children: "Features"
85
- }), /* @__PURE__ */ p("p", {
86
+ }), /* @__PURE__ */ h("p", {
86
87
  className: "text-sm text-muted-foreground",
87
- children: [k, " feature requests across all products"]
88
- })] }), /* @__PURE__ */ p(h, {
88
+ children: [j, " feature requests across all products"]
89
+ })] }), /* @__PURE__ */ h(_, {
89
90
  size: "sm",
90
- onClick: () => u("/products/new-feature-page"),
91
- children: [/* @__PURE__ */ f(o, { className: "mr-1 h-4 w-4" }), "New Feature"]
91
+ onClick: () => f("/products/new-feature-page"),
92
+ children: [/* @__PURE__ */ m(c, { className: "mr-1 h-4 w-4" }), "New Feature"]
92
93
  })]
93
94
  }),
94
- /* @__PURE__ */ p("div", {
95
+ /* @__PURE__ */ h("div", {
95
96
  className: "grid grid-cols-2 md:grid-cols-4 gap-4",
96
97
  children: [
97
- /* @__PURE__ */ f(g, { children: /* @__PURE__ */ p(_, {
98
+ /* @__PURE__ */ m(v, { children: /* @__PURE__ */ h(y, {
98
99
  className: "pt-4",
99
- children: [/* @__PURE__ */ f("p", {
100
+ children: [/* @__PURE__ */ m("p", {
100
101
  className: "text-xs text-muted-foreground",
101
102
  children: "Total Features"
102
- }), /* @__PURE__ */ f("p", {
103
+ }), /* @__PURE__ */ m("p", {
103
104
  className: "text-xl font-bold",
104
- children: M.total
105
+ children: P.total
105
106
  })]
106
107
  }) }),
107
- /* @__PURE__ */ f(g, { children: /* @__PURE__ */ p(_, {
108
+ /* @__PURE__ */ m(v, { children: /* @__PURE__ */ h(y, {
108
109
  className: "pt-4",
109
- children: [/* @__PURE__ */ f("p", {
110
+ children: [/* @__PURE__ */ m("p", {
110
111
  className: "text-xs text-muted-foreground",
111
112
  children: "In Progress"
112
- }), /* @__PURE__ */ f("p", {
113
+ }), /* @__PURE__ */ m("p", {
113
114
  className: "text-xl font-bold",
114
- children: M.inProgress
115
+ children: P.inProgress
115
116
  })]
116
117
  }) }),
117
- /* @__PURE__ */ f(g, { children: /* @__PURE__ */ p(_, {
118
+ /* @__PURE__ */ m(v, { children: /* @__PURE__ */ h(y, {
118
119
  className: "pt-4",
119
- children: [/* @__PURE__ */ f("p", {
120
+ children: [/* @__PURE__ */ m("p", {
120
121
  className: "text-xs text-muted-foreground",
121
122
  children: "Completed"
122
- }), /* @__PURE__ */ f("p", {
123
+ }), /* @__PURE__ */ m("p", {
123
124
  className: "text-xl font-bold",
124
- children: M.completed
125
+ children: P.completed
125
126
  })]
126
127
  }) }),
127
- /* @__PURE__ */ f(g, { children: /* @__PURE__ */ p(_, {
128
+ /* @__PURE__ */ m(v, { children: /* @__PURE__ */ h(y, {
128
129
  className: "pt-4",
129
- children: [/* @__PURE__ */ f("p", {
130
+ children: [/* @__PURE__ */ m("p", {
130
131
  className: "text-xs text-muted-foreground",
131
132
  children: "Avg Priority Score"
132
- }), /* @__PURE__ */ f("p", {
133
+ }), /* @__PURE__ */ m("p", {
133
134
  className: "text-xl font-bold",
134
- children: M.avgPriority
135
+ children: P.avgPriority
135
136
  })]
136
137
  }) })
137
138
  ]
138
139
  }),
139
- /* @__PURE__ */ p("div", {
140
+ /* @__PURE__ */ h("div", {
140
141
  className: "flex items-center justify-between flex-wrap gap-2",
141
- children: [/* @__PURE__ */ p("div", {
142
+ children: [/* @__PURE__ */ h("div", {
142
143
  className: "flex items-center gap-2",
143
- children: [/* @__PURE__ */ f(i, { className: "h-4 w-4 text-muted-foreground" }), j.map((e) => /* @__PURE__ */ f("button", {
144
- onClick: () => S(e),
145
- className: `px-2 py-1 text-xs rounded-md capitalize ${x === e ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground"}`,
144
+ children: [/* @__PURE__ */ m(o, { className: "h-4 w-4 text-muted-foreground" }), N.map((e) => /* @__PURE__ */ m("button", {
145
+ onClick: () => w(e),
146
+ className: `px-2 py-1 text-xs rounded-md capitalize ${C === e ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground"}`,
146
147
  children: e === "all" ? "All" : e.toLowerCase().replace("_", " ")
147
148
  }, e))]
148
- }), /* @__PURE__ */ p("div", {
149
+ }), /* @__PURE__ */ h("div", {
149
150
  className: "flex items-center gap-2",
150
- children: [/* @__PURE__ */ f(r, { className: "h-4 w-4 text-muted-foreground" }), [
151
+ children: [/* @__PURE__ */ m(a, { className: "h-4 w-4 text-muted-foreground" }), [
151
152
  "priorityScore",
152
153
  "voteCount",
153
154
  "businessValue"
154
- ].map((e) => /* @__PURE__ */ f("button", {
155
- onClick: () => w(e),
156
- className: `px-2 py-1 text-xs rounded-md capitalize ${C === e ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground"}`,
155
+ ].map((e) => /* @__PURE__ */ m("button", {
156
+ onClick: () => E(e),
157
+ className: `px-2 py-1 text-xs rounded-md capitalize ${T === e ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground"}`,
157
158
  children: e === "priorityScore" ? "Priority" : e === "voteCount" ? "Votes" : "Value"
158
159
  }, e))]
159
160
  })]
160
161
  }),
161
- /* @__PURE__ */ f("div", {
162
+ /* @__PURE__ */ m("div", {
162
163
  className: "space-y-3",
163
- children: A.map((e) => /* @__PURE__ */ f(g, { children: /* @__PURE__ */ f(_, {
164
- className: "py-4",
165
- children: /* @__PURE__ */ p("div", {
166
- className: "flex items-start justify-between gap-4",
167
- children: [/* @__PURE__ */ p("div", {
168
- className: "flex-1 space-y-2",
169
- children: [
170
- /* @__PURE__ */ p("div", {
171
- className: "flex items-center gap-2",
172
- children: [/* @__PURE__ */ f("span", {
173
- className: "text-sm font-medium",
174
- children: e.title
175
- }), /* @__PURE__ */ f("span", {
176
- className: `text-[10px] px-1.5 py-0.5 rounded-full capitalize ${y[e.status] ?? "bg-gray-100"}`,
177
- children: e.status.toLowerCase().replace("_", " ")
178
- })]
179
- }),
180
- /* @__PURE__ */ f("p", {
181
- className: "text-xs text-muted-foreground",
182
- children: e.description
183
- }),
184
- /* @__PURE__ */ p("div", {
185
- className: "flex items-center gap-4 text-xs text-muted-foreground",
186
- children: [
187
- /* @__PURE__ */ p("span", { children: ["Effort: ", e.effortEstimate ?? "N/A"] }),
188
- /* @__PURE__ */ p("span", { children: ["Submitted by: ", e.submittedBy] }),
189
- /* @__PURE__ */ f("span", { children: new Date(e.updatedAt).toLocaleDateString() })
190
- ]
191
- }),
192
- e.tags.length > 0 && /* @__PURE__ */ f("div", {
193
- className: "flex gap-1",
194
- children: e.tags.map((e) => /* @__PURE__ */ f(m, {
195
- variant: "outline",
196
- className: "text-[10px]",
197
- children: e
198
- }, e))
199
- })
200
- ]
201
- }), /* @__PURE__ */ p("div", {
202
- className: "flex items-center gap-4 shrink-0",
203
- children: [
204
- /* @__PURE__ */ p("div", {
205
- className: "text-center",
206
- children: [/* @__PURE__ */ p("div", {
207
- className: "flex items-center gap-1",
208
- children: [/* @__PURE__ */ f(c, { className: "h-3 w-3 text-primary" }), /* @__PURE__ */ f("span", {
209
- className: "text-sm font-bold",
210
- children: e.priorityScore ?? 0
164
+ children: M.map((e) => /* @__PURE__ */ m(v, {
165
+ ...r(() => f(n("/products/feature-detail-page", e.id)), e.title),
166
+ children: /* @__PURE__ */ m(y, {
167
+ className: "py-4",
168
+ children: /* @__PURE__ */ h("div", {
169
+ className: "flex items-start justify-between gap-4",
170
+ children: [/* @__PURE__ */ h("div", {
171
+ className: "flex-1 space-y-2",
172
+ children: [
173
+ /* @__PURE__ */ h("div", {
174
+ className: "flex items-center gap-2",
175
+ children: [/* @__PURE__ */ m("span", {
176
+ className: "text-sm font-medium",
177
+ children: e.title
178
+ }), /* @__PURE__ */ m("span", {
179
+ className: `text-[10px] px-1.5 py-0.5 rounded-full capitalize ${x[e.status] ?? "bg-gray-100"}`,
180
+ children: e.status.toLowerCase().replace("_", " ")
211
181
  })]
212
- }), /* @__PURE__ */ f("p", {
213
- className: "text-[10px] text-muted-foreground",
214
- children: "Priority"
215
- })]
216
- }),
217
- /* @__PURE__ */ p("div", {
218
- className: "text-center",
219
- children: [/* @__PURE__ */ p("div", {
220
- className: "flex items-center gap-1",
221
- children: [/* @__PURE__ */ f(l, { className: "h-3 w-3 text-green-500" }), /* @__PURE__ */ f("span", {
222
- className: "text-sm font-bold",
223
- children: e.voteCount
182
+ }),
183
+ /* @__PURE__ */ m("p", {
184
+ className: "text-xs text-muted-foreground",
185
+ children: e.description
186
+ }),
187
+ /* @__PURE__ */ h("div", {
188
+ className: "flex items-center gap-4 text-xs text-muted-foreground",
189
+ children: [
190
+ /* @__PURE__ */ h("span", { children: ["Effort: ", e.effortEstimate ?? "N/A"] }),
191
+ /* @__PURE__ */ h("span", { children: ["Submitted by: ", e.submittedBy] }),
192
+ /* @__PURE__ */ m("span", { children: new Date(e.updatedAt).toLocaleDateString() })
193
+ ]
194
+ }),
195
+ e.tags.length > 0 && /* @__PURE__ */ m("div", {
196
+ className: "flex gap-1",
197
+ children: e.tags.map((e) => /* @__PURE__ */ m(g, {
198
+ variant: "outline",
199
+ className: "text-[10px]",
200
+ children: e
201
+ }, e))
202
+ })
203
+ ]
204
+ }), /* @__PURE__ */ h("div", {
205
+ className: "flex items-center gap-4 shrink-0",
206
+ children: [
207
+ /* @__PURE__ */ h("div", {
208
+ className: "text-center",
209
+ children: [/* @__PURE__ */ h("div", {
210
+ className: "flex items-center gap-1",
211
+ children: [/* @__PURE__ */ m(u, { className: "h-3 w-3 text-primary" }), /* @__PURE__ */ m("span", {
212
+ className: "text-sm font-bold",
213
+ children: e.priorityScore ?? 0
214
+ })]
215
+ }), /* @__PURE__ */ m("p", {
216
+ className: "text-[10px] text-muted-foreground",
217
+ children: "Priority"
224
218
  })]
225
- }), /* @__PURE__ */ f("p", {
226
- className: "text-[10px] text-muted-foreground",
227
- children: "Votes"
228
- })]
229
- }),
230
- /* @__PURE__ */ p("div", {
231
- className: "text-center",
232
- children: [/* @__PURE__ */ p("div", {
233
- className: "flex items-center gap-1",
234
- children: [/* @__PURE__ */ f(s, { className: "h-3 w-3 text-yellow-500" }), /* @__PURE__ */ f("span", {
235
- className: "text-sm font-bold",
236
- children: e.businessValue ?? 0
219
+ }),
220
+ /* @__PURE__ */ h("div", {
221
+ className: "text-center",
222
+ children: [/* @__PURE__ */ h("div", {
223
+ className: "flex items-center gap-1",
224
+ children: [/* @__PURE__ */ m(d, { className: "h-3 w-3 text-green-500" }), /* @__PURE__ */ m("span", {
225
+ className: "text-sm font-bold",
226
+ children: e.voteCount
227
+ })]
228
+ }), /* @__PURE__ */ m("p", {
229
+ className: "text-[10px] text-muted-foreground",
230
+ children: "Votes"
237
231
  })]
238
- }), /* @__PURE__ */ f("p", {
239
- className: "text-[10px] text-muted-foreground",
240
- children: "Value"
241
- })]
242
- })
243
- ]
244
- })]
232
+ }),
233
+ /* @__PURE__ */ h("div", {
234
+ className: "text-center",
235
+ children: [/* @__PURE__ */ h("div", {
236
+ className: "flex items-center gap-1",
237
+ children: [/* @__PURE__ */ m(l, { className: "h-3 w-3 text-yellow-500" }), /* @__PURE__ */ m("span", {
238
+ className: "text-sm font-bold",
239
+ children: e.businessValue ?? 0
240
+ })]
241
+ }), /* @__PURE__ */ m("p", {
242
+ className: "text-[10px] text-muted-foreground",
243
+ children: "Value"
244
+ })]
245
+ })
246
+ ]
247
+ })]
248
+ })
245
249
  })
246
- }) }, e.id))
250
+ }, e.id))
247
251
  }),
248
- A.length === 0 && /* @__PURE__ */ f("p", {
252
+ M.length === 0 && /* @__PURE__ */ m("p", {
249
253
  className: "text-center text-muted-foreground py-8",
250
254
  children: "No features match the selected filters."
251
255
  })
@@ -253,6 +257,6 @@ function b() {
253
257
  });
254
258
  }
255
259
  //#endregion
256
- export { b as ProductsFeaturesPagePage };
260
+ export { S as ProductsFeaturesPagePage };
257
261
 
258
262
  //# 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 { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\n\nconst LIST_FEATURE_REQUESTS = gql`\n query ListFeatureRequests(\n $workspaceId: ID!\n $filter: PlanmagnetFeatureRequestFilter\n $pagination: PlanmagnetPaginationInput\n ) {\n planmagnetFeatureRequests(workspaceId: $workspaceId, filter: $filter, pagination: $pagination) {\n items {\n id\n title\n description\n status\n businessValue\n effortEstimate\n priorityScore\n voteCount\n submittedBy\n tags\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 const [sortBy, setSortBy] = useState<'priorityScore' | 'voteCount' | 'businessValue'>(\n 'priorityScore'\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: statusFilter !== 'all' ? { status: statusFilter } : undefined,\n pagination: { first: 50 },\n },\n skip: !workspaceId,\n });\n\n if (loading) {\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].sort((a, b) => {\n const aVal = a[sortBy] ?? 0;\n const bVal = b[sortBy] ?? 0;\n return (bVal as number) - (aVal as number);\n });\n\n const statuses = [\n 'all',\n 'SUBMITTED',\n 'UNDER_REVIEW',\n 'PLANNED',\n 'IN_PROGRESS',\n 'COMPLETED',\n 'DECLINED',\n 'DUPLICATE',\n ];\n\n const stats = {\n total: totalCount,\n inProgress: features.filter((f) => f.status === 'IN_PROGRESS').length,\n completed: features.filter((f) => f.status === 'COMPLETED').length,\n avgPriority:\n features.length > 0\n ? Math.round(features.reduce((s, f) => s + (f.priorityScore ?? 0), 0) / features.length)\n : 0,\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 <p className=\"text-sm text-muted-foreground\">\n {totalCount} feature requests across all products\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\">Avg Priority Score</p>\n <p className=\"text-xl font-bold\">{stats.avgPriority}</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' ? 'All' : 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 {(['priorityScore', 'voteCount', 'businessValue'] as const).map((s) => (\n <button\n key={s}\n onClick={() => setSortBy(s)}\n className={`px-2 py-1 text-xs rounded-md capitalize ${sortBy === s ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'}`}\n >\n {s === 'priorityScore' ? 'Priority' : s === 'voteCount' ? 'Votes' : 'Value'}\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"space-y-3\">\n {sorted.map((feature) => (\n <Card key={feature.id}>\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 <span>Submitted by: {feature.submittedBy}</span>\n <span>{new Date(feature.updatedAt).toLocaleDateString()}</span>\n </div>\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 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 { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { rowLinkProps, detailPath } from '../utils/rowNavigation';\n\nconst LIST_FEATURE_REQUESTS = gql`\n query ListFeatureRequests(\n $workspaceId: ID!\n $filter: PlanmagnetFeatureRequestFilter\n $pagination: PlanmagnetPaginationInput\n ) {\n planmagnetFeatureRequests(workspaceId: $workspaceId, filter: $filter, pagination: $pagination) {\n items {\n id\n title\n description\n status\n businessValue\n effortEstimate\n priorityScore\n voteCount\n submittedBy\n tags\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 const [sortBy, setSortBy] = useState<'priorityScore' | 'voteCount' | 'businessValue'>(\n 'priorityScore'\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: statusFilter !== 'all' ? { status: statusFilter } : undefined,\n pagination: { first: 50 },\n },\n skip: !workspaceId,\n });\n\n if (loading) {\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].sort((a, b) => {\n const aVal = a[sortBy] ?? 0;\n const bVal = b[sortBy] ?? 0;\n return (bVal as number) - (aVal as number);\n });\n\n const statuses = [\n 'all',\n 'SUBMITTED',\n 'UNDER_REVIEW',\n 'PLANNED',\n 'IN_PROGRESS',\n 'COMPLETED',\n 'DECLINED',\n 'DUPLICATE',\n ];\n\n const stats = {\n total: totalCount,\n inProgress: features.filter((f) => f.status === 'IN_PROGRESS').length,\n completed: features.filter((f) => f.status === 'COMPLETED').length,\n avgPriority:\n features.length > 0\n ? Math.round(features.reduce((s, f) => s + (f.priorityScore ?? 0), 0) / features.length)\n : 0,\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 <p className=\"text-sm text-muted-foreground\">\n {totalCount} feature requests across all products\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\">Avg Priority Score</p>\n <p className=\"text-xl font-bold\">{stats.avgPriority}</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' ? 'All' : 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 {(['priorityScore', 'voteCount', 'businessValue'] as const).map((s) => (\n <button\n key={s}\n onClick={() => setSortBy(s)}\n className={`px-2 py-1 text-xs rounded-md capitalize ${sortBy === s ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'}`}\n >\n {s === 'priorityScore' ? 'Priority' : s === 'voteCount' ? 'Votes' : 'Value'}\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 <span>Submitted by: {feature.submittedBy}</span>\n <span>{new Date(feature.updatedAt).toLocaleDateString()}</span>\n </div>\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 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":"ProductsProductsPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProductsProductsPagePage.tsx"],"names":[],"mappings":"AAgEA,wBAAgB,wBAAwB,4CAsLvC"}
1
+ {"version":3,"file":"ProductsProductsPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProductsProductsPagePage.tsx"],"names":[],"mappings":"AAiEA,wBAAgB,wBAAwB,4CA6LvC"}