@burdenoff/microfe-planmagnet 2026.925.10 → 2026.925.12
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 +38 -0
- package/dist/generated/wspace-types.d.ts.map +1 -1
- package/dist/planmagnet/comments/WorkItemActivity.d.ts +4 -0
- package/dist/planmagnet/comments/WorkItemActivity.d.ts.map +1 -0
- package/dist/planmagnet/comments/WorkItemActivity.js +97 -0
- package/dist/planmagnet/comments/WorkItemActivity.js.map +1 -0
- package/dist/planmagnet/comments/WorkItemComments.d.ts.map +1 -1
- package/dist/planmagnet/comments/WorkItemComments.js +2 -2
- package/dist/planmagnet/comments/WorkItemComments.js.map +1 -1
- package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.js +96 -95
- package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.js +116 -153
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.js.map +1 -1
- package/dist/planmagnet/releases/ReleaseNotesCard.d.ts +5 -0
- package/dist/planmagnet/releases/ReleaseNotesCard.d.ts.map +1 -0
- package/dist/planmagnet/releases/ReleaseNotesCard.js +101 -0
- package/dist/planmagnet/releases/ReleaseNotesCard.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkItemActivity.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/comments/WorkItemActivity.tsx"],"names":[],"mappings":"AAyDA,wBAAgB,gBAAgB,CAAC,EAAE,UAAU,EAAE,EAAE;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,2CA+CtE"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { PersonName as e } from "../people/People.js";
|
|
2
|
+
import { gql as t } from "@apollo/client";
|
|
3
|
+
import { useQuery as n } from "@apollo/client/react";
|
|
4
|
+
import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
5
|
+
import { Card as a, CardContent as o, CardHeader as s, CardTitle as c } from "@burdenoff/fe-libs/ui";
|
|
6
|
+
//#region src/planmagnet/comments/WorkItemActivity.tsx
|
|
7
|
+
var l = t`
|
|
8
|
+
query WorkItemActivity($workItemId: ID!) {
|
|
9
|
+
planmagnetWorkItemActivity(workItemId: $workItemId, first: 50) {
|
|
10
|
+
totalCount
|
|
11
|
+
truncated
|
|
12
|
+
items {
|
|
13
|
+
id
|
|
14
|
+
kind
|
|
15
|
+
actorId
|
|
16
|
+
at
|
|
17
|
+
fromStatus
|
|
18
|
+
toStatus
|
|
19
|
+
excerpt
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
`, u = (e) => e ? e.charAt(0) + e.slice(1).toLowerCase().replace(/_/g, " ") : "";
|
|
24
|
+
function d(e) {
|
|
25
|
+
switch (e.kind) {
|
|
26
|
+
case "CREATED": return e.toStatus ? `Created in ${u(e.toStatus)}` : "Created";
|
|
27
|
+
case "STATUS_CHANGED": return `Moved from ${u(e.fromStatus)} to ${u(e.toStatus)}`;
|
|
28
|
+
case "COMMENTED": return `Commented: “${e.excerpt ?? ""}”`;
|
|
29
|
+
default: return e.kind;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function f({ workItemId: t }) {
|
|
33
|
+
let { data: u, loading: f, error: p } = n(l, {
|
|
34
|
+
variables: { workItemId: t },
|
|
35
|
+
skip: !t
|
|
36
|
+
}), m = u?.planmagnetWorkItemActivity, h = m?.items ?? [];
|
|
37
|
+
return /* @__PURE__ */ i(a, {
|
|
38
|
+
"data-testid": "work-item-activity",
|
|
39
|
+
children: [/* @__PURE__ */ r(s, { children: /* @__PURE__ */ r(c, { children: "Activity" }) }), /* @__PURE__ */ i(o, {
|
|
40
|
+
className: "space-y-3",
|
|
41
|
+
children: [
|
|
42
|
+
f && !u && /* @__PURE__ */ r("p", {
|
|
43
|
+
className: "text-sm text-muted-foreground",
|
|
44
|
+
children: "Loading activity…"
|
|
45
|
+
}),
|
|
46
|
+
p && /* @__PURE__ */ i("p", {
|
|
47
|
+
role: "alert",
|
|
48
|
+
className: "text-sm text-destructive",
|
|
49
|
+
children: ["Activity could not be loaded: ", p.message]
|
|
50
|
+
}),
|
|
51
|
+
/* @__PURE__ */ r("ol", {
|
|
52
|
+
className: "space-y-3",
|
|
53
|
+
children: h.map((t, n) => /* @__PURE__ */ i("li", {
|
|
54
|
+
className: "flex gap-3",
|
|
55
|
+
"data-testid": "activity-event",
|
|
56
|
+
children: [/* @__PURE__ */ i("div", {
|
|
57
|
+
className: "flex flex-col items-center",
|
|
58
|
+
children: [/* @__PURE__ */ r("div", { className: "h-2.5 w-2.5 rounded-full bg-primary mt-1.5" }), n < h.length - 1 && /* @__PURE__ */ r("div", { className: "w-px flex-1 bg-border" })]
|
|
59
|
+
}), /* @__PURE__ */ i("div", {
|
|
60
|
+
className: "pb-1 min-w-0",
|
|
61
|
+
children: [/* @__PURE__ */ r("p", {
|
|
62
|
+
className: "text-sm break-words",
|
|
63
|
+
children: d(t)
|
|
64
|
+
}), /* @__PURE__ */ i("p", {
|
|
65
|
+
className: "text-xs text-muted-foreground",
|
|
66
|
+
children: [
|
|
67
|
+
t.actorId ? /* @__PURE__ */ r(e, { id: t.actorId }) : "Unknown",
|
|
68
|
+
" ·",
|
|
69
|
+
" ",
|
|
70
|
+
new Date(t.at).toLocaleString()
|
|
71
|
+
]
|
|
72
|
+
})]
|
|
73
|
+
})]
|
|
74
|
+
}, t.id))
|
|
75
|
+
}),
|
|
76
|
+
m?.truncated && /* @__PURE__ */ i("p", {
|
|
77
|
+
className: "text-xs text-muted-foreground",
|
|
78
|
+
children: [
|
|
79
|
+
"Showing the latest ",
|
|
80
|
+
h.length,
|
|
81
|
+
" of ",
|
|
82
|
+
m.totalCount,
|
|
83
|
+
" events."
|
|
84
|
+
]
|
|
85
|
+
}),
|
|
86
|
+
/* @__PURE__ */ r("p", {
|
|
87
|
+
className: "text-xs text-muted-foreground",
|
|
88
|
+
children: "Creation, status changes and comments are recorded. Other edits are not tracked yet."
|
|
89
|
+
})
|
|
90
|
+
]
|
|
91
|
+
})]
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
//#endregion
|
|
95
|
+
export { f as WorkItemActivity };
|
|
96
|
+
|
|
97
|
+
//# sourceMappingURL=WorkItemActivity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkItemActivity.js","names":[],"sources":["../../../src/planmagnet/comments/WorkItemActivity.tsx"],"sourcesContent":["import { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle } from '@burdenoff/fe-libs/ui';\nimport { PersonName } from '../people/People';\n\n/**\n * A work item's recorded history (P1.4). This card used to synthesise three\n * entries client-side, including \"Status changed to X\" attributed to whoever\n * was assigned, at the item's updatedAt. That was fabricated history. It now\n * shows only what the server has recorded: creation, status changes and\n * comments. Other edits are not recorded yet, and the card says so.\n */\n\nconst ACTIVITY = gql`\n query WorkItemActivity($workItemId: ID!) {\n planmagnetWorkItemActivity(workItemId: $workItemId, first: 50) {\n totalCount\n truncated\n items {\n id\n kind\n actorId\n at\n fromStatus\n toStatus\n excerpt\n }\n }\n }\n`;\n\ninterface ActivityEvent {\n id: string;\n kind: string;\n actorId: string | null;\n at: string;\n fromStatus: string | null;\n toStatus: string | null;\n excerpt: string | null;\n}\n\nconst statusLabel = (status: string | null) =>\n status ? status.charAt(0) + status.slice(1).toLowerCase().replace(/_/g, ' ') : '';\n\nfunction describe(event: ActivityEvent): string {\n switch (event.kind) {\n case 'CREATED':\n return event.toStatus ? `Created in ${statusLabel(event.toStatus)}` : 'Created';\n case 'STATUS_CHANGED':\n return `Moved from ${statusLabel(event.fromStatus)} to ${statusLabel(event.toStatus)}`;\n case 'COMMENTED':\n return `Commented: “${event.excerpt ?? ''}”`;\n default:\n return event.kind;\n }\n}\n\nexport function WorkItemActivity({ workItemId }: { workItemId: string }) {\n const { data, loading, error } = useQuery<{\n planmagnetWorkItemActivity: { totalCount: number; truncated: boolean; items: ActivityEvent[] };\n }>(ACTIVITY, { variables: { workItemId }, skip: !workItemId });\n const activity = data?.planmagnetWorkItemActivity;\n const events = activity?.items ?? [];\n\n return (\n <Card data-testid=\"work-item-activity\">\n <CardHeader>\n <CardTitle>Activity</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {loading && !data && <p className=\"text-sm text-muted-foreground\">Loading activity…</p>}\n {error && (\n <p role=\"alert\" className=\"text-sm text-destructive\">\n Activity could not be loaded: {error.message}\n </p>\n )}\n <ol className=\"space-y-3\">\n {events.map((event, i) => (\n <li key={event.id} className=\"flex gap-3\" data-testid=\"activity-event\">\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 < events.length - 1 && <div className=\"w-px flex-1 bg-border\" />}\n </div>\n <div className=\"pb-1 min-w-0\">\n <p className=\"text-sm break-words\">{describe(event)}</p>\n <p className=\"text-xs text-muted-foreground\">\n {event.actorId ? <PersonName id={event.actorId} /> : 'Unknown'} ·{' '}\n {new Date(event.at).toLocaleString()}\n </p>\n </div>\n </li>\n ))}\n </ol>\n {activity?.truncated && (\n <p className=\"text-xs text-muted-foreground\">\n Showing the latest {events.length} of {activity.totalCount} events.\n </p>\n )}\n <p className=\"text-xs text-muted-foreground\">\n Creation, status changes and comments are recorded. Other edits are not tracked yet.\n </p>\n </CardContent>\n </Card>\n );\n}\n"],"mappings":";;;;;;AAaA,IAAM,IAAW,CAAG;;;;;;;;;;;;;;;;GA4Bd,KAAe,MACnB,IAAS,EAAO,OAAO,EAAE,GAAG,EAAO,MAAM,EAAE,CAAC,aAAa,CAAC,QAAQ,MAAM,IAAI,GAAG;AAEjF,SAAS,EAAS,GAA8B;AAC9C,SAAQ,EAAM,MAAd;EACE,KAAK,UACH,QAAO,EAAM,WAAW,cAAc,EAAY,EAAM,SAAS,KAAK;EACxE,KAAK,iBACH,QAAO,cAAc,EAAY,EAAM,WAAW,CAAC,MAAM,EAAY,EAAM,SAAS;EACtF,KAAK,YACH,QAAO,eAAe,EAAM,WAAW,GAAG;EAC5C,QACE,QAAO,EAAM;;;AAInB,SAAgB,EAAiB,EAAE,iBAAsC;CACvE,IAAM,EAAE,SAAM,YAAS,aAAU,EAE9B,GAAU;EAAE,WAAW,EAAE,eAAY;EAAE,MAAM,CAAC;EAAY,CAAC,EACxD,IAAW,GAAM,4BACjB,IAAS,GAAU,SAAS,EAAE;AAEpC,QACE,kBAAC,GAAD;EAAM,eAAY;YAAlB,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAW,YAAoB,CAAA,EACpB,CAAA,EACb,kBAAC,GAAD;GAAa,WAAU;aAAvB;IACG,KAAW,CAAC,KAAQ,kBAAC,KAAD;KAAG,WAAU;eAAgC;KAAqB,CAAA;IACtF,KACC,kBAAC,KAAD;KAAG,MAAK;KAAQ,WAAU;eAA1B,CAAqD,kCACpB,EAAM,QACnC;;IAEN,kBAAC,MAAD;KAAI,WAAU;eACX,EAAO,KAAK,GAAO,MAClB,kBAAC,MAAD;MAAmB,WAAU;MAAa,eAAY;gBAAtD,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD,EAAK,WAAU,8CAA+C,CAAA,EAC7D,IAAI,EAAO,SAAS,KAAK,kBAAC,OAAD,EAAK,WAAU,yBAA0B,CAAA,CAC/D;UACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,KAAD;QAAG,WAAU;kBAAuB,EAAS,EAAM;QAAK,CAAA,EACxD,kBAAC,KAAD;QAAG,WAAU;kBAAb;SACG,EAAM,UAAU,kBAAC,GAAD,EAAY,IAAI,EAAM,SAAW,CAAA,GAAG;SAAU;SAAG;SACjE,IAAI,KAAK,EAAM,GAAG,CAAC,gBAAgB;SAClC;UACA;SACH;QAZI,EAAM,GAYV,CACL;KACC,CAAA;IACJ,GAAU,aACT,kBAAC,KAAD;KAAG,WAAU;eAAb;MAA6C;MACvB,EAAO;MAAO;MAAK,EAAS;MAAW;MACzD;;IAEN,kBAAC,KAAD;KAAG,WAAU;eAAgC;KAEzC,CAAA;IACQ;KACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkItemComments.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/comments/WorkItemComments.tsx"],"names":[],"mappings":"AAqGA,wBAAgB,gBAAgB,CAAC,EAAE,UAAU,EAAE,EAAE;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"WorkItemComments.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/comments/WorkItemComments.tsx"],"names":[],"mappings":"AAqGA,wBAAgB,gBAAgB,CAAC,EAAE,UAAU,EAAE,EAAE;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,2CAkHtE"}
|
|
@@ -59,7 +59,7 @@ function N({ workItemId: t }) {
|
|
|
59
59
|
},
|
|
60
60
|
skip: !t
|
|
61
61
|
}), [k, j] = o(D, {
|
|
62
|
-
refetchQueries: ["WorkItemComments"],
|
|
62
|
+
refetchQueries: ["WorkItemComments", "WorkItemActivity"],
|
|
63
63
|
awaitRefetchQueries: !0
|
|
64
64
|
}), N = g?.planmagnetWorkItemComments, F = N?.items ?? [], I = u.trim(), L = I.length > w;
|
|
65
65
|
return /* @__PURE__ */ l(b, {
|
|
@@ -162,7 +162,7 @@ function N({ workItemId: t }) {
|
|
|
162
162
|
}
|
|
163
163
|
function P({ comment: e, mine: i, onError: a }) {
|
|
164
164
|
let [s, b] = r(!1), [x, S] = r(e.body), C = a, w = {
|
|
165
|
-
refetchQueries: ["WorkItemComments"],
|
|
165
|
+
refetchQueries: ["WorkItemComments", "WorkItemActivity"],
|
|
166
166
|
awaitRefetchQueries: !0
|
|
167
167
|
}, [T, E] = o(O, w), [D, M] = o(k, w);
|
|
168
168
|
return /* @__PURE__ */ l("li", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkItemComments.js","names":[],"sources":["../../../src/planmagnet/comments/WorkItemComments.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n} from '@burdenoff/fe-libs/ui';\nimport { MessageSquare } from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\nimport { PersonName } from '../people/People';\nimport { throwOnError } from '../utils/mutationResult';\n\n/**\n * Discussion on a work item (P1.4). Anyone who can read the item sees the\n * thread; posting needs edit rights on work items; only a comment's author\n * can edit or delete it. The server enforces all three and says why it refused\n * (shown inline). The controls here only avoid offering what would be refused.\n */\n\nconst MAX_LENGTH = 10_000;\nconst PAGE = 50;\n\nconst COMMENTS = gql`\n query WorkItemComments($workItemId: ID!, $pagination: PlanmagnetPaginationInput) {\n planmagnetWorkItemComments(workItemId: $workItemId, pagination: $pagination) {\n totalCount\n pageInfo {\n hasNextPage\n endCursor\n }\n items {\n id\n authorId\n body\n createdAt\n editedAt\n }\n }\n }\n`;\nconst ADD = gql`\n mutation WorkItemCommentAdd($input: PlanmagnetAddWorkItemCommentInput!) {\n planmagnetAddWorkItemComment(input: $input) {\n id\n }\n }\n`;\nconst EDIT = gql`\n mutation WorkItemCommentEdit($id: ID!, $body: String!) {\n planmagnetEditWorkItemComment(id: $id, body: $body) {\n id\n body\n editedAt\n }\n }\n`;\nconst DELETE = gql`\n mutation WorkItemCommentDelete($id: ID!) {\n planmagnetDeleteWorkItemComment(id: $id)\n }\n`;\n\ninterface Comment {\n id: string;\n authorId: string;\n body: string;\n createdAt: string;\n editedAt: string | null;\n}\n\ninterface CommentsData {\n planmagnetWorkItemComments: {\n totalCount: number;\n pageInfo: { hasNextPage: boolean; endCursor: string | null };\n items: Comment[];\n };\n}\n\nconst messageOf = (e: unknown, fallback: string) => (e instanceof Error ? e.message : fallback);\nconst when = (iso: string) => new Date(iso).toLocaleString();\n\nfunction ErrorLine({ message }: { message: string }) {\n return (\n <p role=\"alert\" className=\"text-sm text-destructive\">\n {message}\n </p>\n );\n}\n\nexport function WorkItemComments({ workItemId }: { workItemId: string }) {\n const { currentUser } = usePlanMagnet();\n const [draft, setDraft] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [loadingMore, setLoadingMore] = useState(false);\n\n const {\n data,\n loading,\n error: loadError,\n fetchMore,\n } = useQuery<CommentsData>(COMMENTS, {\n variables: { workItemId, pagination: { first: PAGE } },\n skip: !workItemId,\n });\n const refetch = { refetchQueries: ['WorkItemComments'], awaitRefetchQueries: true };\n const [add, addState] = useMutation(ADD, refetch);\n\n const thread = data?.planmagnetWorkItemComments;\n const comments = thread?.items ?? [];\n const trimmed = draft.trim();\n const tooLong = trimmed.length > MAX_LENGTH;\n\n const post = async () => {\n setError(null);\n try {\n await throwOnError(add({ variables: { input: { workItemId, body: trimmed } } }));\n setDraft('');\n } catch (e) {\n setError(messageOf(e, 'The comment could not be posted.'));\n }\n };\n\n const loadMore = async () => {\n const after = thread?.pageInfo.endCursor;\n if (!after) return;\n setLoadingMore(true);\n try {\n await fetchMore({\n variables: { pagination: { first: PAGE, after } },\n updateQuery: (prev, { fetchMoreResult }) => ({\n planmagnetWorkItemComments: {\n ...fetchMoreResult.planmagnetWorkItemComments,\n items: [\n ...prev.planmagnetWorkItemComments.items,\n ...fetchMoreResult.planmagnetWorkItemComments.items,\n ],\n },\n }),\n });\n } finally {\n setLoadingMore(false);\n }\n };\n\n return (\n <Card data-testid=\"work-item-comments\">\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <MessageSquare className=\"h-4 w-4\" />\n Discussion {thread ? `(${thread.totalCount})` : ''}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {error && <ErrorLine message={error} />}\n {loading && !data && <p className=\"text-sm text-muted-foreground\">Loading comments…</p>}\n {loadError && <ErrorLine message={`Comments could not be loaded: ${loadError.message}`} />}\n {thread && comments.length === 0 && (\n <p className=\"text-sm text-muted-foreground\">No comments yet.</p>\n )}\n <ol className=\"space-y-3\">\n {comments.map((comment) => (\n <CommentRow\n key={comment.id}\n comment={comment}\n mine={comment.authorId === currentUser?.id}\n onError={setError}\n />\n ))}\n </ol>\n {thread?.pageInfo.hasNextPage && (\n <Button size=\"sm\" variant=\"outline\" onClick={loadMore} disabled={loadingMore}>\n {loadingMore ? 'Loading…' : `Show more (${comments.length} of ${thread.totalCount})`}\n </Button>\n )}\n <div className=\"space-y-2 border-t pt-4\">\n <label htmlFor={`comment-${workItemId}`} className=\"sr-only\">\n Add a comment\n </label>\n <textarea\n id={`comment-${workItemId}`}\n className=\"w-full min-h-[80px] rounded-md border border-input bg-background px-3 py-2 text-sm\"\n placeholder=\"Add a comment…\"\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n />\n {tooLong && <ErrorLine message={`A comment can be at most ${MAX_LENGTH} characters.`} />}\n <div className=\"flex justify-end\">\n <Button\n size=\"sm\"\n onClick={post}\n disabled={!trimmed || tooLong || addState.loading}\n data-testid=\"comment-post\"\n >\n {addState.loading ? 'Posting…' : 'Comment'}\n </Button>\n </div>\n </div>\n </CardContent>\n </Card>\n );\n}\n\n/**\n * Refusals are reported to the PANEL, not kept in the row: a refused edit or\n * delete still refetches the thread, and when the comment is gone (deleted\n * elsewhere) the row unmounts, taking a row-level message with it. Seen in the\n * prod verification: the comment vanished and the reason was never shown.\n */\nfunction CommentRow({\n comment,\n mine,\n onError,\n}: {\n comment: Comment;\n mine: boolean;\n onError: (message: string | null) => void;\n}) {\n const [editing, setEditing] = useState(false);\n const [text, setText] = useState(comment.body);\n const setError = onError;\n const refetch = { refetchQueries: ['WorkItemComments'], awaitRefetchQueries: true };\n const [edit, editState] = useMutation(EDIT, refetch);\n const [remove, removeState] = useMutation(DELETE, refetch);\n\n const save = async () => {\n setError(null);\n try {\n await throwOnError(edit({ variables: { id: comment.id, body: text.trim() } }));\n setEditing(false);\n } catch (e) {\n setError(messageOf(e, 'The comment could not be saved.'));\n }\n };\n\n return (\n <li className=\"rounded-md border p-3 space-y-1\" data-testid=\"comment\">\n <div className=\"flex items-center justify-between gap-2 text-xs text-muted-foreground\">\n <span>\n <span className=\"font-medium text-foreground\">\n <PersonName id={comment.authorId} />\n </span>{' '}\n · {when(comment.createdAt)}\n {comment.editedAt && <span title={`Edited ${when(comment.editedAt)}`}> · edited</span>}\n </span>\n {mine && !editing && (\n <span className=\"flex gap-1\">\n <Button\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-6 px-2 text-xs\"\n onClick={() => setEditing(true)}\n >\n Edit\n </Button>\n <AlertDialog>\n <AlertDialogTrigger asChild>\n <Button\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-6 px-2 text-xs\"\n disabled={removeState.loading}\n >\n Delete\n </Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Delete this comment?</AlertDialogTitle>\n <AlertDialogDescription>\n It is removed from the discussion for everyone.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Keep it</AlertDialogCancel>\n <AlertDialogAction\n className=\"bg-destructive text-destructive-foreground hover:bg-destructive/90\"\n onClick={async () => {\n setError(null);\n try {\n await throwOnError(remove({ variables: { id: comment.id } }));\n } catch (e) {\n setError(messageOf(e, 'The comment could not be deleted.'));\n }\n }}\n >\n Delete\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </span>\n )}\n </div>\n {editing ? (\n <div className=\"space-y-2\">\n <textarea\n aria-label=\"Edit comment\"\n className=\"w-full min-h-[60px] rounded-md border border-input bg-background px-3 py-2 text-sm\"\n value={text}\n onChange={(e) => setText(e.target.value)}\n />\n <div className=\"flex justify-end gap-2\">\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => {\n setEditing(false);\n setText(comment.body);\n setError(null);\n }}\n >\n Cancel\n </Button>\n <Button size=\"sm\" onClick={save} disabled={!text.trim() || editState.loading}>\n {editState.loading ? 'Saving…' : 'Save'}\n </Button>\n </div>\n </div>\n ) : (\n <p className=\"text-sm whitespace-pre-wrap break-words\">{comment.body}</p>\n )}\n </li>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WorkItemComments.js","names":[],"sources":["../../../src/planmagnet/comments/WorkItemComments.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n} from '@burdenoff/fe-libs/ui';\nimport { MessageSquare } from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\nimport { PersonName } from '../people/People';\nimport { throwOnError } from '../utils/mutationResult';\n\n/**\n * Discussion on a work item (P1.4). Anyone who can read the item sees the\n * thread; posting needs edit rights on work items; only a comment's author\n * can edit or delete it. The server enforces all three and says why it refused\n * (shown inline). The controls here only avoid offering what would be refused.\n */\n\nconst MAX_LENGTH = 10_000;\nconst PAGE = 50;\n\nconst COMMENTS = gql`\n query WorkItemComments($workItemId: ID!, $pagination: PlanmagnetPaginationInput) {\n planmagnetWorkItemComments(workItemId: $workItemId, pagination: $pagination) {\n totalCount\n pageInfo {\n hasNextPage\n endCursor\n }\n items {\n id\n authorId\n body\n createdAt\n editedAt\n }\n }\n }\n`;\nconst ADD = gql`\n mutation WorkItemCommentAdd($input: PlanmagnetAddWorkItemCommentInput!) {\n planmagnetAddWorkItemComment(input: $input) {\n id\n }\n }\n`;\nconst EDIT = gql`\n mutation WorkItemCommentEdit($id: ID!, $body: String!) {\n planmagnetEditWorkItemComment(id: $id, body: $body) {\n id\n body\n editedAt\n }\n }\n`;\nconst DELETE = gql`\n mutation WorkItemCommentDelete($id: ID!) {\n planmagnetDeleteWorkItemComment(id: $id)\n }\n`;\n\ninterface Comment {\n id: string;\n authorId: string;\n body: string;\n createdAt: string;\n editedAt: string | null;\n}\n\ninterface CommentsData {\n planmagnetWorkItemComments: {\n totalCount: number;\n pageInfo: { hasNextPage: boolean; endCursor: string | null };\n items: Comment[];\n };\n}\n\nconst messageOf = (e: unknown, fallback: string) => (e instanceof Error ? e.message : fallback);\nconst when = (iso: string) => new Date(iso).toLocaleString();\n\nfunction ErrorLine({ message }: { message: string }) {\n return (\n <p role=\"alert\" className=\"text-sm text-destructive\">\n {message}\n </p>\n );\n}\n\nexport function WorkItemComments({ workItemId }: { workItemId: string }) {\n const { currentUser } = usePlanMagnet();\n const [draft, setDraft] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [loadingMore, setLoadingMore] = useState(false);\n\n const {\n data,\n loading,\n error: loadError,\n fetchMore,\n } = useQuery<CommentsData>(COMMENTS, {\n variables: { workItemId, pagination: { first: PAGE } },\n skip: !workItemId,\n });\n const refetch = {\n refetchQueries: ['WorkItemComments', 'WorkItemActivity'],\n awaitRefetchQueries: true,\n };\n const [add, addState] = useMutation(ADD, refetch);\n\n const thread = data?.planmagnetWorkItemComments;\n const comments = thread?.items ?? [];\n const trimmed = draft.trim();\n const tooLong = trimmed.length > MAX_LENGTH;\n\n const post = async () => {\n setError(null);\n try {\n await throwOnError(add({ variables: { input: { workItemId, body: trimmed } } }));\n setDraft('');\n } catch (e) {\n setError(messageOf(e, 'The comment could not be posted.'));\n }\n };\n\n const loadMore = async () => {\n const after = thread?.pageInfo.endCursor;\n if (!after) return;\n setLoadingMore(true);\n try {\n await fetchMore({\n variables: { pagination: { first: PAGE, after } },\n updateQuery: (prev, { fetchMoreResult }) => ({\n planmagnetWorkItemComments: {\n ...fetchMoreResult.planmagnetWorkItemComments,\n items: [\n ...prev.planmagnetWorkItemComments.items,\n ...fetchMoreResult.planmagnetWorkItemComments.items,\n ],\n },\n }),\n });\n } finally {\n setLoadingMore(false);\n }\n };\n\n return (\n <Card data-testid=\"work-item-comments\">\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <MessageSquare className=\"h-4 w-4\" />\n Discussion {thread ? `(${thread.totalCount})` : ''}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {error && <ErrorLine message={error} />}\n {loading && !data && <p className=\"text-sm text-muted-foreground\">Loading comments…</p>}\n {loadError && <ErrorLine message={`Comments could not be loaded: ${loadError.message}`} />}\n {thread && comments.length === 0 && (\n <p className=\"text-sm text-muted-foreground\">No comments yet.</p>\n )}\n <ol className=\"space-y-3\">\n {comments.map((comment) => (\n <CommentRow\n key={comment.id}\n comment={comment}\n mine={comment.authorId === currentUser?.id}\n onError={setError}\n />\n ))}\n </ol>\n {thread?.pageInfo.hasNextPage && (\n <Button size=\"sm\" variant=\"outline\" onClick={loadMore} disabled={loadingMore}>\n {loadingMore ? 'Loading…' : `Show more (${comments.length} of ${thread.totalCount})`}\n </Button>\n )}\n <div className=\"space-y-2 border-t pt-4\">\n <label htmlFor={`comment-${workItemId}`} className=\"sr-only\">\n Add a comment\n </label>\n <textarea\n id={`comment-${workItemId}`}\n className=\"w-full min-h-[80px] rounded-md border border-input bg-background px-3 py-2 text-sm\"\n placeholder=\"Add a comment…\"\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n />\n {tooLong && <ErrorLine message={`A comment can be at most ${MAX_LENGTH} characters.`} />}\n <div className=\"flex justify-end\">\n <Button\n size=\"sm\"\n onClick={post}\n disabled={!trimmed || tooLong || addState.loading}\n data-testid=\"comment-post\"\n >\n {addState.loading ? 'Posting…' : 'Comment'}\n </Button>\n </div>\n </div>\n </CardContent>\n </Card>\n );\n}\n\n/**\n * Refusals are reported to the PANEL, not kept in the row: a refused edit or\n * delete still refetches the thread, and when the comment is gone (deleted\n * elsewhere) the row unmounts, taking a row-level message with it. Seen in the\n * prod verification: the comment vanished and the reason was never shown.\n */\nfunction CommentRow({\n comment,\n mine,\n onError,\n}: {\n comment: Comment;\n mine: boolean;\n onError: (message: string | null) => void;\n}) {\n const [editing, setEditing] = useState(false);\n const [text, setText] = useState(comment.body);\n const setError = onError;\n const refetch = {\n refetchQueries: ['WorkItemComments', 'WorkItemActivity'],\n awaitRefetchQueries: true,\n };\n const [edit, editState] = useMutation(EDIT, refetch);\n const [remove, removeState] = useMutation(DELETE, refetch);\n\n const save = async () => {\n setError(null);\n try {\n await throwOnError(edit({ variables: { id: comment.id, body: text.trim() } }));\n setEditing(false);\n } catch (e) {\n setError(messageOf(e, 'The comment could not be saved.'));\n }\n };\n\n return (\n <li className=\"rounded-md border p-3 space-y-1\" data-testid=\"comment\">\n <div className=\"flex items-center justify-between gap-2 text-xs text-muted-foreground\">\n <span>\n <span className=\"font-medium text-foreground\">\n <PersonName id={comment.authorId} />\n </span>{' '}\n · {when(comment.createdAt)}\n {comment.editedAt && <span title={`Edited ${when(comment.editedAt)}`}> · edited</span>}\n </span>\n {mine && !editing && (\n <span className=\"flex gap-1\">\n <Button\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-6 px-2 text-xs\"\n onClick={() => setEditing(true)}\n >\n Edit\n </Button>\n <AlertDialog>\n <AlertDialogTrigger asChild>\n <Button\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-6 px-2 text-xs\"\n disabled={removeState.loading}\n >\n Delete\n </Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Delete this comment?</AlertDialogTitle>\n <AlertDialogDescription>\n It is removed from the discussion for everyone.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Keep it</AlertDialogCancel>\n <AlertDialogAction\n className=\"bg-destructive text-destructive-foreground hover:bg-destructive/90\"\n onClick={async () => {\n setError(null);\n try {\n await throwOnError(remove({ variables: { id: comment.id } }));\n } catch (e) {\n setError(messageOf(e, 'The comment could not be deleted.'));\n }\n }}\n >\n Delete\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </span>\n )}\n </div>\n {editing ? (\n <div className=\"space-y-2\">\n <textarea\n aria-label=\"Edit comment\"\n className=\"w-full min-h-[60px] rounded-md border border-input bg-background px-3 py-2 text-sm\"\n value={text}\n onChange={(e) => setText(e.target.value)}\n />\n <div className=\"flex justify-end gap-2\">\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => {\n setEditing(false);\n setText(comment.body);\n setError(null);\n }}\n >\n Cancel\n </Button>\n <Button size=\"sm\" onClick={save} disabled={!text.trim() || editState.loading}>\n {editState.loading ? 'Saving…' : 'Save'}\n </Button>\n </div>\n </div>\n ) : (\n <p className=\"text-sm whitespace-pre-wrap break-words\">{comment.body}</p>\n )}\n </li>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProductsReleaseDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProductsReleaseDetailPagePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ProductsReleaseDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProductsReleaseDetailPagePage.tsx"],"names":[],"mappings":"AA2DA,wBAAgB,6BAA6B,4CAgM5C"}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { usePlanMagnet as e } from "../providers/PlanMagnetProvider.js";
|
|
2
2
|
import { PersonName as t } from "../people/People.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
3
|
+
import { ReleaseNotesCard as n } from "../releases/ReleaseNotesCard.js";
|
|
4
|
+
import { Calendar as r, Clock as i, GitBranch as a, Loader2 as o } from "lucide-react";
|
|
5
|
+
import { useParams as s } from "react-router";
|
|
6
|
+
import { gql as c } from "@apollo/client";
|
|
7
|
+
import { useQuery as l } from "@apollo/client/react";
|
|
8
|
+
import { jsx as u, jsxs as d } from "react/jsx-runtime";
|
|
9
|
+
import { Badge as f, Card as p, CardContent as m, CardHeader as h, CardTitle as g } from "@burdenoff/fe-libs/ui";
|
|
10
|
+
import { Markdown as _ } from "@burdenoff/fe-libs/shared/components";
|
|
10
11
|
//#region src/planmagnet/pages/ProductsReleaseDetailPagePage.tsx
|
|
11
|
-
var
|
|
12
|
+
var v = c`
|
|
12
13
|
query GetRelease($id: ID!) {
|
|
13
14
|
planmagnetRelease(id: $id) {
|
|
14
15
|
id
|
|
@@ -35,7 +36,7 @@ var _ = s`
|
|
|
35
36
|
}
|
|
36
37
|
}
|
|
37
38
|
}
|
|
38
|
-
`,
|
|
39
|
+
`, y = {
|
|
39
40
|
DRAFT: "bg-gray-100 text-gray-800",
|
|
40
41
|
PLANNING: "bg-yellow-100 text-yellow-800",
|
|
41
42
|
IN_PROGRESS: "bg-blue-100 text-blue-800",
|
|
@@ -44,89 +45,89 @@ var _ = s`
|
|
|
44
45
|
CANCELLED: "bg-red-100 text-red-800",
|
|
45
46
|
ROLLED_BACK: "bg-red-100 text-red-800"
|
|
46
47
|
};
|
|
47
|
-
function
|
|
48
|
-
let { workspaceId:
|
|
49
|
-
variables: { id:
|
|
50
|
-
skip: !
|
|
48
|
+
function b() {
|
|
49
|
+
let { workspaceId: c } = e(), b = s().id ?? "", { data: x, loading: S, error: C } = l(v, {
|
|
50
|
+
variables: { id: b },
|
|
51
|
+
skip: !b
|
|
51
52
|
});
|
|
52
|
-
if (
|
|
53
|
+
if (S) return /* @__PURE__ */ u("div", {
|
|
53
54
|
className: "flex items-center justify-center p-12",
|
|
54
|
-
children: /* @__PURE__ */
|
|
55
|
+
children: /* @__PURE__ */ u(o, { className: "h-8 w-8 animate-spin text-muted-foreground" })
|
|
55
56
|
});
|
|
56
|
-
if (
|
|
57
|
+
if (C) return /* @__PURE__ */ d("div", {
|
|
57
58
|
className: "p-6 text-destructive",
|
|
58
|
-
children: ["Failed to load release: ",
|
|
59
|
+
children: ["Failed to load release: ", C.message]
|
|
59
60
|
});
|
|
60
|
-
let
|
|
61
|
-
if (!
|
|
61
|
+
let w = x?.planmagnetRelease;
|
|
62
|
+
if (!w) return /* @__PURE__ */ u("div", {
|
|
62
63
|
className: "p-6 text-muted-foreground",
|
|
63
64
|
children: "Release not found."
|
|
64
65
|
});
|
|
65
|
-
let
|
|
66
|
-
return /* @__PURE__ */
|
|
66
|
+
let T = w.workItems ?? [], E = T.filter((e) => e.type === "STORY" || e.type === "FEATURE"), D = T.filter((e) => e.type === "BUG");
|
|
67
|
+
return /* @__PURE__ */ d("div", {
|
|
67
68
|
className: "space-y-6 p-6",
|
|
68
|
-
children: [/* @__PURE__ */
|
|
69
|
+
children: [/* @__PURE__ */ d("div", {
|
|
69
70
|
className: "flex items-center justify-between",
|
|
70
|
-
children: [/* @__PURE__ */
|
|
71
|
+
children: [/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ d("div", {
|
|
71
72
|
className: "flex items-center gap-2",
|
|
72
73
|
children: [
|
|
73
|
-
/* @__PURE__ */
|
|
74
|
-
/* @__PURE__ */
|
|
74
|
+
/* @__PURE__ */ u(a, { className: "h-5 w-5 text-primary" }),
|
|
75
|
+
/* @__PURE__ */ u("h1", {
|
|
75
76
|
className: "text-2xl font-semibold",
|
|
76
|
-
children:
|
|
77
|
+
children: w.version
|
|
77
78
|
}),
|
|
78
|
-
/* @__PURE__ */
|
|
79
|
-
className: `text-xs px-2 py-0.5 rounded-full capitalize ${
|
|
80
|
-
children:
|
|
79
|
+
/* @__PURE__ */ u("span", {
|
|
80
|
+
className: `text-xs px-2 py-0.5 rounded-full capitalize ${y[w.status] ?? "bg-gray-100"}`,
|
|
81
|
+
children: w.status.toLowerCase().replace("_", " ")
|
|
81
82
|
})
|
|
82
83
|
]
|
|
83
|
-
}), /* @__PURE__ */
|
|
84
|
+
}), /* @__PURE__ */ u("p", {
|
|
84
85
|
className: "text-sm text-muted-foreground mt-1",
|
|
85
|
-
children:
|
|
86
|
-
})] }), /* @__PURE__ */
|
|
86
|
+
children: w.name
|
|
87
|
+
})] }), /* @__PURE__ */ u(f, {
|
|
87
88
|
variant: "outline",
|
|
88
89
|
className: "capitalize",
|
|
89
|
-
children:
|
|
90
|
+
children: w.status.toLowerCase().replace("_", " ")
|
|
90
91
|
})]
|
|
91
|
-
}), /* @__PURE__ */
|
|
92
|
+
}), /* @__PURE__ */ d("div", {
|
|
92
93
|
className: "grid grid-cols-1 lg:grid-cols-3 gap-6",
|
|
93
|
-
children: [/* @__PURE__ */
|
|
94
|
+
children: [/* @__PURE__ */ d("div", {
|
|
94
95
|
className: "lg:col-span-2 space-y-6",
|
|
95
96
|
children: [
|
|
96
|
-
/* @__PURE__ */
|
|
97
|
+
/* @__PURE__ */ d(p, { children: [/* @__PURE__ */ u(h, { children: /* @__PURE__ */ u(g, { children: "Overview" }) }), /* @__PURE__ */ d(m, {
|
|
97
98
|
className: "space-y-4",
|
|
98
|
-
children: [/* @__PURE__ */
|
|
99
|
+
children: [/* @__PURE__ */ u("div", {
|
|
99
100
|
className: "text-sm prose prose-sm dark:prose-invert max-w-none",
|
|
100
|
-
children:
|
|
101
|
-
}), /* @__PURE__ */
|
|
101
|
+
children: w.description ? /* @__PURE__ */ u(_, { children: w.description }) : /* @__PURE__ */ u("p", { children: "No description provided." })
|
|
102
|
+
}), /* @__PURE__ */ d("div", {
|
|
102
103
|
className: "grid grid-cols-3 gap-4",
|
|
103
104
|
children: [
|
|
104
|
-
/* @__PURE__ */
|
|
105
|
+
/* @__PURE__ */ d("div", {
|
|
105
106
|
className: "text-center p-3 bg-muted rounded-md",
|
|
106
|
-
children: [/* @__PURE__ */
|
|
107
|
+
children: [/* @__PURE__ */ u("p", {
|
|
107
108
|
className: "text-lg font-semibold mt-1",
|
|
108
|
-
children:
|
|
109
|
-
}), /* @__PURE__ */
|
|
109
|
+
children: E.length
|
|
110
|
+
}), /* @__PURE__ */ u("p", {
|
|
110
111
|
className: "text-xs text-muted-foreground",
|
|
111
112
|
children: "Features"
|
|
112
113
|
})]
|
|
113
114
|
}),
|
|
114
|
-
/* @__PURE__ */
|
|
115
|
+
/* @__PURE__ */ d("div", {
|
|
115
116
|
className: "text-center p-3 bg-muted rounded-md",
|
|
116
|
-
children: [/* @__PURE__ */
|
|
117
|
+
children: [/* @__PURE__ */ u("p", {
|
|
117
118
|
className: "text-lg font-semibold mt-1",
|
|
118
|
-
children:
|
|
119
|
-
}), /* @__PURE__ */
|
|
119
|
+
children: D.length
|
|
120
|
+
}), /* @__PURE__ */ u("p", {
|
|
120
121
|
className: "text-xs text-muted-foreground",
|
|
121
122
|
children: "Bug Fixes"
|
|
122
123
|
})]
|
|
123
124
|
}),
|
|
124
|
-
/* @__PURE__ */
|
|
125
|
+
/* @__PURE__ */ d("div", {
|
|
125
126
|
className: "text-center p-3 bg-muted rounded-md",
|
|
126
|
-
children: [/* @__PURE__ */
|
|
127
|
+
children: [/* @__PURE__ */ u("p", {
|
|
127
128
|
className: "text-lg font-semibold mt-1",
|
|
128
|
-
children:
|
|
129
|
-
}), /* @__PURE__ */
|
|
129
|
+
children: T.length
|
|
130
|
+
}), /* @__PURE__ */ u("p", {
|
|
130
131
|
className: "text-xs text-muted-foreground",
|
|
131
132
|
children: "Total Items"
|
|
132
133
|
})]
|
|
@@ -134,22 +135,22 @@ function y() {
|
|
|
134
135
|
]
|
|
135
136
|
})]
|
|
136
137
|
})] }),
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
})
|
|
141
|
-
|
|
138
|
+
/* @__PURE__ */ u(n, {
|
|
139
|
+
releaseId: w.id,
|
|
140
|
+
notes: w.releaseNotes ?? null
|
|
141
|
+
}),
|
|
142
|
+
T.length > 0 && /* @__PURE__ */ d(p, { children: [/* @__PURE__ */ u(h, { children: /* @__PURE__ */ d(g, { children: [
|
|
142
143
|
"Work Items (",
|
|
143
|
-
|
|
144
|
+
T.length,
|
|
144
145
|
")"
|
|
145
|
-
] }) }), /* @__PURE__ */
|
|
146
|
+
] }) }), /* @__PURE__ */ u(m, {
|
|
146
147
|
className: "space-y-2",
|
|
147
|
-
children:
|
|
148
|
+
children: T.map((e) => /* @__PURE__ */ d("div", {
|
|
148
149
|
className: "flex items-center justify-between border rounded-md p-3",
|
|
149
|
-
children: [/* @__PURE__ */
|
|
150
|
+
children: [/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("p", {
|
|
150
151
|
className: "text-sm font-medium",
|
|
151
152
|
children: e.title
|
|
152
|
-
}), /* @__PURE__ */
|
|
153
|
+
}), /* @__PURE__ */ d("p", {
|
|
153
154
|
className: "text-xs text-muted-foreground capitalize",
|
|
154
155
|
children: [
|
|
155
156
|
e.type.toLowerCase(),
|
|
@@ -157,7 +158,7 @@ function y() {
|
|
|
157
158
|
e.priority.toLowerCase(),
|
|
158
159
|
" priority"
|
|
159
160
|
]
|
|
160
|
-
})] }), /* @__PURE__ */
|
|
161
|
+
})] }), /* @__PURE__ */ u(f, {
|
|
161
162
|
variant: "outline",
|
|
162
163
|
className: "text-xs capitalize",
|
|
163
164
|
children: e.status.toLowerCase().replace("_", " ")
|
|
@@ -165,89 +166,89 @@ function y() {
|
|
|
165
166
|
}, e.id))
|
|
166
167
|
})] })
|
|
167
168
|
]
|
|
168
|
-
}), /* @__PURE__ */
|
|
169
|
+
}), /* @__PURE__ */ d("div", {
|
|
169
170
|
className: "space-y-6",
|
|
170
171
|
children: [
|
|
171
|
-
/* @__PURE__ */
|
|
172
|
+
/* @__PURE__ */ d(p, { children: [/* @__PURE__ */ u(h, { children: /* @__PURE__ */ u(g, { children: "Timeline" }) }), /* @__PURE__ */ d(m, {
|
|
172
173
|
className: "space-y-3 text-sm",
|
|
173
|
-
children: [/* @__PURE__ */
|
|
174
|
+
children: [/* @__PURE__ */ d("div", {
|
|
174
175
|
className: "flex items-center gap-2",
|
|
175
176
|
children: [
|
|
176
|
-
/* @__PURE__ */
|
|
177
|
-
/* @__PURE__ */
|
|
177
|
+
/* @__PURE__ */ u(r, { className: "h-4 w-4 text-muted-foreground" }),
|
|
178
|
+
/* @__PURE__ */ u("span", {
|
|
178
179
|
className: "text-muted-foreground",
|
|
179
180
|
children: "Planned:"
|
|
180
181
|
}),
|
|
181
|
-
/* @__PURE__ */
|
|
182
|
+
/* @__PURE__ */ u("span", {
|
|
182
183
|
className: "font-medium",
|
|
183
|
-
children:
|
|
184
|
+
children: w.plannedDate ? new Date(w.plannedDate).toLocaleDateString() : "Not set"
|
|
184
185
|
})
|
|
185
186
|
]
|
|
186
|
-
}),
|
|
187
|
+
}), w.releasedAt && /* @__PURE__ */ d("div", {
|
|
187
188
|
className: "flex items-center gap-2",
|
|
188
189
|
children: [
|
|
189
|
-
/* @__PURE__ */
|
|
190
|
-
/* @__PURE__ */
|
|
190
|
+
/* @__PURE__ */ u(i, { className: "h-4 w-4 text-green-500" }),
|
|
191
|
+
/* @__PURE__ */ u("span", {
|
|
191
192
|
className: "text-muted-foreground",
|
|
192
193
|
children: "Released:"
|
|
193
194
|
}),
|
|
194
|
-
/* @__PURE__ */
|
|
195
|
+
/* @__PURE__ */ u("span", {
|
|
195
196
|
className: "font-medium",
|
|
196
|
-
children: new Date(
|
|
197
|
+
children: new Date(w.releasedAt).toLocaleDateString()
|
|
197
198
|
})
|
|
198
199
|
]
|
|
199
200
|
})]
|
|
200
201
|
})] }),
|
|
201
|
-
/* @__PURE__ */
|
|
202
|
+
/* @__PURE__ */ d(p, { children: [/* @__PURE__ */ u(h, { children: /* @__PURE__ */ u(g, { children: "Details" }) }), /* @__PURE__ */ d(m, {
|
|
202
203
|
className: "space-y-2 text-sm",
|
|
203
204
|
children: [
|
|
204
|
-
/* @__PURE__ */
|
|
205
|
+
/* @__PURE__ */ d("div", {
|
|
205
206
|
className: "flex justify-between",
|
|
206
|
-
children: [/* @__PURE__ */
|
|
207
|
+
children: [/* @__PURE__ */ u("span", {
|
|
207
208
|
className: "text-muted-foreground",
|
|
208
209
|
children: "Version"
|
|
209
|
-
}), /* @__PURE__ */
|
|
210
|
+
}), /* @__PURE__ */ u("span", {
|
|
210
211
|
className: "font-medium",
|
|
211
|
-
children:
|
|
212
|
+
children: w.version
|
|
212
213
|
})]
|
|
213
214
|
}),
|
|
214
|
-
/* @__PURE__ */
|
|
215
|
+
/* @__PURE__ */ d("div", {
|
|
215
216
|
className: "flex justify-between",
|
|
216
|
-
children: [/* @__PURE__ */
|
|
217
|
+
children: [/* @__PURE__ */ u("span", {
|
|
217
218
|
className: "text-muted-foreground",
|
|
218
219
|
children: "Status"
|
|
219
|
-
}), /* @__PURE__ */
|
|
220
|
+
}), /* @__PURE__ */ u(f, {
|
|
220
221
|
variant: "outline",
|
|
221
222
|
className: "text-xs capitalize",
|
|
222
|
-
children:
|
|
223
|
+
children: w.status.toLowerCase().replace("_", " ")
|
|
223
224
|
})]
|
|
224
225
|
}),
|
|
225
|
-
/* @__PURE__ */
|
|
226
|
+
/* @__PURE__ */ d("div", {
|
|
226
227
|
className: "flex justify-between",
|
|
227
|
-
children: [/* @__PURE__ */
|
|
228
|
+
children: [/* @__PURE__ */ u("span", {
|
|
228
229
|
className: "text-muted-foreground",
|
|
229
230
|
children: "Owner"
|
|
230
|
-
}), /* @__PURE__ */
|
|
231
|
+
}), /* @__PURE__ */ u("span", { children: /* @__PURE__ */ u(t, { id: w.ownerId }) })]
|
|
231
232
|
}),
|
|
232
|
-
/* @__PURE__ */
|
|
233
|
+
/* @__PURE__ */ d("div", {
|
|
233
234
|
className: "flex justify-between",
|
|
234
|
-
children: [/* @__PURE__ */
|
|
235
|
+
children: [/* @__PURE__ */ u("span", {
|
|
235
236
|
className: "text-muted-foreground",
|
|
236
237
|
children: "Created"
|
|
237
|
-
}), /* @__PURE__ */
|
|
238
|
+
}), /* @__PURE__ */ u("span", { children: new Date(w.createdAt).toLocaleDateString() })]
|
|
238
239
|
}),
|
|
239
|
-
/* @__PURE__ */
|
|
240
|
+
/* @__PURE__ */ d("div", {
|
|
240
241
|
className: "flex justify-between",
|
|
241
|
-
children: [/* @__PURE__ */
|
|
242
|
+
children: [/* @__PURE__ */ u("span", {
|
|
242
243
|
className: "text-muted-foreground",
|
|
243
244
|
children: "Updated"
|
|
244
|
-
}), /* @__PURE__ */
|
|
245
|
+
}), /* @__PURE__ */ u("span", { children: new Date(w.updatedAt).toLocaleDateString() })]
|
|
245
246
|
})
|
|
246
247
|
]
|
|
247
248
|
})] }),
|
|
248
|
-
|
|
249
|
+
w.tags?.length > 0 && /* @__PURE__ */ d(p, { children: [/* @__PURE__ */ u(h, { children: /* @__PURE__ */ u(g, { children: "Tags" }) }), /* @__PURE__ */ u(m, {
|
|
249
250
|
className: "flex flex-wrap gap-1",
|
|
250
|
-
children:
|
|
251
|
+
children: w.tags.map((e) => /* @__PURE__ */ u(f, {
|
|
251
252
|
variant: "outline",
|
|
252
253
|
className: "text-xs",
|
|
253
254
|
children: e
|
|
@@ -259,6 +260,6 @@ function y() {
|
|
|
259
260
|
});
|
|
260
261
|
}
|
|
261
262
|
//#endregion
|
|
262
|
-
export {
|
|
263
|
+
export { b as ProductsReleaseDetailPagePage };
|
|
263
264
|
|
|
264
265
|
//# sourceMappingURL=ProductsReleaseDetailPagePage.js.map
|