@burdenoff/microfe-planmagnet 2026.925.7 → 2026.925.9
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/wspace-types.d.ts +49 -0
- package/dist/generated/wspace-types.d.ts.map +1 -1
- package/dist/planmagnet/board/ProjectBoard.d.ts.map +1 -1
- package/dist/planmagnet/board/ProjectBoard.js +159 -158
- package/dist/planmagnet/board/ProjectBoard.js.map +1 -1
- package/dist/planmagnet/comments/WorkItemComments.d.ts +4 -0
- package/dist/planmagnet/comments/WorkItemComments.d.ts.map +1 -0
- package/dist/planmagnet/comments/WorkItemComments.js +260 -0
- package/dist/planmagnet/comments/WorkItemComments.js.map +1 -0
- package/dist/planmagnet/create/CreateDialogs.d.ts.map +1 -1
- package/dist/planmagnet/create/CreateDialogs.js +118 -117
- package/dist/planmagnet/create/CreateDialogs.js.map +1 -1
- package/dist/planmagnet/pages/GoalsCreateObjectivePagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/GoalsCreateObjectivePagePage.js.map +1 -1
- package/dist/planmagnet/pages/GoalsObjectiveDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/GoalsObjectiveDetailPagePage.js +322 -280
- package/dist/planmagnet/pages/GoalsObjectiveDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksCreateTaskPagePage.d.ts.map +1 -1
- 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.map +1 -1
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.js +166 -143
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.js.map +1 -1
- package/dist/planmagnet/sprints/SprintControls.d.ts.map +1 -1
- package/dist/planmagnet/sprints/SprintControls.js +202 -201
- package/dist/planmagnet/sprints/SprintControls.js.map +1 -1
- package/dist/planmagnet/utils/mutationResult.d.ts +16 -0
- package/dist/planmagnet/utils/mutationResult.d.ts.map +1 -0
- package/dist/planmagnet/utils/mutationResult.js +10 -0
- package/dist/planmagnet/utils/mutationResult.js.map +1 -0
- package/package.json +3 -2
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { usePlanMagnet as e } from "../providers/PlanMagnetProvider.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
2
|
+
import { throwOnError as t } from "../utils/mutationResult.js";
|
|
3
|
+
import { MarkdownEditor as n } from "../../components/MarkdownEditor.js";
|
|
4
|
+
import { WorkItemComments as r } from "../comments/WorkItemComments.js";
|
|
5
|
+
import { useState as i } from "react";
|
|
6
|
+
import { FileText as a, Plus as o, X as s } from "lucide-react";
|
|
7
|
+
import { gql as c } from "@apollo/client";
|
|
8
|
+
import { useMutation as l, useQuery as u } from "@apollo/client/react";
|
|
9
|
+
import { jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
10
|
+
import { Badge as p, Button as m, Card as h, CardContent as g, CardHeader as _, CardTitle as v, Input as y } from "@burdenoff/fe-libs/ui";
|
|
9
11
|
//#region src/planmagnet/pages/TasksTaskDetailPagePage.tsx
|
|
10
|
-
var
|
|
12
|
+
var b = c`
|
|
11
13
|
query GetWorkItemDetail($workItemId: ID!) {
|
|
12
14
|
planmagnetWorkItem(id: $workItemId) {
|
|
13
15
|
id
|
|
@@ -29,7 +31,7 @@ var v = o`
|
|
|
29
31
|
updatedAt
|
|
30
32
|
}
|
|
31
33
|
}
|
|
32
|
-
`,
|
|
34
|
+
`, x = c`
|
|
33
35
|
query GetWorkItemDocs($workItemId: ID!) {
|
|
34
36
|
planmagnetWorkItemDocs(workItemId: $workItemId) {
|
|
35
37
|
id
|
|
@@ -39,28 +41,28 @@ var v = o`
|
|
|
39
41
|
updatedAt
|
|
40
42
|
}
|
|
41
43
|
}
|
|
42
|
-
`,
|
|
44
|
+
`, S = c`
|
|
43
45
|
mutation CreateDocForWorkItem($input: PlanmagnetCreateDocInput!) {
|
|
44
46
|
planmagnetCreateDoc(input: $input) {
|
|
45
47
|
id
|
|
46
48
|
}
|
|
47
49
|
}
|
|
48
|
-
`,
|
|
50
|
+
`, C = c`
|
|
49
51
|
mutation LinkDocToWorkItem($docId: ID!, $workItemId: ID!) {
|
|
50
52
|
planmagnetLinkDocToWorkItem(docId: $docId, workItemId: $workItemId) {
|
|
51
53
|
id
|
|
52
54
|
}
|
|
53
55
|
}
|
|
54
|
-
`,
|
|
56
|
+
`, w = c`
|
|
55
57
|
mutation UnlinkDocFromWorkItem($docId: ID!, $workItemId: ID!) {
|
|
56
58
|
planmagnetUnlinkDocFromWorkItem(docId: $docId, workItemId: $workItemId)
|
|
57
59
|
}
|
|
58
|
-
`,
|
|
60
|
+
`, T = {
|
|
59
61
|
LOW: "bg-gray-100 text-gray-800",
|
|
60
62
|
MEDIUM: "bg-blue-100 text-blue-800",
|
|
61
63
|
HIGH: "bg-orange-100 text-orange-800",
|
|
62
64
|
CRITICAL: "bg-red-100 text-red-800"
|
|
63
|
-
},
|
|
65
|
+
}, E = {
|
|
64
66
|
BACKLOG: "bg-gray-100 text-gray-800",
|
|
65
67
|
TODO: "bg-blue-100 text-blue-800",
|
|
66
68
|
IN_PROGRESS: "bg-yellow-100 text-yellow-800",
|
|
@@ -69,188 +71,209 @@ var v = o`
|
|
|
69
71
|
BLOCKED: "bg-red-100 text-red-800",
|
|
70
72
|
TESTING: "bg-teal-100 text-teal-800",
|
|
71
73
|
CANCELLED: "bg-gray-100 text-gray-800"
|
|
72
|
-
},
|
|
74
|
+
}, D = {
|
|
73
75
|
DRAFT: "bg-gray-100 text-gray-800",
|
|
74
76
|
PUBLISHED: "bg-green-100 text-green-800",
|
|
75
77
|
ARCHIVED: "bg-gray-100 text-gray-500"
|
|
76
78
|
};
|
|
77
|
-
function
|
|
78
|
-
let [
|
|
79
|
+
function O({ workItemId: e }) {
|
|
80
|
+
let [r, c] = i(!1), [p, b] = i(""), [T, E] = i(""), { data: O, loading: k, error: A, refetch: j } = u(x, {
|
|
79
81
|
variables: { workItemId: e },
|
|
80
82
|
skip: !e
|
|
81
|
-
}), [
|
|
82
|
-
if (!
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
83
|
+
}), [M, { loading: N }] = l(S), [P] = l(C), [F, { loading: I }] = l(w), [L, R] = i(null), z = O?.planmagnetWorkItemDocs ?? [], B = async () => {
|
|
84
|
+
if (!(!p.trim() || !T.trim())) {
|
|
85
|
+
R(null);
|
|
86
|
+
try {
|
|
87
|
+
let n = (await t(M({ variables: { input: {
|
|
88
|
+
title: p.trim(),
|
|
89
|
+
content: T.trim()
|
|
90
|
+
} } }))).data?.planmagnetCreateDoc?.id;
|
|
91
|
+
n && await t(P({ variables: {
|
|
92
|
+
docId: n,
|
|
93
|
+
workItemId: e
|
|
94
|
+
} }));
|
|
95
|
+
} catch (e) {
|
|
96
|
+
R(e instanceof Error ? e.message : "The doc could not be saved.");
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
b(""), E(""), c(!1), j();
|
|
100
|
+
}
|
|
101
|
+
}, V = async (n) => {
|
|
102
|
+
R(null);
|
|
103
|
+
try {
|
|
104
|
+
await t(F({ variables: {
|
|
105
|
+
docId: n,
|
|
106
|
+
workItemId: e
|
|
107
|
+
} }));
|
|
108
|
+
} catch (e) {
|
|
109
|
+
R(e instanceof Error ? e.message : "The doc could not be unlinked.");
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
j();
|
|
96
113
|
};
|
|
97
|
-
return /* @__PURE__ */
|
|
114
|
+
return /* @__PURE__ */ f(h, { children: [/* @__PURE__ */ f(_, {
|
|
98
115
|
className: "flex flex-row items-center justify-between space-y-0",
|
|
99
|
-
children: [/* @__PURE__ */
|
|
116
|
+
children: [/* @__PURE__ */ d(v, { children: "Linked Docs" }), !r && /* @__PURE__ */ f(m, {
|
|
100
117
|
size: "sm",
|
|
101
118
|
variant: "outline",
|
|
102
|
-
onClick: () =>
|
|
103
|
-
children: [/* @__PURE__ */
|
|
119
|
+
onClick: () => c(!0),
|
|
120
|
+
children: [/* @__PURE__ */ d(o, { className: "h-4 w-4 mr-1" }), "New Doc"]
|
|
104
121
|
})]
|
|
105
|
-
}), /* @__PURE__ */
|
|
122
|
+
}), /* @__PURE__ */ f(g, {
|
|
106
123
|
className: "space-y-4",
|
|
107
124
|
children: [
|
|
108
|
-
|
|
125
|
+
r && /* @__PURE__ */ f("div", {
|
|
109
126
|
className: "space-y-3 rounded-md border border-input p-3",
|
|
110
127
|
children: [
|
|
111
|
-
/* @__PURE__ */
|
|
128
|
+
/* @__PURE__ */ d(y, {
|
|
112
129
|
placeholder: "Doc title",
|
|
113
|
-
value:
|
|
114
|
-
onChange: (e) =>
|
|
130
|
+
value: p,
|
|
131
|
+
onChange: (e) => b(e.target.value)
|
|
115
132
|
}),
|
|
116
|
-
/* @__PURE__ */
|
|
117
|
-
value:
|
|
133
|
+
/* @__PURE__ */ d(n, {
|
|
134
|
+
value: T,
|
|
118
135
|
onChange: E,
|
|
119
136
|
placeholder: "Write the spec/doc content...",
|
|
120
137
|
minHeight: 140
|
|
121
138
|
}),
|
|
122
|
-
/* @__PURE__ */
|
|
139
|
+
/* @__PURE__ */ f("div", {
|
|
123
140
|
className: "flex gap-2 justify-end",
|
|
124
|
-
children: [/* @__PURE__ */
|
|
141
|
+
children: [/* @__PURE__ */ d(m, {
|
|
125
142
|
size: "sm",
|
|
126
143
|
variant: "ghost",
|
|
127
144
|
onClick: () => {
|
|
128
|
-
|
|
145
|
+
c(!1), b(""), E("");
|
|
129
146
|
},
|
|
130
147
|
children: "Cancel"
|
|
131
|
-
}), /* @__PURE__ */
|
|
148
|
+
}), /* @__PURE__ */ d(m, {
|
|
132
149
|
size: "sm",
|
|
133
|
-
disabled:
|
|
134
|
-
onClick:
|
|
135
|
-
children:
|
|
150
|
+
disabled: N || !p.trim() || !T.trim(),
|
|
151
|
+
onClick: B,
|
|
152
|
+
children: N ? "Creating..." : "Create & Link"
|
|
136
153
|
})]
|
|
137
154
|
})
|
|
138
155
|
]
|
|
139
156
|
}),
|
|
140
|
-
|
|
157
|
+
k && /* @__PURE__ */ d("p", {
|
|
141
158
|
className: "text-sm text-muted-foreground",
|
|
142
159
|
children: "Loading docs..."
|
|
143
160
|
}),
|
|
144
|
-
|
|
161
|
+
A && /* @__PURE__ */ f("p", {
|
|
145
162
|
className: "text-sm text-red-500",
|
|
146
|
-
children: ["Error: ",
|
|
163
|
+
children: ["Error: ", A.message]
|
|
164
|
+
}),
|
|
165
|
+
L && /* @__PURE__ */ d("p", {
|
|
166
|
+
role: "alert",
|
|
167
|
+
className: "text-sm text-destructive",
|
|
168
|
+
children: L
|
|
147
169
|
}),
|
|
148
|
-
!
|
|
170
|
+
!k && !A && z.length === 0 && !r && /* @__PURE__ */ d("p", {
|
|
149
171
|
className: "text-sm text-muted-foreground",
|
|
150
172
|
children: "No docs linked to this work item yet."
|
|
151
173
|
}),
|
|
152
|
-
|
|
174
|
+
z.map((e) => /* @__PURE__ */ f("div", {
|
|
153
175
|
className: "flex items-center justify-between gap-3 rounded-md border border-input p-3",
|
|
154
|
-
children: [/* @__PURE__ */
|
|
176
|
+
children: [/* @__PURE__ */ f("div", {
|
|
155
177
|
className: "flex items-center gap-2 min-w-0",
|
|
156
|
-
children: [/* @__PURE__ */
|
|
178
|
+
children: [/* @__PURE__ */ d(a, { className: "h-4 w-4 text-muted-foreground shrink-0" }), /* @__PURE__ */ f("div", {
|
|
157
179
|
className: "min-w-0",
|
|
158
|
-
children: [/* @__PURE__ */
|
|
180
|
+
children: [/* @__PURE__ */ d("p", {
|
|
159
181
|
className: "text-sm font-medium truncate",
|
|
160
182
|
children: e.title
|
|
161
|
-
}), /* @__PURE__ */
|
|
183
|
+
}), /* @__PURE__ */ f("p", {
|
|
162
184
|
className: "text-xs text-muted-foreground",
|
|
163
185
|
children: ["v", e.version]
|
|
164
186
|
})]
|
|
165
187
|
})]
|
|
166
|
-
}), /* @__PURE__ */
|
|
188
|
+
}), /* @__PURE__ */ f("div", {
|
|
167
189
|
className: "flex items-center gap-2 shrink-0",
|
|
168
|
-
children: [/* @__PURE__ */
|
|
169
|
-
className: `text-xs px-2 py-0.5 rounded-full capitalize ${
|
|
190
|
+
children: [/* @__PURE__ */ d("span", {
|
|
191
|
+
className: `text-xs px-2 py-0.5 rounded-full capitalize ${D[e.status] ?? ""}`,
|
|
170
192
|
children: e.status.toLowerCase()
|
|
171
|
-
}), /* @__PURE__ */
|
|
193
|
+
}), /* @__PURE__ */ d(m, {
|
|
172
194
|
size: "icon",
|
|
173
195
|
variant: "ghost",
|
|
174
|
-
disabled:
|
|
175
|
-
onClick: () =>
|
|
196
|
+
disabled: I,
|
|
197
|
+
onClick: () => V(e.id),
|
|
176
198
|
"aria-label": `Unlink ${e.title}`,
|
|
177
|
-
children: /* @__PURE__ */
|
|
199
|
+
children: /* @__PURE__ */ d(s, { className: "h-4 w-4" })
|
|
178
200
|
})]
|
|
179
201
|
})]
|
|
180
202
|
}, e.id))
|
|
181
203
|
]
|
|
182
204
|
})] });
|
|
183
205
|
}
|
|
184
|
-
function
|
|
185
|
-
let { workspaceId: t } = e(), n = new URLSearchParams(window.location.search).get("taskId") ?? "", { data:
|
|
206
|
+
function k() {
|
|
207
|
+
let { workspaceId: t } = e(), n = new URLSearchParams(window.location.search).get("taskId") ?? "", { data: i, loading: a, error: o } = u(b, {
|
|
186
208
|
variables: { workItemId: n },
|
|
187
209
|
skip: !t || !n
|
|
188
210
|
});
|
|
189
|
-
if (
|
|
211
|
+
if (a) return /* @__PURE__ */ d("div", {
|
|
190
212
|
className: "flex items-center justify-center p-12",
|
|
191
|
-
children: /* @__PURE__ */
|
|
213
|
+
children: /* @__PURE__ */ d("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
|
|
192
214
|
});
|
|
193
|
-
if (
|
|
215
|
+
if (o) return /* @__PURE__ */ f("div", {
|
|
194
216
|
className: "p-6 text-red-500",
|
|
195
|
-
children: ["Error: ",
|
|
217
|
+
children: ["Error: ", o.message]
|
|
196
218
|
});
|
|
197
|
-
let
|
|
198
|
-
if (!
|
|
219
|
+
let s = i?.planmagnetWorkItem;
|
|
220
|
+
if (!s) return /* @__PURE__ */ d("div", {
|
|
199
221
|
className: "p-6 text-muted-foreground",
|
|
200
222
|
children: "Task not found."
|
|
201
223
|
});
|
|
202
|
-
let
|
|
224
|
+
let c = s.status.toLowerCase().replace("_", " "), l = [
|
|
203
225
|
{
|
|
204
226
|
action: "Task created",
|
|
205
|
-
by:
|
|
206
|
-
at:
|
|
227
|
+
by: s.reporterId ?? "Unknown",
|
|
228
|
+
at: s.createdAt
|
|
207
229
|
},
|
|
208
230
|
{
|
|
209
|
-
action: `Assigned to ${
|
|
210
|
-
by:
|
|
211
|
-
at:
|
|
231
|
+
action: `Assigned to ${s.assigneeId ?? "Unassigned"}`,
|
|
232
|
+
by: s.reporterId ?? "Unknown",
|
|
233
|
+
at: s.createdAt
|
|
212
234
|
},
|
|
213
235
|
{
|
|
214
|
-
action: `Status changed to ${
|
|
215
|
-
by:
|
|
216
|
-
at:
|
|
236
|
+
action: `Status changed to ${c}`,
|
|
237
|
+
by: s.assigneeId ?? "Unknown",
|
|
238
|
+
at: s.updatedAt
|
|
217
239
|
}
|
|
218
240
|
];
|
|
219
|
-
return /* @__PURE__ */
|
|
241
|
+
return /* @__PURE__ */ f("div", {
|
|
220
242
|
className: "space-y-6 p-6",
|
|
221
|
-
children: [/* @__PURE__ */
|
|
243
|
+
children: [/* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("h1", {
|
|
222
244
|
className: "text-2xl font-semibold",
|
|
223
|
-
children:
|
|
224
|
-
}), /* @__PURE__ */
|
|
245
|
+
children: s.title
|
|
246
|
+
}), /* @__PURE__ */ f("p", {
|
|
225
247
|
className: "text-sm text-muted-foreground",
|
|
226
248
|
children: [
|
|
227
|
-
|
|
249
|
+
s.key,
|
|
228
250
|
" · ",
|
|
229
|
-
|
|
251
|
+
s.type.toLowerCase()
|
|
230
252
|
]
|
|
231
|
-
})] }), /* @__PURE__ */
|
|
253
|
+
})] }), /* @__PURE__ */ f("div", {
|
|
232
254
|
className: "grid grid-cols-1 lg:grid-cols-3 gap-6",
|
|
233
|
-
children: [/* @__PURE__ */
|
|
255
|
+
children: [/* @__PURE__ */ f("div", {
|
|
234
256
|
className: "lg:col-span-2 space-y-6",
|
|
235
257
|
children: [
|
|
236
|
-
/* @__PURE__ */
|
|
258
|
+
/* @__PURE__ */ f(h, { children: [/* @__PURE__ */ d(_, { children: /* @__PURE__ */ d(v, { children: "Description" }) }), /* @__PURE__ */ d(g, { children: /* @__PURE__ */ d("p", {
|
|
237
259
|
className: "text-sm",
|
|
238
|
-
children:
|
|
260
|
+
children: s.description ?? "No description provided."
|
|
239
261
|
}) })] }),
|
|
240
|
-
/* @__PURE__ */
|
|
241
|
-
/* @__PURE__ */
|
|
262
|
+
/* @__PURE__ */ d(O, { workItemId: s.id }),
|
|
263
|
+
/* @__PURE__ */ d(r, { workItemId: s.id }),
|
|
264
|
+
/* @__PURE__ */ f(h, { children: [/* @__PURE__ */ d(_, { children: /* @__PURE__ */ d(v, { children: "Activity" }) }), /* @__PURE__ */ d(g, { children: /* @__PURE__ */ d("div", {
|
|
242
265
|
className: "space-y-3",
|
|
243
|
-
children:
|
|
266
|
+
children: l.map((e, t) => /* @__PURE__ */ f("div", {
|
|
244
267
|
className: "flex gap-3",
|
|
245
|
-
children: [/* @__PURE__ */
|
|
268
|
+
children: [/* @__PURE__ */ f("div", {
|
|
246
269
|
className: "flex flex-col items-center",
|
|
247
|
-
children: [/* @__PURE__ */
|
|
248
|
-
}), /* @__PURE__ */
|
|
270
|
+
children: [/* @__PURE__ */ d("div", { className: "h-2.5 w-2.5 rounded-full bg-primary mt-1.5" }), t < l.length - 1 && /* @__PURE__ */ d("div", { className: "w-px flex-1 bg-border" })]
|
|
271
|
+
}), /* @__PURE__ */ f("div", {
|
|
249
272
|
className: "pb-3",
|
|
250
|
-
children: [/* @__PURE__ */
|
|
273
|
+
children: [/* @__PURE__ */ d("p", {
|
|
251
274
|
className: "text-sm",
|
|
252
275
|
children: e.action
|
|
253
|
-
}), /* @__PURE__ */
|
|
276
|
+
}), /* @__PURE__ */ f("p", {
|
|
254
277
|
className: "text-xs text-muted-foreground",
|
|
255
278
|
children: [
|
|
256
279
|
e.by,
|
|
@@ -262,100 +285,100 @@ function D() {
|
|
|
262
285
|
}, t))
|
|
263
286
|
}) })] })
|
|
264
287
|
]
|
|
265
|
-
}), /* @__PURE__ */
|
|
288
|
+
}), /* @__PURE__ */ d("div", {
|
|
266
289
|
className: "space-y-6",
|
|
267
|
-
children: /* @__PURE__ */
|
|
290
|
+
children: /* @__PURE__ */ f(h, { children: [/* @__PURE__ */ d(_, { children: /* @__PURE__ */ d(v, { children: "Details" }) }), /* @__PURE__ */ f(g, {
|
|
268
291
|
className: "space-y-3 text-sm",
|
|
269
292
|
children: [
|
|
270
|
-
/* @__PURE__ */
|
|
293
|
+
/* @__PURE__ */ f("div", {
|
|
271
294
|
className: "flex justify-between",
|
|
272
|
-
children: [/* @__PURE__ */
|
|
295
|
+
children: [/* @__PURE__ */ d("span", {
|
|
273
296
|
className: "text-muted-foreground",
|
|
274
297
|
children: "Status"
|
|
275
|
-
}), /* @__PURE__ */
|
|
276
|
-
className: `text-xs px-2 py-0.5 rounded-full capitalize ${
|
|
277
|
-
children:
|
|
298
|
+
}), /* @__PURE__ */ d("span", {
|
|
299
|
+
className: `text-xs px-2 py-0.5 rounded-full capitalize ${E[s.status] ?? ""}`,
|
|
300
|
+
children: c
|
|
278
301
|
})]
|
|
279
302
|
}),
|
|
280
|
-
/* @__PURE__ */
|
|
303
|
+
/* @__PURE__ */ f("div", {
|
|
281
304
|
className: "flex justify-between",
|
|
282
|
-
children: [/* @__PURE__ */
|
|
305
|
+
children: [/* @__PURE__ */ d("span", {
|
|
283
306
|
className: "text-muted-foreground",
|
|
284
307
|
children: "Priority"
|
|
285
|
-
}), /* @__PURE__ */
|
|
286
|
-
className: `text-xs px-2 py-0.5 rounded-full capitalize ${
|
|
287
|
-
children:
|
|
308
|
+
}), /* @__PURE__ */ d("span", {
|
|
309
|
+
className: `text-xs px-2 py-0.5 rounded-full capitalize ${T[s.priority] ?? ""}`,
|
|
310
|
+
children: s.priority.toLowerCase()
|
|
288
311
|
})]
|
|
289
312
|
}),
|
|
290
|
-
/* @__PURE__ */
|
|
313
|
+
/* @__PURE__ */ f("div", {
|
|
291
314
|
className: "flex justify-between",
|
|
292
|
-
children: [/* @__PURE__ */
|
|
315
|
+
children: [/* @__PURE__ */ d("span", {
|
|
293
316
|
className: "text-muted-foreground",
|
|
294
317
|
children: "Type"
|
|
295
|
-
}), /* @__PURE__ */
|
|
318
|
+
}), /* @__PURE__ */ d(p, {
|
|
296
319
|
variant: "outline",
|
|
297
320
|
className: "capitalize",
|
|
298
|
-
children:
|
|
321
|
+
children: s.type.toLowerCase()
|
|
299
322
|
})]
|
|
300
323
|
}),
|
|
301
|
-
/* @__PURE__ */
|
|
324
|
+
/* @__PURE__ */ f("div", {
|
|
302
325
|
className: "flex justify-between",
|
|
303
|
-
children: [/* @__PURE__ */
|
|
326
|
+
children: [/* @__PURE__ */ d("span", {
|
|
304
327
|
className: "text-muted-foreground",
|
|
305
328
|
children: "Story Points"
|
|
306
|
-
}), /* @__PURE__ */
|
|
329
|
+
}), /* @__PURE__ */ d("span", {
|
|
307
330
|
className: "font-medium",
|
|
308
|
-
children:
|
|
331
|
+
children: s.storyPoints ?? 0
|
|
309
332
|
})]
|
|
310
333
|
}),
|
|
311
|
-
/* @__PURE__ */
|
|
334
|
+
/* @__PURE__ */ f("div", {
|
|
312
335
|
className: "flex justify-between",
|
|
313
|
-
children: [/* @__PURE__ */
|
|
336
|
+
children: [/* @__PURE__ */ d("span", {
|
|
314
337
|
className: "text-muted-foreground",
|
|
315
338
|
children: "Assignee"
|
|
316
|
-
}), /* @__PURE__ */
|
|
339
|
+
}), /* @__PURE__ */ d("span", { children: s.assigneeId ?? "Unassigned" })]
|
|
317
340
|
}),
|
|
318
|
-
/* @__PURE__ */
|
|
341
|
+
/* @__PURE__ */ f("div", {
|
|
319
342
|
className: "flex justify-between",
|
|
320
|
-
children: [/* @__PURE__ */
|
|
343
|
+
children: [/* @__PURE__ */ d("span", {
|
|
321
344
|
className: "text-muted-foreground",
|
|
322
345
|
children: "Reporter"
|
|
323
|
-
}), /* @__PURE__ */
|
|
346
|
+
}), /* @__PURE__ */ d("span", { children: s.reporterId ?? "Unknown" })]
|
|
324
347
|
}),
|
|
325
|
-
/* @__PURE__ */
|
|
348
|
+
/* @__PURE__ */ f("div", {
|
|
326
349
|
className: "flex justify-between",
|
|
327
|
-
children: [/* @__PURE__ */
|
|
350
|
+
children: [/* @__PURE__ */ d("span", {
|
|
328
351
|
className: "text-muted-foreground",
|
|
329
352
|
children: "Key"
|
|
330
|
-
}), /* @__PURE__ */
|
|
353
|
+
}), /* @__PURE__ */ d("span", { children: s.key })]
|
|
331
354
|
}),
|
|
332
|
-
/* @__PURE__ */
|
|
355
|
+
/* @__PURE__ */ f("div", {
|
|
333
356
|
className: "flex justify-between",
|
|
334
|
-
children: [/* @__PURE__ */
|
|
357
|
+
children: [/* @__PURE__ */ d("span", {
|
|
335
358
|
className: "text-muted-foreground",
|
|
336
359
|
children: "Due Date"
|
|
337
|
-
}), /* @__PURE__ */
|
|
360
|
+
}), /* @__PURE__ */ d("span", { children: s.dueDate ?? "Not set" })]
|
|
338
361
|
}),
|
|
339
|
-
/* @__PURE__ */
|
|
362
|
+
/* @__PURE__ */ f("div", {
|
|
340
363
|
className: "flex justify-between",
|
|
341
|
-
children: [/* @__PURE__ */
|
|
364
|
+
children: [/* @__PURE__ */ d("span", {
|
|
342
365
|
className: "text-muted-foreground",
|
|
343
366
|
children: "Created"
|
|
344
|
-
}), /* @__PURE__ */
|
|
367
|
+
}), /* @__PURE__ */ d("span", { children: s.createdAt })]
|
|
345
368
|
}),
|
|
346
|
-
/* @__PURE__ */
|
|
369
|
+
/* @__PURE__ */ f("div", {
|
|
347
370
|
className: "flex justify-between",
|
|
348
|
-
children: [/* @__PURE__ */
|
|
371
|
+
children: [/* @__PURE__ */ d("span", {
|
|
349
372
|
className: "text-muted-foreground",
|
|
350
373
|
children: "Updated"
|
|
351
|
-
}), /* @__PURE__ */
|
|
374
|
+
}), /* @__PURE__ */ d("span", { children: s.updatedAt })]
|
|
352
375
|
}),
|
|
353
|
-
/* @__PURE__ */
|
|
376
|
+
/* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("span", {
|
|
354
377
|
className: "text-muted-foreground text-xs",
|
|
355
378
|
children: "Labels"
|
|
356
|
-
}), /* @__PURE__ */
|
|
379
|
+
}), /* @__PURE__ */ d("div", {
|
|
357
380
|
className: "flex gap-1 mt-1 flex-wrap",
|
|
358
|
-
children: (
|
|
381
|
+
children: (s.labels ?? []).map((e) => /* @__PURE__ */ d("span", {
|
|
359
382
|
className: "text-xs px-2 py-0.5 rounded bg-muted",
|
|
360
383
|
children: e
|
|
361
384
|
}, e))
|
|
@@ -367,6 +390,6 @@ function D() {
|
|
|
367
390
|
});
|
|
368
391
|
}
|
|
369
392
|
//#endregion
|
|
370
|
-
export {
|
|
393
|
+
export { k as TasksTaskDetailPagePage };
|
|
371
394
|
|
|
372
395
|
//# 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 { 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 } 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 [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\n const docs = data?.planmagnetWorkItemDocs ?? [];\n\n const handleCreateAndLink = async () => {\n if (!newTitle.trim() || !newContent.trim()) return;\n const result = await createDoc({\n variables: { input: { title: newTitle.trim(), content: newContent.trim() } },\n });\n const docId = result.data?.planmagnetCreateDoc?.id;\n if (docId) {\n await linkDoc({ variables: { docId, workItemId } });\n }\n setNewTitle('');\n setNewContent('');\n setIsComposing(false);\n void refetch();\n };\n\n const handleUnlink = async (docId: string) => {\n await unlinkDoc({ variables: { docId, workItemId } });\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 {!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 <p className=\"text-sm font-medium truncate\">{doc.title}</p>\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 if (loading) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <div className=\"animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full\" />\n </div>\n );\n }\n\n if (error) {\n return <div className=\"p-6 text-red-500\">Error: {error.message}</div>;\n }\n\n const 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 const activityLog = [\n { action: 'Task created', by: task.reporterId ?? 'Unknown', at: task.createdAt },\n {\n action: `Assigned to ${task.assigneeId ?? 'Unassigned'}`,\n by: task.reporterId ?? 'Unknown',\n at: task.createdAt,\n },\n {\n action: `Status changed to ${statusDisplay}`,\n by: task.assigneeId ?? 'Unknown',\n at: task.updatedAt,\n },\n ];\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 <Card>\n <CardHeader>\n <CardTitle>Activity</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-3\">\n {activityLog.map((a, i) => (\n <div key={i} className=\"flex gap-3\">\n <div className=\"flex flex-col items-center\">\n <div className=\"h-2.5 w-2.5 rounded-full bg-primary mt-1.5\" />\n {i < activityLog.length - 1 && <div className=\"w-px flex-1 bg-border\" />}\n </div>\n <div className=\"pb-3\">\n <p className=\"text-sm\">{a.action}</p>\n <p className=\"text-xs text-muted-foreground\">\n {a.by} · {a.at}\n </p>\n </div>\n </div>\n ))}\n </div>\n </CardContent>\n </Card>\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 { 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 } 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 [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 <p className=\"text-sm font-medium truncate\">{doc.title}</p>\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 if (loading) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <div className=\"animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full\" />\n </div>\n );\n }\n\n if (error) {\n return <div className=\"p-6 text-red-500\">Error: {error.message}</div>;\n }\n\n const 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 const activityLog = [\n { action: 'Task created', by: task.reporterId ?? 'Unknown', at: task.createdAt },\n {\n action: `Assigned to ${task.assigneeId ?? 'Unassigned'}`,\n by: task.reporterId ?? 'Unknown',\n at: task.createdAt,\n },\n {\n action: `Status changed to ${statusDisplay}`,\n by: task.assigneeId ?? 'Unknown',\n at: task.updatedAt,\n },\n ];\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 <Card>\n <CardHeader>\n <CardTitle>Activity</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-3\">\n {activityLog.map((a, i) => (\n <div key={i} className=\"flex gap-3\">\n <div className=\"flex flex-col items-center\">\n <div className=\"h-2.5 w-2.5 rounded-full bg-primary mt-1.5\" />\n {i < activityLog.length - 1 && <div className=\"w-px flex-1 bg-border\" />}\n </div>\n <div className=\"pb-3\">\n <p className=\"text-sm\">{a.action}</p>\n <p className=\"text-xs text-muted-foreground\">\n {a.by} · {a.at}\n </p>\n </div>\n </div>\n ))}\n </div>\n </CardContent>\n </Card>\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":";;;;;;;;;;;AAoBA,IAAM,IAAgB,CAAG;;;;;;;;;;;;;;;;;;;;;;GAwBnB,IAAqB,CAAG;;;;;;;;;;GAYxB,IAAa,CAAG;;;;;;GAQhB,IAAwB,CAAG;;;;;;GAQ3B,IAA4B,CAAG;;;;GAkC/B,IAAwC;CAC5C,KAAK;CACL,QAAQ;CACR,MAAM;CACN,UAAU;CACX,EAEK,IAAsC;CAC1C,SAAS;CACT,MAAM;CACN,aAAa;CACb,WAAW;CACX,MAAM;CACN,SAAS;CACT,SAAS;CACT,WAAW;CACZ,EAEK,IAAyC;CAC7C,OAAO;CACP,WAAW;CACX,UAAU;CACX;AAUD,SAAS,EAAgB,EAAE,iBAAsC;CAC/D,IAAM,CAAC,GAAa,KAAkB,EAAS,GAAM,EAC/C,CAAC,GAAU,KAAe,EAAS,GAAG,EACtC,CAAC,GAAY,KAAiB,EAAS,GAAG,EAE1C,EAAE,SAAM,YAAS,UAAO,eAAY,EAEvC,GAAoB;EACrB,WAAW,EAAE,eAAY;EACzB,MAAM,CAAC;EACR,CAAC,EAEI,CAAC,GAAW,EAAE,SAAS,OAAc,EAAY,EAAW,EAC5D,CAAC,KAAW,EAAY,EAAsB,EAC9C,CAAC,GAAW,EAAE,SAAS,OAAe,EAAY,EAA0B,EAG5E,CAAC,GAAa,KAAkB,EAAwB,KAAK,EAE7D,IAAO,GAAM,0BAA0B,EAAE,EAEzC,IAAsB,YAAY;AAClC,SAAC,EAAS,MAAM,IAAI,CAAC,EAAW,MAAM,GAC1C;KAAe,KAAK;AACpB,OAAI;IAIF,IAAM,KAHS,MAAM,EACnB,EAAU,EAAE,WAAW,EAAE,OAAO;KAAE,OAAO,EAAS,MAAM;KAAE,SAAS,EAAW,MAAM;KAAE,EAAE,EAAE,CAAC,CAC5F,EACoB,MAAM,qBAAqB;AAChD,IAAI,KACF,MAAM,EAAa,EAAQ,EAAE,WAAW;KAAE;KAAO;KAAY,EAAE,CAAC,CAAC;YAE5D,GAAG;AACV,MAAe,aAAa,QAAQ,EAAE,UAAU,8BAA8B;AAC9E;;AAKG,GAHL,EAAY,GAAG,EACf,EAAc,GAAG,EACjB,EAAe,GAAM,EAChB,GAAS;;IAGV,IAAe,OAAO,MAAkB;AAC5C,IAAe,KAAK;AACpB,MAAI;AACF,SAAM,EAAa,EAAU,EAAE,WAAW;IAAE;IAAO;IAAY,EAAE,CAAC,CAAC;WAC5D,GAAG;AACV,KAAe,aAAa,QAAQ,EAAE,UAAU,iCAAiC;AACjF;;AAEG,KAAS;;AAGhB,QACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;EAAY,WAAU;YAAtB,CACE,kBAAC,GAAD,EAAA,UAAW,eAAuB,CAAA,EACjC,CAAC,KACA,kBAAC,GAAD;GAAQ,MAAK;GAAK,SAAQ;GAAU,eAAe,EAAe,GAAK;aAAvE,CACE,kBAAC,GAAD,EAAM,WAAU,gBAAiB,CAAA,EAAA,UAE1B;KAEA;KACb,kBAAC,GAAD;EAAa,WAAU;YAAvB;GACG,KACC,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MACE,aAAY;MACZ,OAAO;MACP,WAAW,MAAM,EAAY,EAAE,OAAO,MAAM;MAC5C,CAAA;KACF,kBAAC,GAAD;MACE,OAAO;MACP,UAAU;MACV,aAAY;MACZ,WAAW;MACX,CAAA;KACF,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD;OACE,MAAK;OACL,SAAQ;OACR,eAAe;AAGb,QAFA,EAAe,GAAM,EACrB,EAAY,GAAG,EACf,EAAc,GAAG;;iBAEpB;OAEQ,CAAA,EACT,kBAAC,GAAD;OACE,MAAK;OACL,UAAU,KAAY,CAAC,EAAS,MAAM,IAAI,CAAC,EAAW,MAAM;OAC5D,SAAS;iBAER,IAAW,gBAAgB;OACrB,CAAA,CACL;;KACF;;GAGP,KAAW,kBAAC,KAAD;IAAG,WAAU;cAAgC;IAAmB,CAAA;GAC3E,KAAS,kBAAC,KAAD;IAAG,WAAU;cAAb,CAAoC,WAAQ,EAAM,QAAY;;GACvE,KACC,kBAAC,KAAD;IAAG,MAAK;IAAQ,WAAU;cACvB;IACC,CAAA;GAEL,CAAC,KAAW,CAAC,KAAS,EAAK,WAAW,KAAK,CAAC,KAC3C,kBAAC,KAAD;IAAG,WAAU;cAAgC;IAAyC,CAAA;GAEvF,EAAK,KAAK,MACT,kBAAC,OAAD;IAEE,WAAU;cAFZ,CAIE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAU,WAAU,0CAA2C,CAAA,EAC/D,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,KAAD;OAAG,WAAU;iBAAgC,EAAI;OAAU,CAAA,EAC3D,kBAAC,KAAD;OAAG,WAAU;iBAAb,CAA6C,KAAE,EAAI,QAAY;SAC3D;QACF;QACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,QAAD;MACE,WAAW,+CAA+C,EAAe,EAAI,WAAW;gBAEvF,EAAI,OAAO,aAAa;MACpB,CAAA,EACP,kBAAC,GAAD;MACE,MAAK;MACL,SAAQ;MACR,UAAU;MACV,eAAe,EAAa,EAAI,GAAG;MACnC,cAAY,UAAU,EAAI;gBAE1B,kBAAC,GAAD,EAAG,WAAU,WAAY,CAAA;MAClB,CAAA,CACL;OACF;MA1BC,EAAI,GA0BL,CACN;GACU;IACT,EAAA,CAAA;;AAIX,SAAgB,IAA0B;CACxC,IAAM,EAAE,mBAAgB,GAAe,EAGjC,IAAa,IAAI,gBAAgB,OAAO,SAAS,OAAO,CAAC,IAAI,SAAS,IAAI,IAE1E,EAAE,SAAM,YAAS,aAAU,EAE9B,GAAe;EAChB,WAAW,EAAE,eAAY;EACzB,MAAM,CAAC,KAAe,CAAC;EACxB,CAAC;AAEF,KAAI,EACF,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD,EAAK,WAAU,kFAAmF,CAAA;EAC9F,CAAA;AAIV,KAAI,EACF,QAAO,kBAAC,OAAD;EAAK,WAAU;YAAf,CAAkC,WAAQ,EAAM,QAAc;;CAGvE,IAAM,IAAO,GAAM;AACnB,KAAI,CAAC,EAAM,QAAO,kBAAC,OAAD;EAAK,WAAU;YAA4B;EAAqB,CAAA;CAElF,IAAM,IAAgB,EAAK,OAAO,aAAa,CAAC,QAAQ,KAAK,IAAI,EAE3D,IAAc;EAClB;GAAE,QAAQ;GAAgB,IAAI,EAAK,cAAc;GAAW,IAAI,EAAK;GAAW;EAChF;GACE,QAAQ,eAAe,EAAK,cAAc;GAC1C,IAAI,EAAK,cAAc;GACvB,IAAI,EAAK;GACV;EACD;GACE,QAAQ,qBAAqB;GAC7B,IAAI,EAAK,cAAc;GACvB,IAAI,EAAK;GACV;EACF;AAED,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;GAAI,WAAU;aAA0B,EAAK;GAAW,CAAA,EACxD,kBAAC,KAAD;GAAG,WAAU;aAAb;IACG,EAAK;IAAI;IAAW,EAAK,KAAK,aAAa;IAC1C;KACA,EAAA,CAAA,EACN,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAW,eAAuB,CAAA,EACvB,CAAA,EACb,kBAAC,GAAD,EAAA,UACE,kBAAC,KAAD;MAAG,WAAU;gBAAW,EAAK,eAAe;MAA+B,CAAA,EAC/D,CAAA,CACT,EAAA,CAAA;KACP,kBAAC,GAAD,EAAiB,YAAY,EAAK,IAAM,CAAA;KACxC,kBAAC,GAAD,EAAkB,YAAY,EAAK,IAAM,CAAA;KACzC,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAW,YAAoB,CAAA,EACpB,CAAA,EACb,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;MAAK,WAAU;gBACZ,EAAY,KAAK,GAAG,MACnB,kBAAC,OAAD;OAAa,WAAU;iBAAvB,CACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD,EAAK,WAAU,8CAA+C,CAAA,EAC7D,IAAI,EAAY,SAAS,KAAK,kBAAC,OAAD,EAAK,WAAU,yBAA0B,CAAA,CACpE;WACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,KAAD;SAAG,WAAU;mBAAW,EAAE;SAAW,CAAA,EACrC,kBAAC,KAAD;SAAG,WAAU;mBAAb;UACG,EAAE;UAAG;UAAW,EAAE;UACjB;WACA;UACF;SAXI,EAWJ,CACN;MACE,CAAA,EACM,CAAA,CACT,EAAA,CAAA;KACH;OACN,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAW,WAAmB,CAAA,EACnB,CAAA,EACb,kBAAC,GAAD;KAAa,WAAU;eAAvB;MACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD;QAAM,WAAU;kBAAwB;QAAa,CAAA,EACrD,kBAAC,QAAD;QACE,WAAW,+CAA+C,EAAY,EAAK,WAAW;kBAErF;QACI,CAAA,CACH;;MACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD;QAAM,WAAU;kBAAwB;QAAe,CAAA,EACvD,kBAAC,QAAD;QACE,WAAW,+CAA+C,EAAc,EAAK,aAAa;kBAEzF,EAAK,SAAS,aAAa;QACvB,CAAA,CACH;;MACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD;QAAM,WAAU;kBAAwB;QAAW,CAAA,EACnD,kBAAC,GAAD;QAAO,SAAQ;QAAU,WAAU;kBAChC,EAAK,KAAK,aAAa;QAClB,CAAA,CACJ;;MACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD;QAAM,WAAU;kBAAwB;QAAmB,CAAA,EAC3D,kBAAC,QAAD;QAAM,WAAU;kBAAe,EAAK,eAAe;QAAS,CAAA,CACxD;;MACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD;QAAM,WAAU;kBAAwB;QAAe,CAAA,EACvD,kBAAC,QAAD,EAAA,UAAO,EAAK,cAAc,cAAoB,CAAA,CAC1C;;MACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD;QAAM,WAAU;kBAAwB;QAAe,CAAA,EACvD,kBAAC,QAAD,EAAA,UAAO,EAAK,cAAc,WAAiB,CAAA,CACvC;;MACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD;QAAM,WAAU;kBAAwB;QAAU,CAAA,EAClD,kBAAC,QAAD,EAAA,UAAO,EAAK,KAAW,CAAA,CACnB;;MACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD;QAAM,WAAU;kBAAwB;QAAe,CAAA,EACvD,kBAAC,QAAD,EAAA,UAAO,EAAK,WAAW,WAAiB,CAAA,CACpC;;MACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD;QAAM,WAAU;kBAAwB;QAAc,CAAA,EACtD,kBAAC,QAAD,EAAA,UAAO,EAAK,WAAiB,CAAA,CACzB;;MACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD;QAAM,WAAU;kBAAwB;QAAc,CAAA,EACtD,kBAAC,QAAD,EAAA,UAAO,EAAK,WAAiB,CAAA,CACzB;;MACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,QAAD;OAAM,WAAU;iBAAgC;OAAa,CAAA,EAC7D,kBAAC,OAAD;OAAK,WAAU;kBACX,EAAK,UAAU,EAAE,EAAE,KAAK,MACxB,kBAAC,QAAD;QAAc,WAAU;kBACrB;QACI,EAFI,EAEJ,CACP;OACE,CAAA,CACF,EAAA,CAAA;MACM;OACT,EAAA,CAAA;IACH,CAAA,CACF;KACF"}
|