@burdenoff/microfe-planmagnet 2026.925.18 → 2026.926.2

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.
Files changed (92) hide show
  1. package/dist/generated/wspace-types.d.ts +61 -2
  2. package/dist/generated/wspace-types.d.ts.map +1 -1
  3. package/dist/planmagnet/PlanMagnetRoot.d.ts.map +1 -1
  4. package/dist/planmagnet/PlanMagnetRoot.js +90 -79
  5. package/dist/planmagnet/PlanMagnetRoot.js.map +1 -1
  6. package/dist/planmagnet/PlanMagnetRoutes.d.ts.map +1 -1
  7. package/dist/planmagnet/PlanMagnetRoutes.js +124 -127
  8. package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
  9. package/dist/planmagnet/create/CreateDialogs.d.ts.map +1 -1
  10. package/dist/planmagnet/create/CreateDialogs.js +149 -124
  11. package/dist/planmagnet/create/CreateDialogs.js.map +1 -1
  12. package/dist/planmagnet/pages/DocsDocDetailPagePage.d.ts.map +1 -1
  13. package/dist/planmagnet/pages/DocsDocDetailPagePage.js +1 -1
  14. package/dist/planmagnet/pages/DocsDocDetailPagePage.js.map +1 -1
  15. package/dist/planmagnet/pages/NotFoundPage.d.ts +6 -0
  16. package/dist/planmagnet/pages/NotFoundPage.d.ts.map +1 -0
  17. package/dist/planmagnet/pages/NotFoundPage.js +18 -0
  18. package/dist/planmagnet/pages/NotFoundPage.js.map +1 -0
  19. package/dist/planmagnet/pages/ProductsCreateProductPagePage.d.ts.map +1 -1
  20. package/dist/planmagnet/pages/ProductsCreateProductPagePage.js +93 -98
  21. package/dist/planmagnet/pages/ProductsCreateProductPagePage.js.map +1 -1
  22. package/dist/planmagnet/pages/ProductsCreateRoadmapPagePage.d.ts.map +1 -1
  23. package/dist/planmagnet/pages/ProductsCreateRoadmapPagePage.js +72 -79
  24. package/dist/planmagnet/pages/ProductsCreateRoadmapPagePage.js.map +1 -1
  25. package/dist/planmagnet/pages/ProductsEditProductPagePage.d.ts.map +1 -1
  26. package/dist/planmagnet/pages/ProductsEditProductPagePage.js +112 -123
  27. package/dist/planmagnet/pages/ProductsEditProductPagePage.js.map +1 -1
  28. package/dist/planmagnet/pages/ProductsNewFeaturePagePage.d.ts.map +1 -1
  29. package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js +103 -87
  30. package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js.map +1 -1
  31. package/dist/planmagnet/pages/ProductsProductDetailPagePage.d.ts.map +1 -1
  32. package/dist/planmagnet/pages/ProductsProductDetailPagePage.js +92 -98
  33. package/dist/planmagnet/pages/ProductsProductDetailPagePage.js.map +1 -1
  34. package/dist/planmagnet/pages/ProductsProductsPagePage.d.ts.map +1 -1
  35. package/dist/planmagnet/pages/ProductsProductsPagePage.js +88 -96
  36. package/dist/planmagnet/pages/ProductsProductsPagePage.js.map +1 -1
  37. package/dist/planmagnet/pages/ProductsRoadmapAnalyticsPagePage.d.ts.map +1 -1
  38. package/dist/planmagnet/pages/ProductsRoadmapAnalyticsPagePage.js +116 -114
  39. package/dist/planmagnet/pages/ProductsRoadmapAnalyticsPagePage.js.map +1 -1
  40. package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.d.ts.map +1 -1
  41. package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js +82 -88
  42. package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js.map +1 -1
  43. package/dist/planmagnet/pages/ProductsRoadmapsPagePage.d.ts.map +1 -1
  44. package/dist/planmagnet/pages/ProductsRoadmapsPagePage.js +79 -79
  45. package/dist/planmagnet/pages/ProductsRoadmapsPagePage.js.map +1 -1
  46. package/dist/planmagnet/pages/ProjectsCreateProjectPagePage.d.ts.map +1 -1
  47. package/dist/planmagnet/pages/ProjectsCreateProjectPagePage.js +111 -91
  48. package/dist/planmagnet/pages/ProjectsCreateProjectPagePage.js.map +1 -1
  49. package/dist/planmagnet/pages/ProjectsEditProjectPagePage.d.ts.map +1 -1
  50. package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js +117 -97
  51. package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js.map +1 -1
  52. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.d.ts.map +1 -1
  53. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js +150 -154
  54. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js.map +1 -1
  55. package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.d.ts.map +1 -1
  56. package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.js +154 -117
  57. package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.js.map +1 -1
  58. package/dist/planmagnet/pages/SprintsStartSprintPagePage.d.ts.map +1 -1
  59. package/dist/planmagnet/pages/SprintsStartSprintPagePage.js +75 -31
  60. package/dist/planmagnet/pages/SprintsStartSprintPagePage.js.map +1 -1
  61. package/dist/planmagnet/pages/TasksCreateTaskPagePage.d.ts.map +1 -1
  62. package/dist/planmagnet/pages/TasksCreateTaskPagePage.js +161 -115
  63. package/dist/planmagnet/pages/TasksCreateTaskPagePage.js.map +1 -1
  64. package/dist/planmagnet/pages/TasksEditTaskPagePage.d.ts.map +1 -1
  65. package/dist/planmagnet/pages/TasksEditTaskPagePage.js +117 -102
  66. package/dist/planmagnet/pages/TasksEditTaskPagePage.js.map +1 -1
  67. package/dist/planmagnet/pages/TeamInviteMemberPagePage.d.ts.map +1 -1
  68. package/dist/planmagnet/pages/TeamInviteMemberPagePage.js +147 -147
  69. package/dist/planmagnet/pages/TeamInviteMemberPagePage.js.map +1 -1
  70. package/dist/planmagnet/pages/TeamTeamPagePage.d.ts.map +1 -1
  71. package/dist/planmagnet/pages/TeamTeamPagePage.js +77 -67
  72. package/dist/planmagnet/pages/TeamTeamPagePage.js.map +1 -1
  73. package/dist/planmagnet/roadmaps/planningFocus.d.ts +23 -0
  74. package/dist/planmagnet/roadmaps/planningFocus.d.ts.map +1 -0
  75. package/dist/planmagnet/roadmaps/planningFocus.js +76 -0
  76. package/dist/planmagnet/roadmaps/planningFocus.js.map +1 -0
  77. package/dist/planmagnet/sprints/SprintControls.d.ts.map +1 -1
  78. package/dist/planmagnet/sprints/SprintControls.js +48 -29
  79. package/dist/planmagnet/sprints/SprintControls.js.map +1 -1
  80. package/dist/planmagnet/sprints/SprintDates.d.ts +37 -0
  81. package/dist/planmagnet/sprints/SprintDates.d.ts.map +1 -0
  82. package/dist/planmagnet/sprints/SprintDates.js +114 -0
  83. package/dist/planmagnet/sprints/SprintDates.js.map +1 -0
  84. package/dist/planmagnet/utils/email.d.ts +9 -0
  85. package/dist/planmagnet/utils/email.d.ts.map +1 -0
  86. package/dist/planmagnet/utils/email.js +15 -0
  87. package/dist/planmagnet/utils/email.js.map +1 -0
  88. package/dist/planmagnet/utils/formValidation.d.ts +18 -0
  89. package/dist/planmagnet/utils/formValidation.d.ts.map +1 -0
  90. package/dist/planmagnet/utils/formValidation.js +17 -0
  91. package/dist/planmagnet/utils/formValidation.js.map +1 -0
  92. package/package.json +1 -1
