@burdenoff/microfe-planmagnet 2026.927.3 → 2026.927.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/generated/global-types.d.ts +9 -1
- package/dist/generated/global-types.d.ts.map +1 -1
- package/dist/generated/wspace-operations.d.ts +0 -12
- package/dist/generated/wspace-operations.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.js +14 -10
- package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
- package/dist/planmagnet/admin/PlanMagnetAdminRoot.d.ts.map +1 -1
- package/dist/planmagnet/admin/PlanMagnetAdminRoot.js +149 -127
- package/dist/planmagnet/admin/PlanMagnetAdminRoot.js.map +1 -1
- package/dist/planmagnet/controls/FeatureControls.d.ts +26 -0
- package/dist/planmagnet/controls/FeatureControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/FeatureControls.js +321 -0
- package/dist/planmagnet/controls/FeatureControls.js.map +1 -0
- package/dist/planmagnet/controls/FeatureTriage.d.ts +21 -0
- package/dist/planmagnet/controls/FeatureTriage.d.ts.map +1 -0
- package/dist/planmagnet/controls/FeatureTriage.js +398 -0
- package/dist/planmagnet/controls/FeatureTriage.js.map +1 -0
- package/dist/planmagnet/controls/MilestoneControls.d.ts +17 -0
- package/dist/planmagnet/controls/MilestoneControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/MilestoneControls.js +203 -0
- package/dist/planmagnet/controls/MilestoneControls.js.map +1 -0
- package/dist/planmagnet/controls/ObjectiveControls.d.ts +31 -0
- package/dist/planmagnet/controls/ObjectiveControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/ObjectiveControls.js +296 -0
- package/dist/planmagnet/controls/ObjectiveControls.js.map +1 -0
- package/dist/planmagnet/controls/Pickers.d.ts +26 -0
- package/dist/planmagnet/controls/Pickers.d.ts.map +1 -0
- package/dist/planmagnet/controls/Pickers.js +171 -0
- package/dist/planmagnet/controls/Pickers.js.map +1 -0
- package/dist/planmagnet/controls/ProjectControls.d.ts.map +1 -1
- package/dist/planmagnet/controls/ProjectControls.js +47 -44
- package/dist/planmagnet/controls/ProjectControls.js.map +1 -1
- package/dist/planmagnet/controls/ReleaseControls.d.ts +14 -0
- package/dist/planmagnet/controls/ReleaseControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/ReleaseControls.js +111 -0
- package/dist/planmagnet/controls/ReleaseControls.js.map +1 -0
- package/dist/planmagnet/controls/WorkItemControls.d.ts.map +1 -1
- package/dist/planmagnet/controls/WorkItemControls.js +68 -65
- package/dist/planmagnet/controls/WorkItemControls.js.map +1 -1
- package/dist/planmagnet/hooks/useCounts.d.ts +39 -0
- package/dist/planmagnet/hooks/useCounts.d.ts.map +1 -0
- package/dist/planmagnet/hooks/useCounts.js +209 -0
- package/dist/planmagnet/hooks/useCounts.js.map +1 -0
- package/dist/planmagnet/import/exportColumns.d.ts +52 -0
- package/dist/planmagnet/import/exportColumns.d.ts.map +1 -0
- package/dist/planmagnet/import/exportColumns.js +81 -0
- package/dist/planmagnet/import/exportColumns.js.map +1 -0
- package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.js +255 -242
- package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/DashboardDashboardPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/DashboardDashboardPagePage.js +199 -160
- package/dist/planmagnet/pages/DashboardDashboardPagePage.js.map +1 -1
- package/dist/planmagnet/pages/DocsDocDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/DocsDocDetailPagePage.js +190 -153
- package/dist/planmagnet/pages/DocsDocDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/GoalsCreateObjectivePagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/GoalsCreateObjectivePagePage.js +63 -56
- package/dist/planmagnet/pages/GoalsCreateObjectivePagePage.js.map +1 -1
- package/dist/planmagnet/pages/GoalsGoalsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/GoalsGoalsPagePage.js +2 -7
- package/dist/planmagnet/pages/GoalsGoalsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/GoalsObjectiveDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/GoalsObjectiveDetailPagePage.js +229 -214
- package/dist/planmagnet/pages/GoalsObjectiveDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsEditProductPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsEditProductPagePage.js +145 -114
- package/dist/planmagnet/pages/ProductsEditProductPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsEditReleasePagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsEditReleasePagePage.js +134 -105
- package/dist/planmagnet/pages/ProductsEditReleasePagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsFeatureAnalyticsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsFeatureAnalyticsPagePage.js +97 -117
- package/dist/planmagnet/pages/ProductsFeatureAnalyticsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js +169 -110
- package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsFeaturesPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsFeaturesPagePage.js +117 -103
- package/dist/planmagnet/pages/ProductsFeaturesPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsNewFeaturePagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js +119 -94
- package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.js +4 -8
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsProductsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsProductsPagePage.js +85 -90
- package/dist/planmagnet/pages/ProductsProductsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.js +118 -107
- package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsReleasesPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsReleasesPagePage.js +4 -2
- package/dist/planmagnet/pages/ProductsReleasesPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapAnalyticsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapAnalyticsPagePage.js +48 -71
- package/dist/planmagnet/pages/ProductsRoadmapAnalyticsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapsPagePage.js +17 -13
- package/dist/planmagnet/pages/ProductsRoadmapsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsActiveProjectsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsActiveProjectsPagePage.js +1 -1
- package/dist/planmagnet/pages/ProjectsActiveProjectsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.js +55 -63
- package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js +11 -8
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningPagePage.js +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js +152 -139
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectsPagePage.js +75 -74
- package/dist/planmagnet/pages/ProjectsProjectsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ReportsReportsPagePage.d.ts +7 -0
- package/dist/planmagnet/pages/ReportsReportsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ReportsReportsPagePage.js +39 -201
- package/dist/planmagnet/pages/ReportsReportsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/SprintsStartSprintPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/SprintsStartSprintPagePage.js +118 -99
- package/dist/planmagnet/pages/SprintsStartSprintPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksCreateTaskPagePage.js +123 -128
- package/dist/planmagnet/pages/TasksCreateTaskPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksEditTaskPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksEditTaskPagePage.js +139 -107
- package/dist/planmagnet/pages/TasksEditTaskPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksImportPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/TasksImportPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/TasksImportPagePage.js +309 -0
- package/dist/planmagnet/pages/TasksImportPagePage.js.map +1 -0
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.js +173 -126
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksTasksPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksTasksPagePage.js +111 -104
- package/dist/planmagnet/pages/TasksTasksPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TeamTeamPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TeamTeamPagePage.js +99 -177
- package/dist/planmagnet/pages/TeamTeamPagePage.js.map +1 -1
- package/dist/planmagnet/pages/analytics/DeliveryHealthCards.d.ts.map +1 -1
- package/dist/planmagnet/pages/analytics/DeliveryHealthCards.js +8 -4
- package/dist/planmagnet/pages/analytics/DeliveryHealthCards.js.map +1 -1
- package/dist/planmagnet/releases/ReleaseWorkItemsCard.d.ts.map +1 -1
- package/dist/planmagnet/releases/ReleaseWorkItemsCard.js +10 -4
- package/dist/planmagnet/releases/ReleaseWorkItemsCard.js.map +1 -1
- package/dist/planmagnet/roadmaps/RoadmapControls.d.ts.map +1 -1
- package/dist/planmagnet/roadmaps/RoadmapControls.js +150 -137
- package/dist/planmagnet/roadmaps/RoadmapControls.js.map +1 -1
- package/dist/planmagnet/sprints/SprintControls.d.ts.map +1 -1
- package/dist/planmagnet/sprints/SprintControls.js +32 -30
- package/dist/planmagnet/sprints/SprintControls.js.map +1 -1
- package/dist/planmagnet/utils/mutationResult.d.ts +10 -0
- package/dist/planmagnet/utils/mutationResult.d.ts.map +1 -1
- package/dist/planmagnet/utils/mutationResult.js +2 -1
- package/dist/planmagnet/utils/mutationResult.js.map +1 -1
- package/dist/planmagnet/utils/rowNavigation.d.ts +2 -0
- package/dist/planmagnet/utils/rowNavigation.d.ts.map +1 -1
- package/dist/planmagnet/utils/rowNavigation.js +9 -8
- package/dist/planmagnet/utils/rowNavigation.js.map +1 -1
- package/package.json +1 -1
|
@@ -4,13 +4,13 @@ import { rowLinkProps as r } from "../utils/rowNavigation.js";
|
|
|
4
4
|
import { ProjectBoard as i } from "../board/ProjectBoard.js";
|
|
5
5
|
import { ExportWorkItemsButton as a } from "../export/ExportWorkItemsButton.js";
|
|
6
6
|
import { useState as o } from "react";
|
|
7
|
-
import {
|
|
8
|
-
import { gql as
|
|
9
|
-
import { useQuery as
|
|
10
|
-
import { Fragment as
|
|
11
|
-
import { Card as
|
|
7
|
+
import { FileUp as s, Filter as c } from "lucide-react";
|
|
8
|
+
import { gql as l } from "@apollo/client";
|
|
9
|
+
import { useQuery as u } from "@apollo/client/react";
|
|
10
|
+
import { Fragment as d, jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
11
|
+
import { Button as m, Card as h, CardContent as g } from "@burdenoff/fe-libs/ui";
|
|
12
12
|
//#region src/planmagnet/pages/TasksTasksPagePage.tsx
|
|
13
|
-
var
|
|
13
|
+
var _ = l`
|
|
14
14
|
query GetWorkItems(
|
|
15
15
|
$workspaceId: ID!
|
|
16
16
|
$filter: PlanmagnetWorkItemFilter
|
|
@@ -41,7 +41,7 @@ var h = c`
|
|
|
41
41
|
totalCount
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
-
`,
|
|
44
|
+
`, v = l`
|
|
45
45
|
query GetWorkItemCounts($workspaceId: ID!, $filter: PlanmagnetWorkItemFilter) {
|
|
46
46
|
planmagnetWorkItemCounts(workspaceId: $workspaceId, filter: $filter) {
|
|
47
47
|
total
|
|
@@ -51,7 +51,7 @@ var h = c`
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
|
-
`,
|
|
54
|
+
`, y = 100, b = l`
|
|
55
55
|
query GetBoardProjects($workspaceId: ID!) {
|
|
56
56
|
planmagnetProjects(workspaceId: $workspaceId, pagination: { first: 100 }) {
|
|
57
57
|
items {
|
|
@@ -60,7 +60,7 @@ var h = c`
|
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
|
-
`,
|
|
63
|
+
`, x = [
|
|
64
64
|
"BACKLOG",
|
|
65
65
|
"TODO",
|
|
66
66
|
"IN_PROGRESS",
|
|
@@ -68,7 +68,7 @@ var h = c`
|
|
|
68
68
|
"TESTING",
|
|
69
69
|
"DONE",
|
|
70
70
|
"CANCELLED"
|
|
71
|
-
],
|
|
71
|
+
], S = {
|
|
72
72
|
BACKLOG: "Backlog",
|
|
73
73
|
TODO: "To Do",
|
|
74
74
|
IN_PROGRESS: "In Progress",
|
|
@@ -76,7 +76,7 @@ var h = c`
|
|
|
76
76
|
TESTING: "Testing",
|
|
77
77
|
DONE: "Done",
|
|
78
78
|
CANCELLED: "Cancelled"
|
|
79
|
-
},
|
|
79
|
+
}, C = {
|
|
80
80
|
BACKLOG: "border-t-gray-400",
|
|
81
81
|
TODO: "border-t-blue-400",
|
|
82
82
|
IN_PROGRESS: "border-t-yellow-400",
|
|
@@ -84,46 +84,46 @@ var h = c`
|
|
|
84
84
|
TESTING: "border-t-teal-400",
|
|
85
85
|
DONE: "border-t-green-400",
|
|
86
86
|
CANCELLED: "border-t-muted-foreground"
|
|
87
|
-
},
|
|
87
|
+
}, w = {
|
|
88
88
|
LOW: "bg-gray-100 text-gray-700",
|
|
89
89
|
MEDIUM: "bg-blue-100 text-blue-700",
|
|
90
90
|
HIGH: "bg-orange-100 text-orange-700",
|
|
91
91
|
CRITICAL: "bg-red-100 text-red-700"
|
|
92
|
-
},
|
|
92
|
+
}, T = {
|
|
93
93
|
STORY: "bg-green-100 text-green-700",
|
|
94
94
|
BUG: "bg-red-100 text-red-700",
|
|
95
95
|
TASK: "bg-blue-100 text-blue-700",
|
|
96
96
|
EPIC: "bg-purple-100 text-purple-700",
|
|
97
97
|
SUB_TASK: "bg-gray-100 text-gray-700"
|
|
98
98
|
};
|
|
99
|
-
function
|
|
100
|
-
let { workspaceId:
|
|
101
|
-
variables: { workspaceId:
|
|
102
|
-
skip: !
|
|
103
|
-
}),
|
|
104
|
-
...
|
|
105
|
-
...
|
|
106
|
-
}, [
|
|
99
|
+
function E() {
|
|
100
|
+
let { workspaceId: l } = e(), E = t(), [D, O] = o("all"), [k, A] = o("all"), [j, M] = o(null), { data: N } = u(b, {
|
|
101
|
+
variables: { workspaceId: l },
|
|
102
|
+
skip: !l
|
|
103
|
+
}), P = N?.planmagnetProjects?.items ?? [], F = j ?? P[0]?.id ?? "", I = P.find((e) => e.id === F)?.name ?? "", L = {
|
|
104
|
+
...D !== "all" && { priority: D.toUpperCase() },
|
|
105
|
+
...k !== "all" && { type: k.toUpperCase() }
|
|
106
|
+
}, [R, z] = o(!1), { data: B, loading: V, error: H, fetchMore: U } = u(_, {
|
|
107
107
|
variables: {
|
|
108
|
-
workspaceId:
|
|
109
|
-
filter:
|
|
110
|
-
pagination: { first:
|
|
108
|
+
workspaceId: l,
|
|
109
|
+
filter: L,
|
|
110
|
+
pagination: { first: y }
|
|
111
111
|
},
|
|
112
|
-
skip: !
|
|
113
|
-
}), { data:
|
|
112
|
+
skip: !l || !!F
|
|
113
|
+
}), { data: W } = u(v, {
|
|
114
114
|
variables: {
|
|
115
|
-
workspaceId:
|
|
116
|
-
filter:
|
|
115
|
+
workspaceId: l,
|
|
116
|
+
filter: F ? { projectId: F } : L
|
|
117
117
|
},
|
|
118
|
-
skip: !
|
|
119
|
-
}),
|
|
120
|
-
let e =
|
|
118
|
+
skip: !l
|
|
119
|
+
}), G = async () => {
|
|
120
|
+
let e = B?.planmagnetWorkItems?.pageInfo?.endCursor;
|
|
121
121
|
if (e) {
|
|
122
|
-
|
|
122
|
+
z(!0);
|
|
123
123
|
try {
|
|
124
|
-
await
|
|
124
|
+
await U({
|
|
125
125
|
variables: { pagination: {
|
|
126
|
-
first:
|
|
126
|
+
first: y,
|
|
127
127
|
after: e
|
|
128
128
|
} },
|
|
129
129
|
updateQuery: (e, { fetchMoreResult: t }) => ({ planmagnetWorkItems: {
|
|
@@ -132,79 +132,86 @@ function w() {
|
|
|
132
132
|
} })
|
|
133
133
|
});
|
|
134
134
|
} finally {
|
|
135
|
-
|
|
135
|
+
z(!1);
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
138
|
};
|
|
139
|
-
if (
|
|
139
|
+
if (V && !B) return /* @__PURE__ */ f("div", {
|
|
140
140
|
className: "flex items-center justify-center p-12",
|
|
141
|
-
children: /* @__PURE__ */
|
|
141
|
+
children: /* @__PURE__ */ f("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
|
|
142
142
|
});
|
|
143
|
-
if (
|
|
143
|
+
if (H) return /* @__PURE__ */ p("div", {
|
|
144
144
|
className: "p-6 text-red-500",
|
|
145
|
-
children: ["Error: ",
|
|
145
|
+
children: ["Error: ", H.message]
|
|
146
146
|
});
|
|
147
|
-
let
|
|
148
|
-
return /* @__PURE__ */
|
|
147
|
+
let K = B?.planmagnetWorkItems?.items ?? [], q = W?.planmagnetWorkItemCounts, J = q?.total ?? (F ? void 0 : B?.planmagnetWorkItems?.totalCount), Y = (e) => q?.byStatus.find((t) => t.status === e)?.count ?? K.filter((t) => t.status === e).length, X = B?.planmagnetWorkItems?.pageInfo?.hasNextPage ?? !1;
|
|
148
|
+
return /* @__PURE__ */ p("div", {
|
|
149
149
|
className: "space-y-4 p-6",
|
|
150
|
-
children: [/* @__PURE__ */
|
|
150
|
+
children: [/* @__PURE__ */ f("div", {
|
|
151
151
|
className: "flex items-center justify-between",
|
|
152
|
-
children: /* @__PURE__ */
|
|
153
|
-
/* @__PURE__ */
|
|
152
|
+
children: /* @__PURE__ */ p("div", { children: [
|
|
153
|
+
/* @__PURE__ */ f("h1", {
|
|
154
154
|
className: "text-2xl font-semibold",
|
|
155
155
|
children: "Task Board"
|
|
156
156
|
}),
|
|
157
|
-
/* @__PURE__ */
|
|
157
|
+
/* @__PURE__ */ f("label", {
|
|
158
158
|
className: "sr-only",
|
|
159
159
|
htmlFor: "task-board-project",
|
|
160
160
|
children: "Project"
|
|
161
161
|
}),
|
|
162
|
-
/* @__PURE__ */
|
|
162
|
+
/* @__PURE__ */ p("select", {
|
|
163
163
|
id: "task-board-project",
|
|
164
164
|
className: "mt-2 rounded-md border border-input bg-background px-2 py-1 text-sm",
|
|
165
|
-
value:
|
|
166
|
-
onChange: (e) =>
|
|
167
|
-
children: [
|
|
165
|
+
value: F,
|
|
166
|
+
onChange: (e) => M(e.target.value),
|
|
167
|
+
children: [P.map((e) => /* @__PURE__ */ f("option", {
|
|
168
168
|
value: e.id,
|
|
169
169
|
children: e.name
|
|
170
|
-
}, e.id)), /* @__PURE__ */
|
|
170
|
+
}, e.id)), /* @__PURE__ */ f("option", {
|
|
171
171
|
value: "",
|
|
172
172
|
children: "All projects — status overview"
|
|
173
173
|
})]
|
|
174
174
|
}),
|
|
175
|
-
/* @__PURE__ */
|
|
176
|
-
className: "mt-2",
|
|
177
|
-
children: /* @__PURE__ */
|
|
175
|
+
/* @__PURE__ */ p("div", {
|
|
176
|
+
className: "mt-2 flex flex-wrap gap-2",
|
|
177
|
+
children: [/* @__PURE__ */ f(a, { projectId: F || void 0 }), /* @__PURE__ */ p(m, {
|
|
178
|
+
size: "sm",
|
|
179
|
+
variant: "outline",
|
|
180
|
+
"data-testid": "import-linear",
|
|
181
|
+
onClick: () => E("/tasks/import-page"),
|
|
182
|
+
children: [/* @__PURE__ */ f(s, { className: "mr-1 h-4 w-4" }), "Import from Linear"]
|
|
183
|
+
})]
|
|
178
184
|
}),
|
|
179
|
-
/* @__PURE__ */
|
|
185
|
+
/* @__PURE__ */ f("p", {
|
|
180
186
|
className: "text-sm text-muted-foreground",
|
|
181
187
|
"data-testid": "task-board-total",
|
|
182
|
-
children:
|
|
188
|
+
children: J === void 0 ? "Counting tasks…" : F ? `${J} ${J === 1 ? "task" : "tasks"} in ${I}` : `${J} tasks across all projects${K.length < J ? ` · showing ${K.length}` : ""}`
|
|
183
189
|
})
|
|
184
190
|
] })
|
|
185
|
-
}),
|
|
186
|
-
projectId:
|
|
187
|
-
projectName:
|
|
188
|
-
}) : /* @__PURE__ */
|
|
189
|
-
/* @__PURE__ */
|
|
191
|
+
}), F ? /* @__PURE__ */ f(i, {
|
|
192
|
+
projectId: F,
|
|
193
|
+
projectName: I
|
|
194
|
+
}) : /* @__PURE__ */ p(d, { children: [
|
|
195
|
+
/* @__PURE__ */ p("div", {
|
|
190
196
|
className: "flex gap-4 items-center flex-wrap",
|
|
191
197
|
children: [
|
|
192
|
-
/* @__PURE__ */
|
|
193
|
-
/* @__PURE__ */
|
|
198
|
+
/* @__PURE__ */ f(c, { className: "h-4 w-4 text-muted-foreground" }),
|
|
199
|
+
/* @__PURE__ */ f("div", {
|
|
194
200
|
className: "flex gap-1",
|
|
195
201
|
children: [
|
|
196
202
|
"all",
|
|
203
|
+
"none",
|
|
197
204
|
"low",
|
|
198
205
|
"medium",
|
|
199
206
|
"high",
|
|
200
207
|
"critical"
|
|
201
|
-
].map((e) => /* @__PURE__ */
|
|
202
|
-
onClick: () =>
|
|
203
|
-
className: `px-2 py-1 text-xs rounded capitalize ${
|
|
208
|
+
].map((e) => /* @__PURE__ */ f("button", {
|
|
209
|
+
onClick: () => O(e),
|
|
210
|
+
className: `px-2 py-1 text-xs rounded capitalize ${D === e ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground"}`,
|
|
204
211
|
children: e
|
|
205
212
|
}, e))
|
|
206
213
|
}),
|
|
207
|
-
/* @__PURE__ */
|
|
214
|
+
/* @__PURE__ */ f("div", {
|
|
208
215
|
className: "flex gap-1",
|
|
209
216
|
children: [
|
|
210
217
|
"all",
|
|
@@ -213,77 +220,77 @@ function w() {
|
|
|
213
220
|
"task",
|
|
214
221
|
"epic",
|
|
215
222
|
"sub_task"
|
|
216
|
-
].map((e) => /* @__PURE__ */
|
|
217
|
-
onClick: () =>
|
|
218
|
-
className: `px-2 py-1 text-xs rounded capitalize ${
|
|
223
|
+
].map((e) => /* @__PURE__ */ f("button", {
|
|
224
|
+
onClick: () => A(e),
|
|
225
|
+
className: `px-2 py-1 text-xs rounded capitalize ${k === e ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground"}`,
|
|
219
226
|
children: e === "sub_task" ? "sub-task" : e
|
|
220
227
|
}, e))
|
|
221
228
|
})
|
|
222
229
|
]
|
|
223
230
|
}),
|
|
224
|
-
/* @__PURE__ */
|
|
231
|
+
/* @__PURE__ */ f("div", {
|
|
225
232
|
className: "grid grid-cols-7 gap-3 overflow-x-auto",
|
|
226
|
-
children:
|
|
227
|
-
let t =
|
|
228
|
-
return /* @__PURE__ */
|
|
233
|
+
children: x.map((e) => {
|
|
234
|
+
let t = K.filter((t) => t.status === e);
|
|
235
|
+
return /* @__PURE__ */ p("div", {
|
|
229
236
|
className: "min-w-[200px]",
|
|
230
|
-
children: [/* @__PURE__ */
|
|
231
|
-
className: `border-t-2 ${
|
|
232
|
-
children: /* @__PURE__ */
|
|
237
|
+
children: [/* @__PURE__ */ f("div", {
|
|
238
|
+
className: `border-t-2 ${C[e]} rounded-t-md p-2 bg-muted/50`,
|
|
239
|
+
children: /* @__PURE__ */ p("div", {
|
|
233
240
|
className: "flex justify-between items-center",
|
|
234
|
-
children: [/* @__PURE__ */
|
|
241
|
+
children: [/* @__PURE__ */ f("span", {
|
|
235
242
|
className: "text-sm font-medium",
|
|
236
|
-
children:
|
|
237
|
-
}), /* @__PURE__ */
|
|
243
|
+
children: S[e]
|
|
244
|
+
}), /* @__PURE__ */ f("span", {
|
|
238
245
|
className: "text-xs bg-muted rounded-full px-1.5",
|
|
239
246
|
"data-testid": `task-col-count-${e}`,
|
|
240
|
-
children:
|
|
247
|
+
children: Y(e)
|
|
241
248
|
})]
|
|
242
249
|
})
|
|
243
|
-
}), /* @__PURE__ */
|
|
250
|
+
}), /* @__PURE__ */ f("div", {
|
|
244
251
|
className: "space-y-2 mt-2",
|
|
245
|
-
children: t.map((e) => /* @__PURE__ */
|
|
246
|
-
...r(() =>
|
|
247
|
-
children: /* @__PURE__ */
|
|
252
|
+
children: t.map((e) => /* @__PURE__ */ f(h, {
|
|
253
|
+
...r(() => E(`/tasks/task-detail-page?taskId=${encodeURIComponent(e.id)}`), e.title),
|
|
254
|
+
children: /* @__PURE__ */ p(g, {
|
|
248
255
|
className: "p-3 space-y-2",
|
|
249
256
|
children: [
|
|
250
|
-
/* @__PURE__ */
|
|
257
|
+
/* @__PURE__ */ f("p", {
|
|
251
258
|
className: "text-sm font-medium leading-tight",
|
|
252
259
|
children: e.title
|
|
253
260
|
}),
|
|
254
|
-
/* @__PURE__ */
|
|
261
|
+
/* @__PURE__ */ f("p", {
|
|
255
262
|
className: "text-xs text-muted-foreground",
|
|
256
263
|
children: e.key
|
|
257
264
|
}),
|
|
258
|
-
/* @__PURE__ */
|
|
265
|
+
/* @__PURE__ */ p("div", {
|
|
259
266
|
className: "flex gap-1 flex-wrap",
|
|
260
|
-
children: [/* @__PURE__ */
|
|
261
|
-
className: `text-[10px] px-1.5 py-0.5 rounded-full capitalize ${
|
|
267
|
+
children: [/* @__PURE__ */ f("span", {
|
|
268
|
+
className: `text-[10px] px-1.5 py-0.5 rounded-full capitalize ${w[e.priority] ?? ""}`,
|
|
262
269
|
children: e.priority.toLowerCase()
|
|
263
|
-
}), /* @__PURE__ */
|
|
264
|
-
className: `text-[10px] px-1.5 py-0.5 rounded-full capitalize ${
|
|
270
|
+
}), /* @__PURE__ */ f("span", {
|
|
271
|
+
className: `text-[10px] px-1.5 py-0.5 rounded-full capitalize ${T[e.type] ?? ""}`,
|
|
265
272
|
children: e.type.toLowerCase()
|
|
266
273
|
})]
|
|
267
274
|
}),
|
|
268
|
-
/* @__PURE__ */
|
|
275
|
+
/* @__PURE__ */ p("div", {
|
|
269
276
|
className: "flex items-center justify-between",
|
|
270
|
-
children: [/* @__PURE__ */
|
|
277
|
+
children: [/* @__PURE__ */ f("div", {
|
|
271
278
|
className: "flex gap-1",
|
|
272
|
-
children: (e.labels ?? []).slice(0, 2).map((e) => /* @__PURE__ */
|
|
279
|
+
children: (e.labels ?? []).slice(0, 2).map((e) => /* @__PURE__ */ f("span", {
|
|
273
280
|
className: "text-[9px] px-1 py-0.5 rounded bg-muted",
|
|
274
281
|
children: e
|
|
275
282
|
}, e))
|
|
276
|
-
}), /* @__PURE__ */
|
|
283
|
+
}), /* @__PURE__ */ f("div", {
|
|
277
284
|
className: "flex items-center gap-1",
|
|
278
|
-
children: /* @__PURE__ */
|
|
285
|
+
children: /* @__PURE__ */ f("span", {
|
|
279
286
|
className: "text-[10px] font-medium bg-primary/10 text-primary rounded-full h-5 w-5 flex items-center justify-center",
|
|
280
287
|
children: e.storyPoints ?? 0
|
|
281
288
|
})
|
|
282
289
|
})]
|
|
283
290
|
}),
|
|
284
|
-
/* @__PURE__ */
|
|
291
|
+
/* @__PURE__ */ p("div", {
|
|
285
292
|
className: "flex justify-between text-[10px] text-muted-foreground",
|
|
286
|
-
children: [/* @__PURE__ */
|
|
293
|
+
children: [/* @__PURE__ */ f("span", { children: e.assigneeId ? /* @__PURE__ */ f(n, { id: e.assigneeId }) : "Unassigned" }), /* @__PURE__ */ f("span", { children: e.dueDate ? new Date(e.dueDate).toLocaleDateString() : "" })]
|
|
287
294
|
})
|
|
288
295
|
]
|
|
289
296
|
})
|
|
@@ -292,21 +299,21 @@ function w() {
|
|
|
292
299
|
}, e);
|
|
293
300
|
})
|
|
294
301
|
}),
|
|
295
|
-
|
|
302
|
+
X && /* @__PURE__ */ f("div", {
|
|
296
303
|
className: "flex justify-center",
|
|
297
|
-
children: /* @__PURE__ */
|
|
304
|
+
children: /* @__PURE__ */ f("button", {
|
|
298
305
|
type: "button",
|
|
299
|
-
onClick:
|
|
300
|
-
disabled:
|
|
306
|
+
onClick: G,
|
|
307
|
+
disabled: R,
|
|
301
308
|
className: "px-3 py-1.5 text-sm rounded-md bg-muted text-foreground hover:bg-muted/80 disabled:opacity-50",
|
|
302
309
|
"data-testid": "task-board-load-more",
|
|
303
|
-
children:
|
|
310
|
+
children: R ? "Loading…" : `Load more (${K.length} of ${J})`
|
|
304
311
|
})
|
|
305
312
|
})
|
|
306
313
|
] })]
|
|
307
314
|
});
|
|
308
315
|
}
|
|
309
316
|
//#endregion
|
|
310
|
-
export {
|
|
317
|
+
export { E as TasksTasksPagePage };
|
|
311
318
|
|
|
312
319
|
//# sourceMappingURL=TasksTasksPagePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TasksTasksPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/TasksTasksPagePage.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 } from '@burdenoff/fe-libs/ui';\nimport { Filter } from 'lucide-react';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { rowLinkProps } from '../utils/rowNavigation';\nimport { PersonName } from '../people/People';\nimport { ProjectBoard } from '../board/ProjectBoard';\nimport { ExportWorkItemsButton } from '../export/ExportWorkItemsButton';\n\nconst GET_WORK_ITEMS = gql`\n query GetWorkItems(\n $workspaceId: ID!\n $filter: PlanmagnetWorkItemFilter\n $pagination: PlanmagnetPaginationInput\n ) {\n planmagnetWorkItems(workspaceId: $workspaceId, filter: $filter, pagination: $pagination) {\n items {\n id\n title\n type\n status\n priority\n key\n assigneeId\n reporterId\n sprintId\n storyPoints\n estimateMinutes\n dueDate\n labels\n tags\n createdAt\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n totalCount\n }\n }\n`;\n\n// Server-side counts (QA H2): the list returns at most 100 rows per page, so\n// counting the loaded page undercounted every workspace past 100 items.\nconst GET_WORK_ITEM_COUNTS = gql`\n query GetWorkItemCounts($workspaceId: ID!, $filter: PlanmagnetWorkItemFilter) {\n planmagnetWorkItemCounts(workspaceId: $workspaceId, filter: $filter) {\n total\n byStatus {\n status\n count\n }\n }\n }\n`;\n\nconst PAGE_SIZE = 100;\n\nconst GET_BOARD_PROJECTS = gql`\n query GetBoardProjects($workspaceId: ID!) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n }\n }\n }\n`;\n\ninterface WorkItemNode {\n id: string;\n title: string;\n type: string;\n status: string;\n priority: string;\n key: string;\n assigneeId: string | null;\n reporterId: string | null;\n sprintId: string | null;\n storyPoints: number | null;\n estimateMinutes: number | null;\n dueDate: string | null;\n labels: string[];\n tags: string[];\n createdAt: string;\n}\n\nconst columns = [\n 'BACKLOG',\n 'TODO',\n 'IN_PROGRESS',\n 'IN_REVIEW',\n 'TESTING',\n 'DONE',\n 'CANCELLED',\n] as const;\n\nconst colLabel: Record<string, string> = {\n BACKLOG: 'Backlog',\n TODO: 'To Do',\n IN_PROGRESS: 'In Progress',\n IN_REVIEW: 'In Review',\n TESTING: 'Testing',\n DONE: 'Done',\n CANCELLED: 'Cancelled',\n};\n\nconst colColor: Record<string, string> = {\n BACKLOG: 'border-t-gray-400',\n TODO: 'border-t-blue-400',\n IN_PROGRESS: 'border-t-yellow-400',\n IN_REVIEW: 'border-t-purple-400',\n TESTING: 'border-t-teal-400',\n DONE: 'border-t-green-400',\n CANCELLED: 'border-t-muted-foreground',\n};\n\nconst priorityColor: Record<string, string> = {\n LOW: 'bg-gray-100 text-gray-700',\n MEDIUM: 'bg-blue-100 text-blue-700',\n HIGH: 'bg-orange-100 text-orange-700',\n CRITICAL: 'bg-red-100 text-red-700',\n};\n\nconst typeColor: Record<string, string> = {\n STORY: 'bg-green-100 text-green-700',\n BUG: 'bg-red-100 text-red-700',\n TASK: 'bg-blue-100 text-blue-700',\n EPIC: 'bg-purple-100 text-purple-700',\n // The API serves SUB_TASK (the stored SUBTASK is mapped by the service), so the old SUBTASK key never matched.\n SUB_TASK: 'bg-gray-100 text-gray-700',\n};\n\nexport function TasksTasksPagePage() {\n const { workspaceId } = usePlanMagnet();\n const navigate = usePlanMagnetNavigate();\n const [priorityFilter, setPriorityFilter] = useState<string>('all');\n const [typeFilter, setTypeFilter] = useState<string>('all');\n // P1.2: the Task Board is a project's real board (server-side placement,\n // drag-and-drop, WIP limits). null = not chosen yet -> the first project;\n // '' = the cross-project status overview, which is NOT a board.\n const [boardProject, setBoardProject] = useState<string | null>(null);\n const { data: projectsData } = useQuery(GET_BOARD_PROJECTS, {\n variables: { workspaceId },\n skip: !workspaceId,\n });\n const boardProjects = projectsData?.planmagnetProjects?.items ?? [];\n const selectedProject = boardProject ?? boardProjects[0]?.id ?? '';\n const selectedProjectName = boardProjects.find((p) => p.id === selectedProject)?.name ?? '';\n\n // Filters go to the server so the loaded items AND the counts both reflect\n // every matching item, not just the first page.\n const filter = {\n ...(priorityFilter !== 'all' && { priority: priorityFilter.toUpperCase() }),\n ...(typeFilter !== 'all' && { type: typeFilter.toUpperCase() }),\n };\n const [loadingMore, setLoadingMore] = useState(false);\n\n const { data, loading, error, fetchMore } = useQuery<{\n planmagnetWorkItems: {\n items: WorkItemNode[];\n pageInfo: { hasNextPage: boolean; endCursor: string | null };\n totalCount: number;\n };\n }>(GET_WORK_ITEMS, {\n variables: { workspaceId, filter, pagination: { first: PAGE_SIZE } },\n // The list only feeds the cross-project overview; a board loads its own cards.\n skip: !workspaceId || !!selectedProject,\n });\n const { data: countsData } = useQuery<{\n planmagnetWorkItemCounts: { total: number; byStatus: { status: string; count: number }[] };\n }>(GET_WORK_ITEM_COUNTS, {\n // On a project board the header counts THAT project, without the overview's priority/type filters (their\n // buttons are hidden there, but their state survived and silently narrowed the count). It used to count the\n // whole workspace above a single project's board (BOFF-7943).\n variables: { workspaceId, filter: selectedProject ? { projectId: selectedProject } : filter },\n skip: !workspaceId,\n });\n\n const loadMore = async () => {\n const after = data?.planmagnetWorkItems?.pageInfo?.endCursor;\n if (!after) return;\n setLoadingMore(true);\n try {\n await fetchMore({\n variables: { pagination: { first: PAGE_SIZE, after } },\n updateQuery: (prev, { fetchMoreResult }) => ({\n planmagnetWorkItems: {\n ...fetchMoreResult.planmagnetWorkItems,\n items: [\n ...prev.planmagnetWorkItems.items,\n ...fetchMoreResult.planmagnetWorkItems.items,\n ],\n },\n }),\n });\n } finally {\n setLoadingMore(false);\n }\n };\n\n // Only before the first load: a refetch or a filter change must not blank the board.\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 tasks = data?.planmagnetWorkItems?.items ?? [];\n\n const counts = countsData?.planmagnetWorkItemCounts;\n // Never fall back to the loaded page's length: on a board nothing is loaded here, so that read \"0 tasks\".\n const total: number | undefined =\n counts?.total ?? (selectedProject ? undefined : data?.planmagnetWorkItems?.totalCount);\n const countFor = (status: string) =>\n counts?.byStatus.find((c) => c.status === status)?.count ??\n tasks.filter((t) => t.status === status).length;\n const hasMore = data?.planmagnetWorkItems?.pageInfo?.hasNextPage ?? false;\n\n return (\n <div className=\"space-y-4 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Task Board</h1>\n <label className=\"sr-only\" htmlFor=\"task-board-project\">\n Project\n </label>\n <select\n id=\"task-board-project\"\n className=\"mt-2 rounded-md border border-input bg-background px-2 py-1 text-sm\"\n value={selectedProject}\n onChange={(e) => setBoardProject(e.target.value)}\n >\n {boardProjects.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n <option value=\"\">All projects — status overview</option>\n </select>\n <div className=\"mt-2\">\n <ExportWorkItemsButton projectId={selectedProject || undefined} />\n </div>\n <p className=\"text-sm text-muted-foreground\" data-testid=\"task-board-total\">\n {total === undefined\n ? 'Counting tasks…'\n : selectedProject\n ? `${total} ${total === 1 ? 'task' : 'tasks'} in ${selectedProjectName}`\n : `${total} tasks across all projects${tasks.length < total ? ` · showing ${tasks.length}` : ''}`}\n </p>\n </div>\n </div>\n {selectedProject ? (\n <ProjectBoard projectId={selectedProject} projectName={selectedProjectName} />\n ) : (\n <>\n <div className=\"flex gap-4 items-center flex-wrap\">\n <Filter className=\"h-4 w-4 text-muted-foreground\" />\n <div className=\"flex gap-1\">\n {['all', 'low', 'medium', 'high', 'critical'].map((p) => (\n <button\n key={p}\n onClick={() => setPriorityFilter(p)}\n className={`px-2 py-1 text-xs rounded capitalize ${priorityFilter === p ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'}`}\n >\n {p}\n </button>\n ))}\n </div>\n <div className=\"flex gap-1\">\n {/* sub_task → SUB_TASK: filtering by it works since svc 1f4db8e (it was a masked 500). */}\n {['all', 'story', 'bug', 'task', 'epic', 'sub_task'].map((t) => (\n <button\n key={t}\n onClick={() => setTypeFilter(t)}\n className={`px-2 py-1 text-xs rounded capitalize ${typeFilter === t ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'}`}\n >\n {t === 'sub_task' ? 'sub-task' : t}\n </button>\n ))}\n </div>\n </div>\n <div className=\"grid grid-cols-7 gap-3 overflow-x-auto\">\n {columns.map((col) => {\n const colTasks = tasks.filter((t) => t.status === col);\n return (\n <div key={col} className=\"min-w-[200px]\">\n <div className={`border-t-2 ${colColor[col]} rounded-t-md p-2 bg-muted/50`}>\n <div className=\"flex justify-between items-center\">\n <span className=\"text-sm font-medium\">{colLabel[col]}</span>\n <span\n className=\"text-xs bg-muted rounded-full px-1.5\"\n data-testid={`task-col-count-${col}`}\n >\n {countFor(col)}\n </span>\n </div>\n </div>\n <div className=\"space-y-2 mt-2\">\n {colTasks.map((task) => (\n <Card\n key={task.id}\n {...rowLinkProps(\n () =>\n navigate(\n `/tasks/task-detail-page?taskId=${encodeURIComponent(task.id)}`\n ),\n task.title\n )}\n >\n <CardContent className=\"p-3 space-y-2\">\n <p className=\"text-sm font-medium leading-tight\">{task.title}</p>\n <p className=\"text-xs text-muted-foreground\">{task.key}</p>\n <div className=\"flex gap-1 flex-wrap\">\n <span\n className={`text-[10px] px-1.5 py-0.5 rounded-full capitalize ${priorityColor[task.priority] ?? ''}`}\n >\n {task.priority.toLowerCase()}\n </span>\n <span\n className={`text-[10px] px-1.5 py-0.5 rounded-full capitalize ${typeColor[task.type] ?? ''}`}\n >\n {task.type.toLowerCase()}\n </span>\n </div>\n <div className=\"flex items-center justify-between\">\n <div className=\"flex gap-1\">\n {(task.labels ?? []).slice(0, 2).map((l) => (\n <span key={l} className=\"text-[9px] px-1 py-0.5 rounded bg-muted\">\n {l}\n </span>\n ))}\n </div>\n <div className=\"flex items-center gap-1\">\n <span className=\"text-[10px] font-medium bg-primary/10 text-primary rounded-full h-5 w-5 flex items-center justify-center\">\n {task.storyPoints ?? 0}\n </span>\n </div>\n </div>\n <div className=\"flex justify-between text-[10px] text-muted-foreground\">\n <span>\n {task.assigneeId ? <PersonName id={task.assigneeId} /> : 'Unassigned'}\n </span>\n <span>\n {task.dueDate ? new Date(task.dueDate).toLocaleDateString() : ''}\n </span>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n </div>\n );\n })}\n </div>\n {hasMore && (\n <div className=\"flex justify-center\">\n <button\n type=\"button\"\n onClick={loadMore}\n disabled={loadingMore}\n className=\"px-3 py-1.5 text-sm rounded-md bg-muted text-foreground hover:bg-muted/80 disabled:opacity-50\"\n data-testid=\"task-board-load-more\"\n >\n {loadingMore ? 'Loading…' : `Load more (${tasks.length} of ${total})`}\n </button>\n </div>\n )}\n </>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TasksTasksPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/TasksTasksPagePage.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 { Button, Card, CardContent } from '@burdenoff/fe-libs/ui';\nimport { FileUp, Filter } from 'lucide-react';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { rowLinkProps } from '../utils/rowNavigation';\nimport { PersonName } from '../people/People';\nimport { ProjectBoard } from '../board/ProjectBoard';\nimport { ExportWorkItemsButton } from '../export/ExportWorkItemsButton';\n\nconst GET_WORK_ITEMS = gql`\n query GetWorkItems(\n $workspaceId: ID!\n $filter: PlanmagnetWorkItemFilter\n $pagination: PlanmagnetPaginationInput\n ) {\n planmagnetWorkItems(workspaceId: $workspaceId, filter: $filter, pagination: $pagination) {\n items {\n id\n title\n type\n status\n priority\n key\n assigneeId\n reporterId\n sprintId\n storyPoints\n estimateMinutes\n dueDate\n labels\n tags\n createdAt\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n totalCount\n }\n }\n`;\n\n// Server-side counts (QA H2): the list returns at most 100 rows per page, so\n// counting the loaded page undercounted every workspace past 100 items.\nconst GET_WORK_ITEM_COUNTS = gql`\n query GetWorkItemCounts($workspaceId: ID!, $filter: PlanmagnetWorkItemFilter) {\n planmagnetWorkItemCounts(workspaceId: $workspaceId, filter: $filter) {\n total\n byStatus {\n status\n count\n }\n }\n }\n`;\n\nconst PAGE_SIZE = 100;\n\nconst GET_BOARD_PROJECTS = gql`\n query GetBoardProjects($workspaceId: ID!) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n }\n }\n }\n`;\n\ninterface WorkItemNode {\n id: string;\n title: string;\n type: string;\n status: string;\n priority: string;\n key: string;\n assigneeId: string | null;\n reporterId: string | null;\n sprintId: string | null;\n storyPoints: number | null;\n estimateMinutes: number | null;\n dueDate: string | null;\n labels: string[];\n tags: string[];\n createdAt: string;\n}\n\nconst columns = [\n 'BACKLOG',\n 'TODO',\n 'IN_PROGRESS',\n 'IN_REVIEW',\n 'TESTING',\n 'DONE',\n 'CANCELLED',\n] as const;\n\nconst colLabel: Record<string, string> = {\n BACKLOG: 'Backlog',\n TODO: 'To Do',\n IN_PROGRESS: 'In Progress',\n IN_REVIEW: 'In Review',\n TESTING: 'Testing',\n DONE: 'Done',\n CANCELLED: 'Cancelled',\n};\n\nconst colColor: Record<string, string> = {\n BACKLOG: 'border-t-gray-400',\n TODO: 'border-t-blue-400',\n IN_PROGRESS: 'border-t-yellow-400',\n IN_REVIEW: 'border-t-purple-400',\n TESTING: 'border-t-teal-400',\n DONE: 'border-t-green-400',\n CANCELLED: 'border-t-muted-foreground',\n};\n\nconst priorityColor: Record<string, string> = {\n LOW: 'bg-gray-100 text-gray-700',\n MEDIUM: 'bg-blue-100 text-blue-700',\n HIGH: 'bg-orange-100 text-orange-700',\n CRITICAL: 'bg-red-100 text-red-700',\n};\n\nconst typeColor: Record<string, string> = {\n STORY: 'bg-green-100 text-green-700',\n BUG: 'bg-red-100 text-red-700',\n TASK: 'bg-blue-100 text-blue-700',\n EPIC: 'bg-purple-100 text-purple-700',\n // The API serves SUB_TASK (the stored SUBTASK is mapped by the service), so the old SUBTASK key never matched.\n SUB_TASK: 'bg-gray-100 text-gray-700',\n};\n\nexport function TasksTasksPagePage() {\n const { workspaceId } = usePlanMagnet();\n const navigate = usePlanMagnetNavigate();\n const [priorityFilter, setPriorityFilter] = useState<string>('all');\n const [typeFilter, setTypeFilter] = useState<string>('all');\n // P1.2: the Task Board is a project's real board (server-side placement,\n // drag-and-drop, WIP limits). null = not chosen yet -> the first project;\n // '' = the cross-project status overview, which is NOT a board.\n const [boardProject, setBoardProject] = useState<string | null>(null);\n const { data: projectsData } = useQuery(GET_BOARD_PROJECTS, {\n variables: { workspaceId },\n skip: !workspaceId,\n });\n const boardProjects = projectsData?.planmagnetProjects?.items ?? [];\n const selectedProject = boardProject ?? boardProjects[0]?.id ?? '';\n const selectedProjectName = boardProjects.find((p) => p.id === selectedProject)?.name ?? '';\n\n // Filters go to the server so the loaded items AND the counts both reflect\n // every matching item, not just the first page.\n const filter = {\n ...(priorityFilter !== 'all' && { priority: priorityFilter.toUpperCase() }),\n ...(typeFilter !== 'all' && { type: typeFilter.toUpperCase() }),\n };\n const [loadingMore, setLoadingMore] = useState(false);\n\n const { data, loading, error, fetchMore } = useQuery<{\n planmagnetWorkItems: {\n items: WorkItemNode[];\n pageInfo: { hasNextPage: boolean; endCursor: string | null };\n totalCount: number;\n };\n }>(GET_WORK_ITEMS, {\n variables: { workspaceId, filter, pagination: { first: PAGE_SIZE } },\n // The list only feeds the cross-project overview; a board loads its own cards.\n skip: !workspaceId || !!selectedProject,\n });\n const { data: countsData } = useQuery<{\n planmagnetWorkItemCounts: { total: number; byStatus: { status: string; count: number }[] };\n }>(GET_WORK_ITEM_COUNTS, {\n // On a project board the header counts THAT project, without the overview's priority/type filters (their\n // buttons are hidden there, but their state survived and silently narrowed the count). It used to count the\n // whole workspace above a single project's board (BOFF-7943).\n variables: { workspaceId, filter: selectedProject ? { projectId: selectedProject } : filter },\n skip: !workspaceId,\n });\n\n const loadMore = async () => {\n const after = data?.planmagnetWorkItems?.pageInfo?.endCursor;\n if (!after) return;\n setLoadingMore(true);\n try {\n await fetchMore({\n variables: { pagination: { first: PAGE_SIZE, after } },\n updateQuery: (prev, { fetchMoreResult }) => ({\n planmagnetWorkItems: {\n ...fetchMoreResult.planmagnetWorkItems,\n items: [\n ...prev.planmagnetWorkItems.items,\n ...fetchMoreResult.planmagnetWorkItems.items,\n ],\n },\n }),\n });\n } finally {\n setLoadingMore(false);\n }\n };\n\n // Only before the first load: a refetch or a filter change must not blank the board.\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 tasks = data?.planmagnetWorkItems?.items ?? [];\n\n const counts = countsData?.planmagnetWorkItemCounts;\n // Never fall back to the loaded page's length: on a board nothing is loaded here, so that read \"0 tasks\".\n const total: number | undefined =\n counts?.total ?? (selectedProject ? undefined : data?.planmagnetWorkItems?.totalCount);\n const countFor = (status: string) =>\n counts?.byStatus.find((c) => c.status === status)?.count ??\n tasks.filter((t) => t.status === status).length;\n const hasMore = data?.planmagnetWorkItems?.pageInfo?.hasNextPage ?? false;\n\n return (\n <div className=\"space-y-4 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Task Board</h1>\n <label className=\"sr-only\" htmlFor=\"task-board-project\">\n Project\n </label>\n <select\n id=\"task-board-project\"\n className=\"mt-2 rounded-md border border-input bg-background px-2 py-1 text-sm\"\n value={selectedProject}\n onChange={(e) => setBoardProject(e.target.value)}\n >\n {boardProjects.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n <option value=\"\">All projects — status overview</option>\n </select>\n <div className=\"mt-2 flex flex-wrap gap-2\">\n <ExportWorkItemsButton projectId={selectedProject || undefined} />\n {/* BUILD_PLAN P1.4: the Linear importer had no way in. */}\n <Button\n size=\"sm\"\n variant=\"outline\"\n data-testid=\"import-linear\"\n onClick={() => navigate('/tasks/import-page')}\n >\n <FileUp className=\"mr-1 h-4 w-4\" />\n Import from Linear\n </Button>\n </div>\n <p className=\"text-sm text-muted-foreground\" data-testid=\"task-board-total\">\n {total === undefined\n ? 'Counting tasks…'\n : selectedProject\n ? `${total} ${total === 1 ? 'task' : 'tasks'} in ${selectedProjectName}`\n : `${total} tasks across all projects${tasks.length < total ? ` · showing ${tasks.length}` : ''}`}\n </p>\n </div>\n </div>\n {selectedProject ? (\n <ProjectBoard projectId={selectedProject} projectName={selectedProjectName} />\n ) : (\n <>\n <div className=\"flex gap-4 items-center flex-wrap\">\n <Filter className=\"h-4 w-4 text-muted-foreground\" />\n <div className=\"flex gap-1\">\n {/* 'none' included: a NONE-priority task matched no chip (BOFF-7985). */}\n {['all', 'none', 'low', 'medium', 'high', 'critical'].map((p) => (\n <button\n key={p}\n onClick={() => setPriorityFilter(p)}\n className={`px-2 py-1 text-xs rounded capitalize ${priorityFilter === p ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'}`}\n >\n {p}\n </button>\n ))}\n </div>\n <div className=\"flex gap-1\">\n {/* sub_task → SUB_TASK: filtering by it works since svc 1f4db8e (it was a masked 500). */}\n {['all', 'story', 'bug', 'task', 'epic', 'sub_task'].map((t) => (\n <button\n key={t}\n onClick={() => setTypeFilter(t)}\n className={`px-2 py-1 text-xs rounded capitalize ${typeFilter === t ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'}`}\n >\n {t === 'sub_task' ? 'sub-task' : t}\n </button>\n ))}\n </div>\n </div>\n <div className=\"grid grid-cols-7 gap-3 overflow-x-auto\">\n {columns.map((col) => {\n const colTasks = tasks.filter((t) => t.status === col);\n return (\n <div key={col} className=\"min-w-[200px]\">\n <div className={`border-t-2 ${colColor[col]} rounded-t-md p-2 bg-muted/50`}>\n <div className=\"flex justify-between items-center\">\n <span className=\"text-sm font-medium\">{colLabel[col]}</span>\n <span\n className=\"text-xs bg-muted rounded-full px-1.5\"\n data-testid={`task-col-count-${col}`}\n >\n {countFor(col)}\n </span>\n </div>\n </div>\n <div className=\"space-y-2 mt-2\">\n {colTasks.map((task) => (\n <Card\n key={task.id}\n {...rowLinkProps(\n () =>\n navigate(\n `/tasks/task-detail-page?taskId=${encodeURIComponent(task.id)}`\n ),\n task.title\n )}\n >\n <CardContent className=\"p-3 space-y-2\">\n <p className=\"text-sm font-medium leading-tight\">{task.title}</p>\n <p className=\"text-xs text-muted-foreground\">{task.key}</p>\n <div className=\"flex gap-1 flex-wrap\">\n <span\n className={`text-[10px] px-1.5 py-0.5 rounded-full capitalize ${priorityColor[task.priority] ?? ''}`}\n >\n {task.priority.toLowerCase()}\n </span>\n <span\n className={`text-[10px] px-1.5 py-0.5 rounded-full capitalize ${typeColor[task.type] ?? ''}`}\n >\n {task.type.toLowerCase()}\n </span>\n </div>\n <div className=\"flex items-center justify-between\">\n <div className=\"flex gap-1\">\n {(task.labels ?? []).slice(0, 2).map((l) => (\n <span key={l} className=\"text-[9px] px-1 py-0.5 rounded bg-muted\">\n {l}\n </span>\n ))}\n </div>\n <div className=\"flex items-center gap-1\">\n <span className=\"text-[10px] font-medium bg-primary/10 text-primary rounded-full h-5 w-5 flex items-center justify-center\">\n {task.storyPoints ?? 0}\n </span>\n </div>\n </div>\n <div className=\"flex justify-between text-[10px] text-muted-foreground\">\n <span>\n {task.assigneeId ? <PersonName id={task.assigneeId} /> : 'Unassigned'}\n </span>\n <span>\n {task.dueDate ? new Date(task.dueDate).toLocaleDateString() : ''}\n </span>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n </div>\n );\n })}\n </div>\n {hasMore && (\n <div className=\"flex justify-center\">\n <button\n type=\"button\"\n onClick={loadMore}\n disabled={loadingMore}\n className=\"px-3 py-1.5 text-sm rounded-md bg-muted text-foreground hover:bg-muted/80 disabled:opacity-50\"\n data-testid=\"task-board-load-more\"\n >\n {loadingMore ? 'Loading…' : `Load more (${tasks.length} of ${total})`}\n </button>\n </div>\n )}\n </>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamTeamPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/TeamTeamPagePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TeamTeamPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/TeamTeamPagePage.tsx"],"names":[],"mappings":"AAqFA,wBAAgB,gBAAgB,4CAkD/B"}
|