@burdenoff/microfe-planmagnet 2026.927.1 → 2026.927.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/planmagnet/admin/PlanMagnetAdminRoot.d.ts.map +1 -1
- package/dist/planmagnet/admin/PlanMagnetAdminRoot.js +128 -124
- package/dist/planmagnet/admin/PlanMagnetAdminRoot.js.map +1 -1
- package/dist/planmagnet/controls/ConfirmButton.d.ts +25 -0
- package/dist/planmagnet/controls/ConfirmButton.d.ts.map +1 -0
- package/dist/planmagnet/controls/ConfirmButton.js +30 -0
- package/dist/planmagnet/controls/ConfirmButton.js.map +1 -0
- package/dist/planmagnet/controls/ProjectControls.d.ts +13 -0
- package/dist/planmagnet/controls/ProjectControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/ProjectControls.js +104 -0
- package/dist/planmagnet/controls/ProjectControls.js.map +1 -0
- package/dist/planmagnet/controls/WorkItemControls.d.ts +52 -0
- package/dist/planmagnet/controls/WorkItemControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/WorkItemControls.js +198 -0
- package/dist/planmagnet/controls/WorkItemControls.js.map +1 -0
- package/dist/planmagnet/pages/DashboardDashboardPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/DashboardDashboardPagePage.js +14 -4
- package/dist/planmagnet/pages/DashboardDashboardPagePage.js.map +1 -1
- package/dist/planmagnet/pages/DocsDocDetailPagePage.js +4 -4
- package/dist/planmagnet/pages/DocsDocDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/DocsDocsPagePage.js +4 -4
- package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js +102 -100
- 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 +95 -94
- package/dist/planmagnet/pages/ProductsFeaturesPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.js +97 -90
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js +150 -111
- package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsEditProjectPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js +121 -94
- package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.js +84 -73
- package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsMilestonesPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsMilestonesPagePage.js +13 -8
- package/dist/planmagnet/pages/ProjectsMilestonesPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js +129 -125
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.js +112 -109
- package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js +134 -132
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ReportsReportsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ReportsReportsPagePage.js +72 -83
- 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 +109 -108
- package/dist/planmagnet/pages/SprintsStartSprintPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksCreateTaskPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksCreateTaskPagePage.js +167 -111
- 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 +101 -99
- package/dist/planmagnet/pages/TasksEditTaskPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.js +149 -147
- 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 +4 -8
- 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 +68 -69
- package/dist/planmagnet/pages/TeamTeamPagePage.js.map +1 -1
- package/dist/planmagnet/pages/WorkspaceCreateWorkspacePagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/WorkspaceCreateWorkspacePagePage.js +1 -5
- package/dist/planmagnet/pages/WorkspaceCreateWorkspacePagePage.js.map +1 -1
- package/dist/planmagnet/people/People.d.ts +18 -0
- package/dist/planmagnet/people/People.d.ts.map +1 -1
- package/dist/planmagnet/people/People.js +26 -12
- package/dist/planmagnet/people/People.js.map +1 -1
- package/dist/planmagnet/roadmaps/RoadmapControls.d.ts +34 -0
- package/dist/planmagnet/roadmaps/RoadmapControls.d.ts.map +1 -0
- package/dist/planmagnet/roadmaps/RoadmapControls.js +301 -0
- package/dist/planmagnet/roadmaps/RoadmapControls.js.map +1 -0
- package/dist/planmagnet/sprints/SprintControls.d.ts.map +1 -1
- package/dist/planmagnet/sprints/SprintControls.js +194 -215
- package/dist/planmagnet/sprints/SprintControls.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { usePlanMagnet as e, usePlanMagnetNavigate as t } from "../providers/PlanMagnetProvider.js";
|
|
2
|
-
import {
|
|
2
|
+
import { PersonName as n } from "../people/People.js";
|
|
3
3
|
import { throwOnError as r } from "../utils/mutationResult.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
4
|
+
import { MarkdownEditor as i } from "../../components/MarkdownEditor.js";
|
|
5
|
+
import { WORK_ITEM_PRIORITIES as a, WORK_ITEM_STATUSES as o, WorkItemAssigneeSelect as s, WorkItemEnumSelect as c, WorkItemHeaderActions as l } from "../controls/WorkItemControls.js";
|
|
6
|
+
import { WorkItemComments as u } from "../comments/WorkItemComments.js";
|
|
7
|
+
import { WorkItemActivity as d } from "../comments/WorkItemActivity.js";
|
|
8
|
+
import { useState as f } from "react";
|
|
9
|
+
import { FileText as p, Plus as m, X as h } from "lucide-react";
|
|
10
|
+
import { gql as g } from "@apollo/client";
|
|
11
|
+
import { useMutation as _, useQuery as v } from "@apollo/client/react";
|
|
12
|
+
import { jsx as y, jsxs as b } from "react/jsx-runtime";
|
|
13
|
+
import { Badge as x, Button as S, Card as C, CardContent as w, CardHeader as T, CardTitle as E, Input as D } from "@burdenoff/fe-libs/ui";
|
|
12
14
|
//#region src/planmagnet/pages/TasksTaskDetailPagePage.tsx
|
|
13
|
-
var
|
|
15
|
+
var O = g`
|
|
14
16
|
query GetWorkItemDetail($workItemId: ID!) {
|
|
15
17
|
planmagnetWorkItem(id: $workItemId) {
|
|
16
18
|
id
|
|
@@ -22,6 +24,7 @@ var S = u`
|
|
|
22
24
|
key
|
|
23
25
|
assigneeId
|
|
24
26
|
reporterId
|
|
27
|
+
createdBy
|
|
25
28
|
sprintId
|
|
26
29
|
storyPoints
|
|
27
30
|
estimateMinutes
|
|
@@ -32,7 +35,7 @@ var S = u`
|
|
|
32
35
|
updatedAt
|
|
33
36
|
}
|
|
34
37
|
}
|
|
35
|
-
`,
|
|
38
|
+
`, k = g`
|
|
36
39
|
query GetWorkItemDocs($workItemId: ID!) {
|
|
37
40
|
planmagnetWorkItemDocs(workItemId: $workItemId) {
|
|
38
41
|
id
|
|
@@ -42,52 +45,38 @@ var S = u`
|
|
|
42
45
|
updatedAt
|
|
43
46
|
}
|
|
44
47
|
}
|
|
45
|
-
`,
|
|
48
|
+
`, A = g`
|
|
46
49
|
mutation CreateDocForWorkItem($input: PlanmagnetCreateDocInput!) {
|
|
47
50
|
planmagnetCreateDoc(input: $input) {
|
|
48
51
|
id
|
|
49
52
|
}
|
|
50
53
|
}
|
|
51
|
-
`,
|
|
54
|
+
`, j = g`
|
|
52
55
|
mutation LinkDocToWorkItem($docId: ID!, $workItemId: ID!) {
|
|
53
56
|
planmagnetLinkDocToWorkItem(docId: $docId, workItemId: $workItemId) {
|
|
54
57
|
id
|
|
55
58
|
}
|
|
56
59
|
}
|
|
57
|
-
`,
|
|
60
|
+
`, M = g`
|
|
58
61
|
mutation UnlinkDocFromWorkItem($docId: ID!, $workItemId: ID!) {
|
|
59
62
|
planmagnetUnlinkDocFromWorkItem(docId: $docId, workItemId: $workItemId)
|
|
60
63
|
}
|
|
61
|
-
`,
|
|
62
|
-
LOW: "bg-gray-100 text-gray-800",
|
|
63
|
-
MEDIUM: "bg-blue-100 text-blue-800",
|
|
64
|
-
HIGH: "bg-orange-100 text-orange-800",
|
|
65
|
-
CRITICAL: "bg-red-100 text-red-800"
|
|
66
|
-
}, O = {
|
|
67
|
-
BACKLOG: "bg-gray-100 text-gray-800",
|
|
68
|
-
TODO: "bg-blue-100 text-blue-800",
|
|
69
|
-
IN_PROGRESS: "bg-yellow-100 text-yellow-800",
|
|
70
|
-
IN_REVIEW: "bg-purple-100 text-purple-800",
|
|
71
|
-
DONE: "bg-green-100 text-green-800",
|
|
72
|
-
BLOCKED: "bg-red-100 text-red-800",
|
|
73
|
-
TESTING: "bg-teal-100 text-teal-800",
|
|
74
|
-
CANCELLED: "bg-gray-100 text-gray-800"
|
|
75
|
-
}, k = {
|
|
64
|
+
`, N = {
|
|
76
65
|
DRAFT: "bg-gray-100 text-gray-800",
|
|
77
66
|
PUBLISHED: "bg-green-100 text-green-800",
|
|
78
67
|
ARCHIVED: "bg-gray-100 text-gray-500"
|
|
79
68
|
};
|
|
80
|
-
function
|
|
81
|
-
let
|
|
69
|
+
function P({ workItemId: e }) {
|
|
70
|
+
let n = t(), [a, o] = f(!1), [s, c] = f(""), [l, u] = f(""), { data: d, loading: g, error: x, refetch: O } = v(k, {
|
|
82
71
|
variables: { workItemId: e },
|
|
83
72
|
skip: !e
|
|
84
|
-
}), [P, { loading: F }] =
|
|
85
|
-
if (!(!
|
|
73
|
+
}), [P, { loading: F }] = _(A), [I] = _(j), [L, { loading: R }] = _(M), [z, B] = f(null), V = d?.planmagnetWorkItemDocs ?? [], H = async () => {
|
|
74
|
+
if (!(!s.trim() || !l.trim())) {
|
|
86
75
|
B(null);
|
|
87
76
|
try {
|
|
88
77
|
let t = (await r(P({ variables: { input: {
|
|
89
|
-
title:
|
|
90
|
-
content:
|
|
78
|
+
title: s.trim(),
|
|
79
|
+
content: l.trim()
|
|
91
80
|
} } }))).data?.planmagnetCreateDoc?.id;
|
|
92
81
|
t && await r(I({ variables: {
|
|
93
82
|
docId: t,
|
|
@@ -97,7 +86,7 @@ function A({ workItemId: e }) {
|
|
|
97
86
|
B(e instanceof Error ? e.message : "The doc could not be saved.");
|
|
98
87
|
return;
|
|
99
88
|
}
|
|
100
|
-
|
|
89
|
+
c(""), u(""), o(!1), O();
|
|
101
90
|
}
|
|
102
91
|
}, U = async (t) => {
|
|
103
92
|
B(null);
|
|
@@ -110,240 +99,250 @@ function A({ workItemId: e }) {
|
|
|
110
99
|
B(e instanceof Error ? e.message : "The doc could not be unlinked.");
|
|
111
100
|
return;
|
|
112
101
|
}
|
|
113
|
-
|
|
102
|
+
O();
|
|
114
103
|
};
|
|
115
|
-
return /* @__PURE__ */
|
|
104
|
+
return /* @__PURE__ */ b(C, { children: [/* @__PURE__ */ b(T, {
|
|
116
105
|
className: "flex flex-row items-center justify-between space-y-0",
|
|
117
|
-
children: [/* @__PURE__ */
|
|
106
|
+
children: [/* @__PURE__ */ y(E, { children: "Linked Docs" }), !a && /* @__PURE__ */ b(S, {
|
|
118
107
|
size: "sm",
|
|
119
108
|
variant: "outline",
|
|
120
|
-
onClick: () =>
|
|
121
|
-
children: [/* @__PURE__ */
|
|
109
|
+
onClick: () => o(!0),
|
|
110
|
+
children: [/* @__PURE__ */ y(m, { className: "h-4 w-4 mr-1" }), "New Doc"]
|
|
122
111
|
})]
|
|
123
|
-
}), /* @__PURE__ */
|
|
112
|
+
}), /* @__PURE__ */ b(w, {
|
|
124
113
|
className: "space-y-4",
|
|
125
114
|
children: [
|
|
126
|
-
a && /* @__PURE__ */
|
|
115
|
+
a && /* @__PURE__ */ b("div", {
|
|
127
116
|
className: "space-y-3 rounded-md border border-input p-3",
|
|
128
117
|
children: [
|
|
129
|
-
/* @__PURE__ */
|
|
118
|
+
/* @__PURE__ */ y(D, {
|
|
130
119
|
placeholder: "Doc title",
|
|
131
|
-
value:
|
|
132
|
-
onChange: (e) =>
|
|
120
|
+
value: s,
|
|
121
|
+
onChange: (e) => c(e.target.value)
|
|
133
122
|
}),
|
|
134
|
-
/* @__PURE__ */
|
|
135
|
-
value:
|
|
136
|
-
onChange:
|
|
123
|
+
/* @__PURE__ */ y(i, {
|
|
124
|
+
value: l,
|
|
125
|
+
onChange: u,
|
|
137
126
|
placeholder: "Write the spec/doc content...",
|
|
138
127
|
minHeight: 140
|
|
139
128
|
}),
|
|
140
|
-
/* @__PURE__ */
|
|
129
|
+
/* @__PURE__ */ b("div", {
|
|
141
130
|
className: "flex gap-2 justify-end",
|
|
142
|
-
children: [/* @__PURE__ */
|
|
131
|
+
children: [/* @__PURE__ */ y(S, {
|
|
143
132
|
size: "sm",
|
|
144
133
|
variant: "ghost",
|
|
145
134
|
onClick: () => {
|
|
146
|
-
|
|
135
|
+
o(!1), c(""), u("");
|
|
147
136
|
},
|
|
148
137
|
children: "Cancel"
|
|
149
|
-
}), /* @__PURE__ */
|
|
138
|
+
}), /* @__PURE__ */ y(S, {
|
|
150
139
|
size: "sm",
|
|
151
|
-
disabled: F || !
|
|
140
|
+
disabled: F || !s.trim() || !l.trim(),
|
|
152
141
|
onClick: H,
|
|
153
142
|
children: F ? "Creating..." : "Create & Link"
|
|
154
143
|
})]
|
|
155
144
|
})
|
|
156
145
|
]
|
|
157
146
|
}),
|
|
158
|
-
|
|
147
|
+
g && /* @__PURE__ */ y("p", {
|
|
159
148
|
className: "text-sm text-muted-foreground",
|
|
160
149
|
children: "Loading docs..."
|
|
161
150
|
}),
|
|
162
|
-
|
|
151
|
+
x && /* @__PURE__ */ b("p", {
|
|
163
152
|
className: "text-sm text-red-500",
|
|
164
|
-
children: ["Error: ",
|
|
153
|
+
children: ["Error: ", x.message]
|
|
165
154
|
}),
|
|
166
|
-
z && /* @__PURE__ */
|
|
155
|
+
z && /* @__PURE__ */ y("p", {
|
|
167
156
|
role: "alert",
|
|
168
157
|
className: "text-sm text-destructive",
|
|
169
158
|
children: z
|
|
170
159
|
}),
|
|
171
|
-
!
|
|
160
|
+
!g && !x && V.length === 0 && !a && /* @__PURE__ */ y("p", {
|
|
172
161
|
className: "text-sm text-muted-foreground",
|
|
173
162
|
children: "No docs linked to this work item yet."
|
|
174
163
|
}),
|
|
175
|
-
V.map((e) => /* @__PURE__ */
|
|
164
|
+
V.map((e) => /* @__PURE__ */ b("div", {
|
|
176
165
|
className: "flex items-center justify-between gap-3 rounded-md border border-input p-3",
|
|
177
|
-
children: [/* @__PURE__ */
|
|
166
|
+
children: [/* @__PURE__ */ b("div", {
|
|
178
167
|
className: "flex items-center gap-2 min-w-0",
|
|
179
|
-
children: [/* @__PURE__ */ p
|
|
168
|
+
children: [/* @__PURE__ */ y(p, { className: "h-4 w-4 text-muted-foreground shrink-0" }), /* @__PURE__ */ b("div", {
|
|
180
169
|
className: "min-w-0",
|
|
181
|
-
children: [/* @__PURE__ */
|
|
170
|
+
children: [/* @__PURE__ */ y("button", {
|
|
182
171
|
type: "button",
|
|
183
172
|
className: "block max-w-full truncate text-left text-sm font-medium hover:underline",
|
|
184
|
-
onClick: () =>
|
|
173
|
+
onClick: () => n(`/docs/doc-detail-page?docId=${encodeURIComponent(e.id)}`),
|
|
185
174
|
children: e.title
|
|
186
|
-
}), /* @__PURE__ */
|
|
175
|
+
}), /* @__PURE__ */ b("p", {
|
|
187
176
|
className: "text-xs text-muted-foreground",
|
|
188
177
|
children: ["v", e.version]
|
|
189
178
|
})]
|
|
190
179
|
})]
|
|
191
|
-
}), /* @__PURE__ */
|
|
180
|
+
}), /* @__PURE__ */ b("div", {
|
|
192
181
|
className: "flex items-center gap-2 shrink-0",
|
|
193
|
-
children: [/* @__PURE__ */
|
|
194
|
-
className: `text-xs px-2 py-0.5 rounded-full capitalize ${
|
|
182
|
+
children: [/* @__PURE__ */ y("span", {
|
|
183
|
+
className: `text-xs px-2 py-0.5 rounded-full capitalize ${N[e.status] ?? ""}`,
|
|
195
184
|
children: e.status.toLowerCase()
|
|
196
|
-
}), /* @__PURE__ */
|
|
185
|
+
}), /* @__PURE__ */ y(S, {
|
|
197
186
|
size: "icon",
|
|
198
187
|
variant: "ghost",
|
|
199
188
|
disabled: R,
|
|
200
189
|
onClick: () => U(e.id),
|
|
201
190
|
"aria-label": `Unlink ${e.title}`,
|
|
202
|
-
children: /* @__PURE__ */
|
|
191
|
+
children: /* @__PURE__ */ y(h, { className: "h-4 w-4" })
|
|
203
192
|
})]
|
|
204
193
|
})]
|
|
205
194
|
}, e.id))
|
|
206
195
|
]
|
|
207
196
|
})] });
|
|
208
197
|
}
|
|
209
|
-
function
|
|
210
|
-
let { workspaceId: t } = e(),
|
|
211
|
-
variables: { workItemId:
|
|
212
|
-
skip: !t || !
|
|
198
|
+
function F() {
|
|
199
|
+
let { workspaceId: t } = e(), r = new URLSearchParams(window.location.search).get("taskId") ?? "", { data: i, loading: f, error: p } = v(O, {
|
|
200
|
+
variables: { workItemId: r },
|
|
201
|
+
skip: !t || !r
|
|
213
202
|
});
|
|
214
|
-
if (
|
|
203
|
+
if (f && !i) return /* @__PURE__ */ y("div", {
|
|
215
204
|
className: "flex items-center justify-center p-12",
|
|
216
|
-
children: /* @__PURE__ */
|
|
205
|
+
children: /* @__PURE__ */ y("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
|
|
217
206
|
});
|
|
218
|
-
if (
|
|
207
|
+
if (p) return /* @__PURE__ */ b("div", {
|
|
219
208
|
className: "p-6 text-red-500",
|
|
220
|
-
children: ["Error: ",
|
|
209
|
+
children: ["Error: ", p.message]
|
|
221
210
|
});
|
|
222
|
-
let
|
|
223
|
-
|
|
224
|
-
className: "p-6 text-muted-foreground",
|
|
225
|
-
children: "Task not found."
|
|
226
|
-
});
|
|
227
|
-
let l = c.status.toLowerCase().replace("_", " ");
|
|
228
|
-
return /* @__PURE__ */ m("div", {
|
|
211
|
+
let m = i?.planmagnetWorkItem;
|
|
212
|
+
return m ? /* @__PURE__ */ b("div", {
|
|
229
213
|
className: "space-y-6 p-6",
|
|
230
|
-
children: [/* @__PURE__ */
|
|
231
|
-
className: "
|
|
232
|
-
children:
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
214
|
+
children: [/* @__PURE__ */ b("div", {
|
|
215
|
+
className: "flex items-start justify-between gap-4",
|
|
216
|
+
children: [/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("h1", {
|
|
217
|
+
className: "text-2xl font-semibold",
|
|
218
|
+
children: m.title
|
|
219
|
+
}), /* @__PURE__ */ b("p", {
|
|
220
|
+
className: "text-sm text-muted-foreground",
|
|
221
|
+
children: [
|
|
222
|
+
m.key,
|
|
223
|
+
" · ",
|
|
224
|
+
m.type.toLowerCase()
|
|
225
|
+
]
|
|
226
|
+
})] }), /* @__PURE__ */ y(l, {
|
|
227
|
+
workItemId: m.id,
|
|
228
|
+
title: m.title
|
|
229
|
+
})]
|
|
230
|
+
}), /* @__PURE__ */ b("div", {
|
|
241
231
|
className: "grid grid-cols-1 lg:grid-cols-3 gap-6",
|
|
242
|
-
children: [/* @__PURE__ */
|
|
232
|
+
children: [/* @__PURE__ */ b("div", {
|
|
243
233
|
className: "lg:col-span-2 space-y-6",
|
|
244
234
|
children: [
|
|
245
|
-
/* @__PURE__ */
|
|
235
|
+
/* @__PURE__ */ b(C, { children: [/* @__PURE__ */ y(T, { children: /* @__PURE__ */ y(E, { children: "Description" }) }), /* @__PURE__ */ y(w, { children: /* @__PURE__ */ y("p", {
|
|
246
236
|
className: "text-sm",
|
|
247
|
-
children:
|
|
237
|
+
children: m.description ?? "No description provided."
|
|
248
238
|
}) })] }),
|
|
249
|
-
/* @__PURE__ */
|
|
250
|
-
/* @__PURE__ */
|
|
251
|
-
/* @__PURE__ */
|
|
239
|
+
/* @__PURE__ */ y(P, { workItemId: m.id }),
|
|
240
|
+
/* @__PURE__ */ y(u, { workItemId: m.id }),
|
|
241
|
+
/* @__PURE__ */ y(d, { workItemId: m.id })
|
|
252
242
|
]
|
|
253
|
-
}), /* @__PURE__ */
|
|
243
|
+
}), /* @__PURE__ */ y("div", {
|
|
254
244
|
className: "space-y-6",
|
|
255
|
-
children: /* @__PURE__ */
|
|
245
|
+
children: /* @__PURE__ */ b(C, { children: [/* @__PURE__ */ y(T, { children: /* @__PURE__ */ y(E, { children: "Details" }) }), /* @__PURE__ */ b(w, {
|
|
256
246
|
className: "space-y-3 text-sm",
|
|
257
247
|
children: [
|
|
258
|
-
/* @__PURE__ */
|
|
259
|
-
className: "flex justify-between",
|
|
260
|
-
children: [/* @__PURE__ */
|
|
248
|
+
/* @__PURE__ */ b("div", {
|
|
249
|
+
className: "flex items-start justify-between gap-2",
|
|
250
|
+
children: [/* @__PURE__ */ y("span", {
|
|
261
251
|
className: "text-muted-foreground",
|
|
262
252
|
children: "Status"
|
|
263
|
-
}), /* @__PURE__ */
|
|
264
|
-
|
|
265
|
-
|
|
253
|
+
}), /* @__PURE__ */ y(c, {
|
|
254
|
+
workItemId: m.id,
|
|
255
|
+
field: "status",
|
|
256
|
+
value: m.status,
|
|
257
|
+
options: o,
|
|
258
|
+
label: "Status"
|
|
266
259
|
})]
|
|
267
260
|
}),
|
|
268
|
-
/* @__PURE__ */
|
|
269
|
-
className: "flex justify-between",
|
|
270
|
-
children: [/* @__PURE__ */
|
|
261
|
+
/* @__PURE__ */ b("div", {
|
|
262
|
+
className: "flex items-start justify-between gap-2",
|
|
263
|
+
children: [/* @__PURE__ */ y("span", {
|
|
271
264
|
className: "text-muted-foreground",
|
|
272
265
|
children: "Priority"
|
|
273
|
-
}), /* @__PURE__ */
|
|
274
|
-
|
|
275
|
-
|
|
266
|
+
}), /* @__PURE__ */ y(c, {
|
|
267
|
+
workItemId: m.id,
|
|
268
|
+
field: "priority",
|
|
269
|
+
value: m.priority,
|
|
270
|
+
options: a,
|
|
271
|
+
label: "Priority"
|
|
276
272
|
})]
|
|
277
273
|
}),
|
|
278
|
-
/* @__PURE__ */
|
|
274
|
+
/* @__PURE__ */ b("div", {
|
|
279
275
|
className: "flex justify-between",
|
|
280
|
-
children: [/* @__PURE__ */
|
|
276
|
+
children: [/* @__PURE__ */ y("span", {
|
|
281
277
|
className: "text-muted-foreground",
|
|
282
278
|
children: "Type"
|
|
283
|
-
}), /* @__PURE__ */
|
|
279
|
+
}), /* @__PURE__ */ y(x, {
|
|
284
280
|
variant: "outline",
|
|
285
281
|
className: "capitalize",
|
|
286
|
-
children:
|
|
282
|
+
children: m.type.toLowerCase()
|
|
287
283
|
})]
|
|
288
284
|
}),
|
|
289
|
-
/* @__PURE__ */
|
|
285
|
+
/* @__PURE__ */ b("div", {
|
|
290
286
|
className: "flex justify-between",
|
|
291
|
-
children: [/* @__PURE__ */
|
|
287
|
+
children: [/* @__PURE__ */ y("span", {
|
|
292
288
|
className: "text-muted-foreground",
|
|
293
289
|
children: "Story Points"
|
|
294
|
-
}), /* @__PURE__ */
|
|
290
|
+
}), /* @__PURE__ */ y("span", {
|
|
295
291
|
className: "font-medium",
|
|
296
|
-
children:
|
|
292
|
+
children: m.storyPoints ?? 0
|
|
297
293
|
})]
|
|
298
294
|
}),
|
|
299
|
-
/* @__PURE__ */
|
|
300
|
-
className: "flex justify-between",
|
|
301
|
-
children: [/* @__PURE__ */
|
|
295
|
+
/* @__PURE__ */ b("div", {
|
|
296
|
+
className: "flex items-start justify-between gap-2",
|
|
297
|
+
children: [/* @__PURE__ */ y("span", {
|
|
302
298
|
className: "text-muted-foreground",
|
|
303
299
|
children: "Assignee"
|
|
304
|
-
}), /* @__PURE__ */
|
|
300
|
+
}), /* @__PURE__ */ y(s, {
|
|
301
|
+
workItemId: m.id,
|
|
302
|
+
assigneeId: m.assigneeId
|
|
303
|
+
})]
|
|
305
304
|
}),
|
|
306
|
-
/* @__PURE__ */
|
|
305
|
+
/* @__PURE__ */ b("div", {
|
|
307
306
|
className: "flex justify-between",
|
|
308
|
-
children: [/* @__PURE__ */
|
|
307
|
+
children: [/* @__PURE__ */ y("span", {
|
|
309
308
|
className: "text-muted-foreground",
|
|
310
309
|
children: "Reporter"
|
|
311
|
-
}), /* @__PURE__ */
|
|
310
|
+
}), /* @__PURE__ */ y(n, { id: m.reporterId ?? m.createdBy })]
|
|
312
311
|
}),
|
|
313
|
-
/* @__PURE__ */
|
|
312
|
+
/* @__PURE__ */ b("div", {
|
|
314
313
|
className: "flex justify-between",
|
|
315
|
-
children: [/* @__PURE__ */
|
|
314
|
+
children: [/* @__PURE__ */ y("span", {
|
|
316
315
|
className: "text-muted-foreground",
|
|
317
316
|
children: "Key"
|
|
318
|
-
}), /* @__PURE__ */
|
|
317
|
+
}), /* @__PURE__ */ y("span", { children: m.key })]
|
|
319
318
|
}),
|
|
320
|
-
/* @__PURE__ */
|
|
319
|
+
/* @__PURE__ */ b("div", {
|
|
321
320
|
className: "flex justify-between",
|
|
322
|
-
children: [/* @__PURE__ */
|
|
321
|
+
children: [/* @__PURE__ */ y("span", {
|
|
323
322
|
className: "text-muted-foreground",
|
|
324
323
|
children: "Due Date"
|
|
325
|
-
}), /* @__PURE__ */
|
|
324
|
+
}), /* @__PURE__ */ y("span", { children: m.dueDate ?? "Not set" })]
|
|
326
325
|
}),
|
|
327
|
-
/* @__PURE__ */
|
|
326
|
+
/* @__PURE__ */ b("div", {
|
|
328
327
|
className: "flex justify-between",
|
|
329
|
-
children: [/* @__PURE__ */
|
|
328
|
+
children: [/* @__PURE__ */ y("span", {
|
|
330
329
|
className: "text-muted-foreground",
|
|
331
330
|
children: "Created"
|
|
332
|
-
}), /* @__PURE__ */
|
|
331
|
+
}), /* @__PURE__ */ y("span", { children: m.createdAt })]
|
|
333
332
|
}),
|
|
334
|
-
/* @__PURE__ */
|
|
333
|
+
/* @__PURE__ */ b("div", {
|
|
335
334
|
className: "flex justify-between",
|
|
336
|
-
children: [/* @__PURE__ */
|
|
335
|
+
children: [/* @__PURE__ */ y("span", {
|
|
337
336
|
className: "text-muted-foreground",
|
|
338
337
|
children: "Updated"
|
|
339
|
-
}), /* @__PURE__ */
|
|
338
|
+
}), /* @__PURE__ */ y("span", { children: m.updatedAt })]
|
|
340
339
|
}),
|
|
341
|
-
/* @__PURE__ */
|
|
340
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("span", {
|
|
342
341
|
className: "text-muted-foreground text-xs",
|
|
343
342
|
children: "Labels"
|
|
344
|
-
}), /* @__PURE__ */
|
|
343
|
+
}), /* @__PURE__ */ y("div", {
|
|
345
344
|
className: "flex gap-1 mt-1 flex-wrap",
|
|
346
|
-
children: (
|
|
345
|
+
children: (m.labels ?? []).map((e) => /* @__PURE__ */ y("span", {
|
|
347
346
|
className: "text-xs px-2 py-0.5 rounded bg-muted",
|
|
348
347
|
children: e
|
|
349
348
|
}, e))
|
|
@@ -352,9 +351,12 @@ function j() {
|
|
|
352
351
|
})] })
|
|
353
352
|
})]
|
|
354
353
|
})]
|
|
354
|
+
}) : /* @__PURE__ */ y("div", {
|
|
355
|
+
className: "p-6 text-muted-foreground",
|
|
356
|
+
children: "Task not found."
|
|
355
357
|
});
|
|
356
358
|
}
|
|
357
359
|
//#endregion
|
|
358
|
-
export {
|
|
360
|
+
export { F as TasksTaskDetailPagePage };
|
|
359
361
|
|
|
360
362
|
//# sourceMappingURL=TasksTaskDetailPagePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TasksTaskDetailPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/TasksTaskDetailPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { throwOnError } from '../utils/mutationResult';\nimport { WorkItemComments } from '../comments/WorkItemComments';\nimport { WorkItemActivity } from '../comments/WorkItemActivity';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport {\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Badge,\n Button,\n Input,\n} from '@burdenoff/fe-libs/ui';\nimport { FileText, Plus, X } from 'lucide-react';\nimport { MarkdownEditor } from '#src/components/MarkdownEditor';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\n\nconst GET_WORK_ITEM = gql`\n query GetWorkItemDetail($workItemId: ID!) {\n planmagnetWorkItem(id: $workItemId) {\n id\n title\n description\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 updatedAt\n }\n }\n`;\n\nconst GET_WORK_ITEM_DOCS = gql`\n query GetWorkItemDocs($workItemId: ID!) {\n planmagnetWorkItemDocs(workItemId: $workItemId) {\n id\n title\n status\n version\n updatedAt\n }\n }\n`;\n\nconst CREATE_DOC = gql`\n mutation CreateDocForWorkItem($input: PlanmagnetCreateDocInput!) {\n planmagnetCreateDoc(input: $input) {\n id\n }\n }\n`;\n\nconst LINK_DOC_TO_WORK_ITEM = gql`\n mutation LinkDocToWorkItem($docId: ID!, $workItemId: ID!) {\n planmagnetLinkDocToWorkItem(docId: $docId, workItemId: $workItemId) {\n id\n }\n }\n`;\n\nconst UNLINK_DOC_FROM_WORK_ITEM = gql`\n mutation UnlinkDocFromWorkItem($docId: ID!, $workItemId: ID!) {\n planmagnetUnlinkDocFromWorkItem(docId: $docId, workItemId: $workItemId)\n }\n`;\n\ninterface WorkItemNode {\n id: string;\n title: string;\n description: string | null;\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 updatedAt: string;\n}\n\ninterface WorkItemDocNode {\n id: string;\n title: string;\n status: string;\n version: number;\n updatedAt: string;\n}\n\nconst priorityColor: Record<string, string> = {\n LOW: 'bg-gray-100 text-gray-800',\n MEDIUM: 'bg-blue-100 text-blue-800',\n HIGH: 'bg-orange-100 text-orange-800',\n CRITICAL: 'bg-red-100 text-red-800',\n};\n\nconst statusColor: Record<string, string> = {\n BACKLOG: 'bg-gray-100 text-gray-800',\n TODO: 'bg-blue-100 text-blue-800',\n IN_PROGRESS: 'bg-yellow-100 text-yellow-800',\n IN_REVIEW: 'bg-purple-100 text-purple-800',\n DONE: 'bg-green-100 text-green-800',\n BLOCKED: 'bg-red-100 text-red-800',\n TESTING: 'bg-teal-100 text-teal-800',\n CANCELLED: 'bg-gray-100 text-gray-800',\n};\n\nconst docStatusColor: Record<string, string> = {\n DRAFT: 'bg-gray-100 text-gray-800',\n PUBLISHED: 'bg-green-100 text-green-800',\n ARCHIVED: 'bg-gray-100 text-gray-500',\n};\n\n/**\n * Linked-docs panel (BOFF-4443): create a doc and link it to this work item\n * in one action, view currently-linked docs, and unlink one. Reads/writes go\n * through the real planmagnetWorkItemDocs / planmagnetCreateDoc /\n * planmagnetLinkDocToWorkItem / planmagnetUnlinkDocFromWorkItem GraphQL\n * fields — no fabricated data. Full doc editing (revisions, revert) lives on\n * a dedicated doc detail view; this panel is scoped to linking.\n */\nfunction LinkedDocsPanel({ workItemId }: { workItemId: string }) {\n const navigate = usePlanMagnetNavigate();\n const [isComposing, setIsComposing] = useState(false);\n const [newTitle, setNewTitle] = useState('');\n const [newContent, setNewContent] = useState('');\n\n const { data, loading, error, refetch } = useQuery<{\n planmagnetWorkItemDocs: WorkItemDocNode[];\n }>(GET_WORK_ITEM_DOCS, {\n variables: { workItemId },\n skip: !workItemId,\n });\n\n const [createDoc, { loading: creating }] = useMutation(CREATE_DOC);\n const [linkDoc] = useMutation(LINK_DOC_TO_WORK_ITEM);\n const [unlinkDoc, { loading: unlinking }] = useMutation(UNLINK_DOC_FROM_WORK_ITEM);\n // A refused mutation resolves with { error } (fe-libs errorPolicy 'all');\n // the composer used to clear itself as if the doc had been saved.\n const [actionError, setActionError] = useState<string | null>(null);\n\n const docs = data?.planmagnetWorkItemDocs ?? [];\n\n const handleCreateAndLink = async () => {\n if (!newTitle.trim() || !newContent.trim()) return;\n setActionError(null);\n try {\n const result = await throwOnError(\n createDoc({ variables: { input: { title: newTitle.trim(), content: newContent.trim() } } })\n );\n const docId = result.data?.planmagnetCreateDoc?.id;\n if (docId) {\n await throwOnError(linkDoc({ variables: { docId, workItemId } }));\n }\n } catch (e) {\n setActionError(e instanceof Error ? e.message : 'The doc could not be saved.');\n return;\n }\n setNewTitle('');\n setNewContent('');\n setIsComposing(false);\n void refetch();\n };\n\n const handleUnlink = async (docId: string) => {\n setActionError(null);\n try {\n await throwOnError(unlinkDoc({ variables: { docId, workItemId } }));\n } catch (e) {\n setActionError(e instanceof Error ? e.message : 'The doc could not be unlinked.');\n return;\n }\n void refetch();\n };\n\n return (\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0\">\n <CardTitle>Linked Docs</CardTitle>\n {!isComposing && (\n <Button size=\"sm\" variant=\"outline\" onClick={() => setIsComposing(true)}>\n <Plus className=\"h-4 w-4 mr-1\" />\n New Doc\n </Button>\n )}\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {isComposing && (\n <div className=\"space-y-3 rounded-md border border-input p-3\">\n <Input\n placeholder=\"Doc title\"\n value={newTitle}\n onChange={(e) => setNewTitle(e.target.value)}\n />\n <MarkdownEditor\n value={newContent}\n onChange={setNewContent}\n placeholder=\"Write the spec/doc content...\"\n minHeight={140}\n />\n <div className=\"flex gap-2 justify-end\">\n <Button\n size=\"sm\"\n variant=\"ghost\"\n onClick={() => {\n setIsComposing(false);\n setNewTitle('');\n setNewContent('');\n }}\n >\n Cancel\n </Button>\n <Button\n size=\"sm\"\n disabled={creating || !newTitle.trim() || !newContent.trim()}\n onClick={handleCreateAndLink}\n >\n {creating ? 'Creating...' : 'Create & Link'}\n </Button>\n </div>\n </div>\n )}\n\n {loading && <p className=\"text-sm text-muted-foreground\">Loading docs...</p>}\n {error && <p className=\"text-sm text-red-500\">Error: {error.message}</p>}\n {actionError && (\n <p role=\"alert\" className=\"text-sm text-destructive\">\n {actionError}\n </p>\n )}\n {!loading && !error && docs.length === 0 && !isComposing && (\n <p className=\"text-sm text-muted-foreground\">No docs linked to this work item yet.</p>\n )}\n {docs.map((doc) => (\n <div\n key={doc.id}\n className=\"flex items-center justify-between gap-3 rounded-md border border-input p-3\"\n >\n <div className=\"flex items-center gap-2 min-w-0\">\n <FileText className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <div className=\"min-w-0\">\n <button\n type=\"button\"\n className=\"block max-w-full truncate text-left text-sm font-medium hover:underline\"\n onClick={() =>\n navigate(`/docs/doc-detail-page?docId=${encodeURIComponent(doc.id)}`)\n }\n >\n {doc.title}\n </button>\n <p className=\"text-xs text-muted-foreground\">v{doc.version}</p>\n </div>\n </div>\n <div className=\"flex items-center gap-2 shrink-0\">\n <span\n className={`text-xs px-2 py-0.5 rounded-full capitalize ${docStatusColor[doc.status] ?? ''}`}\n >\n {doc.status.toLowerCase()}\n </span>\n <Button\n size=\"icon\"\n variant=\"ghost\"\n disabled={unlinking}\n onClick={() => handleUnlink(doc.id)}\n aria-label={`Unlink ${doc.title}`}\n >\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n );\n}\n\nexport function TasksTaskDetailPagePage() {\n const { workspaceId } = usePlanMagnet();\n\n // In a real app, workItemId comes from route params.\n const workItemId = new URLSearchParams(window.location.search).get('taskId') ?? '';\n\n const { data, loading, error } = useQuery<{\n planmagnetWorkItem: WorkItemNode;\n }>(GET_WORK_ITEM, {\n variables: { workItemId },\n skip: !workspaceId || !workItemId,\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 task = data?.planmagnetWorkItem;\n if (!task) return <div className=\"p-6 text-muted-foreground\">Task not found.</div>;\n\n const statusDisplay = task.status.toLowerCase().replace('_', ' ');\n\n return (\n <div className=\"space-y-6 p-6\">\n <div>\n <h1 className=\"text-2xl font-semibold\">{task.title}</h1>\n <p className=\"text-sm text-muted-foreground\">\n {task.key} · {task.type.toLowerCase()}\n </p>\n </div>\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n <div className=\"lg:col-span-2 space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle>Description</CardTitle>\n </CardHeader>\n <CardContent>\n <p className=\"text-sm\">{task.description ?? 'No description provided.'}</p>\n </CardContent>\n </Card>\n <LinkedDocsPanel workItemId={task.id} />\n <WorkItemComments workItemId={task.id} />\n <WorkItemActivity workItemId={task.id} />\n </div>\n <div className=\"space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle>Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3 text-sm\">\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Status</span>\n <span\n className={`text-xs px-2 py-0.5 rounded-full capitalize ${statusColor[task.status] ?? ''}`}\n >\n {statusDisplay}\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Priority</span>\n <span\n className={`text-xs px-2 py-0.5 rounded-full capitalize ${priorityColor[task.priority] ?? ''}`}\n >\n {task.priority.toLowerCase()}\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Type</span>\n <Badge variant=\"outline\" className=\"capitalize\">\n {task.type.toLowerCase()}\n </Badge>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Story Points</span>\n <span className=\"font-medium\">{task.storyPoints ?? 0}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Assignee</span>\n <span>{task.assigneeId ?? 'Unassigned'}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Reporter</span>\n <span>{task.reporterId ?? 'Unknown'}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Key</span>\n <span>{task.key}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Due Date</span>\n <span>{task.dueDate ?? 'Not set'}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Created</span>\n <span>{task.createdAt}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Updated</span>\n <span>{task.updatedAt}</span>\n </div>\n <div>\n <span className=\"text-muted-foreground text-xs\">Labels</span>\n <div className=\"flex gap-1 mt-1 flex-wrap\">\n {(task.labels ?? []).map((l) => (\n <span key={l} className=\"text-xs px-2 py-0.5 rounded bg-muted\">\n {l}\n </span>\n ))}\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TasksTaskDetailPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/TasksTaskDetailPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { throwOnError } from '../utils/mutationResult';\nimport { WorkItemComments } from '../comments/WorkItemComments';\nimport { WorkItemActivity } from '../comments/WorkItemActivity';\nimport { PersonName } from '../people/People';\nimport {\n WORK_ITEM_PRIORITIES,\n WORK_ITEM_STATUSES,\n WorkItemAssigneeSelect,\n WorkItemEnumSelect,\n WorkItemHeaderActions,\n} from '../controls/WorkItemControls';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport {\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Badge,\n Button,\n Input,\n} from '@burdenoff/fe-libs/ui';\nimport { FileText, Plus, X } from 'lucide-react';\nimport { MarkdownEditor } from '#src/components/MarkdownEditor';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\n\nconst GET_WORK_ITEM = gql`\n query GetWorkItemDetail($workItemId: ID!) {\n planmagnetWorkItem(id: $workItemId) {\n id\n title\n description\n type\n status\n priority\n key\n assigneeId\n reporterId\n createdBy\n sprintId\n storyPoints\n estimateMinutes\n dueDate\n labels\n tags\n createdAt\n updatedAt\n }\n }\n`;\n\nconst GET_WORK_ITEM_DOCS = gql`\n query GetWorkItemDocs($workItemId: ID!) {\n planmagnetWorkItemDocs(workItemId: $workItemId) {\n id\n title\n status\n version\n updatedAt\n }\n }\n`;\n\nconst CREATE_DOC = gql`\n mutation CreateDocForWorkItem($input: PlanmagnetCreateDocInput!) {\n planmagnetCreateDoc(input: $input) {\n id\n }\n }\n`;\n\nconst LINK_DOC_TO_WORK_ITEM = gql`\n mutation LinkDocToWorkItem($docId: ID!, $workItemId: ID!) {\n planmagnetLinkDocToWorkItem(docId: $docId, workItemId: $workItemId) {\n id\n }\n }\n`;\n\nconst UNLINK_DOC_FROM_WORK_ITEM = gql`\n mutation UnlinkDocFromWorkItem($docId: ID!, $workItemId: ID!) {\n planmagnetUnlinkDocFromWorkItem(docId: $docId, workItemId: $workItemId)\n }\n`;\n\ninterface WorkItemNode {\n id: string;\n title: string;\n description: string | null;\n type: string;\n status: string;\n priority: string;\n key: string;\n assigneeId: string | null;\n reporterId: string | null;\n createdBy: string;\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 updatedAt: string;\n}\n\ninterface WorkItemDocNode {\n id: string;\n title: string;\n status: string;\n version: number;\n updatedAt: string;\n}\n\nconst docStatusColor: Record<string, string> = {\n DRAFT: 'bg-gray-100 text-gray-800',\n PUBLISHED: 'bg-green-100 text-green-800',\n ARCHIVED: 'bg-gray-100 text-gray-500',\n};\n\n/**\n * Linked-docs panel (BOFF-4443): create a doc and link it to this work item\n * in one action, view currently-linked docs, and unlink one. Reads/writes go\n * through the real planmagnetWorkItemDocs / planmagnetCreateDoc /\n * planmagnetLinkDocToWorkItem / planmagnetUnlinkDocFromWorkItem GraphQL\n * fields — no fabricated data. Full doc editing (revisions, revert) lives on\n * a dedicated doc detail view; this panel is scoped to linking.\n */\nfunction LinkedDocsPanel({ workItemId }: { workItemId: string }) {\n const navigate = usePlanMagnetNavigate();\n const [isComposing, setIsComposing] = useState(false);\n const [newTitle, setNewTitle] = useState('');\n const [newContent, setNewContent] = useState('');\n\n const { data, loading, error, refetch } = useQuery<{\n planmagnetWorkItemDocs: WorkItemDocNode[];\n }>(GET_WORK_ITEM_DOCS, {\n variables: { workItemId },\n skip: !workItemId,\n });\n\n const [createDoc, { loading: creating }] = useMutation(CREATE_DOC);\n const [linkDoc] = useMutation(LINK_DOC_TO_WORK_ITEM);\n const [unlinkDoc, { loading: unlinking }] = useMutation(UNLINK_DOC_FROM_WORK_ITEM);\n // A refused mutation resolves with { error } (fe-libs errorPolicy 'all');\n // the composer used to clear itself as if the doc had been saved.\n const [actionError, setActionError] = useState<string | null>(null);\n\n const docs = data?.planmagnetWorkItemDocs ?? [];\n\n const handleCreateAndLink = async () => {\n if (!newTitle.trim() || !newContent.trim()) return;\n setActionError(null);\n try {\n const result = await throwOnError(\n createDoc({ variables: { input: { title: newTitle.trim(), content: newContent.trim() } } })\n );\n const docId = result.data?.planmagnetCreateDoc?.id;\n if (docId) {\n await throwOnError(linkDoc({ variables: { docId, workItemId } }));\n }\n } catch (e) {\n setActionError(e instanceof Error ? e.message : 'The doc could not be saved.');\n return;\n }\n setNewTitle('');\n setNewContent('');\n setIsComposing(false);\n void refetch();\n };\n\n const handleUnlink = async (docId: string) => {\n setActionError(null);\n try {\n await throwOnError(unlinkDoc({ variables: { docId, workItemId } }));\n } catch (e) {\n setActionError(e instanceof Error ? e.message : 'The doc could not be unlinked.');\n return;\n }\n void refetch();\n };\n\n return (\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0\">\n <CardTitle>Linked Docs</CardTitle>\n {!isComposing && (\n <Button size=\"sm\" variant=\"outline\" onClick={() => setIsComposing(true)}>\n <Plus className=\"h-4 w-4 mr-1\" />\n New Doc\n </Button>\n )}\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {isComposing && (\n <div className=\"space-y-3 rounded-md border border-input p-3\">\n <Input\n placeholder=\"Doc title\"\n value={newTitle}\n onChange={(e) => setNewTitle(e.target.value)}\n />\n <MarkdownEditor\n value={newContent}\n onChange={setNewContent}\n placeholder=\"Write the spec/doc content...\"\n minHeight={140}\n />\n <div className=\"flex gap-2 justify-end\">\n <Button\n size=\"sm\"\n variant=\"ghost\"\n onClick={() => {\n setIsComposing(false);\n setNewTitle('');\n setNewContent('');\n }}\n >\n Cancel\n </Button>\n <Button\n size=\"sm\"\n disabled={creating || !newTitle.trim() || !newContent.trim()}\n onClick={handleCreateAndLink}\n >\n {creating ? 'Creating...' : 'Create & Link'}\n </Button>\n </div>\n </div>\n )}\n\n {loading && <p className=\"text-sm text-muted-foreground\">Loading docs...</p>}\n {error && <p className=\"text-sm text-red-500\">Error: {error.message}</p>}\n {actionError && (\n <p role=\"alert\" className=\"text-sm text-destructive\">\n {actionError}\n </p>\n )}\n {!loading && !error && docs.length === 0 && !isComposing && (\n <p className=\"text-sm text-muted-foreground\">No docs linked to this work item yet.</p>\n )}\n {docs.map((doc) => (\n <div\n key={doc.id}\n className=\"flex items-center justify-between gap-3 rounded-md border border-input p-3\"\n >\n <div className=\"flex items-center gap-2 min-w-0\">\n <FileText className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <div className=\"min-w-0\">\n <button\n type=\"button\"\n className=\"block max-w-full truncate text-left text-sm font-medium hover:underline\"\n onClick={() =>\n navigate(`/docs/doc-detail-page?docId=${encodeURIComponent(doc.id)}`)\n }\n >\n {doc.title}\n </button>\n <p className=\"text-xs text-muted-foreground\">v{doc.version}</p>\n </div>\n </div>\n <div className=\"flex items-center gap-2 shrink-0\">\n <span\n className={`text-xs px-2 py-0.5 rounded-full capitalize ${docStatusColor[doc.status] ?? ''}`}\n >\n {doc.status.toLowerCase()}\n </span>\n <Button\n size=\"icon\"\n variant=\"ghost\"\n disabled={unlinking}\n onClick={() => handleUnlink(doc.id)}\n aria-label={`Unlink ${doc.title}`}\n >\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n );\n}\n\nexport function TasksTaskDetailPagePage() {\n const { workspaceId } = usePlanMagnet();\n\n // In a real app, workItemId comes from route params.\n const workItemId = new URLSearchParams(window.location.search).get('taskId') ?? '';\n\n const { data, loading, error } = useQuery<{\n planmagnetWorkItem: WorkItemNode;\n }>(GET_WORK_ITEM, {\n variables: { workItemId },\n skip: !workspaceId || !workItemId,\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 task = data?.planmagnetWorkItem;\n if (!task) return <div className=\"p-6 text-muted-foreground\">Task not found.</div>;\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\">{task.title}</h1>\n <p className=\"text-sm text-muted-foreground\">\n {task.key} · {task.type.toLowerCase()}\n </p>\n </div>\n <WorkItemHeaderActions workItemId={task.id} title={task.title} />\n </div>\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n <div className=\"lg:col-span-2 space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle>Description</CardTitle>\n </CardHeader>\n <CardContent>\n <p className=\"text-sm\">{task.description ?? 'No description provided.'}</p>\n </CardContent>\n </Card>\n <LinkedDocsPanel workItemId={task.id} />\n <WorkItemComments workItemId={task.id} />\n <WorkItemActivity workItemId={task.id} />\n </div>\n <div className=\"space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle>Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3 text-sm\">\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"text-muted-foreground\">Status</span>\n <WorkItemEnumSelect\n workItemId={task.id}\n field=\"status\"\n value={task.status}\n options={WORK_ITEM_STATUSES}\n label=\"Status\"\n />\n </div>\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"text-muted-foreground\">Priority</span>\n <WorkItemEnumSelect\n workItemId={task.id}\n field=\"priority\"\n value={task.priority}\n options={WORK_ITEM_PRIORITIES}\n label=\"Priority\"\n />\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Type</span>\n <Badge variant=\"outline\" className=\"capitalize\">\n {task.type.toLowerCase()}\n </Badge>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Story Points</span>\n <span className=\"font-medium\">{task.storyPoints ?? 0}</span>\n </div>\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"text-muted-foreground\">Assignee</span>\n {/* Members by name (BOFF-7946); choosing one assigns the task (BOFF-7938). */}\n <WorkItemAssigneeSelect workItemId={task.id} assigneeId={task.assigneeId} />\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Reporter</span>\n {/* No PlanMagnet form sets reporterId, so a UI-created task has none; its creator reported it. */}\n <PersonName id={task.reporterId ?? task.createdBy} />\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Key</span>\n <span>{task.key}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Due Date</span>\n <span>{task.dueDate ?? 'Not set'}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Created</span>\n <span>{task.createdAt}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Updated</span>\n <span>{task.updatedAt}</span>\n </div>\n <div>\n <span className=\"text-muted-foreground text-xs\">Labels</span>\n <div className=\"flex gap-1 mt-1 flex-wrap\">\n {(task.labels ?? []).map((l) => (\n <span key={l} className=\"text-xs px-2 py-0.5 rounded bg-muted\">\n {l}\n </span>\n ))}\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TasksTasksPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/TasksTasksPagePage.tsx"],"names":[],"mappings":"AAyIA,wBAAgB,kBAAkB,
|
|
1
|
+
{"version":3,"file":"TasksTasksPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/TasksTasksPagePage.tsx"],"names":[],"mappings":"AAyIA,wBAAgB,kBAAkB,4CAqPjC"}
|