@@ -1,11 +1,12 @@
1
- import { usePlanMagnet as e } from "../providers/PlanMagnetProvider.js";
2
- import { PersonName as t } from "../people/People.js";
3
- import { gql as n } from "@apollo/client";
4
- import { useQuery as r } from "@apollo/client/react";
5
- import { jsx as i, jsxs as a } from "react/jsx-runtime";
6
- import { Badge as o, Card as s, CardContent as c, CardHeader as l, CardTitle as u } from "@burdenoff/fe-libs/ui";
1
+ import { usePlanMagnet as e, usePlanMagnetNavigate as t } from "../providers/PlanMagnetProvider.js";
2
+ import { PersonName as n } from "../people/People.js";
3
+ import { UserPlus as r } from "lucide-react";
4
+ import { gql as i } from "@apollo/client";
5
+ import { useQuery as a } from "@apollo/client/react";
6
+ import { jsx as o, jsxs as s } from "react/jsx-runtime";
7
+ import { Badge as c, Button as l, Card as u, CardContent as d, CardHeader as f, CardTitle as p } from "@burdenoff/fe-libs/ui";
7
8
  //#region src/planmagnet/pages/TeamTeamPagePage.tsx
8
- var d = n`
9
+ var m = i`
9
10
  query GetTeamData(
10
11
  $workspaceId: ID!
11
12
  $projectPagination: PlanmagnetPaginationInput
@@ -32,164 +33,173 @@ var d = n`
32
33
  totalCount
33
34
  }
34
35
  }
35
- `, f = {
36
+ `, h = {
36
37
  active: "bg-green-400",
37
38
  away: "bg-yellow-400",
38
39
  busy: "bg-red-400",
39
40
  offline: "bg-gray-300"
40
41
  };
41
- function p() {
42
- let { workspaceId: n } = e(), { data: p, loading: m, error: h } = r(d, {
42
+ function g() {
43
+ let { workspaceId: i } = e(), g = t(), { data: _, loading: v, error: y } = a(m, {
43
44
  variables: {
44
- workspaceId: n,
45
+ workspaceId: i,
45
46
  projectPagination: { first: 100 },
46
47
  workItemPagination: { first: 500 }
47
48
  },
48
- skip: !n
49
+ skip: !i
49
50
  });
50
- if (m && !p) return /* @__PURE__ */ i("div", {
51
+ if (v && !_) return /* @__PURE__ */ o("div", {
51
52
  className: "flex items-center justify-center p-12",
52
- children: /* @__PURE__ */ i("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
53
+ children: /* @__PURE__ */ o("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
53
54
  });
54
- if (h) return /* @__PURE__ */ a("div", {
55
+ if (y) return /* @__PURE__ */ s("div", {
55
56
  className: "p-6 text-red-500",
56
- children: ["Error: ", h.message]
57
+ children: ["Error: ", y.message]
57
58
  });
58
- let g = p?.planmagnetProjects?.items ?? [], _ = p?.planmagnetWorkItems?.items ?? [], v = new Set(_.filter((e) => e.assigneeId).map((e) => e.assigneeId)), y = new Set(g.filter((e) => e.ownerId).map((e) => e.ownerId)), b = new Set([...v, ...y]), x = Array.from(b).map((e) => {
59
- let t = _.filter((t) => t.assigneeId === e), n = t.length, r = t.filter((e) => e.status === "DONE").length, i = t.filter((e) => e.status === "DONE").reduce((e, t) => e + (t.storyPoints ?? 0), 0);
59
+ let b = _?.planmagnetProjects?.items ?? [], x = _?.planmagnetWorkItems?.items ?? [], S = new Set(x.filter((e) => e.assigneeId).map((e) => e.assigneeId)), C = new Set(b.filter((e) => e.ownerId).map((e) => e.ownerId)), w = new Set([...S, ...C]), T = Array.from(w).map((e) => {
60
+ let t = x.filter((t) => t.assigneeId === e), n = t.length, r = t.filter((e) => e.status === "DONE").length, i = t.filter((e) => e.status === "DONE").reduce((e, t) => e + (t.storyPoints ?? 0), 0);
60
61
  return {
61
62
  id: e,
62
63
  name: e,
63
- role: g.filter((t) => t.ownerId === e).length > 0 ? "Project Owner" : "Contributor",
64
+ role: b.filter((t) => t.ownerId === e).length > 0 ? "Project Owner" : "Contributor",
64
65
  department: "Engineering",
65
66
  tasksAssigned: n,
66
67
  tasksCompleted: r,
67
68
  velocity: i,
68
69
  status: n > 0 ? "active" : "offline"
69
70
  };
70
- }), S = g.reduce((e, t) => {
71
+ }), E = b.reduce((e, t) => {
71
72
  let n = t.methodology ?? "unassigned";
72
73
  return e[n] || (e[n] = {
73
74
  projects: [],
74
75
  ownerIds: /* @__PURE__ */ new Set()
75
76
  }), e[n].projects.push(t), t.ownerId && e[n].ownerIds.add(t.ownerId), e;
76
- }, {}), C = Object.entries(S).map(([e, t]) => ({
77
+ }, {}), D = Object.entries(E).map(([e, t]) => ({
77
78
  id: e,
78
79
  name: `${e.charAt(0).toUpperCase()}${e.slice(1)} Team`,
79
80
  description: `Projects using ${e} methodology`,
80
81
  projectsCount: t.projects.length,
81
82
  leadId: Array.from(t.ownerIds)[0] ?? "Unassigned"
82
83
  }));
83
- return /* @__PURE__ */ a("div", {
84
+ return /* @__PURE__ */ s("div", {
84
85
  className: "space-y-6 p-6",
85
86
  children: [
86
- /* @__PURE__ */ a("div", { children: [/* @__PURE__ */ i("h1", {
87
- className: "text-2xl font-semibold",
88
- children: "Team Overview"
89
- }), /* @__PURE__ */ a("p", {
90
- className: "text-sm text-muted-foreground",
91
- children: [
92
- x.length,
93
- " contributors across ",
94
- C.length,
95
- " teams"
96
- ]
97
- })] }),
98
- /* @__PURE__ */ a("div", {
87
+ /* @__PURE__ */ s("div", {
88
+ className: "flex items-start justify-between gap-4",
89
+ children: [/* @__PURE__ */ s("div", { children: [/* @__PURE__ */ o("h1", {
90
+ className: "text-2xl font-semibold",
91
+ children: "Team Overview"
92
+ }), /* @__PURE__ */ s("p", {
93
+ className: "text-sm text-muted-foreground",
94
+ children: [
95
+ T.length,
96
+ " contributors across ",
97
+ D.length,
98
+ " teams"
99
+ ]
100
+ })] }), /* @__PURE__ */ s(l, {
101
+ size: "sm",
102
+ variant: "outline",
103
+ onClick: () => g("/team/invite-member-page"),
104
+ "data-testid": "team-invite",
105
+ children: [/* @__PURE__ */ o(r, { className: "mr-1 h-4 w-4" }), "Invite member"]
106
+ })]
107
+ }),
108
+ /* @__PURE__ */ s("div", {
99
109
  className: "space-y-4",
100
- children: [/* @__PURE__ */ i("h2", {
110
+ children: [/* @__PURE__ */ o("h2", {
101
111
  className: "text-lg font-medium",
102
112
  children: "Teams"
103
- }), /* @__PURE__ */ a("div", {
113
+ }), /* @__PURE__ */ s("div", {
104
114
  className: "grid grid-cols-1 md:grid-cols-2 gap-4",
105
- children: [C.map((e) => /* @__PURE__ */ a(s, { children: [/* @__PURE__ */ i(l, {
115
+ children: [D.map((e) => /* @__PURE__ */ s(u, { children: [/* @__PURE__ */ o(f, {
106
116
  className: "pb-2",
107
- children: /* @__PURE__ */ a("div", {
117
+ children: /* @__PURE__ */ s("div", {
108
118
  className: "flex items-center justify-between",
109
- children: [/* @__PURE__ */ i(u, {
119
+ children: [/* @__PURE__ */ o(p, {
110
120
  className: "text-base",
111
121
  children: e.name
112
- }), /* @__PURE__ */ a(o, {
122
+ }), /* @__PURE__ */ s(c, {
113
123
  variant: "outline",
114
124
  children: [e.projectsCount, " projects"]
115
125
  })]
116
126
  })
117
- }), /* @__PURE__ */ a(c, { children: [/* @__PURE__ */ i("p", {
127
+ }), /* @__PURE__ */ s(d, { children: [/* @__PURE__ */ o("p", {
118
128
  className: "text-sm text-muted-foreground",
119
129
  children: e.description
120
- }), /* @__PURE__ */ a("p", {
130
+ }), /* @__PURE__ */ s("p", {
121
131
  className: "text-xs text-muted-foreground mt-2",
122
- children: ["Lead: ", /* @__PURE__ */ i(t, { id: e.leadId })]
123
- })] })] }, e.id)), C.length === 0 && /* @__PURE__ */ i("p", {
132
+ children: ["Lead: ", /* @__PURE__ */ o(n, { id: e.leadId })]
133
+ })] })] }, e.id)), D.length === 0 && /* @__PURE__ */ o("p", {
124
134
  className: "text-sm text-muted-foreground col-span-2 text-center py-4",
125
135
  children: "No teams found. Create projects to see team groupings."
126
136
  })]
127
137
  })]
128
138
  }),
129
- /* @__PURE__ */ a("div", {
139
+ /* @__PURE__ */ s("div", {
130
140
  className: "space-y-4",
131
- children: [/* @__PURE__ */ i("h2", {
141
+ children: [/* @__PURE__ */ o("h2", {
132
142
  className: "text-lg font-medium",
133
143
  children: "Members"
134
- }), /* @__PURE__ */ a("div", {
144
+ }), /* @__PURE__ */ s("div", {
135
145
  className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",
136
- children: [x.map((e) => /* @__PURE__ */ i(s, { children: /* @__PURE__ */ a(c, {
146
+ children: [T.map((e) => /* @__PURE__ */ o(u, { children: /* @__PURE__ */ s(d, {
137
147
  className: "pt-4 space-y-3",
138
148
  children: [
139
- /* @__PURE__ */ a("div", {
149
+ /* @__PURE__ */ s("div", {
140
150
  className: "flex items-center gap-3",
141
- children: [/* @__PURE__ */ a("div", {
151
+ children: [/* @__PURE__ */ s("div", {
142
152
  className: "relative",
143
- children: [/* @__PURE__ */ i("div", {
153
+ children: [/* @__PURE__ */ o("div", {
144
154
  className: "h-10 w-10 rounded-full bg-primary/10 flex items-center justify-center text-sm font-medium text-primary",
145
155
  children: e.name.split(/[\s-]+/).slice(0, 2).map((e) => e[0]?.toUpperCase() ?? "").join("")
146
- }), /* @__PURE__ */ i("div", { className: `absolute -bottom-0.5 -right-0.5 h-3 w-3 rounded-full border-2 border-background ${f[e.status]}` })]
147
- }), /* @__PURE__ */ a("div", { children: [/* @__PURE__ */ i("p", {
156
+ }), /* @__PURE__ */ o("div", { className: `absolute -bottom-0.5 -right-0.5 h-3 w-3 rounded-full border-2 border-background ${h[e.status]}` })]
157
+ }), /* @__PURE__ */ s("div", { children: [/* @__PURE__ */ o("p", {
148
158
  className: "text-sm font-medium",
149
159
  children: e.name
150
- }), /* @__PURE__ */ i("p", {
160
+ }), /* @__PURE__ */ o("p", {
151
161
  className: "text-xs text-muted-foreground",
152
162
  children: e.role
153
163
  })] })]
154
164
  }),
155
- /* @__PURE__ */ a("div", {
165
+ /* @__PURE__ */ s("div", {
156
166
  className: "grid grid-cols-3 gap-2 text-center text-xs",
157
167
  children: [
158
- /* @__PURE__ */ a("div", { children: [/* @__PURE__ */ i("p", {
168
+ /* @__PURE__ */ s("div", { children: [/* @__PURE__ */ o("p", {
159
169
  className: "font-semibold",
160
170
  children: e.tasksAssigned
161
- }), /* @__PURE__ */ i("p", {
171
+ }), /* @__PURE__ */ o("p", {
162
172
  className: "text-muted-foreground",
163
173
  children: "Assigned"
164
174
  })] }),
165
- /* @__PURE__ */ a("div", { children: [/* @__PURE__ */ i("p", {
175
+ /* @__PURE__ */ s("div", { children: [/* @__PURE__ */ o("p", {
166
176
  className: "font-semibold",
167
177
  children: e.tasksCompleted
168
- }), /* @__PURE__ */ i("p", {
178
+ }), /* @__PURE__ */ o("p", {
169
179
  className: "text-muted-foreground",
170
180
  children: "Done"
171
181
  })] }),
172
- /* @__PURE__ */ a("div", { children: [/* @__PURE__ */ i("p", {
182
+ /* @__PURE__ */ s("div", { children: [/* @__PURE__ */ o("p", {
173
183
  className: "font-semibold",
174
184
  children: e.velocity
175
- }), /* @__PURE__ */ i("p", {
185
+ }), /* @__PURE__ */ o("p", {
176
186
  className: "text-muted-foreground",
177
187
  children: "Velocity"
178
188
  })] })
179
189
  ]
180
190
  }),
181
- /* @__PURE__ */ a("div", {
191
+ /* @__PURE__ */ s("div", {
182
192
  className: "flex justify-between text-xs",
183
- children: [/* @__PURE__ */ i("span", {
193
+ children: [/* @__PURE__ */ o("span", {
184
194
  className: "text-muted-foreground",
185
195
  children: e.department
186
- }), /* @__PURE__ */ i("span", {
196
+ }), /* @__PURE__ */ o("span", {
187
197
  className: "capitalize text-muted-foreground",
188
198
  children: e.status
189
199
  })]
190
200
  })
191
201
  ]
192
- }) }, e.id)), x.length === 0 && /* @__PURE__ */ i("p", {
202
+ }) }, e.id)), T.length === 0 && /* @__PURE__ */ o("p", {
193
203
  className: "text-sm text-muted-foreground col-span-3 text-center py-4",
194
204
  children: "No team members found. Assign work items to see members here."
195
205
  })]
@@ -199,6 +209,6 @@ function p() {
199
209
  });
200
210
  }
201
211
  //#endregion
202
- export { p as TeamTeamPagePage };
212
+ export { g as TeamTeamPagePage };
203
213
 
204
214
  //# sourceMappingURL=TeamTeamPagePage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TeamTeamPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/TeamTeamPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Badge } from '@burdenoff/fe-libs/ui';\nimport { Users } from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\nimport { PersonName } from '../people/People';\n\nconst GET_TEAM_DATA = gql`\n query GetTeamData(\n $workspaceId: ID!\n $projectPagination: PlanmagnetPaginationInput\n $workItemPagination: PlanmagnetPaginationInput\n ) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: $projectPagination) {\n items {\n id\n name\n key\n status\n ownerId\n methodology\n }\n totalCount\n }\n planmagnetWorkItems(workspaceId: $workspaceId, pagination: $workItemPagination) {\n items {\n id\n status\n assigneeId\n storyPoints\n }\n totalCount\n }\n }\n`;\n\ninterface ProjectNode {\n id: string;\n name: string;\n key: string;\n status: string;\n ownerId: string | null;\n methodology: string | null;\n}\n\ninterface WorkItemNode {\n id: string;\n status: string;\n assigneeId: string | null;\n storyPoints: number | null;\n}\n\ninterface TeamData {\n projects: { items: ProjectNode[]; totalCount: number };\n workItems: { items: WorkItemNode[]; totalCount: number };\n}\n\nconst statusColor: Record<string, string> = {\n active: 'bg-green-400',\n away: 'bg-yellow-400',\n busy: 'bg-red-400',\n offline: 'bg-gray-300',\n};\n\nexport function TeamTeamPagePage() {\n const { workspaceId } = usePlanMagnet();\n\n const { data, loading, error } = useQuery<TeamData>(GET_TEAM_DATA, {\n variables: {\n workspaceId,\n projectPagination: { 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 workItems = data?.planmagnetWorkItems?.items ?? [];\n\n const assigneeIds = new Set(\n workItems.filter((wi) => wi.assigneeId).map((wi) => wi.assigneeId as string)\n );\n const ownerIds = new Set(projects.filter((p) => p.ownerId).map((p) => p.ownerId as string));\n const allMemberIds = new Set([...assigneeIds, ...ownerIds]);\n\n const members = Array.from(allMemberIds).map((memberId) => {\n const memberWorkItems = workItems.filter((wi) => wi.assigneeId === memberId);\n const assigned = memberWorkItems.length;\n const completed = memberWorkItems.filter((wi) => wi.status === 'DONE').length;\n const velocity = memberWorkItems\n .filter((wi) => wi.status === 'DONE')\n .reduce((s, wi) => s + (wi.storyPoints ?? 0), 0);\n const memberProjects = projects.filter((p) => p.ownerId === memberId);\n\n return {\n id: memberId,\n name: memberId,\n role: memberProjects.length > 0 ? 'Project Owner' : 'Contributor',\n department: 'Engineering',\n tasksAssigned: assigned,\n tasksCompleted: completed,\n velocity,\n status: assigned > 0 ? 'active' : 'offline',\n };\n });\n\n const teamsByMethodology = projects.reduce(\n (acc, p) => {\n const method = p.methodology ?? 'unassigned';\n if (!acc[method]) {\n acc[method] = { projects: [], ownerIds: new Set<string>() };\n }\n acc[method].projects.push(p);\n if (p.ownerId) acc[method].ownerIds.add(p.ownerId);\n return acc;\n },\n {} as Record<string, { projects: ProjectNode[]; ownerIds: Set<string> }>\n );\n\n const teams = Object.entries(teamsByMethodology).map(([methodology, group]) => ({\n id: methodology,\n name: `${methodology.charAt(0).toUpperCase()}${methodology.slice(1)} Team`,\n description: `Projects using ${methodology} methodology`,\n projectsCount: group.projects.length,\n leadId: Array.from(group.ownerIds)[0] ?? 'Unassigned',\n }));\n\n return (\n <div className=\"space-y-6 p-6\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Team Overview</h1>\n <p className=\"text-sm text-muted-foreground\">\n {members.length} contributors across {teams.length} teams\n </p>\n </div>\n\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-medium\">Teams</h2>\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {teams.map((team) => (\n <Card key={team.id}>\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base\">{team.name}</CardTitle>\n <Badge variant=\"outline\">{team.projectsCount} projects</Badge>\n </div>\n </CardHeader>\n <CardContent>\n <p className=\"text-sm text-muted-foreground\">{team.description}</p>\n <p className=\"text-xs text-muted-foreground mt-2\">\n Lead: <PersonName id={team.leadId} />\n </p>\n </CardContent>\n </Card>\n ))}\n {teams.length === 0 && (\n <p className=\"text-sm text-muted-foreground col-span-2 text-center py-4\">\n No teams found. Create projects to see team groupings.\n </p>\n )}\n </div>\n </div>\n\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-medium\">Members</h2>\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {members.map((member) => (\n <Card key={member.id}>\n <CardContent className=\"pt-4 space-y-3\">\n <div className=\"flex items-center gap-3\">\n <div className=\"relative\">\n <div className=\"h-10 w-10 rounded-full bg-primary/10 flex items-center justify-center text-sm font-medium text-primary\">\n {member.name\n .split(/[\\s-]+/)\n .slice(0, 2)\n .map((n) => n[0]?.toUpperCase() ?? '')\n .join('')}\n </div>\n <div\n className={`absolute -bottom-0.5 -right-0.5 h-3 w-3 rounded-full border-2 border-background ${statusColor[member.status]}`}\n />\n </div>\n <div>\n <p className=\"text-sm font-medium\">{member.name}</p>\n <p className=\"text-xs text-muted-foreground\">{member.role}</p>\n </div>\n </div>\n <div className=\"grid grid-cols-3 gap-2 text-center text-xs\">\n <div>\n <p className=\"font-semibold\">{member.tasksAssigned}</p>\n <p className=\"text-muted-foreground\">Assigned</p>\n </div>\n <div>\n <p className=\"font-semibold\">{member.tasksCompleted}</p>\n <p className=\"text-muted-foreground\">Done</p>\n </div>\n <div>\n <p className=\"font-semibold\">{member.velocity}</p>\n <p className=\"text-muted-foreground\">Velocity</p>\n </div>\n </div>\n <div className=\"flex justify-between text-xs\">\n <span className=\"text-muted-foreground\">{member.department}</span>\n <span className=\"capitalize text-muted-foreground\">{member.status}</span>\n </div>\n </CardContent>\n </Card>\n ))}\n {members.length === 0 && (\n <p className=\"text-sm text-muted-foreground col-span-3 text-center py-4\">\n No team members found. Assign work items to see members here.\n </p>\n )}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"TeamTeamPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/TeamTeamPagePage.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 { UserPlus, Users } from 'lucide-react';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { PersonName } from '../people/People';\n\nconst GET_TEAM_DATA = gql`\n query GetTeamData(\n $workspaceId: ID!\n $projectPagination: PlanmagnetPaginationInput\n $workItemPagination: PlanmagnetPaginationInput\n ) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: $projectPagination) {\n items {\n id\n name\n key\n status\n ownerId\n methodology\n }\n totalCount\n }\n planmagnetWorkItems(workspaceId: $workspaceId, pagination: $workItemPagination) {\n items {\n id\n status\n assigneeId\n storyPoints\n }\n totalCount\n }\n }\n`;\n\ninterface ProjectNode {\n id: string;\n name: string;\n key: string;\n status: string;\n ownerId: string | null;\n methodology: string | null;\n}\n\ninterface WorkItemNode {\n id: string;\n status: string;\n assigneeId: string | null;\n storyPoints: number | null;\n}\n\ninterface TeamData {\n projects: { items: ProjectNode[]; totalCount: number };\n workItems: { items: WorkItemNode[]; totalCount: number };\n}\n\nconst statusColor: Record<string, string> = {\n active: 'bg-green-400',\n away: 'bg-yellow-400',\n busy: 'bg-red-400',\n offline: 'bg-gray-300',\n};\n\nexport function TeamTeamPagePage() {\n const { workspaceId } = usePlanMagnet();\n const navigate = usePlanMagnetNavigate();\n\n const { data, loading, error } = useQuery<TeamData>(GET_TEAM_DATA, {\n variables: {\n workspaceId,\n projectPagination: { 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 workItems = data?.planmagnetWorkItems?.items ?? [];\n\n const assigneeIds = new Set(\n workItems.filter((wi) => wi.assigneeId).map((wi) => wi.assigneeId as string)\n );\n const ownerIds = new Set(projects.filter((p) => p.ownerId).map((p) => p.ownerId as string));\n const allMemberIds = new Set([...assigneeIds, ...ownerIds]);\n\n const members = Array.from(allMemberIds).map((memberId) => {\n const memberWorkItems = workItems.filter((wi) => wi.assigneeId === memberId);\n const assigned = memberWorkItems.length;\n const completed = memberWorkItems.filter((wi) => wi.status === 'DONE').length;\n const velocity = memberWorkItems\n .filter((wi) => wi.status === 'DONE')\n .reduce((s, wi) => s + (wi.storyPoints ?? 0), 0);\n const memberProjects = projects.filter((p) => p.ownerId === memberId);\n\n return {\n id: memberId,\n name: memberId,\n role: memberProjects.length > 0 ? 'Project Owner' : 'Contributor',\n department: 'Engineering',\n tasksAssigned: assigned,\n tasksCompleted: completed,\n velocity,\n status: assigned > 0 ? 'active' : 'offline',\n };\n });\n\n const teamsByMethodology = projects.reduce(\n (acc, p) => {\n const method = p.methodology ?? 'unassigned';\n if (!acc[method]) {\n acc[method] = { projects: [], ownerIds: new Set<string>() };\n }\n acc[method].projects.push(p);\n if (p.ownerId) acc[method].ownerIds.add(p.ownerId);\n return acc;\n },\n {} as Record<string, { projects: ProjectNode[]; ownerIds: Set<string> }>\n );\n\n const teams = Object.entries(teamsByMethodology).map(([methodology, group]) => ({\n id: methodology,\n name: `${methodology.charAt(0).toUpperCase()}${methodology.slice(1)} Team`,\n description: `Projects using ${methodology} methodology`,\n projectsCount: group.projects.length,\n leadId: Array.from(group.ownerIds)[0] ?? 'Unassigned',\n }));\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-start justify-between gap-4\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Team Overview</h1>\n <p className=\"text-sm text-muted-foreground\">\n {members.length} contributors across {teams.length} teams\n </p>\n </div>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => navigate('/team/invite-member-page')}\n data-testid=\"team-invite\"\n >\n <UserPlus className=\"mr-1 h-4 w-4\" />\n Invite member\n </Button>\n </div>\n\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-medium\">Teams</h2>\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {teams.map((team) => (\n <Card key={team.id}>\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base\">{team.name}</CardTitle>\n <Badge variant=\"outline\">{team.projectsCount} projects</Badge>\n </div>\n </CardHeader>\n <CardContent>\n <p className=\"text-sm text-muted-foreground\">{team.description}</p>\n <p className=\"text-xs text-muted-foreground mt-2\">\n Lead: <PersonName id={team.leadId} />\n </p>\n </CardContent>\n </Card>\n ))}\n {teams.length === 0 && (\n <p className=\"text-sm text-muted-foreground col-span-2 text-center py-4\">\n No teams found. Create projects to see team groupings.\n </p>\n )}\n </div>\n </div>\n\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-medium\">Members</h2>\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {members.map((member) => (\n <Card key={member.id}>\n <CardContent className=\"pt-4 space-y-3\">\n <div className=\"flex items-center gap-3\">\n <div className=\"relative\">\n <div className=\"h-10 w-10 rounded-full bg-primary/10 flex items-center justify-center text-sm font-medium text-primary\">\n {member.name\n .split(/[\\s-]+/)\n .slice(0, 2)\n .map((n) => n[0]?.toUpperCase() ?? '')\n .join('')}\n </div>\n <div\n className={`absolute -bottom-0.5 -right-0.5 h-3 w-3 rounded-full border-2 border-background ${statusColor[member.status]}`}\n />\n </div>\n <div>\n <p className=\"text-sm font-medium\">{member.name}</p>\n <p className=\"text-xs text-muted-foreground\">{member.role}</p>\n </div>\n </div>\n <div className=\"grid grid-cols-3 gap-2 text-center text-xs\">\n <div>\n <p className=\"font-semibold\">{member.tasksAssigned}</p>\n <p className=\"text-muted-foreground\">Assigned</p>\n </div>\n <div>\n <p className=\"font-semibold\">{member.tasksCompleted}</p>\n <p className=\"text-muted-foreground\">Done</p>\n </div>\n <div>\n <p className=\"font-semibold\">{member.velocity}</p>\n <p className=\"text-muted-foreground\">Velocity</p>\n </div>\n </div>\n <div className=\"flex justify-between text-xs\">\n <span className=\"text-muted-foreground\">{member.department}</span>\n <span className=\"capitalize text-muted-foreground\">{member.status}</span>\n </div>\n </CardContent>\n </Card>\n ))}\n {members.length === 0 && (\n <p className=\"text-sm text-muted-foreground col-span-3 text-center py-4\">\n No team members found. Assign work items to see members here.\n </p>\n )}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * What a roadmap is organised around (BOFF-7934). Separate from how it is
3
+ * displayed: the roadmap page has ONE layout today (items grouped by lane with
4
+ * their dates), so the service accepts only the TIMELINE display and these
5
+ * pages no longer offer Gantt / Swimlane / Custom — a stored label is not a
6
+ * view. Legacy roadmaps were never classified, so a missing focus is shown as
7
+ * "not set", never guessed.
8
+ */
9
+ export type PlanningFocus = 'THEME' | 'FEATURE' | 'TECHNOLOGY' | 'PORTFOLIO';
10
+ export declare const PLANNING_FOCUSES: readonly PlanningFocus[];
11
+ /** The only display the roadmap page has; the create/update inputs require one. */
12
+ export declare const ROADMAP_DISPLAY = "TIMELINE";
13
+ export declare function planningFocusLabel(focus: string | null | undefined): string;
14
+ /** Icon AND label, never colour alone. */
15
+ export declare function PlanningFocusBadge({ focus }: {
16
+ focus: string | null | undefined;
17
+ }): import("react/jsx-runtime").JSX.Element;
18
+ export declare function PlanningFocusSelect({ value, onChange, id, }: {
19
+ value: PlanningFocus | null;
20
+ onChange: (value: PlanningFocus | null) => void;
21
+ id?: string;
22
+ }): import("react/jsx-runtime").JSX.Element;
23
+ //# sourceMappingURL=planningFocus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planningFocus.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/roadmaps/planningFocus.tsx"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,SAAS,GAAG,YAAY,GAAG,WAAW,CAAC;AAE7E,eAAO,MAAM,gBAAgB,EAAE,SAAS,aAAa,EAKpD,CAAC;AASF,mFAAmF;AACnF,eAAO,MAAM,eAAe,aAAa,CAAC;AAE1C,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAE3E;AAED,0CAA0C;AAC1C,wBAAgB,kBAAkB,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;CAAE,2CAoBjF;AAED,wBAAgB,mBAAmB,CAAC,EAClC,KAAK,EACL,QAAQ,EACR,EAAqB,GACtB,EAAE;IACD,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;IAC5B,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,KAAK,IAAI,CAAC;IAChD,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,2CAwBA"}
@@ -0,0 +1,76 @@
1
+ import { Boxes as e, Cpu as t, Layers as n, Lightbulb as r } from "lucide-react";
2
+ import { jsx as i, jsxs as a } from "react/jsx-runtime";
3
+ //#region src/planmagnet/roadmaps/planningFocus.tsx
4
+ var o = [
5
+ "THEME",
6
+ "FEATURE",
7
+ "TECHNOLOGY",
8
+ "PORTFOLIO"
9
+ ], s = {
10
+ THEME: {
11
+ label: "Theme",
12
+ icon: r
13
+ },
14
+ FEATURE: {
15
+ label: "Feature",
16
+ icon: n
17
+ },
18
+ TECHNOLOGY: {
19
+ label: "Technology",
20
+ icon: t
21
+ },
22
+ PORTFOLIO: {
23
+ label: "Portfolio",
24
+ icon: e
25
+ }
26
+ }, c = "TIMELINE";
27
+ function l(e) {
28
+ return e && e in s ? s[e].label : "Focus not set";
29
+ }
30
+ function u({ focus: e }) {
31
+ if (!e || !(e in s)) return /* @__PURE__ */ i("span", {
32
+ className: "inline-flex items-center gap-1 text-xs text-muted-foreground",
33
+ "data-testid": "planning-focus",
34
+ children: "Focus not set"
35
+ });
36
+ let { label: t, icon: n } = s[e];
37
+ return /* @__PURE__ */ a("span", {
38
+ className: "inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-xs text-foreground",
39
+ "data-testid": "planning-focus",
40
+ children: [
41
+ /* @__PURE__ */ i(n, { className: "h-3 w-3" }),
42
+ " ",
43
+ t
44
+ ]
45
+ });
46
+ }
47
+ function d({ value: e, onChange: t, id: n = "planning-focus" }) {
48
+ return /* @__PURE__ */ a("div", { children: [
49
+ /* @__PURE__ */ i("label", {
50
+ htmlFor: n,
51
+ className: "text-sm font-medium",
52
+ children: "Planning focus"
53
+ }),
54
+ /* @__PURE__ */ a("select", {
55
+ id: n,
56
+ className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm",
57
+ value: e ?? "",
58
+ onChange: (e) => t(e.target.value ? e.target.value : null),
59
+ children: [/* @__PURE__ */ i("option", {
60
+ value: "",
61
+ children: "Not set"
62
+ }), o.map((e) => /* @__PURE__ */ i("option", {
63
+ value: e,
64
+ children: s[e].label
65
+ }, e))]
66
+ }),
67
+ /* @__PURE__ */ i("p", {
68
+ className: "mt-1 text-xs text-muted-foreground",
69
+ children: "What the roadmap is organised around. Roadmaps are shown in one layout for now."
70
+ })
71
+ ] });
72
+ }
73
+ //#endregion
74
+ export { o as PLANNING_FOCUSES, u as PlanningFocusBadge, d as PlanningFocusSelect, c as ROADMAP_DISPLAY, l as planningFocusLabel };
75
+
76
+ //# sourceMappingURL=planningFocus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planningFocus.js","names":[],"sources":["../../../src/planmagnet/roadmaps/planningFocus.tsx"],"sourcesContent":["import { Boxes, Cpu, Layers, Lightbulb, type LucideIcon } from 'lucide-react';\n\n/**\n * What a roadmap is organised around (BOFF-7934). Separate from how it is\n * displayed: the roadmap page has ONE layout today (items grouped by lane with\n * their dates), so the service accepts only the TIMELINE display and these\n * pages no longer offer Gantt / Swimlane / Custom — a stored label is not a\n * view. Legacy roadmaps were never classified, so a missing focus is shown as\n * \"not set\", never guessed.\n */\nexport type PlanningFocus = 'THEME' | 'FEATURE' | 'TECHNOLOGY' | 'PORTFOLIO';\n\nexport const PLANNING_FOCUSES: readonly PlanningFocus[] = [\n 'THEME',\n 'FEATURE',\n 'TECHNOLOGY',\n 'PORTFOLIO',\n];\n\nconst FOCUS: Record<PlanningFocus, { label: string; icon: LucideIcon }> = {\n THEME: { label: 'Theme', icon: Lightbulb },\n FEATURE: { label: 'Feature', icon: Layers },\n TECHNOLOGY: { label: 'Technology', icon: Cpu },\n PORTFOLIO: { label: 'Portfolio', icon: Boxes },\n};\n\n/** The only display the roadmap page has; the create/update inputs require one. */\nexport const ROADMAP_DISPLAY = 'TIMELINE';\n\nexport function planningFocusLabel(focus: string | null | undefined): string {\n return focus && focus in FOCUS ? FOCUS[focus as PlanningFocus].label : 'Focus not set';\n}\n\n/** Icon AND label, never colour alone. */\nexport function PlanningFocusBadge({ focus }: { focus: string | null | undefined }) {\n if (!focus || !(focus in FOCUS)) {\n return (\n <span\n className=\"inline-flex items-center gap-1 text-xs text-muted-foreground\"\n data-testid=\"planning-focus\"\n >\n Focus not set\n </span>\n );\n }\n const { label, icon: Icon } = FOCUS[focus as PlanningFocus];\n return (\n <span\n className=\"inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-xs text-foreground\"\n data-testid=\"planning-focus\"\n >\n <Icon className=\"h-3 w-3\" /> {label}\n </span>\n );\n}\n\nexport function PlanningFocusSelect({\n value,\n onChange,\n id = 'planning-focus',\n}: {\n value: PlanningFocus | null;\n onChange: (value: PlanningFocus | null) => void;\n id?: string;\n}) {\n return (\n <div>\n <label htmlFor={id} className=\"text-sm font-medium\">\n Planning focus\n </label>\n <select\n id={id}\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm\"\n value={value ?? ''}\n onChange={(e) => onChange(e.target.value ? (e.target.value as PlanningFocus) : null)}\n >\n <option value=\"\">Not set</option>\n {PLANNING_FOCUSES.map((f) => (\n <option key={f} value={f}>\n {FOCUS[f].label}\n </option>\n ))}\n </select>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n What the roadmap is organised around. Roadmaps are shown in one layout for now.\n </p>\n </div>\n );\n}\n"],"mappings":";;;AAYA,IAAa,IAA6C;CACxD;CACA;CACA;CACA;CACD,EAEK,IAAoE;CACxE,OAAO;EAAE,OAAO;EAAS,MAAM;EAAW;CAC1C,SAAS;EAAE,OAAO;EAAW,MAAM;EAAQ;CAC3C,YAAY;EAAE,OAAO;EAAc,MAAM;EAAK;CAC9C,WAAW;EAAE,OAAO;EAAa,MAAM;EAAO;CAC/C,EAGY,IAAkB;AAE/B,SAAgB,EAAmB,GAA0C;AAC3E,QAAO,KAAS,KAAS,IAAQ,EAAM,GAAwB,QAAQ;;AAIzE,SAAgB,EAAmB,EAAE,YAA+C;AAClF,KAAI,CAAC,KAAS,EAAE,KAAS,GACvB,QACE,kBAAC,QAAD;EACE,WAAU;EACV,eAAY;YACb;EAEM,CAAA;CAGX,IAAM,EAAE,UAAO,MAAM,MAAS,EAAM;AACpC,QACE,kBAAC,QAAD;EACE,WAAU;EACV,eAAY;YAFd;GAIE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA;;GAAE;GACzB;;;AAIX,SAAgB,EAAoB,EAClC,UACA,aACA,QAAK,oBAKJ;AACD,QACE,kBAAC,OAAD,EAAA,UAAA;EACE,kBAAC,SAAD;GAAO,SAAS;GAAI,WAAU;aAAsB;GAE5C,CAAA;EACR,kBAAC,UAAD;GACM;GACJ,WAAU;GACV,OAAO,KAAS;GAChB,WAAW,MAAM,EAAS,EAAE,OAAO,QAAS,EAAE,OAAO,QAA0B,KAAK;aAJtF,CAME,kBAAC,UAAD;IAAQ,OAAM;cAAG;IAAgB,CAAA,EAChC,EAAiB,KAAK,MACrB,kBAAC,UAAD;IAAgB,OAAO;cACpB,EAAM,GAAG;IACH,EAFI,EAEJ,CACT,CACK;;EACT,kBAAC,KAAD;GAAG,WAAU;aAAqC;GAE9C,CAAA;EACA,EAAA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"SprintControls.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/sprints/SprintControls.tsx"],"names":[],"mappings":"AA6BA;;;;;;;;;;;;GAYG;AAEH,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,GAAG,WAAW,CAAC;AACxF,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,UAAU,GAAG,QAAQ,CAAC;AAQ3D,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,EAAE,CAI/D;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAExD;AAsCD,wBAAgB,sBAAsB,CAAC,EACrC,QAAQ,EACR,UAAU,EACV,MAAM,GACP,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB,kDA2DA;AAsFD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAQD,wBAAgB,oBAAoB,CAAC,EACnC,QAAQ,EACR,SAAS,EACT,MAAM,EACN,KAAK,GACN,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,cAAc,EAAE,CAAC;CACzB,2CA2EA;AAqKD,wBAAgB,eAAe,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,2CAuKvF"}
1
+ {"version":3,"file":"SprintControls.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/sprints/SprintControls.tsx"],"names":[],"mappings":"AA6BA;;;;;;;;;;;;GAYG;AAEH,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,GAAG,WAAW,CAAC;AACxF,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,UAAU,GAAG,QAAQ,CAAC;AAQ3D,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,EAAE,CAI/D;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAExD;AAsCD,wBAAgB,sBAAsB,CAAC,EACrC,QAAQ,EACR,UAAU,EACV,MAAM,GACP,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB,kDA2DA;AAsFD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAQD,wBAAgB,oBAAoB,CAAC,EACnC,QAAQ,EACR,SAAS,EACT,MAAM,EACN,KAAK,GACN,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,cAAc,EAAE,CAAC;CACzB,2CA2EA;AAqKD,wBAAgB,eAAe,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,2CAwMvF"}
@@ -371,13 +371,13 @@ var X = l`
371
371
  capacity: ""
