@burdenoff/microfe-planmagnet 2026.927.2 → 2026.927.3
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/admin/PlanMagnetAdminRoot.d.ts.map +1 -1
- package/dist/planmagnet/admin/PlanMagnetAdminRoot.js +128 -124
- package/dist/planmagnet/admin/PlanMagnetAdminRoot.js.map +1 -1
- package/dist/planmagnet/controls/ConfirmButton.d.ts +25 -0
- package/dist/planmagnet/controls/ConfirmButton.d.ts.map +1 -0
- package/dist/planmagnet/controls/ConfirmButton.js +30 -0
- package/dist/planmagnet/controls/ConfirmButton.js.map +1 -0
- package/dist/planmagnet/controls/ProjectControls.d.ts +13 -0
- package/dist/planmagnet/controls/ProjectControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/ProjectControls.js +104 -0
- package/dist/planmagnet/controls/ProjectControls.js.map +1 -0
- package/dist/planmagnet/controls/WorkItemControls.d.ts +52 -0
- package/dist/planmagnet/controls/WorkItemControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/WorkItemControls.js +198 -0
- package/dist/planmagnet/controls/WorkItemControls.js.map +1 -0
- package/dist/planmagnet/pages/DocsDocDetailPagePage.js +4 -4
- package/dist/planmagnet/pages/DocsDocDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/DocsDocsPagePage.js +4 -4
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.js +97 -90
- 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 +150 -111
- package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsEditProjectPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js +114 -91
- package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js +134 -132
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/SprintsStartSprintPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/SprintsStartSprintPagePage.js +6 -5
- package/dist/planmagnet/pages/SprintsStartSprintPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksCreateTaskPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksCreateTaskPagePage.js +167 -111
- package/dist/planmagnet/pages/TasksCreateTaskPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.js +147 -147
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TeamTeamPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TeamTeamPagePage.js +1 -1
- package/dist/planmagnet/pages/TeamTeamPagePage.js.map +1 -1
- package/dist/planmagnet/people/People.js +1 -1
- package/dist/planmagnet/roadmaps/RoadmapControls.d.ts +34 -0
- package/dist/planmagnet/roadmaps/RoadmapControls.d.ts.map +1 -0
- package/dist/planmagnet/roadmaps/RoadmapControls.js +301 -0
- package/dist/planmagnet/roadmaps/RoadmapControls.js.map +1 -0
- package/dist/planmagnet/sprints/SprintControls.d.ts.map +1 -1
- package/dist/planmagnet/sprints/SprintControls.js +194 -215
- package/dist/planmagnet/sprints/SprintControls.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { PersonName as e } from "../people/People.js";
|
|
2
2
|
import { useEntityId as t } from "../hooks/useEntityId.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
3
|
+
import { ProjectHeaderActions as n } from "../controls/ProjectControls.js";
|
|
4
|
+
import { Calendar as r, CheckSquare as i, FolderKanban as a, Users as o, Zap as s } from "lucide-react";
|
|
5
|
+
import { gql as c } from "@apollo/client";
|
|
6
|
+
import { useQuery as l } from "@apollo/client/react";
|
|
7
|
+
import { jsx as u, jsxs as d } from "react/jsx-runtime";
|
|
8
|
+
import { Badge as f, Card as p, CardContent as m, CardHeader as h, CardTitle as g } from "@burdenoff/fe-libs/ui";
|
|
8
9
|
//#region src/planmagnet/pages/ProjectsProjectDetailPagePage.tsx
|
|
9
|
-
var
|
|
10
|
+
var _ = c`
|
|
10
11
|
query GetProjectDetail($id: ID!) {
|
|
11
12
|
planmagnetProject(id: $id) {
|
|
12
13
|
id
|
|
@@ -56,7 +57,7 @@ var g = s`
|
|
|
56
57
|
}
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
|
-
`,
|
|
60
|
+
`, v = {
|
|
60
61
|
ACTIVE: "bg-green-100 text-green-800",
|
|
61
62
|
ON_HOLD: "bg-orange-100 text-orange-800",
|
|
62
63
|
CANCELLED: "bg-red-100 text-red-800",
|
|
@@ -64,292 +65,293 @@ var g = s`
|
|
|
64
65
|
PLANNING: "bg-gray-100 text-gray-800",
|
|
65
66
|
ARCHIVED: "bg-gray-100 text-gray-800"
|
|
66
67
|
};
|
|
67
|
-
function
|
|
68
|
-
let
|
|
69
|
-
variables: { id:
|
|
70
|
-
skip: !
|
|
68
|
+
function y() {
|
|
69
|
+
let c = t("projectId"), { data: y, loading: b, error: x } = l(_, {
|
|
70
|
+
variables: { id: c },
|
|
71
|
+
skip: !c
|
|
71
72
|
});
|
|
72
|
-
if (!
|
|
73
|
+
if (!c) return /* @__PURE__ */ u("div", {
|
|
73
74
|
className: "p-6 text-muted-foreground",
|
|
74
75
|
children: "No project selected. Open one from the list."
|
|
75
76
|
});
|
|
76
|
-
if (
|
|
77
|
+
if (b && !y) return /* @__PURE__ */ u("div", {
|
|
77
78
|
className: "flex items-center justify-center p-12",
|
|
78
|
-
children: /* @__PURE__ */
|
|
79
|
+
children: /* @__PURE__ */ u("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
|
|
79
80
|
});
|
|
80
|
-
if (
|
|
81
|
+
if (x) return /* @__PURE__ */ d("div", {
|
|
81
82
|
className: "p-6 text-red-500",
|
|
82
|
-
children: ["Error loading project: ",
|
|
83
|
+
children: ["Error loading project: ", x.message]
|
|
83
84
|
});
|
|
84
|
-
let
|
|
85
|
-
if (!
|
|
85
|
+
let S = y?.planmagnetProject;
|
|
86
|
+
if (!S) return /* @__PURE__ */ u("div", {
|
|
86
87
|
className: "p-6 text-muted-foreground",
|
|
87
88
|
children: "Project not found."
|
|
88
89
|
});
|
|
89
|
-
let
|
|
90
|
-
return /* @__PURE__ */
|
|
90
|
+
let C = S.workItems ?? [], w = S.sprints ?? [], T = S.milestones ?? [], E = w.find((e) => e.status === "ACTIVE"), D = w.filter((e) => e.status === "COMPLETED" && e.velocity != null).sort((e, t) => (t.endDate ?? "").localeCompare(e.endDate ?? ""))[0], O = C.length, k = C.filter((e) => e.status === "DONE").length;
|
|
91
|
+
return /* @__PURE__ */ d("div", {
|
|
91
92
|
className: "space-y-6 p-6",
|
|
92
93
|
children: [
|
|
93
|
-
/* @__PURE__ */
|
|
94
|
+
/* @__PURE__ */ d("div", {
|
|
94
95
|
className: "flex items-center justify-between",
|
|
95
|
-
children: [/* @__PURE__ */
|
|
96
|
+
children: [/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ d("div", {
|
|
96
97
|
className: "flex items-center gap-2",
|
|
97
98
|
children: [
|
|
98
|
-
/* @__PURE__ */
|
|
99
|
-
/* @__PURE__ */
|
|
99
|
+
/* @__PURE__ */ u(a, { className: "h-5 w-5 text-primary" }),
|
|
100
|
+
/* @__PURE__ */ u("h1", {
|
|
100
101
|
className: "text-2xl font-semibold",
|
|
101
|
-
children:
|
|
102
|
+
children: S.name
|
|
102
103
|
}),
|
|
103
|
-
/* @__PURE__ */
|
|
104
|
-
className: `text-xs px-2 py-0.5 rounded-full capitalize ${
|
|
105
|
-
children:
|
|
104
|
+
/* @__PURE__ */ u("span", {
|
|
105
|
+
className: `text-xs px-2 py-0.5 rounded-full capitalize ${v[S.status] ?? "bg-gray-100"}`,
|
|
106
|
+
children: S.status.toLowerCase().replace("_", " ")
|
|
106
107
|
})
|
|
107
108
|
]
|
|
108
|
-
}), /* @__PURE__ */
|
|
109
|
+
}), /* @__PURE__ */ u("p", {
|
|
109
110
|
className: "text-sm text-muted-foreground mt-1",
|
|
110
|
-
children:
|
|
111
|
-
})] }), /* @__PURE__ */
|
|
112
|
-
className: "flex gap-2",
|
|
113
|
-
children: [/* @__PURE__ */
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
111
|
+
children: S.description ?? "No description"
|
|
112
|
+
})] }), /* @__PURE__ */ d("div", {
|
|
113
|
+
className: "flex flex-col items-end gap-2",
|
|
114
|
+
children: [/* @__PURE__ */ u(n, {
|
|
115
|
+
projectId: S.id,
|
|
116
|
+
name: S.name,
|
|
117
|
+
status: S.status
|
|
118
|
+
}), /* @__PURE__ */ u(f, {
|
|
117
119
|
variant: "outline",
|
|
118
120
|
className: "capitalize",
|
|
119
|
-
children:
|
|
121
|
+
children: S.methodology.toLowerCase()
|
|
120
122
|
})]
|
|
121
123
|
})]
|
|
122
124
|
}),
|
|
123
|
-
/* @__PURE__ */
|
|
125
|
+
/* @__PURE__ */ d("div", {
|
|
124
126
|
className: "grid grid-cols-2 md:grid-cols-4 gap-4",
|
|
125
127
|
children: [
|
|
126
|
-
/* @__PURE__ */
|
|
128
|
+
/* @__PURE__ */ u(p, { children: /* @__PURE__ */ d(m, {
|
|
127
129
|
className: "pt-4",
|
|
128
|
-
children: [/* @__PURE__ */
|
|
130
|
+
children: [/* @__PURE__ */ d("div", {
|
|
129
131
|
className: "flex items-center gap-2 text-muted-foreground text-xs",
|
|
130
|
-
children: [/* @__PURE__ */
|
|
131
|
-
}), /* @__PURE__ */
|
|
132
|
+
children: [/* @__PURE__ */ u(i, { className: "h-4 w-4" }), "Work Items"]
|
|
133
|
+
}), /* @__PURE__ */ d("p", {
|
|
132
134
|
className: "text-xl font-bold mt-1",
|
|
133
135
|
children: [
|
|
134
|
-
|
|
136
|
+
k,
|
|
135
137
|
"/",
|
|
136
|
-
|
|
138
|
+
O
|
|
137
139
|
]
|
|
138
140
|
})]
|
|
139
141
|
}) }),
|
|
140
|
-
/* @__PURE__ */
|
|
142
|
+
/* @__PURE__ */ u(p, { children: /* @__PURE__ */ d(m, {
|
|
141
143
|
className: "pt-4",
|
|
142
|
-
children: [/* @__PURE__ */
|
|
144
|
+
children: [/* @__PURE__ */ d("div", {
|
|
143
145
|
className: "flex items-center gap-2 text-muted-foreground text-xs",
|
|
144
|
-
children: [/* @__PURE__ */
|
|
145
|
-
}), /* @__PURE__ */
|
|
146
|
+
children: [/* @__PURE__ */ u(s, { className: "h-4 w-4" }), "Sprints"]
|
|
147
|
+
}), /* @__PURE__ */ u("p", {
|
|
146
148
|
className: "text-xl font-bold mt-1",
|
|
147
|
-
children:
|
|
149
|
+
children: w.length
|
|
148
150
|
})]
|
|
149
151
|
}) }),
|
|
150
|
-
/* @__PURE__ */
|
|
152
|
+
/* @__PURE__ */ u(p, { children: /* @__PURE__ */ d(m, {
|
|
151
153
|
className: "pt-4",
|
|
152
|
-
children: [/* @__PURE__ */
|
|
154
|
+
children: [/* @__PURE__ */ d("div", {
|
|
153
155
|
className: "flex items-center gap-2 text-muted-foreground text-xs",
|
|
154
|
-
children: [/* @__PURE__ */
|
|
155
|
-
}), /* @__PURE__ */
|
|
156
|
+
children: [/* @__PURE__ */ u(r, { className: "h-4 w-4" }), "Milestones"]
|
|
157
|
+
}), /* @__PURE__ */ u("p", {
|
|
156
158
|
className: "text-xl font-bold mt-1",
|
|
157
|
-
children:
|
|
159
|
+
children: T.length
|
|
158
160
|
})]
|
|
159
161
|
}) }),
|
|
160
|
-
/* @__PURE__ */
|
|
162
|
+
/* @__PURE__ */ u(p, { children: /* @__PURE__ */ d(m, {
|
|
161
163
|
className: "pt-4",
|
|
162
|
-
children: [/* @__PURE__ */
|
|
164
|
+
children: [/* @__PURE__ */ d("div", {
|
|
163
165
|
className: "flex items-center gap-2 text-muted-foreground text-xs",
|
|
164
|
-
children: [/* @__PURE__ */
|
|
165
|
-
}), /* @__PURE__ */
|
|
166
|
+
children: [/* @__PURE__ */ u(o, { className: "h-4 w-4" }), "Owner"]
|
|
167
|
+
}), /* @__PURE__ */ u("p", {
|
|
166
168
|
className: "text-sm font-bold mt-1 truncate",
|
|
167
|
-
children: /* @__PURE__ */
|
|
169
|
+
children: /* @__PURE__ */ u(e, { id: S.ownerId })
|
|
168
170
|
})]
|
|
169
171
|
}) })
|
|
170
172
|
]
|
|
171
173
|
}),
|
|
172
|
-
/* @__PURE__ */
|
|
174
|
+
/* @__PURE__ */ d("div", {
|
|
173
175
|
className: "grid grid-cols-1 lg:grid-cols-3 gap-6",
|
|
174
|
-
children: [/* @__PURE__ */
|
|
176
|
+
children: [/* @__PURE__ */ d("div", {
|
|
175
177
|
className: "lg:col-span-2 space-y-6",
|
|
176
178
|
children: [
|
|
177
|
-
/* @__PURE__ */
|
|
178
|
-
/* @__PURE__ */
|
|
179
|
+
/* @__PURE__ */ d(p, { children: [/* @__PURE__ */ u(h, { children: /* @__PURE__ */ u(g, { children: "Timeline" }) }), /* @__PURE__ */ d(m, { children: [
|
|
180
|
+
/* @__PURE__ */ d("div", {
|
|
179
181
|
className: "flex justify-between text-sm mb-2",
|
|
180
|
-
children: [/* @__PURE__ */
|
|
182
|
+
children: [/* @__PURE__ */ u("span", {
|
|
181
183
|
className: "text-muted-foreground",
|
|
182
184
|
children: "Duration"
|
|
183
|
-
}), /* @__PURE__ */
|
|
185
|
+
}), /* @__PURE__ */ u("span", {
|
|
184
186
|
className: "font-medium",
|
|
185
|
-
children:
|
|
187
|
+
children: O > 0 ? `${Math.round(k / O * 100)}% tasks done` : "No tasks yet"
|
|
186
188
|
})]
|
|
187
189
|
}),
|
|
188
|
-
/* @__PURE__ */
|
|
190
|
+
/* @__PURE__ */ u("div", {
|
|
189
191
|
className: "w-full h-4 rounded-full bg-muted overflow-hidden",
|
|
190
|
-
children: /* @__PURE__ */
|
|
192
|
+
children: /* @__PURE__ */ u("div", {
|
|
191
193
|
className: "h-full bg-primary rounded-full",
|
|
192
|
-
style: { width: `${
|
|
194
|
+
style: { width: `${O > 0 ? Math.round(k / O * 100) : 0}%` }
|
|
193
195
|
})
|
|
194
196
|
}),
|
|
195
|
-
/* @__PURE__ */
|
|
197
|
+
/* @__PURE__ */ d("div", {
|
|
196
198
|
className: "flex justify-between text-xs text-muted-foreground mt-2",
|
|
197
|
-
children: [/* @__PURE__ */
|
|
199
|
+
children: [/* @__PURE__ */ u("span", { children: S.startDate ? new Date(S.startDate).toLocaleDateString() : "Not set" }), /* @__PURE__ */ u("span", { children: S.endDate ? new Date(S.endDate).toLocaleDateString() : "Not set" })]
|
|
198
200
|
})
|
|
199
201
|
] })] }),
|
|
200
|
-
|
|
202
|
+
E && /* @__PURE__ */ d(p, { children: [/* @__PURE__ */ u(h, { children: /* @__PURE__ */ d(g, {
|
|
201
203
|
className: "flex items-center gap-2",
|
|
202
|
-
children: [/* @__PURE__ */
|
|
203
|
-
}) }), /* @__PURE__ */
|
|
204
|
+
children: [/* @__PURE__ */ u(s, { className: "h-4 w-4 text-primary" }), "Active Sprint"]
|
|
205
|
+
}) }), /* @__PURE__ */ d(m, {
|
|
204
206
|
className: "space-y-3",
|
|
205
207
|
children: [
|
|
206
|
-
/* @__PURE__ */
|
|
208
|
+
/* @__PURE__ */ d("div", {
|
|
207
209
|
className: "flex justify-between",
|
|
208
|
-
children: [/* @__PURE__ */
|
|
210
|
+
children: [/* @__PURE__ */ u("span", {
|
|
209
211
|
className: "font-medium",
|
|
210
|
-
children:
|
|
211
|
-
}), /* @__PURE__ */
|
|
212
|
+
children: E.name
|
|
213
|
+
}), /* @__PURE__ */ u(f, { children: "Active" })]
|
|
212
214
|
}),
|
|
213
|
-
|
|
215
|
+
E.goal && /* @__PURE__ */ u("p", {
|
|
214
216
|
className: "text-sm text-muted-foreground",
|
|
215
|
-
children:
|
|
217
|
+
children: E.goal
|
|
216
218
|
}),
|
|
217
|
-
/* @__PURE__ */
|
|
219
|
+
/* @__PURE__ */ d("div", {
|
|
218
220
|
className: "grid grid-cols-3 gap-4 text-center",
|
|
219
221
|
children: [
|
|
220
|
-
/* @__PURE__ */
|
|
222
|
+
/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ d("p", {
|
|
221
223
|
className: "text-lg font-semibold",
|
|
222
224
|
children: [
|
|
223
|
-
|
|
225
|
+
E.workItems?.filter((e) => e.status === "DONE").reduce((e, t) => e + (t.storyPoints ?? 0), 0),
|
|
224
226
|
"/",
|
|
225
|
-
|
|
227
|
+
E.workItems?.reduce((e, t) => e + (t.storyPoints ?? 0), 0) ?? 0
|
|
226
228
|
]
|
|
227
|
-
}), /* @__PURE__ */
|
|
229
|
+
}), /* @__PURE__ */ u("p", {
|
|
228
230
|
className: "text-xs text-muted-foreground",
|
|
229
231
|
children: "Points"
|
|
230
232
|
})] }),
|
|
231
|
-
/* @__PURE__ */
|
|
233
|
+
/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ d("p", {
|
|
232
234
|
className: "text-lg font-semibold",
|
|
233
235
|
children: [
|
|
234
|
-
|
|
236
|
+
E.workItems?.filter((e) => e.status === "DONE").length ?? 0,
|
|
235
237
|
"/",
|
|
236
|
-
|
|
238
|
+
E.workItems?.length ?? 0
|
|
237
239
|
]
|
|
238
|
-
}), /* @__PURE__ */
|
|
240
|
+
}), /* @__PURE__ */ u("p", {
|
|
239
241
|
className: "text-xs text-muted-foreground",
|
|
240
242
|
children: "Tasks"
|
|
241
243
|
})] }),
|
|
242
|
-
/* @__PURE__ */
|
|
244
|
+
/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("p", {
|
|
243
245
|
className: "text-lg font-semibold",
|
|
244
|
-
children:
|
|
245
|
-
}), /* @__PURE__ */
|
|
246
|
+
children: D ? `${D.velocity} pts` : "—"
|
|
247
|
+
}), /* @__PURE__ */ u("p", {
|
|
246
248
|
className: "text-xs text-muted-foreground",
|
|
247
|
-
children: "Velocity"
|
|
249
|
+
children: "Velocity of the last sprint"
|
|
248
250
|
})] })
|
|
249
251
|
]
|
|
250
252
|
})
|
|
251
253
|
]
|
|
252
254
|
})] }),
|
|
253
|
-
/* @__PURE__ */
|
|
255
|
+
/* @__PURE__ */ d(p, { children: [/* @__PURE__ */ u(h, { children: /* @__PURE__ */ d(g, { children: [
|
|
254
256
|
"Recent Work Items (",
|
|
255
|
-
|
|
257
|
+
C.length,
|
|
256
258
|
")"
|
|
257
|
-
] }) }), /* @__PURE__ */
|
|
259
|
+
] }) }), /* @__PURE__ */ d(m, {
|
|
258
260
|
className: "space-y-2",
|
|
259
|
-
children: [
|
|
261
|
+
children: [C.slice(0, 5).map((e) => /* @__PURE__ */ d("div", {
|
|
260
262
|
className: "flex items-center justify-between border rounded-md p-2.5",
|
|
261
|
-
children: [/* @__PURE__ */
|
|
263
|
+
children: [/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("p", {
|
|
262
264
|
className: "text-sm font-medium",
|
|
263
265
|
children: e.key
|
|
264
|
-
}), /* @__PURE__ */
|
|
266
|
+
}), /* @__PURE__ */ u("div", {
|
|
265
267
|
className: "flex gap-1 mt-1",
|
|
266
|
-
children: e.labels.map((e) => /* @__PURE__ */
|
|
268
|
+
children: e.labels.map((e) => /* @__PURE__ */ u("span", {
|
|
267
269
|
className: "text-[10px] px-1.5 py-0.5 rounded bg-muted",
|
|
268
270
|
children: e
|
|
269
271
|
}, e))
|
|
270
|
-
})] }), /* @__PURE__ */
|
|
272
|
+
})] }), /* @__PURE__ */ d("div", {
|
|
271
273
|
className: "flex items-center gap-2",
|
|
272
|
-
children: [/* @__PURE__ */
|
|
274
|
+
children: [/* @__PURE__ */ d("span", {
|
|
273
275
|
className: "text-xs text-muted-foreground",
|
|
274
276
|
children: [e.storyPoints ?? 0, " pts"]
|
|
275
|
-
}), /* @__PURE__ */
|
|
277
|
+
}), /* @__PURE__ */ u(f, {
|
|
276
278
|
variant: "secondary",
|
|
277
279
|
className: "capitalize text-xs",
|
|
278
280
|
children: e.status.toLowerCase().replace("_", " ")
|
|
279
281
|
})]
|
|
280
282
|
})]
|
|
281
|
-
}, e.id)),
|
|
283
|
+
}, e.id)), C.length === 0 && /* @__PURE__ */ u("p", {
|
|
282
284
|
className: "text-sm text-muted-foreground text-center py-4",
|
|
283
285
|
children: "No work items yet."
|
|
284
286
|
})]
|
|
285
287
|
})] })
|
|
286
288
|
]
|
|
287
|
-
}), /* @__PURE__ */
|
|
289
|
+
}), /* @__PURE__ */ d("div", {
|
|
288
290
|
className: "space-y-6",
|
|
289
|
-
children: [/* @__PURE__ */
|
|
291
|
+
children: [/* @__PURE__ */ d(p, { children: [/* @__PURE__ */ u(h, { children: /* @__PURE__ */ d(g, { children: [
|
|
290
292
|
"Milestones (",
|
|
291
|
-
|
|
293
|
+
T.length,
|
|
292
294
|
")"
|
|
293
|
-
] }) }), /* @__PURE__ */
|
|
295
|
+
] }) }), /* @__PURE__ */ d(m, {
|
|
294
296
|
className: "space-y-3",
|
|
295
|
-
children: [
|
|
297
|
+
children: [T.map((e) => /* @__PURE__ */ d("div", {
|
|
296
298
|
className: "border-b pb-2 last:border-0",
|
|
297
|
-
children: [/* @__PURE__ */
|
|
299
|
+
children: [/* @__PURE__ */ d("div", {
|
|
298
300
|
className: "flex justify-between",
|
|
299
|
-
children: [/* @__PURE__ */
|
|
301
|
+
children: [/* @__PURE__ */ u("span", {
|
|
300
302
|
className: "text-sm font-medium",
|
|
301
303
|
children: e.name
|
|
302
|
-
}), /* @__PURE__ */
|
|
304
|
+
}), /* @__PURE__ */ u(f, {
|
|
303
305
|
variant: "outline",
|
|
304
306
|
className: "text-xs capitalize",
|
|
305
307
|
children: e.status.toLowerCase().replace("_", " ")
|
|
306
308
|
})]
|
|
307
|
-
}), /* @__PURE__ */
|
|
309
|
+
}), /* @__PURE__ */ d("div", {
|
|
308
310
|
className: "flex items-center gap-1 text-xs text-muted-foreground mt-1",
|
|
309
|
-
children: [/* @__PURE__ */
|
|
311
|
+
children: [/* @__PURE__ */ u(r, { className: "h-3 w-3" }), e.dueDate ? new Date(e.dueDate).toLocaleDateString() : "No due date"]
|
|
310
312
|
})]
|
|
311
|
-
}, e.id)),
|
|
313
|
+
}, e.id)), T.length === 0 && /* @__PURE__ */ u("p", {
|
|
312
314
|
className: "text-sm text-muted-foreground text-center py-2",
|
|
313
315
|
children: "No milestones."
|
|
314
316
|
})]
|
|
315
|
-
})] }), /* @__PURE__ */
|
|
317
|
+
})] }), /* @__PURE__ */ d(p, { children: [/* @__PURE__ */ u(h, { children: /* @__PURE__ */ u(g, { children: "Details" }) }), /* @__PURE__ */ d(m, {
|
|
316
318
|
className: "space-y-2 text-sm",
|
|
317
319
|
children: [
|
|
318
|
-
/* @__PURE__ */
|
|
320
|
+
/* @__PURE__ */ d("div", {
|
|
319
321
|
className: "flex justify-between",
|
|
320
|
-
children: [/* @__PURE__ */
|
|
322
|
+
children: [/* @__PURE__ */ u("span", {
|
|
321
323
|
className: "text-muted-foreground",
|
|
322
324
|
children: "Owner"
|
|
323
|
-
}), /* @__PURE__ */
|
|
325
|
+
}), /* @__PURE__ */ u("span", { children: /* @__PURE__ */ u(e, { id: S.ownerId }) })]
|
|
324
326
|
}),
|
|
325
|
-
/* @__PURE__ */
|
|
327
|
+
/* @__PURE__ */ d("div", {
|
|
326
328
|
className: "flex justify-between",
|
|
327
|
-
children: [/* @__PURE__ */
|
|
329
|
+
children: [/* @__PURE__ */ u("span", {
|
|
328
330
|
className: "text-muted-foreground",
|
|
329
331
|
children: "Key"
|
|
330
|
-
}), /* @__PURE__ */
|
|
332
|
+
}), /* @__PURE__ */ u("span", {
|
|
331
333
|
className: "font-mono",
|
|
332
|
-
children:
|
|
334
|
+
children: S.key
|
|
333
335
|
})]
|
|
334
336
|
}),
|
|
335
|
-
/* @__PURE__ */
|
|
337
|
+
/* @__PURE__ */ d("div", {
|
|
336
338
|
className: "flex justify-between",
|
|
337
|
-
children: [/* @__PURE__ */
|
|
339
|
+
children: [/* @__PURE__ */ u("span", {
|
|
338
340
|
className: "text-muted-foreground",
|
|
339
341
|
children: "Methodology"
|
|
340
|
-
}), /* @__PURE__ */
|
|
342
|
+
}), /* @__PURE__ */ u("span", {
|
|
341
343
|
className: "capitalize",
|
|
342
|
-
children:
|
|
344
|
+
children: S.methodology.toLowerCase()
|
|
343
345
|
})]
|
|
344
346
|
}),
|
|
345
|
-
|
|
347
|
+
S.tags.length > 0 && /* @__PURE__ */ d("div", {
|
|
346
348
|
className: "flex justify-between items-start",
|
|
347
|
-
children: [/* @__PURE__ */
|
|
349
|
+
children: [/* @__PURE__ */ u("span", {
|
|
348
350
|
className: "text-muted-foreground",
|
|
349
351
|
children: "Tags"
|
|
350
|
-
}), /* @__PURE__ */
|
|
352
|
+
}), /* @__PURE__ */ u("div", {
|
|
351
353
|
className: "flex gap-1 flex-wrap justify-end",
|
|
352
|
-
children:
|
|
354
|
+
children: S.tags.map((e) => /* @__PURE__ */ u(f, {
|
|
353
355
|
variant: "outline",
|
|
354
356
|
className: "text-xs",
|
|
355
357
|
children: e
|
|
@@ -364,6 +366,6 @@ function v() {
|
|
|
364
366
|
});
|
|
365
367
|
}
|
|
366
368
|
//#endregion
|
|
367
|
-
export {
|
|
369
|
+
export { y as ProjectsProjectDetailPagePage };
|
|
368
370
|
|
|
369
371
|
//# sourceMappingURL=ProjectsProjectDetailPagePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectsProjectDetailPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProjectsProjectDetailPagePage.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 { FolderKanban, CheckSquare, Users, Zap, Calendar } from 'lucide-react';\nimport { useEntityId } from '../hooks/useEntityId';\nimport { PersonName } from '../people/People';\n\nconst GET_PROJECT_DETAIL = gql`\n query GetProjectDetail($id: ID!) {\n planmagnetProject(id: $id) {\n id\n name\n key\n description\n status\n methodology\n ownerId\n startDate\n endDate\n tags\n createdAt\n sprints {\n id\n name\n status\n goal\n capacity\n velocity\n startDate\n endDate\n workItems {\n id\n status\n storyPoints\n }\n }\n milestones {\n id\n name\n description\n status\n dueDate\n ownerId\n }\n workItems {\n id\n key\n description\n status\n priority\n storyPoints\n assigneeId\n labels\n createdAt\n }\n }\n }\n`;\n\nconst statusColor: Record<string, string> = {\n ACTIVE: 'bg-green-100 text-green-800',\n ON_HOLD: 'bg-orange-100 text-orange-800',\n CANCELLED: 'bg-red-100 text-red-800',\n COMPLETED: 'bg-blue-100 text-blue-800',\n PLANNING: 'bg-gray-100 text-gray-800',\n ARCHIVED: 'bg-gray-100 text-gray-800',\n};\n\nexport function ProjectsProjectDetailPagePage() {\n const projectId = useEntityId('projectId');\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_PROJECT_DETAIL, {\n variables: { id: projectId },\n skip: !projectId,\n });\n\n if (!projectId)\n return (\n <div className=\"p-6 text-muted-foreground\">No project selected. Open one from the list.</div>\n );\n // Only before the first load: a refetch must not blank the page (it\n // unmounts every component on it and loses their state).\n if (loading && !data)\n return (\n <div className=\"flex items-center justify-center p-12\">\n <div className=\"animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full\" />\n </div>\n );\n if (error) return <div className=\"p-6 text-red-500\">Error loading project: {error.message}</div>;\n\n const project = data?.planmagnetProject;\n if (!project) return <div className=\"p-6 text-muted-foreground\">Project not found.</div>;\n\n const projectWorkItems = project.workItems ?? [];\n const projectSprints = project.sprints ?? [];\n const projectMilestones = project.milestones ?? [];\n const activeSprint = projectSprints.find((s: { status: string }) => s.status === 'ACTIVE');\n const totalTasks = projectWorkItems.length;\n const completedTasks = projectWorkItems.filter(\n (wi: { status: string }) => wi.status === 'DONE'\n ).length;\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"flex items-center gap-2\">\n <FolderKanban className=\"h-5 w-5 text-primary\" />\n <h1 className=\"text-2xl font-semibold\">{project.name}</h1>\n <span\n className={`text-xs px-2 py-0.5 rounded-full capitalize ${statusColor[project.status] ?? 'bg-gray-100'}`}\n >\n {project.status.toLowerCase().replace('_', ' ')}\n </span>\n </div>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {project.description ?? 'No description'}\n </p>\n </div>\n <div className=\"flex gap-2\">\n <Badge className=\"capitalize\">{project.status.toLowerCase().replace('_', ' ')}</Badge>\n <Badge variant=\"outline\" className=\"capitalize\">\n {project.methodology.toLowerCase()}\n </Badge>\n </div>\n </div>\n\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <CheckSquare className=\"h-4 w-4\" />\n Work Items\n </div>\n <p className=\"text-xl font-bold mt-1\">\n {completedTasks}/{totalTasks}\n </p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <Zap className=\"h-4 w-4\" />\n Sprints\n </div>\n <p className=\"text-xl font-bold mt-1\">{projectSprints.length}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <Calendar className=\"h-4 w-4\" />\n Milestones\n </div>\n <p className=\"text-xl font-bold mt-1\">{projectMilestones.length}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <Users className=\"h-4 w-4\" />\n Owner\n </div>\n <p className=\"text-sm font-bold mt-1 truncate\">\n <PersonName id={project.ownerId} />\n </p>\n </CardContent>\n </Card>\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>Timeline</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"flex justify-between text-sm mb-2\">\n <span className=\"text-muted-foreground\">Duration</span>\n <span className=\"font-medium\">\n {totalTasks > 0\n ? `${Math.round((completedTasks / totalTasks) * 100)}% tasks done`\n : 'No tasks yet'}\n </span>\n </div>\n <div className=\"w-full h-4 rounded-full bg-muted overflow-hidden\">\n <div\n className=\"h-full bg-primary rounded-full\"\n style={{\n width: `${totalTasks > 0 ? Math.round((completedTasks / totalTasks) * 100) : 0}%`,\n }}\n />\n </div>\n <div className=\"flex justify-between text-xs text-muted-foreground mt-2\">\n <span>\n {project.startDate ? new Date(project.startDate).toLocaleDateString() : 'Not set'}\n </span>\n <span>\n {project.endDate ? new Date(project.endDate).toLocaleDateString() : 'Not set'}\n </span>\n </div>\n </CardContent>\n </Card>\n\n {activeSprint && (\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Zap className=\"h-4 w-4 text-primary\" />\n Active Sprint\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <div className=\"flex justify-between\">\n <span className=\"font-medium\">{activeSprint.name}</span>\n <Badge>Active</Badge>\n </div>\n {activeSprint.goal && (\n <p className=\"text-sm text-muted-foreground\">{activeSprint.goal}</p>\n )}\n <div className=\"grid grid-cols-3 gap-4 text-center\">\n <div>\n <p className=\"text-lg font-semibold\">\n {activeSprint.workItems\n ?.filter((wi: { status: string }) => wi.status === 'DONE')\n .reduce(\n (s: number, wi: { storyPoints: number | null }) =>\n s + (wi.storyPoints ?? 0),\n 0\n )}\n /\n {activeSprint.workItems?.reduce(\n (s: number, wi: { storyPoints: number | null }) =>\n s + (wi.storyPoints ?? 0),\n 0\n ) ?? 0}\n </p>\n <p className=\"text-xs text-muted-foreground\">Points</p>\n </div>\n <div>\n <p className=\"text-lg font-semibold\">\n {activeSprint.workItems?.filter(\n (wi: { status: string }) => wi.status === 'DONE'\n ).length ?? 0}\n /{activeSprint.workItems?.length ?? 0}\n </p>\n <p className=\"text-xs text-muted-foreground\">Tasks</p>\n </div>\n <div>\n <p className=\"text-lg font-semibold\">{activeSprint.velocity ?? 0}</p>\n <p className=\"text-xs text-muted-foreground\">Velocity</p>\n </div>\n </div>\n </CardContent>\n </Card>\n )}\n\n <Card>\n <CardHeader>\n <CardTitle>Recent Work Items ({projectWorkItems.length})</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n {projectWorkItems\n .slice(0, 5)\n .map(\n (task: {\n id: string;\n key: string;\n description: string | null;\n status: string;\n storyPoints: number | null;\n labels: string[];\n }) => (\n <div\n key={task.id}\n className=\"flex items-center justify-between border rounded-md p-2.5\"\n >\n <div>\n <p className=\"text-sm font-medium\">{task.key}</p>\n <div className=\"flex gap-1 mt-1\">\n {task.labels.map((l: string) => (\n <span key={l} className=\"text-[10px] px-1.5 py-0.5 rounded bg-muted\">\n {l}\n </span>\n ))}\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs text-muted-foreground\">\n {task.storyPoints ?? 0} pts\n </span>\n <Badge variant=\"secondary\" className=\"capitalize text-xs\">\n {task.status.toLowerCase().replace('_', ' ')}\n </Badge>\n </div>\n </div>\n )\n )}\n {projectWorkItems.length === 0 && (\n <p className=\"text-sm text-muted-foreground text-center py-4\">No work items yet.</p>\n )}\n </CardContent>\n </Card>\n </div>\n\n <div className=\"space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle>Milestones ({projectMilestones.length})</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {projectMilestones.map(\n (ms: { id: string; name: string; status: string; dueDate: string | null }) => (\n <div key={ms.id} className=\"border-b pb-2 last:border-0\">\n <div className=\"flex justify-between\">\n <span className=\"text-sm font-medium\">{ms.name}</span>\n <Badge variant=\"outline\" className=\"text-xs capitalize\">\n {ms.status.toLowerCase().replace('_', ' ')}\n </Badge>\n </div>\n <div className=\"flex items-center gap-1 text-xs text-muted-foreground mt-1\">\n <Calendar className=\"h-3 w-3\" />\n {ms.dueDate ? new Date(ms.dueDate).toLocaleDateString() : 'No due date'}\n </div>\n </div>\n )\n )}\n {projectMilestones.length === 0 && (\n <p className=\"text-sm text-muted-foreground text-center py-2\">No milestones.</p>\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\">Owner</span>\n <span>\n <PersonName id={project.ownerId} />\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Key</span>\n <span className=\"font-mono\">{project.key}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Methodology</span>\n <span className=\"capitalize\">{project.methodology.toLowerCase()}</span>\n </div>\n {project.tags.length > 0 && (\n <div className=\"flex justify-between items-start\">\n <span className=\"text-muted-foreground\">Tags</span>\n <div className=\"flex gap-1 flex-wrap justify-end\">\n {project.tags.map((tag: string) => (\n <Badge key={tag} variant=\"outline\" className=\"text-xs\">\n {tag}\n </Badge>\n ))}\n </div>\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ProjectsProjectDetailPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProjectsProjectDetailPagePage.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 { FolderKanban, CheckSquare, Users, Zap, Calendar } from 'lucide-react';\nimport { useEntityId } from '../hooks/useEntityId';\nimport { PersonName } from '../people/People';\nimport { ProjectHeaderActions } from '../controls/ProjectControls';\n\nconst GET_PROJECT_DETAIL = gql`\n query GetProjectDetail($id: ID!) {\n planmagnetProject(id: $id) {\n id\n name\n key\n description\n status\n methodology\n ownerId\n startDate\n endDate\n tags\n createdAt\n sprints {\n id\n name\n status\n goal\n capacity\n velocity\n startDate\n endDate\n workItems {\n id\n status\n storyPoints\n }\n }\n milestones {\n id\n name\n description\n status\n dueDate\n ownerId\n }\n workItems {\n id\n key\n description\n status\n priority\n storyPoints\n assigneeId\n labels\n createdAt\n }\n }\n }\n`;\n\nconst statusColor: Record<string, string> = {\n ACTIVE: 'bg-green-100 text-green-800',\n ON_HOLD: 'bg-orange-100 text-orange-800',\n CANCELLED: 'bg-red-100 text-red-800',\n COMPLETED: 'bg-blue-100 text-blue-800',\n PLANNING: 'bg-gray-100 text-gray-800',\n ARCHIVED: 'bg-gray-100 text-gray-800',\n};\n\nexport function ProjectsProjectDetailPagePage() {\n const projectId = useEntityId('projectId');\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_PROJECT_DETAIL, {\n variables: { id: projectId },\n skip: !projectId,\n });\n\n if (!projectId)\n return (\n <div className=\"p-6 text-muted-foreground\">No project selected. Open one from the list.</div>\n );\n // Only before the first load: a refetch must not blank the page (it\n // unmounts every component on it and loses their state).\n if (loading && !data)\n return (\n <div className=\"flex items-center justify-center p-12\">\n <div className=\"animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full\" />\n </div>\n );\n if (error) return <div className=\"p-6 text-red-500\">Error loading project: {error.message}</div>;\n\n const project = data?.planmagnetProject;\n if (!project) return <div className=\"p-6 text-muted-foreground\">Project not found.</div>;\n\n const projectWorkItems = project.workItems ?? [];\n const projectSprints = project.sprints ?? [];\n const projectMilestones = project.milestones ?? [];\n const activeSprint = projectSprints.find((s: { status: string }) => s.status === 'ACTIVE');\n // Velocity exists only for a COMPLETED sprint (BOFF-7944: this tile read the running sprint's velocity, which is\n // never set, so it always showed 0). Show the latest completed sprint's instead.\n const lastCompleted = projectSprints\n .filter(\n (s: { status: string; velocity: number | null }) =>\n s.status === 'COMPLETED' && s.velocity != null\n )\n .sort((a: { endDate: string | null }, b: { endDate: string | null }) =>\n (b.endDate ?? '').localeCompare(a.endDate ?? '')\n )[0];\n const totalTasks = projectWorkItems.length;\n const completedTasks = projectWorkItems.filter(\n (wi: { status: string }) => wi.status === 'DONE'\n ).length;\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"flex items-center gap-2\">\n <FolderKanban className=\"h-5 w-5 text-primary\" />\n <h1 className=\"text-2xl font-semibold\">{project.name}</h1>\n <span\n className={`text-xs px-2 py-0.5 rounded-full capitalize ${statusColor[project.status] ?? 'bg-gray-100'}`}\n >\n {project.status.toLowerCase().replace('_', ' ')}\n </span>\n </div>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {project.description ?? 'No description'}\n </p>\n </div>\n <div className=\"flex flex-col items-end gap-2\">\n {/* Status, Edit and Delete (BOFF-7940): a project could never leave PLANNING from the UI. */}\n <ProjectHeaderActions\n projectId={project.id}\n name={project.name}\n status={project.status}\n />\n <Badge variant=\"outline\" className=\"capitalize\">\n {project.methodology.toLowerCase()}\n </Badge>\n </div>\n </div>\n\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <CheckSquare className=\"h-4 w-4\" />\n Work Items\n </div>\n <p className=\"text-xl font-bold mt-1\">\n {completedTasks}/{totalTasks}\n </p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <Zap className=\"h-4 w-4\" />\n Sprints\n </div>\n <p className=\"text-xl font-bold mt-1\">{projectSprints.length}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <Calendar className=\"h-4 w-4\" />\n Milestones\n </div>\n <p className=\"text-xl font-bold mt-1\">{projectMilestones.length}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <Users className=\"h-4 w-4\" />\n Owner\n </div>\n <p className=\"text-sm font-bold mt-1 truncate\">\n <PersonName id={project.ownerId} />\n </p>\n </CardContent>\n </Card>\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>Timeline</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"flex justify-between text-sm mb-2\">\n <span className=\"text-muted-foreground\">Duration</span>\n <span className=\"font-medium\">\n {totalTasks > 0\n ? `${Math.round((completedTasks / totalTasks) * 100)}% tasks done`\n : 'No tasks yet'}\n </span>\n </div>\n <div className=\"w-full h-4 rounded-full bg-muted overflow-hidden\">\n <div\n className=\"h-full bg-primary rounded-full\"\n style={{\n width: `${totalTasks > 0 ? Math.round((completedTasks / totalTasks) * 100) : 0}%`,\n }}\n />\n </div>\n <div className=\"flex justify-between text-xs text-muted-foreground mt-2\">\n <span>\n {project.startDate ? new Date(project.startDate).toLocaleDateString() : 'Not set'}\n </span>\n <span>\n {project.endDate ? new Date(project.endDate).toLocaleDateString() : 'Not set'}\n </span>\n </div>\n </CardContent>\n </Card>\n\n {activeSprint && (\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Zap className=\"h-4 w-4 text-primary\" />\n Active Sprint\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <div className=\"flex justify-between\">\n <span className=\"font-medium\">{activeSprint.name}</span>\n <Badge>Active</Badge>\n </div>\n {activeSprint.goal && (\n <p className=\"text-sm text-muted-foreground\">{activeSprint.goal}</p>\n )}\n <div className=\"grid grid-cols-3 gap-4 text-center\">\n <div>\n <p className=\"text-lg font-semibold\">\n {activeSprint.workItems\n ?.filter((wi: { status: string }) => wi.status === 'DONE')\n .reduce(\n (s: number, wi: { storyPoints: number | null }) =>\n s + (wi.storyPoints ?? 0),\n 0\n )}\n /\n {activeSprint.workItems?.reduce(\n (s: number, wi: { storyPoints: number | null }) =>\n s + (wi.storyPoints ?? 0),\n 0\n ) ?? 0}\n </p>\n <p className=\"text-xs text-muted-foreground\">Points</p>\n </div>\n <div>\n <p className=\"text-lg font-semibold\">\n {activeSprint.workItems?.filter(\n (wi: { status: string }) => wi.status === 'DONE'\n ).length ?? 0}\n /{activeSprint.workItems?.length ?? 0}\n </p>\n <p className=\"text-xs text-muted-foreground\">Tasks</p>\n </div>\n <div>\n <p className=\"text-lg font-semibold\">\n {lastCompleted ? `${lastCompleted.velocity} pts` : '—'}\n </p>\n <p className=\"text-xs text-muted-foreground\">Velocity of the last sprint</p>\n </div>\n </div>\n </CardContent>\n </Card>\n )}\n\n <Card>\n <CardHeader>\n <CardTitle>Recent Work Items ({projectWorkItems.length})</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n {projectWorkItems\n .slice(0, 5)\n .map(\n (task: {\n id: string;\n key: string;\n description: string | null;\n status: string;\n storyPoints: number | null;\n labels: string[];\n }) => (\n <div\n key={task.id}\n className=\"flex items-center justify-between border rounded-md p-2.5\"\n >\n <div>\n <p className=\"text-sm font-medium\">{task.key}</p>\n <div className=\"flex gap-1 mt-1\">\n {task.labels.map((l: string) => (\n <span key={l} className=\"text-[10px] px-1.5 py-0.5 rounded bg-muted\">\n {l}\n </span>\n ))}\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs text-muted-foreground\">\n {task.storyPoints ?? 0} pts\n </span>\n <Badge variant=\"secondary\" className=\"capitalize text-xs\">\n {task.status.toLowerCase().replace('_', ' ')}\n </Badge>\n </div>\n </div>\n )\n )}\n {projectWorkItems.length === 0 && (\n <p className=\"text-sm text-muted-foreground text-center py-4\">No work items yet.</p>\n )}\n </CardContent>\n </Card>\n </div>\n\n <div className=\"space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle>Milestones ({projectMilestones.length})</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {projectMilestones.map(\n (ms: { id: string; name: string; status: string; dueDate: string | null }) => (\n <div key={ms.id} className=\"border-b pb-2 last:border-0\">\n <div className=\"flex justify-between\">\n <span className=\"text-sm font-medium\">{ms.name}</span>\n <Badge variant=\"outline\" className=\"text-xs capitalize\">\n {ms.status.toLowerCase().replace('_', ' ')}\n </Badge>\n </div>\n <div className=\"flex items-center gap-1 text-xs text-muted-foreground mt-1\">\n <Calendar className=\"h-3 w-3\" />\n {ms.dueDate ? new Date(ms.dueDate).toLocaleDateString() : 'No due date'}\n </div>\n </div>\n )\n )}\n {projectMilestones.length === 0 && (\n <p className=\"text-sm text-muted-foreground text-center py-2\">No milestones.</p>\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\">Owner</span>\n <span>\n <PersonName id={project.ownerId} />\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Key</span>\n <span className=\"font-mono\">{project.key}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Methodology</span>\n <span className=\"capitalize\">{project.methodology.toLowerCase()}</span>\n </div>\n {project.tags.length > 0 && (\n <div className=\"flex justify-between items-start\">\n <span className=\"text-muted-foreground\">Tags</span>\n <div className=\"flex gap-1 flex-wrap justify-end\">\n {project.tags.map((tag: string) => (\n <Badge key={tag} variant=\"outline\" className=\"text-xs\">\n {tag}\n </Badge>\n ))}\n </div>\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SprintsStartSprintPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/SprintsStartSprintPagePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SprintsStartSprintPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/SprintsStartSprintPagePage.tsx"],"names":[],"mappings":"AAsGA,wBAAgB,0BAA0B,4CAkQzC"}
|
|
@@ -49,14 +49,14 @@ var v = l`
|
|
|
49
49
|
}
|
|
50
50
|
`;
|
|
51
51
|
function y(e) {
|
|
52
|
-
let t = e.workItems ?? []
|
|
52
|
+
let t = e.workItems ?? [];
|
|
53
53
|
return {
|
|
54
|
-
totalPoints:
|
|
55
|
-
completedPoints:
|
|
54
|
+
totalPoints: t.reduce((e, t) => e + (t.storyPoints ?? 0), 0),
|
|
55
|
+
completedPoints: t.filter((e) => e.status === "DONE").reduce((e, t) => e + (t.storyPoints ?? 0), 0),
|
|
56
56
|
tasksTotal: t.length,
|
|
57
57
|
tasksCompleted: t.filter((e) => e.status === "DONE").length,
|
|
58
58
|
teamMemberIds: Array.from(new Set(t.map((e) => e.assigneeId).filter((e) => !!e))),
|
|
59
|
-
velocity: e.velocity
|
|
59
|
+
velocity: e.velocity
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
62
|
function b() {
|
|
@@ -173,9 +173,10 @@ function b() {
|
|
|
173
173
|
className: "p-3 bg-muted rounded-md",
|
|
174
174
|
children: [/* @__PURE__ */ d("p", {
|
|
175
175
|
className: "text-lg font-bold",
|
|
176
|
-
children: t.velocity
|
|
176
|
+
children: t.velocity == null ? "—" : t.velocity
|
|
177
177
|
}), /* @__PURE__ */ d("p", {
|
|
178
178
|
className: "text-xs text-muted-foreground",
|
|
179
|
+
title: "Story points done when the sprint was completed",
|
|
179
180
|
children: "Velocity"
|
|
180
181
|
})]
|
|
181
182
|
})
|