@burdenoff/microfe-planmagnet 2026.731.2 → 2026.827.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/planmagnet/PlanMagnetRoutes.js +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
- package/dist/planmagnet/pages/ProductsEditProductPagePage.js +1 -1
- package/dist/planmagnet/pages/ProductsEditProductPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsEditReleasePagePage.js +1 -1
- package/dist/planmagnet/pages/ProductsEditReleasePagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsFeatureAnalyticsPagePage.js +1 -1
- package/dist/planmagnet/pages/ProductsFeatureAnalyticsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js +1 -1
- 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 +92 -91
- package/dist/planmagnet/pages/ProductsFeaturesPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.js +1 -1
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.js +1 -1
- package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapAnalyticsPagePage.js +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapAnalyticsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapsPagePage.js +66 -65
- package/dist/planmagnet/pages/ProductsRoadmapsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectsPagePage.js +71 -70
- package/dist/planmagnet/pages/ProjectsProjectsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ReportsReportsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ReportsReportsPagePage.js +1 -1
- package/dist/planmagnet/pages/ReportsReportsPagePage.js.map +1 -1
- package/dist/planmagnet/providers/PlanMagnetProvider.js +1 -1
- package/dist/planmagnet/providers/PlanMagnetProvider.js.map +1 -1
- package/package.json +4 -4
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { usePlanMagnet as e } from "../providers/PlanMagnetProvider.js";
|
|
2
|
-
import { CheckSquare as
|
|
3
|
-
import { gql as
|
|
4
|
-
import { useQuery as
|
|
5
|
-
import { jsx as
|
|
6
|
-
import { useI18n as
|
|
7
|
-
import { Badge as
|
|
1
|
+
import { usePlanMagnet as e, usePlanMagnetNavigate as t } from "../providers/PlanMagnetProvider.js";
|
|
2
|
+
import { CheckSquare as n, FolderKanban as r, Plus as i, TrendingUp as a, Users as o } from "lucide-react";
|
|
3
|
+
import { gql as s } from "@apollo/client";
|
|
4
|
+
import { useQuery as c } from "@apollo/client/react";
|
|
5
|
+
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
6
|
+
import { useI18n as d } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
7
|
+
import { Badge as f, Button as p, Card as m, CardContent as h, CardHeader as g, CardTitle as _ } from "@burdenoff/fe-libs/ui";
|
|
8
8
|
//#region src/planmagnet/pages/ProjectsProjectsPagePage.tsx
|
|
9
|
-
var
|
|
9
|
+
var v = s`
|
|
10
10
|
query GetProjects($workspaceId: ID!) {
|
|
11
11
|
planmagnetProjects(workspaceId: $workspaceId, pagination: { first: 100 }) {
|
|
12
12
|
items {
|
|
@@ -25,135 +25,136 @@ var _ = o`
|
|
|
25
25
|
totalCount
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
-
`,
|
|
28
|
+
`, y = {
|
|
29
29
|
SCRUM: "bg-blue-100 text-blue-800",
|
|
30
30
|
KANBAN: "bg-purple-100 text-purple-800",
|
|
31
31
|
WATERFALL: "bg-gray-100 text-gray-800",
|
|
32
32
|
HYBRID: "bg-teal-100 text-teal-800",
|
|
33
33
|
AGILE: "bg-indigo-100 text-indigo-800",
|
|
34
34
|
CUSTOM: "bg-amber-100 text-amber-800"
|
|
35
|
-
},
|
|
36
|
-
function
|
|
37
|
-
let { workspaceId:
|
|
38
|
-
if (
|
|
35
|
+
}, b = (e) => e === "ACTIVE" ? "default" : "secondary";
|
|
36
|
+
function x() {
|
|
37
|
+
let s = t(), { workspaceId: x } = e(), { t: S } = d(), { data: C, loading: w, error: T } = c(v, { variables: { workspaceId: x ?? "default" } });
|
|
38
|
+
if (w) return /* @__PURE__ */ l("div", {
|
|
39
39
|
className: "flex items-center justify-center p-12",
|
|
40
|
-
children: /* @__PURE__ */
|
|
40
|
+
children: /* @__PURE__ */ l("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
|
|
41
41
|
});
|
|
42
|
-
if (
|
|
42
|
+
if (T) return /* @__PURE__ */ u("div", {
|
|
43
43
|
className: "p-6 text-red-500",
|
|
44
44
|
children: [
|
|
45
|
-
|
|
45
|
+
S("planmagnet.projects.errorLoading", "Error loading projects"),
|
|
46
46
|
": ",
|
|
47
|
-
|
|
47
|
+
T.message
|
|
48
48
|
]
|
|
49
49
|
});
|
|
50
|
-
let
|
|
51
|
-
total:
|
|
52
|
-
active:
|
|
53
|
-
completed:
|
|
54
|
-
onHold:
|
|
50
|
+
let E = C?.planmagnetProjects?.items ?? [], D = {
|
|
51
|
+
total: E.length,
|
|
52
|
+
active: E.filter((e) => e.status === "ACTIVE").length,
|
|
53
|
+
completed: E.filter((e) => e.status === "COMPLETED").length,
|
|
54
|
+
onHold: E.filter((e) => e.status === "ON_HOLD").length
|
|
55
55
|
};
|
|
56
|
-
return /* @__PURE__ */
|
|
56
|
+
return /* @__PURE__ */ u("div", {
|
|
57
57
|
className: "space-y-6 p-6",
|
|
58
58
|
children: [
|
|
59
|
-
/* @__PURE__ */
|
|
59
|
+
/* @__PURE__ */ u("div", {
|
|
60
60
|
className: "flex items-center justify-between",
|
|
61
|
-
children: [/* @__PURE__ */
|
|
61
|
+
children: [/* @__PURE__ */ u("div", { children: [/* @__PURE__ */ l("h1", {
|
|
62
62
|
className: "text-2xl font-semibold",
|
|
63
|
-
children:
|
|
64
|
-
}), /* @__PURE__ */
|
|
63
|
+
children: S("planmagnet.projects.title", "All Projects")
|
|
64
|
+
}), /* @__PURE__ */ l("p", {
|
|
65
65
|
className: "text-sm text-muted-foreground",
|
|
66
|
-
children:
|
|
67
|
-
})] }), /* @__PURE__ */
|
|
66
|
+
children: S("planmagnet.projects.subtitle", "Manage and track all projects across teams")
|
|
67
|
+
})] }), /* @__PURE__ */ u(p, {
|
|
68
68
|
size: "sm",
|
|
69
|
-
|
|
69
|
+
onClick: () => s("/projects/create-project-page"),
|
|
70
|
+
children: [/* @__PURE__ */ l(i, { className: "mr-1 h-4 w-4" }), S("planmagnet.projects.actions.newProject", "New Project")]
|
|
70
71
|
})]
|
|
71
72
|
}),
|
|
72
|
-
/* @__PURE__ */
|
|
73
|
+
/* @__PURE__ */ l("div", {
|
|
73
74
|
className: "grid grid-cols-2 md:grid-cols-4 gap-4",
|
|
74
75
|
children: [
|
|
75
76
|
{
|
|
76
|
-
label:
|
|
77
|
-
value:
|
|
78
|
-
icon:
|
|
77
|
+
label: S("planmagnet.projects.metrics.totalProjects", "Total Projects"),
|
|
78
|
+
value: D.total,
|
|
79
|
+
icon: r
|
|
79
80
|
},
|
|
80
81
|
{
|
|
81
|
-
label:
|
|
82
|
-
value:
|
|
83
|
-
icon:
|
|
82
|
+
label: S("planmagnet.projects.metrics.active", "Active"),
|
|
83
|
+
value: D.active,
|
|
84
|
+
icon: a
|
|
84
85
|
},
|
|
85
86
|
{
|
|
86
|
-
label:
|
|
87
|
-
value:
|
|
88
|
-
icon:
|
|
87
|
+
label: S("planmagnet.projects.metrics.completed", "Completed"),
|
|
88
|
+
value: D.completed,
|
|
89
|
+
icon: n
|
|
89
90
|
},
|
|
90
91
|
{
|
|
91
|
-
label:
|
|
92
|
-
value:
|
|
93
|
-
icon:
|
|
92
|
+
label: S("planmagnet.projects.metrics.onHold", "On Hold"),
|
|
93
|
+
value: D.onHold,
|
|
94
|
+
icon: a
|
|
94
95
|
}
|
|
95
|
-
].map((e) => /* @__PURE__ */
|
|
96
|
+
].map((e) => /* @__PURE__ */ l(m, { children: /* @__PURE__ */ u(h, {
|
|
96
97
|
className: "pt-4",
|
|
97
|
-
children: [/* @__PURE__ */
|
|
98
|
+
children: [/* @__PURE__ */ u("div", {
|
|
98
99
|
className: "flex items-center gap-2 text-muted-foreground text-sm",
|
|
99
|
-
children: [/* @__PURE__ */
|
|
100
|
-
}), /* @__PURE__ */
|
|
100
|
+
children: [/* @__PURE__ */ l(e.icon, { className: "h-4 w-4" }), e.label]
|
|
101
|
+
}), /* @__PURE__ */ l("p", {
|
|
101
102
|
className: "text-xl font-semibold mt-1",
|
|
102
103
|
children: e.value
|
|
103
104
|
})]
|
|
104
105
|
}) }, e.label))
|
|
105
106
|
}),
|
|
106
|
-
/* @__PURE__ */
|
|
107
|
+
/* @__PURE__ */ l("div", {
|
|
107
108
|
className: "grid grid-cols-1 md:grid-cols-2 gap-4",
|
|
108
|
-
children:
|
|
109
|
+
children: E.map((e) => /* @__PURE__ */ u(m, { children: [/* @__PURE__ */ l(g, {
|
|
109
110
|
className: "pb-2",
|
|
110
|
-
children: /* @__PURE__ */
|
|
111
|
+
children: /* @__PURE__ */ u("div", {
|
|
111
112
|
className: "flex items-center justify-between",
|
|
112
|
-
children: [/* @__PURE__ */
|
|
113
|
+
children: [/* @__PURE__ */ l(_, {
|
|
113
114
|
className: "text-base",
|
|
114
115
|
children: e.name
|
|
115
|
-
}), /* @__PURE__ */
|
|
116
|
+
}), /* @__PURE__ */ l("span", {
|
|
116
117
|
className: "text-xs text-muted-foreground font-mono",
|
|
117
118
|
children: e.key
|
|
118
119
|
})]
|
|
119
120
|
})
|
|
120
|
-
}), /* @__PURE__ */
|
|
121
|
+
}), /* @__PURE__ */ u(h, {
|
|
121
122
|
className: "space-y-3",
|
|
122
123
|
children: [
|
|
123
|
-
/* @__PURE__ */
|
|
124
|
+
/* @__PURE__ */ l("p", {
|
|
124
125
|
className: "text-sm text-muted-foreground",
|
|
125
|
-
children: e.description ??
|
|
126
|
+
children: e.description ?? S("planmagnet.projects.shared.noDescription", "No description")
|
|
126
127
|
}),
|
|
127
|
-
/* @__PURE__ */
|
|
128
|
+
/* @__PURE__ */ u("div", {
|
|
128
129
|
className: "flex gap-2",
|
|
129
|
-
children: [/* @__PURE__ */
|
|
130
|
-
variant:
|
|
130
|
+
children: [/* @__PURE__ */ l(f, {
|
|
131
|
+
variant: b(e.status),
|
|
131
132
|
className: "capitalize",
|
|
132
133
|
children: e.status.toLowerCase().replace("_", " ")
|
|
133
|
-
}), /* @__PURE__ */
|
|
134
|
-
className: `text-xs px-2 py-0.5 rounded-full capitalize ${
|
|
134
|
+
}), /* @__PURE__ */ l("span", {
|
|
135
|
+
className: `text-xs px-2 py-0.5 rounded-full capitalize ${y[e.methodology] ?? "bg-gray-100"}`,
|
|
135
136
|
children: e.methodology.toLowerCase()
|
|
136
137
|
})]
|
|
137
138
|
}),
|
|
138
|
-
e.tags.length > 0 && /* @__PURE__ */
|
|
139
|
+
e.tags.length > 0 && /* @__PURE__ */ l("div", {
|
|
139
140
|
className: "flex gap-1 flex-wrap",
|
|
140
|
-
children: e.tags.map((e) => /* @__PURE__ */
|
|
141
|
+
children: e.tags.map((e) => /* @__PURE__ */ l(f, {
|
|
141
142
|
variant: "outline",
|
|
142
143
|
className: "text-xs",
|
|
143
144
|
children: e
|
|
144
145
|
}, e))
|
|
145
146
|
}),
|
|
146
|
-
/* @__PURE__ */
|
|
147
|
+
/* @__PURE__ */ u("div", {
|
|
147
148
|
className: "flex justify-between text-xs text-muted-foreground border-t pt-2",
|
|
148
|
-
children: [/* @__PURE__ */
|
|
149
|
+
children: [/* @__PURE__ */ u("span", {
|
|
149
150
|
className: "flex items-center gap-1",
|
|
150
151
|
children: [
|
|
151
|
-
/* @__PURE__ */
|
|
152
|
-
|
|
152
|
+
/* @__PURE__ */ l(o, { className: "h-3 w-3" }),
|
|
153
|
+
S("planmagnet.projects.shared.owner", "Owner"),
|
|
153
154
|
": ",
|
|
154
155
|
e.ownerId
|
|
155
156
|
]
|
|
156
|
-
}), /* @__PURE__ */
|
|
157
|
+
}), /* @__PURE__ */ u("span", { children: [
|
|
157
158
|
e.startDate ? new Date(e.startDate).toLocaleDateString() : "—",
|
|
158
159
|
" -",
|
|
159
160
|
" ",
|
|
@@ -163,14 +164,14 @@ function b() {
|
|
|
163
164
|
]
|
|
164
165
|
})] }, e.id))
|
|
165
166
|
}),
|
|
166
|
-
|
|
167
|
+
E.length === 0 && /* @__PURE__ */ l("p", {
|
|
167
168
|
className: "text-center text-muted-foreground py-8",
|
|
168
|
-
children:
|
|
169
|
+
children: S("planmagnet.projects.empty", "No projects found.")
|
|
169
170
|
})
|
|
170
171
|
]
|
|
171
172
|
});
|
|
172
173
|
}
|
|
173
174
|
//#endregion
|
|
174
|
-
export {
|
|
175
|
+
export { x as ProjectsProjectsPagePage };
|
|
175
176
|
|
|
176
177
|
//# 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 } from '../providers/PlanMagnetProvider';\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 { 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 if (loading)\n return (\n <div className=\"flex items-center justify-center p-12\">\n <div className=\"animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full\" />\n </div>\n );\n if (error)\n return (\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\">\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 key={project.id}>\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')}: {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 { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\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 if (loading)\n return (\n <div className=\"flex items-center justify-center p-12\">\n <div className=\"animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full\" />\n </div>\n );\n if (error)\n return (\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 key={project.id}>\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')}: {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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReportsReportsPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ReportsReportsPagePage.tsx"],"names":[],"mappings":"AA6FA,wBAAgB,sBAAsB,
|
|
1
|
+
{"version":3,"file":"ReportsReportsPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ReportsReportsPagePage.tsx"],"names":[],"mappings":"AA6FA,wBAAgB,sBAAsB,4CAsKrC"}
|
|
@@ -117,7 +117,7 @@ function v() {
|
|
|
117
117
|
children: [A.length, " reports configured"]
|
|
118
118
|
})] }), /* @__PURE__ */ u(d, {
|
|
119
119
|
size: "sm",
|
|
120
|
-
onClick: () => y("/reports/create"),
|
|
120
|
+
onClick: () => y("/reports/create-report-page"),
|
|
121
121
|
children: [/* @__PURE__ */ l(o, { className: "mr-1 h-4 w-4" }), "New Report"]
|
|
122
122
|
})]
|
|
123
123
|
}),
|
|
@@ -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, currentUser } = 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 if (loading) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <div className=\"animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full\" />\n </div>\n );\n }\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 const creatorName = currentUser?.name ?? currentUser?.firstName ?? 'System';\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 createdBy: creatorName,\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 createdBy: creatorName,\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 createdBy: creatorName,\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 <Button size=\"sm\" onClick={() => navigate('/reports/create')}>\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 <span className=\"flex items-center gap-1\">{report.createdBy}</span>\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":["// 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, currentUser } = 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 if (loading) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <div className=\"animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full\" />\n </div>\n );\n }\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 const creatorName = currentUser?.name ?? currentUser?.firstName ?? 'System';\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 createdBy: creatorName,\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 createdBy: creatorName,\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 createdBy: creatorName,\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 <span className=\"flex items-center gap-1\">{report.createdBy}</span>\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,6 +1,6 @@
|
|
|
1
1
|
import { CombinedGraphQLErrors as e } from "../../node_modules/@apollo/client/errors/CombinedGraphQLErrors.js";
|
|
2
2
|
import { createContext as t, useCallback as n, useContext as r, useMemo as i } from "react";
|
|
3
|
-
import { MemoryRouter as a, useNavigate as o } from "react-router
|
|
3
|
+
import { MemoryRouter as a, useNavigate as o } from "react-router";
|
|
4
4
|
import { ApolloClient as s, HttpLink as c, InMemoryCache as l, from as u } from "@apollo/client";
|
|
5
5
|
import { onError as d } from "@apollo/client/link/error";
|
|
6
6
|
import { setContext as f } from "@apollo/client/link/context";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlanMagnetProvider.js","names":[],"sources":["../../../src/planmagnet/providers/PlanMagnetProvider.tsx"],"sourcesContent":["import type { FC, PropsWithChildren } from 'react';\nimport { createContext, useContext, useMemo, useCallback } from 'react';\nimport { MemoryRouter, useNavigate as useRouterNavigate } from 'react-router
|
|
1
|
+
{"version":3,"file":"PlanMagnetProvider.js","names":[],"sources":["../../../src/planmagnet/providers/PlanMagnetProvider.tsx"],"sourcesContent":["import type { FC, PropsWithChildren } from 'react';\nimport { createContext, useContext, useMemo, useCallback } from 'react';\nimport { MemoryRouter, useNavigate as useRouterNavigate } from 'react-router';\nimport { ApolloClient, InMemoryCache, HttpLink, from } from '@apollo/client';\nimport { onError } from '@apollo/client/link/error';\nimport { CombinedGraphQLErrors } from '@apollo/client/errors';\nimport { setContext } from '@apollo/client/link/context';\nimport { ApolloProvider } from '@apollo/client/react';\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport type { PlanMagnetRootProps } from '../types';\n\n// Create a shared QueryClient for React Query (retained for any REST/non-GraphQL needs)\nconst queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 5 * 60 * 1000, // 5 minutes\n retry: 1,\n refetchOnWindowFocus: false,\n },\n },\n});\n\n/**\n * Context value for PlanMagnet microfrontend\n */\ntype PlanMagnetContextValue = PlanMagnetRootProps;\n\nconst PlanMagnetContext = createContext<PlanMagnetContextValue | null>(null);\n\n/**\n * Hook to access PlanMagnet context\n */\nexport const usePlanMagnet = () => {\n const context = useContext(PlanMagnetContext);\n if (!context) {\n throw new Error('usePlanMagnet must be used within PlanMagnetProvider');\n }\n return context;\n};\n\n/**\n * Hook for navigation within the PlanMagnet microfrontend.\n * Uses the shell's navigate function if available, falling back to\n * React Router's useNavigate. Automatically prepends basePath.\n *\n * Usage:\n * const navigate = usePlanMagnetNavigate();\n * navigate('/products/123'); // navigates to /planmagnet/products/123\n */\nexport const usePlanMagnetNavigate = () => {\n const { navigate: shellNavigate, basePath } = usePlanMagnet();\n const routerNavigate = useRouterNavigate();\n\n return useCallback(\n (path: string) => {\n const fullPath = basePath && basePath !== '/' ? `${basePath}${path}` : path;\n if (shellNavigate) {\n shellNavigate(fullPath);\n } else {\n routerNavigate(fullPath);\n }\n },\n [shellNavigate, basePath, routerNavigate]\n );\n};\n\n/**\n * Provider component for PlanMagnet microfrontend.\n * Sets up routing, Apollo Client with auth error detection, and context.\n *\n * The Apollo Client is configured with:\n * - An onError link that detects UNAUTHENTICATED / FORBIDDEN responses and\n * invokes the `onAuthError` prop so the host shell can trigger logout.\n * - A dynamic auth link that reads the token per-request (not baked in at\n * client creation time), so token refreshes take effect immediately.\n * - InMemoryCache with type policies for proper cache normalization.\n * - Default fetch policy: cache-and-network.\n */\nexport const PlanMagnetProvider: FC<PropsWithChildren<PlanMagnetRootProps>> = ({\n children,\n basePath,\n navigate,\n currentUser,\n workspaceId,\n tenantId,\n apiGatewayUrl,\n authToken,\n workspaceToken,\n registerNavItems,\n registerFooterItems,\n onAuthError,\n}) => {\n // Build Apollo Client with error link + dynamic auth link\n const apolloClient = useMemo(() => {\n // Error link (Apollo v4 pattern): detect authentication failures\n const errorLink = onError(({ error }) => {\n if (CombinedGraphQLErrors.is(error)) {\n for (const graphQLError of error.errors) {\n const code = graphQLError.extensions?.code;\n if (code === 'UNAUTHENTICATED' || code === 'FORBIDDEN') {\n console.warn('[PlanMagnet] Auth error detected — notifying host shell');\n onAuthError?.();\n return; // Only fire once per batch\n }\n }\n } else if (error) {\n // Network-level errors (e.g., gateway returning 401/403 as non-JSON)\n const msg = error.message ?? '';\n if (msg.includes('401') || msg.includes('403') || msg.includes('Unauthorized')) {\n console.warn('[PlanMagnet] Auth network error — notifying host shell');\n onAuthError?.();\n }\n }\n });\n\n // Auth link: dynamically attach dual-token auth and workspace context per-request.\n // The workspace gateway requires:\n // Authorization: Bearer <authToken> (platform identity)\n // X-Workspace-Authorization: Bearer <workspaceToken> (workspace access)\n const authLink = setContext((_, { headers }) => ({\n headers: {\n ...headers,\n ...(authToken ? { Authorization: `Bearer ${authToken}` } : {}),\n ...(workspaceToken ? { 'X-Workspace-Authorization': `Bearer ${workspaceToken}` } : {}),\n ...(workspaceId ? { 'x-workspace-id': workspaceId } : {}),\n },\n }));\n\n const httpLink = new HttpLink({\n uri: apiGatewayUrl ? `${apiGatewayUrl}/workspaces/graphql` : '/workspaces/graphql',\n });\n\n return new ApolloClient({\n link: from([errorLink, authLink, httpLink]),\n cache: new InMemoryCache({\n typePolicies: {\n Query: {\n fields: {\n // Merge paginated results for common list queries\n roadmaps: { merge: false },\n featureRequests: { merge: false },\n releases: { merge: false },\n competitors: { merge: false },\n roadmapItems: { merge: false },\n projects: { merge: false },\n workItems: { merge: false },\n sprints: { merge: false },\n milestones: { merge: false },\n },\n },\n Roadmap: { keyFields: ['id'] },\n RoadmapItem: { keyFields: ['id'] },\n Release: { keyFields: ['id'] },\n FeatureRequest: { keyFields: ['id'] },\n FeatureVote: { keyFields: ['id'] },\n Competitor: { keyFields: ['id'] },\n Project: { keyFields: ['id'] },\n WorkItem: { keyFields: ['id'] },\n Sprint: { keyFields: ['id'] },\n Milestone: { keyFields: ['id'] },\n Team: { keyFields: ['id'] },\n TeamMember: { keyFields: ['id'] },\n },\n }),\n defaultOptions: {\n watchQuery: { fetchPolicy: 'cache-and-network', errorPolicy: 'all' },\n query: { errorPolicy: 'all' },\n mutate: { errorPolicy: 'all' },\n },\n });\n }, [apiGatewayUrl, authToken, workspaceToken, workspaceId, onAuthError]);\n\n const contextValue: PlanMagnetContextValue = {\n basePath,\n navigate,\n currentUser,\n workspaceId,\n tenantId,\n apiGatewayUrl,\n authToken,\n workspaceToken,\n registerNavItems,\n registerFooterItems,\n onAuthError,\n };\n\n const isIntegrated = !!basePath;\n\n // Core providers that wrap the children\n const content = (\n <QueryClientProvider client={queryClient}>\n <PlanMagnetContext.Provider value={contextValue}>{children}</PlanMagnetContext.Provider>\n </QueryClientProvider>\n );\n\n // When integrated into a shell (basePath provided), the shell already has a router and ApolloProvider\n // so we don't create another one. When standalone (no basePath), use MemoryRouter and ApolloProvider.\n return isIntegrated ? (\n content\n ) : (\n <ApolloProvider client={apolloClient}>\n <MemoryRouter>{content}</MemoryRouter>\n </ApolloProvider>\n );\n};\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@burdenoff/microfe-planmagnet",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.827.1",
|
|
4
4
|
"description": "Burdenoff PlanMagnet Microfrontend",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -43,14 +43,14 @@
|
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@apollo/client": ">=4.0.11 <4.2.0",
|
|
46
|
-
"@burdenoff/fe-libs": "2026.
|
|
46
|
+
"@burdenoff/fe-libs": "2026.801.1",
|
|
47
47
|
"@tanstack/react-query": "^5.90.16",
|
|
48
48
|
"clsx": "^2.1.1",
|
|
49
49
|
"graphql": "^16.10.0",
|
|
50
50
|
"lucide-react": "^0.468.0",
|
|
51
51
|
"react": "^19.0.0",
|
|
52
52
|
"react-dom": "^19.0.0",
|
|
53
|
-
"react-router
|
|
53
|
+
"react-router": "^8.3.0",
|
|
54
54
|
"tailwind-merge": "^3.4.0",
|
|
55
55
|
"zustand": "^5.0.3",
|
|
56
56
|
"recharts": "^2.15.0",
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
"zustand": "^5.0.0"
|
|
99
99
|
},
|
|
100
100
|
"publishConfig": {
|
|
101
|
-
"access": "
|
|
101
|
+
"access": "public"
|
|
102
102
|
},
|
|
103
103
|
"overrides": {
|
|
104
104
|
"lodash": ">=4.17.21",
|