372
372
  };
373
373
  function $({ onCreated: n }) {
374
- let { workspaceId: i } = e(), [a, s] = r(!1), [c, l] = r(Q), [m, h] = r(null), { data: g } = d(Z, {
374
+ let { workspaceId: i } = e(), [a, s] = r(!1), [c, l] = r(Q), [m, h] = r(null), { data: g, loading: _, error: v, refetch: y } = d(Z, {
375
375
  variables: { workspaceId: i ?? "" },
376
376
  skip: !a || !i
377
- }), _ = g?.planmagnetProjects.items ?? [], v = c.projectId || _[0]?.id || "", [y, { loading: b }] = u(X, {
377
+ }), b = g?.planmagnetProjects.items ?? [], x = c.projectId || b[0]?.id || "", [S, { loading: C }] = u(X, {
378
378
  refetchQueries: L,
379
379
  awaitRefetchQueries: !0
380
- }), x = c.capacity.trim() === "" ? void 0 : Number(c.capacity), S = x !== void 0 && (!Number.isInteger(x) || x < 0), C = !!(c.startDate && c.endDate && c.endDate < c.startDate), T = c.name.trim() !== "" && v !== "" && !S && !C && !b;
380
+ }), T = c.capacity.trim() === "" ? void 0 : Number(c.capacity), P = T !== void 0 && (!Number.isInteger(T) || T < 0), F = !!(c.startDate && c.endDate && c.endDate < c.startDate), I = c.name.trim() !== "" && x !== "" && !P && !F && !C;
381
381
  return /* @__PURE__ */ p(D, {
382
382
  open: a,
383
383
  onOpenChange: (e) => {
@@ -409,26 +409,45 @@ function $({ onCreated: n }) {
409
409
  name: e.target.value
410
410
  })
411
411
  })] }),
