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