@burdenoff/microfe-planmagnet 2026.927.3 → 2026.927.5

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 (166) hide show
  1. package/dist/generated/global-types.d.ts +9 -1
  2. package/dist/generated/global-types.d.ts.map +1 -1
  3. package/dist/generated/wspace-operations.d.ts +0 -12
  4. package/dist/generated/wspace-operations.d.ts.map +1 -1
  5. package/dist/planmagnet/PlanMagnetRoutes.d.ts.map +1 -1
  6. package/dist/planmagnet/PlanMagnetRoutes.js +14 -10
  7. package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
  8. package/dist/planmagnet/admin/PlanMagnetAdminRoot.d.ts.map +1 -1
  9. package/dist/planmagnet/admin/PlanMagnetAdminRoot.js +149 -127
  10. package/dist/planmagnet/admin/PlanMagnetAdminRoot.js.map +1 -1
  11. package/dist/planmagnet/controls/FeatureControls.d.ts +26 -0
  12. package/dist/planmagnet/controls/FeatureControls.d.ts.map +1 -0
  13. package/dist/planmagnet/controls/FeatureControls.js +321 -0
  14. package/dist/planmagnet/controls/FeatureControls.js.map +1 -0
  15. package/dist/planmagnet/controls/FeatureTriage.d.ts +21 -0
  16. package/dist/planmagnet/controls/FeatureTriage.d.ts.map +1 -0
  17. package/dist/planmagnet/controls/FeatureTriage.js +398 -0
  18. package/dist/planmagnet/controls/FeatureTriage.js.map +1 -0
  19. package/dist/planmagnet/controls/MilestoneControls.d.ts +17 -0
  20. package/dist/planmagnet/controls/MilestoneControls.d.ts.map +1 -0
  21. package/dist/planmagnet/controls/MilestoneControls.js +203 -0
  22. package/dist/planmagnet/controls/MilestoneControls.js.map +1 -0
  23. package/dist/planmagnet/controls/ObjectiveControls.d.ts +31 -0
  24. package/dist/planmagnet/controls/ObjectiveControls.d.ts.map +1 -0
  25. package/dist/planmagnet/controls/ObjectiveControls.js +296 -0
  26. package/dist/planmagnet/controls/ObjectiveControls.js.map +1 -0
  27. package/dist/planmagnet/controls/Pickers.d.ts +26 -0
  28. package/dist/planmagnet/controls/Pickers.d.ts.map +1 -0
  29. package/dist/planmagnet/controls/Pickers.js +171 -0
  30. package/dist/planmagnet/controls/Pickers.js.map +1 -0
  31. package/dist/planmagnet/controls/ProjectControls.d.ts.map +1 -1
  32. package/dist/planmagnet/controls/ProjectControls.js +47 -44
  33. package/dist/planmagnet/controls/ProjectControls.js.map +1 -1
  34. package/dist/planmagnet/controls/ReleaseControls.d.ts +14 -0
  35. package/dist/planmagnet/controls/ReleaseControls.d.ts.map +1 -0
  36. package/dist/planmagnet/controls/ReleaseControls.js +111 -0
  37. package/dist/planmagnet/controls/ReleaseControls.js.map +1 -0
  38. package/dist/planmagnet/controls/WorkItemControls.d.ts.map +1 -1
  39. package/dist/planmagnet/controls/WorkItemControls.js +68 -65
  40. package/dist/planmagnet/controls/WorkItemControls.js.map +1 -1
  41. package/dist/planmagnet/hooks/useCounts.d.ts +39 -0
  42. package/dist/planmagnet/hooks/useCounts.d.ts.map +1 -0
  43. package/dist/planmagnet/hooks/useCounts.js +209 -0
  44. package/dist/planmagnet/hooks/useCounts.js.map +1 -0
  45. package/dist/planmagnet/import/exportColumns.d.ts +52 -0
  46. package/dist/planmagnet/import/exportColumns.d.ts.map +1 -0
  47. package/dist/planmagnet/import/exportColumns.js +81 -0
  48. package/dist/planmagnet/import/exportColumns.js.map +1 -0
  49. package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.d.ts.map +1 -1
  50. package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.js +255 -242
  51. package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
  52. package/dist/planmagnet/pages/DashboardDashboardPagePage.d.ts.map +1 -1
  53. package/dist/planmagnet/pages/DashboardDashboardPagePage.js +199 -160
  54. package/dist/planmagnet/pages/DashboardDashboardPagePage.js.map +1 -1
  55. package/dist/planmagnet/pages/DocsDocDetailPagePage.d.ts.map +1 -1
  56. package/dist/planmagnet/pages/DocsDocDetailPagePage.js +190 -153
  57. package/dist/planmagnet/pages/DocsDocDetailPagePage.js.map +1 -1
  58. package/dist/planmagnet/pages/GoalsCreateObjectivePagePage.d.ts.map +1 -1
  59. package/dist/planmagnet/pages/GoalsCreateObjectivePagePage.js +63 -56
  60. package/dist/planmagnet/pages/GoalsCreateObjectivePagePage.js.map +1 -1
  61. package/dist/planmagnet/pages/GoalsGoalsPagePage.d.ts.map +1 -1
  62. package/dist/planmagnet/pages/GoalsGoalsPagePage.js +2 -7
  63. package/dist/planmagnet/pages/GoalsGoalsPagePage.js.map +1 -1
  64. package/dist/planmagnet/pages/GoalsObjectiveDetailPagePage.d.ts.map +1 -1
  65. package/dist/planmagnet/pages/GoalsObjectiveDetailPagePage.js +229 -214
  66. package/dist/planmagnet/pages/GoalsObjectiveDetailPagePage.js.map +1 -1
  67. package/dist/planmagnet/pages/ProductsEditProductPagePage.d.ts.map +1 -1
  68. package/dist/planmagnet/pages/ProductsEditProductPagePage.js +145 -114
  69. package/dist/planmagnet/pages/ProductsEditProductPagePage.js.map +1 -1
  70. package/dist/planmagnet/pages/ProductsEditReleasePagePage.d.ts.map +1 -1
  71. package/dist/planmagnet/pages/ProductsEditReleasePagePage.js +134 -105
  72. package/dist/planmagnet/pages/ProductsEditReleasePagePage.js.map +1 -1
  73. package/dist/planmagnet/pages/ProductsFeatureAnalyticsPagePage.d.ts.map +1 -1
  74. package/dist/planmagnet/pages/ProductsFeatureAnalyticsPagePage.js +97 -117
  75. package/dist/planmagnet/pages/ProductsFeatureAnalyticsPagePage.js.map +1 -1
  76. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.d.ts.map +1 -1
  77. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js +169 -110
  78. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js.map +1 -1
  79. package/dist/planmagnet/pages/ProductsFeaturesPagePage.d.ts.map +1 -1
  80. package/dist/planmagnet/pages/ProductsFeaturesPagePage.js +117 -103
  81. package/dist/planmagnet/pages/ProductsFeaturesPagePage.js.map +1 -1
  82. package/dist/planmagnet/pages/ProductsNewFeaturePagePage.d.ts.map +1 -1
  83. package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js +119 -94
  84. package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js.map +1 -1
  85. package/dist/planmagnet/pages/ProductsProductDetailPagePage.d.ts.map +1 -1
  86. package/dist/planmagnet/pages/ProductsProductDetailPagePage.js +4 -8
  87. package/dist/planmagnet/pages/ProductsProductDetailPagePage.js.map +1 -1
  88. package/dist/planmagnet/pages/ProductsProductsPagePage.d.ts.map +1 -1
  89. package/dist/planmagnet/pages/ProductsProductsPagePage.js +85 -90
  90. package/dist/planmagnet/pages/ProductsProductsPagePage.js.map +1 -1
  91. package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.d.ts.map +1 -1
  92. package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.js +118 -107
  93. package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.js.map +1 -1
  94. package/dist/planmagnet/pages/ProductsReleasesPagePage.d.ts.map +1 -1
  95. package/dist/planmagnet/pages/ProductsReleasesPagePage.js +4 -2
  96. package/dist/planmagnet/pages/ProductsReleasesPagePage.js.map +1 -1
  97. package/dist/planmagnet/pages/ProductsRoadmapAnalyticsPagePage.d.ts.map +1 -1
  98. package/dist/planmagnet/pages/ProductsRoadmapAnalyticsPagePage.js +48 -71
  99. package/dist/planmagnet/pages/ProductsRoadmapAnalyticsPagePage.js.map +1 -1
  100. package/dist/planmagnet/pages/ProductsRoadmapsPagePage.d.ts.map +1 -1
  101. package/dist/planmagnet/pages/ProductsRoadmapsPagePage.js +17 -13
  102. package/dist/planmagnet/pages/ProductsRoadmapsPagePage.js.map +1 -1
  103. package/dist/planmagnet/pages/ProjectsActiveProjectsPagePage.d.ts.map +1 -1
  104. package/dist/planmagnet/pages/ProjectsActiveProjectsPagePage.js +1 -1
  105. package/dist/planmagnet/pages/ProjectsActiveProjectsPagePage.js.map +1 -1
  106. package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.d.ts.map +1 -1
  107. package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.js +55 -63
  108. package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.js.map +1 -1
  109. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.d.ts.map +1 -1
  110. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js +11 -8
  111. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js.map +1 -1
  112. package/dist/planmagnet/pages/ProjectsPlanningPagePage.d.ts.map +1 -1
  113. package/dist/planmagnet/pages/ProjectsPlanningPagePage.js +1 -1
  114. package/dist/planmagnet/pages/ProjectsPlanningPagePage.js.map +1 -1
  115. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.d.ts.map +1 -1
  116. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js +152 -139
  117. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js.map +1 -1
  118. package/dist/planmagnet/pages/ProjectsProjectsPagePage.d.ts.map +1 -1
  119. package/dist/planmagnet/pages/ProjectsProjectsPagePage.js +75 -74
  120. package/dist/planmagnet/pages/ProjectsProjectsPagePage.js.map +1 -1
  121. package/dist/planmagnet/pages/ReportsReportsPagePage.d.ts +7 -0
  122. package/dist/planmagnet/pages/ReportsReportsPagePage.d.ts.map +1 -1
  123. package/dist/planmagnet/pages/ReportsReportsPagePage.js +39 -201
  124. package/dist/planmagnet/pages/ReportsReportsPagePage.js.map +1 -1
  125. package/dist/planmagnet/pages/SprintsStartSprintPagePage.d.ts.map +1 -1
  126. package/dist/planmagnet/pages/SprintsStartSprintPagePage.js +118 -99
  127. package/dist/planmagnet/pages/SprintsStartSprintPagePage.js.map +1 -1
  128. package/dist/planmagnet/pages/TasksCreateTaskPagePage.js +123 -128
  129. package/dist/planmagnet/pages/TasksCreateTaskPagePage.js.map +1 -1
  130. package/dist/planmagnet/pages/TasksEditTaskPagePage.d.ts.map +1 -1
  131. package/dist/planmagnet/pages/TasksEditTaskPagePage.js +139 -107
  132. package/dist/planmagnet/pages/TasksEditTaskPagePage.js.map +1 -1
  133. package/dist/planmagnet/pages/TasksImportPagePage.d.ts +2 -0
  134. package/dist/planmagnet/pages/TasksImportPagePage.d.ts.map +1 -0
  135. package/dist/planmagnet/pages/TasksImportPagePage.js +309 -0
  136. package/dist/planmagnet/pages/TasksImportPagePage.js.map +1 -0
  137. package/dist/planmagnet/pages/TasksTaskDetailPagePage.d.ts.map +1 -1
  138. package/dist/planmagnet/pages/TasksTaskDetailPagePage.js +173 -126
  139. package/dist/planmagnet/pages/TasksTaskDetailPagePage.js.map +1 -1
  140. package/dist/planmagnet/pages/TasksTasksPagePage.d.ts.map +1 -1
  141. package/dist/planmagnet/pages/TasksTasksPagePage.js +111 -104
  142. package/dist/planmagnet/pages/TasksTasksPagePage.js.map +1 -1
  143. package/dist/planmagnet/pages/TeamTeamPagePage.d.ts.map +1 -1
  144. package/dist/planmagnet/pages/TeamTeamPagePage.js +99 -177
  145. package/dist/planmagnet/pages/TeamTeamPagePage.js.map +1 -1
  146. package/dist/planmagnet/pages/analytics/DeliveryHealthCards.d.ts.map +1 -1
  147. package/dist/planmagnet/pages/analytics/DeliveryHealthCards.js +8 -4
  148. package/dist/planmagnet/pages/analytics/DeliveryHealthCards.js.map +1 -1
  149. package/dist/planmagnet/releases/ReleaseWorkItemsCard.d.ts.map +1 -1
  150. package/dist/planmagnet/releases/ReleaseWorkItemsCard.js +10 -4
  151. package/dist/planmagnet/releases/ReleaseWorkItemsCard.js.map +1 -1
  152. package/dist/planmagnet/roadmaps/RoadmapControls.d.ts.map +1 -1
  153. package/dist/planmagnet/roadmaps/RoadmapControls.js +150 -137
  154. package/dist/planmagnet/roadmaps/RoadmapControls.js.map +1 -1
  155. package/dist/planmagnet/sprints/SprintControls.d.ts.map +1 -1
  156. package/dist/planmagnet/sprints/SprintControls.js +32 -30
  157. package/dist/planmagnet/sprints/SprintControls.js.map +1 -1
  158. package/dist/planmagnet/utils/mutationResult.d.ts +10 -0
  159. package/dist/planmagnet/utils/mutationResult.d.ts.map +1 -1
  160. package/dist/planmagnet/utils/mutationResult.js +2 -1
  161. package/dist/planmagnet/utils/mutationResult.js.map +1 -1
  162. package/dist/planmagnet/utils/rowNavigation.d.ts +2 -0
  163. package/dist/planmagnet/utils/rowNavigation.d.ts.map +1 -1
  164. package/dist/planmagnet/utils/rowNavigation.js +9 -8
  165. package/dist/planmagnet/utils/rowNavigation.js.map +1 -1
  166. package/package.json +1 -1