412
- /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
413
- htmlFor: "new-sprint-project",
414
- className: "text-sm font-medium",
415
- children: "Project"
416
- }), /* @__PURE__ */ p("select", {
417
- id: "new-sprint-project",
418
- className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm",
419
- value: v,
420
- onChange: (e) => l({
421
- ...c,
422
- projectId: e.target.value
412
+ /* @__PURE__ */ p("div", { children: [
413
+ /* @__PURE__ */ f("label", {
414
+ htmlFor: "new-sprint-project",
415
+ className: "text-sm font-medium",
416
+ children: "Project"
423
417
  }),
424
- children: [_.length === 0 && /* @__PURE__ */ f("option", {
425
- value: "",
426
- children: "No projects"
427
- }), _.map((e) => /* @__PURE__ */ f("option", {
428
- value: e.id,
429
- children: e.name
430
- }, e.id))]
431
- })] }),
418
+ /* @__PURE__ */ p("select", {
419
+ id: "new-sprint-project",
420
+ className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm",
421
+ value: x,
422
+ onChange: (e) => l({
423
+ ...c,
424
+ projectId: e.target.value
425
+ }),
426
+ children: [b.length === 0 && /* @__PURE__ */ f("option", {
427
+ value: "",
428
+ children: _ && !g ? "Loading projects…" : v ? "Projects could not be loaded" : "No projects yet"
429
+ }), b.map((e) => /* @__PURE__ */ f("option", {
430
+ value: e.id,
431
+ children: e.name
432
+ }, e.id))]
433
+ }),
434
+ v && /* @__PURE__ */ p("p", {
435
+ role: "alert",
436
+ className: "mt-1 flex items-center gap-2 text-xs text-destructive",
437
+ children: [v.message, /* @__PURE__ */ f(w, {
438
+ type: "button",
439
+ size: "sm",
440
+ variant: "ghost",
441
+ className: "h-6 px-2 text-xs",
442
+ onClick: () => void y(),
443
+ children: "Retry"
444
+ })]
445
+ }),
446
+ !_ && !v && g && b.length === 0 && /* @__PURE__ */ f("p", {
447
+ className: "mt-1 text-xs text-muted-foreground",
448
+ children: "Create a project first (Projects → New project)."
449
+ })
450
+ ] }),
432
451
  /* @__PURE__ */ p("div", {
433
452
  className: "grid grid-cols-2 gap-3",
434
453
  children: [/* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
@@ -459,7 +478,7 @@ function $({ onCreated: n }) {
459
478
  })
460
479
  })] })]
461
480
  }),
462
- C && /* @__PURE__ */ f(V, { message: "The end date is before the start date." }),
481
+ F && /* @__PURE__ */ f(V, { message: "The end date is before the start date." }),
463
482
  /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
464
483
  htmlFor: "new-sprint-capacity",
465
484
  className: "text-sm font-medium",
@@ -475,7 +494,7 @@ function $({ onCreated: n }) {
475
494
  capacity: e.target.value
476
495
  })
477
496
  })] }),
