@burdenoff/microfe-planmagnet 2026.930.24 → 2026.930.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/planmagnet/comments/CommentThread.d.ts +8 -1
  2. package/dist/planmagnet/comments/CommentThread.d.ts.map +1 -1
  3. package/dist/planmagnet/comments/CommentThread.js +188 -181
  4. package/dist/planmagnet/comments/CommentThread.js.map +1 -1
  5. package/dist/planmagnet/comments/TargetComments.d.ts +10 -2
  6. package/dist/planmagnet/comments/TargetComments.d.ts.map +1 -1
  7. package/dist/planmagnet/comments/TargetComments.js +10 -8
  8. package/dist/planmagnet/comments/TargetComments.js.map +1 -1
  9. package/dist/planmagnet/comments/WorkItemComments.d.ts +7 -1
  10. package/dist/planmagnet/comments/WorkItemComments.d.ts.map +1 -1
  11. package/dist/planmagnet/comments/WorkItemComments.js +5 -4
  12. package/dist/planmagnet/comments/WorkItemComments.js.map +1 -1
  13. package/dist/planmagnet/discussion/WorkItemDiscussionPanel.d.ts +8 -0
  14. package/dist/planmagnet/discussion/WorkItemDiscussionPanel.d.ts.map +1 -0
  15. package/dist/planmagnet/discussion/WorkItemDiscussionPanel.js +217 -0
  16. package/dist/planmagnet/discussion/WorkItemDiscussionPanel.js.map +1 -0
  17. package/dist/planmagnet/docs/DocDiffView.d.ts +26 -0
  18. package/dist/planmagnet/docs/DocDiffView.d.ts.map +1 -0
  19. package/dist/planmagnet/docs/DocDiffView.js +52 -0
  20. package/dist/planmagnet/docs/DocDiffView.js.map +1 -0
  21. package/dist/planmagnet/docs/DocSuggestionsPanel.d.ts +13 -0
  22. package/dist/planmagnet/docs/DocSuggestionsPanel.d.ts.map +1 -0
  23. package/dist/planmagnet/docs/DocSuggestionsPanel.js +308 -0
  24. package/dist/planmagnet/docs/DocSuggestionsPanel.js.map +1 -0
  25. package/dist/planmagnet/docs/DocVersionCompare.d.ts +7 -0
  26. package/dist/planmagnet/docs/DocVersionCompare.d.ts.map +1 -0
  27. package/dist/planmagnet/docs/DocVersionCompare.js +105 -0
  28. package/dist/planmagnet/docs/DocVersionCompare.js.map +1 -0
  29. package/dist/planmagnet/hooks/usePresence.d.ts +39 -0
  30. package/dist/planmagnet/hooks/usePresence.d.ts.map +1 -0
  31. package/dist/planmagnet/hooks/usePresence.js +146 -0
  32. package/dist/planmagnet/hooks/usePresence.js.map +1 -0
  33. package/dist/planmagnet/links/CodeLinksPanel.d.ts +22 -0
  34. package/dist/planmagnet/links/CodeLinksPanel.d.ts.map +1 -0
  35. package/dist/planmagnet/links/CodeLinksPanel.js +94 -0
  36. package/dist/planmagnet/links/CodeLinksPanel.js.map +1 -0
  37. package/dist/planmagnet/pages/DocsDocDetailPagePage.d.ts.map +1 -1
  38. package/dist/planmagnet/pages/DocsDocDetailPagePage.js +488 -217
  39. package/dist/planmagnet/pages/DocsDocDetailPagePage.js.map +1 -1
  40. package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.d.ts.map +1 -1
  41. package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js +136 -130
  42. package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js.map +1 -1
  43. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.d.ts.map +1 -1
  44. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js +205 -196
  45. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js.map +1 -1
  46. package/dist/planmagnet/pages/TasksTaskDetailPagePage.d.ts.map +1 -1
  47. package/dist/planmagnet/pages/TasksTaskDetailPagePage.js +194 -160
  48. package/dist/planmagnet/pages/TasksTaskDetailPagePage.js.map +1 -1
  49. package/dist/planmagnet/presence/PresenceAvatars.d.ts +16 -0
  50. package/dist/planmagnet/presence/PresenceAvatars.d.ts.map +1 -0
  51. package/dist/planmagnet/presence/PresenceAvatars.js +56 -0
  52. package/dist/planmagnet/presence/PresenceAvatars.js.map +1 -0
  53. package/dist/planmagnet/utils/graphqlErrors.d.ts +6 -0
  54. package/dist/planmagnet/utils/graphqlErrors.d.ts.map +1 -1
  55. package/dist/planmagnet/utils/graphqlErrors.js +5 -2
  56. package/dist/planmagnet/utils/graphqlErrors.js.map +1 -1
  57. package/dist/planmagnet/utils/lineDiff.d.ts +21 -0
  58. package/dist/planmagnet/utils/lineDiff.d.ts.map +1 -0
  59. package/dist/planmagnet/utils/lineDiff.js +36 -0
  60. package/dist/planmagnet/utils/lineDiff.js.map +1 -0
  61. package/package.json +1 -1
