@burdenoff/microfe-planmagnet 2026.928.5 → 2026.928.6
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 +20 -11
- package/dist/planmagnet/PlanMagnetRoot.js.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.js +216 -196
- package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
- package/dist/planmagnet/controls/Pickers.d.ts +7 -0
- package/dist/planmagnet/controls/Pickers.d.ts.map +1 -1
- package/dist/planmagnet/controls/Pickers.js +58 -20
- package/dist/planmagnet/controls/Pickers.js.map +1 -1
- package/dist/planmagnet/controls/WorkItemControls.d.ts +6 -2
- package/dist/planmagnet/controls/WorkItemControls.d.ts.map +1 -1
- package/dist/planmagnet/controls/WorkItemControls.js +8 -8
- package/dist/planmagnet/controls/WorkItemControls.js.map +1 -1
- package/dist/planmagnet/pages/DashboardDashboardPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/DashboardDashboardPagePage.js +11 -3
- package/dist/planmagnet/pages/DashboardDashboardPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js +16 -6
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.js +7 -2
- package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningPagePage.js +76 -56
- package/dist/planmagnet/pages/ProjectsPlanningPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js +241 -188
- 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 +168 -122
- package/dist/planmagnet/pages/SprintsStartSprintPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TeamCreateTeamPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TeamCreateTeamPagePage.js +288 -91
- package/dist/planmagnet/pages/TeamCreateTeamPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TeamTeamDetailPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/TeamTeamDetailPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/TeamTeamDetailPagePage.js +217 -0
- package/dist/planmagnet/pages/TeamTeamDetailPagePage.js.map +1 -0
- package/dist/planmagnet/pages/TeamTeamEditPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/TeamTeamEditPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/TeamTeamEditPagePage.js +211 -0
- package/dist/planmagnet/pages/TeamTeamEditPagePage.js.map +1 -0
- package/dist/planmagnet/pages/TeamTeamsListPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/TeamTeamsListPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/TeamTeamsListPagePage.js +118 -0
- package/dist/planmagnet/pages/TeamTeamsListPagePage.js.map +1 -0
- package/dist/planmagnet/sprints/SprintControls.d.ts +15 -3
- package/dist/planmagnet/sprints/SprintControls.d.ts.map +1 -1
- package/dist/planmagnet/sprints/SprintControls.js +293 -190
- package/dist/planmagnet/sprints/SprintControls.js.map +1 -1
- package/dist/planmagnet/team/TeamControls.d.ts +31 -0
- package/dist/planmagnet/team/TeamControls.d.ts.map +1 -0
- package/dist/planmagnet/team/TeamControls.js +407 -0
- package/dist/planmagnet/team/TeamControls.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { usePlanMagnet as e, usePlanMagnetNavigate as t } from "../providers/PlanMagnetProvider.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
2
|
+
import { TeamSelect as n } from "../controls/Pickers.js";
|
|
3
|
+
import { detailPath as r, rowLinkProps as i } from "../utils/rowNavigation.js";
|
|
4
|
+
import { NewSprintDialog as a } from "../sprints/SprintControls.js";
|
|
5
|
+
import { useState as o } from "react";
|
|
6
|
+
import { CalendarClock as s, FolderKanban as c, Users as l } from "lucide-react";
|
|
7
|
+
import { gql as u } from "@apollo/client";
|
|
8
|
+
import { useQuery as d } from "@apollo/client/react";
|
|
9
|
+
import { Fragment as f, jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
10
|
+
import { Badge as h, Card as g, CardContent as _, CardHeader as v, CardTitle as y } from "@burdenoff/fe-libs/ui";
|
|
9
11
|
//#region src/planmagnet/pages/ProjectsPlanningPagePage.tsx
|
|
10
|
-
var
|
|
11
|
-
query GetSprints($workspaceId: ID
|
|
12
|
-
planmagnetSprints(workspaceId: $workspaceId, pagination: { first: 100 }) {
|
|
12
|
+
var b = u`
|
|
13
|
+
query GetSprints($workspaceId: ID!, $filter: PlanmagnetSprintFilter) {
|
|
14
|
+
planmagnetSprints(workspaceId: $workspaceId, filter: $filter, pagination: { first: 100 }) {
|
|
13
15
|
items {
|
|
14
16
|
id
|
|
15
17
|
name
|
|
@@ -18,6 +20,10 @@ var g = s`
|
|
|
18
20
|
id
|
|
19
21
|
name
|
|
20
22
|
}
|
|
23
|
+
team {
|
|
24
|
+
id
|
|
25
|
+
name
|
|
26
|
+
}
|
|
21
27
|
status
|
|
22
28
|
startDate
|
|
23
29
|
endDate
|
|
@@ -33,107 +39,121 @@ var g = s`
|
|
|
33
39
|
totalCount
|
|
34
40
|
}
|
|
35
41
|
}
|
|
36
|
-
`,
|
|
42
|
+
`, x = {
|
|
37
43
|
PLANNING: "bg-blue-100 text-blue-800",
|
|
38
44
|
ACTIVE: "bg-green-100 text-green-800",
|
|
39
45
|
REVIEW: "bg-purple-100 text-purple-800",
|
|
40
46
|
COMPLETED: "bg-gray-100 text-gray-800",
|
|
41
47
|
CANCELLED: "bg-red-100 text-red-800"
|
|
42
48
|
};
|
|
43
|
-
function
|
|
44
|
-
let { workspaceId:
|
|
45
|
-
|
|
49
|
+
function S() {
|
|
50
|
+
let { workspaceId: u } = e(), S = t(), [C, w] = o(""), { data: T, loading: E, error: D } = d(b, { variables: {
|
|
51
|
+
workspaceId: u ?? "default",
|
|
52
|
+
filter: C ? { teamId: C } : void 0
|
|
53
|
+
} });
|
|
54
|
+
if (E && !T) return /* @__PURE__ */ p("div", {
|
|
46
55
|
className: "flex items-center justify-center p-12",
|
|
47
|
-
children: /* @__PURE__ */
|
|
56
|
+
children: /* @__PURE__ */ p("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
|
|
48
57
|
});
|
|
49
|
-
if (
|
|
58
|
+
if (D) return /* @__PURE__ */ m("div", {
|
|
50
59
|
className: "p-6 text-red-500",
|
|
51
|
-
children: ["Error loading planning sessions: ",
|
|
60
|
+
children: ["Error loading planning sessions: ", D.message]
|
|
52
61
|
});
|
|
53
|
-
let
|
|
54
|
-
return /* @__PURE__ */
|
|
62
|
+
let O = T?.planmagnetSprints?.items ?? [];
|
|
63
|
+
return /* @__PURE__ */ m("div", {
|
|
55
64
|
className: "space-y-6 p-6",
|
|
56
65
|
children: [
|
|
57
|
-
/* @__PURE__ */
|
|
66
|
+
/* @__PURE__ */ m("div", {
|
|
58
67
|
className: "flex items-center justify-between",
|
|
59
|
-
children: [/* @__PURE__ */
|
|
68
|
+
children: [/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("h1", {
|
|
60
69
|
className: "text-2xl font-semibold",
|
|
61
70
|
children: "Planning Sessions"
|
|
62
|
-
}), /* @__PURE__ */
|
|
71
|
+
}), /* @__PURE__ */ m("p", {
|
|
63
72
|
className: "text-sm text-muted-foreground",
|
|
64
|
-
children: [
|
|
65
|
-
})] }), /* @__PURE__ */
|
|
73
|
+
children: [T?.planmagnetSprints?.totalCount ?? O.length, " sprints across all projects"]
|
|
74
|
+
})] }), /* @__PURE__ */ m("div", {
|
|
75
|
+
className: "flex items-center gap-2",
|
|
76
|
+
children: [/* @__PURE__ */ p(n, {
|
|
77
|
+
value: C,
|
|
78
|
+
onChange: w,
|
|
79
|
+
noneLabel: "All teams"
|
|
80
|
+
}), /* @__PURE__ */ p(a, { onCreated: (e) => S(r("/projects/planning-detail-page", e)) })]
|
|
81
|
+
})]
|
|
66
82
|
}),
|
|
67
|
-
/* @__PURE__ */
|
|
83
|
+
/* @__PURE__ */ p("div", {
|
|
68
84
|
className: "grid grid-cols-1 md:grid-cols-2 gap-4",
|
|
69
|
-
children:
|
|
70
|
-
let t = e.workItems.reduce((e, t) => e + (t.storyPoints ?? 0), 0),
|
|
71
|
-
return /* @__PURE__ */
|
|
72
|
-
...
|
|
73
|
-
children: [/* @__PURE__ */
|
|
85
|
+
children: O.map((e) => {
|
|
86
|
+
let t = e.workItems.reduce((e, t) => e + (t.storyPoints ?? 0), 0), n = e.capacity ?? 0, a = n > 0 ? Math.round(t / n * 100) : 0;
|
|
87
|
+
return /* @__PURE__ */ m(g, {
|
|
88
|
+
...i(() => S(r("/projects/planning-detail-page", e.id)), e.name),
|
|
89
|
+
children: [/* @__PURE__ */ p(v, {
|
|
74
90
|
className: "pb-2",
|
|
75
|
-
children: /* @__PURE__ */
|
|
91
|
+
children: /* @__PURE__ */ m("div", {
|
|
76
92
|
className: "flex items-center justify-between",
|
|
77
|
-
children: [/* @__PURE__ */
|
|
93
|
+
children: [/* @__PURE__ */ m(y, {
|
|
78
94
|
className: "text-base flex items-center gap-2",
|
|
79
|
-
children: [/* @__PURE__ */
|
|
80
|
-
}), /* @__PURE__ */
|
|
95
|
+
children: [/* @__PURE__ */ p(s, { className: "h-4 w-4 text-primary" }), e.name]
|
|
96
|
+
}), /* @__PURE__ */ p(h, {
|
|
81
97
|
variant: e.status === "COMPLETED" ? "default" : "secondary",
|
|
82
98
|
className: "capitalize",
|
|
83
99
|
children: e.status.toLowerCase().replace("_", " ")
|
|
84
100
|
})]
|
|
85
101
|
})
|
|
86
|
-
}), /* @__PURE__ */
|
|
102
|
+
}), /* @__PURE__ */ m(_, {
|
|
87
103
|
className: "space-y-3",
|
|
88
104
|
children: [
|
|
89
|
-
/* @__PURE__ */
|
|
105
|
+
/* @__PURE__ */ m("div", {
|
|
90
106
|
className: "flex gap-2",
|
|
91
|
-
children: [/* @__PURE__ */
|
|
92
|
-
className: `text-xs px-2 py-0.5 rounded-full capitalize ${
|
|
107
|
+
children: [/* @__PURE__ */ p("span", {
|
|
108
|
+
className: `text-xs px-2 py-0.5 rounded-full capitalize ${x[e.status] ?? "bg-gray-100"}`,
|
|
93
109
|
children: e.status.toLowerCase().replace("_", " ")
|
|
94
|
-
}), /* @__PURE__ */
|
|
110
|
+
}), /* @__PURE__ */ p("span", {
|
|
95
111
|
className: "text-xs text-muted-foreground flex items-center gap-1",
|
|
96
|
-
children:
|
|
112
|
+
children: e.team ? /* @__PURE__ */ m(f, { children: [
|
|
113
|
+
/* @__PURE__ */ p(l, { className: "h-3 w-3" }),
|
|
114
|
+
"Team: ",
|
|
115
|
+
e.team.name
|
|
116
|
+
] }) : /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p(c, { className: "h-3 w-3" }), e.project?.name ?? "Unknown project"] })
|
|
97
117
|
})]
|
|
98
118
|
}),
|
|
99
|
-
e.goal && /* @__PURE__ */
|
|
119
|
+
e.goal && /* @__PURE__ */ p("p", {
|
|
100
120
|
className: "text-sm text-muted-foreground",
|
|
101
121
|
children: e.goal
|
|
102
122
|
}),
|
|
103
|
-
/* @__PURE__ */
|
|
123
|
+
/* @__PURE__ */ m("div", {
|
|
104
124
|
className: "flex gap-3 text-xs text-muted-foreground",
|
|
105
|
-
children: [/* @__PURE__ */
|
|
125
|
+
children: [/* @__PURE__ */ m("span", {
|
|
106
126
|
className: "flex items-center gap-1",
|
|
107
127
|
children: [
|
|
108
|
-
/* @__PURE__ */
|
|
128
|
+
/* @__PURE__ */ p(s, { className: "h-3 w-3" }),
|
|
109
129
|
e.startDate ? new Date(e.startDate).toLocaleDateString() : "—",
|
|
110
130
|
" -",
|
|
111
131
|
" ",
|
|
112
132
|
e.endDate ? new Date(e.endDate).toLocaleDateString() : "—"
|
|
113
133
|
]
|
|
114
|
-
}), /* @__PURE__ */
|
|
134
|
+
}), /* @__PURE__ */ m("span", { children: [e.workItems.length, " work items"] })]
|
|
115
135
|
}),
|
|
116
|
-
|
|
136
|
+
n > 0 && /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ m("div", {
|
|
117
137
|
className: "flex justify-between text-xs mb-1",
|
|
118
|
-
children: [/* @__PURE__ */
|
|
138
|
+
children: [/* @__PURE__ */ p("span", {
|
|
119
139
|
className: "text-muted-foreground",
|
|
120
140
|
children: "Capacity"
|
|
121
|
-
}), /* @__PURE__ */
|
|
141
|
+
}), /* @__PURE__ */ m("span", {
|
|
122
142
|
className: "font-medium",
|
|
123
143
|
children: [
|
|
124
144
|
t,
|
|
125
145
|
"/",
|
|
126
|
-
|
|
146
|
+
n,
|
|
127
147
|
" pts (",
|
|
128
|
-
|
|
148
|
+
a,
|
|
129
149
|
"%)"
|
|
130
150
|
]
|
|
131
151
|
})]
|
|
132
|
-
}), /* @__PURE__ */
|
|
152
|
+
}), /* @__PURE__ */ p("div", {
|
|
133
153
|
className: "w-full h-2 rounded-full bg-muted overflow-hidden",
|
|
134
|
-
children: /* @__PURE__ */
|
|
135
|
-
className: `h-full rounded-full ${
|
|
136
|
-
style: { width: `${Math.min(
|
|
154
|
+
children: /* @__PURE__ */ p("div", {
|
|
155
|
+
className: `h-full rounded-full ${a > 90 ? "bg-red-400" : "bg-primary"}`,
|
|
156
|
+
style: { width: `${Math.min(a, 100)}%` }
|
|
137
157
|
})
|
|
138
158
|
})] })
|
|
139
159
|
]
|
|
@@ -141,7 +161,7 @@ function v() {
|
|
|
141
161
|
}, e.id);
|
|
142
162
|
})
|
|
143
163
|
}),
|
|
144
|
-
|
|
164
|
+
O.length === 0 && /* @__PURE__ */ p("p", {
|
|
145
165
|
className: "text-center text-muted-foreground py-8",
|
|
146
166
|
children: "No planning sessions found."
|
|
147
167
|
})
|
|
@@ -149,6 +169,6 @@ function v() {
|
|
|
149
169
|
});
|
|
150
170
|
}
|
|
151
171
|
//#endregion
|
|
152
|
-
export {
|
|
172
|
+
export { S as ProjectsPlanningPagePage };
|
|
153
173
|
|
|
154
174
|
//# sourceMappingURL=ProjectsPlanningPagePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectsPlanningPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProjectsPlanningPagePage.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, FolderKanban } from 'lucide-react';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { rowLinkProps, detailPath } from '../utils/rowNavigation';\nimport { NewSprintDialog } from '../sprints/SprintControls';\n\nconst GET_SPRINTS = gql`\n query GetSprints($workspaceId: ID!) {\n planmagnetSprints(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n projectId\n project {\n id\n name\n }\n status\n startDate\n endDate\n goal\n capacity\n velocity\n workItems {\n id\n status\n storyPoints\n }\n }\n totalCount\n }\n }\n`;\n\nconst statusColor: Record<string, string> = {\n PLANNING: 'bg-blue-100 text-blue-800',\n ACTIVE: 'bg-green-100 text-green-800',\n REVIEW: 'bg-purple-100 text-purple-800',\n COMPLETED: 'bg-gray-100 text-gray-800',\n CANCELLED: 'bg-red-100 text-red-800',\n};\n\nexport function ProjectsPlanningPagePage() {\n const { workspaceId } = usePlanMagnet();\n const navigate = usePlanMagnetNavigate();\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_SPRINTS, {\n variables: { workspaceId: workspaceId ?? 'default' },\n });\n\n // Only before the first load: a refetch after a sprint action must not blank\n // the page (it unmounted the controls mid-action).\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)\n return <div className=\"p-6 text-red-500\">Error loading planning sessions: {error.message}</div>;\n\n const sprints = data?.planmagnetSprints?.items ?? [];\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\">Planning Sessions</h1>\n <p className=\"text-sm text-muted-foreground\">\n {/* The server total, not the loaded page's length (BOFF-7970). */}\n {data?.planmagnetSprints?.totalCount ?? sprints.length} sprints across all projects\n </p>\n </div>\n <NewSprintDialog\n onCreated={(id) => navigate(detailPath('/projects/planning-detail-page', id))}\n />\n </div>\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {sprints.map(\n (sprint: {\n id: string;\n name: string;\n projectId: string;\n project: { id: string; name: string } | null;\n status: string;\n startDate: string | null;\n endDate: string | null;\n goal: string | null;\n capacity: number | null;\n velocity: number | null;\n workItems: { id: string; status: string; storyPoints: number | null }[];\n }) => {\n const totalPoints = sprint.workItems.reduce(\n (sum: number, wi: { storyPoints: number | null }) => sum + (wi.storyPoints ?? 0),\n 0\n );\n const allocatedCapacity = sprint.capacity ?? 0;\n const capPct =\n allocatedCapacity > 0 ? Math.round((totalPoints / allocatedCapacity) * 100) : 0;\n return (\n <Card\n key={sprint.id}\n {...rowLinkProps(\n () => navigate(detailPath('/projects/planning-detail-page', sprint.id)),\n sprint.name\n )}\n >\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base flex items-center gap-2\">\n <CalendarClock className=\"h-4 w-4 text-primary\" />\n {sprint.name}\n </CardTitle>\n <Badge\n variant={sprint.status === 'COMPLETED' ? 'default' : 'secondary'}\n className=\"capitalize\"\n >\n {sprint.status.toLowerCase().replace('_', ' ')}\n </Badge>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <div className=\"flex gap-2\">\n <span\n className={`text-xs px-2 py-0.5 rounded-full capitalize ${statusColor[sprint.status] ?? 'bg-gray-100'}`}\n >\n {sprint.status.toLowerCase().replace('_', ' ')}\n </span>\n <span className=\"text-xs text-muted-foreground flex items-center gap-1\">\n <FolderKanban className=\"h-3 w-3\" />\n {sprint.project?.name ?? 'Unknown project'}\n </span>\n </div>\n {sprint.goal && <p className=\"text-sm text-muted-foreground\">{sprint.goal}</p>}\n <div className=\"flex gap-3 text-xs text-muted-foreground\">\n <span className=\"flex items-center gap-1\">\n <CalendarClock className=\"h-3 w-3\" />\n {sprint.startDate\n ? new Date(sprint.startDate).toLocaleDateString()\n : '—'} -{' '}\n {sprint.endDate ? new Date(sprint.endDate).toLocaleDateString() : '—'}\n </span>\n <span>{sprint.workItems.length} work items</span>\n </div>\n {allocatedCapacity > 0 && (\n <div>\n <div className=\"flex justify-between text-xs mb-1\">\n <span className=\"text-muted-foreground\">Capacity</span>\n <span className=\"font-medium\">\n {totalPoints}/{allocatedCapacity} pts ({capPct}%)\n </span>\n </div>\n <div className=\"w-full h-2 rounded-full bg-muted overflow-hidden\">\n <div\n className={`h-full rounded-full ${capPct > 90 ? 'bg-red-400' : 'bg-primary'}`}\n style={{ width: `${Math.min(capPct, 100)}%` }}\n />\n </div>\n </div>\n )}\n </CardContent>\n </Card>\n );\n }\n )}\n </div>\n {sprints.length === 0 && (\n <p className=\"text-center text-muted-foreground py-8\">No planning sessions found.</p>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ProjectsPlanningPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProjectsPlanningPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Badge } from '@burdenoff/fe-libs/ui';\nimport { CalendarClock, FolderKanban, Users } from 'lucide-react';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { rowLinkProps, detailPath } from '../utils/rowNavigation';\nimport { NewSprintDialog } from '../sprints/SprintControls';\nimport { TeamSelect } from '../controls/Pickers';\n\nconst GET_SPRINTS = gql`\n query GetSprints($workspaceId: ID!, $filter: PlanmagnetSprintFilter) {\n planmagnetSprints(workspaceId: $workspaceId, filter: $filter, pagination: { first: 100 }) {\n items {\n id\n name\n projectId\n project {\n id\n name\n }\n team {\n id\n name\n }\n status\n startDate\n endDate\n goal\n capacity\n velocity\n workItems {\n id\n status\n storyPoints\n }\n }\n totalCount\n }\n }\n`;\n\nconst statusColor: Record<string, string> = {\n PLANNING: 'bg-blue-100 text-blue-800',\n ACTIVE: 'bg-green-100 text-green-800',\n REVIEW: 'bg-purple-100 text-purple-800',\n COMPLETED: 'bg-gray-100 text-gray-800',\n CANCELLED: 'bg-red-100 text-red-800',\n};\n\nexport function ProjectsPlanningPagePage() {\n const { workspaceId } = usePlanMagnet();\n const navigate = usePlanMagnetNavigate();\n // BOFF-8044: an optional team filter, symmetric with the already-schema-supported (but until now\n // UI-unused) projectId filter. '' means \"every team and every project\".\n const [teamFilter, setTeamFilter] = useState('');\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_SPRINTS, {\n variables: {\n workspaceId: workspaceId ?? 'default',\n filter: teamFilter ? { teamId: teamFilter } : undefined,\n },\n });\n\n // Only before the first load: a refetch after a sprint action must not blank\n // the page (it unmounted the controls mid-action).\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)\n return <div className=\"p-6 text-red-500\">Error loading planning sessions: {error.message}</div>;\n\n const sprints = data?.planmagnetSprints?.items ?? [];\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\">Planning Sessions</h1>\n <p className=\"text-sm text-muted-foreground\">\n {/* The server total, not the loaded page's length (BOFF-7970). */}\n {data?.planmagnetSprints?.totalCount ?? sprints.length} sprints across all projects\n </p>\n </div>\n <div className=\"flex items-center gap-2\">\n <TeamSelect value={teamFilter} onChange={setTeamFilter} noneLabel=\"All teams\" />\n <NewSprintDialog\n onCreated={(id) => navigate(detailPath('/projects/planning-detail-page', id))}\n />\n </div>\n </div>\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {sprints.map(\n (sprint: {\n id: string;\n name: string;\n projectId: string;\n project: { id: string; name: string } | null;\n team: { id: string; name: string } | null;\n status: string;\n startDate: string | null;\n endDate: string | null;\n goal: string | null;\n capacity: number | null;\n velocity: number | null;\n workItems: { id: string; status: string; storyPoints: number | null }[];\n }) => {\n const totalPoints = sprint.workItems.reduce(\n (sum: number, wi: { storyPoints: number | null }) => sum + (wi.storyPoints ?? 0),\n 0\n );\n const allocatedCapacity = sprint.capacity ?? 0;\n const capPct =\n allocatedCapacity > 0 ? Math.round((totalPoints / allocatedCapacity) * 100) : 0;\n return (\n <Card\n key={sprint.id}\n {...rowLinkProps(\n () => navigate(detailPath('/projects/planning-detail-page', sprint.id)),\n sprint.name\n )}\n >\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base flex items-center gap-2\">\n <CalendarClock className=\"h-4 w-4 text-primary\" />\n {sprint.name}\n </CardTitle>\n <Badge\n variant={sprint.status === 'COMPLETED' ? 'default' : 'secondary'}\n className=\"capitalize\"\n >\n {sprint.status.toLowerCase().replace('_', ' ')}\n </Badge>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <div className=\"flex gap-2\">\n <span\n className={`text-xs px-2 py-0.5 rounded-full capitalize ${statusColor[sprint.status] ?? 'bg-gray-100'}`}\n >\n {sprint.status.toLowerCase().replace('_', ' ')}\n </span>\n <span className=\"text-xs text-muted-foreground flex items-center gap-1\">\n {sprint.team ? (\n <>\n <Users className=\"h-3 w-3\" />\n Team: {sprint.team.name}\n </>\n ) : (\n <>\n <FolderKanban className=\"h-3 w-3\" />\n {sprint.project?.name ?? 'Unknown project'}\n </>\n )}\n </span>\n </div>\n {sprint.goal && <p className=\"text-sm text-muted-foreground\">{sprint.goal}</p>}\n <div className=\"flex gap-3 text-xs text-muted-foreground\">\n <span className=\"flex items-center gap-1\">\n <CalendarClock className=\"h-3 w-3\" />\n {sprint.startDate\n ? new Date(sprint.startDate).toLocaleDateString()\n : '—'} -{' '}\n {sprint.endDate ? new Date(sprint.endDate).toLocaleDateString() : '—'}\n </span>\n <span>{sprint.workItems.length} work items</span>\n </div>\n {allocatedCapacity > 0 && (\n <div>\n <div className=\"flex justify-between text-xs mb-1\">\n <span className=\"text-muted-foreground\">Capacity</span>\n <span className=\"font-medium\">\n {totalPoints}/{allocatedCapacity} pts ({capPct}%)\n </span>\n </div>\n <div className=\"w-full h-2 rounded-full bg-muted overflow-hidden\">\n <div\n className={`h-full rounded-full ${capPct > 90 ? 'bg-red-400' : 'bg-primary'}`}\n style={{ width: `${Math.min(capPct, 100)}%` }}\n />\n </div>\n </div>\n )}\n </CardContent>\n </Card>\n );\n }\n )}\n </div>\n {sprints.length === 0 && (\n <p className=\"text-center text-muted-foreground py-8\">No planning sessions found.</p>\n )}\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":"AAuHA,wBAAgB,6BAA6B,4CAiiB5C"}
|