478
- S && /* @__PURE__ */ f(V, { message: "Capacity must be a whole number, 0 or more." }),
497
+ P && /* @__PURE__ */ f(V, { message: "Capacity must be a whole number, 0 or more." }),
479
498
  /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
480
499
  htmlFor: "new-sprint-goal",
481
500
  className: "text-sm font-medium",
@@ -496,22 +515,22 @@ function $({ onCreated: n }) {
496
515
  onClick: async () => {
497
516
  h(null);
498
517
  try {
499
- let e = (await t(y({ variables: { input: {
518
+ let e = (await t(S({ variables: { input: {
500
519
  name: c.name.trim(),
501
- projectId: v,
520
+ projectId: x,
502
521
  startDate: c.startDate || void 0,
503
522
  endDate: c.endDate || void 0,
504
523
  goal: c.goal.trim() || void 0,
505
- capacity: x
524
+ capacity: T
506
525
  } } }))).data?.planmagnetCreateSprint.id;
507
526
  l(Q), s(!1), e && n(e);
508
527
  } catch (e) {
509
528
  h(e instanceof Error ? e.message : "The sprint could not be created.");
510
529
  }
511
530
  },
512
- disabled: !T,
531
+ disabled: !I,
513
532
  "data-testid": "new-sprint-submit",
514
- children: b ? "Creating…" : "Create sprint"
533
+ children: C ? "Creating…" : "Create sprint"
515
534
  }) })
516
535
  ]
517
536
  })]