@@ -1,21 +1,26 @@
1
- import { usePlanMagnetNavigate as e } from "../providers/PlanMagnetProvider.js";
2
- import { PersonName as t } from "../people/People.js";
3
- import { LEAVES_PAGE_CONTEXT as n, throwOnError as ee } from "../utils/mutationResult.js";
4
- import { WorkItemSearchSelect as te } from "../controls/Pickers.js";
5
- import { MarkdownEditor as ne } from "../../components/MarkdownEditor.js";
6
- import { DOC_STATUSES as re, DocStatusBadge as ie } from "../docs/DocStatusBadge.js";
7
- import { DocComments as ae } from "../comments/TargetComments.js";
8
- import { useState as r } from "react";
9
- import { ArrowLeft as oe, History as se, Link2 as i, X as ce } from "lucide-react";
10
- import { useSearchParams as le } from "react-router";
11
- import { gql as a } from "@apollo/client";
12
- import { useApolloClient as ue, useMutation as o, useQuery as de } from "@apollo/client/react";
13
- import { jsx as s, jsxs as c } from "react/jsx-runtime";
14
- import { AlertDialog as l, AlertDialogAction as u, AlertDialogCancel as d, AlertDialogContent as f, AlertDialogDescription as p, AlertDialogFooter as m, AlertDialogHeader as h, AlertDialogTitle as g, AlertDialogTrigger as _, Button as v, Card as y, CardContent as b, CardHeader as x, CardTitle as S, Input as C } from "@burdenoff/fe-libs/ui";
15
- import { clearGraphqlFetchResponseCache as fe } from "@burdenoff/fe-libs/shared/graphql";
16
- import { Markdown as w } from "@burdenoff/fe-libs/shared/components";
1
+ import { usePlanMagnet as e, usePlanMagnetNavigate as t } from "../providers/PlanMagnetProvider.js";
2
+ import { PersonName as n } from "../people/People.js";
3
+ import { LEAVES_PAGE_CONTEXT as ee, throwOnError as r } from "../utils/mutationResult.js";
4
+ import { isForbidden as i, mutationErrorMessage as a } from "../utils/graphqlErrors.js";
5
+ import { WorkItemSearchSelect as o } from "../controls/Pickers.js";
6
+ import { MarkdownEditor as s } from "../../components/MarkdownEditor.js";
7
+ import { DOC_STATUSES as te, DocStatusBadge as ne } from "../docs/DocStatusBadge.js";
8
+ import { PresenceAvatars as re } from "../presence/PresenceAvatars.js";
9
+ import { DocComments as ie } from "../comments/TargetComments.js";
10
+ import { usePresence as ae } from "../hooks/usePresence.js";
11
+ import { DocSuggestionsPanel as oe } from "../docs/DocSuggestionsPanel.js";
12
+ import { DocVersionCompare as se } from "../docs/DocVersionCompare.js";
13
+ import { useEffect as c, useRef as ce, useState as l } from "react";
14
+ import { ArrowLeft as le, History as ue, Link2 as de, Lock as u, X as fe } from "lucide-react";
15
+ import { useSearchParams as pe } from "react-router";
16
+ import { gql as d } from "@apollo/client";
17
+ import { useApolloClient as me, useMutation as f, useQuery as he, useSubscription as ge } from "@apollo/client/react";
18
+ import { jsx as p, jsxs as m } from "react/jsx-runtime";
19
+ import { AlertDialog as _e, AlertDialogAction as h, AlertDialogCancel as g, AlertDialogContent as _, AlertDialogDescription as ve, AlertDialogFooter as ye, AlertDialogHeader as be, AlertDialogTitle as xe, AlertDialogTrigger as Se, Button as v, Card as y, CardContent as b, CardHeader as x, CardTitle as S, Input as C } from "@burdenoff/fe-libs/ui";
20
+ import { clearGraphqlFetchResponseCache as w } from "@burdenoff/fe-libs/shared/graphql";
21
+ import { Markdown as T } from "@burdenoff/fe-libs/shared/components";
17
22
  //#region src/planmagnet/pages/DocsDocDetailPagePage.tsx
18
- var T = a`
23
+ var E = d`
19
24
  query DocDetail($id: ID!) {
20
25
  planmagnetDoc(id: $id) {
21
26
  id
@@ -27,6 +32,11 @@ var T = a`
27
32
  createdAt
28
33
  updatedBy
29
34
  updatedAt
35
+ lock {
36
+ holderId
37
+ acquiredAt
38
+ expiresAt
39
+ }
30
40
  revisions {
31
41
  id
32
42
  version
@@ -43,7 +53,7 @@ var T = a`
43
53
  }
44
54
  }
45
55
  }
