@burdenoff/microfe-planmagnet 2026.924.2 → 2026.924.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/PlanMagnetRoot.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoot.js +93 -142
- package/dist/planmagnet/PlanMagnetRoot.js.map +1 -1
- package/dist/planmagnet/admin/PlanMagnetAdminRoot.d.ts.map +1 -1
- package/dist/planmagnet/admin/PlanMagnetAdminRoot.js +150 -149
- package/dist/planmagnet/admin/PlanMagnetAdminRoot.js.map +1 -1
- package/dist/planmagnet/pages/DashboardDashboardPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/DashboardDashboardPagePage.js +113 -116
- package/dist/planmagnet/pages/DashboardDashboardPagePage.js.map +1 -1
- package/dist/planmagnet/pages/GoalsGoalsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/GoalsGoalsPagePage.js +59 -58
- package/dist/planmagnet/pages/GoalsGoalsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/GoalsObjectiveDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/GoalsObjectiveDetailPagePage.js +150 -149
- package/dist/planmagnet/pages/GoalsObjectiveDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsEditProductPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsEditProductPagePage.js +108 -107
- package/dist/planmagnet/pages/ProductsEditProductPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.js +93 -92
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsProductsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsProductsPagePage.js +89 -87
- package/dist/planmagnet/pages/ProductsProductsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.js +94 -93
- package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsReleasesPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsReleasesPagePage.js +57 -56
- package/dist/planmagnet/pages/ProductsReleasesPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js +82 -81
- package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapsPagePage.js +72 -71
- package/dist/planmagnet/pages/ProductsRoadmapsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsActiveProjectsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsActiveProjectsPagePage.js +38 -37
- package/dist/planmagnet/pages/ProjectsActiveProjectsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.js +72 -71
- package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsMilestonesPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsMilestonesPagePage.js +47 -46
- package/dist/planmagnet/pages/ProjectsMilestonesPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js +120 -119
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js +131 -130
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectsPagePage.js +77 -75
- package/dist/planmagnet/pages/ProjectsProjectsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ReportsReportsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ReportsReportsPagePage.js +71 -70
- package/dist/planmagnet/pages/ReportsReportsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TeamTeamPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TeamTeamPagePage.js +58 -57
- package/dist/planmagnet/pages/TeamTeamPagePage.js.map +1 -1
- package/dist/planmagnet/pages/WorkspaceCreateWorkspacePagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/WorkspaceCreateWorkspacePagePage.js +81 -72
- package/dist/planmagnet/pages/WorkspaceCreateWorkspacePagePage.js.map +1 -1
- package/dist/planmagnet/people/People.d.ts +20 -0
- package/dist/planmagnet/people/People.d.ts.map +1 -0
- package/dist/planmagnet/people/People.js +42 -0
- package/dist/planmagnet/people/People.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
1
|
+
import { PersonName as e } from "../people/People.js";
|
|
2
|
+
import { useEntityId as t } from "../hooks/useEntityId.js";
|
|
3
|
+
import { BarChart3 as n, CalendarClock as r, FolderKanban as i, Users as a } from "lucide-react";
|
|
4
|
+
import { gql as o } from "@apollo/client";
|
|
5
|
+
import { useQuery as s } from "@apollo/client/react";
|
|
6
|
+
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
7
|
+
import { Badge as u, Card as d, CardContent as f, CardHeader as p, CardTitle as m } from "@burdenoff/fe-libs/ui";
|
|
7
8
|
//#region src/planmagnet/pages/ProjectsPlanningDetailPagePage.tsx
|
|
8
|
-
var
|
|
9
|
+
var h = o`
|
|
9
10
|
query GetSprintDetail($id: ID!) {
|
|
10
11
|
planmagnetSprint(id: $id) {
|
|
11
12
|
id
|
|
@@ -27,7 +28,7 @@ var m = a`
|
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
|
-
`,
|
|
31
|
+
`, g = o`
|
|
31
32
|
query GetSprintCapacity($sprintId: ID!) {
|
|
32
33
|
planmagnetSprintCapacity(sprintId: $sprintId) {
|
|
33
34
|
sprintId
|
|
@@ -47,262 +48,262 @@ var m = a`
|
|
|
47
48
|
}
|
|
48
49
|
}
|
|
49
50
|
`;
|
|
50
|
-
function
|
|
51
|
-
let
|
|
52
|
-
variables: { id:
|
|
53
|
-
skip: !
|
|
54
|
-
}), { data:
|
|
55
|
-
variables: { sprintId:
|
|
56
|
-
skip: !
|
|
51
|
+
function _() {
|
|
52
|
+
let o = t("sprintId"), { data: _, loading: v, error: y } = s(h, {
|
|
53
|
+
variables: { id: o },
|
|
54
|
+
skip: !o
|
|
55
|
+
}), { data: b } = s(g, {
|
|
56
|
+
variables: { sprintId: o },
|
|
57
|
+
skip: !o
|
|
57
58
|
});
|
|
58
|
-
if (!
|
|
59
|
+
if (!o) return /* @__PURE__ */ c("div", {
|
|
59
60
|
className: "p-6 text-muted-foreground",
|
|
60
61
|
children: "No planning session selected. Open one from the list."
|
|
61
62
|
});
|
|
62
|
-
if (
|
|
63
|
+
if (v) return /* @__PURE__ */ c("div", {
|
|
63
64
|
className: "flex items-center justify-center p-12",
|
|
64
|
-
children: /* @__PURE__ */
|
|
65
|
+
children: /* @__PURE__ */ c("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
|
|
65
66
|
});
|
|
66
|
-
if (
|
|
67
|
+
if (y) return /* @__PURE__ */ l("div", {
|
|
67
68
|
className: "p-6 text-red-500",
|
|
68
|
-
children: ["Error loading planning session: ",
|
|
69
|
+
children: ["Error loading planning session: ", y.message]
|
|
69
70
|
});
|
|
70
|
-
let
|
|
71
|
-
if (!
|
|
71
|
+
let x = _?.planmagnetSprint;
|
|
72
|
+
if (!x) return /* @__PURE__ */ c("div", {
|
|
72
73
|
className: "p-6 text-muted-foreground",
|
|
73
74
|
children: "Planning session not found."
|
|
74
75
|
});
|
|
75
|
-
let
|
|
76
|
-
for (let e of
|
|
76
|
+
let S = b?.planmagnetSprintCapacity, C = {};
|
|
77
|
+
for (let e of S?.members ?? []) C[e.actorId] = {
|
|
77
78
|
employeeName: e.employeeName,
|
|
78
79
|
allocatedHours: e.allocatedHours,
|
|
79
80
|
billableHours: e.billableHours,
|
|
80
81
|
utilizationPercent: e.utilizationPercent
|
|
81
82
|
};
|
|
82
|
-
let
|
|
83
|
-
|
|
84
|
-
let
|
|
85
|
-
return /* @__PURE__ */
|
|
83
|
+
let w = x.workItems ?? [], T = w.reduce((e, t) => e + (t.storyPoints ?? 0), 0);
|
|
84
|
+
w.filter((e) => e.status === "DONE").reduce((e, t) => e + (t.storyPoints ?? 0), 0);
|
|
85
|
+
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))];
|
|
86
|
+
return /* @__PURE__ */ l("div", {
|
|
86
87
|
className: "space-y-6 p-6",
|
|
87
|
-
children: [/* @__PURE__ */
|
|
88
|
+
children: [/* @__PURE__ */ l("div", {
|
|
88
89
|
className: "flex items-center justify-between",
|
|
89
|
-
children: [/* @__PURE__ */
|
|
90
|
+
children: [/* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("h1", {
|
|
90
91
|
className: "text-2xl font-semibold",
|
|
91
|
-
children:
|
|
92
|
-
}), /* @__PURE__ */
|
|
92
|
+
children: x.name
|
|
93
|
+
}), /* @__PURE__ */ l("p", {
|
|
93
94
|
className: "text-sm text-muted-foreground",
|
|
94
95
|
children: [
|
|
95
|
-
|
|
96
|
+
x.projectId,
|
|
96
97
|
" ·",
|
|
97
98
|
" ",
|
|
98
|
-
|
|
99
|
+
x.startDate ? new Date(x.startDate).toLocaleDateString() : "—",
|
|
99
100
|
" -",
|
|
100
101
|
" ",
|
|
101
|
-
|
|
102
|
+
x.endDate ? new Date(x.endDate).toLocaleDateString() : "—"
|
|
102
103
|
]
|
|
103
|
-
})] }), /* @__PURE__ */
|
|
104
|
+
})] }), /* @__PURE__ */ c("div", {
|
|
104
105
|
className: "flex gap-2",
|
|
105
|
-
children: /* @__PURE__ */
|
|
106
|
+
children: /* @__PURE__ */ c(u, {
|
|
106
107
|
className: "capitalize",
|
|
107
|
-
children:
|
|
108
|
+
children: x.status.toLowerCase().replace("_", " ")
|
|
108
109
|
})
|
|
109
110
|
})]
|
|
110
|
-
}), /* @__PURE__ */
|
|
111
|
+
}), /* @__PURE__ */ l("div", {
|
|
111
112
|
className: "grid grid-cols-1 lg:grid-cols-3 gap-6",
|
|
112
|
-
children: [/* @__PURE__ */
|
|
113
|
+
children: [/* @__PURE__ */ l("div", {
|
|
113
114
|
className: "lg:col-span-2 space-y-6",
|
|
114
|
-
children: [/* @__PURE__ */
|
|
115
|
+
children: [/* @__PURE__ */ l(d, { children: [/* @__PURE__ */ c(p, { children: /* @__PURE__ */ c(m, { children: "Capacity Allocation" }) }), /* @__PURE__ */ l(f, {
|
|
115
116
|
className: "space-y-4",
|
|
116
|
-
children: [/* @__PURE__ */
|
|
117
|
+
children: [/* @__PURE__ */ l("div", {
|
|
117
118
|
className: "grid grid-cols-3 gap-4 text-center",
|
|
118
119
|
children: [
|
|
119
|
-
/* @__PURE__ */
|
|
120
|
+
/* @__PURE__ */ l("div", {
|
|
120
121
|
className: "p-4 bg-muted rounded-md",
|
|
121
|
-
children: [/* @__PURE__ */
|
|
122
|
+
children: [/* @__PURE__ */ c("p", {
|
|
122
123
|
className: "text-2xl font-bold",
|
|
123
|
-
children:
|
|
124
|
-
}), /* @__PURE__ */
|
|
124
|
+
children: E
|
|
125
|
+
}), /* @__PURE__ */ c("p", {
|
|
125
126
|
className: "text-xs text-muted-foreground",
|
|
126
127
|
children: "Capacity"
|
|
127
128
|
})]
|
|
128
129
|
}),
|
|
129
|
-
/* @__PURE__ */
|
|
130
|
+
/* @__PURE__ */ l("div", {
|
|
130
131
|
className: "p-4 bg-primary/10 rounded-md",
|
|
131
|
-
children: [/* @__PURE__ */
|
|
132
|
+
children: [/* @__PURE__ */ c("p", {
|
|
132
133
|
className: "text-2xl font-bold text-primary",
|
|
133
|
-
children:
|
|
134
|
-
}), /* @__PURE__ */
|
|
134
|
+
children: T
|
|
135
|
+
}), /* @__PURE__ */ c("p", {
|
|
135
136
|
className: "text-xs text-muted-foreground",
|
|
136
137
|
children: "Allocated"
|
|
137
138
|
})]
|
|
138
139
|
}),
|
|
139
|
-
/* @__PURE__ */
|
|
140
|
+
/* @__PURE__ */ l("div", {
|
|
140
141
|
className: "p-4 bg-muted rounded-md",
|
|
141
|
-
children: [/* @__PURE__ */
|
|
142
|
+
children: [/* @__PURE__ */ c("p", {
|
|
142
143
|
className: "text-2xl font-bold",
|
|
143
|
-
children:
|
|
144
|
-
}), /* @__PURE__ */
|
|
144
|
+
children: O > 0 ? O : 0
|
|
145
|
+
}), /* @__PURE__ */ c("p", {
|
|
145
146
|
className: "text-xs text-muted-foreground",
|
|
146
147
|
children: "Remaining"
|
|
147
148
|
})]
|
|
148
149
|
})
|
|
149
150
|
]
|
|
150
|
-
}), /* @__PURE__ */
|
|
151
|
+
}), /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ l("div", {
|
|
151
152
|
className: "flex justify-between text-sm mb-2",
|
|
152
|
-
children: [/* @__PURE__ */
|
|
153
|
+
children: [/* @__PURE__ */ c("span", {
|
|
153
154
|
className: "text-muted-foreground",
|
|
154
155
|
children: "Utilization"
|
|
155
|
-
}), /* @__PURE__ */
|
|
156
|
+
}), /* @__PURE__ */ l("span", {
|
|
156
157
|
className: "font-medium",
|
|
157
|
-
children: [
|
|
158
|
+
children: [D, "%"]
|
|
158
159
|
})]
|
|
159
|
-
}), /* @__PURE__ */
|
|
160
|
+
}), /* @__PURE__ */ c("div", {
|
|
160
161
|
className: "w-full h-4 rounded-full bg-muted overflow-hidden",
|
|
161
|
-
children: /* @__PURE__ */
|
|
162
|
-
className: `h-full rounded-full ${
|
|
163
|
-
style: { width: `${Math.min(
|
|
162
|
+
children: /* @__PURE__ */ c("div", {
|
|
163
|
+
className: `h-full rounded-full ${D > 90 ? "bg-red-400" : "bg-green-400"}`,
|
|
164
|
+
style: { width: `${Math.min(D, 100)}%` }
|
|
164
165
|
})
|
|
165
166
|
})] })]
|
|
166
|
-
})] }), /* @__PURE__ */
|
|
167
|
+
})] }), /* @__PURE__ */ l(d, { children: [/* @__PURE__ */ c(p, { children: /* @__PURE__ */ l(m, { children: [
|
|
167
168
|
"Team Members (",
|
|
168
|
-
|
|
169
|
+
k.length,
|
|
169
170
|
")"
|
|
170
|
-
] }) }), /* @__PURE__ */
|
|
171
|
-
/* @__PURE__ */
|
|
171
|
+
] }) }), /* @__PURE__ */ l(f, { children: [
|
|
172
|
+
/* @__PURE__ */ l("div", {
|
|
172
173
|
className: "grid grid-cols-2 gap-3",
|
|
173
|
-
children: [
|
|
174
|
-
let
|
|
175
|
-
return /* @__PURE__ */
|
|
174
|
+
children: [k.map((t) => {
|
|
175
|
+
let n = C[t];
|
|
176
|
+
return /* @__PURE__ */ l("div", {
|
|
176
177
|
className: "flex items-center gap-2 border rounded-md p-2.5",
|
|
177
|
-
children: [/* @__PURE__ */
|
|
178
|
+
children: [/* @__PURE__ */ c("div", {
|
|
178
179
|
className: "h-8 w-8 rounded-full bg-primary/10 flex items-center justify-center text-xs font-medium text-primary",
|
|
179
|
-
children:
|
|
180
|
-
}), /* @__PURE__ */
|
|
180
|
+
children: t.slice(0, 2).toUpperCase()
|
|
181
|
+
}), /* @__PURE__ */ l("div", {
|
|
181
182
|
className: "min-w-0",
|
|
182
|
-
children: [/* @__PURE__ */
|
|
183
|
+
children: [/* @__PURE__ */ c("span", {
|
|
183
184
|
className: "text-sm truncate block",
|
|
184
|
-
children:
|
|
185
|
-
}),
|
|
185
|
+
children: n?.employeeName ?? /* @__PURE__ */ c(e, { id: t })
|
|
186
|
+
}), n && /* @__PURE__ */ l("span", {
|
|
186
187
|
className: "text-xs text-muted-foreground",
|
|
187
188
|
children: [
|
|
188
|
-
|
|
189
|
+
n.allocatedHours,
|
|
189
190
|
"h allocated (",
|
|
190
|
-
|
|
191
|
+
n.billableHours,
|
|
191
192
|
"h billable)",
|
|
192
|
-
|
|
193
|
+
n.utilizationPercent != null && ` · ${n.utilizationPercent}% util`
|
|
193
194
|
]
|
|
194
195
|
})]
|
|
195
196
|
})]
|
|
196
|
-
},
|
|
197
|
-
}),
|
|
197
|
+
}, t);
|
|
198
|
+
}), k.length === 0 && /* @__PURE__ */ c("p", {
|
|
198
199
|
className: "text-sm text-muted-foreground col-span-2 text-center py-4",
|
|
199
200
|
children: "No team members assigned."
|
|
200
201
|
})]
|
|
201
202
|
}),
|
|
202
|
-
|
|
203
|
+
S?.crewfoundryUnavailable && k.length > 0 && /* @__PURE__ */ c("p", {
|
|
203
204
|
className: "text-xs text-muted-foreground mt-3 border-t pt-3",
|
|
204
205
|
children: "Workforce allocation from CrewFoundry is unavailable for this workspace — no CrewFoundry module provisioned yet."
|
|
205
206
|
}),
|
|
206
|
-
!
|
|
207
|
+
!S?.crewfoundryUnavailable && (S?.unmatchedAssigneeIds?.length ?? 0) > 0 && /* @__PURE__ */ l("p", {
|
|
207
208
|
className: "text-xs text-muted-foreground mt-3 border-t pt-3",
|
|
208
|
-
children: [
|
|
209
|
+
children: [S.unmatchedAssigneeIds.length, " assignee(s) have no matching CrewFoundry employee record — allocation hours shown only for matched employees."]
|
|
209
210
|
})
|
|
210
211
|
] })] })]
|
|
211
|
-
}), /* @__PURE__ */
|
|
212
|
+
}), /* @__PURE__ */ l(d, { children: [/* @__PURE__ */ c(p, { children: /* @__PURE__ */ c(m, { children: "Session Info" }) }), /* @__PURE__ */ l(f, {
|
|
212
213
|
className: "space-y-3 text-sm",
|
|
213
214
|
children: [
|
|
214
|
-
/* @__PURE__ */
|
|
215
|
+
/* @__PURE__ */ l("div", {
|
|
215
216
|
className: "flex items-center gap-2",
|
|
216
217
|
children: [
|
|
217
|
-
/* @__PURE__ */
|
|
218
|
-
/* @__PURE__ */
|
|
218
|
+
/* @__PURE__ */ c(i, { className: "h-4 w-4 text-muted-foreground" }),
|
|
219
|
+
/* @__PURE__ */ c("span", {
|
|
219
220
|
className: "text-muted-foreground",
|
|
220
221
|
children: "Project:"
|
|
221
222
|
}),
|
|
222
|
-
/* @__PURE__ */
|
|
223
|
+
/* @__PURE__ */ c("span", {
|
|
223
224
|
className: "font-medium",
|
|
224
|
-
children:
|
|
225
|
+
children: x.projectId
|
|
225
226
|
})
|
|
226
227
|
]
|
|
227
228
|
}),
|
|
228
|
-
/* @__PURE__ */
|
|
229
|
+
/* @__PURE__ */ l("div", {
|
|
229
230
|
className: "flex items-center gap-2",
|
|
230
231
|
children: [
|
|
231
|
-
/* @__PURE__ */
|
|
232
|
-
/* @__PURE__ */
|
|
232
|
+
/* @__PURE__ */ c(r, { className: "h-4 w-4 text-muted-foreground" }),
|
|
233
|
+
/* @__PURE__ */ c("span", {
|
|
233
234
|
className: "text-muted-foreground",
|
|
234
235
|
children: "Start:"
|
|
235
236
|
}),
|
|
236
|
-
/* @__PURE__ */
|
|
237
|
+
/* @__PURE__ */ c("span", {
|
|
237
238
|
className: "font-medium",
|
|
238
|
-
children:
|
|
239
|
+
children: x.startDate ? new Date(x.startDate).toLocaleDateString() : "Not set"
|
|
239
240
|
})
|
|
240
241
|
]
|
|
241
242
|
}),
|
|
242
|
-
/* @__PURE__ */
|
|
243
|
+
/* @__PURE__ */ l("div", {
|
|
243
244
|
className: "flex items-center gap-2",
|
|
244
245
|
children: [
|
|
245
|
-
/* @__PURE__ */
|
|
246
|
-
/* @__PURE__ */
|
|
246
|
+
/* @__PURE__ */ c(r, { className: "h-4 w-4 text-muted-foreground" }),
|
|
247
|
+
/* @__PURE__ */ c("span", {
|
|
247
248
|
className: "text-muted-foreground",
|
|
248
249
|
children: "End:"
|
|
249
250
|
}),
|
|
250
|
-
/* @__PURE__ */
|
|
251
|
+
/* @__PURE__ */ c("span", {
|
|
251
252
|
className: "font-medium",
|
|
252
|
-
children:
|
|
253
|
+
children: x.endDate ? new Date(x.endDate).toLocaleDateString() : "Not set"
|
|
253
254
|
})
|
|
254
255
|
]
|
|
255
256
|
}),
|
|
256
|
-
/* @__PURE__ */
|
|
257
|
+
/* @__PURE__ */ l("div", {
|
|
257
258
|
className: "flex items-center gap-2",
|
|
258
259
|
children: [
|
|
259
|
-
/* @__PURE__ */
|
|
260
|
-
/* @__PURE__ */
|
|
260
|
+
/* @__PURE__ */ c(a, { className: "h-4 w-4 text-muted-foreground" }),
|
|
261
|
+
/* @__PURE__ */ c("span", {
|
|
261
262
|
className: "text-muted-foreground",
|
|
262
263
|
children: "Assignees:"
|
|
263
264
|
}),
|
|
264
|
-
/* @__PURE__ */
|
|
265
|
+
/* @__PURE__ */ c("span", {
|
|
265
266
|
className: "font-medium",
|
|
266
|
-
children:
|
|
267
|
+
children: k.length
|
|
267
268
|
})
|
|
268
269
|
]
|
|
269
270
|
}),
|
|
270
|
-
/* @__PURE__ */
|
|
271
|
+
/* @__PURE__ */ l("div", {
|
|
271
272
|
className: "flex items-center gap-2",
|
|
272
273
|
children: [
|
|
273
|
-
/* @__PURE__ */
|
|
274
|
-
/* @__PURE__ */
|
|
274
|
+
/* @__PURE__ */ c(n, { className: "h-4 w-4 text-muted-foreground" }),
|
|
275
|
+
/* @__PURE__ */ c("span", {
|
|
275
276
|
className: "text-muted-foreground",
|
|
276
277
|
children: "Capacity:"
|
|
277
278
|
}),
|
|
278
|
-
/* @__PURE__ */
|
|
279
|
+
/* @__PURE__ */ l("span", {
|
|
279
280
|
className: "font-medium",
|
|
280
|
-
children: [
|
|
281
|
+
children: [E, " pts"]
|
|
281
282
|
})
|
|
282
283
|
]
|
|
283
284
|
}),
|
|
284
|
-
|
|
285
|
+
x.velocity != null && /* @__PURE__ */ l("div", {
|
|
285
286
|
className: "flex items-center gap-2",
|
|
286
287
|
children: [
|
|
287
|
-
/* @__PURE__ */
|
|
288
|
-
/* @__PURE__ */
|
|
288
|
+
/* @__PURE__ */ c(n, { className: "h-4 w-4 text-muted-foreground" }),
|
|
289
|
+
/* @__PURE__ */ c("span", {
|
|
289
290
|
className: "text-muted-foreground",
|
|
290
291
|
children: "Velocity:"
|
|
291
292
|
}),
|
|
292
|
-
/* @__PURE__ */
|
|
293
|
+
/* @__PURE__ */ l("span", {
|
|
293
294
|
className: "font-medium",
|
|
294
|
-
children: [
|
|
295
|
+
children: [x.velocity, " pts"]
|
|
295
296
|
})
|
|
296
297
|
]
|
|
297
298
|
}),
|
|
298
|
-
|
|
299
|
+
x.goal && /* @__PURE__ */ l("div", {
|
|
299
300
|
className: "border-t pt-3 mt-3",
|
|
300
|
-
children: [/* @__PURE__ */
|
|
301
|
+
children: [/* @__PURE__ */ c("p", {
|
|
301
302
|
className: "text-muted-foreground text-xs mb-1",
|
|
302
303
|
children: "Goal"
|
|
303
|
-
}), /* @__PURE__ */
|
|
304
|
+
}), /* @__PURE__ */ c("p", {
|
|
304
305
|
className: "text-sm",
|
|
305
|
-
children:
|
|
306
|
+
children: x.goal
|
|
306
307
|
})]
|
|
307
308
|
})
|
|
308
309
|
]
|
|
@@ -311,6 +312,6 @@ function g() {
|
|
|
311
312
|
});
|
|
312
313
|
}
|
|
313
314
|
//#endregion
|
|
314
|
-
export {
|
|
315
|
+
export { _ as ProjectsPlanningDetailPagePage };
|
|
315
316
|
|
|
316
317
|
//# 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 { useEntityId } from '../hooks/useEntityId';\n\nconst GET_SPRINT_DETAIL = gql`\n query GetSprintDetail($id: ID!) {\n planmagnetSprint(id: $id) {\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// 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 sprintId = useEntityId('sprintId');\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: { id: sprintId },\n skip: !sprintId,\n });\n\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 (!sprintId)\n return (\n <div className=\"p-6 text-muted-foreground\">\n No planning session selected. Open one from the list.\n </div>\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?.planmagnetSprint;\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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"}
|
|
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 { useEntityId } from '../hooks/useEntityId';\nimport { PersonName } from '../people/People';\n\nconst GET_SPRINT_DETAIL = gql`\n query GetSprintDetail($id: ID!) {\n planmagnetSprint(id: $id) {\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// 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 sprintId = useEntityId('sprintId');\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: { id: sprintId },\n skip: !sprintId,\n });\n\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 (!sprintId)\n return (\n <div className=\"p-6 text-muted-foreground\">\n No planning session selected. Open one from the list.\n </div>\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?.planmagnetSprint;\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 ?? <PersonName id={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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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectsProjectDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProjectsProjectDetailPagePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ProjectsProjectDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProjectsProjectDetailPagePage.tsx"],"names":[],"mappings":"AAsEA,wBAAgB,6BAA6B,4CAkT5C"}
|