@burdenoff/microfe-planmagnet 2026.928.8 → 2026.928.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/planmagnet/PlanMagnetRoot.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoot.js +1 -1
- package/dist/planmagnet/PlanMagnetRoot.js.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.js +219 -207
- package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
- package/dist/planmagnet/controls/WorkItemControls.d.ts +21 -0
- package/dist/planmagnet/controls/WorkItemControls.d.ts.map +1 -1
- package/dist/planmagnet/controls/WorkItemControls.js +34 -15
- package/dist/planmagnet/controls/WorkItemControls.js.map +1 -1
- package/dist/planmagnet/pages/ProductsCreateProductPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsCreateProductPagePage.js +198 -99
- package/dist/planmagnet/pages/ProductsCreateProductPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsEditProductPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsEditProductPagePage.js +260 -170
- package/dist/planmagnet/pages/ProductsEditProductPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsEditRoadmapPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProductsEditRoadmapPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProductsEditRoadmapPagePage.js +283 -0
- package/dist/planmagnet/pages/ProductsEditRoadmapPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.js +166 -246
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsProductsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsProductsPagePage.js +147 -117
- package/dist/planmagnet/pages/ProductsProductsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ReportsReportsPagePage.d.ts +0 -7
- package/dist/planmagnet/pages/ReportsReportsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ReportsReportsPagePage.js +517 -39
- package/dist/planmagnet/pages/ReportsReportsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksMyWorkPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/TasksMyWorkPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/TasksMyWorkPagePage.js +257 -0
- package/dist/planmagnet/pages/TasksMyWorkPagePage.js.map +1 -0
- package/dist/planmagnet/product/ProductControls.d.ts +52 -0
- package/dist/planmagnet/product/ProductControls.d.ts.map +1 -0
- package/dist/planmagnet/product/ProductControls.js +780 -0
- package/dist/planmagnet/product/ProductControls.js.map +1 -0
- package/dist/planmagnet/roadmaps/RoadmapControls.d.ts.map +1 -1
- package/dist/planmagnet/roadmaps/RoadmapControls.js +1 -1
- package/dist/planmagnet/roadmaps/RoadmapControls.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,92 +1,112 @@
|
|
|
1
1
|
import { usePlanMagnet as e, usePlanMagnetNavigate as t } from "../providers/PlanMagnetProvider.js";
|
|
2
2
|
import { throwOnError as n } from "../utils/mutationResult.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
3
|
+
import { enumLabel as r } from "../controls/WorkItemControls.js";
|
|
4
|
+
import { detailPath as i } from "../utils/rowNavigation.js";
|
|
5
|
+
import { useState as a } from "react";
|
|
6
|
+
import { Eye as o, Loader2 as s, Package as c, Save as l, X as u } from "lucide-react";
|
|
7
|
+
import { gql as d } from "@apollo/client";
|
|
8
|
+
import { useMutation as f } from "@apollo/client/react";
|
|
9
|
+
import { jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
10
|
+
import { Badge as h, Button as g, Card as _, CardContent as v, CardHeader as y, CardTitle as b, Input as x } from "@burdenoff/fe-libs/ui";
|
|
10
11
|
//#region src/planmagnet/pages/ProductsCreateProductPagePage.tsx
|
|
11
|
-
var
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
var S = [
|
|
13
|
+
"CONCEPT",
|
|
14
|
+
"DEVELOPMENT",
|
|
15
|
+
"BETA",
|
|
16
|
+
"LAUNCHED",
|
|
17
|
+
"MATURE",
|
|
18
|
+
"DEPRECATED"
|
|
19
|
+
], C = d`
|
|
20
|
+
mutation CreateProduct($input: PlanmagnetCreateProductInput!) {
|
|
21
|
+
planmagnetCreateProduct(input: $input) {
|
|
14
22
|
id
|
|
15
23
|
name
|
|
16
24
|
description
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
isPublic
|
|
25
|
+
vision
|
|
26
|
+
lifecycleStage
|
|
20
27
|
ownerId
|
|
21
28
|
createdAt
|
|
22
29
|
}
|
|
23
30
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
31
|
+
`, w = {
|
|
32
|
+
name: "",
|
|
33
|
+
unit: "",
|
|
34
|
+
target: "",
|
|
35
|
+
current: "",
|
|
36
|
+
window: ""
|
|
37
|
+
};
|
|
38
|
+
function T() {
|
|
39
|
+
let { currentUser: d } = e(), T = t(), [E, D] = a({
|
|
27
40
|
name: "",
|
|
28
41
|
description: "",
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}), [O, k] =
|
|
32
|
-
|
|
42
|
+
vision: "",
|
|
43
|
+
lifecycleStage: "CONCEPT"
|
|
44
|
+
}), [O, k] = a(w), [A, j] = a(null), [M, { loading: N }] = f(C, { refetchQueries: ["GetProducts"] }), P = Object.values(O).some((e) => e.trim() !== ""), F = O.name.trim() && O.unit.trim() && O.window.trim() && O.target.trim() !== "" && !Number.isNaN(Number(O.target)) && O.current.trim() !== "" && !Number.isNaN(Number(O.current)), I = E.name.trim() && E.vision.trim() && (!P || F), L = async () => {
|
|
45
|
+
if (I) {
|
|
46
|
+
j(null);
|
|
47
|
+
try {
|
|
48
|
+
let e = (await n(M({ variables: { input: {
|
|
49
|
+
name: E.name,
|
|
50
|
+
description: E.description || void 0,
|
|
51
|
+
vision: E.vision,
|
|
52
|
+
lifecycleStage: E.lifecycleStage,
|
|
53
|
+
ownerId: d?.id ?? "",
|
|
54
|
+
...F ? { northStar: {
|
|
55
|
+
name: O.name,
|
|
56
|
+
unit: O.unit,
|
|
57
|
+
target: Number(O.target),
|
|
58
|
+
current: Number(O.current),
|
|
59
|
+
window: O.window
|
|
60
|
+
} } : {}
|
|
61
|
+
} } }))).data?.planmagnetCreateProduct?.id;
|
|
62
|
+
T(e ? i("/products/product-detail-page", e) : "/products/products-page");
|
|
63
|
+
} catch (e) {
|
|
64
|
+
j(e instanceof Error ? e.message : "The product could not be created.");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
return /* @__PURE__ */ m("div", {
|
|
33
69
|
className: "space-y-6 p-6",
|
|
34
70
|
children: [
|
|
35
|
-
/* @__PURE__ */
|
|
71
|
+
/* @__PURE__ */ m("div", {
|
|
36
72
|
className: "flex items-center justify-between",
|
|
37
|
-
children: [/* @__PURE__ */
|
|
73
|
+
children: [/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("h1", {
|
|
38
74
|
className: "text-2xl font-semibold",
|
|
39
75
|
children: "Create Product"
|
|
40
|
-
}), /* @__PURE__ */
|
|
76
|
+
}), /* @__PURE__ */ p("p", {
|
|
41
77
|
className: "text-sm text-muted-foreground",
|
|
42
78
|
children: "Define a new product with its vision and strategy."
|
|
43
|
-
})] }), /* @__PURE__ */
|
|
79
|
+
})] }), /* @__PURE__ */ m("div", {
|
|
44
80
|
className: "flex items-center gap-2",
|
|
45
|
-
children: [/* @__PURE__ */
|
|
81
|
+
children: [/* @__PURE__ */ m(g, {
|
|
46
82
|
variant: "outline",
|
|
47
83
|
size: "sm",
|
|
48
84
|
onClick: () => T("/products/products-page"),
|
|
49
|
-
children: [/* @__PURE__ */
|
|
50
|
-
}), /* @__PURE__ */
|
|
85
|
+
children: [/* @__PURE__ */ p(u, { className: "mr-1 h-4 w-4" }), "Cancel"]
|
|
86
|
+
}), /* @__PURE__ */ m(g, {
|
|
51
87
|
size: "sm",
|
|
52
|
-
onClick:
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
await n(A({ variables: { input: {
|
|
57
|
-
name: E.name,
|
|
58
|
-
description: E.description || void 0,
|
|
59
|
-
type: a,
|
|
60
|
-
...E.planningFocus ? { planningFocus: E.planningFocus } : {},
|
|
61
|
-
isPublic: E.isPublic,
|
|
62
|
-
ownerId: w?.id ?? ""
|
|
63
|
-
} } })), T("/products/products-page");
|
|
64
|
-
} catch (e) {
|
|
65
|
-
k(e instanceof Error ? e.message : "The product could not be created.");
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
disabled: j || !E.name.trim(),
|
|
70
|
-
children: [j ? /* @__PURE__ */ m(c, { className: "mr-1 h-4 w-4 animate-spin" }) : /* @__PURE__ */ m(u, { className: "mr-1 h-4 w-4" }), "Create Product"]
|
|
88
|
+
onClick: () => void L(),
|
|
89
|
+
disabled: N || !I,
|
|
90
|
+
children: [N ? /* @__PURE__ */ p(s, { className: "mr-1 h-4 w-4 animate-spin" }) : /* @__PURE__ */ p(l, { className: "mr-1 h-4 w-4" }), "Create Product"]
|
|
71
91
|
})]
|
|
72
92
|
})]
|
|
73
93
|
}),
|
|
74
|
-
|
|
94
|
+
A && /* @__PURE__ */ m("div", {
|
|
75
95
|
role: "alert",
|
|
76
96
|
className: "p-3 rounded-md bg-destructive/10 text-destructive text-sm",
|
|
77
|
-
children: ["Failed to create product: ",
|
|
97
|
+
children: ["Failed to create product: ", A]
|
|
78
98
|
}),
|
|
79
|
-
/* @__PURE__ */
|
|
99
|
+
/* @__PURE__ */ m("div", {
|
|
80
100
|
className: "grid grid-cols-1 lg:grid-cols-3 gap-6",
|
|
81
101
|
children: [/* @__PURE__ */ m("div", {
|
|
82
102
|
className: "lg:col-span-2 space-y-6",
|
|
83
|
-
children: /* @__PURE__ */
|
|
103
|
+
children: [/* @__PURE__ */ m(_, { children: [/* @__PURE__ */ p(y, { children: /* @__PURE__ */ p(b, { children: "Basic Information" }) }), /* @__PURE__ */ m(v, {
|
|
84
104
|
className: "space-y-4",
|
|
85
105
|
children: [
|
|
86
|
-
/* @__PURE__ */
|
|
106
|
+
/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
87
107
|
className: "text-sm font-medium",
|
|
88
108
|
children: "Product Name"
|
|
89
|
-
}), /* @__PURE__ */
|
|
109
|
+
}), /* @__PURE__ */ p(x, {
|
|
90
110
|
placeholder: "e.g. PlanMagnet Analytics",
|
|
91
111
|
value: E.name,
|
|
92
112
|
onChange: (e) => D({
|
|
@@ -95,11 +115,11 @@ function w() {
|
|
|
95
115
|
}),
|
|
96
116
|
className: "mt-1"
|
|
97
117
|
})] }),
|
|
98
|
-
/* @__PURE__ */
|
|
118
|
+
/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
99
119
|
className: "text-sm font-medium",
|
|
100
120
|
children: "Description"
|
|
101
|
-
}), /* @__PURE__ */
|
|
102
|
-
className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[
|
|
121
|
+
}), /* @__PURE__ */ p("textarea", {
|
|
122
|
+
className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[60px]",
|
|
103
123
|
placeholder: "Describe what this product does...",
|
|
104
124
|
value: E.description,
|
|
105
125
|
onChange: (e) => D({
|
|
@@ -107,70 +127,149 @@ function w() {
|
|
|
107
127
|
description: e.target.value
|
|
108
128
|
})
|
|
109
129
|
})] }),
|
|
110
|
-
/* @__PURE__ */ m(
|
|
111
|
-
|
|
130
|
+
/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
131
|
+
className: "text-sm font-medium",
|
|
132
|
+
children: "Vision"
|
|
133
|
+
}), /* @__PURE__ */ p("textarea", {
|
|
134
|
+
className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[80px]",
|
|
135
|
+
placeholder: "Where this product is headed and why it matters...",
|
|
136
|
+
value: E.vision,
|
|
112
137
|
onChange: (e) => D({
|
|
113
138
|
...E,
|
|
114
|
-
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
|
|
139
|
+
vision: e.target.value
|
|
140
|
+
}),
|
|
141
|
+
"data-testid": "product-vision"
|
|
142
|
+
})] }),
|
|
143
|
+
/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
118
144
|
className: "text-sm font-medium",
|
|
119
|
-
children: "
|
|
120
|
-
}), /* @__PURE__ */
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
145
|
+
children: "Lifecycle Stage"
|
|
146
|
+
}), /* @__PURE__ */ p("select", {
|
|
147
|
+
"aria-label": "Lifecycle stage",
|
|
148
|
+
"data-testid": "product-lifecycle-stage",
|
|
149
|
+
className: "mt-1 w-full rounded-md border border-input bg-background px-2 py-1.5 text-sm",
|
|
150
|
+
value: E.lifecycleStage,
|
|
151
|
+
onChange: (e) => D({
|
|
152
|
+
...E,
|
|
153
|
+
lifecycleStage: e.target.value
|
|
154
|
+
}),
|
|
155
|
+
children: S.map((e) => /* @__PURE__ */ p("option", {
|
|
156
|
+
value: e,
|
|
157
|
+
children: r(e)
|
|
158
|
+
}, e))
|
|
130
159
|
})] })
|
|
131
160
|
]
|
|
132
|
-
})] })
|
|
133
|
-
|
|
161
|
+
})] }), /* @__PURE__ */ m(_, { children: [/* @__PURE__ */ p(y, { children: /* @__PURE__ */ p(b, { children: "North Star metric (optional)" }) }), /* @__PURE__ */ m(v, {
|
|
162
|
+
className: "space-y-4",
|
|
163
|
+
children: [
|
|
164
|
+
/* @__PURE__ */ p("p", {
|
|
165
|
+
className: "text-xs text-muted-foreground",
|
|
166
|
+
children: "Leave every field blank to skip — it can be added later from the product's edit page."
|
|
167
|
+
}),
|
|
168
|
+
/* @__PURE__ */ m("div", {
|
|
169
|
+
className: "grid grid-cols-2 gap-4",
|
|
170
|
+
children: [
|
|
171
|
+
/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
172
|
+
className: "text-sm font-medium",
|
|
173
|
+
children: "Metric name"
|
|
174
|
+
}), /* @__PURE__ */ p(x, {
|
|
175
|
+
placeholder: "e.g. Weekly active users",
|
|
176
|
+
value: O.name,
|
|
177
|
+
onChange: (e) => k({
|
|
178
|
+
...O,
|
|
179
|
+
name: e.target.value
|
|
180
|
+
}),
|
|
181
|
+
className: "mt-1"
|
|
182
|
+
})] }),
|
|
183
|
+
/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
184
|
+
className: "text-sm font-medium",
|
|
185
|
+
children: "Unit"
|
|
186
|
+
}), /* @__PURE__ */ p(x, {
|
|
187
|
+
placeholder: "e.g. users",
|
|
188
|
+
value: O.unit,
|
|
189
|
+
onChange: (e) => k({
|
|
190
|
+
...O,
|
|
191
|
+
unit: e.target.value
|
|
192
|
+
}),
|
|
193
|
+
className: "mt-1"
|
|
194
|
+
})] }),
|
|
195
|
+
/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
196
|
+
className: "text-sm font-medium",
|
|
197
|
+
children: "Target"
|
|
198
|
+
}), /* @__PURE__ */ p(x, {
|
|
199
|
+
type: "number",
|
|
200
|
+
value: O.target,
|
|
201
|
+
onChange: (e) => k({
|
|
202
|
+
...O,
|
|
203
|
+
target: e.target.value
|
|
204
|
+
}),
|
|
205
|
+
className: "mt-1"
|
|
206
|
+
})] }),
|
|
207
|
+
/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
208
|
+
className: "text-sm font-medium",
|
|
209
|
+
children: "Current"
|
|
210
|
+
}), /* @__PURE__ */ p(x, {
|
|
211
|
+
type: "number",
|
|
212
|
+
value: O.current,
|
|
213
|
+
onChange: (e) => k({
|
|
214
|
+
...O,
|
|
215
|
+
current: e.target.value
|
|
216
|
+
}),
|
|
217
|
+
className: "mt-1"
|
|
218
|
+
})] }),
|
|
219
|
+
/* @__PURE__ */ m("div", {
|
|
220
|
+
className: "col-span-2",
|
|
221
|
+
children: [/* @__PURE__ */ p("label", {
|
|
222
|
+
className: "text-sm font-medium",
|
|
223
|
+
children: "Window"
|
|
224
|
+
}), /* @__PURE__ */ p(x, {
|
|
225
|
+
placeholder: "e.g. Q1 2027, weekly, ongoing",
|
|
226
|
+
value: O.window,
|
|
227
|
+
onChange: (e) => k({
|
|
228
|
+
...O,
|
|
229
|
+
window: e.target.value
|
|
230
|
+
}),
|
|
231
|
+
className: "mt-1"
|
|
232
|
+
})]
|
|
233
|
+
})
|
|
234
|
+
]
|
|
235
|
+
}),
|
|
236
|
+
P && !F && /* @__PURE__ */ p("p", {
|
|
237
|
+
className: "text-xs text-destructive",
|
|
238
|
+
children: "Fill in every North Star field (or clear them all) — name, unit, target, current and window are all required together."
|
|
239
|
+
})
|
|
240
|
+
]
|
|
241
|
+
})] })]
|
|
242
|
+
}), /* @__PURE__ */ m("div", {
|
|
134
243
|
className: "space-y-6",
|
|
135
|
-
children: [/* @__PURE__ */
|
|
244
|
+
children: [/* @__PURE__ */ m(_, { children: [/* @__PURE__ */ p(y, { children: /* @__PURE__ */ m(b, {
|
|
136
245
|
className: "flex items-center gap-2",
|
|
137
|
-
children: [/* @__PURE__ */
|
|
138
|
-
}) }), /* @__PURE__ */
|
|
246
|
+
children: [/* @__PURE__ */ p(o, { className: "h-4 w-4" }), "Preview"]
|
|
247
|
+
}) }), /* @__PURE__ */ m(v, {
|
|
139
248
|
className: "space-y-3",
|
|
140
249
|
children: [
|
|
141
|
-
/* @__PURE__ */
|
|
250
|
+
/* @__PURE__ */ m("div", {
|
|
142
251
|
className: "flex items-center gap-2",
|
|
143
|
-
children: [/* @__PURE__ */
|
|
252
|
+
children: [/* @__PURE__ */ p(c, { className: "h-5 w-5 text-primary" }), /* @__PURE__ */ p("span", {
|
|
144
253
|
className: "font-medium",
|
|
145
254
|
children: E.name || "Product Name"
|
|
146
255
|
})]
|
|
147
256
|
}),
|
|
148
|
-
/* @__PURE__ */
|
|
257
|
+
/* @__PURE__ */ p("p", {
|
|
149
258
|
className: "text-sm text-muted-foreground",
|
|
150
|
-
children: E.
|
|
259
|
+
children: E.vision || "No vision set yet"
|
|
151
260
|
}),
|
|
152
|
-
/* @__PURE__ */
|
|
153
|
-
variant:
|
|
261
|
+
/* @__PURE__ */ p(h, {
|
|
262
|
+
variant: "secondary",
|
|
154
263
|
className: "capitalize",
|
|
155
|
-
children: E.
|
|
156
|
-
}),
|
|
157
|
-
/* @__PURE__ */ h("div", {
|
|
158
|
-
className: "pt-2 border-t",
|
|
159
|
-
children: [/* @__PURE__ */ m("p", {
|
|
160
|
-
className: "text-xs font-medium text-muted-foreground",
|
|
161
|
-
children: "PLANNING FOCUS"
|
|
162
|
-
}), /* @__PURE__ */ m("div", {
|
|
163
|
-
className: "mt-1",
|
|
164
|
-
children: /* @__PURE__ */ m(r, { focus: E.planningFocus })
|
|
165
|
-
})]
|
|
264
|
+
children: r(E.lifecycleStage)
|
|
166
265
|
})
|
|
167
266
|
]
|
|
168
|
-
})] }), /* @__PURE__ */
|
|
267
|
+
})] }), /* @__PURE__ */ m(_, { children: [/* @__PURE__ */ p(y, { children: /* @__PURE__ */ p(b, { children: "Quick Tips" }) }), /* @__PURE__ */ m(v, {
|
|
169
268
|
className: "text-sm text-muted-foreground space-y-2",
|
|
170
269
|
children: [
|
|
171
|
-
/* @__PURE__ */
|
|
172
|
-
/* @__PURE__ */
|
|
173
|
-
/* @__PURE__ */
|
|
270
|
+
/* @__PURE__ */ p("p", { children: "A strong product vision guides all feature decisions." }),
|
|
271
|
+
/* @__PURE__ */ p("p", { children: "Link roadmaps, releases, feature requests and OKRs from the product's own page once it is created." }),
|
|
272
|
+
/* @__PURE__ */ p("p", { children: "Products start in \"Concept\" and move through their lifecycle over time." })
|
|
174
273
|
]
|
|
175
274
|
})] })]
|
|
176
275
|
})]
|
|
@@ -179,6 +278,6 @@ function w() {
|
|
|
179
278
|
});
|
|
180
279
|
}
|
|
181
280
|
//#endregion
|
|
182
|
-
export {
|
|
281
|
+
export { T as ProductsCreateProductPagePage };
|
|
183
282
|
|
|
184
283
|
//# sourceMappingURL=ProductsCreateProductPagePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProductsCreateProductPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProductsCreateProductPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation } from '@apollo/client/react';\nimport {\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Button,\n Input,\n Badge,\n} from '@burdenoff/fe-libs/ui';\nimport { Save, X, Package, Eye, Loader2 } from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\nimport { usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { throwOnError } from '../utils/mutationResult';\nimport {\n PlanningFocusBadge,\n PlanningFocusSelect,\n ROADMAP_DISPLAY,\n type PlanningFocus,\n} from '../roadmaps/planningFocus';\n\nconst CREATE_ROADMAP = gql`\n mutation CreateRoadmap($input: PlanmagnetCreateRoadmapInput!) {\n planmagnetCreateRoadmap(input: $input) {\n id\n name\n description\n type\n planningFocus\n isPublic\n ownerId\n createdAt\n }\n }\n`;\n\nexport function ProductsCreateProductPagePage() {\n const { workspaceId, currentUser } = usePlanMagnet();\n const navigate = usePlanMagnetNavigate();\n\n const [form, setForm] = useState({\n name: '',\n description: '',\n planningFocus: null as PlanningFocus | null,\n isPublic: false,\n });\n\n const [saveError, setSaveError] = useState<string | null>(null);\n const [createRoadmap, { loading: saving }] = useMutation(CREATE_ROADMAP, {\n refetchQueries: ['ListRoadmaps'],\n });\n\n // Navigate only after the service ACCEPTED it (see ProductsCreateRoadmapPage).\n const handleCreate = async () => {\n if (!form.name.trim()) return;\n setSaveError(null);\n try {\n await throwOnError(\n createRoadmap({\n variables: {\n input: {\n name: form.name,\n description: form.description || undefined,\n type: ROADMAP_DISPLAY,\n ...(form.planningFocus ? { planningFocus: form.planningFocus } : {}),\n isPublic: form.isPublic,\n ownerId: currentUser?.id ?? '',\n },\n },\n })\n );\n navigate('/products/products-page');\n } catch (e) {\n setSaveError(e instanceof Error ? e.message : 'The product could not be created.');\n }\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\">Create Product</h1>\n <p className=\"text-sm text-muted-foreground\">\n Define a new product with its vision and strategy.\n </p>\n </div>\n <div className=\"flex items-center gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={() => navigate('/products/products-page')}>\n <X className=\"mr-1 h-4 w-4\" />\n Cancel\n </Button>\n <Button size=\"sm\" onClick={handleCreate} disabled={saving || !form.name.trim()}>\n {saving ? (\n <Loader2 className=\"mr-1 h-4 w-4 animate-spin\" />\n ) : (\n <Save className=\"mr-1 h-4 w-4\" />\n )}\n Create Product\n </Button>\n </div>\n </div>\n\n {saveError && (\n <div role=\"alert\" className=\"p-3 rounded-md bg-destructive/10 text-destructive text-sm\">\n Failed to create product: {saveError}\n </div>\n )}\n\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n <div className=\"lg:col-span-2 space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle>Basic Information</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label className=\"text-sm font-medium\">Product Name</label>\n <Input\n placeholder=\"e.g. PlanMagnet Analytics\"\n value={form.name}\n onChange={(e) => setForm({ ...form, name: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Description</label>\n <textarea\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[80px]\"\n placeholder=\"Describe what this product does...\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n />\n </div>\n <PlanningFocusSelect\n value={form.planningFocus}\n onChange={(planningFocus) => setForm({ ...form, planningFocus })}\n />\n <div>\n <label className=\"text-sm font-medium\">Visibility</label>\n <div className=\"mt-1 flex gap-2\">\n {[false, true].map((pub) => (\n <button\n key={String(pub)}\n onClick={() => setForm({ ...form, isPublic: pub })}\n className={`rounded-md px-3 py-1.5 text-sm ${form.isPublic === pub ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'}`}\n >\n {pub ? 'Public' : 'Private'}\n </button>\n ))}\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n\n <div className=\"space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Eye className=\"h-4 w-4\" />\n Preview\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n <Package className=\"h-5 w-5 text-primary\" />\n <span className=\"font-medium\">{form.name || 'Product Name'}</span>\n </div>\n <p className=\"text-sm text-muted-foreground\">\n {form.description || 'No description yet'}\n </p>\n <Badge variant={form.isPublic ? 'default' : 'secondary'} className=\"capitalize\">\n {form.isPublic ? 'Public' : 'Private'}\n </Badge>\n <div className=\"pt-2 border-t\">\n <p className=\"text-xs font-medium text-muted-foreground\">PLANNING FOCUS</p>\n <div className=\"mt-1\">\n <PlanningFocusBadge focus={form.planningFocus} />\n </div>\n </div>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Quick Tips</CardTitle>\n </CardHeader>\n <CardContent className=\"text-sm text-muted-foreground space-y-2\">\n <p>A strong product vision guides all feature decisions.</p>\n <p>Keep the strategy focused on 2-3 key differentiators.</p>\n <p>\n Products start in "planning" and move to "active" when launched.\n </p>\n </CardContent>\n </Card>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ProductsCreateProductPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProductsCreateProductPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation } from '@apollo/client/react';\nimport {\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Button,\n Input,\n Badge,\n} from '@burdenoff/fe-libs/ui';\nimport { Save, X, Package, Eye, Loader2 } from 'lucide-react';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { detailPath } from '../utils/rowNavigation';\nimport { throwOnError } from '../utils/mutationResult';\nimport { enumLabel } from '../controls/WorkItemControls';\n\n/**\n * Create a Product (BOFF-8045). A Product is a real strategy entity — name, vision,\n * lifecycle stage, owner and an optional North Star metric — distinct from a Roadmap.\n * It links roadmaps/releases/feature requests/OKRs after creation, from the product\n * detail page's Links panel; nothing is attached at creation time.\n */\n\nconst PRODUCT_LIFECYCLE_STAGES = [\n 'CONCEPT',\n 'DEVELOPMENT',\n 'BETA',\n 'LAUNCHED',\n 'MATURE',\n 'DEPRECATED',\n] as const;\ntype ProductLifecycleStage = (typeof PRODUCT_LIFECYCLE_STAGES)[number];\n\nconst CREATE_PRODUCT = gql`\n mutation CreateProduct($input: PlanmagnetCreateProductInput!) {\n planmagnetCreateProduct(input: $input) {\n id\n name\n description\n vision\n lifecycleStage\n ownerId\n createdAt\n }\n }\n`;\n\ninterface NorthStarForm {\n name: string;\n unit: string;\n target: string;\n current: string;\n window: string;\n}\n\nconst EMPTY_NORTH_STAR: NorthStarForm = { name: '', unit: '', target: '', current: '', window: '' };\n\nexport function ProductsCreateProductPagePage() {\n const { currentUser } = usePlanMagnet();\n const navigate = usePlanMagnetNavigate();\n\n const [form, setForm] = useState({\n name: '',\n description: '',\n vision: '',\n lifecycleStage: 'CONCEPT' as ProductLifecycleStage,\n });\n const [northStar, setNorthStar] = useState<NorthStarForm>(EMPTY_NORTH_STAR);\n\n const [saveError, setSaveError] = useState<string | null>(null);\n const [createProduct, { loading: saving }] = useMutation<{\n planmagnetCreateProduct: { id: string };\n }>(CREATE_PRODUCT, {\n refetchQueries: ['GetProducts'],\n });\n\n const northStarStarted = Object.values(northStar).some((v) => v.trim() !== '');\n const northStarComplete =\n northStar.name.trim() &&\n northStar.unit.trim() &&\n northStar.window.trim() &&\n northStar.target.trim() !== '' &&\n !Number.isNaN(Number(northStar.target)) &&\n northStar.current.trim() !== '' &&\n !Number.isNaN(Number(northStar.current));\n\n const canSave =\n form.name.trim() && form.vision.trim() && (!northStarStarted || northStarComplete);\n\n // Navigate only after the service ACCEPTED it, straight to the new product (not the list).\n const handleCreate = async () => {\n if (!canSave) return;\n setSaveError(null);\n try {\n const result = await throwOnError(\n createProduct({\n variables: {\n input: {\n name: form.name,\n description: form.description || undefined,\n vision: form.vision,\n lifecycleStage: form.lifecycleStage,\n ownerId: currentUser?.id ?? '',\n ...(northStarComplete\n ? {\n northStar: {\n name: northStar.name,\n unit: northStar.unit,\n target: Number(northStar.target),\n current: Number(northStar.current),\n window: northStar.window,\n },\n }\n : {}),\n },\n },\n })\n );\n const newId = result.data?.planmagnetCreateProduct?.id;\n navigate(\n newId ? detailPath('/products/product-detail-page', newId) : '/products/products-page'\n );\n } catch (e) {\n setSaveError(e instanceof Error ? e.message : 'The product could not be created.');\n }\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\">Create Product</h1>\n <p className=\"text-sm text-muted-foreground\">\n Define a new product with its vision and strategy.\n </p>\n </div>\n <div className=\"flex items-center gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={() => navigate('/products/products-page')}>\n <X className=\"mr-1 h-4 w-4\" />\n Cancel\n </Button>\n <Button size=\"sm\" onClick={() => void handleCreate()} disabled={saving || !canSave}>\n {saving ? (\n <Loader2 className=\"mr-1 h-4 w-4 animate-spin\" />\n ) : (\n <Save className=\"mr-1 h-4 w-4\" />\n )}\n Create Product\n </Button>\n </div>\n </div>\n\n {saveError && (\n <div role=\"alert\" className=\"p-3 rounded-md bg-destructive/10 text-destructive text-sm\">\n Failed to create product: {saveError}\n </div>\n )}\n\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n <div className=\"lg:col-span-2 space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle>Basic Information</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label className=\"text-sm font-medium\">Product Name</label>\n <Input\n placeholder=\"e.g. PlanMagnet Analytics\"\n value={form.name}\n onChange={(e) => setForm({ ...form, name: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Description</label>\n <textarea\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[60px]\"\n placeholder=\"Describe what this product does...\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Vision</label>\n <textarea\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[80px]\"\n placeholder=\"Where this product is headed and why it matters...\"\n value={form.vision}\n onChange={(e) => setForm({ ...form, vision: e.target.value })}\n data-testid=\"product-vision\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Lifecycle Stage</label>\n <select\n aria-label=\"Lifecycle stage\"\n data-testid=\"product-lifecycle-stage\"\n className=\"mt-1 w-full rounded-md border border-input bg-background px-2 py-1.5 text-sm\"\n value={form.lifecycleStage}\n onChange={(e) =>\n setForm({ ...form, lifecycleStage: e.target.value as ProductLifecycleStage })\n }\n >\n {PRODUCT_LIFECYCLE_STAGES.map((stage) => (\n <option key={stage} value={stage}>\n {enumLabel(stage)}\n </option>\n ))}\n </select>\n </div>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>North Star metric (optional)</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <p className=\"text-xs text-muted-foreground\">\n Leave every field blank to skip — it can be added later from the product's edit\n page.\n </p>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"text-sm font-medium\">Metric name</label>\n <Input\n placeholder=\"e.g. Weekly active users\"\n value={northStar.name}\n onChange={(e) => setNorthStar({ ...northStar, name: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Unit</label>\n <Input\n placeholder=\"e.g. users\"\n value={northStar.unit}\n onChange={(e) => setNorthStar({ ...northStar, unit: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Target</label>\n <Input\n type=\"number\"\n value={northStar.target}\n onChange={(e) => setNorthStar({ ...northStar, target: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Current</label>\n <Input\n type=\"number\"\n value={northStar.current}\n onChange={(e) => setNorthStar({ ...northStar, current: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n <div className=\"col-span-2\">\n <label className=\"text-sm font-medium\">Window</label>\n <Input\n placeholder=\"e.g. Q1 2027, weekly, ongoing\"\n value={northStar.window}\n onChange={(e) => setNorthStar({ ...northStar, window: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n </div>\n {northStarStarted && !northStarComplete && (\n <p className=\"text-xs text-destructive\">\n Fill in every North Star field (or clear them all) — name, unit, target, current\n and window are all required together.\n </p>\n )}\n </CardContent>\n </Card>\n </div>\n\n <div className=\"space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Eye className=\"h-4 w-4\" />\n Preview\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n <Package className=\"h-5 w-5 text-primary\" />\n <span className=\"font-medium\">{form.name || 'Product Name'}</span>\n </div>\n <p className=\"text-sm text-muted-foreground\">{form.vision || 'No vision set yet'}</p>\n <Badge variant=\"secondary\" className=\"capitalize\">\n {enumLabel(form.lifecycleStage)}\n </Badge>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Quick Tips</CardTitle>\n </CardHeader>\n <CardContent className=\"text-sm text-muted-foreground space-y-2\">\n <p>A strong product vision guides all feature decisions.</p>\n <p>\n Link roadmaps, releases, feature requests and OKRs from the product's own page\n once it is created.\n </p>\n <p>\n Products start in "Concept" and move through their lifecycle over time.\n </p>\n </CardContent>\n </Card>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProductsEditProductPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProductsEditProductPagePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ProductsEditProductPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProductsEditProductPagePage.tsx"],"names":[],"mappings":"AAmHA,wBAAgB,2BAA2B,4CAqT1C"}
|