46
- `, pe = a`
56
+ `, Ce = d`
47
57
  mutation DocUpdate($id: ID!, $input: PlanmagnetUpdateDocInput!) {
48
58
  planmagnetUpdateDoc(id: $id, input: $input) {
49
59
  id
@@ -51,131 +61,302 @@ var T = a`
51
61
  status
52
62
  }
53
63
  }
54
- `, me = a`
64
+ `, we = d`
55
65
  mutation DocRevert($id: ID!, $toVersion: Int!, $expectedVersion: Int) {
56
66
  planmagnetRevertDoc(id: $id, toVersion: $toVersion, expectedVersion: $expectedVersion) {
57
67
  id
58
68
  version
59
69
  }
60
70
  }
61
- `, he = a`
71
+ `, Te = d`
62
72
  mutation DocDelete($id: ID!) {
63
73
  planmagnetDeleteDoc(id: $id)
64
74
  }
65
- `, ge = a`
75
+ `, Ee = d`
66
76
  mutation DocLinkWorkItem($docId: ID!, $workItemId: ID!) {
67
77
  planmagnetLinkDocToWorkItem(docId: $docId, workItemId: $workItemId) {
68
78
  id
69
79
  }
70
80
  }
71
- `, _e = a`
81
+ `, De = d`
72
82
  mutation DocUnlinkWorkItem($docId: ID!, $workItemId: ID!) {
73
83
  planmagnetUnlinkDocFromWorkItem(docId: $docId, workItemId: $workItemId)
74
84
  }
75
- `, E = (e, t) => e instanceof Error ? e.message : t, D = (e) => new Date(e).toLocaleString();
76
- function O() {
77
- let [a] = le(), O = a.get("docId") ?? "", k = e(), [A, j] = r(!1), [M, N] = r(""), [P, F] = r(""), [I, L] = r(""), [R, z] = r(null), [B, ve] = r(null), [V, ye] = r(null), { data: H, loading: be, error: U } = de(T, {
78
- variables: { id: O },
79
- skip: !O,
85
+ `, Oe = d`
86
+ mutation DocCheckout($docId: ID!) {
87
+ planmagnetCheckoutDoc(docId: $docId) {
88
+ id
89
+ lock {
90
+ holderId
91
+ acquiredAt
92
+ expiresAt
93
+ }
94
+ }
95
+ }
96
+ `, D = d`
97
+ mutation DocReleaseLock($docId: ID!) {
98
+ planmagnetReleaseDoc(docId: $docId) {
99
+ id
100
+ lock {
101
+ holderId
102
+ acquiredAt
103
+ expiresAt
104
+ }
105
+ }
106
+ }
107
+ `, ke = d`
108
+ mutation DocBreakLock($docId: ID!) {
109
+ planmagnetBreakDocLock(docId: $docId) {
110
+ id
111
+ lock {
112
+ holderId
113
+ acquiredAt
114
+ expiresAt
115
+ }
116
+ }
117
+ }
118
+ `, Ae = d`
119
+ mutation DocSuggestEdit($input: PlanmagnetSuggestDocEditInput!) {
120
+ planmagnetSuggestDocEdit(input: $input) {
121
+ id
122
+ status
123
+ }
124
+ }
125
+ `, je = d`
126
+ subscription PlanmagnetOnDocUpdatedFeed($docId: ID!, $workspaceId: ID!) {
127
+ planmagnetOnDocUpdated(docId: $docId, workspaceId: $workspaceId) {
128
+ id
129
+ kind
130
+ actorId
131
+ changedFields
132
+ at
133
+ }
134
+ }
135
+ `, Me = (e, t) => e instanceof Error ? e.message : t, O = (e) => new Date(e).toLocaleString();
136
+ function Ne({ lock: e, currentUserId: t, now: ee, onBreakLock: r, breaking: i }) {
137
+ let a = e.holderId === t, o = Math.max(0, Math.round((new Date(e.expiresAt).getTime() - ee) / 6e4)), s = new Date(e.expiresAt).toLocaleTimeString([], {
138
+ hour: "2-digit",
139
+ minute: "2-digit"
140
+ });
141
+ return a ? /* @__PURE__ */ m("p", {
142
+ role: "status",
143
+ "data-testid": "doc-lock-status",
144
+ className: "flex items-center gap-1.5 text-sm text-status-warning-text",
145
+ children: [
146
+ /* @__PURE__ */ p(u, {
147
+ className: "h-3.5 w-3.5",
148
+ "aria-hidden": "true"
149
+ }),
150
+ "You are editing — lock expires in ",
151
+ o,
152
+ " min."
153
+ ]
154
+ }) : /* @__PURE__ */ m("div", {
155
+ "data-testid": "doc-lock-status",
156
+ className: "flex flex-wrap items-center justify-between gap-2 rounded-md border border-status-warning-border bg-status-warning-subtle p-2",
157
+ children: [/* @__PURE__ */ m("p", {
158
+ className: "flex items-center gap-1.5 text-sm text-status-warning-text",
159
+ children: [
160
+ /* @__PURE__ */ p(u, {
161
+ className: "h-3.5 w-3.5",
162
+ "aria-hidden": "true"
163
+ }),
164
+ "Being edited by ",
165
+ /* @__PURE__ */ p(n, { id: e.holderId }),
166
+ " until ",
167
+ s,
168
+ "."
169
+ ]
170
+ }), /* @__PURE__ */ p(v, {
171
+ size: "sm",
172
+ variant: "outline",
173
+ disabled: i,
174
+ onClick: r,
175
+ "data-testid": "doc-break-lock",
176
+ children: i ? "Breaking…" : "Break lock"
177
+ })]
178
+ });
179
+ }
180
+ function k() {
181
+ let [u] = pe(), d = u.get("docId") ?? "", k = t(), { workspaceId: A, currentUser: j } = e(), [M, N] = l("view"), [P, Pe] = l(""), [Fe, Ie] = l(""), [F, Le] = l(""), [Re, I] = l(null), [L, ze] = l(null), [R, Be] = l(null), [z, Ve] = l(""), [B, He] = l(""), [V, Ue] = l(""), [We, H] = l(null), [Ge, Ke] = l(null), [qe, Je] = l(""), U = ae("DOC", d || null), { data: Ye, loading: Xe, error: Ze } = he(E, {
182
+ variables: { id: d },
183
+ skip: !d,
80
184
  fetchPolicy: "cache-and-network"
81
- }), xe = ue(), W = {
185
+ }), W = me(), G = {
82
186
  refetchQueries: ["DocDetail"],
83
187
  awaitRefetchQueries: !0
84
- }, [G, K] = o(pe, W), [Se, Ce] = o(me, W), [we, Te] = o(he, {
188
+ }, [Qe, K] = f(Ce, G), [$e, et] = f(we, G), [tt, nt] = f(Te, {
85
189
  refetchQueries: ["DocsList"],
86
- context: n
87
- }), [Ee, De] = o(_e, W), [Oe, ke] = o(ge, {
88
- ...W,
190
+ context: ee
191
+ }), [rt, it] = f(De, G), [at, ot] = f(Ee, {
192
+ ...G,
89
193
  refetchQueries: ["DocDetail", "GetWorkItemDocs"]
90
- }), [q, J] = r(""), Y = H?.planmagnetDoc, X = K.loading || Ce.loading || Te.loading, Z = async (e, t) => {
91
- z(null);
194
+ }), [q, st] = l(""), [ct, lt] = f(Oe, G), [ut] = f(D, G), [dt, ft] = f(ke, G), [pt, J] = f(Ae, {
195
+ refetchQueries: ["DocDetail", "DocSuggestionsPanel"],
196
+ awaitRefetchQueries: !0
197
+ }), Y = Ye?.planmagnetDoc, X = K.loading || et.loading || nt.loading, [mt, ht] = l(() => Date.now());
198
+ c(() => {
199
+ if (M !== "edit") return;
200
+ let e = setInterval(() => ht(Date.now()), 3e4);
201
+ return () => clearInterval(e);
202
+ }, [M]), c(() => {
203
+ if (M !== "edit" || !d) return;
204
+ let e = setInterval(() => {
205
+ ct({ variables: { docId: d } }).catch(() => void 0);
206
+ }, 5 * 6e4);
207
+ return () => clearInterval(e);
208
+ }, [M, d]);
209
+ let gt = ce(!1);
210
+ c(() => {
211
+ gt.current = M === "edit";
212
+ }, [M]), c(() => () => {
213
+ gt.current && d && W.mutate({
214
+ mutation: D,
215
+ variables: { docId: d }
216
+ }).catch(() => void 0);
217
+ }, []), ge(je, {
218
+ variables: {
219
+ docId: d,
220
+ workspaceId: A ?? ""
221
+ },
222
+ skip: !d || !A,
223
+ onData: () => {
224
+ w(), W.query({
225
+ query: E,
226
+ variables: { id: d },
227
+ fetchPolicy: "network-only"
228
+ }).catch(() => void 0);
229
+ },
230
+ onError: (e) => {
231
+ console.debug("[DocsDocDetailPagePage] doc subscription unavailable:", { message: e instanceof Error ? e.message : String(e) });
232
+ }
233
+ });
234
+ let Z = async (e, t) => {
235
+ I(null);
92
236
  try {
93
- return await ee(e()), !0;
237
+ return await r(e()), !0;
94
238
  } catch (e) {
95
- return z(E(e, t)), fe(), await xe.query({
96
- query: T,
97
- variables: { id: O },
239
+ return I(Me(e, t)), w(), await W.query({
240
+ query: E,
241
+ variables: { id: d },
98
242
  fetchPolicy: "network-only"
99
243
  }).catch(() => void 0), !1;
100
244
  }
101
245
  };
102
- if (!O) return /* @__PURE__ */ s("div", {
246
+ if (!d) return /* @__PURE__ */ p("div", {
103
247
  className: "p-6 text-sm text-muted-foreground",
104
248
  children: "No doc selected."
105
249
  });
106
- if (be && !H) return /* @__PURE__ */ s("div", {
250
+ if (Xe && !Ye) return /* @__PURE__ */ p("div", {
107
251
  className: "p-6 text-sm text-muted-foreground",
108
252
  children: "Loading doc…"
109
253
  });
110
- if (U && !Y) return /* @__PURE__ */ c("p", {
254
+ if (Ze && !Y) return /* @__PURE__ */ m("p", {
111
255
  role: "alert",
112
256
  className: "p-6 text-sm text-destructive",
113
- children: ["The doc could not be loaded: ", U.message]
257
+ children: ["The doc could not be loaded: ", Ze.message]
114
258
  });
115
- if (!Y) return /* @__PURE__ */ c("div", {
259
+ if (!Y) return /* @__PURE__ */ m("div", {
116
260
  className: "space-y-3 p-6",
117
- children: [/* @__PURE__ */ s("p", {
261
+ children: [/* @__PURE__ */ p("p", {
118
262
  className: "text-sm text-muted-foreground",
119
263
  children: "This doc does not exist in this workspace, or it was deleted."
120
- }), /* @__PURE__ */ s(v, {
264
+ }), /* @__PURE__ */ p(v, {
121
265
  size: "sm",
122
266
  variant: "outline",
123
267
  onClick: () => k("/docs/docs-page"),
124
268
  children: "Back to docs"
125
269
  })]
126
270
  });
127
- let Ae = () => {
128
- N(Y.title), F(Y.content), L(""), z(null), ye(Y.version), j(!0);
129
- }, je = async () => {
130
- await Z(() => G({ variables: {
271
+ let _t = async () => {
272
+ I(null);
273
+ try {
274
+ await r(ct({ variables: { docId: Y.id } }));
275
+ } catch (e) {
276
+ I(i(e) ? "Your role cannot edit this doc." : a(e, "The doc could not be checked out for editing."));
277
+ return;
278
+ }
279
+ Pe(Y.title), Ie(Y.content), Le(""), Be(Y.version), N("edit");
280
+ }, vt = () => {
281
+ N("view"), I(null), ut({ variables: { docId: Y.id } }).catch(() => void 0);
282
+ }, yt = async () => {
283
+ await Z(() => Qe({ variables: {
131
284
  id: Y.id,
132
285
  input: {
133
- title: M.trim(),
134
- content: P,
135
- ...I.trim() ? { changeNote: I.trim() } : {},
136
- expectedVersion: V
286
+ title: P.trim(),
287
+ content: Fe,
288
+ ...F.trim() ? { changeNote: F.trim() } : {},
289
+ expectedVersion: R
137
290
  }
138
- } }), "The doc could not be saved.") && j(!1);
139
- }, Q = [...Y.revisions].sort((e, t) => t.version - e.version), $ = B === null ? null : Q.find((e) => e.version === B);
140
- return /* @__PURE__ */ c("div", {
291
+ } }), "The doc could not be saved.") && (N("view"), ut({ variables: { docId: Y.id } }).catch(() => void 0));
292
+ }, bt = async () => {
293
+ I(null);
294
+ try {
295
+ await r(dt({ variables: { docId: Y.id } }));
296
+ } catch (e) {
297
+ I(i(e) ? "Your role cannot force-release this lock." : a(e, "The lock could not be broken."));
298
+ }
299
+ }, xt = () => {
300
+ Ve(Y.title), He(Y.content), Ue(""), H(null), Ke(Y.version), Je(Y.title), N("suggest");
301
+ }, St = () => {
302
+ N("view"), H(null);
303
+ }, Ct = async () => {
304
+ H(null);
305
+ try {
306
+ await r(pt({ variables: { input: {
307
+ docId: Y.id,
308
+ baseVersion: Ge ?? Y.version,
309
+ proposedContent: B,
310
+ ...z.trim() === qe ? {} : { proposedTitle: z.trim() },
311
+ ...V.trim() ? { note: V.trim() } : {}
312
+ } } })), N("view");
313
+ } catch (e) {
314
+ H(i(e) ? "Your role cannot suggest edits on this doc." : a(e, "The suggestion could not be submitted."));
315
+ }
316
+ }, wt = !!Y.lock && Y.lock.holderId !== j?.id, Q = [...Y.revisions].sort((e, t) => t.version - e.version), $ = L === null ? null : Q.find((e) => e.version === L);
317
+ return /* @__PURE__ */ m("div", {
141
318
  className: "space-y-6 p-6",
142
319
  "data-testid": "doc-detail",
143
320
  children: [
144
- /* @__PURE__ */ c(v, {
321
+ /* @__PURE__ */ m(v, {
145
322
  size: "sm",
146
323
  variant: "ghost",
147
324
  onClick: () => k("/docs/docs-page"),
148
- children: [/* @__PURE__ */ s(oe, { className: "mr-1 h-4 w-4" }), "All docs"]
325
+ children: [/* @__PURE__ */ p(le, { className: "mr-1 h-4 w-4" }), "All docs"]
149
326
  }),
150
- /* @__PURE__ */ c("div", {
327
+ /* @__PURE__ */ m("div", {
151
328
  className: "flex flex-wrap items-start justify-between gap-3",
152
- children: [/* @__PURE__ */ c("div", {
329
+ children: [/* @__PURE__ */ m("div", {
153
330
  className: "min-w-0 space-y-1",
154
- children: [/* @__PURE__ */ s("h1", {
155
- className: "text-2xl font-semibold break-words",
156
- "data-testid": "doc-title",
157
- children: Y.title
158
- }), /* @__PURE__ */ c("p", {
159
- className: "text-xs text-muted-foreground",
160
- children: [
161
- /* @__PURE__ */ s(ie, { status: Y.status }),
162
- " · version ",
163
- Y.version,
164
- " · updated",
165
- " ",
166
- D(Y.updatedAt),
167
- " by ",
168
- /* @__PURE__ */ s(t, { id: Y.updatedBy ?? Y.createdBy })
169
- ]
170
- })]
171
- }), !A && /* @__PURE__ */ c("div", {
331
+ children: [
332
+ /* @__PURE__ */ p("h1", {
333
+ className: "text-2xl font-semibold break-words",
334
+ "data-testid": "doc-title",
335
+ children: Y.title
336
+ }),
337
+ /* @__PURE__ */ m("p", {
338
+ className: "text-xs text-muted-foreground",
339
+ children: [
340
+ /* @__PURE__ */ p(ne, { status: Y.status }),
341
+ " · version ",
342
+ Y.version,
343
+ " · updated",
344
+ " ",
345
+ O(Y.updatedAt),
346
+ " by ",
347
+ /* @__PURE__ */ p(n, { id: Y.updatedBy ?? Y.createdBy })
348
+ ]
349
+ }),
350
+ /* @__PURE__ */ p(re, { others: U.others })
351
+ ]
352
+ }), M === "view" && /* @__PURE__ */ m("div", {
172
353
  className: "flex flex-wrap gap-2",
173
354
  children: [
174
- re.filter((e) => e !== Y.status).map((e) => /* @__PURE__ */ s(v, {
355
+ te.filter((e) => e !== Y.status).map((e) => /* @__PURE__ */ p(v, {
175
356
  size: "sm",
176
357
  variant: "outline",
177
358
  disabled: X,
178
- onClick: () => Z(() => G({ variables: {
359
+ onClick: () => Z(() => Qe({ variables: {
179
360
  id: Y.id,
180
361
  input: {
181
362
  status: e,
@@ -184,271 +365,361 @@ function O() {
184
365
  } }), "The status could not be changed."),
185
366
  children: e === "PUBLISHED" ? "Publish" : e === "ARCHIVED" ? "Archive" : "Back to draft"
186
367
  }, e)),
187
- /* @__PURE__ */ s(v, {
368
+ /* @__PURE__ */ p(v, {
369
+ size: "sm",
370
+ variant: "outline",
371
+ onClick: xt,
372
+ disabled: J.loading,
373
+ "data-testid": "doc-suggest",
374
+ children: "Suggest an edit"
375
+ }),
376
+ /* @__PURE__ */ p(v, {
188
377
  size: "sm",
189
- onClick: Ae,
378
+ onClick: () => void _t(),
379
+ disabled: wt || lt.loading,
190
380
  "data-testid": "doc-edit",
191
- children: "Edit"
381
+ children: lt.loading ? "Checking out…" : "Edit"
192
382
  }),
193
- /* @__PURE__ */ c(l, { children: [/* @__PURE__ */ s(_, {
383
+ /* @__PURE__ */ m(_e, { children: [/* @__PURE__ */ p(Se, {
194
384
  asChild: !0,
195
- children: /* @__PURE__ */ s(v, {
385
+ children: /* @__PURE__ */ p(v, {
196
386
  size: "sm",
197
387
  variant: "outline",
198
388
  disabled: X,
199
389
  children: "Delete"
200
390
  })
201
- }), /* @__PURE__ */ c(f, { children: [/* @__PURE__ */ c(h, { children: [/* @__PURE__ */ c(g, { children: [
391
+ }), /* @__PURE__ */ m(_, { children: [/* @__PURE__ */ m(be, { children: [/* @__PURE__ */ m(xe, { children: [
202
392
  "Delete “",
203
393
  Y.title,
204
394
  "”?"
205
- ] }), /* @__PURE__ */ c(p, { children: [
395
+ ] }), /* @__PURE__ */ m(ve, { children: [
206
396
  "The doc and its history are removed for everyone, and it is unlinked from",
207
397
  " ",
208
398
  Y.linkedWorkItems.length,
209
399
  " work item",
210
400
  Y.linkedWorkItems.length === 1 ? "" : "s",
211
401
  "."
212
- ] })] }), /* @__PURE__ */ c(m, { children: [/* @__PURE__ */ s(d, { children: "Keep it" }), /* @__PURE__ */ s(u, {
402
+ ] })] }), /* @__PURE__ */ m(ye, { children: [/* @__PURE__ */ p(g, { children: "Keep it" }), /* @__PURE__ */ p(h, {
213
403
  className: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
214
404
  onClick: async () => {
215
- await Z(() => we({ variables: { id: Y.id } }), "The doc could not be deleted.") && k("/docs/docs-page");
405
+ await Z(() => tt({ variables: { id: Y.id } }), "The doc could not be deleted.") && k("/docs/docs-page");
216
406
  },
217
407
  children: "Delete"
218
408
  })] })] })] })
219
409
  ]
220
410
  })]
221
411
  }),
222
- R && /* @__PURE__ */ s("p", {
412
+ Y.lock && /* @__PURE__ */ p(Ne, {
413
+ lock: Y.lock,
414
+ currentUserId: j?.id,
415
+ now: mt,
416
+ onBreakLock: () => void bt(),
417
+ breaking: ft.loading
418
+ }),
419
+ Re && /* @__PURE__ */ p("p", {
223
420
  role: "alert",
224
421
  className: "text-sm text-destructive",
225
422
  "data-testid": "doc-error",
226
- children: R
423
+ children: Re
227
424
  }),
228
- A && V !== Y.version && /* @__PURE__ */ c("p", {
425
+ M === "edit" && R !== Y.version && /* @__PURE__ */ m("p", {
229
426
  className: "text-sm text-status-warning-text",
230
427
  "data-testid": "doc-moved-on",
231
428
  children: [
232
429
  "Someone saved version ",
233
430
  Y.version,
234
431
  " after you started editing version ",
235
- V,
432
+ R,
236
433
  ". Your text is kept below; copy what you need, then discard and edit the latest."
237
434
  ]
238
435
  }),
239
- A ? /* @__PURE__ */ s(y, { children: /* @__PURE__ */ c(b, {
436
+ M === "edit" && /* @__PURE__ */ p(y, { children: /* @__PURE__ */ m(b, {
240
437
  className: "space-y-3 pt-6",
241
438
  children: [
242
- /* @__PURE__ */ s(C, {
439
+ /* @__PURE__ */ p(C, {
243
440
  "aria-label": "Doc title",
244
- value: M,
245
- onChange: (e) => N(e.target.value)
246
- }),
247
- /* @__PURE__ */ s(ne, {
248
441
  value: P,
249
- onChange: F,
442
+ onChange: (e) => Pe(e.target.value)
443
+ }),
444
+ /* @__PURE__ */ p(s, {
445
+ value: Fe,
446
+ onChange: Ie,
250
447
  minHeight: 240
251
448
  }),
252
- /* @__PURE__ */ s(C, {
449
+ /* @__PURE__ */ p(C, {
253
450
  "aria-label": "Change note",
254
451
  placeholder: "What changed? (optional, shown in the history)",
255
- value: I,
256
- onChange: (e) => L(e.target.value)
452
+ value: F,
453
+ onChange: (e) => Le(e.target.value)
257
454
  }),
258
- /* @__PURE__ */ c("div", {
455
+ /* @__PURE__ */ m("div", {
259
456
  className: "flex justify-end gap-2",
260
- children: [/* @__PURE__ */ s(v, {
457
+ children: [/* @__PURE__ */ p(v, {
261
458
  size: "sm",
262
459
  variant: "ghost",
263
- onClick: () => {
264
- j(!1), z(null);
265
- },
266
- children: V === Y.version ? "Cancel" : "Discard my edits"
267
- }), /* @__PURE__ */ s(v, {
460
+ onClick: vt,
461
+ children: R === Y.version ? "Cancel" : "Discard my edits"
462
+ }), /* @__PURE__ */ p(v, {
268
463
  size: "sm",
269
- onClick: je,
270
- disabled: K.loading || V !== Y.version,
464
+ onClick: yt,
465
+ disabled: K.loading || R !== Y.version,
271
466
  "data-testid": "doc-save",
272
467
  children: K.loading ? "Saving…" : "Save new version"
273
468
  })]
274
469
  })
275
470
  ]
276
- }) }) : /* @__PURE__ */ s(y, { children: /* @__PURE__ */ s(b, {
471
+ }) }),
472
+ M === "suggest" && /* @__PURE__ */ m(y, {
473
+ "data-testid": "doc-suggest-form",
474
+ children: [/* @__PURE__ */ p(x, { children: /* @__PURE__ */ p(S, {
475
+ className: "text-base",
476
+ children: "Suggest an edit"
477
+ }) }), /* @__PURE__ */ m(b, {
478
+ className: "space-y-3",
479
+ children: [
480
+ /* @__PURE__ */ m("p", {
481
+ className: "text-xs text-muted-foreground",
482
+ children: [
483
+ "Proposed against version ",
484
+ Ge ?? Y.version,
485
+ ". It does not change the doc — someone with edit rights accepts or rejects it below."
486
+ ]
487
+ }),
488
+ /* @__PURE__ */ p(C, {
489
+ "aria-label": "Suggested title",
490
+ value: z,
491
+ onChange: (e) => Ve(e.target.value)
492
+ }),
493
+ /* @__PURE__ */ p(s, {
494
+ value: B,
495
+ onChange: He,
496
+ minHeight: 240
497
+ }),
498
+ /* @__PURE__ */ p(C, {
499
+ "aria-label": "Note (optional)",
500
+ placeholder: "Why this change? (optional)",
501
+ value: V,
502
+ onChange: (e) => Ue(e.target.value)
503
+ }),
504
+ We && /* @__PURE__ */ p("p", {
505
+ role: "alert",
506
+ className: "text-sm text-destructive",
507
+ children: We
508
+ }),
509
+ /* @__PURE__ */ m("div", {
510
+ className: "flex justify-end gap-2",
511
+ children: [/* @__PURE__ */ p(v, {
512
+ size: "sm",
513
+ variant: "ghost",
514
+ onClick: St,
515
+ children: "Cancel"
516
+ }), /* @__PURE__ */ p(v, {
517
+ size: "sm",
518
+ onClick: () => void Ct(),
519
+ disabled: J.loading || !B.trim() || !z.trim(),
520
+ "data-testid": "doc-suggest-submit",
521
+ children: J.loading ? "Submitting…" : "Submit suggestion"
522
+ })]
523
+ })
524
+ ]
525
+ })]
526
+ }),
527
+ M === "view" && /* @__PURE__ */ p(y, { children: /* @__PURE__ */ p(b, {
277
528
  className: "prose prose-sm max-w-none pt-6 dark:prose-invert",
278
- children: Y.content.trim() ? /* @__PURE__ */ s(w, { children: Y.content }) : /* @__PURE__ */ s("p", {
529
+ children: Y.content.trim() ? /* @__PURE__ */ p(T, { children: Y.content }) : /* @__PURE__ */ p("p", {
279
530
  className: "text-sm text-muted-foreground",
280
531
  children: "This doc is empty."
281
532
  })
282
533
  }) }),
283
- /* @__PURE__ */ c("div", {
534
+ /* @__PURE__ */ m("div", {
284
535
  className: "grid grid-cols-1 gap-6 lg:grid-cols-2",
285
- children: [/* @__PURE__ */ c(y, {
536
+ children: [/* @__PURE__ */ m(y, {
286
537
  "data-testid": "doc-history",
287
- children: [/* @__PURE__ */ s(x, { children: /* @__PURE__ */ c(S, {
538
+ children: [/* @__PURE__ */ p(x, { children: /* @__PURE__ */ m(S, {
288
539
  className: "flex items-center gap-2",
289
540
  children: [
290
- /* @__PURE__ */ s(se, { className: "h-4 w-4" }),
541
+ /* @__PURE__ */ p(ue, { className: "h-4 w-4" }),
291
542
  " History (",
292
543
  Q.length,
293
544
  ")"
294
545
  ]
295
- }) }), /* @__PURE__ */ c(b, {
546
+ }) }), /* @__PURE__ */ m(b, {
296
547
  className: "space-y-2",
297
- children: [/* @__PURE__ */ s("ol", {
298
- className: "space-y-2",
299
- children: Q.map((e) => {
300
- let n = e.version === Y.version;
301
- return /* @__PURE__ */ c("li", {
302
- className: "space-y-1 rounded-md border p-2",
303
- "data-testid": "doc-revision",
304
- children: [/* @__PURE__ */ c("div", {
305
- className: "flex flex-wrap items-center justify-between gap-2",
306
- children: [/* @__PURE__ */ c("span", {
307
- className: "text-sm font-medium",
308
- children: [
309
- "Version ",
310
- e.version,
311
- n ? " (current)" : ""
312
- ]
313
- }), /* @__PURE__ */ c("span", {
314
- className: "flex gap-1",
315
- children: [/* @__PURE__ */ s(v, {
316
- size: "sm",
317
- variant: "ghost",
318
- className: "h-7 text-xs",
319
- "aria-expanded": B === e.version,
320
- onClick: () => ve(B === e.version ? null : e.version),
321
- children: B === e.version ? "Hide" : "View"
322
- }), !n && !A && /* @__PURE__ */ c(l, { children: [/* @__PURE__ */ s(_, {
323
- asChild: !0,
324
- children: /* @__PURE__ */ s(v, {
548
+ children: [
549
+ /* @__PURE__ */ p("ol", {
550
+ className: "space-y-2",
551
+ children: Q.map((e) => {
552
+ let t = e.version === Y.version;
553
+ return /* @__PURE__ */ m("li", {
554
+ className: "space-y-1 rounded-md border p-2",
555
+ "data-testid": "doc-revision",
556
+ children: [/* @__PURE__ */ m("div", {
557
+ className: "flex flex-wrap items-center justify-between gap-2",
558
+ children: [/* @__PURE__ */ m("span", {
559
+ className: "text-sm font-medium",
560
+ children: [
561
+ "Version ",
562
+ e.version,
563
+ t ? " (current)" : ""
564
+ ]
565
+ }), /* @__PURE__ */ m("span", {
566
+ className: "flex gap-1",
567
+ children: [/* @__PURE__ */ p(v, {
325
568
  size: "sm",
326
- variant: "outline",
569
+ variant: "ghost",
327
570
  className: "h-7 text-xs",
328
- disabled: X,
329
- "data-testid": "doc-restore",
571
+ "aria-expanded": L === e.version,
572
+ onClick: () => ze(L === e.version ? null : e.version),
573
+ children: L === e.version ? "Hide" : "View"
574
+ }), !t && M === "view" && /* @__PURE__ */ m(_e, { children: [/* @__PURE__ */ p(Se, {
575
+ asChild: !0,
576
+ children: /* @__PURE__ */ p(v, {
577
+ size: "sm",
578
+ variant: "outline",
579
+ className: "h-7 text-xs",
580
+ disabled: X,
581
+ "data-testid": "doc-restore",
582
+ children: "Restore"
583
+ })
584
+ }), /* @__PURE__ */ m(_, { children: [/* @__PURE__ */ m(be, { children: [/* @__PURE__ */ m(xe, { children: [
585
+ "Restore version ",
586
+ e.version,
587
+ "?"
588
+ ] }), /* @__PURE__ */ m(ve, { children: [
589
+ "Its title and text become version ",
590
+ Y.version + 1,
591
+ ". Nothing is deleted: version ",
592
+ Y.version,
593
+ " stays in the history."
594
+ ] })] }), /* @__PURE__ */ m(ye, { children: [/* @__PURE__ */ p(g, { children: "Cancel" }), /* @__PURE__ */ p(h, {
595
+ onClick: () => Z(() => $e({ variables: {
596
+ id: Y.id,
597
+ toVersion: e.version,
598
+ expectedVersion: Y.version
599
+ } }), "The version could not be restored."),
330
600
  children: "Restore"
331
- })
332
- }), /* @__PURE__ */ c(f, { children: [/* @__PURE__ */ c(h, { children: [/* @__PURE__ */ c(g, { children: [
333
- "Restore version ",
334
- e.version,
335
- "?"
336
- ] }), /* @__PURE__ */ c(p, { children: [
337
- "Its title and text become version ",
338
- Y.version + 1,
339
- ". Nothing is deleted: version ",
340
- Y.version,
341
- " stays in the history."
342
- ] })] }), /* @__PURE__ */ c(m, { children: [/* @__PURE__ */ s(d, { children: "Cancel" }), /* @__PURE__ */ s(u, {
343
- onClick: () => Z(() => Se({ variables: {
344
- id: Y.id,
345
- toVersion: e.version,
346
- expectedVersion: Y.version
347
- } }), "The version could not be restored."),
348
- children: "Restore"
349
- })] })] })] })]
601
+ })] })] })] })]
602
+ })]
603
+ }), /* @__PURE__ */ m("p", {
604
+ className: "text-xs text-muted-foreground",
605
+ children: [
606
+ O(e.createdAt),
607
+ " · ",
608
+ /* @__PURE__ */ p(n, { id: e.createdBy }),
609
+ e.changeNote ? ` · ${e.changeNote}` : ""
610
+ ]
350
611
  })]
351
- }), /* @__PURE__ */ c("p", {
352
- className: "text-xs text-muted-foreground",
353
- children: [
354
- D(e.createdAt),
355
- " · ",
356
- /* @__PURE__ */ s(t, { id: e.createdBy }),
357
- e.changeNote ? ` · ${e.changeNote}` : ""
358
- ]
359
- })]
360
- }, e.id);
612
+ }, e.id);
613
+ })
614
+ }),
615
+ $ && /* @__PURE__ */ m("div", {
616
+ className: "space-y-1 rounded-md border bg-muted/40 p-3",
617
+ "data-testid": "doc-revision-view",
618
+ children: [/* @__PURE__ */ m("p", {
619
+ className: "text-sm font-medium",
620
+ children: [
621
+ "Version ",
622
+ $.version,
623
+ ": ",
624
+ $.title
625
+ ]
626
+ }), /* @__PURE__ */ p("div", {
627
+ className: "prose prose-sm max-w-none dark:prose-invert",
628
+ children: /* @__PURE__ */ p(T, { children: $.content })
629
+ })]
630
+ }),
631
+ /* @__PURE__ */ p(se, {
632
+ docId: Y.id,
633
+ versions: Q
361
634
  })
362
- }), $ && /* @__PURE__ */ c("div", {
363
- className: "space-y-1 rounded-md border bg-muted/40 p-3",
364
- "data-testid": "doc-revision-view",
365
- children: [/* @__PURE__ */ c("p", {
366
- className: "text-sm font-medium",
367
- children: [
368
- "Version ",
369
- $.version,
370
- ": ",
371
- $.title
372
- ]
373
- }), /* @__PURE__ */ s("div", {
374
- className: "prose prose-sm max-w-none dark:prose-invert",
375
- children: /* @__PURE__ */ s(w, { children: $.content })
376
- })]
377
- })]
635
+ ]
378
636
  })]
379
- }), /* @__PURE__ */ c(y, {
637
+ }), /* @__PURE__ */ m(y, {
380
638
  "data-testid": "doc-linked-items",
381
- children: [/* @__PURE__ */ s(x, { children: /* @__PURE__ */ c(S, {
639
+ children: [/* @__PURE__ */ p(x, { children: /* @__PURE__ */ m(S, {
382
640
  className: "flex items-center gap-2",
383
641
  children: [
384
- /* @__PURE__ */ s(i, { className: "h-4 w-4" }),
642
+ /* @__PURE__ */ p(de, { className: "h-4 w-4" }),
385
643
  " Linked work items (",
386
644
  Y.linkedWorkItems.length,
387
645
  ")"
388
646
  ]
389
- }) }), /* @__PURE__ */ c(b, {
647
+ }) }), /* @__PURE__ */ m(b, {
390
648
  className: "space-y-2",
391
649
  children: [
392
- Y.linkedWorkItems.length === 0 && /* @__PURE__ */ s("p", {
650
+ Y.linkedWorkItems.length === 0 && /* @__PURE__ */ p("p", {
393
651
  className: "text-sm text-muted-foreground",
394
652
  children: "Not linked to any work item yet. Pick one below, or use “Link existing doc” on the task."
395
653
  }),
396
- Y.linkedWorkItems.map((e) => /* @__PURE__ */ c("div", {
654
+ Y.linkedWorkItems.map((e) => /* @__PURE__ */ m("div", {
397
655
  className: "flex items-center justify-between gap-2 rounded-md border p-2",
398
- children: [/* @__PURE__ */ c("button", {
656
+ children: [/* @__PURE__ */ m("button", {
399
657
  type: "button",
400
658
  className: "min-w-0 truncate text-left text-sm hover:underline",
401
659
  onClick: () => k(`/tasks/task-detail-page?taskId=${encodeURIComponent(e.id)}`),
402
660
  children: [
403
- /* @__PURE__ */ s("span", {
661
+ /* @__PURE__ */ p("span", {
404
662
  className: "text-muted-foreground",
405
663
  children: e.key
406
664
  }),
407
665
  " ",
408
666
  e.title
409
667
  ]
410
- }), /* @__PURE__ */ s(v, {
668
+ }), /* @__PURE__ */ p(v, {
411
669
  size: "icon",
412
670
  variant: "ghost",
413
- disabled: De.loading,
671
+ disabled: it.loading,
414
672
  "aria-label": `Unlink ${e.title}`,
415
- onClick: () => Z(() => Ee({ variables: {
673
+ onClick: () => Z(() => rt({ variables: {
416
674
  docId: Y.id,
417
675
  workItemId: e.id
418
676
  } }), "The work item could not be unlinked."),
419
- children: /* @__PURE__ */ s(ce, { className: "h-4 w-4" })
677
+ children: /* @__PURE__ */ p(fe, { className: "h-4 w-4" })
420
678
  })]
421
679
  }, e.id)),
422
- /* @__PURE__ */ c("div", {
680
+ /* @__PURE__ */ m("div", {
423
681
  className: "space-y-2 pt-2",
424
682
  "data-testid": "doc-link-work-item",
425
- children: [/* @__PURE__ */ s(te, {
683
+ children: [/* @__PURE__ */ p(o, {
426
684
  id: "doc-link-work-item-select",
427
685
  value: q,
428
- onChange: J,
686
+ onChange: st,
429
687
  exclude: Y.linkedWorkItems.map((e) => e.id)
430
- }), /* @__PURE__ */ c(v, {
688
+ }), /* @__PURE__ */ m(v, {
431
689
  size: "sm",
432
690
  variant: "outline",
433
- disabled: !q || ke.loading,
691
+ disabled: !q || ot.loading,
434
692
  onClick: async () => {
435
- await Z(() => Oe({ variables: {
693
+ await Z(() => at({ variables: {
436
694
  docId: Y.id,
437
695
  workItemId: q
438
- } }), "The work item could not be linked.") && J("");
696
+ } }), "The work item could not be linked.") && st("");
439
697
  },
440
- children: [/* @__PURE__ */ s(i, { className: "mr-1 h-4 w-4" }), "Link work item"]
698
+ children: [/* @__PURE__ */ p(de, { className: "mr-1 h-4 w-4" }), "Link work item"]
441
699
  })]
442
700
  })
443
701
  ]
444
702
  })]
445
703
  })]
446
704
  }),
447
- /* @__PURE__ */ s(ae, { docId: Y.id })
705
+ /* @__PURE__ */ p(oe, {
706
+ docId: Y.id,
707
+ docTitle: Y.title,
708
+ docContent: Y.content,
709
+ revisions: Q,
710
+ currentUserId: j?.id
711
+ }),
712
+ /* @__PURE__ */ p(ie, {
713
+ docId: Y.id,
714
+ presence: {
715
+ typingActorIds: U.typingActorIds,
716
+ notifyTyping: U.notifyTyping
717
+ }
718
+ })
448
719
  ]
449
720
  });
450
721
  }
451
722
  //#endregion
452
- export { O as DocsDocDetailPagePage };
723
+ export { k as DocsDocDetailPagePage };
453
724
 
454
725
  //# sourceMappingURL=DocsDocDetailPagePage.js.map