@burdenoff/microfe-planmagnet 2026.927.2 → 2026.927.4

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 (106) hide show
  1. package/dist/planmagnet/admin/PlanMagnetAdminRoot.d.ts.map +1 -1
  2. package/dist/planmagnet/admin/PlanMagnetAdminRoot.js +128 -124
  3. package/dist/planmagnet/admin/PlanMagnetAdminRoot.js.map +1 -1
  4. package/dist/planmagnet/controls/ConfirmButton.d.ts +25 -0
  5. package/dist/planmagnet/controls/ConfirmButton.d.ts.map +1 -0
  6. package/dist/planmagnet/controls/ConfirmButton.js +30 -0
  7. package/dist/planmagnet/controls/ConfirmButton.js.map +1 -0
  8. package/dist/planmagnet/controls/FeatureControls.d.ts +26 -0
  9. package/dist/planmagnet/controls/FeatureControls.d.ts.map +1 -0
  10. package/dist/planmagnet/controls/FeatureControls.js +318 -0
  11. package/dist/planmagnet/controls/FeatureControls.js.map +1 -0
  12. package/dist/planmagnet/controls/MilestoneControls.d.ts +17 -0
  13. package/dist/planmagnet/controls/MilestoneControls.d.ts.map +1 -0
  14. package/dist/planmagnet/controls/MilestoneControls.js +200 -0
  15. package/dist/planmagnet/controls/MilestoneControls.js.map +1 -0
  16. package/dist/planmagnet/controls/ObjectiveControls.d.ts +31 -0
  17. package/dist/planmagnet/controls/ObjectiveControls.d.ts.map +1 -0
  18. package/dist/planmagnet/controls/ObjectiveControls.js +296 -0
  19. package/dist/planmagnet/controls/ObjectiveControls.js.map +1 -0
  20. package/dist/planmagnet/controls/Pickers.d.ts +26 -0
  21. package/dist/planmagnet/controls/Pickers.d.ts.map +1 -0
  22. package/dist/planmagnet/controls/Pickers.js +171 -0
  23. package/dist/planmagnet/controls/Pickers.js.map +1 -0
  24. package/dist/planmagnet/controls/ProjectControls.d.ts +13 -0
  25. package/dist/planmagnet/controls/ProjectControls.d.ts.map +1 -0
  26. package/dist/planmagnet/controls/ProjectControls.js +104 -0
  27. package/dist/planmagnet/controls/ProjectControls.js.map +1 -0
  28. package/dist/planmagnet/controls/ReleaseControls.d.ts +14 -0
  29. package/dist/planmagnet/controls/ReleaseControls.d.ts.map +1 -0
  30. package/dist/planmagnet/controls/ReleaseControls.js +108 -0
  31. package/dist/planmagnet/controls/ReleaseControls.js.map +1 -0
  32. package/dist/planmagnet/controls/WorkItemControls.d.ts +52 -0
  33. package/dist/planmagnet/controls/WorkItemControls.d.ts.map +1 -0
  34. package/dist/planmagnet/controls/WorkItemControls.js +198 -0
  35. package/dist/planmagnet/controls/WorkItemControls.js.map +1 -0
  36. package/dist/planmagnet/pages/DocsDocDetailPagePage.d.ts.map +1 -1
  37. package/dist/planmagnet/pages/DocsDocDetailPagePage.js +188 -154
  38. package/dist/planmagnet/pages/DocsDocDetailPagePage.js.map +1 -1
  39. package/dist/planmagnet/pages/DocsDocsPagePage.js +4 -4
  40. package/dist/planmagnet/pages/GoalsCreateObjectivePagePage.d.ts.map +1 -1
  41. package/dist/planmagnet/pages/GoalsCreateObjectivePagePage.js +63 -56
  42. package/dist/planmagnet/pages/GoalsCreateObjectivePagePage.js.map +1 -1
  43. package/dist/planmagnet/pages/GoalsObjectiveDetailPagePage.d.ts.map +1 -1
  44. package/dist/planmagnet/pages/GoalsObjectiveDetailPagePage.js +229 -214
  45. package/dist/planmagnet/pages/GoalsObjectiveDetailPagePage.js.map +1 -1
  46. package/dist/planmagnet/pages/ProductsEditProductPagePage.d.ts.map +1 -1
  47. package/dist/planmagnet/pages/ProductsEditProductPagePage.js +142 -114
  48. package/dist/planmagnet/pages/ProductsEditProductPagePage.js.map +1 -1
  49. package/dist/planmagnet/pages/ProductsEditReleasePagePage.d.ts.map +1 -1
  50. package/dist/planmagnet/pages/ProductsEditReleasePagePage.js +134 -105
  51. package/dist/planmagnet/pages/ProductsEditReleasePagePage.js.map +1 -1
  52. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.d.ts.map +1 -1
  53. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js +102 -108
  54. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js.map +1 -1
  55. package/dist/planmagnet/pages/ProductsNewFeaturePagePage.d.ts.map +1 -1
  56. package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js +119 -94
  57. package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js.map +1 -1
  58. package/dist/planmagnet/pages/ProductsProductDetailPagePage.d.ts.map +1 -1
  59. package/dist/planmagnet/pages/ProductsProductDetailPagePage.js +97 -90
  60. package/dist/planmagnet/pages/ProductsProductDetailPagePage.js.map +1 -1
  61. package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.d.ts.map +1 -1
  62. package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.js +107 -106
  63. package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.js.map +1 -1
  64. package/dist/planmagnet/pages/ProductsReleasesPagePage.d.ts.map +1 -1
  65. package/dist/planmagnet/pages/ProductsReleasesPagePage.js +2 -0
  66. package/dist/planmagnet/pages/ProductsReleasesPagePage.js.map +1 -1
  67. package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.d.ts.map +1 -1
  68. package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js +150 -111
  69. package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js.map +1 -1
  70. package/dist/planmagnet/pages/ProjectsEditProjectPagePage.d.ts.map +1 -1
  71. package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js +116 -93
  72. package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js.map +1 -1
  73. package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.d.ts.map +1 -1
  74. package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.js +55 -63
  75. package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.js.map +1 -1
  76. package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.js +4 -4
  77. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.d.ts.map +1 -1
  78. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js +134 -132
  79. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js.map +1 -1
  80. package/dist/planmagnet/pages/SprintsStartSprintPagePage.d.ts.map +1 -1
  81. package/dist/planmagnet/pages/SprintsStartSprintPagePage.js +6 -5
  82. package/dist/planmagnet/pages/SprintsStartSprintPagePage.js.map +1 -1
  83. package/dist/planmagnet/pages/TasksCreateTaskPagePage.d.ts.map +1 -1
  84. package/dist/planmagnet/pages/TasksCreateTaskPagePage.js +167 -116
  85. package/dist/planmagnet/pages/TasksCreateTaskPagePage.js.map +1 -1
  86. package/dist/planmagnet/pages/TasksEditTaskPagePage.d.ts.map +1 -1
  87. package/dist/planmagnet/pages/TasksEditTaskPagePage.js +139 -107
  88. package/dist/planmagnet/pages/TasksEditTaskPagePage.js.map +1 -1
  89. package/dist/planmagnet/pages/TasksTaskDetailPagePage.d.ts.map +1 -1
  90. package/dist/planmagnet/pages/TasksTaskDetailPagePage.js +205 -158
  91. package/dist/planmagnet/pages/TasksTaskDetailPagePage.js.map +1 -1
  92. package/dist/planmagnet/pages/TasksTasksPagePage.d.ts.map +1 -1
  93. package/dist/planmagnet/pages/TasksTasksPagePage.js +1 -0
  94. package/dist/planmagnet/pages/TasksTasksPagePage.js.map +1 -1
  95. package/dist/planmagnet/pages/TeamTeamPagePage.d.ts.map +1 -1
  96. package/dist/planmagnet/pages/TeamTeamPagePage.js +1 -1
  97. package/dist/planmagnet/pages/TeamTeamPagePage.js.map +1 -1
  98. package/dist/planmagnet/people/People.js +1 -1
  99. package/dist/planmagnet/roadmaps/RoadmapControls.d.ts +34 -0
  100. package/dist/planmagnet/roadmaps/RoadmapControls.d.ts.map +1 -0
  101. package/dist/planmagnet/roadmaps/RoadmapControls.js +301 -0
  102. package/dist/planmagnet/roadmaps/RoadmapControls.js.map +1 -0
  103. package/dist/planmagnet/sprints/SprintControls.d.ts.map +1 -1
  104. package/dist/planmagnet/sprints/SprintControls.js +194 -215
  105. package/dist/planmagnet/sprints/SprintControls.js.map +1 -1
  106. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"DocsDocDetailPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/DocsDocDetailPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useSearchParams } from 'react-router';\nimport { gql } from '@apollo/client';\nimport { useApolloClient, 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 Input,\n} from '@burdenoff/fe-libs/ui';\nimport { Markdown } from '@burdenoff/fe-libs/shared/components';\nimport { clearGraphqlFetchResponseCache } from '@burdenoff/fe-libs/shared/graphql';\nimport { ArrowLeft, History, Link2, X } from 'lucide-react';\nimport { MarkdownEditor } from '#src/components/MarkdownEditor';\nimport { usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { PersonName } from '../people/People';\nimport { throwOnError } from '../utils/mutationResult';\nimport { DOC_STATUSES, DocStatusBadge, type DocStatus } from '../docs/DocStatusBadge';\n\n/**\n * One doc (P1.4): read it, edit it with a change note, publish or archive it,\n * browse its history and restore an older version, see and unlink the work\n * items it is attached to, and delete it.\n *\n * Every write carries `expectedVersion` — the version on screen — so a save\n * over someone else's newer edit is refused with the reason, and the editor\n * keeps the unsaved text rather than overwriting theirs.\n */\n\nconst DOC = gql`\n query DocDetail($id: ID!) {\n planmagnetDoc(id: $id) {\n id\n title\n content\n status\n version\n createdBy\n createdAt\n updatedBy\n updatedAt\n revisions {\n id\n version\n title\n content\n changeNote\n createdBy\n createdAt\n }\n linkedWorkItems {\n id\n key\n title\n }\n }\n }\n`;\nconst UPDATE = gql`\n mutation DocUpdate($id: ID!, $input: PlanmagnetUpdateDocInput!) {\n planmagnetUpdateDoc(id: $id, input: $input) {\n id\n version\n status\n }\n }\n`;\nconst REVERT = gql`\n mutation DocRevert($id: ID!, $toVersion: Int!, $expectedVersion: Int) {\n planmagnetRevertDoc(id: $id, toVersion: $toVersion, expectedVersion: $expectedVersion) {\n id\n version\n }\n }\n`;\nconst DELETE = gql`\n mutation DocDelete($id: ID!) {\n planmagnetDeleteDoc(id: $id)\n }\n`;\nconst UNLINK = gql`\n mutation DocUnlinkWorkItem($docId: ID!, $workItemId: ID!) {\n planmagnetUnlinkDocFromWorkItem(docId: $docId, workItemId: $workItemId)\n }\n`;\n\ninterface Revision {\n id: string;\n version: number;\n title: string;\n content: string;\n changeNote: string | null;\n createdBy: string;\n createdAt: string;\n}\n\ninterface Doc {\n id: string;\n title: string;\n content: string;\n status: string;\n version: number;\n createdBy: string;\n createdAt: string;\n updatedBy: string | null;\n updatedAt: string;\n revisions: Revision[];\n linkedWorkItems: { id: string; key: string; title: string }[];\n}\n\nconst messageOf = (e: unknown, fallback: string) => (e instanceof Error ? e.message : fallback);\nconst when = (iso: string) => new Date(iso).toLocaleString();\n\nexport function DocsDocDetailPagePage() {\n const [params] = useSearchParams();\n const docId = params.get('docId') ?? '';\n const navigate = usePlanMagnetNavigate();\n const [editing, setEditing] = useState(false);\n const [title, setTitle] = useState('');\n const [content, setContent] = useState('');\n const [changeNote, setChangeNote] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [viewing, setViewing] = useState<number | null>(null);\n // The version the editor started from — not the one on screen now, which a\n // refetch after someone else's save may already have moved past.\n const [editBase, setEditBase] = useState<number | null>(null);\n\n const {\n data,\n loading,\n error: loadError,\n } = useQuery<{ planmagnetDoc: Doc | null }>(DOC, {\n variables: { id: docId },\n skip: !docId,\n // Cached copies go stale here: a deleted doc, or someone else's newer version.\n fetchPolicy: 'cache-and-network',\n });\n const client = useApolloClient();\n const after = { refetchQueries: ['DocDetail'], awaitRefetchQueries: true };\n const [update, updateState] = useMutation(UPDATE, after);\n const [revert, revertState] = useMutation(REVERT, after);\n const [remove, removeState] = useMutation(DELETE, { refetchQueries: ['DocsList'] });\n const [unlink, unlinkState] = useMutation(UNLINK, after);\n\n const doc = data?.planmagnetDoc;\n const busy = updateState.loading || revertState.loading || removeState.loading;\n\n // Refusals are panel-level: a refused write refetches, and anything the\n // refetch re-renders must not take the reason with it.\n const run = async (action: () => Promise<{ error?: unknown }>, fallback: string) => {\n setError(null);\n try {\n await throwOnError(action());\n return true;\n } catch (e) {\n setError(messageOf(e, fallback));\n // A refusal because the doc moved on: show the current version, but\n // leave the editor's text alone so nothing typed is lost.\n //\n // fe-libs replays any identical query answered in the last 15 s\n // (fetch.ts RECENT_QUERY_CACHE_TTL_MS) underneath Apollo's fetch\n // policies, and only a SUCCESSFUL mutation clears that cache. Measured in\n // prod 2026-09-25: after a refused save, even a network-only read was\n // served the pre-refusal response, so the page kept the old version and\n // never said the doc had moved on. A refused write is still a write\n // attempt: clear the cache (the public API fe-libs documents for this),\n // then read the doc; it lands in the normalized cache the page renders.\n clearGraphqlFetchResponseCache();\n await client\n .query({ query: DOC, variables: { id: docId }, fetchPolicy: 'network-only' })\n .catch(() => undefined);\n return false;\n }\n };\n\n if (!docId) {\n return <div className=\"p-6 text-sm text-muted-foreground\">No doc selected.</div>;\n }\n if (loading && !data) {\n return <div className=\"p-6 text-sm text-muted-foreground\">Loading doc…</div>;\n }\n if (loadError && !doc) {\n return (\n <p role=\"alert\" className=\"p-6 text-sm text-destructive\">\n The doc could not be loaded: {loadError.message}\n </p>\n );\n }\n if (!doc) {\n return (\n <div className=\"space-y-3 p-6\">\n <p className=\"text-sm text-muted-foreground\">\n This doc does not exist in this workspace, or it was deleted.\n </p>\n <Button size=\"sm\" variant=\"outline\" onClick={() => navigate('/docs/docs-page')}>\n Back to docs\n </Button>\n </div>\n );\n }\n\n const startEditing = () => {\n setTitle(doc.title);\n setContent(doc.content);\n setChangeNote('');\n setError(null);\n setEditBase(doc.version);\n setEditing(true);\n };\n const save = async () => {\n const saved = await run(\n () =>\n update({\n variables: {\n id: doc.id,\n input: {\n title: title.trim(),\n content,\n ...(changeNote.trim() ? { changeNote: changeNote.trim() } : {}),\n expectedVersion: editBase,\n },\n },\n }),\n 'The doc could not be saved.'\n );\n if (saved) setEditing(false);\n };\n\n const revisions = [...doc.revisions].sort((a, b) => b.version - a.version);\n const shown = viewing === null ? null : revisions.find((r) => r.version === viewing);\n\n return (\n <div className=\"space-y-6 p-6\" data-testid=\"doc-detail\">\n <Button size=\"sm\" variant=\"ghost\" onClick={() => navigate('/docs/docs-page')}>\n <ArrowLeft className=\"mr-1 h-4 w-4\" />\n All docs\n </Button>\n\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"min-w-0 space-y-1\">\n <h1 className=\"text-2xl font-semibold break-words\" data-testid=\"doc-title\">\n {doc.title}\n </h1>\n <p className=\"text-xs text-muted-foreground\">\n <DocStatusBadge status={doc.status} /> · version {doc.version} · updated{' '}\n {when(doc.updatedAt)} by <PersonName id={doc.updatedBy ?? doc.createdBy} />\n </p>\n </div>\n {!editing && (\n <div className=\"flex flex-wrap gap-2\">\n {DOC_STATUSES.filter((s) => s !== doc.status).map((s: DocStatus) => (\n <Button\n key={s}\n size=\"sm\"\n variant=\"outline\"\n disabled={busy}\n onClick={() =>\n run(\n () =>\n update({\n variables: {\n id: doc.id,\n input: { status: s, expectedVersion: doc.version },\n },\n }),\n 'The status could not be changed.'\n )\n }\n >\n {s === 'PUBLISHED' ? 'Publish' : s === 'ARCHIVED' ? 'Archive' : 'Back to draft'}\n </Button>\n ))}\n <Button size=\"sm\" onClick={startEditing} data-testid=\"doc-edit\">\n Edit\n </Button>\n <AlertDialog>\n <AlertDialogTrigger asChild>\n <Button size=\"sm\" variant=\"outline\" disabled={busy}>\n Delete\n </Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Delete “{doc.title}”?</AlertDialogTitle>\n <AlertDialogDescription>\n The doc and its history are removed for everyone, and it is unlinked from{' '}\n {doc.linkedWorkItems.length} work item\n {doc.linkedWorkItems.length === 1 ? '' : 's'}.\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 const deleted = await run(\n () => remove({ variables: { id: doc.id } }),\n 'The doc could not be deleted.'\n );\n if (deleted) navigate('/docs/docs-page');\n }}\n >\n Delete\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n )}\n </div>\n\n {error && (\n <p role=\"alert\" className=\"text-sm text-destructive\" data-testid=\"doc-error\">\n {error}\n </p>\n )}\n {editing && editBase !== doc.version && (\n <p className=\"text-sm text-status-warning-text\" data-testid=\"doc-moved-on\">\n Someone saved version {doc.version} after you started editing version {editBase}. Your\n text is kept below; copy what you need, then discard and edit the latest.\n </p>\n )}\n\n {editing ? (\n <Card>\n <CardContent className=\"space-y-3 pt-6\">\n <Input\n aria-label=\"Doc title\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n />\n <MarkdownEditor value={content} onChange={setContent} minHeight={240} />\n <Input\n aria-label=\"Change note\"\n placeholder=\"What changed? (optional, shown in the history)\"\n value={changeNote}\n onChange={(e) => setChangeNote(e.target.value)}\n />\n <div className=\"flex justify-end gap-2\">\n <Button\n size=\"sm\"\n variant=\"ghost\"\n onClick={() => {\n setEditing(false);\n setError(null);\n }}\n >\n {editBase !== doc.version ? 'Discard my edits' : 'Cancel'}\n </Button>\n <Button\n size=\"sm\"\n onClick={save}\n disabled={updateState.loading || editBase !== doc.version}\n data-testid=\"doc-save\"\n >\n {updateState.loading ? 'Saving…' : 'Save new version'}\n </Button>\n </div>\n </CardContent>\n </Card>\n ) : (\n <Card>\n <CardContent className=\"prose prose-sm max-w-none pt-6 dark:prose-invert\">\n {doc.content.trim() ? (\n <Markdown>{doc.content}</Markdown>\n ) : (\n <p className=\"text-sm text-muted-foreground\">This doc is empty.</p>\n )}\n </CardContent>\n </Card>\n )}\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n <Card data-testid=\"doc-history\">\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <History className=\"h-4 w-4\" /> History ({revisions.length})\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n <ol className=\"space-y-2\">\n {revisions.map((rev) => {\n const current = rev.version === doc.version;\n return (\n <li\n key={rev.id}\n className=\"space-y-1 rounded-md border p-2\"\n data-testid=\"doc-revision\"\n >\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <span className=\"text-sm font-medium\">\n Version {rev.version}\n {current ? ' (current)' : ''}\n </span>\n <span className=\"flex gap-1\">\n <Button\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-7 text-xs\"\n aria-expanded={viewing === rev.version}\n onClick={() => setViewing(viewing === rev.version ? null : rev.version)}\n >\n {viewing === rev.version ? 'Hide' : 'View'}\n </Button>\n {!current && !editing && (\n <AlertDialog>\n <AlertDialogTrigger asChild>\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7 text-xs\"\n disabled={busy}\n data-testid=\"doc-restore\"\n >\n Restore\n </Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Restore version {rev.version}?</AlertDialogTitle>\n <AlertDialogDescription>\n Its title and text become version {doc.version + 1}. Nothing is\n deleted: version {doc.version} stays in the history.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction\n onClick={() =>\n run(\n () =>\n revert({\n variables: {\n id: doc.id,\n toVersion: rev.version,\n expectedVersion: doc.version,\n },\n }),\n 'The version could not be restored.'\n )\n }\n >\n Restore\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n )}\n </span>\n </div>\n <p className=\"text-xs text-muted-foreground\">\n {when(rev.createdAt)} · <PersonName id={rev.createdBy} />\n {rev.changeNote ? ` · ${rev.changeNote}` : ''}\n </p>\n </li>\n );\n })}\n </ol>\n {shown && (\n <div\n className=\"space-y-1 rounded-md border bg-muted/40 p-3\"\n data-testid=\"doc-revision-view\"\n >\n <p className=\"text-sm font-medium\">\n Version {shown.version}: {shown.title}\n </p>\n <div className=\"prose prose-sm max-w-none dark:prose-invert\">\n <Markdown>{shown.content}</Markdown>\n </div>\n </div>\n )}\n </CardContent>\n </Card>\n\n <Card data-testid=\"doc-linked-items\">\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Link2 className=\"h-4 w-4\" /> Linked work items ({doc.linkedWorkItems.length})\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n {doc.linkedWorkItems.length === 0 && (\n <p className=\"text-sm text-muted-foreground\">\n Not linked to any work item. A doc created from a task&apos;s “Linked Docs” panel is\n linked to that task; linking an existing doc is not available yet.\n </p>\n )}\n {doc.linkedWorkItems.map((item) => (\n <div\n key={item.id}\n className=\"flex items-center justify-between gap-2 rounded-md border p-2\"\n >\n <button\n type=\"button\"\n className=\"min-w-0 truncate text-left text-sm hover:underline\"\n onClick={() =>\n navigate(`/tasks/task-detail-page?taskId=${encodeURIComponent(item.id)}`)\n }\n >\n <span className=\"text-muted-foreground\">{item.key}</span> {item.title}\n </button>\n <Button\n size=\"icon\"\n variant=\"ghost\"\n disabled={unlinkState.loading}\n aria-label={`Unlink ${item.title}`}\n onClick={() =>\n run(\n () => unlink({ variables: { docId: doc.id, workItemId: item.id } }),\n 'The work item could not be unlinked.'\n )\n }\n >\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n ))}\n </CardContent>\n </Card>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"DocsDocDetailPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/DocsDocDetailPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useSearchParams } from 'react-router';\nimport { gql } from '@apollo/client';\nimport { useApolloClient, 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 Input,\n} from '@burdenoff/fe-libs/ui';\nimport { Markdown } from '@burdenoff/fe-libs/shared/components';\nimport { clearGraphqlFetchResponseCache } from '@burdenoff/fe-libs/shared/graphql';\nimport { ArrowLeft, History, Link2, X } from 'lucide-react';\nimport { WorkItemSearchSelect } from '../controls/Pickers';\nimport { MarkdownEditor } from '#src/components/MarkdownEditor';\nimport { usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { PersonName } from '../people/People';\nimport { throwOnError } from '../utils/mutationResult';\nimport { DOC_STATUSES, DocStatusBadge, type DocStatus } from '../docs/DocStatusBadge';\n\n/**\n * One doc (P1.4): read it, edit it with a change note, publish or archive it,\n * browse its history and restore an older version, see and unlink the work\n * items it is attached to, and delete it.\n *\n * Every write carries `expectedVersion` — the version on screen — so a save\n * over someone else's newer edit is refused with the reason, and the editor\n * keeps the unsaved text rather than overwriting theirs.\n */\n\nconst DOC = gql`\n query DocDetail($id: ID!) {\n planmagnetDoc(id: $id) {\n id\n title\n content\n status\n version\n createdBy\n createdAt\n updatedBy\n updatedAt\n revisions {\n id\n version\n title\n content\n changeNote\n createdBy\n createdAt\n }\n linkedWorkItems {\n id\n key\n title\n }\n }\n }\n`;\nconst UPDATE = gql`\n mutation DocUpdate($id: ID!, $input: PlanmagnetUpdateDocInput!) {\n planmagnetUpdateDoc(id: $id, input: $input) {\n id\n version\n status\n }\n }\n`;\nconst REVERT = gql`\n mutation DocRevert($id: ID!, $toVersion: Int!, $expectedVersion: Int) {\n planmagnetRevertDoc(id: $id, toVersion: $toVersion, expectedVersion: $expectedVersion) {\n id\n version\n }\n }\n`;\nconst DELETE = gql`\n mutation DocDelete($id: ID!) {\n planmagnetDeleteDoc(id: $id)\n }\n`;\nconst LINK = gql`\n mutation DocLinkWorkItem($docId: ID!, $workItemId: ID!) {\n planmagnetLinkDocToWorkItem(docId: $docId, workItemId: $workItemId) {\n id\n }\n }\n`;\n\nconst UNLINK = gql`\n mutation DocUnlinkWorkItem($docId: ID!, $workItemId: ID!) {\n planmagnetUnlinkDocFromWorkItem(docId: $docId, workItemId: $workItemId)\n }\n`;\n\ninterface Revision {\n id: string;\n version: number;\n title: string;\n content: string;\n changeNote: string | null;\n createdBy: string;\n createdAt: string;\n}\n\ninterface Doc {\n id: string;\n title: string;\n content: string;\n status: string;\n version: number;\n createdBy: string;\n createdAt: string;\n updatedBy: string | null;\n updatedAt: string;\n revisions: Revision[];\n linkedWorkItems: { id: string; key: string; title: string }[];\n}\n\nconst messageOf = (e: unknown, fallback: string) => (e instanceof Error ? e.message : fallback);\nconst when = (iso: string) => new Date(iso).toLocaleString();\n\nexport function DocsDocDetailPagePage() {\n const [params] = useSearchParams();\n const docId = params.get('docId') ?? '';\n const navigate = usePlanMagnetNavigate();\n const [editing, setEditing] = useState(false);\n const [title, setTitle] = useState('');\n const [content, setContent] = useState('');\n const [changeNote, setChangeNote] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [viewing, setViewing] = useState<number | null>(null);\n // The version the editor started from — not the one on screen now, which a\n // refetch after someone else's save may already have moved past.\n const [editBase, setEditBase] = useState<number | null>(null);\n\n const {\n data,\n loading,\n error: loadError,\n } = useQuery<{ planmagnetDoc: Doc | null }>(DOC, {\n variables: { id: docId },\n skip: !docId,\n // Cached copies go stale here: a deleted doc, or someone else's newer version.\n fetchPolicy: 'cache-and-network',\n });\n const client = useApolloClient();\n const after = { refetchQueries: ['DocDetail'], awaitRefetchQueries: true };\n const [update, updateState] = useMutation(UPDATE, after);\n const [revert, revertState] = useMutation(REVERT, after);\n const [remove, removeState] = useMutation(DELETE, { refetchQueries: ['DocsList'] });\n const [unlink, unlinkState] = useMutation(UNLINK, after);\n const [link, linkState] = useMutation(LINK, {\n ...after,\n refetchQueries: ['DocDetail', 'GetWorkItemDocs'],\n });\n // BOFF-7961: link this doc to a work item from here too (it could only be linked when created from a task).\n const [linkChoice, setLinkChoice] = useState('');\n\n const doc = data?.planmagnetDoc;\n const busy = updateState.loading || revertState.loading || removeState.loading;\n\n // Refusals are panel-level: a refused write refetches, and anything the\n // refetch re-renders must not take the reason with it.\n const run = async (action: () => Promise<{ error?: unknown }>, fallback: string) => {\n setError(null);\n try {\n await throwOnError(action());\n return true;\n } catch (e) {\n setError(messageOf(e, fallback));\n // A refusal because the doc moved on: show the current version, but\n // leave the editor's text alone so nothing typed is lost.\n //\n // fe-libs replays any identical query answered in the last 15 s\n // (fetch.ts RECENT_QUERY_CACHE_TTL_MS) underneath Apollo's fetch\n // policies, and only a SUCCESSFUL mutation clears that cache. Measured in\n // prod 2026-09-25: after a refused save, even a network-only read was\n // served the pre-refusal response, so the page kept the old version and\n // never said the doc had moved on. A refused write is still a write\n // attempt: clear the cache (the public API fe-libs documents for this),\n // then read the doc; it lands in the normalized cache the page renders.\n clearGraphqlFetchResponseCache();\n await client\n .query({ query: DOC, variables: { id: docId }, fetchPolicy: 'network-only' })\n .catch(() => undefined);\n return false;\n }\n };\n\n if (!docId) {\n return <div className=\"p-6 text-sm text-muted-foreground\">No doc selected.</div>;\n }\n if (loading && !data) {\n return <div className=\"p-6 text-sm text-muted-foreground\">Loading doc…</div>;\n }\n if (loadError && !doc) {\n return (\n <p role=\"alert\" className=\"p-6 text-sm text-destructive\">\n The doc could not be loaded: {loadError.message}\n </p>\n );\n }\n if (!doc) {\n return (\n <div className=\"space-y-3 p-6\">\n <p className=\"text-sm text-muted-foreground\">\n This doc does not exist in this workspace, or it was deleted.\n </p>\n <Button size=\"sm\" variant=\"outline\" onClick={() => navigate('/docs/docs-page')}>\n Back to docs\n </Button>\n </div>\n );\n }\n\n const startEditing = () => {\n setTitle(doc.title);\n setContent(doc.content);\n setChangeNote('');\n setError(null);\n setEditBase(doc.version);\n setEditing(true);\n };\n const save = async () => {\n const saved = await run(\n () =>\n update({\n variables: {\n id: doc.id,\n input: {\n title: title.trim(),\n content,\n ...(changeNote.trim() ? { changeNote: changeNote.trim() } : {}),\n expectedVersion: editBase,\n },\n },\n }),\n 'The doc could not be saved.'\n );\n if (saved) setEditing(false);\n };\n\n const revisions = [...doc.revisions].sort((a, b) => b.version - a.version);\n const shown = viewing === null ? null : revisions.find((r) => r.version === viewing);\n\n return (\n <div className=\"space-y-6 p-6\" data-testid=\"doc-detail\">\n <Button size=\"sm\" variant=\"ghost\" onClick={() => navigate('/docs/docs-page')}>\n <ArrowLeft className=\"mr-1 h-4 w-4\" />\n All docs\n </Button>\n\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"min-w-0 space-y-1\">\n <h1 className=\"text-2xl font-semibold break-words\" data-testid=\"doc-title\">\n {doc.title}\n </h1>\n <p className=\"text-xs text-muted-foreground\">\n <DocStatusBadge status={doc.status} /> · version {doc.version} · updated{' '}\n {when(doc.updatedAt)} by <PersonName id={doc.updatedBy ?? doc.createdBy} />\n </p>\n </div>\n {!editing && (\n <div className=\"flex flex-wrap gap-2\">\n {DOC_STATUSES.filter((s) => s !== doc.status).map((s: DocStatus) => (\n <Button\n key={s}\n size=\"sm\"\n variant=\"outline\"\n disabled={busy}\n onClick={() =>\n run(\n () =>\n update({\n variables: {\n id: doc.id,\n input: { status: s, expectedVersion: doc.version },\n },\n }),\n 'The status could not be changed.'\n )\n }\n >\n {s === 'PUBLISHED' ? 'Publish' : s === 'ARCHIVED' ? 'Archive' : 'Back to draft'}\n </Button>\n ))}\n <Button size=\"sm\" onClick={startEditing} data-testid=\"doc-edit\">\n Edit\n </Button>\n <AlertDialog>\n <AlertDialogTrigger asChild>\n <Button size=\"sm\" variant=\"outline\" disabled={busy}>\n Delete\n </Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Delete “{doc.title}”?</AlertDialogTitle>\n <AlertDialogDescription>\n The doc and its history are removed for everyone, and it is unlinked from{' '}\n {doc.linkedWorkItems.length} work item\n {doc.linkedWorkItems.length === 1 ? '' : 's'}.\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 const deleted = await run(\n () => remove({ variables: { id: doc.id } }),\n 'The doc could not be deleted.'\n );\n if (deleted) navigate('/docs/docs-page');\n }}\n >\n Delete\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n )}\n </div>\n\n {error && (\n <p role=\"alert\" className=\"text-sm text-destructive\" data-testid=\"doc-error\">\n {error}\n </p>\n )}\n {editing && editBase !== doc.version && (\n <p className=\"text-sm text-status-warning-text\" data-testid=\"doc-moved-on\">\n Someone saved version {doc.version} after you started editing version {editBase}. Your\n text is kept below; copy what you need, then discard and edit the latest.\n </p>\n )}\n\n {editing ? (\n <Card>\n <CardContent className=\"space-y-3 pt-6\">\n <Input\n aria-label=\"Doc title\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n />\n <MarkdownEditor value={content} onChange={setContent} minHeight={240} />\n <Input\n aria-label=\"Change note\"\n placeholder=\"What changed? (optional, shown in the history)\"\n value={changeNote}\n onChange={(e) => setChangeNote(e.target.value)}\n />\n <div className=\"flex justify-end gap-2\">\n <Button\n size=\"sm\"\n variant=\"ghost\"\n onClick={() => {\n setEditing(false);\n setError(null);\n }}\n >\n {editBase !== doc.version ? 'Discard my edits' : 'Cancel'}\n </Button>\n <Button\n size=\"sm\"\n onClick={save}\n disabled={updateState.loading || editBase !== doc.version}\n data-testid=\"doc-save\"\n >\n {updateState.loading ? 'Saving…' : 'Save new version'}\n </Button>\n </div>\n </CardContent>\n </Card>\n ) : (\n <Card>\n <CardContent className=\"prose prose-sm max-w-none pt-6 dark:prose-invert\">\n {doc.content.trim() ? (\n <Markdown>{doc.content}</Markdown>\n ) : (\n <p className=\"text-sm text-muted-foreground\">This doc is empty.</p>\n )}\n </CardContent>\n </Card>\n )}\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n <Card data-testid=\"doc-history\">\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <History className=\"h-4 w-4\" /> History ({revisions.length})\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n <ol className=\"space-y-2\">\n {revisions.map((rev) => {\n const current = rev.version === doc.version;\n return (\n <li\n key={rev.id}\n className=\"space-y-1 rounded-md border p-2\"\n data-testid=\"doc-revision\"\n >\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <span className=\"text-sm font-medium\">\n Version {rev.version}\n {current ? ' (current)' : ''}\n </span>\n <span className=\"flex gap-1\">\n <Button\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-7 text-xs\"\n aria-expanded={viewing === rev.version}\n onClick={() => setViewing(viewing === rev.version ? null : rev.version)}\n >\n {viewing === rev.version ? 'Hide' : 'View'}\n </Button>\n {!current && !editing && (\n <AlertDialog>\n <AlertDialogTrigger asChild>\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7 text-xs\"\n disabled={busy}\n data-testid=\"doc-restore\"\n >\n Restore\n </Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Restore version {rev.version}?</AlertDialogTitle>\n <AlertDialogDescription>\n Its title and text become version {doc.version + 1}. Nothing is\n deleted: version {doc.version} stays in the history.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction\n onClick={() =>\n run(\n () =>\n revert({\n variables: {\n id: doc.id,\n toVersion: rev.version,\n expectedVersion: doc.version,\n },\n }),\n 'The version could not be restored.'\n )\n }\n >\n Restore\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n )}\n </span>\n </div>\n <p className=\"text-xs text-muted-foreground\">\n {when(rev.createdAt)} · <PersonName id={rev.createdBy} />\n {rev.changeNote ? ` · ${rev.changeNote}` : ''}\n </p>\n </li>\n );\n })}\n </ol>\n {shown && (\n <div\n className=\"space-y-1 rounded-md border bg-muted/40 p-3\"\n data-testid=\"doc-revision-view\"\n >\n <p className=\"text-sm font-medium\">\n Version {shown.version}: {shown.title}\n </p>\n <div className=\"prose prose-sm max-w-none dark:prose-invert\">\n <Markdown>{shown.content}</Markdown>\n </div>\n </div>\n )}\n </CardContent>\n </Card>\n\n <Card data-testid=\"doc-linked-items\">\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Link2 className=\"h-4 w-4\" /> Linked work items ({doc.linkedWorkItems.length})\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n {doc.linkedWorkItems.length === 0 && (\n <p className=\"text-sm text-muted-foreground\">\n Not linked to any work item yet. Pick one below, or use &ldquo;Link existing\n doc&rdquo; on the task.\n </p>\n )}\n {doc.linkedWorkItems.map((item) => (\n <div\n key={item.id}\n className=\"flex items-center justify-between gap-2 rounded-md border p-2\"\n >\n <button\n type=\"button\"\n className=\"min-w-0 truncate text-left text-sm hover:underline\"\n onClick={() =>\n navigate(`/tasks/task-detail-page?taskId=${encodeURIComponent(item.id)}`)\n }\n >\n <span className=\"text-muted-foreground\">{item.key}</span> {item.title}\n </button>\n <Button\n size=\"icon\"\n variant=\"ghost\"\n disabled={unlinkState.loading}\n aria-label={`Unlink ${item.title}`}\n onClick={() =>\n run(\n () => unlink({ variables: { docId: doc.id, workItemId: item.id } }),\n 'The work item could not be unlinked.'\n )\n }\n >\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n ))}\n <div className=\"space-y-2 pt-2\" data-testid=\"doc-link-work-item\">\n <WorkItemSearchSelect\n id=\"doc-link-work-item-select\"\n value={linkChoice}\n onChange={setLinkChoice}\n exclude={doc.linkedWorkItems.map((w) => w.id)}\n />\n <Button\n size=\"sm\"\n variant=\"outline\"\n disabled={!linkChoice || linkState.loading}\n onClick={async () => {\n const done = await run(\n () => link({ variables: { docId: doc.id, workItemId: linkChoice } }),\n 'The work item could not be linked.'\n );\n if (done) setLinkChoice('');\n }}\n >\n <Link2 className=\"mr-1 h-4 w-4\" />\n Link work item\n </Button>\n </div>\n </CardContent>\n </Card>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { usePlanMagnet as e, usePlanMagnetNavigate as t } from "../providers/PlanMagnetProvider.js";
2
2
  import { PersonName as n } from "../people/People.js";
3
- import { MarkdownEditor as r } from "../../components/MarkdownEditor.js";
4
- import { throwOnError as i } from "../utils/mutationResult.js";
3
+ import { throwOnError as r } from "../utils/mutationResult.js";
4
+ import { MarkdownEditor as i } from "../../components/MarkdownEditor.js";
5
5
  import { DOC_STATUSES as a, DOC_STATUS_LABEL as o, DocStatusBadge as s } from "../docs/DocStatusBadge.js";
6
6
  import { useDeferredValue as c, useState as l } from "react";
7
7
  import { FileText as u, Plus as d, Search as f } from "lucide-react";
@@ -55,7 +55,7 @@ function E() {
55
55
  }), [K, q] = m(w, { refetchQueries: ["DocsList"] }), J = H?.planmagnetDocs, Y = J?.items ?? [], X = async () => {
56
56
  R(null);
57
57
  try {
58
- let e = (await i(K({ variables: { input: {
58
+ let e = (await r(K({ variables: { input: {
59
59
  title: N.trim(),
60
60
  content: F
61
61
  } } }))).data?.planmagnetCreateDoc.id;
@@ -116,7 +116,7 @@ function E() {
116
116
  value: N,
117
117
  onChange: (e) => P(e.target.value)
118
118
  }),
119
- /* @__PURE__ */ g(r, {
119
+ /* @__PURE__ */ g(i, {
120
120
  value: F,
121
121
  onChange: I,
122
122
  placeholder: "Write the doc…",
@@ -1 +1 @@
1
- {"version":3,"file":"GoalsCreateObjectivePagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/GoalsCreateObjectivePagePage.tsx"],"names":[],"mappings":"AAiBA,wBAAgB,4BAA4B,4CA4G3C"}
1
+ {"version":3,"file":"GoalsCreateObjectivePagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/GoalsCreateObjectivePagePage.tsx"],"names":[],"mappings":"AAkBA,wBAAgB,4BAA4B,4CAkH3C"}
@@ -1,115 +1,122 @@
1
1
  import { usePlanMagnetNavigate as e } from "../providers/PlanMagnetProvider.js";
2
- import { useState as t } from "react";
3
- import { Flag as n, Save as r, X as i } from "lucide-react";
4
- import { gql as a } from "@apollo/client";
5
- import { useMutation as o } from "@apollo/client/react";
6
- import { jsx as s, jsxs as c } from "react/jsx-runtime";
7
- import { Button as l, Card as u, CardContent as d, CardHeader as f, CardTitle as p, Input as m } from "@burdenoff/fe-libs/ui";
2
+ import { throwOnError as t } from "../utils/mutationResult.js";
3
+ import { useState as n } from "react";
4
+ import { Flag as r, Save as i, X as a } from "lucide-react";
5
+ import { gql as o } from "@apollo/client";
6
+ import { useMutation as s } from "@apollo/client/react";
7
+ import { jsx as c, jsxs as l } from "react/jsx-runtime";
8
+ import { Button as u, Card as d, CardContent as f, CardHeader as p, CardTitle as m, Input as h } from "@burdenoff/fe-libs/ui";
8
9
  //#region src/planmagnet/pages/GoalsCreateObjectivePagePage.tsx
9
- var h = a`
10
+ var g = o`
10
11
  mutation CreateObjective($input: PlanmagnetCreateObjectiveInput!) {
11
12
  planmagnetCreateObjective(input: $input) {
12
13
  id
13
14
  }
14
15
  }
15
16
  `;
16
- function g() {
17
- let a = e(), [g, _] = t({
17
+ function _() {
18
+ let o = e(), [_, v] = n({
18
19
  title: "",
19
20
  description: "",
20
21
  periodLabel: "",
21
22
  endDate: ""
22
- }), [v, { loading: y, error: b }] = o(h);
23
- return /* @__PURE__ */ c("div", {
23
+ }), [y, { loading: b }] = s(g), [x, S] = n(null);
24
+ return /* @__PURE__ */ l("div", {
24
25
  className: "space-y-6 p-6 max-w-4xl",
25
26
  children: [
26
- /* @__PURE__ */ c("div", {
27
+ /* @__PURE__ */ l("div", {
27
28
  className: "flex items-center justify-between",
28
- children: [/* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s("h1", {
29
+ children: [/* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("h1", {
29
30
  className: "text-2xl font-semibold",
30
31
  children: "Create Objective"
31
- }), /* @__PURE__ */ s("p", {
32
+ }), /* @__PURE__ */ c("p", {
32
33
  className: "text-sm text-muted-foreground",
33
34
  children: "Define a workspace goal for a time period, then add key results to make progress measurable."
34
- })] }), /* @__PURE__ */ c("div", {
35
+ })] }), /* @__PURE__ */ l("div", {
35
36
  className: "flex gap-2",
36
- children: [/* @__PURE__ */ c(l, {
37
+ children: [/* @__PURE__ */ l(u, {
37
38
  variant: "outline",
38
39
  size: "sm",
39
- onClick: () => a("/goals/goals-page"),
40
- children: [/* @__PURE__ */ s(i, { className: "mr-1 h-4 w-4" }), "Cancel"]
41
- }), /* @__PURE__ */ c(l, {
40
+ onClick: () => o("/goals/goals-page"),
41
+ children: [/* @__PURE__ */ c(a, { className: "mr-1 h-4 w-4" }), "Cancel"]
42
+ }), /* @__PURE__ */ l(u, {
42
43
  size: "sm",
43
44
  onClick: async () => {
44
- if (!g.title.trim() || !g.periodLabel.trim()) return;
45
- let e = (await v({ variables: { input: {
46
- title: g.title.trim(),
47
- description: g.description.trim() || void 0,
48
- periodLabel: g.periodLabel.trim(),
49
- endDate: g.endDate || void 0
50
- } } })).data?.planmagnetCreateObjective?.id;
51
- a(e ? `/goals/objective-detail-page?objectiveId=${e}` : "/goals/goals-page");
45
+ if (!(!_.title.trim() || !_.periodLabel.trim())) {
46
+ S(null);
47
+ try {
48
+ let e = (await t(y({ variables: { input: {
49
+ title: _.title.trim(),
50
+ description: _.description.trim() || void 0,
51
+ periodLabel: _.periodLabel.trim(),
52
+ endDate: _.endDate || void 0
53
+ } } }))).data?.planmagnetCreateObjective?.id;
54
+ o(e ? `/goals/objective-detail-page?objectiveId=${e}` : "/goals/goals-page");
55
+ } catch (e) {
56
+ S(e instanceof Error ? e : /* @__PURE__ */ Error("The objective could not be created."));
57
+ }
58
+ }
52
59
  },
53
- disabled: y || !g.title.trim() || !g.periodLabel.trim(),
54
- children: [/* @__PURE__ */ s(r, { className: "mr-1 h-4 w-4" }), y ? "Creating..." : "Create Objective"]
60
+ disabled: b || !_.title.trim() || !_.periodLabel.trim(),
61
+ children: [/* @__PURE__ */ c(i, { className: "mr-1 h-4 w-4" }), b ? "Creating..." : "Create Objective"]
55
62
  })]
56
63
  })]
57
64
  }),
58
- b && /* @__PURE__ */ c("div", {
65
+ x && /* @__PURE__ */ l("div", {
59
66
  className: "p-6 text-red-500",
60
- children: ["Error: ", b.message]
67
+ children: ["Error: ", x.message]
61
68
  }),
62
- /* @__PURE__ */ c(u, { children: [/* @__PURE__ */ s(f, { children: /* @__PURE__ */ c(p, {
69
+ /* @__PURE__ */ l(d, { children: [/* @__PURE__ */ c(p, { children: /* @__PURE__ */ l(m, {
63
70
  className: "flex items-center gap-2",
64
- children: [/* @__PURE__ */ s(n, { className: "h-4 w-4" }), "Objective Details"]
65
- }) }), /* @__PURE__ */ c(d, {
71
+ children: [/* @__PURE__ */ c(r, { className: "h-4 w-4" }), "Objective Details"]
72
+ }) }), /* @__PURE__ */ l(f, {
66
73
  className: "space-y-4",
67
74
  children: [
68
- /* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s("label", {
75
+ /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
69
76
  className: "text-sm font-medium",
70
77
  children: "Title"
71
- }), /* @__PURE__ */ s(m, {
72
- value: g.title,
73
- onChange: (e) => _({
74
- ...g,
78
+ }), /* @__PURE__ */ c(h, {
79
+ value: _.title,
80
+ onChange: (e) => v({
81
+ ..._,
75
82
  title: e.target.value
76
83
  }),
77
84
  className: "mt-1",
78
85
  placeholder: "e.g. Grow enterprise revenue"
79
86
  })] }),
80
- /* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s("label", {
87
+ /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
81
88
  className: "text-sm font-medium",
82
89
  children: "Description"
83
- }), /* @__PURE__ */ s("textarea", {
90
+ }), /* @__PURE__ */ c("textarea", {
84
91
  className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[100px]",
85
- value: g.description,
86
- onChange: (e) => _({
87
- ...g,
92
+ value: _.description,
93
+ onChange: (e) => v({
94
+ ..._,
88
95
  description: e.target.value
89
96
  }),
90
97
  placeholder: "Why this objective matters this period..."
91
98
  })] }),
92
- /* @__PURE__ */ c("div", {
99
+ /* @__PURE__ */ l("div", {
93
100
  className: "grid grid-cols-2 gap-4",
94
- children: [/* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s("label", {
101
+ children: [/* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
95
102
  className: "text-sm font-medium",
96
103
  children: "Time Period"
97
- }), /* @__PURE__ */ s(m, {
98
- value: g.periodLabel,
99
- onChange: (e) => _({
100
- ...g,
104
+ }), /* @__PURE__ */ c(h, {
105
+ value: _.periodLabel,
106
+ onChange: (e) => v({
107
+ ..._,
101
108
  periodLabel: e.target.value
102
109
  }),
103
110
  className: "mt-1",
104
111
  placeholder: "e.g. Q3 2026"
105
- })] }), /* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s("label", {
112
+ })] }), /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
106
113
  className: "text-sm font-medium",
107
114
  children: "Target End Date"
108
- }), /* @__PURE__ */ s(m, {
115
+ }), /* @__PURE__ */ c(h, {
109
116
  type: "date",
110
- value: g.endDate,
111
- onChange: (e) => _({
112
- ...g,
117
+ value: _.endDate,
118
+ onChange: (e) => v({
119
+ ..._,
113
120
  endDate: e.target.value
114
121
  }),
115
122
  className: "mt-1"
@@ -121,6 +128,6 @@ function g() {
121
128
  });
122
129
  }
123
130
  //#endregion
124
- export { g as GoalsCreateObjectivePagePage };
131
+ export { _ as GoalsCreateObjectivePagePage };
125
132
 
126
133
  //# sourceMappingURL=GoalsCreateObjectivePagePage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"GoalsCreateObjectivePagePage.js","names":[],"sources":["../../../src/planmagnet/pages/GoalsCreateObjectivePagePage.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 } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Button, Input } from '@burdenoff/fe-libs/ui';\nimport { Save, X, Flag } from 'lucide-react';\nimport { usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\n\nconst CREATE_OBJECTIVE = gql`\n mutation CreateObjective($input: PlanmagnetCreateObjectiveInput!) {\n planmagnetCreateObjective(input: $input) {\n id\n }\n }\n`;\n\nexport function GoalsCreateObjectivePagePage() {\n const navigate = usePlanMagnetNavigate();\n const [form, setForm] = useState({\n title: '',\n description: '',\n periodLabel: '',\n endDate: '',\n });\n\n const [createObjective, { loading: saving, error }] = useMutation(CREATE_OBJECTIVE);\n\n const handleCreate = async () => {\n if (!form.title.trim() || !form.periodLabel.trim()) return;\n // mutation-error: shown from the hook's `error`; it only navigates when an id came back.\n const result = await createObjective({\n variables: {\n input: {\n title: form.title.trim(),\n description: form.description.trim() || undefined,\n periodLabel: form.periodLabel.trim(),\n endDate: form.endDate || undefined,\n },\n },\n });\n const newId = result.data?.planmagnetCreateObjective?.id;\n if (newId) {\n navigate(`/goals/objective-detail-page?objectiveId=${newId}`);\n } else {\n navigate('/goals/goals-page');\n }\n };\n\n return (\n <div className=\"space-y-6 p-6 max-w-4xl\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Create Objective</h1>\n <p className=\"text-sm text-muted-foreground\">\n Define a workspace goal for a time period, then add key results to make progress\n measurable.\n </p>\n </div>\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={() => navigate('/goals/goals-page')}>\n <X className=\"mr-1 h-4 w-4\" />\n Cancel\n </Button>\n <Button\n size=\"sm\"\n onClick={handleCreate}\n disabled={saving || !form.title.trim() || !form.periodLabel.trim()}\n >\n <Save className=\"mr-1 h-4 w-4\" />\n {saving ? 'Creating...' : 'Create Objective'}\n </Button>\n </div>\n </div>\n {error && <div className=\"p-6 text-red-500\">Error: {error.message}</div>}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Flag className=\"h-4 w-4\" />\n Objective Details\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label className=\"text-sm font-medium\">Title</label>\n <Input\n value={form.title}\n onChange={(e) => setForm({ ...form, title: e.target.value })}\n className=\"mt-1\"\n placeholder=\"e.g. Grow enterprise revenue\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Description</label>\n <textarea\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[100px]\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n placeholder=\"Why this objective matters this period...\"\n />\n </div>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"text-sm font-medium\">Time Period</label>\n <Input\n value={form.periodLabel}\n onChange={(e) => setForm({ ...form, periodLabel: e.target.value })}\n className=\"mt-1\"\n placeholder=\"e.g. Q3 2026\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Target End Date</label>\n <Input\n type=\"date\"\n value={form.endDate}\n onChange={(e) => setForm({ ...form, endDate: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":";;;;;;;;AASA,IAAM,IAAmB,CAAG;;;;;;;AAQ5B,SAAgB,IAA+B;CAC7C,IAAM,IAAW,GAAuB,EAClC,CAAC,GAAM,KAAW,EAAS;EAC/B,OAAO;EACP,aAAa;EACb,aAAa;EACb,SAAS;EACV,CAAC,EAEI,CAAC,GAAiB,EAAE,SAAS,GAAQ,cAAW,EAAY,EAAiB;AAuBnF,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;eAAyB;KAAqB,CAAA,EAC5D,kBAAC,KAAD;KAAG,WAAU;eAAgC;KAGzC,CAAA,CACA,EAAA,CAAA,EACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAQ,SAAQ;MAAU,MAAK;MAAK,eAAe,EAAS,oBAAoB;gBAAhF,CACE,kBAAC,GAAD,EAAG,WAAU,gBAAiB,CAAA,EAAA,SAEvB;SACT,kBAAC,GAAD;MACE,MAAK;MACL,SAtCW,YAAY;AAC/B,WAAI,CAAC,EAAK,MAAM,MAAM,IAAI,CAAC,EAAK,YAAY,MAAM,CAAE;OAYpD,IAAM,KAVS,MAAM,EAAgB,EACnC,WAAW,EACT,OAAO;QACL,OAAO,EAAK,MAAM,MAAM;QACxB,aAAa,EAAK,YAAY,MAAM,IAAI,KAAA;QACxC,aAAa,EAAK,YAAY,MAAM;QACpC,SAAS,EAAK,WAAW,KAAA;QAC1B,EACF,EACF,CAAC,EACmB,MAAM,2BAA2B;AACtD,OACE,EADE,IACO,4CAA4C,MAE5C,oBAAoB;;MAsBvB,UAAU,KAAU,CAAC,EAAK,MAAM,MAAM,IAAI,CAAC,EAAK,YAAY,MAAM;gBAHpE,CAKE,kBAAC,GAAD,EAAM,WAAU,gBAAiB,CAAA,EAChC,IAAS,gBAAgB,mBACnB;QACL;OACF;;GACL,KAAS,kBAAC,OAAD;IAAK,WAAU;cAAf,CAAkC,WAAQ,EAAM,QAAc;;GACxE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;IAAW,WAAU;cAArB,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,oBAElB;OACD,CAAA,EACb,kBAAC,GAAD;IAAa,WAAU;cAAvB;KACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;MAAO,WAAU;gBAAsB;MAAa,CAAA,EACpD,kBAAC,GAAD;MACE,OAAO,EAAK;MACZ,WAAW,MAAM,EAAQ;OAAE,GAAG;OAAM,OAAO,EAAE,OAAO;OAAO,CAAC;MAC5D,WAAU;MACV,aAAY;MACZ,CAAA,CACE,EAAA,CAAA;KACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;MAAO,WAAU;gBAAsB;MAAmB,CAAA,EAC1D,kBAAC,YAAD;MACE,WAAU;MACV,OAAO,EAAK;MACZ,WAAW,MAAM,EAAQ;OAAE,GAAG;OAAM,aAAa,EAAE,OAAO;OAAO,CAAC;MAClE,aAAY;MACZ,CAAA,CACE,EAAA,CAAA;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;OAAO,WAAU;iBAAsB;OAAmB,CAAA,EAC1D,kBAAC,GAAD;OACE,OAAO,EAAK;OACZ,WAAW,MAAM,EAAQ;QAAE,GAAG;QAAM,aAAa,EAAE,OAAO;QAAO,CAAC;OAClE,WAAU;OACV,aAAY;OACZ,CAAA,CACE,EAAA,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;OAAO,WAAU;iBAAsB;OAAuB,CAAA,EAC9D,kBAAC,GAAD;OACE,MAAK;OACL,OAAO,EAAK;OACZ,WAAW,MAAM,EAAQ;QAAE,GAAG;QAAM,SAAS,EAAE,OAAO;QAAO,CAAC;OAC9D,WAAU;OACV,CAAA,CACE,EAAA,CAAA,CACF;;KACM;MACT,EAAA,CAAA;GACH"}
1
+ {"version":3,"file":"GoalsCreateObjectivePagePage.js","names":[],"sources":["../../../src/planmagnet/pages/GoalsCreateObjectivePagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { throwOnError } from '../utils/mutationResult';\nimport { useMutation } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Button, Input } from '@burdenoff/fe-libs/ui';\nimport { Save, X, Flag } from 'lucide-react';\nimport { usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\n\nconst CREATE_OBJECTIVE = gql`\n mutation CreateObjective($input: PlanmagnetCreateObjectiveInput!) {\n planmagnetCreateObjective(input: $input) {\n id\n }\n }\n`;\n\nexport function GoalsCreateObjectivePagePage() {\n const navigate = usePlanMagnetNavigate();\n const [form, setForm] = useState({\n title: '',\n description: '',\n periodLabel: '',\n endDate: '',\n });\n\n const [createObjective, { loading: saving }] = useMutation(CREATE_OBJECTIVE);\n const [error, setError] = useState<Error | null>(null);\n\n // BOFF-7955: a refused create RESOLVES with { error } (errorPolicy 'all'); the old else-branch then navigated to\n // the list and unmounted the banner, so the refusal was never seen. Stay on the form and show it.\n const handleCreate = async () => {\n if (!form.title.trim() || !form.periodLabel.trim()) return;\n setError(null);\n try {\n const result = await throwOnError(\n createObjective({\n variables: {\n input: {\n title: form.title.trim(),\n description: form.description.trim() || undefined,\n periodLabel: form.periodLabel.trim(),\n endDate: form.endDate || undefined,\n },\n },\n })\n );\n const newId = (result.data as { planmagnetCreateObjective?: { id: string } } | undefined)\n ?.planmagnetCreateObjective?.id;\n navigate(newId ? `/goals/objective-detail-page?objectiveId=${newId}` : '/goals/goals-page');\n } catch (e) {\n setError(e instanceof Error ? e : new Error('The objective could not be created.'));\n }\n };\n\n return (\n <div className=\"space-y-6 p-6 max-w-4xl\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Create Objective</h1>\n <p className=\"text-sm text-muted-foreground\">\n Define a workspace goal for a time period, then add key results to make progress\n measurable.\n </p>\n </div>\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={() => navigate('/goals/goals-page')}>\n <X className=\"mr-1 h-4 w-4\" />\n Cancel\n </Button>\n <Button\n size=\"sm\"\n onClick={handleCreate}\n disabled={saving || !form.title.trim() || !form.periodLabel.trim()}\n >\n <Save className=\"mr-1 h-4 w-4\" />\n {saving ? 'Creating...' : 'Create Objective'}\n </Button>\n </div>\n </div>\n {error && <div className=\"p-6 text-red-500\">Error: {error.message}</div>}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Flag className=\"h-4 w-4\" />\n Objective Details\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label className=\"text-sm font-medium\">Title</label>\n <Input\n value={form.title}\n onChange={(e) => setForm({ ...form, title: e.target.value })}\n className=\"mt-1\"\n placeholder=\"e.g. Grow enterprise revenue\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Description</label>\n <textarea\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[100px]\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n placeholder=\"Why this objective matters this period...\"\n />\n </div>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"text-sm font-medium\">Time Period</label>\n <Input\n value={form.periodLabel}\n onChange={(e) => setForm({ ...form, periodLabel: e.target.value })}\n className=\"mt-1\"\n placeholder=\"e.g. Q3 2026\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Target End Date</label>\n <Input\n type=\"date\"\n value={form.endDate}\n onChange={(e) => setForm({ ...form, endDate: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"GoalsObjectiveDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/GoalsObjectiveDetailPagePage.tsx"],"names":[],"mappings":"AAqPA,wBAAgB,4BAA4B,4CAyQ3C"}
1
+ {"version":3,"file":"GoalsObjectiveDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/GoalsObjectiveDetailPagePage.tsx"],"names":[],"mappings":"AAiQA,wBAAgB,4BAA4B,4CAwQ3C"}