@burdenoff/microfe-planmagnet 2026.930.23 → 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.
- package/dist/index.js +6 -5
- package/dist/planmagnet/PlanMagnetRoot.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoot.js +154 -147
- package/dist/planmagnet/PlanMagnetRoot.js.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.js +66 -62
- package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
- package/dist/planmagnet/controls/FeatureControls.d.ts +11 -0
- package/dist/planmagnet/controls/FeatureControls.d.ts.map +1 -1
- package/dist/planmagnet/controls/FeatureControls.js +305 -135
- package/dist/planmagnet/controls/FeatureControls.js.map +1 -1
- package/dist/planmagnet/controls/Pickers.d.ts +18 -0
- package/dist/planmagnet/controls/Pickers.d.ts.map +1 -1
- package/dist/planmagnet/controls/Pickers.js +78 -1
- package/dist/planmagnet/controls/Pickers.js.map +1 -1
- package/dist/planmagnet/controls/PrioritizationControls.d.ts +72 -0
- package/dist/planmagnet/controls/PrioritizationControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/PrioritizationControls.js +246 -0
- package/dist/planmagnet/controls/PrioritizationControls.js.map +1 -0
- package/dist/planmagnet/index.d.ts +1 -0
- package/dist/planmagnet/index.d.ts.map +1 -1
- package/dist/planmagnet/index.js +1 -0
- package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js +131 -125
- package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsFeaturesPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsFeaturesPagePage.js +183 -99
- package/dist/planmagnet/pages/ProductsFeaturesPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsNewFeaturePagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js +113 -97
- package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsPrioritizationPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProductsPrioritizationPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProductsPrioritizationPagePage.js +363 -0
- package/dist/planmagnet/pages/ProductsPrioritizationPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.js +96 -79
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js +133 -123
- package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js.map +1 -1
- package/dist/planmagnet/product/ProductControls.d.ts +33 -0
- package/dist/planmagnet/product/ProductControls.d.ts.map +1 -1
- package/dist/planmagnet/product/ProductControls.js +593 -268
- package/dist/planmagnet/product/ProductControls.js.map +1 -1
- package/dist/planmagnet/product/routes.d.ts +10 -0
- package/dist/planmagnet/product/routes.d.ts.map +1 -0
- package/dist/planmagnet/product/routes.js +6 -0
- package/dist/planmagnet/product/routes.js.map +1 -0
- package/dist/planmagnet/roadmaps/RoadmapControls.d.ts +10 -0
- package/dist/planmagnet/roadmaps/RoadmapControls.d.ts.map +1 -1
- package/dist/planmagnet/roadmaps/RoadmapControls.js +235 -184
- package/dist/planmagnet/roadmaps/RoadmapControls.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { ErrorLine as e } from "./ConfirmButton.js";
|
|
2
|
+
import { parseIntField as t } from "../utils/formValidation.js";
|
|
3
|
+
import { jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
4
|
+
import { Badge as i, Input as a } from "@burdenoff/fe-libs/ui";
|
|
5
|
+
//#region src/planmagnet/controls/PrioritizationControls.tsx
|
|
6
|
+
var o = [
|
|
7
|
+
"MUST",
|
|
8
|
+
"SHOULD",
|
|
9
|
+
"COULD",
|
|
10
|
+
"WONT"
|
|
11
|
+
], s = [
|
|
12
|
+
"BASIC",
|
|
13
|
+
"PERFORMANCE",
|
|
14
|
+
"DELIGHTER",
|
|
15
|
+
"INDIFFERENT",
|
|
16
|
+
"REVERSE"
|
|
17
|
+
], c = [
|
|
18
|
+
"QUICK_WIN",
|
|
19
|
+
"MAJOR_PROJECT",
|
|
20
|
+
"FILL_IN",
|
|
21
|
+
"TIME_SINK"
|
|
22
|
+
], l = {
|
|
23
|
+
MUST: {
|
|
24
|
+
label: "Must",
|
|
25
|
+
hint: "Non-negotiable — the release does not ship without it.",
|
|
26
|
+
variant: "default"
|
|
27
|
+
},
|
|
28
|
+
SHOULD: {
|
|
29
|
+
label: "Should",
|
|
30
|
+
hint: "Important, but the release can still ship without it.",
|
|
31
|
+
variant: "info"
|
|
32
|
+
},
|
|
33
|
+
COULD: {
|
|
34
|
+
label: "Could",
|
|
35
|
+
hint: "Nice to have if there is time.",
|
|
36
|
+
variant: "secondary"
|
|
37
|
+
},
|
|
38
|
+
WONT: {
|
|
39
|
+
label: "Won't",
|
|
40
|
+
hint: "Explicitly out of scope this time around.",
|
|
41
|
+
variant: "outline"
|
|
42
|
+
}
|
|
43
|
+
}, u = {
|
|
44
|
+
BASIC: {
|
|
45
|
+
label: "Basic",
|
|
46
|
+
hint: "Expected — its absence causes dissatisfaction, its presence goes unnoticed.",
|
|
47
|
+
variant: "secondary"
|
|
48
|
+
},
|
|
49
|
+
PERFORMANCE: {
|
|
50
|
+
label: "Performance",
|
|
51
|
+
hint: "Satisfaction scales with how well it is delivered.",
|
|
52
|
+
variant: "info"
|
|
53
|
+
},
|
|
54
|
+
DELIGHTER: {
|
|
55
|
+
label: "Delighter",
|
|
56
|
+
hint: "Unexpected — its absence is not missed, its presence delights.",
|
|
57
|
+
variant: "success"
|
|
58
|
+
},
|
|
59
|
+
INDIFFERENT: {
|
|
60
|
+
label: "Indifferent",
|
|
61
|
+
hint: "Users do not care either way.",
|
|
62
|
+
variant: "outline"
|
|
63
|
+
},
|
|
64
|
+
REVERSE: {
|
|
65
|
+
label: "Reverse",
|
|
66
|
+
hint: "Some users prefer this NOT be there.",
|
|
67
|
+
variant: "destructive"
|
|
68
|
+
}
|
|
69
|
+
}, d = {
|
|
70
|
+
QUICK_WIN: {
|
|
71
|
+
label: "Quick win",
|
|
72
|
+
hint: "High value, low effort (value ≥ 6, effort ≤ 5) — do these first.",
|
|
73
|
+
variant: "success"
|
|
74
|
+
},
|
|
75
|
+
MAJOR_PROJECT: {
|
|
76
|
+
label: "Major project",
|
|
77
|
+
hint: "High value, high effort (value ≥ 6, effort ≥ 6) — plan and staff deliberately.",
|
|
78
|
+
variant: "info"
|
|
79
|
+
},
|
|
80
|
+
FILL_IN: {
|
|
81
|
+
label: "Fill-in",
|
|
82
|
+
hint: "Low value, low effort (value ≤ 5, effort ≤ 5) — fine as filler work.",
|
|
83
|
+
variant: "secondary"
|
|
84
|
+
},
|
|
85
|
+
TIME_SINK: {
|
|
86
|
+
label: "Time sink",
|
|
87
|
+
hint: "Low value, high effort (value ≤ 5, effort ≥ 6) — avoid or deprioritize.",
|
|
88
|
+
variant: "destructive"
|
|
89
|
+
}
|
|
90
|
+
}, f = (e) => e && e in l ? l[e].label : "Not set", p = (e) => e && e in u ? u[e].label : "Not set";
|
|
91
|
+
function m({ quadrant: e, hideWhenUnscored: t = !1, className: r }) {
|
|
92
|
+
if (!e) return t ? null : /* @__PURE__ */ n(i, {
|
|
93
|
+
variant: "outline",
|
|
94
|
+
className: r,
|
|
95
|
+
"data-testid": "prio-quadrant-badge",
|
|
96
|
+
children: "Unscored"
|
|
97
|
+
});
|
|
98
|
+
let a = e in d ? d[e] : null;
|
|
99
|
+
return /* @__PURE__ */ n(i, {
|
|
100
|
+
variant: a?.variant ?? "outline",
|
|
101
|
+
className: r,
|
|
102
|
+
"data-testid": "prio-quadrant-badge",
|
|
103
|
+
children: a?.label ?? e
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
var h = {
|
|
107
|
+
moscow: "",
|
|
108
|
+
kano: "",
|
|
109
|
+
valueScore: "",
|
|
110
|
+
effortScore: ""
|
|
111
|
+
}, g = "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm disabled:opacity-60";
|
|
112
|
+
function _({ idPrefix: i, values: c, onChange: d, disabled: f = !1 }) {
|
|
113
|
+
let p = t(c.valueScore, {
|
|
114
|
+
min: 1,
|
|
115
|
+
max: 10
|
|
116
|
+
}), m = t(c.effortScore, {
|
|
117
|
+
min: 1,
|
|
118
|
+
max: 10
|
|
119
|
+
});
|
|
120
|
+
return /* @__PURE__ */ r("div", {
|
|
121
|
+
className: "space-y-3",
|
|
122
|
+
"data-testid": "prio-fields",
|
|
123
|
+
children: [/* @__PURE__ */ r("div", {
|
|
124
|
+
className: "grid grid-cols-2 gap-3",
|
|
125
|
+
children: [/* @__PURE__ */ r("div", { children: [
|
|
126
|
+
/* @__PURE__ */ n("label", {
|
|
127
|
+
htmlFor: `${i}-moscow`,
|
|
128
|
+
className: "text-sm font-medium",
|
|
129
|
+
children: "MoSCoW"
|
|
130
|
+
}),
|
|
131
|
+
/* @__PURE__ */ r("select", {
|
|
132
|
+
id: `${i}-moscow`,
|
|
133
|
+
"data-testid": "prio-field-moscow",
|
|
134
|
+
className: g,
|
|
135
|
+
value: c.moscow,
|
|
136
|
+
disabled: f,
|
|
137
|
+
onChange: (e) => d({
|
|
138
|
+
...c,
|
|
139
|
+
moscow: e.target.value
|
|
140
|
+
}),
|
|
141
|
+
children: [/* @__PURE__ */ n("option", {
|
|
142
|
+
value: "",
|
|
143
|
+
children: "Not set"
|
|
144
|
+
}), o.map((e) => /* @__PURE__ */ n("option", {
|
|
145
|
+
value: e,
|
|
146
|
+
children: l[e].label
|
|
147
|
+
}, e))]
|
|
148
|
+
}),
|
|
149
|
+
/* @__PURE__ */ n("p", {
|
|
150
|
+
className: "mt-1 text-xs text-muted-foreground",
|
|
151
|
+
children: c.moscow && c.moscow in l ? l[c.moscow].hint : "Must/Should/Could/Won't for this release."
|
|
152
|
+
})
|
|
153
|
+
] }), /* @__PURE__ */ r("div", { children: [
|
|
154
|
+
/* @__PURE__ */ n("label", {
|
|
155
|
+
htmlFor: `${i}-kano`,
|
|
156
|
+
className: "text-sm font-medium",
|
|
157
|
+
children: "Kano"
|
|
158
|
+
}),
|
|
159
|
+
/* @__PURE__ */ r("select", {
|
|
160
|
+
id: `${i}-kano`,
|
|
161
|
+
"data-testid": "prio-field-kano",
|
|
162
|
+
className: g,
|
|
163
|
+
value: c.kano,
|
|
164
|
+
disabled: f,
|
|
165
|
+
onChange: (e) => d({
|
|
166
|
+
...c,
|
|
167
|
+
kano: e.target.value
|
|
168
|
+
}),
|
|
169
|
+
children: [/* @__PURE__ */ n("option", {
|
|
170
|
+
value: "",
|
|
171
|
+
children: "Not set"
|
|
172
|
+
}), s.map((e) => /* @__PURE__ */ n("option", {
|
|
173
|
+
value: e,
|
|
174
|
+
children: u[e].label
|
|
175
|
+
}, e))]
|
|
176
|
+
}),
|
|
177
|
+
/* @__PURE__ */ n("p", {
|
|
178
|
+
className: "mt-1 text-xs text-muted-foreground",
|
|
179
|
+
children: c.kano && c.kano in u ? u[c.kano].hint : "How this shapes customer satisfaction."
|
|
180
|
+
})
|
|
181
|
+
] })]
|
|
182
|
+
}), /* @__PURE__ */ r("div", {
|
|
183
|
+
className: "grid grid-cols-2 gap-3",
|
|
184
|
+
children: [/* @__PURE__ */ r("div", { children: [
|
|
185
|
+
/* @__PURE__ */ n("label", {
|
|
186
|
+
htmlFor: `${i}-value-score`,
|
|
187
|
+
className: "text-sm font-medium",
|
|
188
|
+
children: "Value score (1-10)"
|
|
189
|
+
}),
|
|
190
|
+
/* @__PURE__ */ n(a, {
|
|
191
|
+
id: `${i}-value-score`,
|
|
192
|
+
"data-testid": "prio-field-value-score",
|
|
193
|
+
type: "number",
|
|
194
|
+
min: 1,
|
|
195
|
+
max: 10,
|
|
196
|
+
className: "mt-1",
|
|
197
|
+
placeholder: "Not set",
|
|
198
|
+
value: c.valueScore,
|
|
199
|
+
"aria-invalid": p.invalid,
|
|
200
|
+
disabled: f,
|
|
201
|
+
onChange: (e) => d({
|
|
202
|
+
...c,
|
|
203
|
+
valueScore: e.target.value
|
|
204
|
+
})
|
|
205
|
+
}),
|
|
206
|
+
p.invalid && /* @__PURE__ */ n(e, { message: "Value score is a whole number from 1 to 10." })
|
|
207
|
+
] }), /* @__PURE__ */ r("div", { children: [
|
|
208
|
+
/* @__PURE__ */ n("label", {
|
|
209
|
+
htmlFor: `${i}-effort-score`,
|
|
210
|
+
className: "text-sm font-medium",
|
|
211
|
+
children: "Effort score (1-10)"
|
|
212
|
+
}),
|
|
213
|
+
/* @__PURE__ */ n(a, {
|
|
214
|
+
id: `${i}-effort-score`,
|
|
215
|
+
"data-testid": "prio-field-effort-score",
|
|
216
|
+
type: "number",
|
|
217
|
+
min: 1,
|
|
218
|
+
max: 10,
|
|
219
|
+
className: "mt-1",
|
|
220
|
+
placeholder: "Not set",
|
|
221
|
+
value: c.effortScore,
|
|
222
|
+
"aria-invalid": m.invalid,
|
|
223
|
+
disabled: f,
|
|
224
|
+
onChange: (e) => d({
|
|
225
|
+
...c,
|
|
226
|
+
effortScore: e.target.value
|
|
227
|
+
})
|
|
228
|
+
}),
|
|
229
|
+
m.invalid && /* @__PURE__ */ n(e, { message: "Effort score is a whole number from 1 to 10." })
|
|
230
|
+
] })]
|
|
231
|
+
})]
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
function v(e) {
|
|
235
|
+
return !t(e.valueScore, {
|
|
236
|
+
min: 1,
|
|
237
|
+
max: 10
|
|
238
|
+
}).invalid && !t(e.effortScore, {
|
|
239
|
+
min: 1,
|
|
240
|
+
max: 10
|
|
241
|
+
}).invalid;
|
|
242
|
+
}
|
|
243
|
+
//#endregion
|
|
244
|
+
export { h as EMPTY_PRIORITIZATION_FORM, u as KANO_META, s as KANO_VALUES, l as MOSCOW_META, o as MOSCOW_VALUES, _ as PrioritizationScoreFields, d as QUADRANT_META, c as QUADRANT_VALUES, m as QuadrantBadge, p as kanoLabel, f as moscowLabel, v as prioritizationScoresValid };
|
|
245
|
+
|
|
246
|
+
//# sourceMappingURL=PrioritizationControls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PrioritizationControls.js","names":[],"sources":["../../../src/planmagnet/controls/PrioritizationControls.tsx"],"sourcesContent":["import { Badge, Input } from '@burdenoff/fe-libs/ui';\nimport { parseIntField } from '../utils/formValidation';\nimport { ErrorLine } from './ConfirmButton';\n\n/**\n * Prioritization (PRM-27): MoSCoW, Kano and Value-vs-Effort scoring shared by the feature request create/edit\n * form, the feature detail page, and the roadmap initiative (RoadmapItem) edit dialog — one presentational form\n * fragment plus the badge that shows the server-computed Value-vs-Effort quadrant, so the three surfaces (and the\n * prioritization page's own item cards) render it identically instead of three near-copies drifting apart.\n *\n * The quadrant itself is never computed client-side — `FeatureRequest.valueEffortQuadrant` /\n * `RoadmapItem.valueEffortQuadrant` are server-derived (and not stored), so `QuadrantBadge` only ever renders a\n * value that came back from a query or a mutation response.\n */\n\nexport const MOSCOW_VALUES = ['MUST', 'SHOULD', 'COULD', 'WONT'] as const;\nexport type MoscowValue = (typeof MOSCOW_VALUES)[number];\n\nexport const KANO_VALUES = ['BASIC', 'PERFORMANCE', 'DELIGHTER', 'INDIFFERENT', 'REVERSE'] as const;\nexport type KanoValue = (typeof KANO_VALUES)[number];\n\nexport const QUADRANT_VALUES = ['QUICK_WIN', 'MAJOR_PROJECT', 'FILL_IN', 'TIME_SINK'] as const;\nexport type QuadrantValue = (typeof QUADRANT_VALUES)[number];\n\ntype BadgeVariant =\n | 'default'\n | 'success'\n | 'warning'\n | 'info'\n | 'secondary'\n | 'destructive'\n | 'outline';\n\nexport const MOSCOW_META: Record<\n MoscowValue,\n { label: string; hint: string; variant: BadgeVariant }\n> = {\n MUST: {\n label: 'Must',\n hint: 'Non-negotiable — the release does not ship without it.',\n variant: 'default',\n },\n SHOULD: {\n label: 'Should',\n hint: 'Important, but the release can still ship without it.',\n variant: 'info',\n },\n COULD: { label: 'Could', hint: 'Nice to have if there is time.', variant: 'secondary' },\n WONT: { label: \"Won't\", hint: 'Explicitly out of scope this time around.', variant: 'outline' },\n};\n\nexport const KANO_META: Record<KanoValue, { label: string; hint: string; variant: BadgeVariant }> =\n {\n BASIC: {\n label: 'Basic',\n hint: 'Expected — its absence causes dissatisfaction, its presence goes unnoticed.',\n variant: 'secondary',\n },\n PERFORMANCE: {\n label: 'Performance',\n hint: 'Satisfaction scales with how well it is delivered.',\n variant: 'info',\n },\n DELIGHTER: {\n label: 'Delighter',\n hint: 'Unexpected — its absence is not missed, its presence delights.',\n variant: 'success',\n },\n INDIFFERENT: {\n label: 'Indifferent',\n hint: 'Users do not care either way.',\n variant: 'outline',\n },\n REVERSE: {\n label: 'Reverse',\n hint: 'Some users prefer this NOT be there.',\n variant: 'destructive',\n },\n };\n\nexport const QUADRANT_META: Record<\n QuadrantValue,\n { label: string; hint: string; variant: BadgeVariant }\n> = {\n QUICK_WIN: {\n label: 'Quick win',\n hint: 'High value, low effort (value ≥ 6, effort ≤ 5) — do these first.',\n variant: 'success',\n },\n MAJOR_PROJECT: {\n label: 'Major project',\n hint: 'High value, high effort (value ≥ 6, effort ≥ 6) — plan and staff deliberately.',\n variant: 'info',\n },\n FILL_IN: {\n label: 'Fill-in',\n hint: 'Low value, low effort (value ≤ 5, effort ≤ 5) — fine as filler work.',\n variant: 'secondary',\n },\n TIME_SINK: {\n label: 'Time sink',\n hint: 'Low value, high effort (value ≤ 5, effort ≥ 6) — avoid or deprioritize.',\n variant: 'destructive',\n },\n};\n\nexport const moscowLabel = (value: string | null | undefined): string =>\n value && value in MOSCOW_META ? MOSCOW_META[value as MoscowValue].label : 'Not set';\nexport const kanoLabel = (value: string | null | undefined): string =>\n value && value in KANO_META ? KANO_META[value as KanoValue].label : 'Not set';\nexport const quadrantLabel = (value: string | null | undefined): string =>\n value && value in QUADRANT_META ? QUADRANT_META[value as QuadrantValue].label : 'Unscored';\n\n/**\n * The Value-vs-Effort quadrant, read back from the server (`FeatureRequest.valueEffortQuadrant` /\n * `RoadmapItem.valueEffortQuadrant` / a `PlanmagnetPrioritizationBucket.bucket`) — never computed here. Renders\n * an \"Unscored\" badge when null (one or both of valueScore/effortScore is not set yet) unless `hideWhenUnscored`.\n */\nexport function QuadrantBadge({\n quadrant,\n hideWhenUnscored = false,\n className,\n}: {\n quadrant: string | null | undefined;\n hideWhenUnscored?: boolean;\n className?: string;\n}) {\n if (!quadrant) {\n if (hideWhenUnscored) return null;\n return (\n <Badge variant=\"outline\" className={className} data-testid=\"prio-quadrant-badge\">\n Unscored\n </Badge>\n );\n }\n const meta = quadrant in QUADRANT_META ? QUADRANT_META[quadrant as QuadrantValue] : null;\n return (\n <Badge\n variant={meta?.variant ?? 'outline'}\n className={className}\n data-testid=\"prio-quadrant-badge\"\n >\n {meta?.label ?? quadrant}\n </Badge>\n );\n}\n\nexport interface PrioritizationFormValues {\n /** '' = not set */\n moscow: string;\n /** '' = not set */\n kano: string;\n /** '' = not set, else a whole number 1-10 as text */\n valueScore: string;\n /** '' = not set, else a whole number 1-10 as text */\n effortScore: string;\n}\n\nexport const EMPTY_PRIORITIZATION_FORM: PrioritizationFormValues = {\n moscow: '',\n kano: '',\n valueScore: '',\n effortScore: '',\n};\n\nconst selectClass =\n 'mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm disabled:opacity-60';\n\n/**\n * The four prioritization inputs (PRM-27): MoSCoW and Kano selects (each with a short explanation of the\n * selected value), and 1-10 value/effort number inputs. Fully controlled; clearing a select or number input back\n * to empty is how a caller sends `null` (cleared) rather than omitting the field. Shared by the feature request\n * create/edit form, the feature detail page, and the roadmap initiative edit dialog.\n */\nexport function PrioritizationScoreFields({\n idPrefix,\n values,\n onChange,\n disabled = false,\n}: {\n idPrefix: string;\n values: PrioritizationFormValues;\n onChange: (next: PrioritizationFormValues) => void;\n disabled?: boolean;\n}) {\n const value = parseIntField(values.valueScore, { min: 1, max: 10 });\n const effort = parseIntField(values.effortScore, { min: 1, max: 10 });\n\n return (\n <div className=\"space-y-3\" data-testid=\"prio-fields\">\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <label htmlFor={`${idPrefix}-moscow`} className=\"text-sm font-medium\">\n MoSCoW\n </label>\n <select\n id={`${idPrefix}-moscow`}\n data-testid=\"prio-field-moscow\"\n className={selectClass}\n value={values.moscow}\n disabled={disabled}\n onChange={(e) => onChange({ ...values, moscow: e.target.value })}\n >\n <option value=\"\">Not set</option>\n {MOSCOW_VALUES.map((v) => (\n <option key={v} value={v}>\n {MOSCOW_META[v].label}\n </option>\n ))}\n </select>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {values.moscow && values.moscow in MOSCOW_META\n ? MOSCOW_META[values.moscow as MoscowValue].hint\n : \"Must/Should/Could/Won't for this release.\"}\n </p>\n </div>\n <div>\n <label htmlFor={`${idPrefix}-kano`} className=\"text-sm font-medium\">\n Kano\n </label>\n <select\n id={`${idPrefix}-kano`}\n data-testid=\"prio-field-kano\"\n className={selectClass}\n value={values.kano}\n disabled={disabled}\n onChange={(e) => onChange({ ...values, kano: e.target.value })}\n >\n <option value=\"\">Not set</option>\n {KANO_VALUES.map((v) => (\n <option key={v} value={v}>\n {KANO_META[v].label}\n </option>\n ))}\n </select>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {values.kano && values.kano in KANO_META\n ? KANO_META[values.kano as KanoValue].hint\n : 'How this shapes customer satisfaction.'}\n </p>\n </div>\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <label htmlFor={`${idPrefix}-value-score`} className=\"text-sm font-medium\">\n Value score (1-10)\n </label>\n <Input\n id={`${idPrefix}-value-score`}\n data-testid=\"prio-field-value-score\"\n type=\"number\"\n min={1}\n max={10}\n className=\"mt-1\"\n placeholder=\"Not set\"\n value={values.valueScore}\n aria-invalid={value.invalid}\n disabled={disabled}\n onChange={(e) => onChange({ ...values, valueScore: e.target.value })}\n />\n {value.invalid && <ErrorLine message=\"Value score is a whole number from 1 to 10.\" />}\n </div>\n <div>\n <label htmlFor={`${idPrefix}-effort-score`} className=\"text-sm font-medium\">\n Effort score (1-10)\n </label>\n <Input\n id={`${idPrefix}-effort-score`}\n data-testid=\"prio-field-effort-score\"\n type=\"number\"\n min={1}\n max={10}\n className=\"mt-1\"\n placeholder=\"Not set\"\n value={values.effortScore}\n aria-invalid={effort.invalid}\n disabled={disabled}\n onChange={(e) => onChange({ ...values, effortScore: e.target.value })}\n />\n {effort.invalid && <ErrorLine message=\"Effort score is a whole number from 1 to 10.\" />}\n </div>\n </div>\n </div>\n );\n}\n\n/** True when neither of the two score fields holds an out-of-range value (empty is always valid — it means \"clear\"). */\nexport function prioritizationScoresValid(values: PrioritizationFormValues): boolean {\n return (\n !parseIntField(values.valueScore, { min: 1, max: 10 }).invalid &&\n !parseIntField(values.effortScore, { min: 1, max: 10 }).invalid\n );\n}\n"],"mappings":"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"}
|
|
@@ -4,4 +4,5 @@ export type { PlanMagnetRootProps, NavItem, FooterItem } from './types';
|
|
|
4
4
|
export { usePlanMagnet, usePlanMagnetNavigate } from './providers/PlanMagnetProvider';
|
|
5
5
|
export { usePlanMagnetStore } from './store/planmagnetStore';
|
|
6
6
|
export { INTEGRATIONS_SYNCS_PATH, INTEGRATIONS_NEW_SYNC_PATH, INTEGRATIONS_SYNC_DETAIL_PATH, integrationsSyncDetailPath, } from './integrations/routes';
|
|
7
|
+
export { PRIORITIZATION_PATH } from './product/routes';
|
|
7
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/planmagnet/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,YAAY,EAAE,mBAAmB,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACtF,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAG7D,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,6BAA6B,EAC7B,0BAA0B,GAC3B,MAAM,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/planmagnet/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,YAAY,EAAE,mBAAmB,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACtF,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAG7D,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,6BAA6B,EAC7B,0BAA0B,GAC3B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/planmagnet/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProductsFeatureDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProductsFeatureDetailPagePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ProductsFeatureDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProductsFeatureDetailPagePage.tsx"],"names":[],"mappings":"AA6FA,wBAAgB,6BAA6B,4CA4Q5C"}
|