@burdenoff/microfe-planmagnet 2026.731.1 → 2026.731.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/generated/wspace-operations.d.ts +54 -0
- package/dist/generated/wspace-operations.d.ts.map +1 -1
- package/dist/generated/wspace-types.d.ts +35 -0
- package/dist/generated/wspace-types.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js +101 -47
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectsPlanningDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProjectsPlanningDetailPagePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ProjectsPlanningDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProjectsPlanningDetailPagePage.tsx"],"names":[],"mappings":"AA0DA,wBAAgB,8BAA8B,4CAwO7C"}
|
|
@@ -29,48 +29,77 @@ var m = a`
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
+
`, h = a`
|
|
33
|
+
query GetSprintCapacity($sprintId: ID!) {
|
|
34
|
+
planmagnetSprintCapacity(sprintId: $sprintId) {
|
|
35
|
+
sprintId
|
|
36
|
+
crewfoundryUnavailable
|
|
37
|
+
unmatchedAssigneeIds
|
|
38
|
+
members {
|
|
39
|
+
actorId
|
|
40
|
+
employeeName
|
|
41
|
+
department
|
|
42
|
+
position
|
|
43
|
+
allocatedHours
|
|
44
|
+
billableHours
|
|
45
|
+
utilizationPercent
|
|
46
|
+
assignedStoryPoints
|
|
47
|
+
assignedWorkItemCount
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
32
51
|
`;
|
|
33
|
-
function
|
|
34
|
-
let { workspaceId: a } = e(), { data:
|
|
35
|
-
|
|
52
|
+
function g() {
|
|
53
|
+
let { workspaceId: a } = e(), { data: g, loading: _, error: v } = o(m, { variables: { workspaceId: a ?? "default" } }), y = g?.planmagnetSprints?.items?.[0]?.id, { data: b } = o(h, {
|
|
54
|
+
variables: { sprintId: y },
|
|
55
|
+
skip: !y
|
|
56
|
+
});
|
|
57
|
+
if (_) return /* @__PURE__ */ s("div", {
|
|
36
58
|
className: "flex items-center justify-center p-12",
|
|
37
59
|
children: /* @__PURE__ */ s("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
|
|
38
60
|
});
|
|
39
|
-
if (
|
|
61
|
+
if (v) return /* @__PURE__ */ c("div", {
|
|
40
62
|
className: "p-6 text-red-500",
|
|
41
|
-
children: ["Error loading planning session: ",
|
|
63
|
+
children: ["Error loading planning session: ", v.message]
|
|
42
64
|
});
|
|
43
|
-
let
|
|
44
|
-
if (!
|
|
65
|
+
let x = g?.planmagnetSprints?.items?.[0];
|
|
66
|
+
if (!x) return /* @__PURE__ */ s("div", {
|
|
45
67
|
className: "p-6 text-muted-foreground",
|
|
46
68
|
children: "Planning session not found."
|
|
47
69
|
});
|
|
48
|
-
let
|
|
49
|
-
|
|
50
|
-
|
|
70
|
+
let S = b?.planmagnetSprintCapacity, C = {};
|
|
71
|
+
for (let e of S?.members ?? []) C[e.actorId] = {
|
|
72
|
+
employeeName: e.employeeName,
|
|
73
|
+
allocatedHours: e.allocatedHours,
|
|
74
|
+
billableHours: e.billableHours,
|
|
75
|
+
utilizationPercent: e.utilizationPercent
|
|
76
|
+
};
|
|
77
|
+
let w = x.workItems ?? [], T = w.reduce((e, t) => e + (t.storyPoints ?? 0), 0);
|
|
78
|
+
w.filter((e) => e.status === "DONE").reduce((e, t) => e + (t.storyPoints ?? 0), 0);
|
|
79
|
+
let E = x.capacity ?? T, D = E > 0 ? Math.round(T / E * 100) : 0, O = E - T, k = [...new Set(w.map((e) => e.assigneeId).filter(Boolean))];
|
|
51
80
|
return /* @__PURE__ */ c("div", {
|
|
52
81
|
className: "space-y-6 p-6",
|
|
53
82
|
children: [/* @__PURE__ */ c("div", {
|
|
54
83
|
className: "flex items-center justify-between",
|
|
55
84
|
children: [/* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s("h1", {
|
|
56
85
|
className: "text-2xl font-semibold",
|
|
57
|
-
children:
|
|
86
|
+
children: x.name
|
|
58
87
|
}), /* @__PURE__ */ c("p", {
|
|
59
88
|
className: "text-sm text-muted-foreground",
|
|
60
89
|
children: [
|
|
61
|
-
|
|
90
|
+
x.projectId,
|
|
62
91
|
" ·",
|
|
63
92
|
" ",
|
|
64
|
-
|
|
93
|
+
x.startDate ? new Date(x.startDate).toLocaleDateString() : "—",
|
|
65
94
|
" -",
|
|
66
95
|
" ",
|
|
67
|
-
|
|
96
|
+
x.endDate ? new Date(x.endDate).toLocaleDateString() : "—"
|
|
68
97
|
]
|
|
69
98
|
})] }), /* @__PURE__ */ s("div", {
|
|
70
99
|
className: "flex gap-2",
|
|
71
100
|
children: /* @__PURE__ */ s(l, {
|
|
72
101
|
className: "capitalize",
|
|
73
|
-
children:
|
|
102
|
+
children: x.status.toLowerCase().replace("_", " ")
|
|
74
103
|
})
|
|
75
104
|
})]
|
|
76
105
|
}), /* @__PURE__ */ c("div", {
|
|
@@ -86,7 +115,7 @@ function h() {
|
|
|
86
115
|
className: "p-4 bg-muted rounded-md",
|
|
87
116
|
children: [/* @__PURE__ */ s("p", {
|
|
88
117
|
className: "text-2xl font-bold",
|
|
89
|
-
children:
|
|
118
|
+
children: E
|
|
90
119
|
}), /* @__PURE__ */ s("p", {
|
|
91
120
|
className: "text-xs text-muted-foreground",
|
|
92
121
|
children: "Capacity"
|
|
@@ -96,7 +125,7 @@ function h() {
|
|
|
96
125
|
className: "p-4 bg-primary/10 rounded-md",
|
|
97
126
|
children: [/* @__PURE__ */ s("p", {
|
|
98
127
|
className: "text-2xl font-bold text-primary",
|
|
99
|
-
children:
|
|
128
|
+
children: T
|
|
100
129
|
}), /* @__PURE__ */ s("p", {
|
|
101
130
|
className: "text-xs text-muted-foreground",
|
|
102
131
|
children: "Allocated"
|
|
@@ -106,7 +135,7 @@ function h() {
|
|
|
106
135
|
className: "p-4 bg-muted rounded-md",
|
|
107
136
|
children: [/* @__PURE__ */ s("p", {
|
|
108
137
|
className: "text-2xl font-bold",
|
|
109
|
-
children:
|
|
138
|
+
children: O > 0 ? O : 0
|
|
110
139
|
}), /* @__PURE__ */ s("p", {
|
|
111
140
|
className: "text-xs text-muted-foreground",
|
|
112
141
|
children: "Remaining"
|
|
@@ -120,35 +149,60 @@ function h() {
|
|
|
120
149
|
children: "Utilization"
|
|
121
150
|
}), /* @__PURE__ */ c("span", {
|
|
122
151
|
className: "font-medium",
|
|
123
|
-
children: [
|
|
152
|
+
children: [D, "%"]
|
|
124
153
|
})]
|
|
125
154
|
}), /* @__PURE__ */ s("div", {
|
|
126
155
|
className: "w-full h-4 rounded-full bg-muted overflow-hidden",
|
|
127
156
|
children: /* @__PURE__ */ s("div", {
|
|
128
|
-
className: `h-full rounded-full ${
|
|
129
|
-
style: { width: `${Math.min(
|
|
157
|
+
className: `h-full rounded-full ${D > 90 ? "bg-red-400" : "bg-green-400"}`,
|
|
158
|
+
style: { width: `${Math.min(D, 100)}%` }
|
|
130
159
|
})
|
|
131
160
|
})] })]
|
|
132
161
|
})] }), /* @__PURE__ */ c(u, { children: [/* @__PURE__ */ s(f, { children: /* @__PURE__ */ c(p, { children: [
|
|
133
162
|
"Team Members (",
|
|
134
|
-
|
|
163
|
+
k.length,
|
|
135
164
|
")"
|
|
136
|
-
] }) }), /* @__PURE__ */
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
165
|
+
] }) }), /* @__PURE__ */ c(d, { children: [
|
|
166
|
+
/* @__PURE__ */ c("div", {
|
|
167
|
+
className: "grid grid-cols-2 gap-3",
|
|
168
|
+
children: [k.map((e) => {
|
|
169
|
+
let t = C[e];
|
|
170
|
+
return /* @__PURE__ */ c("div", {
|
|
171
|
+
className: "flex items-center gap-2 border rounded-md p-2.5",
|
|
172
|
+
children: [/* @__PURE__ */ s("div", {
|
|
173
|
+
className: "h-8 w-8 rounded-full bg-primary/10 flex items-center justify-center text-xs font-medium text-primary",
|
|
174
|
+
children: e.slice(0, 2).toUpperCase()
|
|
175
|
+
}), /* @__PURE__ */ c("div", {
|
|
176
|
+
className: "min-w-0",
|
|
177
|
+
children: [/* @__PURE__ */ s("span", {
|
|
178
|
+
className: "text-sm truncate block",
|
|
179
|
+
children: t?.employeeName ?? e
|
|
180
|
+
}), t && /* @__PURE__ */ c("span", {
|
|
181
|
+
className: "text-xs text-muted-foreground",
|
|
182
|
+
children: [
|
|
183
|
+
t.allocatedHours,
|
|
184
|
+
"h allocated (",
|
|
185
|
+
t.billableHours,
|
|
186
|
+
"h billable)",
|
|
187
|
+
t.utilizationPercent != null && ` · ${t.utilizationPercent}% util`
|
|
188
|
+
]
|
|
189
|
+
})]
|
|
190
|
+
})]
|
|
191
|
+
}, e);
|
|
192
|
+
}), k.length === 0 && /* @__PURE__ */ s("p", {
|
|
193
|
+
className: "text-sm text-muted-foreground col-span-2 text-center py-4",
|
|
194
|
+
children: "No team members assigned."
|
|
146
195
|
})]
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
196
|
+
}),
|
|
197
|
+
S?.crewfoundryUnavailable && k.length > 0 && /* @__PURE__ */ s("p", {
|
|
198
|
+
className: "text-xs text-muted-foreground mt-3 border-t pt-3",
|
|
199
|
+
children: "Workforce allocation from CrewFoundry is unavailable for this workspace — no CrewFoundry module provisioned yet."
|
|
200
|
+
}),
|
|
201
|
+
!S?.crewfoundryUnavailable && (S?.unmatchedAssigneeIds?.length ?? 0) > 0 && /* @__PURE__ */ c("p", {
|
|
202
|
+
className: "text-xs text-muted-foreground mt-3 border-t pt-3",
|
|
203
|
+
children: [S.unmatchedAssigneeIds.length, " assignee(s) have no matching CrewFoundry employee record — allocation hours shown only for matched employees."]
|
|
204
|
+
})
|
|
205
|
+
] })] })]
|
|
152
206
|
}), /* @__PURE__ */ c(u, { children: [/* @__PURE__ */ s(f, { children: /* @__PURE__ */ s(p, { children: "Session Info" }) }), /* @__PURE__ */ c(d, {
|
|
153
207
|
className: "space-y-3 text-sm",
|
|
154
208
|
children: [
|
|
@@ -162,7 +216,7 @@ function h() {
|
|
|
162
216
|
}),
|
|
163
217
|
/* @__PURE__ */ s("span", {
|
|
164
218
|
className: "font-medium",
|
|
165
|
-
children:
|
|
219
|
+
children: x.projectId
|
|
166
220
|
})
|
|
167
221
|
]
|
|
168
222
|
}),
|
|
@@ -176,7 +230,7 @@ function h() {
|
|
|
176
230
|
}),
|
|
177
231
|
/* @__PURE__ */ s("span", {
|
|
178
232
|
className: "font-medium",
|
|
179
|
-
children:
|
|
233
|
+
children: x.startDate ? new Date(x.startDate).toLocaleDateString() : "Not set"
|
|
180
234
|
})
|
|
181
235
|
]
|
|
182
236
|
}),
|
|
@@ -190,7 +244,7 @@ function h() {
|
|
|
190
244
|
}),
|
|
191
245
|
/* @__PURE__ */ s("span", {
|
|
192
246
|
className: "font-medium",
|
|
193
|
-
children:
|
|
247
|
+
children: x.endDate ? new Date(x.endDate).toLocaleDateString() : "Not set"
|
|
194
248
|
})
|
|
195
249
|
]
|
|
196
250
|
}),
|
|
@@ -204,7 +258,7 @@ function h() {
|
|
|
204
258
|
}),
|
|
205
259
|
/* @__PURE__ */ s("span", {
|
|
206
260
|
className: "font-medium",
|
|
207
|
-
children:
|
|
261
|
+
children: k.length
|
|
208
262
|
})
|
|
209
263
|
]
|
|
210
264
|
}),
|
|
@@ -218,11 +272,11 @@ function h() {
|
|
|
218
272
|
}),
|
|
219
273
|
/* @__PURE__ */ c("span", {
|
|
220
274
|
className: "font-medium",
|
|
221
|
-
children: [
|
|
275
|
+
children: [E, " pts"]
|
|
222
276
|
})
|
|
223
277
|
]
|
|
224
278
|
}),
|
|
225
|
-
|
|
279
|
+
x.velocity != null && /* @__PURE__ */ c("div", {
|
|
226
280
|
className: "flex items-center gap-2",
|
|
227
281
|
children: [
|
|
228
282
|
/* @__PURE__ */ s(t, { className: "h-4 w-4 text-muted-foreground" }),
|
|
@@ -232,18 +286,18 @@ function h() {
|
|
|
232
286
|
}),
|
|
233
287
|
/* @__PURE__ */ c("span", {
|
|
234
288
|
className: "font-medium",
|
|
235
|
-
children: [
|
|
289
|
+
children: [x.velocity, " pts"]
|
|
236
290
|
})
|
|
237
291
|
]
|
|
238
292
|
}),
|
|
239
|
-
|
|
293
|
+
x.goal && /* @__PURE__ */ c("div", {
|
|
240
294
|
className: "border-t pt-3 mt-3",
|
|
241
295
|
children: [/* @__PURE__ */ s("p", {
|
|
242
296
|
className: "text-muted-foreground text-xs mb-1",
|
|
243
297
|
children: "Goal"
|
|
244
298
|
}), /* @__PURE__ */ s("p", {
|
|
245
299
|
className: "text-sm",
|
|
246
|
-
children:
|
|
300
|
+
children: x.goal
|
|
247
301
|
})]
|
|
248
302
|
})
|
|
249
303
|
]
|
|
@@ -252,6 +306,6 @@ function h() {
|
|
|
252
306
|
});
|
|
253
307
|
}
|
|
254
308
|
//#endregion
|
|
255
|
-
export {
|
|
309
|
+
export { g as ProjectsPlanningDetailPagePage };
|
|
256
310
|
|
|
257
311
|
//# sourceMappingURL=ProjectsPlanningDetailPagePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectsPlanningDetailPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProjectsPlanningDetailPagePage.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 { CalendarClock, Users, BarChart3, FolderKanban } from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\n\nconst GET_SPRINT_DETAIL = gql`\n query GetSprintDetail($workspaceId: ID!) {\n planmagnetSprints(workspaceId: $workspaceId, pagination: { first: 1 }) {\n items {\n id\n name\n projectId\n status\n startDate\n endDate\n goal\n capacity\n velocity\n workItems {\n id\n key\n status\n storyPoints\n assigneeId\n priority\n }\n }\n }\n }\n`;\n\nexport function ProjectsPlanningDetailPagePage() {\n const { workspaceId } = usePlanMagnet();\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_SPRINT_DETAIL, {\n variables: { workspaceId: workspaceId ?? 'default' },\n });\n\n if (loading)\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)\n return <div className=\"p-6 text-red-500\">Error loading planning session: {error.message}</div>;\n\n const sprint = data?.planmagnetSprints?.items?.[0];\n if (!sprint) return <div className=\"p-6 text-muted-foreground\">Planning session not found.</div>;\n\n const workItems = sprint.workItems ?? [];\n const totalPoints = workItems.reduce(\n (sum: number, wi: { storyPoints: number | null }) => sum + (wi.storyPoints ?? 0),\n 0\n );\n const completedPoints = workItems\n .filter((wi: { status: string }) => wi.status === 'DONE')\n .reduce((sum: number, wi: { storyPoints: number | null }) => sum + (wi.storyPoints ?? 0), 0);\n const allocatedCapacity = sprint.capacity ?? totalPoints;\n const capPct = allocatedCapacity > 0 ? Math.round((totalPoints / allocatedCapacity) * 100) : 0;\n const remaining = allocatedCapacity - totalPoints;\n\n // Derive unique assignees from work items\n const uniqueAssignees = [\n ...new Set(\n workItems\n .map((wi: { assigneeId: string | null }) => wi.assigneeId)\n .filter(Boolean) as string[]\n ),\n ];\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">{sprint.name}</h1>\n <p className=\"text-sm text-muted-foreground\">\n {sprint.projectId} ·{' '}\n {sprint.startDate ? new Date(sprint.startDate).toLocaleDateString() : '—'} -{' '}\n {sprint.endDate ? new Date(sprint.endDate).toLocaleDateString() : '—'}\n </p>\n </div>\n <div className=\"flex gap-2\">\n <Badge className=\"capitalize\">{sprint.status.toLowerCase().replace('_', ' ')}</Badge>\n </div>\n </div>\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>Capacity Allocation</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"grid grid-cols-3 gap-4 text-center\">\n <div className=\"p-4 bg-muted rounded-md\">\n <p className=\"text-2xl font-bold\">{allocatedCapacity}</p>\n <p className=\"text-xs text-muted-foreground\">Capacity</p>\n </div>\n <div className=\"p-4 bg-primary/10 rounded-md\">\n <p className=\"text-2xl font-bold text-primary\">{totalPoints}</p>\n <p className=\"text-xs text-muted-foreground\">Allocated</p>\n </div>\n <div className=\"p-4 bg-muted rounded-md\">\n <p className=\"text-2xl font-bold\">{remaining > 0 ? remaining : 0}</p>\n <p className=\"text-xs text-muted-foreground\">Remaining</p>\n </div>\n </div>\n <div>\n <div className=\"flex justify-between text-sm mb-2\">\n <span className=\"text-muted-foreground\">Utilization</span>\n <span className=\"font-medium\">{capPct}%</span>\n </div>\n <div className=\"w-full h-4 rounded-full bg-muted overflow-hidden\">\n <div\n className={`h-full rounded-full ${capPct > 90 ? 'bg-red-400' : 'bg-green-400'}`}\n style={{ width: `${Math.min(capPct, 100)}%` }}\n />\n </div>\n </div>\n </CardContent>\n </Card>\n <Card>\n <CardHeader>\n <CardTitle>Team Members ({uniqueAssignees.length})</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-2 gap-3\">\n {uniqueAssignees.map((assigneeId: string) => (\n <div key={assigneeId} className=\"flex items-center gap-2 border rounded-md p-2.5\">\n <div className=\"h-8 w-8 rounded-full bg-primary/10 flex items-center justify-center text-xs font-medium text-primary\">\n {assigneeId.slice(0, 2).toUpperCase()}\n </div>\n <span className=\"text-sm truncate\">{assigneeId}</span>\n </div>\n ))}\n {uniqueAssignees.length === 0 && (\n <p className=\"text-sm text-muted-foreground col-span-2 text-center py-4\">\n No team members assigned.\n </p>\n )}\n </div>\n </CardContent>\n </Card>\n </div>\n <Card>\n <CardHeader>\n <CardTitle>Session Info</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3 text-sm\">\n <div className=\"flex items-center gap-2\">\n <FolderKanban className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"text-muted-foreground\">Project:</span>\n <span className=\"font-medium\">{sprint.projectId}</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <CalendarClock className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"text-muted-foreground\">Start:</span>\n <span className=\"font-medium\">\n {sprint.startDate ? new Date(sprint.startDate).toLocaleDateString() : 'Not set'}\n </span>\n </div>\n <div className=\"flex items-center gap-2\">\n <CalendarClock className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"text-muted-foreground\">End:</span>\n <span className=\"font-medium\">\n {sprint.endDate ? new Date(sprint.endDate).toLocaleDateString() : 'Not set'}\n </span>\n </div>\n <div className=\"flex items-center gap-2\">\n <Users className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"text-muted-foreground\">Assignees:</span>\n <span className=\"font-medium\">{uniqueAssignees.length}</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <BarChart3 className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"text-muted-foreground\">Capacity:</span>\n <span className=\"font-medium\">{allocatedCapacity} pts</span>\n </div>\n {sprint.velocity != null && (\n <div className=\"flex items-center gap-2\">\n <BarChart3 className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"text-muted-foreground\">Velocity:</span>\n <span className=\"font-medium\">{sprint.velocity} pts</span>\n </div>\n )}\n {sprint.goal && (\n <div className=\"border-t pt-3 mt-3\">\n <p className=\"text-muted-foreground text-xs mb-1\">Goal</p>\n <p className=\"text-sm\">{sprint.goal}</p>\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ProjectsPlanningDetailPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProjectsPlanningDetailPagePage.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 { CalendarClock, Users, BarChart3, FolderKanban } from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\n\nconst GET_SPRINT_DETAIL = gql`\n query GetSprintDetail($workspaceId: ID!) {\n planmagnetSprints(workspaceId: $workspaceId, pagination: { first: 1 }) {\n items {\n id\n name\n projectId\n status\n startDate\n endDate\n goal\n capacity\n velocity\n workItems {\n id\n key\n status\n storyPoints\n assigneeId\n priority\n }\n }\n }\n }\n`;\n\n// Real cross-layer CrewFoundry workforce capacity (BOFF-4444). Fails open on\n// the backend — an unreachable/unprovisioned CrewFoundry never blocks this\n// page, it just yields crewfoundryUnavailable: true, handled below.\nconst GET_SPRINT_CAPACITY = gql`\n query GetSprintCapacity($sprintId: ID!) {\n planmagnetSprintCapacity(sprintId: $sprintId) {\n sprintId\n crewfoundryUnavailable\n unmatchedAssigneeIds\n members {\n actorId\n employeeName\n department\n position\n allocatedHours\n billableHours\n utilizationPercent\n assignedStoryPoints\n assignedWorkItemCount\n }\n }\n }\n`;\n\nexport function ProjectsPlanningDetailPagePage() {\n const { workspaceId } = usePlanMagnet();\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_SPRINT_DETAIL, {\n variables: { workspaceId: workspaceId ?? 'default' },\n });\n\n const sprintId = data?.planmagnetSprints?.items?.[0]?.id;\n // Real cross-layer CrewFoundry capacity (BOFF-4444) — called unconditionally\n // (with `skip`) to keep hook order stable across the loading/error/loaded\n // renders above.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const { data: capacityData } = useQuery<Record<string, any>>(GET_SPRINT_CAPACITY, {\n variables: { sprintId },\n skip: !sprintId,\n });\n\n if (loading)\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)\n return <div className=\"p-6 text-red-500\">Error loading planning session: {error.message}</div>;\n\n const sprint = data?.planmagnetSprints?.items?.[0];\n if (!sprint) return <div className=\"p-6 text-muted-foreground\">Planning session not found.</div>;\n\n const capacity = capacityData?.planmagnetSprintCapacity;\n const allocationByAssignee: Record<\n string,\n {\n employeeName: string;\n allocatedHours: number;\n billableHours: number;\n utilizationPercent: number | null;\n }\n > = {};\n for (const member of capacity?.members ?? []) {\n allocationByAssignee[member.actorId] = {\n employeeName: member.employeeName,\n allocatedHours: member.allocatedHours,\n billableHours: member.billableHours,\n utilizationPercent: member.utilizationPercent,\n };\n }\n\n const workItems = sprint.workItems ?? [];\n const totalPoints = workItems.reduce(\n (sum: number, wi: { storyPoints: number | null }) => sum + (wi.storyPoints ?? 0),\n 0\n );\n const completedPoints = workItems\n .filter((wi: { status: string }) => wi.status === 'DONE')\n .reduce((sum: number, wi: { storyPoints: number | null }) => sum + (wi.storyPoints ?? 0), 0);\n const allocatedCapacity = sprint.capacity ?? totalPoints;\n const capPct = allocatedCapacity > 0 ? Math.round((totalPoints / allocatedCapacity) * 100) : 0;\n const remaining = allocatedCapacity - totalPoints;\n\n // Derive unique assignees from work items\n const uniqueAssignees = [\n ...new Set(\n workItems\n .map((wi: { assigneeId: string | null }) => wi.assigneeId)\n .filter(Boolean) as string[]\n ),\n ];\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">{sprint.name}</h1>\n <p className=\"text-sm text-muted-foreground\">\n {sprint.projectId} ·{' '}\n {sprint.startDate ? new Date(sprint.startDate).toLocaleDateString() : '—'} -{' '}\n {sprint.endDate ? new Date(sprint.endDate).toLocaleDateString() : '—'}\n </p>\n </div>\n <div className=\"flex gap-2\">\n <Badge className=\"capitalize\">{sprint.status.toLowerCase().replace('_', ' ')}</Badge>\n </div>\n </div>\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>Capacity Allocation</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"grid grid-cols-3 gap-4 text-center\">\n <div className=\"p-4 bg-muted rounded-md\">\n <p className=\"text-2xl font-bold\">{allocatedCapacity}</p>\n <p className=\"text-xs text-muted-foreground\">Capacity</p>\n </div>\n <div className=\"p-4 bg-primary/10 rounded-md\">\n <p className=\"text-2xl font-bold text-primary\">{totalPoints}</p>\n <p className=\"text-xs text-muted-foreground\">Allocated</p>\n </div>\n <div className=\"p-4 bg-muted rounded-md\">\n <p className=\"text-2xl font-bold\">{remaining > 0 ? remaining : 0}</p>\n <p className=\"text-xs text-muted-foreground\">Remaining</p>\n </div>\n </div>\n <div>\n <div className=\"flex justify-between text-sm mb-2\">\n <span className=\"text-muted-foreground\">Utilization</span>\n <span className=\"font-medium\">{capPct}%</span>\n </div>\n <div className=\"w-full h-4 rounded-full bg-muted overflow-hidden\">\n <div\n className={`h-full rounded-full ${capPct > 90 ? 'bg-red-400' : 'bg-green-400'}`}\n style={{ width: `${Math.min(capPct, 100)}%` }}\n />\n </div>\n </div>\n </CardContent>\n </Card>\n <Card>\n <CardHeader>\n <CardTitle>Team Members ({uniqueAssignees.length})</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-2 gap-3\">\n {uniqueAssignees.map((assigneeId: string) => {\n const workforce = allocationByAssignee[assigneeId];\n return (\n <div\n key={assigneeId}\n className=\"flex items-center gap-2 border rounded-md p-2.5\"\n >\n <div className=\"h-8 w-8 rounded-full bg-primary/10 flex items-center justify-center text-xs font-medium text-primary\">\n {assigneeId.slice(0, 2).toUpperCase()}\n </div>\n <div className=\"min-w-0\">\n <span className=\"text-sm truncate block\">\n {workforce?.employeeName ?? assigneeId}\n </span>\n {workforce && (\n <span className=\"text-xs text-muted-foreground\">\n {workforce.allocatedHours}h allocated ({workforce.billableHours}h\n billable)\n {workforce.utilizationPercent != null &&\n ` · ${workforce.utilizationPercent}% util`}\n </span>\n )}\n </div>\n </div>\n );\n })}\n {uniqueAssignees.length === 0 && (\n <p className=\"text-sm text-muted-foreground col-span-2 text-center py-4\">\n No team members assigned.\n </p>\n )}\n </div>\n {/* Real cross-layer CrewFoundry workforce allocation (BOFF-4444). */}\n {capacity?.crewfoundryUnavailable && uniqueAssignees.length > 0 && (\n <p className=\"text-xs text-muted-foreground mt-3 border-t pt-3\">\n Workforce allocation from CrewFoundry is unavailable for this workspace — no\n CrewFoundry module provisioned yet.\n </p>\n )}\n {!capacity?.crewfoundryUnavailable &&\n (capacity?.unmatchedAssigneeIds?.length ?? 0) > 0 && (\n <p className=\"text-xs text-muted-foreground mt-3 border-t pt-3\">\n {capacity.unmatchedAssigneeIds.length} assignee(s) have no matching CrewFoundry\n employee record — allocation hours shown only for matched employees.\n </p>\n )}\n </CardContent>\n </Card>\n </div>\n <Card>\n <CardHeader>\n <CardTitle>Session Info</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3 text-sm\">\n <div className=\"flex items-center gap-2\">\n <FolderKanban className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"text-muted-foreground\">Project:</span>\n <span className=\"font-medium\">{sprint.projectId}</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <CalendarClock className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"text-muted-foreground\">Start:</span>\n <span className=\"font-medium\">\n {sprint.startDate ? new Date(sprint.startDate).toLocaleDateString() : 'Not set'}\n </span>\n </div>\n <div className=\"flex items-center gap-2\">\n <CalendarClock className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"text-muted-foreground\">End:</span>\n <span className=\"font-medium\">\n {sprint.endDate ? new Date(sprint.endDate).toLocaleDateString() : 'Not set'}\n </span>\n </div>\n <div className=\"flex items-center gap-2\">\n <Users className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"text-muted-foreground\">Assignees:</span>\n <span className=\"font-medium\">{uniqueAssignees.length}</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <BarChart3 className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"text-muted-foreground\">Capacity:</span>\n <span className=\"font-medium\">{allocatedCapacity} pts</span>\n </div>\n {sprint.velocity != null && (\n <div className=\"flex items-center gap-2\">\n <BarChart3 className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"text-muted-foreground\">Velocity:</span>\n <span className=\"font-medium\">{sprint.velocity} pts</span>\n </div>\n )}\n {sprint.goal && (\n <div className=\"border-t pt-3 mt-3\">\n <p className=\"text-muted-foreground text-xs mb-1\">Goal</p>\n <p className=\"text-sm\">{sprint.goal}</p>\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|