@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,14 +1,15 @@
|
|
|
1
1
|
import { usePlanMagnet as e, usePlanMagnetNavigate as t } from "../providers/PlanMagnetProvider.js";
|
|
2
2
|
import { PersonName as n } from "../people/People.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
3
|
+
import { countLabel as r, useProjectCounts as i } from "../hooks/useCounts.js";
|
|
4
|
+
import { detailPath as a, rowLinkProps as o } from "../utils/rowNavigation.js";
|
|
5
|
+
import { CheckSquare as s, FolderKanban as c, Plus as l, TrendingUp as u, Users as d } from "lucide-react";
|
|
6
|
+
import { gql as f } from "@apollo/client";
|
|
7
|
+
import { useQuery as p } from "@apollo/client/react";
|
|
8
|
+
import { jsx as m, jsxs as h } from "react/jsx-runtime";
|
|
9
|
+
import { useI18n as g } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
10
|
+
import { Badge as _, Button as v, Card as y, CardContent as b, CardHeader as x, CardTitle as S } from "@burdenoff/fe-libs/ui";
|
|
10
11
|
//#region src/planmagnet/pages/ProjectsProjectsPagePage.tsx
|
|
11
|
-
var
|
|
12
|
+
var C = f`
|
|
12
13
|
query GetProjects($workspaceId: ID!) {
|
|
13
14
|
planmagnetProjects(workspaceId: $workspaceId, pagination: { first: 100 }) {
|
|
14
15
|
items {
|
|
@@ -27,139 +28,139 @@ var x = u`
|
|
|
27
28
|
totalCount
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
|
-
`,
|
|
31
|
+
`, w = {
|
|
31
32
|
SCRUM: "bg-blue-100 text-blue-800",
|
|
32
33
|
KANBAN: "bg-purple-100 text-purple-800",
|
|
33
34
|
WATERFALL: "bg-gray-100 text-gray-800",
|
|
34
35
|
HYBRID: "bg-teal-100 text-teal-800",
|
|
35
36
|
AGILE: "bg-indigo-100 text-indigo-800",
|
|
36
37
|
CUSTOM: "bg-amber-100 text-amber-800"
|
|
37
|
-
},
|
|
38
|
-
function
|
|
39
|
-
let
|
|
40
|
-
if (
|
|
38
|
+
}, T = (e) => e === "ACTIVE" ? "default" : "secondary";
|
|
39
|
+
function E() {
|
|
40
|
+
let f = t(), { workspaceId: E } = e(), { t: D } = g(), { data: O, loading: k, error: A } = p(C, { variables: { workspaceId: E ?? "default" } }), j = i();
|
|
41
|
+
if (k && !O) return /* @__PURE__ */ m("div", {
|
|
41
42
|
className: "flex items-center justify-center p-12",
|
|
42
|
-
children: /* @__PURE__ */
|
|
43
|
+
children: /* @__PURE__ */ m("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
|
|
43
44
|
});
|
|
44
|
-
if (
|
|
45
|
+
if (A) return /* @__PURE__ */ h("div", {
|
|
45
46
|
className: "p-6 text-red-500",
|
|
46
47
|
children: [
|
|
47
|
-
|
|
48
|
+
D("planmagnet.projects.errorLoading", "Error loading projects"),
|
|
48
49
|
": ",
|
|
49
|
-
|
|
50
|
+
A.message
|
|
50
51
|
]
|
|
51
52
|
});
|
|
52
|
-
let
|
|
53
|
-
total:
|
|
54
|
-
active:
|
|
55
|
-
completed:
|
|
56
|
-
onHold:
|
|
53
|
+
let M = O?.planmagnetProjects?.items ?? [], N = {
|
|
54
|
+
total: r(j?.all),
|
|
55
|
+
active: r(j?.active),
|
|
56
|
+
completed: r(j?.completed),
|
|
57
|
+
onHold: r(j?.onHold)
|
|
57
58
|
};
|
|
58
|
-
return /* @__PURE__ */
|
|
59
|
+
return /* @__PURE__ */ h("div", {
|
|
59
60
|
className: "space-y-6 p-6",
|
|
60
61
|
children: [
|
|
61
|
-
/* @__PURE__ */
|
|
62
|
+
/* @__PURE__ */ h("div", {
|
|
62
63
|
className: "flex items-center justify-between",
|
|
63
|
-
children: [/* @__PURE__ */
|
|
64
|
+
children: [/* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("h1", {
|
|
64
65
|
className: "text-2xl font-semibold",
|
|
65
|
-
children:
|
|
66
|
-
}), /* @__PURE__ */
|
|
66
|
+
children: D("planmagnet.projects.title", "All Projects")
|
|
67
|
+
}), /* @__PURE__ */ m("p", {
|
|
67
68
|
className: "text-sm text-muted-foreground",
|
|
68
|
-
children:
|
|
69
|
-
})] }), /* @__PURE__ */
|
|
69
|
+
children: D("planmagnet.projects.subtitle", "Manage and track all projects across teams")
|
|
70
|
+
})] }), /* @__PURE__ */ h(v, {
|
|
70
71
|
size: "sm",
|
|
71
|
-
onClick: () =>
|
|
72
|
-
children: [/* @__PURE__ */
|
|
72
|
+
onClick: () => f("/projects/create-project-page"),
|
|
73
|
+
children: [/* @__PURE__ */ m(l, { className: "mr-1 h-4 w-4" }), D("planmagnet.projects.actions.newProject", "New Project")]
|
|
73
74
|
})]
|
|
74
75
|
}),
|
|
75
|
-
/* @__PURE__ */
|
|
76
|
+
/* @__PURE__ */ m("div", {
|
|
76
77
|
className: "grid grid-cols-2 md:grid-cols-4 gap-4",
|
|
77
78
|
children: [
|
|
78
79
|
{
|
|
79
|
-
label:
|
|
80
|
-
value:
|
|
81
|
-
icon:
|
|
80
|
+
label: D("planmagnet.projects.metrics.totalProjects", "Total Projects"),
|
|
81
|
+
value: N.total,
|
|
82
|
+
icon: c
|
|
82
83
|
},
|
|
83
84
|
{
|
|
84
|
-
label:
|
|
85
|
-
value:
|
|
86
|
-
icon:
|
|
85
|
+
label: D("planmagnet.projects.metrics.active", "Active"),
|
|
86
|
+
value: N.active,
|
|
87
|
+
icon: u
|
|
87
88
|
},
|
|
88
89
|
{
|
|
89
|
-
label:
|
|
90
|
-
value:
|
|
91
|
-
icon:
|
|
90
|
+
label: D("planmagnet.projects.metrics.completed", "Completed"),
|
|
91
|
+
value: N.completed,
|
|
92
|
+
icon: s
|
|
92
93
|
},
|
|
93
94
|
{
|
|
94
|
-
label:
|
|
95
|
-
value:
|
|
96
|
-
icon:
|
|
95
|
+
label: D("planmagnet.projects.metrics.onHold", "On Hold"),
|
|
96
|
+
value: N.onHold,
|
|
97
|
+
icon: u
|
|
97
98
|
}
|
|
98
|
-
].map((e) => /* @__PURE__ */
|
|
99
|
+
].map((e) => /* @__PURE__ */ m(y, { children: /* @__PURE__ */ h(b, {
|
|
99
100
|
className: "pt-4",
|
|
100
|
-
children: [/* @__PURE__ */
|
|
101
|
+
children: [/* @__PURE__ */ h("div", {
|
|
101
102
|
className: "flex items-center gap-2 text-muted-foreground text-sm",
|
|
102
|
-
children: [/* @__PURE__ */
|
|
103
|
-
}), /* @__PURE__ */
|
|
103
|
+
children: [/* @__PURE__ */ m(e.icon, { className: "h-4 w-4" }), e.label]
|
|
104
|
+
}), /* @__PURE__ */ m("p", {
|
|
104
105
|
className: "text-xl font-semibold mt-1",
|
|
105
106
|
children: e.value
|
|
106
107
|
})]
|
|
107
108
|
}) }, e.label))
|
|
108
109
|
}),
|
|
109
|
-
/* @__PURE__ */
|
|
110
|
+
/* @__PURE__ */ m("div", {
|
|
110
111
|
className: "grid grid-cols-1 md:grid-cols-2 gap-4",
|
|
111
|
-
children:
|
|
112
|
-
...
|
|
113
|
-
children: [/* @__PURE__ */
|
|
112
|
+
children: M.map((e) => /* @__PURE__ */ h(y, {
|
|
113
|
+
...o(() => f(a("/projects/project-detail-page", e.id)), e.name),
|
|
114
|
+
children: [/* @__PURE__ */ m(x, {
|
|
114
115
|
className: "pb-2",
|
|
115
|
-
children: /* @__PURE__ */
|
|
116
|
+
children: /* @__PURE__ */ h("div", {
|
|
116
117
|
className: "flex items-center justify-between",
|
|
117
|
-
children: [/* @__PURE__ */
|
|
118
|
+
children: [/* @__PURE__ */ m(S, {
|
|
118
119
|
className: "text-base",
|
|
119
120
|
children: e.name
|
|
120
|
-
}), /* @__PURE__ */
|
|
121
|
+
}), /* @__PURE__ */ m("span", {
|
|
121
122
|
className: "text-xs text-muted-foreground font-mono",
|
|
122
123
|
children: e.key
|
|
123
124
|
})]
|
|
124
125
|
})
|
|
125
|
-
}), /* @__PURE__ */
|
|
126
|
+
}), /* @__PURE__ */ h(b, {
|
|
126
127
|
className: "space-y-3",
|
|
127
128
|
children: [
|
|
128
|
-
/* @__PURE__ */
|
|
129
|
+
/* @__PURE__ */ m("p", {
|
|
129
130
|
className: "text-sm text-muted-foreground",
|
|
130
|
-
children: e.description ??
|
|
131
|
+
children: e.description ?? D("planmagnet.projects.shared.noDescription", "No description")
|
|
131
132
|
}),
|
|
132
|
-
/* @__PURE__ */
|
|
133
|
+
/* @__PURE__ */ h("div", {
|
|
133
134
|
className: "flex gap-2",
|
|
134
|
-
children: [/* @__PURE__ */
|
|
135
|
-
variant:
|
|
135
|
+
children: [/* @__PURE__ */ m(_, {
|
|
136
|
+
variant: T(e.status),
|
|
136
137
|
className: "capitalize",
|
|
137
138
|
children: e.status.toLowerCase().replace("_", " ")
|
|
138
|
-
}), /* @__PURE__ */
|
|
139
|
-
className: `text-xs px-2 py-0.5 rounded-full capitalize ${
|
|
139
|
+
}), /* @__PURE__ */ m("span", {
|
|
140
|
+
className: `text-xs px-2 py-0.5 rounded-full capitalize ${w[e.methodology] ?? "bg-gray-100"}`,
|
|
140
141
|
children: e.methodology.toLowerCase()
|
|
141
142
|
})]
|
|
142
143
|
}),
|
|
143
|
-
e.tags.length > 0 && /* @__PURE__ */
|
|
144
|
+
e.tags.length > 0 && /* @__PURE__ */ m("div", {
|
|
144
145
|
className: "flex gap-1 flex-wrap",
|
|
145
|
-
children: e.tags.map((e) => /* @__PURE__ */
|
|
146
|
+
children: e.tags.map((e) => /* @__PURE__ */ m(_, {
|
|
146
147
|
variant: "outline",
|
|
147
148
|
className: "text-xs",
|
|
148
149
|
children: e
|
|
149
150
|
}, e))
|
|
150
151
|
}),
|
|
151
|
-
/* @__PURE__ */
|
|
152
|
+
/* @__PURE__ */ h("div", {
|
|
152
153
|
className: "flex justify-between text-xs text-muted-foreground border-t pt-2",
|
|
153
|
-
children: [/* @__PURE__ */
|
|
154
|
+
children: [/* @__PURE__ */ h("span", {
|
|
154
155
|
className: "flex items-center gap-1",
|
|
155
156
|
children: [
|
|
156
|
-
/* @__PURE__ */
|
|
157
|
-
|
|
157
|
+
/* @__PURE__ */ m(d, { className: "h-3 w-3" }),
|
|
158
|
+
D("planmagnet.projects.shared.owner", "Owner"),
|
|
158
159
|
":",
|
|
159
160
|
" ",
|
|
160
|
-
/* @__PURE__ */
|
|
161
|
+
/* @__PURE__ */ m(n, { id: e.ownerId })
|
|
161
162
|
]
|
|
162
|
-
}), /* @__PURE__ */
|
|
163
|
+
}), /* @__PURE__ */ h("span", { children: [
|
|
163
164
|
e.startDate ? new Date(e.startDate).toLocaleDateString() : "—",
|
|
164
165
|
" -",
|
|
165
166
|
" ",
|
|
@@ -170,14 +171,14 @@ function w() {
|
|
|
170
171
|
})]
|
|
171
172
|
}, e.id))
|
|
172
173
|
}),
|
|
173
|
-
|
|
174
|
+
M.length === 0 && /* @__PURE__ */ m("p", {
|
|
174
175
|
className: "text-center text-muted-foreground py-8",
|
|
175
|
-
children:
|
|
176
|
+
children: D("planmagnet.projects.empty", "No projects found.")
|
|
176
177
|
})
|
|
177
178
|
]
|
|
178
179
|
});
|
|
179
180
|
}
|
|
180
181
|
//#endregion
|
|
181
|
-
export {
|
|
182
|
+
export { E as ProjectsProjectsPagePage };
|
|
182
183
|
|
|
183
184
|
//# sourceMappingURL=ProjectsProjectsPagePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectsProjectsPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProjectsProjectsPagePage.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, Button } from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { FolderKanban, Plus, Users, CheckSquare, TrendingUp } from 'lucide-react';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { rowLinkProps, detailPath } from '../utils/rowNavigation';\nimport { PersonName } from '../people/People';\n\nconst GET_PROJECTS = gql`\n query GetProjects($workspaceId: ID!) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n key\n description\n status\n methodology\n ownerId\n startDate\n endDate\n tags\n createdAt\n }\n totalCount\n }\n }\n`;\n\nconst methodColor: Record<string, string> = {\n SCRUM: 'bg-blue-100 text-blue-800',\n KANBAN: 'bg-purple-100 text-purple-800',\n WATERFALL: 'bg-gray-100 text-gray-800',\n HYBRID: 'bg-teal-100 text-teal-800',\n AGILE: 'bg-indigo-100 text-indigo-800',\n CUSTOM: 'bg-amber-100 text-amber-800',\n};\n\nconst statusVariant = (status: string) => (status === 'ACTIVE' ? 'default' : 'secondary');\n\nexport function ProjectsProjectsPagePage() {\n const navigate = usePlanMagnetNavigate();\n const { workspaceId } = usePlanMagnet();\n const { t } = useI18n();\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_PROJECTS, {\n variables: { workspaceId: workspaceId ?? 'default' },\n });\n\n // Only before the first load: a refetch must not blank the page (it\n\n // unmounts every component on it and loses their state).\n\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 (\n <div className=\"p-6 text-red-500\">\n {t('planmagnet.projects.errorLoading', 'Error loading projects')}: {error.message}\n </div>\n );\n\n const projects = data?.planmagnetProjects?.items ?? [];\n\n const stats = {\n total: projects.length,\n active: projects.filter((p: { status: string }) => p.status === 'ACTIVE').length,\n completed: projects.filter((p: { status: string }) => p.status === 'COMPLETED').length,\n onHold: projects.filter((p: { status: string }) => p.status === 'ON_HOLD').length,\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\">\n {t('planmagnet.projects.title', 'All Projects')}\n </h1>\n <p className=\"text-sm text-muted-foreground\">\n {t('planmagnet.projects.subtitle', 'Manage and track all projects across teams')}\n </p>\n </div>\n <Button size=\"sm\" onClick={() => navigate('/projects/create-project-page')}>\n <Plus className=\"mr-1 h-4 w-4\" />\n {t('planmagnet.projects.actions.newProject', 'New Project')}\n </Button>\n </div>\n\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n {[\n {\n label: t('planmagnet.projects.metrics.totalProjects', 'Total Projects'),\n value: stats.total,\n icon: FolderKanban,\n },\n {\n label: t('planmagnet.projects.metrics.active', 'Active'),\n value: stats.active,\n icon: TrendingUp,\n },\n {\n label: t('planmagnet.projects.metrics.completed', 'Completed'),\n value: stats.completed,\n icon: CheckSquare,\n },\n {\n label: t('planmagnet.projects.metrics.onHold', 'On Hold'),\n value: stats.onHold,\n icon: TrendingUp,\n },\n ].map((s) => (\n <Card key={s.label}>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-sm\">\n <s.icon className=\"h-4 w-4\" />\n {s.label}\n </div>\n <p className=\"text-xl font-semibold mt-1\">{s.value}</p>\n </CardContent>\n </Card>\n ))}\n </div>\n\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {projects.map(\n (project: {\n id: string;\n name: string;\n key: string;\n description: string | null;\n status: string;\n methodology: string;\n ownerId: string;\n startDate: string | null;\n endDate: string | null;\n tags: string[];\n }) => {\n return (\n <Card\n key={project.id}\n {...rowLinkProps(\n () => navigate(detailPath('/projects/project-detail-page', project.id)),\n project.name\n )}\n >\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base\">{project.name}</CardTitle>\n <span className=\"text-xs text-muted-foreground font-mono\">{project.key}</span>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <p className=\"text-sm text-muted-foreground\">\n {project.description ??\n t('planmagnet.projects.shared.noDescription', 'No description')}\n </p>\n <div className=\"flex gap-2\">\n <Badge variant={statusVariant(project.status)} className=\"capitalize\">\n {project.status.toLowerCase().replace('_', ' ')}\n </Badge>\n <span\n className={`text-xs px-2 py-0.5 rounded-full capitalize ${methodColor[project.methodology] ?? 'bg-gray-100'}`}\n >\n {project.methodology.toLowerCase()}\n </span>\n </div>\n {project.tags.length > 0 && (\n <div className=\"flex gap-1 flex-wrap\">\n {project.tags.map((tag: string) => (\n <Badge key={tag} variant=\"outline\" className=\"text-xs\">\n {tag}\n </Badge>\n ))}\n </div>\n )}\n <div className=\"flex justify-between text-xs text-muted-foreground border-t pt-2\">\n <span className=\"flex items-center gap-1\">\n <Users className=\"h-3 w-3\" />\n {t('planmagnet.projects.shared.owner', 'Owner')}:{' '}\n <PersonName id={project.ownerId} />\n </span>\n <span>\n {project.startDate ? new Date(project.startDate).toLocaleDateString() : '—'} -{' '}\n {project.endDate ? new Date(project.endDate).toLocaleDateString() : '—'}\n </span>\n </div>\n </CardContent>\n </Card>\n );\n }\n )}\n </div>\n {projects.length === 0 && (\n <p className=\"text-center text-muted-foreground py-8\">\n {t('planmagnet.projects.empty', 'No projects found.')}\n </p>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ProjectsProjectsPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProjectsProjectsPagePage.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, Button } from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { FolderKanban, Plus, Users, CheckSquare, TrendingUp } from 'lucide-react';\nimport { countLabel, useProjectCounts } from '../hooks/useCounts';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { rowLinkProps, detailPath } from '../utils/rowNavigation';\nimport { PersonName } from '../people/People';\n\nconst GET_PROJECTS = gql`\n query GetProjects($workspaceId: ID!) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n key\n description\n status\n methodology\n ownerId\n startDate\n endDate\n tags\n createdAt\n }\n totalCount\n }\n }\n`;\n\nconst methodColor: Record<string, string> = {\n SCRUM: 'bg-blue-100 text-blue-800',\n KANBAN: 'bg-purple-100 text-purple-800',\n WATERFALL: 'bg-gray-100 text-gray-800',\n HYBRID: 'bg-teal-100 text-teal-800',\n AGILE: 'bg-indigo-100 text-indigo-800',\n CUSTOM: 'bg-amber-100 text-amber-800',\n};\n\nconst statusVariant = (status: string) => (status === 'ACTIVE' ? 'default' : 'secondary');\n\nexport function ProjectsProjectsPagePage() {\n const navigate = usePlanMagnetNavigate();\n const { workspaceId } = usePlanMagnet();\n const { t } = useI18n();\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_PROJECTS, {\n variables: { workspaceId: workspaceId ?? 'default' },\n });\n // Server counts (BOFF-7969): these tiles counted the rows of one 100-row page.\n const counts = useProjectCounts();\n\n // Only before the first load: a refetch must not blank the page (it\n\n // unmounts every component on it and loses their state).\n\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 (\n <div className=\"p-6 text-red-500\">\n {t('planmagnet.projects.errorLoading', 'Error loading projects')}: {error.message}\n </div>\n );\n\n const projects = data?.planmagnetProjects?.items ?? [];\n\n const stats = {\n total: countLabel(counts?.all),\n active: countLabel(counts?.active),\n completed: countLabel(counts?.completed),\n onHold: countLabel(counts?.onHold),\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\">\n {t('planmagnet.projects.title', 'All Projects')}\n </h1>\n <p className=\"text-sm text-muted-foreground\">\n {t('planmagnet.projects.subtitle', 'Manage and track all projects across teams')}\n </p>\n </div>\n <Button size=\"sm\" onClick={() => navigate('/projects/create-project-page')}>\n <Plus className=\"mr-1 h-4 w-4\" />\n {t('planmagnet.projects.actions.newProject', 'New Project')}\n </Button>\n </div>\n\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n {[\n {\n label: t('planmagnet.projects.metrics.totalProjects', 'Total Projects'),\n value: stats.total,\n icon: FolderKanban,\n },\n {\n label: t('planmagnet.projects.metrics.active', 'Active'),\n value: stats.active,\n icon: TrendingUp,\n },\n {\n label: t('planmagnet.projects.metrics.completed', 'Completed'),\n value: stats.completed,\n icon: CheckSquare,\n },\n {\n label: t('planmagnet.projects.metrics.onHold', 'On Hold'),\n value: stats.onHold,\n icon: TrendingUp,\n },\n ].map((s) => (\n <Card key={s.label}>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-sm\">\n <s.icon className=\"h-4 w-4\" />\n {s.label}\n </div>\n <p className=\"text-xl font-semibold mt-1\">{s.value}</p>\n </CardContent>\n </Card>\n ))}\n </div>\n\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {projects.map(\n (project: {\n id: string;\n name: string;\n key: string;\n description: string | null;\n status: string;\n methodology: string;\n ownerId: string;\n startDate: string | null;\n endDate: string | null;\n tags: string[];\n }) => {\n return (\n <Card\n key={project.id}\n {...rowLinkProps(\n () => navigate(detailPath('/projects/project-detail-page', project.id)),\n project.name\n )}\n >\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base\">{project.name}</CardTitle>\n <span className=\"text-xs text-muted-foreground font-mono\">{project.key}</span>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <p className=\"text-sm text-muted-foreground\">\n {project.description ??\n t('planmagnet.projects.shared.noDescription', 'No description')}\n </p>\n <div className=\"flex gap-2\">\n <Badge variant={statusVariant(project.status)} className=\"capitalize\">\n {project.status.toLowerCase().replace('_', ' ')}\n </Badge>\n <span\n className={`text-xs px-2 py-0.5 rounded-full capitalize ${methodColor[project.methodology] ?? 'bg-gray-100'}`}\n >\n {project.methodology.toLowerCase()}\n </span>\n </div>\n {project.tags.length > 0 && (\n <div className=\"flex gap-1 flex-wrap\">\n {project.tags.map((tag: string) => (\n <Badge key={tag} variant=\"outline\" className=\"text-xs\">\n {tag}\n </Badge>\n ))}\n </div>\n )}\n <div className=\"flex justify-between text-xs text-muted-foreground border-t pt-2\">\n <span className=\"flex items-center gap-1\">\n <Users className=\"h-3 w-3\" />\n {t('planmagnet.projects.shared.owner', 'Owner')}:{' '}\n <PersonName id={project.ownerId} />\n </span>\n <span>\n {project.startDate ? new Date(project.startDate).toLocaleDateString() : '—'} -{' '}\n {project.endDate ? new Date(project.endDate).toLocaleDateString() : '—'}\n </span>\n </div>\n </CardContent>\n </Card>\n );\n }\n )}\n </div>\n {projects.length === 0 && (\n <p className=\"text-center text-muted-foreground py-8\">\n {t('planmagnet.projects.empty', 'No projects found.')}\n </p>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reports (BOFF-7967). There is no saved-report model and no report runner yet, so there are no reports to list.
|
|
3
|
+
* This page used to invent them — one "Velocity Report" per completed sprint, one "Burndown" per active sprint, one
|
|
4
|
+
* "Status Report" per active project — with made-up schedules, "Run Today" counts for reports that never ran, and
|
|
5
|
+
* the viewer named as their creator. It now says so, and points to where the same analysis lives, computed on the
|
|
6
|
+
* server from real data.
|
|
7
|
+
*/
|
|
1
8
|
export declare function ReportsReportsPagePage(): import("react/jsx-runtime").JSX.Element;
|
|
2
9
|
//# sourceMappingURL=ReportsReportsPagePage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReportsReportsPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ReportsReportsPagePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ReportsReportsPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ReportsReportsPagePage.tsx"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,wBAAgB,sBAAsB,4CA+CrC"}
|
|
@@ -1,211 +1,49 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { useQuery as c } from "@apollo/client/react";
|
|
6
|
-
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
7
|
-
import { Button as d, Card as f, CardContent as p, CardHeader as m, CardTitle as h } from "@burdenoff/fe-libs/ui";
|
|
1
|
+
import { usePlanMagnetNavigate as e } from "../providers/PlanMagnetProvider.js";
|
|
2
|
+
import { BarChart3 as t, FileSpreadsheet as n, LineChart as r } from "lucide-react";
|
|
3
|
+
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
4
|
+
import { Button as o, Card as s, CardContent as c, CardHeader as l, CardTitle as u } from "@burdenoff/fe-libs/ui";
|
|
8
5
|
//#region src/planmagnet/pages/ReportsReportsPagePage.tsx
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
$projectPagination: PlanmagnetPaginationInput
|
|
13
|
-
$sprintPagination: PlanmagnetPaginationInput
|
|
14
|
-
$workItemPagination: PlanmagnetPaginationInput
|
|
15
|
-
) {
|
|
16
|
-
planmagnetProjects(workspaceId: $workspaceId, pagination: $projectPagination) {
|
|
17
|
-
items {
|
|
18
|
-
id
|
|
19
|
-
name
|
|
20
|
-
key
|
|
21
|
-
status
|
|
22
|
-
methodology
|
|
23
|
-
startDate
|
|
24
|
-
endDate
|
|
25
|
-
}
|
|
26
|
-
totalCount
|
|
27
|
-
}
|
|
28
|
-
planmagnetSprints(workspaceId: $workspaceId, pagination: $sprintPagination) {
|
|
29
|
-
items {
|
|
30
|
-
id
|
|
31
|
-
name
|
|
32
|
-
status
|
|
33
|
-
velocity
|
|
34
|
-
startDate
|
|
35
|
-
endDate
|
|
36
|
-
}
|
|
37
|
-
totalCount
|
|
38
|
-
}
|
|
39
|
-
planmagnetWorkItems(workspaceId: $workspaceId, pagination: $workItemPagination) {
|
|
40
|
-
items {
|
|
41
|
-
id
|
|
42
|
-
status
|
|
43
|
-
storyPoints
|
|
44
|
-
createdAt
|
|
45
|
-
}
|
|
46
|
-
totalCount
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
`, _ = {
|
|
50
|
-
velocity: "bg-blue-100 text-blue-800",
|
|
51
|
-
burndown: "bg-orange-100 text-orange-800",
|
|
52
|
-
burnup: "bg-green-100 text-green-800",
|
|
53
|
-
cumulative_flow: "bg-purple-100 text-purple-800",
|
|
54
|
-
cycle_time: "bg-yellow-100 text-yellow-800",
|
|
55
|
-
lead_time: "bg-pink-100 text-pink-800",
|
|
56
|
-
project_status: "bg-gray-100 text-gray-800"
|
|
57
|
-
};
|
|
58
|
-
function v() {
|
|
59
|
-
let { workspaceId: s } = e(), v = t(), [y, b] = n("all"), { data: x, loading: S, error: C } = c(g, {
|
|
60
|
-
variables: {
|
|
61
|
-
workspaceId: s,
|
|
62
|
-
projectPagination: { first: 100 },
|
|
63
|
-
sprintPagination: { first: 100 },
|
|
64
|
-
workItemPagination: { first: 500 }
|
|
65
|
-
},
|
|
66
|
-
skip: !s
|
|
67
|
-
});
|
|
68
|
-
if (S && !x) return /* @__PURE__ */ l("div", {
|
|
69
|
-
className: "flex items-center justify-center p-12",
|
|
70
|
-
children: /* @__PURE__ */ l("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
|
|
71
|
-
});
|
|
72
|
-
if (C) return /* @__PURE__ */ u("div", {
|
|
73
|
-
className: "p-6 text-red-500",
|
|
74
|
-
children: ["Error: ", C.message]
|
|
75
|
-
});
|
|
76
|
-
let w = x?.planmagnetProjects?.items ?? [], T = x?.planmagnetSprints?.items ?? [];
|
|
77
|
-
x?.planmagnetWorkItems?.items;
|
|
78
|
-
let E = T.filter((e) => e.status === "COMPLETED"), D = T.filter((e) => e.status === "ACTIVE"), O = [
|
|
79
|
-
...E.map((e) => ({
|
|
80
|
-
id: `velocity-${e.id}`,
|
|
81
|
-
name: `${e.name} Velocity Report`,
|
|
82
|
-
description: `Velocity analysis for ${e.name} (${e.velocity ?? 0} pts)`,
|
|
83
|
-
type: "velocity",
|
|
84
|
-
lastRun: e.endDate ?? "",
|
|
85
|
-
schedule: null
|
|
86
|
-
})),
|
|
87
|
-
...D.map((e) => ({
|
|
88
|
-
id: `burndown-${e.id}`,
|
|
89
|
-
name: `${e.name} Burndown`,
|
|
90
|
-
description: `Active burndown tracking for ${e.name}`,
|
|
91
|
-
type: "burndown",
|
|
92
|
-
lastRun: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
93
|
-
schedule: "daily"
|
|
94
|
-
})),
|
|
95
|
-
...w.filter((e) => e.status === "ACTIVE").map((e) => ({
|
|
96
|
-
id: `status-${e.id}`,
|
|
97
|
-
name: `${e.name} Status Report`,
|
|
98
|
-
description: `Project status overview for ${e.key}`,
|
|
99
|
-
type: "project_status",
|
|
100
|
-
lastRun: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
101
|
-
schedule: "weekly"
|
|
102
|
-
}))
|
|
103
|
-
], k = ["all", ...new Set(O.map((e) => e.type))], A = y === "all" ? O : O.filter((e) => e.type === y), j = O.filter((e) => e.schedule).length, M = (/* @__PURE__ */ new Date()).toISOString().split("T")[0], N = O.filter((e) => e.lastRun === M).length;
|
|
104
|
-
return /* @__PURE__ */ u("div", {
|
|
6
|
+
function d() {
|
|
7
|
+
let d = e();
|
|
8
|
+
return /* @__PURE__ */ a("div", {
|
|
105
9
|
className: "space-y-6 p-6",
|
|
106
|
-
children: [
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
10
|
+
children: [/* @__PURE__ */ a("div", { children: [/* @__PURE__ */ a("h1", {
|
|
11
|
+
className: "text-2xl font-semibold flex items-center gap-2",
|
|
12
|
+
children: [/* @__PURE__ */ i(t, { className: "h-6 w-6" }), "Reports"]
|
|
13
|
+
}), /* @__PURE__ */ i("p", {
|
|
14
|
+
className: "text-sm text-muted-foreground",
|
|
15
|
+
children: "Saved and scheduled reports are not available yet — there are none to show."
|
|
16
|
+
})] }), /* @__PURE__ */ i("div", {
|
|
17
|
+
className: "grid gap-4 md:grid-cols-2",
|
|
18
|
+
children: [{
|
|
19
|
+
title: "Analytics",
|
|
20
|
+
body: "Sprint burndown, velocity, cumulative flow, cycle time and delivery health for any project.",
|
|
21
|
+
icon: r,
|
|
22
|
+
to: "/analytics/analytics-page"
|
|
23
|
+
}, {
|
|
24
|
+
title: "Task Board export",
|
|
25
|
+
body: "Download every work item that matches the board’s filters as CSV.",
|
|
26
|
+
icon: n,
|
|
27
|
+
to: "/tasks/tasks-page"
|
|
28
|
+
}].map((e) => /* @__PURE__ */ a(s, { children: [/* @__PURE__ */ i(l, { children: /* @__PURE__ */ a(u, {
|
|
29
|
+
className: "flex items-center gap-2 text-base",
|
|
30
|
+
children: [/* @__PURE__ */ i(e.icon, { className: "h-5 w-5 text-primary" }), e.title]
|
|
31
|
+
}) }), /* @__PURE__ */ a(c, {
|
|
32
|
+
className: "space-y-3",
|
|
33
|
+
children: [/* @__PURE__ */ i("p", {
|
|
113
34
|
className: "text-sm text-muted-foreground",
|
|
114
|
-
children:
|
|
115
|
-
})
|
|
35
|
+
children: e.body
|
|
36
|
+
}), /* @__PURE__ */ a(o, {
|
|
116
37
|
size: "sm",
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}),
|
|
121
|
-
/* @__PURE__ */ u("div", {
|
|
122
|
-
className: "grid grid-cols-3 gap-4",
|
|
123
|
-
children: [
|
|
124
|
-
/* @__PURE__ */ l(f, { children: /* @__PURE__ */ u(p, {
|
|
125
|
-
className: "pt-4",
|
|
126
|
-
children: [/* @__PURE__ */ l("p", {
|
|
127
|
-
className: "text-xs text-muted-foreground",
|
|
128
|
-
children: "Total Reports"
|
|
129
|
-
}), /* @__PURE__ */ l("p", {
|
|
130
|
-
className: "text-xl font-bold",
|
|
131
|
-
children: O.length
|
|
132
|
-
})]
|
|
133
|
-
}) }),
|
|
134
|
-
/* @__PURE__ */ l(f, { children: /* @__PURE__ */ u(p, {
|
|
135
|
-
className: "pt-4",
|
|
136
|
-
children: [/* @__PURE__ */ l("p", {
|
|
137
|
-
className: "text-xs text-muted-foreground",
|
|
138
|
-
children: "Scheduled"
|
|
139
|
-
}), /* @__PURE__ */ l("p", {
|
|
140
|
-
className: "text-xl font-bold",
|
|
141
|
-
children: j
|
|
142
|
-
})]
|
|
143
|
-
}) }),
|
|
144
|
-
/* @__PURE__ */ l(f, { children: /* @__PURE__ */ u(p, {
|
|
145
|
-
className: "pt-4",
|
|
146
|
-
children: [/* @__PURE__ */ l("p", {
|
|
147
|
-
className: "text-xs text-muted-foreground",
|
|
148
|
-
children: "Run Today"
|
|
149
|
-
}), /* @__PURE__ */ l("p", {
|
|
150
|
-
className: "text-xl font-bold",
|
|
151
|
-
children: N
|
|
152
|
-
})]
|
|
153
|
-
}) })
|
|
154
|
-
]
|
|
155
|
-
}),
|
|
156
|
-
/* @__PURE__ */ l("div", {
|
|
157
|
-
className: "flex gap-1",
|
|
158
|
-
children: k.map((e) => /* @__PURE__ */ l("button", {
|
|
159
|
-
onClick: () => b(e),
|
|
160
|
-
className: `px-3 py-1.5 text-sm rounded-md capitalize ${y === e ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-muted"}`,
|
|
161
|
-
children: e === "all" ? "All" : e.replace("_", " ")
|
|
162
|
-
}, e))
|
|
163
|
-
}),
|
|
164
|
-
/* @__PURE__ */ u("div", {
|
|
165
|
-
className: "grid grid-cols-1 md:grid-cols-2 gap-4",
|
|
166
|
-
children: [A.map((e) => /* @__PURE__ */ u(f, { children: [/* @__PURE__ */ l(m, {
|
|
167
|
-
className: "pb-2",
|
|
168
|
-
children: /* @__PURE__ */ u("div", {
|
|
169
|
-
className: "flex items-center justify-between",
|
|
170
|
-
children: [/* @__PURE__ */ u(h, {
|
|
171
|
-
className: "text-base flex items-center gap-2",
|
|
172
|
-
children: [/* @__PURE__ */ l(r, { className: "h-4 w-4 text-primary" }), e.name]
|
|
173
|
-
}), /* @__PURE__ */ l("span", {
|
|
174
|
-
className: `text-xs px-2 py-0.5 rounded-full capitalize ${_[e.type] ?? "bg-gray-100"}`,
|
|
175
|
-
children: e.type.replace("_", " ")
|
|
176
|
-
})]
|
|
177
|
-
})
|
|
178
|
-
}), /* @__PURE__ */ u(p, {
|
|
179
|
-
className: "space-y-2",
|
|
180
|
-
children: [/* @__PURE__ */ l("p", {
|
|
181
|
-
className: "text-sm text-muted-foreground",
|
|
182
|
-
children: e.description
|
|
183
|
-
}), /* @__PURE__ */ u("div", {
|
|
184
|
-
className: "flex gap-3 text-xs text-muted-foreground",
|
|
185
|
-
children: [e.schedule && /* @__PURE__ */ u("span", {
|
|
186
|
-
className: "flex items-center gap-1",
|
|
187
|
-
children: [/* @__PURE__ */ l(a, { className: "h-3 w-3" }), e.schedule]
|
|
188
|
-
}), e.lastRun && /* @__PURE__ */ u("span", {
|
|
189
|
-
className: "flex items-center gap-1",
|
|
190
|
-
children: [
|
|
191
|
-
/* @__PURE__ */ l(i, { className: "h-3 w-3" }),
|
|
192
|
-
"Last: ",
|
|
193
|
-
e.lastRun
|
|
194
|
-
]
|
|
195
|
-
})]
|
|
196
|
-
})]
|
|
197
|
-
})] }, e.id)), A.length === 0 && /* @__PURE__ */ u("div", {
|
|
198
|
-
className: "col-span-2 text-center py-12",
|
|
199
|
-
children: [/* @__PURE__ */ l(r, { className: "h-12 w-12 text-muted-foreground mx-auto mb-3" }), /* @__PURE__ */ l("p", {
|
|
200
|
-
className: "text-sm text-muted-foreground",
|
|
201
|
-
children: "No reports found for the selected filter."
|
|
202
|
-
})]
|
|
38
|
+
variant: "outline",
|
|
39
|
+
onClick: () => d(e.to),
|
|
40
|
+
children: ["Open ", e.title]
|
|
203
41
|
})]
|
|
204
|
-
})
|
|
205
|
-
]
|
|
42
|
+
})] }, e.title))
|
|
43
|
+
})]
|
|
206
44
|
});
|
|
207
45
|
}
|
|
208
46
|
//#endregion
|
|
209
|
-
export {
|
|
47
|
+
export { d as ReportsReportsPagePage };
|
|
210
48
|
|
|
211
49
|
//# sourceMappingURL=ReportsReportsPagePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReportsReportsPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ReportsReportsPagePage.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, Button } from '@burdenoff/fe-libs/ui';\nimport { BarChart3, Plus, Clock, Calendar } from 'lucide-react';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\n\nconst GET_REPORTS_DATA = gql`\n query GetReportsData(\n $workspaceId: ID!\n $projectPagination: PlanmagnetPaginationInput\n $sprintPagination: PlanmagnetPaginationInput\n $workItemPagination: PlanmagnetPaginationInput\n ) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: $projectPagination) {\n items {\n id\n name\n key\n status\n methodology\n startDate\n endDate\n }\n totalCount\n }\n planmagnetSprints(workspaceId: $workspaceId, pagination: $sprintPagination) {\n items {\n id\n name\n status\n velocity\n startDate\n endDate\n }\n totalCount\n }\n planmagnetWorkItems(workspaceId: $workspaceId, pagination: $workItemPagination) {\n items {\n id\n status\n storyPoints\n createdAt\n }\n totalCount\n }\n }\n`;\n\ninterface ProjectNode {\n id: string;\n name: string;\n key: string;\n status: string;\n methodology: string | null;\n startDate: string | null;\n endDate: string | null;\n}\n\ninterface SprintNode {\n id: string;\n name: string;\n status: string;\n velocity: number | null;\n startDate: string | null;\n endDate: string | null;\n}\n\ninterface WorkItemNode {\n id: string;\n status: string;\n storyPoints: number | null;\n createdAt: string;\n}\n\ninterface ReportsData {\n projects: { items: ProjectNode[]; totalCount: number };\n sprints: { items: SprintNode[]; totalCount: number };\n workItems: { items: WorkItemNode[]; totalCount: number };\n}\n\nconst typeColor: Record<string, string> = {\n velocity: 'bg-blue-100 text-blue-800',\n burndown: 'bg-orange-100 text-orange-800',\n burnup: 'bg-green-100 text-green-800',\n cumulative_flow: 'bg-purple-100 text-purple-800',\n cycle_time: 'bg-yellow-100 text-yellow-800',\n lead_time: 'bg-pink-100 text-pink-800',\n project_status: 'bg-gray-100 text-gray-800',\n};\n\nexport function ReportsReportsPagePage() {\n const { workspaceId } = usePlanMagnet();\n const navigate = usePlanMagnetNavigate();\n const [typeFilter, setTypeFilter] = useState<string>('all');\n\n const { data, loading, error } = useQuery<ReportsData>(GET_REPORTS_DATA, {\n variables: {\n workspaceId,\n projectPagination: { first: 100 },\n sprintPagination: { first: 100 },\n workItemPagination: { first: 500 },\n },\n skip: !workspaceId,\n });\n\n // Only before the first load: a refetch must not blank the page (it\n\n // unmounts every component on it and loses their state).\n\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 }\n\n if (error) {\n return <div className=\"p-6 text-red-500\">Error: {error.message}</div>;\n }\n\n const projects = data?.planmagnetProjects?.items ?? [];\n const sprints = data?.planmagnetSprints?.items ?? [];\n const workItems = data?.planmagnetWorkItems?.items ?? [];\n\n const completedSprints = sprints.filter((s) => s.status === 'COMPLETED');\n const activeSprints = sprints.filter((s) => s.status === 'ACTIVE');\n\n const reports = [\n ...completedSprints.map((sprint) => ({\n id: `velocity-${sprint.id}`,\n name: `${sprint.name} Velocity Report`,\n description: `Velocity analysis for ${sprint.name} (${sprint.velocity ?? 0} pts)`,\n type: 'velocity',\n lastRun: sprint.endDate ?? '',\n schedule: null as string | null,\n })),\n ...activeSprints.map((sprint) => ({\n id: `burndown-${sprint.id}`,\n name: `${sprint.name} Burndown`,\n description: `Active burndown tracking for ${sprint.name}`,\n type: 'burndown',\n lastRun: new Date().toISOString().split('T')[0],\n schedule: 'daily' as string | null,\n })),\n ...projects\n .filter((p) => p.status === 'ACTIVE')\n .map((project) => ({\n id: `status-${project.id}`,\n name: `${project.name} Status Report`,\n description: `Project status overview for ${project.key}`,\n type: 'project_status',\n lastRun: new Date().toISOString().split('T')[0],\n schedule: 'weekly' as string | null,\n })),\n ];\n\n const types = ['all', ...new Set(reports.map((r) => r.type))];\n const filtered = typeFilter === 'all' ? reports : reports.filter((r) => r.type === typeFilter);\n\n const scheduledCount = reports.filter((r) => r.schedule).length;\n const todayStr = new Date().toISOString().split('T')[0];\n const runTodayCount = reports.filter((r) => r.lastRun === todayStr).length;\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\">Reports</h1>\n <p className=\"text-sm text-muted-foreground\">{reports.length} reports configured</p>\n </div>\n {/* The route is `reports/create-report-page`; `/reports/create` has never\n existed, so this button navigated into the catch-all. */}\n <Button size=\"sm\" onClick={() => navigate('/reports/create-report-page')}>\n <Plus className=\"mr-1 h-4 w-4\" />\n New Report\n </Button>\n </div>\n <div className=\"grid grid-cols-3 gap-4\">\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-xs text-muted-foreground\">Total Reports</p>\n <p className=\"text-xl font-bold\">{reports.length}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-xs text-muted-foreground\">Scheduled</p>\n <p className=\"text-xl font-bold\">{scheduledCount}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-xs text-muted-foreground\">Run Today</p>\n <p className=\"text-xl font-bold\">{runTodayCount}</p>\n </CardContent>\n </Card>\n </div>\n <div className=\"flex gap-1\">\n {types.map((t) => (\n <button\n key={t}\n onClick={() => setTypeFilter(t)}\n className={`px-3 py-1.5 text-sm rounded-md capitalize ${typeFilter === t ? 'bg-primary text-primary-foreground' : 'text-muted-foreground hover:bg-muted'}`}\n >\n {t === 'all' ? 'All' : t.replace('_', ' ')}\n </button>\n ))}\n </div>\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {filtered.map((report) => (\n <Card key={report.id}>\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base flex items-center gap-2\">\n <BarChart3 className=\"h-4 w-4 text-primary\" />\n {report.name}\n </CardTitle>\n <span\n className={`text-xs px-2 py-0.5 rounded-full capitalize ${typeColor[report.type] ?? 'bg-gray-100'}`}\n >\n {report.type.replace('_', ' ')}\n </span>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n <p className=\"text-sm text-muted-foreground\">{report.description}</p>\n <div className=\"flex gap-3 text-xs text-muted-foreground\">\n {report.schedule && (\n <span className=\"flex items-center gap-1\">\n <Clock className=\"h-3 w-3\" />\n {report.schedule}\n </span>\n )}\n {report.lastRun && (\n <span className=\"flex items-center gap-1\">\n <Calendar className=\"h-3 w-3\" />\n Last: {report.lastRun}\n </span>\n )}\n </div>\n </CardContent>\n </Card>\n ))}\n {filtered.length === 0 && (\n <div className=\"col-span-2 text-center py-12\">\n <BarChart3 className=\"h-12 w-12 text-muted-foreground mx-auto mb-3\" />\n <p className=\"text-sm text-muted-foreground\">\n No reports found for the selected filter.\n </p>\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ReportsReportsPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ReportsReportsPagePage.tsx"],"sourcesContent":["import { Card, CardContent, CardHeader, CardTitle, Button } from '@burdenoff/fe-libs/ui';\nimport { BarChart3, FileSpreadsheet, LineChart } from 'lucide-react';\nimport { usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\n\n/**\n * Reports (BOFF-7967). There is no saved-report model and no report runner yet, so there are no reports to list.\n * This page used to invent them — one \"Velocity Report\" per completed sprint, one \"Burndown\" per active sprint, one\n * \"Status Report\" per active project — with made-up schedules, \"Run Today\" counts for reports that never ran, and\n * the viewer named as their creator. It now says so, and points to where the same analysis lives, computed on the\n * server from real data.\n */\nexport function ReportsReportsPagePage() {\n const navigate = usePlanMagnetNavigate();\n const places = [\n {\n title: 'Analytics',\n body: 'Sprint burndown, velocity, cumulative flow, cycle time and delivery health for any project.',\n icon: LineChart,\n to: '/analytics/analytics-page',\n },\n {\n title: 'Task Board export',\n body: 'Download every work item that matches the board’s filters as CSV.',\n icon: FileSpreadsheet,\n to: '/tasks/tasks-page',\n },\n ];\n return (\n <div className=\"space-y-6 p-6\">\n <div>\n <h1 className=\"text-2xl font-semibold flex items-center gap-2\">\n <BarChart3 className=\"h-6 w-6\" />\n Reports\n </h1>\n <p className=\"text-sm text-muted-foreground\">\n Saved and scheduled reports are not available yet — there are none to show.\n </p>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n {places.map((p) => (\n <Card key={p.title}>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2 text-base\">\n <p.icon className=\"h-5 w-5 text-primary\" />\n {p.title}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <p className=\"text-sm text-muted-foreground\">{p.body}</p>\n <Button size=\"sm\" variant=\"outline\" onClick={() => navigate(p.to)}>\n Open {p.title}\n </Button>\n </CardContent>\n </Card>\n ))}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;AAWA,SAAgB,IAAyB;CACvC,IAAM,IAAW,GAAuB;AAexC,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;GAAI,WAAU;aAAd,CACE,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA,EAAA,UAE9B;MACL,kBAAC,KAAD;GAAG,WAAU;aAAgC;GAEzC,CAAA,CACA,EAAA,CAAA,EACN,kBAAC,OAAD;GAAK,WAAU;aAzBJ,CACb;IACE,OAAO;IACP,MAAM;IACN,MAAM;IACN,IAAI;IACL,EACD;IACE,OAAO;IACP,MAAM;IACN,MAAM;IACN,IAAI;IACL,CACF,CAaa,KAAK,MACX,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;IAAW,WAAU;cAArB,CACE,kBAAC,EAAE,MAAH,EAAQ,WAAU,wBAAyB,CAAA,EAC1C,EAAE,MACO;OACD,CAAA,EACb,kBAAC,GAAD;IAAa,WAAU;cAAvB,CACE,kBAAC,KAAD;KAAG,WAAU;eAAiC,EAAE;KAAS,CAAA,EACzD,kBAAC,GAAD;KAAQ,MAAK;KAAK,SAAQ;KAAU,eAAe,EAAS,EAAE,GAAG;eAAjE,CAAmE,SAC3D,EAAE,MACD;OACG;MACT,EAAA,EAbI,EAAE,MAaN,CACP;GACE,CAAA,CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SprintsStartSprintPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/SprintsStartSprintPagePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SprintsStartSprintPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/SprintsStartSprintPagePage.tsx"],"names":[],"mappings":"AAuGA,wBAAgB,0BAA0B,4CAoRzC"}
|