@@ -1,23 +1,15 @@
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 { parseIntField as r } from "../utils/formValidation.js";
4
- import { useState as i } from "react";
5
- import { Loader2 as a, Save as o, Star as s, X as c } from "lucide-react";
6
- import { gql as l } from "@apollo/client";
7
- import { useMutation as u, useQuery as d } from "@apollo/client/react";
8
- import { jsx as f, jsxs as p } from "react/jsx-runtime";
9
- import { Button as m, Card as h, CardContent as g, CardHeader as _, CardTitle as v, Input as y } from "@burdenoff/fe-libs/ui";
3
+ import { ProjectSelect as r, WorkItemSearchSelect as i } from "../controls/Pickers.js";
4
+ import { parseIntField as a } from "../utils/formValidation.js";
5
+ import { useState as o } from "react";
6
+ import { Loader2 as s, Save as c, Star 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 { Button as h, Card as g, CardContent as _, CardHeader as v, CardTitle as y, Input as b } from "@burdenoff/fe-libs/ui";
10
11
  //#region src/planmagnet/pages/ProductsNewFeaturePagePage.tsx
11
- var b = l`
12
- query ListRoadmapsForFeatureSelect($workspaceId: ID!, $pagination: PlanmagnetPaginationInput) {
13
- planmagnetRoadmaps(workspaceId: $workspaceId, pagination: $pagination) {
14
- items {
15
- id
16
- name
17
- }
18
- }
19
- }
20
- `, x = l`
12
+ var x = d`
21
13
  mutation CreateFeatureRequest($input: PlanmagnetCreateFeatureRequestInput!) {
22
14
  planmagnetCreateFeatureRequest(input: $input) {
23
15
  id
@@ -30,107 +22,105 @@ var b = l`
30
22
  }
31
23
  `;
32
24
  function S() {
33
- let { workspaceId: l } = e(), S = t(), { data: C } = d(b, {
34
- variables: {
35
- workspaceId: l,
36
- pagination: { first: 100 }
37
- },
38
- skip: !l
39
- }), [w, T] = i({
25
+ let { workspaceId: d } = e(), S = t(), [C, w] = o({
40
26
  title: "",
41
27
  description: "",
42
28
  status: "SUBMITTED",
43
29
  businessValue: "50",
44
30
  effortEstimate: "medium",
45
- tags: ""
46
- }), [E, { loading: D }] = u(x, { refetchQueries: ["ListFeatureRequests"] }), [O, k] = i(null), A = r(w.businessValue, {
31
+ tags: "",
32
+ projectId: "",
33
+ workItemId: ""
34
+ }), [T, { loading: E }] = f(x, { refetchQueries: ["ListFeatureRequests"] }), [D, O] = o(null), k = a(C.businessValue, {
47
35
  min: 0,
48
36
  max: 100
49
37
  });
50
- return C?.planmagnetRoadmaps?.items, /* @__PURE__ */ p("div", {
38
+ return /* @__PURE__ */ m("div", {
51
39
  className: "space-y-6 p-6 max-w-4xl",
52
40
  children: [
53
- /* @__PURE__ */ p("div", {
41
+ /* @__PURE__ */ m("div", {
54
42
  className: "flex items-center justify-between",
55
- children: [/* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("h1", {
43
+ children: [/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("h1", {
56
44
  className: "text-2xl font-semibold",
57
45
  children: "New Feature"
58
- }), /* @__PURE__ */ f("p", {
46
+ }), /* @__PURE__ */ p("p", {
59
47
  className: "text-sm text-muted-foreground",
60
48
  children: "Define a new feature request with business value metrics."
61
- })] }), /* @__PURE__ */ p("div", {
49
+ })] }), /* @__PURE__ */ m("div", {
62
50
  className: "flex gap-2",
63
- children: [/* @__PURE__ */ p(m, {
51
+ children: [/* @__PURE__ */ m(h, {
64
52
  variant: "outline",
65
53
  size: "sm",
66
54
  onClick: () => S("/products/features-page"),
67
- children: [/* @__PURE__ */ f(c, { className: "mr-1 h-4 w-4" }), "Cancel"]
68
- }), /* @__PURE__ */ p(m, {
55
+ children: [/* @__PURE__ */ p(u, { className: "mr-1 h-4 w-4" }), "Cancel"]
56
+ }), /* @__PURE__ */ m(h, {
69
57
  size: "sm",
70
58
  onClick: async () => {
71
- if (!(!w.title.trim() || A.invalid)) {
72
- k(null);
59
+ if (!(!C.title.trim() || k.invalid)) {
60
+ O(null);
73
61
  try {
74
- await n(E({ variables: { input: {
75
- title: w.title,
76
- description: w.description || void 0,
77
- status: w.status,
78
- businessValue: A.value,
79
- effortEstimate: w.effortEstimate,
80
- tags: w.tags ? w.tags.split(",").map((e) => e.trim()).filter(Boolean) : void 0
62
+ await n(T({ variables: { input: {
63
+ title: C.title,
64
+ description: C.description || void 0,
65
+ status: C.status,
66
+ businessValue: k.value,
67
+ effortEstimate: C.effortEstimate,
68
+ projectId: C.projectId || void 0,
69
+ workItemId: C.workItemId || void 0,
70
+ tags: C.tags ? C.tags.split(",").map((e) => e.trim()).filter(Boolean) : void 0
81
71
  } } })), S("/products/features-page");
82
72
  } catch (e) {
83
- k(e instanceof Error ? e.message : "The feature could not be created.");
73
+ O(e instanceof Error ? e.message : "The feature could not be created.");
84
74
  }
85
75
  }
86
76
  },
87
- disabled: D || !w.title.trim() || A.invalid,
88
- children: [D ? /* @__PURE__ */ f(a, { className: "mr-1 h-4 w-4 animate-spin" }) : /* @__PURE__ */ f(o, { className: "mr-1 h-4 w-4" }), "Create Feature"]
77
+ disabled: E || !C.title.trim() || k.invalid,
78
+ children: [E ? /* @__PURE__ */ p(s, { className: "mr-1 h-4 w-4 animate-spin" }) : /* @__PURE__ */ p(c, { className: "mr-1 h-4 w-4" }), "Create Feature"]
89
79
  })]
90
80
  })]
91
81
  }),
92
- O && /* @__PURE__ */ p("div", {
82
+ D && /* @__PURE__ */ m("div", {
93
83
  role: "alert",
94
84
  className: "p-3 rounded-md bg-destructive/10 text-destructive text-sm",
95
- children: ["Failed to create feature: ", O]
85
+ children: ["Failed to create feature: ", D]
96
86
  }),
97
- /* @__PURE__ */ p(h, { children: [/* @__PURE__ */ f(_, { children: /* @__PURE__ */ f(v, { children: "Feature Details" }) }), /* @__PURE__ */ p(g, {
87
+ /* @__PURE__ */ m(g, { children: [/* @__PURE__ */ p(v, { children: /* @__PURE__ */ p(y, { children: "Feature Details" }) }), /* @__PURE__ */ m(_, {
98
88
  className: "space-y-4",
99
89
  children: [
100
- /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
90
+ /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
101
91
  className: "text-sm font-medium",
102
92
  children: "Title"
103
- }), /* @__PURE__ */ f(y, {
104
- value: w.title,
105
- onChange: (e) => T({
106
- ...w,
93
+ }), /* @__PURE__ */ p(b, {
94
+ value: C.title,
95
+ onChange: (e) => w({
96
+ ...C,
107
97
  title: e.target.value
108
98
  }),
109
99
  className: "mt-1",
110
100
  placeholder: "e.g. Advanced Search Filters"
111
101
  })] }),
112
- /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
102
+ /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
113
103
  className: "text-sm font-medium",
114
104
  children: "Description"
115
- }), /* @__PURE__ */ f("textarea", {
105
+ }), /* @__PURE__ */ p("textarea", {
116
106
  className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[100px]",
117
- value: w.description,
118
- onChange: (e) => T({
119
- ...w,
107
+ value: C.description,
108
+ onChange: (e) => w({
109
+ ...C,
120
110
  description: e.target.value
121
111
  }),
122
112
  placeholder: "Describe the feature and its user value..."
123
113
  })] }),
124
- /* @__PURE__ */ p("div", {
114
+ /* @__PURE__ */ m("div", {
125
115
  className: "grid grid-cols-2 gap-4",
126
- children: [/* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
116
+ children: [/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
127
117
  className: "text-sm font-medium",
128
118
  children: "Status"
129
- }), /* @__PURE__ */ f("select", {
119
+ }), /* @__PURE__ */ p("select", {
130
120
  className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm capitalize",
131
- value: w.status,
132
- onChange: (e) => T({
133
- ...w,
121
+ value: C.status,
122
+ onChange: (e) => w({
123
+ ...C,
134
124
  status: e.target.value
135
125
  }),
136
126
  children: [
@@ -139,18 +129,18 @@ function S() {
139
129
  "PLANNED",
140
130
  "IN_PROGRESS",
141
131
  "COMPLETED"
142
- ].map((e) => /* @__PURE__ */ f("option", {
132
+ ].map((e) => /* @__PURE__ */ p("option", {
143
133
  value: e,
144
134
  children: e.toLowerCase().replace("_", " ")
145
135
  }, e))
146
- })] }), /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
136
+ })] }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
147
137
  className: "text-sm font-medium",
148
138
  children: "Effort Estimate"
149
- }), /* @__PURE__ */ f("select", {
139
+ }), /* @__PURE__ */ p("select", {
150
140
  className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm capitalize",
151
- value: w.effortEstimate,
152
- onChange: (e) => T({
153
- ...w,
141
+ value: C.effortEstimate,
142
+ onChange: (e) => w({
143
+ ...C,
154
144
  effortEstimate: e.target.value
155
145
  }),
156
146
  children: [
@@ -158,19 +148,54 @@ function S() {
158
148
  "medium",
159
149
  "large",
160
150
  "epic"
161
- ].map((e) => /* @__PURE__ */ f("option", {
151
+ ].map((e) => /* @__PURE__ */ p("option", {
162
152
  value: e,
163
153
  children: e
164
154
  }, e))
165
155
  })] })]
166
156
  }),
167
- /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
157
+ /* @__PURE__ */ m("div", {
158
+ className: "grid grid-cols-2 gap-4",
159
+ children: [/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
160
+ htmlFor: "feature-project",
161
+ className: "text-sm font-medium",
162
+ children: "Project"
163
+ }), /* @__PURE__ */ p("div", {
164
+ className: "mt-1",
165
+ children: /* @__PURE__ */ p(r, {
166
+ id: "feature-project",
167
+ value: C.projectId,
168
+ noneLabel: "No project",
169
+ onChange: (e) => w({
170
+ ...C,
171
+ projectId: e,
172
+ workItemId: ""
173
+ })
174
+ })
175
+ })] }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
176
+ htmlFor: "feature-work-item",
177
+ className: "text-sm font-medium",
178
+ children: "Delivered by work item"
179
+ }), /* @__PURE__ */ p("div", {
180
+ className: "mt-1",
181
+ children: /* @__PURE__ */ p(i, {
182
+ id: "feature-work-item",
183
+ projectId: C.projectId || void 0,
184
+ value: C.workItemId,
185
+ onChange: (e) => w({
186
+ ...C,
187
+ workItemId: e
188
+ })
189
+ })
190
+ })] })]
191
+ }),
192
+ /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
168
193
  className: "text-sm font-medium",
169
194
  children: "Tags (comma-separated)"
170
- }), /* @__PURE__ */ f(y, {
171
- value: w.tags,
172
- onChange: (e) => T({
173
- ...w,
195
+ }), /* @__PURE__ */ p(b, {
196
+ value: C.tags,
197
+ onChange: (e) => w({
198
+ ...C,
174
199
  tags: e.target.value
175
200
  }),
176
201
  className: "mt-1",
@@ -178,51 +203,51 @@ function S() {
178
203
  })] })
179
204
  ]
180
205
  })] }),
181
- /* @__PURE__ */ p(h, { children: [/* @__PURE__ */ f(_, { children: /* @__PURE__ */ p(v, {
206
+ /* @__PURE__ */ m(g, { children: [/* @__PURE__ */ p(v, { children: /* @__PURE__ */ m(y, {
182
207
  className: "flex items-center gap-2",
183
- children: [/* @__PURE__ */ f(s, { className: "h-4 w-4" }), "Business Value"]
184
- }) }), /* @__PURE__ */ p(g, {
208
+ children: [/* @__PURE__ */ p(l, { className: "h-4 w-4" }), "Business Value"]
209
+ }) }), /* @__PURE__ */ m(_, {
185
210
  className: "space-y-4",
186
- children: [/* @__PURE__ */ p("div", { children: [
187
- /* @__PURE__ */ f("label", {
211
+ children: [/* @__PURE__ */ m("div", { children: [
212
+ /* @__PURE__ */ p("label", {
188
213
  htmlFor: "feature-business-value",
189
214
  className: "text-sm font-medium",
190
215
  children: "Business Value (0-100)"
191
216
  }),
192
- /* @__PURE__ */ f(y, {
217
+ /* @__PURE__ */ p(b, {
193
218
  id: "feature-business-value",
194
219
  type: "number",
195
220
  min: 0,
196
221
  max: 100,
197
222
  step: 1,
198
- value: w.businessValue,
199
- onChange: (e) => T({
200
- ...w,
223
+ value: C.businessValue,
224
+ onChange: (e) => w({
225
+ ...C,
201
226
  businessValue: e.target.value
202
227
  }),
203
- "aria-invalid": A.invalid,
228
+ "aria-invalid": k.invalid,
204
229
  className: "mt-1"
205
230
  }),
206
- A.invalid ? /* @__PURE__ */ f("p", {
231
+ k.invalid ? /* @__PURE__ */ p("p", {
207
232
  role: "alert",
208
233
  className: "text-xs text-destructive mt-1",
209
234
  children: "Business value must be a whole number from 0 to 100."
210
- }) : /* @__PURE__ */ f("p", {
235
+ }) : /* @__PURE__ */ p("p", {
211
236
  className: "text-xs text-muted-foreground mt-1",
212
237
  children: "How much business value does this feature deliver?"
213
238
  })
214
- ] }), /* @__PURE__ */ p("div", {
239
+ ] }), /* @__PURE__ */ m("div", {
215
240
  className: "p-4 bg-muted rounded-md text-center",
216
241
  children: [
217
- /* @__PURE__ */ f("p", {
242
+ /* @__PURE__ */ p("p", {
218
243
  className: "text-xs text-muted-foreground",
219
244
  children: "Business Value Score"
220
245
  }),
221
- /* @__PURE__ */ f("p", {
246
+ /* @__PURE__ */ p("p", {
222
247
  className: "text-3xl font-bold text-primary mt-2",
223
- children: A.invalid || A.value === void 0 ? "—" : A.value
248
+ children: k.invalid || k.value === void 0 ? "—" : k.value
224
249
  }),
225
- /* @__PURE__ */ f("p", {
250
+ /* @__PURE__ */ p("p", {
226
251
  className: "text-xs text-muted-foreground",
227
252
  children: "out of 100"
228
253
  })
@@ -1 +1 @@
1
- {"version":3,"file":"ProductsNewFeaturePagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProductsNewFeaturePagePage.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, useMutation } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Button, Input } from '@burdenoff/fe-libs/ui';\nimport { Save, X, Star, Loader2 } from 'lucide-react';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { throwOnError } from '../utils/mutationResult';\nimport { parseIntField } from '../utils/formValidation';\n\nconst LIST_ROADMAPS_FOR_SELECT = gql`\n query ListRoadmapsForFeatureSelect($workspaceId: ID!, $pagination: PlanmagnetPaginationInput) {\n planmagnetRoadmaps(workspaceId: $workspaceId, pagination: $pagination) {\n items {\n id\n name\n }\n }\n }\n`;\n\nconst CREATE_FEATURE_REQUEST = gql`\n mutation CreateFeatureRequest($input: PlanmagnetCreateFeatureRequestInput!) {\n planmagnetCreateFeatureRequest(input: $input) {\n id\n title\n status\n businessValue\n effortEstimate\n priorityScore\n }\n }\n`;\n\nexport function ProductsNewFeaturePagePage() {\n const { workspaceId } = usePlanMagnet();\n const navigate = usePlanMagnetNavigate();\n\n const {\n data: roadmapsData,\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_ROADMAPS_FOR_SELECT, {\n variables: { workspaceId, pagination: { first: 100 } },\n skip: !workspaceId,\n });\n\n const [form, setForm] = useState({\n title: '',\n description: '',\n status: 'SUBMITTED' as string,\n businessValue: '50',\n effortEstimate: 'medium',\n tags: '',\n });\n\n // Navigate only once the service has accepted the feature: with fe-libs' errorPolicy 'all' a refused\n // mutation resolves, so the old onCompleted navigation could leave the form as if it had saved.\n const [createFeature, { loading: saving }] = useMutation(CREATE_FEATURE_REQUEST, {\n refetchQueries: ['ListFeatureRequests'],\n });\n const [saveError, setSaveError] = useState<string | null>(null);\n // Business value is a whole number from 0 to 100 (BOFF-7833: prod had stored 150).\n const businessValue = parseIntField(form.businessValue, { min: 0, max: 100 });\n\n const statusOptions = [\n 'SUBMITTED',\n 'UNDER_REVIEW',\n 'PLANNED',\n 'IN_PROGRESS',\n 'COMPLETED',\n ] as const;\n const efforts = ['small', 'medium', 'large', 'epic'] as const;\n\n const handleCreate = async () => {\n if (!form.title.trim() || businessValue.invalid) return;\n setSaveError(null);\n try {\n await throwOnError(\n createFeature({\n variables: {\n input: {\n title: form.title,\n description: form.description || undefined,\n status: form.status,\n businessValue: businessValue.value,\n effortEstimate: form.effortEstimate,\n tags: form.tags\n ? form.tags\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean)\n : undefined,\n },\n },\n })\n );\n navigate('/products/features-page');\n } catch (e) {\n setSaveError(e instanceof Error ? e.message : 'The feature could not be created.');\n }\n };\n\n const roadmaps = roadmapsData?.planmagnetRoadmaps?.items ?? [];\n\n return (\n <div className=\"space-y-6 p-6 max-w-4xl\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">New Feature</h1>\n <p className=\"text-sm text-muted-foreground\">\n Define a new feature request with business value metrics.\n </p>\n </div>\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={() => navigate('/products/features-page')}>\n <X className=\"mr-1 h-4 w-4\" />\n Cancel\n </Button>\n <Button\n size=\"sm\"\n onClick={handleCreate}\n disabled={saving || !form.title.trim() || businessValue.invalid}\n >\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 Feature\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 feature: {saveError}\n </div>\n )}\n\n <Card>\n <CardHeader>\n <CardTitle>Feature Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label className=\"text-sm font-medium\">Title</label>\n <Input\n value={form.title}\n onChange={(e) => setForm({ ...form, title: e.target.value })}\n className=\"mt-1\"\n placeholder=\"e.g. Advanced Search Filters\"\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-[100px]\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n placeholder=\"Describe the feature and its user value...\"\n />\n </div>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"text-sm font-medium\">Status</label>\n <select\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm capitalize\"\n value={form.status}\n onChange={(e) => setForm({ ...form, status: e.target.value })}\n >\n {statusOptions.map((s) => (\n <option key={s} value={s}>\n {s.toLowerCase().replace('_', ' ')}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"text-sm font-medium\">Effort Estimate</label>\n <select\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm capitalize\"\n value={form.effortEstimate}\n onChange={(e) => setForm({ ...form, effortEstimate: e.target.value })}\n >\n {efforts.map((e) => (\n <option key={e} value={e}>\n {e}\n </option>\n ))}\n </select>\n </div>\n </div>\n <div>\n <label className=\"text-sm font-medium\">Tags (comma-separated)</label>\n <Input\n value={form.tags}\n onChange={(e) => setForm({ ...form, tags: e.target.value })}\n className=\"mt-1\"\n placeholder=\"e.g. search, ux, performance\"\n />\n </div>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Star className=\"h-4 w-4\" />\n Business Value\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label htmlFor=\"feature-business-value\" className=\"text-sm font-medium\">\n Business Value (0-100)\n </label>\n <Input\n id=\"feature-business-value\"\n type=\"number\"\n min={0}\n max={100}\n step={1}\n value={form.businessValue}\n onChange={(e) => setForm({ ...form, businessValue: e.target.value })}\n aria-invalid={businessValue.invalid}\n className=\"mt-1\"\n />\n {businessValue.invalid ? (\n <p role=\"alert\" className=\"text-xs text-destructive mt-1\">\n Business value must be a whole number from 0 to 100.\n </p>\n ) : (\n <p className=\"text-xs text-muted-foreground mt-1\">\n How much business value does this feature deliver?\n </p>\n )}\n </div>\n\n <div className=\"p-4 bg-muted rounded-md text-center\">\n <p className=\"text-xs text-muted-foreground\">Business Value Score</p>\n <p className=\"text-3xl font-bold text-primary mt-2\">\n {businessValue.invalid || businessValue.value === undefined\n ? '—'\n : businessValue.value}\n </p>\n <p className=\"text-xs text-muted-foreground\">out of 100</p>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ProductsNewFeaturePagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProductsNewFeaturePagePage.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 { Card, CardContent, CardHeader, CardTitle, Button, Input } from '@burdenoff/fe-libs/ui';\nimport { Save, X, Star, Loader2 } from 'lucide-react';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { throwOnError } from '../utils/mutationResult';\nimport { parseIntField } from '../utils/formValidation';\nimport { ProjectSelect, WorkItemSearchSelect } from '../controls/Pickers';\n\nconst CREATE_FEATURE_REQUEST = gql`\n mutation CreateFeatureRequest($input: PlanmagnetCreateFeatureRequestInput!) {\n planmagnetCreateFeatureRequest(input: $input) {\n id\n title\n status\n businessValue\n effortEstimate\n priorityScore\n }\n }\n`;\n\nexport function ProductsNewFeaturePagePage() {\n const { workspaceId } = usePlanMagnet();\n const navigate = usePlanMagnetNavigate();\n\n const [form, setForm] = useState({\n title: '',\n description: '',\n status: 'SUBMITTED' as string,\n businessValue: '50',\n effortEstimate: 'medium',\n tags: '',\n projectId: '',\n workItemId: '',\n });\n\n // Navigate only once the service has accepted the feature: with fe-libs' errorPolicy 'all' a refused\n // mutation resolves, so the old onCompleted navigation could leave the form as if it had saved.\n const [createFeature, { loading: saving }] = useMutation(CREATE_FEATURE_REQUEST, {\n refetchQueries: ['ListFeatureRequests'],\n });\n const [saveError, setSaveError] = useState<string | null>(null);\n // Business value is a whole number from 0 to 100 (BOFF-7833: prod had stored 150).\n const businessValue = parseIntField(form.businessValue, { min: 0, max: 100 });\n\n const statusOptions = [\n 'SUBMITTED',\n 'UNDER_REVIEW',\n 'PLANNED',\n 'IN_PROGRESS',\n 'COMPLETED',\n ] as const;\n const efforts = ['small', 'medium', 'large', 'epic'] as const;\n\n const handleCreate = async () => {\n if (!form.title.trim() || businessValue.invalid) return;\n setSaveError(null);\n try {\n await throwOnError(\n createFeature({\n variables: {\n input: {\n title: form.title,\n description: form.description || undefined,\n status: form.status,\n businessValue: businessValue.value,\n effortEstimate: form.effortEstimate,\n projectId: form.projectId || undefined,\n workItemId: form.workItemId || undefined,\n tags: form.tags\n ? form.tags\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean)\n : undefined,\n },\n },\n })\n );\n navigate('/products/features-page');\n } catch (e) {\n setSaveError(e instanceof Error ? e.message : 'The feature could not be created.');\n }\n };\n\n return (\n <div className=\"space-y-6 p-6 max-w-4xl\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">New Feature</h1>\n <p className=\"text-sm text-muted-foreground\">\n Define a new feature request with business value metrics.\n </p>\n </div>\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={() => navigate('/products/features-page')}>\n <X className=\"mr-1 h-4 w-4\" />\n Cancel\n </Button>\n <Button\n size=\"sm\"\n onClick={handleCreate}\n disabled={saving || !form.title.trim() || businessValue.invalid}\n >\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 Feature\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 feature: {saveError}\n </div>\n )}\n\n <Card>\n <CardHeader>\n <CardTitle>Feature Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label className=\"text-sm font-medium\">Title</label>\n <Input\n value={form.title}\n onChange={(e) => setForm({ ...form, title: e.target.value })}\n className=\"mt-1\"\n placeholder=\"e.g. Advanced Search Filters\"\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-[100px]\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n placeholder=\"Describe the feature and its user value...\"\n />\n </div>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"text-sm font-medium\">Status</label>\n <select\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm capitalize\"\n value={form.status}\n onChange={(e) => setForm({ ...form, status: e.target.value })}\n >\n {statusOptions.map((s) => (\n <option key={s} value={s}>\n {s.toLowerCase().replace('_', ' ')}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"text-sm font-medium\">Effort Estimate</label>\n <select\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm capitalize\"\n value={form.effortEstimate}\n onChange={(e) => setForm({ ...form, effortEstimate: e.target.value })}\n >\n {efforts.map((e) => (\n <option key={e} value={e}>\n {e}\n </option>\n ))}\n </select>\n </div>\n </div>\n {/* BOFF-7966: a request could not be tied to a project or to the work item that delivers it, so the\n release readiness card's \"customer requests riding on unfinished work\" could never fill. */}\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label htmlFor=\"feature-project\" className=\"text-sm font-medium\">\n Project\n </label>\n <div className=\"mt-1\">\n <ProjectSelect\n id=\"feature-project\"\n value={form.projectId}\n noneLabel=\"No project\"\n onChange={(projectId) => setForm({ ...form, projectId, workItemId: '' })}\n />\n </div>\n </div>\n <div>\n <label htmlFor=\"feature-work-item\" className=\"text-sm font-medium\">\n Delivered by work item\n </label>\n <div className=\"mt-1\">\n <WorkItemSearchSelect\n id=\"feature-work-item\"\n projectId={form.projectId || undefined}\n value={form.workItemId}\n onChange={(workItemId) => setForm({ ...form, workItemId })}\n />\n </div>\n </div>\n </div>\n <div>\n <label className=\"text-sm font-medium\">Tags (comma-separated)</label>\n <Input\n value={form.tags}\n onChange={(e) => setForm({ ...form, tags: e.target.value })}\n className=\"mt-1\"\n placeholder=\"e.g. search, ux, performance\"\n />\n </div>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Star className=\"h-4 w-4\" />\n Business Value\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label htmlFor=\"feature-business-value\" className=\"text-sm font-medium\">\n Business Value (0-100)\n </label>\n <Input\n id=\"feature-business-value\"\n type=\"number\"\n min={0}\n max={100}\n step={1}\n value={form.businessValue}\n onChange={(e) => setForm({ ...form, businessValue: e.target.value })}\n aria-invalid={businessValue.invalid}\n className=\"mt-1\"\n />\n {businessValue.invalid ? (\n <p role=\"alert\" className=\"text-xs text-destructive mt-1\">\n Business value must be a whole number from 0 to 100.\n </p>\n ) : (\n <p className=\"text-xs text-muted-foreground mt-1\">\n How much business value does this feature deliver?\n </p>\n )}\n </div>\n\n <div className=\"p-4 bg-muted rounded-md text-center\">\n <p className=\"text-xs text-muted-foreground\">Business Value Score</p>\n <p className=\"text-3xl font-bold text-primary mt-2\">\n {businessValue.invalid || businessValue.value === undefined\n ? '—'\n : businessValue.value}\n </p>\n <p className=\"text-xs text-muted-foreground\">out of 100</p>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ProductsProductDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProductsProductDetailPagePage.tsx"],"names":[],"mappings":"AAoGA,wBAAgB,6BAA6B,4CA8N5C"}
1
+ {"version":3,"file":"ProductsProductDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProductsProductDetailPagePage.tsx"],"names":[],"mappings":"AAoGA,wBAAgB,6BAA6B,4CAmO5C"}
@@ -127,12 +127,12 @@ function C() {
127
127
  icon: c
128
128
  },
129
129
  {
130
- label: "Releases",
130
+ label: "Releases in workspace",
131
131
  value: P,
132
132
  icon: a
133
133
  },
134
134
  {
135
- label: "Features",
135
+ label: "Feature requests in workspace",
136
136
  value: N,
137
137
  icon: s
138
138
  },
@@ -156,11 +156,7 @@ function C() {
156
156
  className: "grid grid-cols-1 lg:grid-cols-3 gap-6",
157
157
  children: [/* @__PURE__ */ m("div", {
158
158
  className: "lg:col-span-2 space-y-6",
159
- children: [/* @__PURE__ */ m(g, { children: [/* @__PURE__ */ p(v, { children: /* @__PURE__ */ m(y, { children: [
160
- "Feature Requests (",
161
- j.length,
162
- ")"
163
- ] }) }), /* @__PURE__ */ m(_, {
159
+ children: [/* @__PURE__ */ m(g, { children: [/* @__PURE__ */ p(v, { children: /* @__PURE__ */ m(y, { children: ["Latest feature requests in the workspace", N > j.length ? ` (${j.length} of ${N})` : ""] }) }), /* @__PURE__ */ m(_, {
164
160
  className: "space-y-3",
165
161
  children: [j.length === 0 && /* @__PURE__ */ p("p", {
166
162
  className: "text-sm text-muted-foreground",
@@ -217,7 +213,7 @@ function C() {
217
213
  })] })]
218
214
  }), /* @__PURE__ */ m("div", {
219
215
  className: "space-y-6",
220
- children: [/* @__PURE__ */ m(g, { children: [/* @__PURE__ */ p(v, { children: /* @__PURE__ */ p(y, { children: "Recent Releases" }) }), /* @__PURE__ */ m(_, {
216
+ children: [/* @__PURE__ */ m(g, { children: [/* @__PURE__ */ p(v, { children: /* @__PURE__ */ p(y, { children: "Latest releases in the workspace" }) }), /* @__PURE__ */ m(_, {
221
217
  className: "space-y-3",
222
218
  children: [M.length === 0 && /* @__PURE__ */ p("p", {
223
219
  className: "text-sm text-muted-foreground",
@@ -1 +1 @@
1
- {"version":3,"file":"ProductsProductDetailPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProductsProductDetailPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Badge } from '@burdenoff/fe-libs/ui';\nimport { Package, GitBranch, Map, Star, Users, Calendar, Loader2 } from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\nimport { useParams } from 'react-router';\nimport { PersonName } from '../people/People';\nimport { PlanningFocusBadge } from '../roadmaps/planningFocus';\nimport { RoadmapHeaderActions } from '../roadmaps/RoadmapControls';\n\nconst GET_ROADMAP = gql`\n query GetRoadmapDetail($id: ID!) {\n planmagnetRoadmap(id: $id) {\n id\n workspaceId\n name\n description\n type\n planningFocus\n isPublic\n ownerId\n createdAt\n updatedAt\n items {\n id\n title\n description\n status\n startDate\n endDate\n color\n swimlane\n sortOrder\n }\n }\n }\n`;\n\nconst LIST_FEATURE_REQUESTS_FOR_PRODUCT = gql`\n query ListFeatureRequestsForProduct($workspaceId: ID!, $pagination: PlanmagnetPaginationInput) {\n planmagnetFeatureRequests(workspaceId: $workspaceId, pagination: $pagination) {\n items {\n id\n title\n description\n status\n priorityScore\n voteCount\n businessValue\n createdAt\n }\n totalCount\n }\n }\n`;\n\nconst LIST_RELEASES_FOR_PRODUCT = gql`\n query ListReleasesForProduct($workspaceId: ID!, $pagination: PlanmagnetPaginationInput) {\n planmagnetReleases(workspaceId: $workspaceId, pagination: $pagination) {\n items {\n id\n name\n version\n status\n plannedDate\n }\n totalCount\n }\n }\n`;\n\ninterface RoadmapItemNode {\n id: string;\n title: string;\n description: string | null;\n status: string;\n startDate: string | null;\n endDate: string | null;\n}\n\ninterface FeatureRequestNode {\n id: string;\n title: string;\n description: string | null;\n status: string;\n priorityScore: number | null;\n voteCount: number;\n businessValue: number | null;\n}\n\ninterface ReleaseNode {\n id: string;\n name: string;\n version: string;\n status: string;\n plannedDate: string | null;\n}\n\nexport function ProductsProductDetailPagePage() {\n const { workspaceId } = usePlanMagnet();\n const params = useParams<{ id: string }>();\n const roadmapId = params.id ?? '';\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>>(GET_ROADMAP, {\n variables: { id: roadmapId },\n skip: !roadmapId,\n });\n\n const {\n data: featuresData,\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_FOR_PRODUCT, {\n variables: { workspaceId, pagination: { first: 20 } },\n skip: !workspaceId,\n });\n\n const {\n data: releasesData,\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_RELEASES_FOR_PRODUCT, {\n variables: { workspaceId, pagination: { first: 20 } },\n skip: !workspaceId,\n });\n\n // Only before the first load: a refetch must not blank the page (it\n\n // unmounts every component on it and loses their state).\n\n if (loading && !data) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-muted-foreground\" />\n </div>\n );\n }\n\n if (error) {\n return <div className=\"p-6 text-destructive\">Failed to load product: {error.message}</div>;\n }\n\n const roadmap = data?.planmagnetRoadmap;\n if (!roadmap) return <div className=\"p-6 text-muted-foreground\">Product not found.</div>;\n\n const roadmapItems: RoadmapItemNode[] = roadmap.items ?? [];\n const features: FeatureRequestNode[] = featuresData?.planmagnetFeatureRequests?.items ?? [];\n const releases: ReleaseNode[] = releasesData?.planmagnetReleases?.items ?? [];\n const totalFeatures = featuresData?.planmagnetFeatureRequests?.totalCount ?? 0;\n const totalReleases = releasesData?.planmagnetReleases?.totalCount ?? 0;\n\n const 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 };\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <div>\n <h1 className=\"text-2xl font-semibold\">{roadmap.name}</h1>\n <p className=\"text-sm text-muted-foreground\">\n {roadmap.description ?? 'No description'}\n </p>\n </div>\n </div>\n {/* Edit and Delete (BOFF-7941): the Edit page existed and nothing linked to it. */}\n <div className=\"flex flex-col items-end gap-2\">\n <RoadmapHeaderActions roadmapId={roadmap.id} name={roadmap.name} />\n <PlanningFocusBadge focus={roadmap.planningFocus} />\n </div>\n </div>\n\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n {[\n { label: 'Roadmap Items', value: roadmapItems.length, icon: Star },\n { label: 'Releases', value: totalReleases, icon: GitBranch },\n { label: 'Features', value: totalFeatures, icon: Map },\n // The name, as the Details card below shows it — not the owner's UUID in large type (BOFF-7976).\n { label: 'Owner', value: <PersonName id={roadmap.ownerId} />, icon: Users },\n ].map((s) => (\n <Card key={s.label}>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-sm\">\n <s.icon className=\"h-4 w-4\" />\n {s.label}\n </div>\n <p className=\"text-xl font-semibold mt-1\">{s.value}</p>\n </CardContent>\n </Card>\n ))}\n </div>\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>Feature Requests ({features.length})</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {features.length === 0 && (\n <p className=\"text-sm text-muted-foreground\">No feature requests yet.</p>\n )}\n {features.map((f) => (\n <div key={f.id} className=\"flex items-center justify-between rounded-md border p-3\">\n <div>\n <p className=\"text-sm font-medium\">{f.title}</p>\n <p className=\"text-xs text-muted-foreground\">\n Votes: {f.voteCount} &middot; Business Value: {f.businessValue ?? 'N/A'}\n </p>\n </div>\n <div className=\"flex items-center gap-2\">\n <Badge variant=\"secondary\" className=\"capitalize text-xs\">\n {f.status.toLowerCase().replace('_', ' ')}\n </Badge>\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Roadmap Items ({roadmapItems.length})</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {roadmapItems.length === 0 && (\n <p className=\"text-sm text-muted-foreground\">No roadmap items linked.</p>\n )}\n {roadmapItems.map((item) => (\n <div\n key={item.id}\n className=\"flex items-center justify-between rounded-md border p-3\"\n >\n <div>\n <p className=\"text-sm font-medium\">{item.title}</p>\n <p className=\"text-xs text-muted-foreground\">\n {item.startDate\n ? new Date(item.startDate).toLocaleDateString()\n : 'No start date'}\n {' - '}\n {item.endDate ? new Date(item.endDate).toLocaleDateString() : 'No end date'}\n </p>\n </div>\n <Badge variant=\"outline\" className=\"capitalize text-xs\">\n {item.status.toLowerCase().replace('_', ' ')}\n </Badge>\n </div>\n ))}\n </CardContent>\n </Card>\n </div>\n\n <div className=\"space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle>Recent Releases</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {releases.length === 0 && (\n <p className=\"text-sm text-muted-foreground\">No releases yet.</p>\n )}\n {releases.map((r) => (\n <div key={r.id} className=\"border-b pb-2 last:border-0 last:pb-0\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-sm font-medium\">{r.version}</span>\n <Badge variant=\"outline\" className=\"text-xs capitalize\">\n {r.status.toLowerCase().replace('_', ' ')}\n </Badge>\n </div>\n <p className=\"text-xs text-muted-foreground\">{r.name}</p>\n <div className=\"flex items-center gap-1 mt-1 text-xs text-muted-foreground\">\n <Calendar className=\"h-3 w-3\" />\n {r.plannedDate ? new Date(r.plannedDate).toLocaleDateString() : 'No date set'}\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2 text-sm\">\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Created</span>\n <span>{new Date(roadmap.createdAt).toLocaleDateString()}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Updated</span>\n <span>{new Date(roadmap.updatedAt).toLocaleDateString()}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Owner</span>\n <span>\n <PersonName id={roadmap.ownerId} />\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Visibility</span>\n <span>{roadmap.isPublic ? 'Public' : 'Private'}</span>\n </div>\n </CardContent>\n </Card>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ProductsProductDetailPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProductsProductDetailPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Badge } from '@burdenoff/fe-libs/ui';\nimport { Package, GitBranch, Map, Star, Users, Calendar, Loader2 } from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\nimport { useParams } from 'react-router';\nimport { PersonName } from '../people/People';\nimport { PlanningFocusBadge } from '../roadmaps/planningFocus';\nimport { RoadmapHeaderActions } from '../roadmaps/RoadmapControls';\n\nconst GET_ROADMAP = gql`\n query GetRoadmapDetail($id: ID!) {\n planmagnetRoadmap(id: $id) {\n id\n workspaceId\n name\n description\n type\n planningFocus\n isPublic\n ownerId\n createdAt\n updatedAt\n items {\n id\n title\n description\n status\n startDate\n endDate\n color\n swimlane\n sortOrder\n }\n }\n }\n`;\n\nconst LIST_FEATURE_REQUESTS_FOR_PRODUCT = gql`\n query ListFeatureRequestsForProduct($workspaceId: ID!, $pagination: PlanmagnetPaginationInput) {\n planmagnetFeatureRequests(workspaceId: $workspaceId, pagination: $pagination) {\n items {\n id\n title\n description\n status\n priorityScore\n voteCount\n businessValue\n createdAt\n }\n totalCount\n }\n }\n`;\n\nconst LIST_RELEASES_FOR_PRODUCT = gql`\n query ListReleasesForProduct($workspaceId: ID!, $pagination: PlanmagnetPaginationInput) {\n planmagnetReleases(workspaceId: $workspaceId, pagination: $pagination) {\n items {\n id\n name\n version\n status\n plannedDate\n }\n totalCount\n }\n }\n`;\n\ninterface RoadmapItemNode {\n id: string;\n title: string;\n description: string | null;\n status: string;\n startDate: string | null;\n endDate: string | null;\n}\n\ninterface FeatureRequestNode {\n id: string;\n title: string;\n description: string | null;\n status: string;\n priorityScore: number | null;\n voteCount: number;\n businessValue: number | null;\n}\n\ninterface ReleaseNode {\n id: string;\n name: string;\n version: string;\n status: string;\n plannedDate: string | null;\n}\n\nexport function ProductsProductDetailPagePage() {\n const { workspaceId } = usePlanMagnet();\n const params = useParams<{ id: string }>();\n const roadmapId = params.id ?? '';\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>>(GET_ROADMAP, {\n variables: { id: roadmapId },\n skip: !roadmapId,\n });\n\n const {\n data: featuresData,\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_FOR_PRODUCT, {\n variables: { workspaceId, pagination: { first: 20 } },\n skip: !workspaceId,\n });\n\n const {\n data: releasesData,\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_RELEASES_FOR_PRODUCT, {\n variables: { workspaceId, pagination: { first: 20 } },\n skip: !workspaceId,\n });\n\n // Only before the first load: a refetch must not blank the page (it\n\n // unmounts every component on it and loses their state).\n\n if (loading && !data) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-muted-foreground\" />\n </div>\n );\n }\n\n if (error) {\n return <div className=\"p-6 text-destructive\">Failed to load product: {error.message}</div>;\n }\n\n const roadmap = data?.planmagnetRoadmap;\n if (!roadmap) return <div className=\"p-6 text-muted-foreground\">Product not found.</div>;\n\n const roadmapItems: RoadmapItemNode[] = roadmap.items ?? [];\n const features: FeatureRequestNode[] = featuresData?.planmagnetFeatureRequests?.items ?? [];\n const releases: ReleaseNode[] = releasesData?.planmagnetReleases?.items ?? [];\n const totalFeatures = featuresData?.planmagnetFeatureRequests?.totalCount ?? 0;\n const totalReleases = releasesData?.planmagnetReleases?.totalCount ?? 0;\n\n const 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 };\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <div>\n <h1 className=\"text-2xl font-semibold\">{roadmap.name}</h1>\n <p className=\"text-sm text-muted-foreground\">\n {roadmap.description ?? 'No description'}\n </p>\n </div>\n </div>\n {/* Edit and Delete (BOFF-7941): the Edit page existed and nothing linked to it. */}\n <div className=\"flex flex-col items-end gap-2\">\n <RoadmapHeaderActions roadmapId={roadmap.id} name={roadmap.name} />\n <PlanningFocusBadge focus={roadmap.planningFocus} />\n </div>\n </div>\n\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n {[\n { label: 'Roadmap Items', value: roadmapItems.length, icon: Star },\n // A product (a roadmap) has no project scope of its own, so these are the WORKSPACE's numbers — said so,\n // rather than shown as if they belonged to the product (BOFF-7991).\n { label: 'Releases in workspace', value: totalReleases, icon: GitBranch },\n { label: 'Feature requests in workspace', value: totalFeatures, icon: Map },\n // The name, as the Details card below shows it — not the owner's UUID in large type (BOFF-7976).\n { label: 'Owner', value: <PersonName id={roadmap.ownerId} />, icon: Users },\n ].map((s) => (\n <Card key={s.label}>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-sm\">\n <s.icon className=\"h-4 w-4\" />\n {s.label}\n </div>\n <p className=\"text-xl font-semibold mt-1\">{s.value}</p>\n </CardContent>\n </Card>\n ))}\n </div>\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>\n Latest feature requests in the workspace\n {totalFeatures > features.length ? ` (${features.length} of ${totalFeatures})` : ''}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {features.length === 0 && (\n <p className=\"text-sm text-muted-foreground\">No feature requests yet.</p>\n )}\n {features.map((f) => (\n <div key={f.id} className=\"flex items-center justify-between rounded-md border p-3\">\n <div>\n <p className=\"text-sm font-medium\">{f.title}</p>\n <p className=\"text-xs text-muted-foreground\">\n Votes: {f.voteCount} &middot; Business Value: {f.businessValue ?? 'N/A'}\n </p>\n </div>\n <div className=\"flex items-center gap-2\">\n <Badge variant=\"secondary\" className=\"capitalize text-xs\">\n {f.status.toLowerCase().replace('_', ' ')}\n </Badge>\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Roadmap Items ({roadmapItems.length})</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {roadmapItems.length === 0 && (\n <p className=\"text-sm text-muted-foreground\">No roadmap items linked.</p>\n )}\n {roadmapItems.map((item) => (\n <div\n key={item.id}\n className=\"flex items-center justify-between rounded-md border p-3\"\n >\n <div>\n <p className=\"text-sm font-medium\">{item.title}</p>\n <p className=\"text-xs text-muted-foreground\">\n {item.startDate\n ? new Date(item.startDate).toLocaleDateString()\n : 'No start date'}\n {' - '}\n {item.endDate ? new Date(item.endDate).toLocaleDateString() : 'No end date'}\n </p>\n </div>\n <Badge variant=\"outline\" className=\"capitalize text-xs\">\n {item.status.toLowerCase().replace('_', ' ')}\n </Badge>\n </div>\n ))}\n </CardContent>\n </Card>\n </div>\n\n <div className=\"space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle>Latest releases in the workspace</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {releases.length === 0 && (\n <p className=\"text-sm text-muted-foreground\">No releases yet.</p>\n )}\n {releases.map((r) => (\n <div key={r.id} className=\"border-b pb-2 last:border-0 last:pb-0\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-sm font-medium\">{r.version}</span>\n <Badge variant=\"outline\" className=\"text-xs capitalize\">\n {r.status.toLowerCase().replace('_', ' ')}\n </Badge>\n </div>\n <p className=\"text-xs text-muted-foreground\">{r.name}</p>\n <div className=\"flex items-center gap-1 mt-1 text-xs text-muted-foreground\">\n <Calendar className=\"h-3 w-3\" />\n {r.plannedDate ? new Date(r.plannedDate).toLocaleDateString() : 'No date set'}\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2 text-sm\">\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Created</span>\n <span>{new Date(roadmap.createdAt).toLocaleDateString()}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Updated</span>\n <span>{new Date(roadmap.updatedAt).toLocaleDateString()}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Owner</span>\n <span>\n <PersonName id={roadmap.ownerId} />\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Visibility</span>\n <span>{roadmap.isPublic ? 'Public' : 'Private'}</span>\n </div>\n </CardContent>\n </Card>\n </div>\n </div>\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":"AAqEA,wBAAgB,wBAAwB,4CAkLvC"}
1
+ {"version":3,"file":"ProductsProductsPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProductsProductsPagePage.tsx"],"names":[],"mappings":"AAsEA,wBAAgB,wBAAwB,4CA+KvC"}