@burdenoff/microfe-planmagnet 2026.1002.2 → 2026.1008.1

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 (165) hide show
  1. package/dist/generated/wspace-operations.d.ts +574 -0
  2. package/dist/generated/wspace-operations.d.ts.map +1 -1
  3. package/dist/generated/wspace-types.d.ts +486 -16
  4. package/dist/generated/wspace-types.d.ts.map +1 -1
  5. package/dist/index.js +8 -8
  6. package/dist/planmagnet/PlanMagnetRoot.d.ts.map +1 -1
  7. package/dist/planmagnet/PlanMagnetRoot.js +174 -168
  8. package/dist/planmagnet/PlanMagnetRoot.js.map +1 -1
  9. package/dist/planmagnet/PlanMagnetRoutes.d.ts.map +1 -1
  10. package/dist/planmagnet/PlanMagnetRoutes.js +63 -59
  11. package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
  12. package/dist/planmagnet/board/BulkActions.d.ts.map +1 -1
  13. package/dist/planmagnet/board/BulkActions.js +106 -55
  14. package/dist/planmagnet/board/BulkActions.js.map +1 -1
  15. package/dist/planmagnet/controls/Pickers.d.ts +3 -3
  16. package/dist/planmagnet/controls/Pickers.js.map +1 -1
  17. package/dist/planmagnet/dashboards/DashboardUI.d.ts +0 -4
  18. package/dist/planmagnet/dashboards/DashboardUI.d.ts.map +1 -1
  19. package/dist/planmagnet/dashboards/DashboardUI.js +6 -13
  20. package/dist/planmagnet/dashboards/DashboardUI.js.map +1 -1
  21. package/dist/planmagnet/dashboards/cards/SprintCapacityCard.d.ts.map +1 -1
  22. package/dist/planmagnet/dashboards/cards/SprintCapacityCard.js +70 -59
  23. package/dist/planmagnet/dashboards/cards/SprintCapacityCard.js.map +1 -1
  24. package/dist/planmagnet/forecast/ResourceForecastCard.js +1 -1
  25. package/dist/planmagnet/forecast/ResourceForecastCard.js.map +1 -1
  26. package/dist/planmagnet/index.d.ts +1 -1
  27. package/dist/planmagnet/index.d.ts.map +1 -1
  28. package/dist/planmagnet/pages/DashboardsProjectManagerPagePage.d.ts +3 -3
  29. package/dist/planmagnet/pages/DashboardsProjectManagerPagePage.d.ts.map +1 -1
  30. package/dist/planmagnet/pages/DashboardsProjectManagerPagePage.js +26 -19
  31. package/dist/planmagnet/pages/DashboardsProjectManagerPagePage.js.map +1 -1
  32. package/dist/planmagnet/pages/DashboardsTeamUtilizationPagePage.d.ts +2 -2
  33. package/dist/planmagnet/pages/DashboardsTeamUtilizationPagePage.d.ts.map +1 -1
  34. package/dist/planmagnet/pages/DashboardsTeamUtilizationPagePage.js +18 -12
  35. package/dist/planmagnet/pages/DashboardsTeamUtilizationPagePage.js.map +1 -1
  36. package/dist/planmagnet/pages/ProductsCustomerSatisfactionPagePage.d.ts +2 -0
  37. package/dist/planmagnet/pages/ProductsCustomerSatisfactionPagePage.d.ts.map +1 -0
  38. package/dist/planmagnet/pages/ProductsCustomerSatisfactionPagePage.js +251 -0
  39. package/dist/planmagnet/pages/ProductsCustomerSatisfactionPagePage.js.map +1 -0
  40. package/dist/planmagnet/pages/ProductsProductDetailPagePage.d.ts.map +1 -1
  41. package/dist/planmagnet/pages/ProductsProductDetailPagePage.js +94 -92
  42. package/dist/planmagnet/pages/ProductsProductDetailPagePage.js.map +1 -1
  43. package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.d.ts.map +1 -1
  44. package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.js +116 -114
  45. package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.js.map +1 -1
  46. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.d.ts.map +1 -1
  47. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js +174 -159
  48. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js.map +1 -1
  49. package/dist/planmagnet/pages/TasksCreateTaskPagePage.d.ts.map +1 -1
  50. package/dist/planmagnet/pages/TasksCreateTaskPagePage.js +159 -145
  51. package/dist/planmagnet/pages/TasksCreateTaskPagePage.js.map +1 -1
  52. package/dist/planmagnet/pages/TasksEditTaskPagePage.d.ts.map +1 -1
  53. package/dist/planmagnet/pages/TasksEditTaskPagePage.js +161 -143
  54. package/dist/planmagnet/pages/TasksEditTaskPagePage.js.map +1 -1
  55. package/dist/planmagnet/pages/TasksTaskDetailPagePage.d.ts.map +1 -1
  56. package/dist/planmagnet/pages/TasksTaskDetailPagePage.js +157 -155
  57. package/dist/planmagnet/pages/TasksTaskDetailPagePage.js.map +1 -1
  58. package/dist/planmagnet/pages/TeamInviteMemberPagePage.d.ts.map +1 -1
  59. package/dist/planmagnet/pages/TeamInviteMemberPagePage.js +142 -82
  60. package/dist/planmagnet/pages/TeamInviteMemberPagePage.js.map +1 -1
  61. package/dist/planmagnet/pages/analytics/DeliveryKpisCard.d.ts.map +1 -1
  62. package/dist/planmagnet/pages/analytics/DeliveryKpisCard.js +97 -99
  63. package/dist/planmagnet/pages/analytics/DeliveryKpisCard.js.map +1 -1
  64. package/dist/planmagnet/product/FeatureLinkPanels.js +66 -66
  65. package/dist/planmagnet/product/ProductFeatureControls.js +38 -38
  66. package/dist/planmagnet/product/ProductFeatureLinkCard.js +8 -8
  67. package/dist/planmagnet/product/ProductLineControls.js +83 -83
  68. package/dist/planmagnet/product/ProductTeamsPanel.js +6 -6
  69. package/dist/planmagnet/product/routes.d.ts +6 -0
  70. package/dist/planmagnet/product/routes.d.ts.map +1 -1
  71. package/dist/planmagnet/product/routes.js +2 -2
  72. package/dist/planmagnet/product/routes.js.map +1 -1
  73. package/dist/planmagnet/satisfaction/DeliverySatisfactionSection.d.ts +20 -0
  74. package/dist/planmagnet/satisfaction/DeliverySatisfactionSection.d.ts.map +1 -0
  75. package/dist/planmagnet/satisfaction/DeliverySatisfactionSection.js +55 -0
  76. package/dist/planmagnet/satisfaction/DeliverySatisfactionSection.js.map +1 -0
  77. package/dist/planmagnet/satisfaction/SatisfactionFigures.d.ts +30 -0
  78. package/dist/planmagnet/satisfaction/SatisfactionFigures.d.ts.map +1 -0
  79. package/dist/planmagnet/satisfaction/SatisfactionFigures.js +282 -0
  80. package/dist/planmagnet/satisfaction/SatisfactionFigures.js.map +1 -0
  81. package/dist/planmagnet/satisfaction/SatisfactionImportDialog.d.ts +9 -0
  82. package/dist/planmagnet/satisfaction/SatisfactionImportDialog.d.ts.map +1 -0
  83. package/dist/planmagnet/satisfaction/SatisfactionImportDialog.js +390 -0
  84. package/dist/planmagnet/satisfaction/SatisfactionImportDialog.js.map +1 -0
  85. package/dist/planmagnet/satisfaction/SatisfactionLinkFields.d.ts +17 -0
  86. package/dist/planmagnet/satisfaction/SatisfactionLinkFields.d.ts.map +1 -0
  87. package/dist/planmagnet/satisfaction/SatisfactionLinkFields.js +77 -0
  88. package/dist/planmagnet/satisfaction/SatisfactionLinkFields.js.map +1 -0
  89. package/dist/planmagnet/satisfaction/SatisfactionReleaseSelect.d.ts +18 -0
  90. package/dist/planmagnet/satisfaction/SatisfactionReleaseSelect.d.ts.map +1 -0
  91. package/dist/planmagnet/satisfaction/SatisfactionReleaseSelect.js +87 -0
  92. package/dist/planmagnet/satisfaction/SatisfactionReleaseSelect.js.map +1 -0
  93. package/dist/planmagnet/satisfaction/SatisfactionResponseDialog.d.ts +13 -0
  94. package/dist/planmagnet/satisfaction/SatisfactionResponseDialog.d.ts.map +1 -0
  95. package/dist/planmagnet/satisfaction/SatisfactionResponseDialog.js +326 -0
  96. package/dist/planmagnet/satisfaction/SatisfactionResponseDialog.js.map +1 -0
  97. package/dist/planmagnet/satisfaction/SatisfactionResponsesTable.d.ts +23 -0
  98. package/dist/planmagnet/satisfaction/SatisfactionResponsesTable.d.ts.map +1 -0
  99. package/dist/planmagnet/satisfaction/SatisfactionResponsesTable.js +258 -0
  100. package/dist/planmagnet/satisfaction/SatisfactionResponsesTable.js.map +1 -0
  101. package/dist/planmagnet/satisfaction/SatisfactionSummaryCard.d.ts +6 -0
  102. package/dist/planmagnet/satisfaction/SatisfactionSummaryCard.d.ts.map +1 -0
  103. package/dist/planmagnet/satisfaction/SatisfactionSummaryCard.js +56 -0
  104. package/dist/planmagnet/satisfaction/SatisfactionSummaryCard.js.map +1 -0
  105. package/dist/planmagnet/satisfaction/SatisfactionWindowPicker.d.ts +16 -0
  106. package/dist/planmagnet/satisfaction/SatisfactionWindowPicker.d.ts.map +1 -0
  107. package/dist/planmagnet/satisfaction/SatisfactionWindowPicker.js +102 -0
  108. package/dist/planmagnet/satisfaction/SatisfactionWindowPicker.js.map +1 -0
  109. package/dist/planmagnet/satisfaction/satisfaction.d.ts +154 -0
  110. package/dist/planmagnet/satisfaction/satisfaction.d.ts.map +1 -0
  111. package/dist/planmagnet/satisfaction/satisfaction.js +210 -0
  112. package/dist/planmagnet/satisfaction/satisfaction.js.map +1 -0
  113. package/dist/planmagnet/satisfaction/satisfactionCsv.d.ts +108 -0
  114. package/dist/planmagnet/satisfaction/satisfactionCsv.d.ts.map +1 -0
  115. package/dist/planmagnet/satisfaction/satisfactionCsv.js +211 -0
  116. package/dist/planmagnet/satisfaction/satisfactionCsv.js.map +1 -0
  117. package/dist/planmagnet/satisfaction/satisfactionForm.d.ts +90 -0
  118. package/dist/planmagnet/satisfaction/satisfactionForm.d.ts.map +1 -0
  119. package/dist/planmagnet/satisfaction/satisfactionForm.js +90 -0
  120. package/dist/planmagnet/satisfaction/satisfactionForm.js.map +1 -0
  121. package/dist/planmagnet/satisfaction/satisfactionOperations.d.ts +116 -0
  122. package/dist/planmagnet/satisfaction/satisfactionOperations.d.ts.map +1 -0
  123. package/dist/planmagnet/satisfaction/satisfactionOperations.js +86 -0
  124. package/dist/planmagnet/satisfaction/satisfactionOperations.js.map +1 -0
  125. package/dist/planmagnet/satisfaction/useSatisfactionAccess.d.ts +20 -0
  126. package/dist/planmagnet/satisfaction/useSatisfactionAccess.d.ts.map +1 -0
  127. package/dist/planmagnet/satisfaction/useSatisfactionAccess.js +31 -0
  128. package/dist/planmagnet/satisfaction/useSatisfactionAccess.js.map +1 -0
  129. package/dist/planmagnet/skills/RequiredSkillsEditor.d.ts +35 -0
  130. package/dist/planmagnet/skills/RequiredSkillsEditor.d.ts.map +1 -0
  131. package/dist/planmagnet/skills/RequiredSkillsEditor.js +124 -0
  132. package/dist/planmagnet/skills/RequiredSkillsEditor.js.map +1 -0
  133. package/dist/planmagnet/skills/SkillChips.d.ts +30 -0
  134. package/dist/planmagnet/skills/SkillChips.d.ts.map +1 -0
  135. package/dist/planmagnet/skills/SkillChips.js +57 -0
  136. package/dist/planmagnet/skills/SkillChips.js.map +1 -0
  137. package/dist/planmagnet/skills/SkillCoverageCard.d.ts +24 -0
  138. package/dist/planmagnet/skills/SkillCoverageCard.d.ts.map +1 -0
  139. package/dist/planmagnet/skills/SkillCoverageCard.js +256 -0
  140. package/dist/planmagnet/skills/SkillCoverageCard.js.map +1 -0
  141. package/dist/planmagnet/skills/WorkItemRequiredSkills.d.ts +10 -0
  142. package/dist/planmagnet/skills/WorkItemRequiredSkills.d.ts.map +1 -0
  143. package/dist/planmagnet/skills/WorkItemRequiredSkills.js +65 -0
  144. package/dist/planmagnet/skills/WorkItemRequiredSkills.js.map +1 -0
  145. package/dist/planmagnet/skills/skillOperations.d.ts +52 -0
  146. package/dist/planmagnet/skills/skillOperations.d.ts.map +1 -0
  147. package/dist/planmagnet/skills/skillOperations.js +44 -0
  148. package/dist/planmagnet/skills/skillOperations.js.map +1 -0
  149. package/dist/planmagnet/skills/skillTags.d.ts +103 -0
  150. package/dist/planmagnet/skills/skillTags.d.ts.map +1 -0
  151. package/dist/planmagnet/skills/skillTags.js +115 -0
  152. package/dist/planmagnet/skills/skillTags.js.map +1 -0
  153. package/dist/planmagnet/skills/useRequiredSkillsDraft.d.ts +28 -0
  154. package/dist/planmagnet/skills/useRequiredSkillsDraft.d.ts.map +1 -0
  155. package/dist/planmagnet/skills/useRequiredSkillsDraft.js +30 -0
  156. package/dist/planmagnet/skills/useRequiredSkillsDraft.js.map +1 -0
  157. package/dist/planmagnet/team/PendingInvitations.d.ts +27 -0
  158. package/dist/planmagnet/team/PendingInvitations.d.ts.map +1 -0
  159. package/dist/planmagnet/team/PendingInvitations.js +220 -0
  160. package/dist/planmagnet/team/PendingInvitations.js.map +1 -0
  161. package/dist/planmagnet/team/invitationEmail.d.ts +35 -0
  162. package/dist/planmagnet/team/invitationEmail.d.ts.map +1 -0
  163. package/dist/planmagnet/team/invitationEmail.js +73 -0
  164. package/dist/planmagnet/team/invitationEmail.js.map +1 -0
  165. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ProductsProductDetailPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProductsProductDetailPagePage.tsx"],"sourcesContent":["import { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Badge, Button } from '@burdenoff/fe-libs/ui';\nimport { Package, Target, Users, Calendar, Loader2, Pencil, ListTree } from 'lucide-react';\nimport { usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { useEntityId } from '../hooks/useEntityId';\nimport { detailPath } from '../utils/rowNavigation';\nimport { PersonName } from '../people/People';\nimport { enumLabel } from '../controls/WorkItemControls';\nimport { PlanMagnetNotFoundPage } from './NotFoundPage';\nimport {\n ProductHeaderActions,\n ProductRoadmapsPanel,\n ProductReleasesPanel,\n ProductFeatureRequestsPanel,\n ProductObjectivesPanel,\n ProductAboutPanel,\n ProductCompetitorsPanel,\n type ProductRoadmapRef,\n type ProductReleaseRef,\n type ProductFeatureRequestRef,\n type ProductObjectiveRef,\n type ProductCompetitorRef,\n} from '../product/ProductControls';\nimport { ProductLinePicker } from '../product/ProductLineControls';\nimport { ProductTeamsPanel } from '../product/ProductTeamsPanel';\nimport { ProductFeaturesPanel } from '../product/ProductFeatureControls';\n\n/**\n * Product detail (BOFF-8045): the product's own fields, its North Star, and a Links\n * management panel for roadmaps/releases/feature requests/OKR objectives. Every relation\n * is selected directly off `planmagnetProduct(id)` rather than a separate workspace-wide\n * query — before this rewrite the page queried EVERY feature request/release in the\n * workspace regardless of product, which is the pre-existing bug this fixes (there was no\n * productId to filter on until now).\n *\n * PRM-01 adds the product's place in the hierarchy: its product line, the teams that own it\n * (a link that grants no access), and its features — capabilities the team builds, distinct\n * from the feature requests below. Each of those sections runs its own query, so a field the\n * gateway does not serve yet fails that card, never this page's GetProductDetail.\n */\n\nconst GET_PRODUCT_DETAIL = gql`\n query GetProductDetail($id: ID!) {\n planmagnetProduct(id: $id) {\n id\n workspaceId\n name\n description\n vision\n lifecycleStage\n ownerId\n archivedAt\n mission\n valueProposition\n businessModel\n targetSegments\n competitors {\n id\n name\n description\n website\n }\n northStar {\n name\n unit\n target\n current\n window\n measuredAt\n progressRatio\n }\n roadmaps {\n id\n name\n }\n releases {\n id\n name\n version\n status\n }\n featureRequests {\n id\n title\n status\n }\n objectives {\n id\n title\n status\n }\n createdAt\n updatedAt\n }\n }\n`;\n\ninterface ProductDetail {\n id: string;\n workspaceId: string;\n name: string;\n description: string | null;\n vision: string;\n lifecycleStage: string;\n ownerId: string;\n archivedAt: string | null;\n mission: string | null;\n valueProposition: string | null;\n businessModel: string | null;\n targetSegments: string[];\n competitors: ProductCompetitorRef[];\n northStar: {\n name: string;\n unit: string;\n target: number;\n current: number;\n window: string;\n measuredAt: string | null;\n progressRatio: number | null;\n } | null;\n roadmaps: ProductRoadmapRef[];\n releases: ProductReleaseRef[];\n featureRequests: ProductFeatureRequestRef[];\n objectives: ProductObjectiveRef[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport function ProductsProductDetailPagePage() {\n const navigate = usePlanMagnetNavigate();\n const productId = useEntityId('productId') ?? '';\n\n const { data, loading, error } = useQuery<{ planmagnetProduct: ProductDetail | null }>(\n GET_PRODUCT_DETAIL,\n { variables: { id: productId }, skip: !productId }\n );\n\n if (!productId) {\n return (\n <div className=\"p-6 text-muted-foreground\">No product selected. Open one from the list.</div>\n );\n }\n\n // Only before the first load: a refetch must not blank the page (it\n // unmounts every component on it and loses their state).\n if (loading && !data) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-muted-foreground\" />\n </div>\n );\n }\n\n if (error) {\n return <div className=\"p-6 text-destructive\">Failed to load product: {error.message}</div>;\n }\n\n const product = data?.planmagnetProduct;\n // Deleted, unauthorized or an unknown id all read back the same way (no cross-tenant\n // existence leak) — the real 404 page, not an inline message.\n if (!product) return <PlanMagnetNotFoundPage />;\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-start justify-between gap-4\">\n <div>\n <div className=\"flex items-center gap-2\">\n <Package className=\"h-5 w-5 text-primary\" />\n <h1 className=\"text-2xl font-semibold\">{product.name}</h1>\n {product.archivedAt && <Badge variant=\"outline\">Archived</Badge>}\n <Badge variant=\"secondary\" className=\"capitalize\">\n {enumLabel(product.lifecycleStage)}\n </Badge>\n </div>\n <p className=\"text-sm text-muted-foreground mt-1\">{product.vision || 'No vision set'}</p>\n </div>\n <div className=\"flex flex-col items-end gap-2\">\n <div className=\"flex gap-2\">\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => navigate(detailPath('/products/edit-product-page', product.id))}\n >\n <Pencil className=\"mr-1 h-4 w-4\" />\n Edit\n </Button>\n <ProductHeaderActions\n productId={product.id}\n name={product.name}\n archivedAt={product.archivedAt}\n />\n </div>\n </div>\n </div>\n\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <Target className=\"h-4 w-4\" />\n North Star\n </div>\n {product.northStar ? (\n <p className=\"text-sm font-bold mt-1 truncate\">\n {product.northStar.current} / {product.northStar.target} {product.northStar.unit}\n {product.northStar.progressRatio != null\n ? ` (${Math.round(product.northStar.progressRatio * 100)}%)`\n : ''}\n </p>\n ) : (\n <p className=\"text-sm font-medium mt-1 text-muted-foreground\">Not set</p>\n )}\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <Users className=\"h-4 w-4\" />\n Owner\n </div>\n <p className=\"text-sm font-bold mt-1 truncate\">\n <PersonName id={product.ownerId} />\n </p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <Calendar className=\"h-4 w-4\" />\n Created\n </div>\n <p className=\"text-xl font-bold mt-1\">\n {new Date(product.createdAt).toLocaleDateString()}\n </p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <Calendar className=\"h-4 w-4\" />\n Updated\n </div>\n <p className=\"text-xl font-bold mt-1\">\n {new Date(product.updatedAt).toLocaleDateString()}\n </p>\n </CardContent>\n </Card>\n </div>\n\n {product.description && (\n <Card>\n <CardContent className=\"pt-4 text-sm text-muted-foreground\">\n {product.description}\n </CardContent>\n </Card>\n )}\n\n {/* PRM-01: Product line > Product > Feature > Epic > Story. */}\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n <Card>\n <CardHeader>\n <CardTitle>Product line</CardTitle>\n </CardHeader>\n <CardContent>\n <ProductLinePicker productId={product.id} />\n </CardContent>\n </Card>\n <Card className=\"lg:col-span-2\">\n <CardHeader>\n <CardTitle>Teams</CardTitle>\n </CardHeader>\n <CardContent>\n <ProductTeamsPanel productId={product.id} />\n </CardContent>\n </Card>\n </div>\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between gap-2\">\n <CardTitle>Features</CardTitle>\n <Button\n size=\"sm\"\n variant=\"ghost\"\n onClick={() => navigate('/products/product-hierarchy-page')}\n data-testid=\"product-view-hierarchy\"\n >\n <ListTree className=\"mr-1 h-4 w-4\" />\n View hierarchy\n </Button>\n </CardHeader>\n <CardContent>\n <ProductFeaturesPanel productId={product.id} productArchived={!!product.archivedAt} />\n </CardContent>\n </Card>\n\n {/* PRM-02: strategy narrative + competitive landscape. */}\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\n <ProductAboutPanel product={product} />\n <Card>\n <CardHeader>\n <CardTitle>Competitive landscape</CardTitle>\n </CardHeader>\n <CardContent>\n <ProductCompetitorsPanel productId={product.id} competitors={product.competitors} />\n </CardContent>\n </Card>\n </div>\n\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\n <Card>\n <CardHeader>\n <CardTitle>Roadmaps</CardTitle>\n </CardHeader>\n <CardContent>\n <ProductRoadmapsPanel productId={product.id} roadmaps={product.roadmaps} />\n </CardContent>\n </Card>\n <Card>\n <CardHeader>\n <CardTitle>Releases</CardTitle>\n </CardHeader>\n <CardContent>\n <ProductReleasesPanel productId={product.id} releases={product.releases} />\n </CardContent>\n </Card>\n <Card>\n <CardHeader>\n <CardTitle>Feature requests</CardTitle>\n </CardHeader>\n <CardContent>\n <ProductFeatureRequestsPanel\n productId={product.id}\n featureRequests={product.featureRequests}\n />\n </CardContent>\n </Card>\n <Card>\n <CardHeader>\n <CardTitle>OKR Objectives</CardTitle>\n </CardHeader>\n <CardContent>\n <ProductObjectivesPanel productId={product.id} objectives={product.objectives} />\n </CardContent>\n </Card>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ProductsProductDetailPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProductsProductDetailPagePage.tsx"],"sourcesContent":["import { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Badge, Button } from '@burdenoff/fe-libs/ui';\nimport { Package, Target, Users, Calendar, Loader2, Pencil, ListTree } from 'lucide-react';\nimport { usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { useEntityId } from '../hooks/useEntityId';\nimport { detailPath } from '../utils/rowNavigation';\nimport { PersonName } from '../people/People';\nimport { enumLabel } from '../controls/WorkItemControls';\nimport { PlanMagnetNotFoundPage } from './NotFoundPage';\nimport {\n ProductHeaderActions,\n ProductRoadmapsPanel,\n ProductReleasesPanel,\n ProductFeatureRequestsPanel,\n ProductObjectivesPanel,\n ProductAboutPanel,\n ProductCompetitorsPanel,\n type ProductRoadmapRef,\n type ProductReleaseRef,\n type ProductFeatureRequestRef,\n type ProductObjectiveRef,\n type ProductCompetitorRef,\n} from '../product/ProductControls';\nimport { ProductLinePicker } from '../product/ProductLineControls';\nimport { ProductTeamsPanel } from '../product/ProductTeamsPanel';\nimport { ProductFeaturesPanel } from '../product/ProductFeatureControls';\nimport { SatisfactionSummaryCard } from '../satisfaction/SatisfactionSummaryCard';\n\n/**\n * Product detail (BOFF-8045): the product's own fields, its North Star, and a Links\n * management panel for roadmaps/releases/feature requests/OKR objectives. Every relation\n * is selected directly off `planmagnetProduct(id)` rather than a separate workspace-wide\n * query — before this rewrite the page queried EVERY feature request/release in the\n * workspace regardless of product, which is the pre-existing bug this fixes (there was no\n * productId to filter on until now).\n *\n * PRM-01 adds the product's place in the hierarchy: its product line, the teams that own it\n * (a link that grants no access), and its features — capabilities the team builds, distinct\n * from the feature requests below. Each of those sections runs its own query, so a field the\n * gateway does not serve yet fails that card, never this page's GetProductDetail.\n */\n\nconst GET_PRODUCT_DETAIL = gql`\n query GetProductDetail($id: ID!) {\n planmagnetProduct(id: $id) {\n id\n workspaceId\n name\n description\n vision\n lifecycleStage\n ownerId\n archivedAt\n mission\n valueProposition\n businessModel\n targetSegments\n competitors {\n id\n name\n description\n website\n }\n northStar {\n name\n unit\n target\n current\n window\n measuredAt\n progressRatio\n }\n roadmaps {\n id\n name\n }\n releases {\n id\n name\n version\n status\n }\n featureRequests {\n id\n title\n status\n }\n objectives {\n id\n title\n status\n }\n createdAt\n updatedAt\n }\n }\n`;\n\ninterface ProductDetail {\n id: string;\n workspaceId: string;\n name: string;\n description: string | null;\n vision: string;\n lifecycleStage: string;\n ownerId: string;\n archivedAt: string | null;\n mission: string | null;\n valueProposition: string | null;\n businessModel: string | null;\n targetSegments: string[];\n competitors: ProductCompetitorRef[];\n northStar: {\n name: string;\n unit: string;\n target: number;\n current: number;\n window: string;\n measuredAt: string | null;\n progressRatio: number | null;\n } | null;\n roadmaps: ProductRoadmapRef[];\n releases: ProductReleaseRef[];\n featureRequests: ProductFeatureRequestRef[];\n objectives: ProductObjectiveRef[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport function ProductsProductDetailPagePage() {\n const navigate = usePlanMagnetNavigate();\n const productId = useEntityId('productId') ?? '';\n\n const { data, loading, error } = useQuery<{ planmagnetProduct: ProductDetail | null }>(\n GET_PRODUCT_DETAIL,\n { variables: { id: productId }, skip: !productId }\n );\n\n if (!productId) {\n return (\n <div className=\"p-6 text-muted-foreground\">No product selected. Open one from the list.</div>\n );\n }\n\n // Only before the first load: a refetch must not blank the page (it\n // unmounts every component on it and loses their state).\n if (loading && !data) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-muted-foreground\" />\n </div>\n );\n }\n\n if (error) {\n return <div className=\"p-6 text-destructive\">Failed to load product: {error.message}</div>;\n }\n\n const product = data?.planmagnetProduct;\n // Deleted, unauthorized or an unknown id all read back the same way (no cross-tenant\n // existence leak) — the real 404 page, not an inline message.\n if (!product) return <PlanMagnetNotFoundPage />;\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-start justify-between gap-4\">\n <div>\n <div className=\"flex items-center gap-2\">\n <Package className=\"h-5 w-5 text-primary\" />\n <h1 className=\"text-2xl font-semibold\">{product.name}</h1>\n {product.archivedAt && <Badge variant=\"outline\">Archived</Badge>}\n <Badge variant=\"secondary\" className=\"capitalize\">\n {enumLabel(product.lifecycleStage)}\n </Badge>\n </div>\n <p className=\"text-sm text-muted-foreground mt-1\">{product.vision || 'No vision set'}</p>\n </div>\n <div className=\"flex flex-col items-end gap-2\">\n <div className=\"flex gap-2\">\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => navigate(detailPath('/products/edit-product-page', product.id))}\n >\n <Pencil className=\"mr-1 h-4 w-4\" />\n Edit\n </Button>\n <ProductHeaderActions\n productId={product.id}\n name={product.name}\n archivedAt={product.archivedAt}\n />\n </div>\n </div>\n </div>\n\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <Target className=\"h-4 w-4\" />\n North Star\n </div>\n {product.northStar ? (\n <p className=\"text-sm font-bold mt-1 truncate\">\n {product.northStar.current} / {product.northStar.target} {product.northStar.unit}\n {product.northStar.progressRatio != null\n ? ` (${Math.round(product.northStar.progressRatio * 100)}%)`\n : ''}\n </p>\n ) : (\n <p className=\"text-sm font-medium mt-1 text-muted-foreground\">Not set</p>\n )}\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <Users className=\"h-4 w-4\" />\n Owner\n </div>\n <p className=\"text-sm font-bold mt-1 truncate\">\n <PersonName id={product.ownerId} />\n </p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <Calendar className=\"h-4 w-4\" />\n Created\n </div>\n <p className=\"text-xl font-bold mt-1\">\n {new Date(product.createdAt).toLocaleDateString()}\n </p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <Calendar className=\"h-4 w-4\" />\n Updated\n </div>\n <p className=\"text-xl font-bold mt-1\">\n {new Date(product.updatedAt).toLocaleDateString()}\n </p>\n </CardContent>\n </Card>\n </div>\n\n {product.description && (\n <Card>\n <CardContent className=\"pt-4 text-sm text-muted-foreground\">\n {product.description}\n </CardContent>\n </Card>\n )}\n\n {/* PRM-01: Product line > Product > Feature > Epic > Story. */}\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n <Card>\n <CardHeader>\n <CardTitle>Product line</CardTitle>\n </CardHeader>\n <CardContent>\n <ProductLinePicker productId={product.id} />\n </CardContent>\n </Card>\n <Card className=\"lg:col-span-2\">\n <CardHeader>\n <CardTitle>Teams</CardTitle>\n </CardHeader>\n <CardContent>\n <ProductTeamsPanel productId={product.id} />\n </CardContent>\n </Card>\n </div>\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between gap-2\">\n <CardTitle>Features</CardTitle>\n <Button\n size=\"sm\"\n variant=\"ghost\"\n onClick={() => navigate('/products/product-hierarchy-page')}\n data-testid=\"product-view-hierarchy\"\n >\n <ListTree className=\"mr-1 h-4 w-4\" />\n View hierarchy\n </Button>\n </CardHeader>\n <CardContent>\n <ProductFeaturesPanel productId={product.id} productArchived={!!product.archivedAt} />\n </CardContent>\n </Card>\n\n {/* ANR-21: CSAT and NPS from responses about this product (its own query — a failure stays in the card). */}\n <SatisfactionSummaryCard scope={{ productId: product.id }} />\n\n {/* PRM-02: strategy narrative + competitive landscape. */}\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\n <ProductAboutPanel product={product} />\n <Card>\n <CardHeader>\n <CardTitle>Competitive landscape</CardTitle>\n </CardHeader>\n <CardContent>\n <ProductCompetitorsPanel productId={product.id} competitors={product.competitors} />\n </CardContent>\n </Card>\n </div>\n\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\n <Card>\n <CardHeader>\n <CardTitle>Roadmaps</CardTitle>\n </CardHeader>\n <CardContent>\n <ProductRoadmapsPanel productId={product.id} roadmaps={product.roadmaps} />\n </CardContent>\n </Card>\n <Card>\n <CardHeader>\n <CardTitle>Releases</CardTitle>\n </CardHeader>\n <CardContent>\n <ProductReleasesPanel productId={product.id} releases={product.releases} />\n </CardContent>\n </Card>\n <Card>\n <CardHeader>\n <CardTitle>Feature requests</CardTitle>\n </CardHeader>\n <CardContent>\n <ProductFeatureRequestsPanel\n productId={product.id}\n featureRequests={product.featureRequests}\n />\n </CardContent>\n </Card>\n <Card>\n <CardHeader>\n <CardTitle>OKR Objectives</CardTitle>\n </CardHeader>\n <CardContent>\n <ProductObjectivesPanel productId={product.id} objectives={product.objectives} />\n </CardContent>\n </Card>\n </div>\n </div>\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":"AAgEA,wBAAgB,6BAA6B,4CAuM5C"}
1
+ {"version":3,"file":"ProductsReleaseDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProductsReleaseDetailPagePage.tsx"],"names":[],"mappings":"AAiEA,wBAAgB,6BAA6B,4CAyM5C"}
@@ -1,20 +1,21 @@
1
1
  import { usePlanMagnet as e } from "../providers/PlanMagnetProvider.js";
2
2
  import { PersonName as t } from "../people/People.js";
3
3
  import { ReleaseHeaderActions as n } from "../controls/ReleaseControls.js";
4
- import { ReleaseNotesCard as r } from "../releases/ReleaseNotesCard.js";
5
- import { ReleaseGatesCard as i } from "../releases/ReleaseGatesCard.js";
6
- import { ReleaseReadinessCard as a } from "../releases/ReleaseReadinessCard.js";
7
- import { ReleaseChecklistCard as o } from "../releases/ReleaseChecklistCard.js";
8
- import { ReleaseWorkItemsCard as s } from "../releases/ReleaseWorkItemsCard.js";
9
- import { Calendar as c, Clock as l, GitBranch as u, Loader2 as d } from "lucide-react";
10
- import { useParams as f } from "react-router";
11
- import { gql as p } from "@apollo/client";
12
- import { useQuery as m } from "@apollo/client/react";
13
- import { jsx as h, jsxs as g } from "react/jsx-runtime";
14
- import { Badge as _, Card as v, CardContent as y, CardHeader as b, CardTitle as x } from "@burdenoff/fe-libs/ui";
15
- import { Markdown as S } from "@burdenoff/fe-libs/shared/components";
4
+ import { SatisfactionSummaryCard as r } from "../satisfaction/SatisfactionSummaryCard.js";
5
+ import { ReleaseNotesCard as i } from "../releases/ReleaseNotesCard.js";
6
+ import { ReleaseGatesCard as a } from "../releases/ReleaseGatesCard.js";
7
+ import { ReleaseReadinessCard as o } from "../releases/ReleaseReadinessCard.js";
8
+ import { ReleaseChecklistCard as s } from "../releases/ReleaseChecklistCard.js";
9
+ import { ReleaseWorkItemsCard as c } from "../releases/ReleaseWorkItemsCard.js";
10
+ import { Calendar as l, Clock as u, GitBranch as d, Loader2 as f } from "lucide-react";
11
+ import { useParams as p } from "react-router";
12
+ import { gql as m } from "@apollo/client";
13
+ import { useQuery as h } from "@apollo/client/react";
14
+ import { jsx as g, jsxs as _ } from "react/jsx-runtime";
15
+ import { Badge as v, Card as y, CardContent as b, CardHeader as x, CardTitle as S } from "@burdenoff/fe-libs/ui";
16
+ import { Markdown as C } from "@burdenoff/fe-libs/shared/components";
16
17
  //#region src/planmagnet/pages/ProductsReleaseDetailPagePage.tsx
17
- var C = p`
18
+ var w = m`
18
19
  query GetRelease($id: ID!) {
19
20
  planmagnetRelease(id: $id) {
20
21
  id
@@ -41,7 +42,7 @@ var C = p`
41
42
  }
42
43
  }
43
44
  }
44
- `, w = {
45
+ `, T = {
45
46
  DRAFT: "bg-gray-100 text-gray-800",
46
47
  PLANNING: "bg-yellow-100 text-yellow-800",
47
48
  IN_PROGRESS: "bg-blue-100 text-blue-800",
@@ -50,109 +51,109 @@ var C = p`
50
51
  CANCELLED: "bg-red-100 text-red-800",
51
52
  ROLLED_BACK: "bg-red-100 text-red-800"
52
53
  };
53
- function T() {
54
- let { workspaceId: p } = e(), T = f().id ?? "", { data: E, loading: D, error: O } = m(C, {
55
- variables: { id: T },
56
- skip: !T
54
+ function E() {
55
+ let { workspaceId: m } = e(), E = p().id ?? "", { data: D, loading: O, error: k } = h(w, {
56
+ variables: { id: E },
57
+ skip: !E
57
58
  });
58
- if (D && !E) return /* @__PURE__ */ h("div", {
59
+ if (O && !D) return /* @__PURE__ */ g("div", {
59
60
  className: "flex items-center justify-center p-12",
60
- children: /* @__PURE__ */ h(d, { className: "h-8 w-8 animate-spin text-muted-foreground" })
61
+ children: /* @__PURE__ */ g(f, { className: "h-8 w-8 animate-spin text-muted-foreground" })
61
62
  });
62
- if (O) return /* @__PURE__ */ g("div", {
63
+ if (k) return /* @__PURE__ */ _("div", {
63
64
  className: "p-6 text-destructive",
64
- children: ["Failed to load release: ", O.message]
65
+ children: ["Failed to load release: ", k.message]
65
66
  });
66
- let k = E?.planmagnetRelease;
67
- if (!k) return /* @__PURE__ */ h("div", {
67
+ let A = D?.planmagnetRelease;
68
+ if (!A) return /* @__PURE__ */ g("div", {
68
69
  className: "p-6 text-muted-foreground",
69
70
  children: "Release not found."
70
71
  });
71
- let A = k.workItems ?? [], j = A.filter((e) => e.type === "EPIC" || e.type === "STORY"), M = A.filter((e) => e.type === "BUG"), N = A.length - j.length - M.length;
72
- return /* @__PURE__ */ g("div", {
72
+ let j = A.workItems ?? [], M = j.filter((e) => e.type === "EPIC" || e.type === "STORY"), N = j.filter((e) => e.type === "BUG"), P = j.length - M.length - N.length;
73
+ return /* @__PURE__ */ _("div", {
73
74
  className: "space-y-6 p-6",
74
- children: [/* @__PURE__ */ g("div", {
75
+ children: [/* @__PURE__ */ _("div", {
75
76
  className: "flex items-center justify-between",
76
- children: [/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ g("div", {
77
+ children: [/* @__PURE__ */ _("div", { children: [/* @__PURE__ */ _("div", {
77
78
  className: "flex items-center gap-2",
78
79
  children: [
79
- /* @__PURE__ */ h(u, { className: "h-5 w-5 text-primary" }),
80
- /* @__PURE__ */ h("h1", {
80
+ /* @__PURE__ */ g(d, { className: "h-5 w-5 text-primary" }),
81
+ /* @__PURE__ */ g("h1", {
81
82
  className: "text-2xl font-semibold",
82
- children: k.version
83
+ children: A.version
83
84
  }),
84
- /* @__PURE__ */ h("span", {
85
- className: `text-xs px-2 py-0.5 rounded-full capitalize ${w[k.status] ?? "bg-gray-100"}`,
86
- children: k.status.toLowerCase().replace("_", " ")
85
+ /* @__PURE__ */ g("span", {
86
+ className: `text-xs px-2 py-0.5 rounded-full capitalize ${T[A.status] ?? "bg-gray-100"}`,
87
+ children: A.status.toLowerCase().replace("_", " ")
87
88
  })
88
89
  ]
89
- }), /* @__PURE__ */ h("p", {
90
+ }), /* @__PURE__ */ g("p", {
90
91
  className: "text-sm text-muted-foreground mt-1",
91
- children: k.name
92
- })] }), /* @__PURE__ */ h(n, {
93
- releaseId: k.id,
94
- version: k.version,
95
- status: k.status
92
+ children: A.name
93
+ })] }), /* @__PURE__ */ g(n, {
94
+ releaseId: A.id,
95
+ version: A.version,
96
+ status: A.status
96
97
  })]
97
- }), /* @__PURE__ */ g("div", {
98
+ }), /* @__PURE__ */ _("div", {
98
99
  className: "grid grid-cols-1 lg:grid-cols-3 gap-6",
99
- children: [/* @__PURE__ */ g("div", {
100
+ children: [/* @__PURE__ */ _("div", {
100
101
  className: "lg:col-span-2 space-y-6",
101
102
  children: [
102
- /* @__PURE__ */ h(a, {
103
- releaseId: k.id,
104
- projectId: k.projectId || null,
105
- releaseStatus: k.status,
106
- plannedDate: k.plannedDate ?? null
103
+ /* @__PURE__ */ g(o, {
104
+ releaseId: A.id,
105
+ projectId: A.projectId || null,
106
+ releaseStatus: A.status,
107
+ plannedDate: A.plannedDate ?? null
107
108
  }),
108
- /* @__PURE__ */ h(o, {
109
- releaseId: k.id,
110
- projectId: k.projectId || null
109
+ /* @__PURE__ */ g(s, {
110
+ releaseId: A.id,
111
+ projectId: A.projectId || null
111
112
  }),
112
- /* @__PURE__ */ g(v, { children: [/* @__PURE__ */ h(b, { children: /* @__PURE__ */ h(x, { children: "Overview" }) }), /* @__PURE__ */ g(y, {
113
+ /* @__PURE__ */ _(y, { children: [/* @__PURE__ */ g(x, { children: /* @__PURE__ */ g(S, { children: "Overview" }) }), /* @__PURE__ */ _(b, {
113
114
  className: "space-y-4",
114
- children: [/* @__PURE__ */ h("div", {
115
+ children: [/* @__PURE__ */ g("div", {
115
116
  className: "text-sm prose prose-sm dark:prose-invert max-w-none",
116
- children: k.description ? /* @__PURE__ */ h(S, { children: k.description }) : /* @__PURE__ */ h("p", { children: "No description provided." })
117
- }), /* @__PURE__ */ g("div", {
117
+ children: A.description ? /* @__PURE__ */ g(C, { children: A.description }) : /* @__PURE__ */ g("p", { children: "No description provided." })
118
+ }), /* @__PURE__ */ _("div", {
118
119
  className: "grid grid-cols-4 gap-4",
119
120
  children: [
120
- /* @__PURE__ */ g("div", {
121
+ /* @__PURE__ */ _("div", {
121
122
  className: "text-center p-3 bg-muted rounded-md",
122
- children: [/* @__PURE__ */ h("p", {
123
+ children: [/* @__PURE__ */ g("p", {
123
124
  className: "text-lg font-semibold mt-1",
124
- children: j.length
125
- }), /* @__PURE__ */ h("p", {
125
+ children: M.length
126
+ }), /* @__PURE__ */ g("p", {
126
127
  className: "text-xs text-muted-foreground",
127
128
  children: "Features"
128
129
  })]
129
130
  }),
130
- /* @__PURE__ */ g("div", {
131
+ /* @__PURE__ */ _("div", {
131
132
  className: "text-center p-3 bg-muted rounded-md",
132
- children: [/* @__PURE__ */ h("p", {
133
+ children: [/* @__PURE__ */ g("p", {
133
134
  className: "text-lg font-semibold mt-1",
134
- children: M.length
135
- }), /* @__PURE__ */ h("p", {
135
+ children: N.length
136
+ }), /* @__PURE__ */ g("p", {
136
137
  className: "text-xs text-muted-foreground",
137
138
  children: "Bug Fixes"
138
139
  })]
139
140
  }),
140
- /* @__PURE__ */ g("div", {
141
+ /* @__PURE__ */ _("div", {
141
142
  className: "text-center p-3 bg-muted rounded-md",
142
- children: [/* @__PURE__ */ h("p", {
143
+ children: [/* @__PURE__ */ g("p", {
143
144
  className: "text-lg font-semibold mt-1",
144
- children: N
145
- }), /* @__PURE__ */ h("p", {
145
+ children: P
146
+ }), /* @__PURE__ */ g("p", {
146
147
  className: "text-xs text-muted-foreground",
147
148
  children: "Other"
148
149
  })]
149
150
  }),
150
- /* @__PURE__ */ g("div", {
151
+ /* @__PURE__ */ _("div", {
151
152
  className: "text-center p-3 bg-muted rounded-md",
152
- children: [/* @__PURE__ */ h("p", {
153
+ children: [/* @__PURE__ */ g("p", {
153
154
  className: "text-lg font-semibold mt-1",
154
- children: A.length
155
- }), /* @__PURE__ */ h("p", {
155
+ children: j.length
156
+ }), /* @__PURE__ */ g("p", {
156
157
  className: "text-xs text-muted-foreground",
157
158
  children: "Total Items"
158
159
  })]
@@ -160,104 +161,105 @@ function T() {
160
161
  ]
161
162
  })]
162
163
  })] }),
163
- /* @__PURE__ */ h(i, {
164
- releaseId: k.id,
165
- projectId: k.projectId ?? null,
166
- releaseStatus: k.status
164
+ /* @__PURE__ */ g(a, {
165
+ releaseId: A.id,
166
+ projectId: A.projectId ?? null,
167
+ releaseStatus: A.status
167
168
  }),
168
- /* @__PURE__ */ h(r, {
169
- releaseId: k.id,
170
- notes: k.releaseNotes ?? null
169
+ /* @__PURE__ */ g(i, {
170
+ releaseId: A.id,
171
+ notes: A.releaseNotes ?? null
171
172
  }),
172
- /* @__PURE__ */ h(s, {
173
- releaseId: k.id,
174
- projectId: k.projectId || null,
175
- items: A
173
+ /* @__PURE__ */ g(c, {
174
+ releaseId: A.id,
175
+ projectId: A.projectId || null,
176
+ items: j
176
177
  })
177
178
  ]
178
- }), /* @__PURE__ */ g("div", {
179
+ }), /* @__PURE__ */ _("div", {
179
180
  className: "space-y-6",
180
181
  children: [
181
- /* @__PURE__ */ g(v, { children: [/* @__PURE__ */ h(b, { children: /* @__PURE__ */ h(x, { children: "Timeline" }) }), /* @__PURE__ */ g(y, {
182
+ /* @__PURE__ */ g(r, { scope: { releaseId: A.id } }),
183
+ /* @__PURE__ */ _(y, { children: [/* @__PURE__ */ g(x, { children: /* @__PURE__ */ g(S, { children: "Timeline" }) }), /* @__PURE__ */ _(b, {
182
184
  className: "space-y-3 text-sm",
183
- children: [/* @__PURE__ */ g("div", {
185
+ children: [/* @__PURE__ */ _("div", {
184
186
  className: "flex items-center gap-2",
185
187
  children: [
186
- /* @__PURE__ */ h(c, { className: "h-4 w-4 text-muted-foreground" }),
187
- /* @__PURE__ */ h("span", {
188
+ /* @__PURE__ */ g(l, { className: "h-4 w-4 text-muted-foreground" }),
189
+ /* @__PURE__ */ g("span", {
188
190
  className: "text-muted-foreground",
189
191
  children: "Planned:"
190
192
  }),
191
- /* @__PURE__ */ h("span", {
193
+ /* @__PURE__ */ g("span", {
192
194
  className: "font-medium",
193
- children: k.plannedDate ? new Date(k.plannedDate).toLocaleDateString() : "Not set"
195
+ children: A.plannedDate ? new Date(A.plannedDate).toLocaleDateString() : "Not set"
194
196
  })
195
197
  ]
196
- }), k.releasedAt && /* @__PURE__ */ g("div", {
198
+ }), A.releasedAt && /* @__PURE__ */ _("div", {
197
199
  className: "flex items-center gap-2",
198
200
  children: [
199
- /* @__PURE__ */ h(l, { className: "h-4 w-4 text-green-500" }),
200
- /* @__PURE__ */ h("span", {
201
+ /* @__PURE__ */ g(u, { className: "h-4 w-4 text-green-500" }),
202
+ /* @__PURE__ */ g("span", {
201
203
  className: "text-muted-foreground",
202
204
  children: "Released:"
203
205
  }),
204
- /* @__PURE__ */ h("span", {
206
+ /* @__PURE__ */ g("span", {
205
207
  className: "font-medium",
206
- children: new Date(k.releasedAt).toLocaleDateString()
208
+ children: new Date(A.releasedAt).toLocaleDateString()
207
209
  })
208
210
  ]
209
211
  })]
210
212
  })] }),
211
- /* @__PURE__ */ g(v, { children: [/* @__PURE__ */ h(b, { children: /* @__PURE__ */ h(x, { children: "Details" }) }), /* @__PURE__ */ g(y, {
213
+ /* @__PURE__ */ _(y, { children: [/* @__PURE__ */ g(x, { children: /* @__PURE__ */ g(S, { children: "Details" }) }), /* @__PURE__ */ _(b, {
212
214
  className: "space-y-2 text-sm",
213
215
  children: [
214
- /* @__PURE__ */ g("div", {
216
+ /* @__PURE__ */ _("div", {
215
217
  className: "flex justify-between",
216
- children: [/* @__PURE__ */ h("span", {
218
+ children: [/* @__PURE__ */ g("span", {
217
219
  className: "text-muted-foreground",
218
220
  children: "Version"
219
- }), /* @__PURE__ */ h("span", {
221
+ }), /* @__PURE__ */ g("span", {
220
222
  className: "font-medium",
221
- children: k.version
223
+ children: A.version
222
224
  })]
223
225
  }),
224
- /* @__PURE__ */ g("div", {
226
+ /* @__PURE__ */ _("div", {
225
227
  className: "flex justify-between",
226
- children: [/* @__PURE__ */ h("span", {
228
+ children: [/* @__PURE__ */ g("span", {
227
229
  className: "text-muted-foreground",
228
230
  children: "Status"
229
- }), /* @__PURE__ */ h(_, {
231
+ }), /* @__PURE__ */ g(v, {
230
232
  variant: "outline",
231
233
  className: "text-xs capitalize",
232
- children: k.status.toLowerCase().replace("_", " ")
234
+ children: A.status.toLowerCase().replace("_", " ")
233
235
  })]
234
236
  }),
235
- /* @__PURE__ */ g("div", {
237
+ /* @__PURE__ */ _("div", {
236
238
  className: "flex justify-between",
237
- children: [/* @__PURE__ */ h("span", {
239
+ children: [/* @__PURE__ */ g("span", {
238
240
  className: "text-muted-foreground",
239
241
  children: "Owner"
240
- }), /* @__PURE__ */ h("span", { children: /* @__PURE__ */ h(t, { id: k.ownerId }) })]
242
+ }), /* @__PURE__ */ g("span", { children: /* @__PURE__ */ g(t, { id: A.ownerId }) })]
241
243
  }),
242
- /* @__PURE__ */ g("div", {
244
+ /* @__PURE__ */ _("div", {
243
245
  className: "flex justify-between",
244
- children: [/* @__PURE__ */ h("span", {
246
+ children: [/* @__PURE__ */ g("span", {
245
247
  className: "text-muted-foreground",
246
248
  children: "Created"
247
- }), /* @__PURE__ */ h("span", { children: new Date(k.createdAt).toLocaleDateString() })]
249
+ }), /* @__PURE__ */ g("span", { children: new Date(A.createdAt).toLocaleDateString() })]
248
250
  }),
249
- /* @__PURE__ */ g("div", {
251
+ /* @__PURE__ */ _("div", {
250
252
  className: "flex justify-between",
251
- children: [/* @__PURE__ */ h("span", {
253
+ children: [/* @__PURE__ */ g("span", {
252
254
  className: "text-muted-foreground",
253
255
  children: "Updated"
254
- }), /* @__PURE__ */ h("span", { children: new Date(k.updatedAt).toLocaleDateString() })]
256
+ }), /* @__PURE__ */ g("span", { children: new Date(A.updatedAt).toLocaleDateString() })]
255
257
  })
256
258
  ]
257
259
  })] }),
258
- k.tags?.length > 0 && /* @__PURE__ */ g(v, { children: [/* @__PURE__ */ h(b, { children: /* @__PURE__ */ h(x, { children: "Tags" }) }), /* @__PURE__ */ h(y, {
260
+ A.tags?.length > 0 && /* @__PURE__ */ _(y, { children: [/* @__PURE__ */ g(x, { children: /* @__PURE__ */ g(S, { children: "Tags" }) }), /* @__PURE__ */ g(b, {
259
261
  className: "flex flex-wrap gap-1",
260
- children: k.tags.map((e) => /* @__PURE__ */ h(_, {
262
+ children: A.tags.map((e) => /* @__PURE__ */ g(v, {
261
263
  variant: "outline",
262
264
  className: "text-xs",
263
265
  children: e
@@ -269,6 +271,6 @@ function T() {
269
271
  });
270
272
  }
271
273
  //#endregion
272
- export { T as ProductsReleaseDetailPagePage };
274
+ export { E as ProductsReleaseDetailPagePage };
273
275
 
274
276
  //# sourceMappingURL=ProductsReleaseDetailPagePage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ProductsReleaseDetailPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProductsReleaseDetailPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Badge } from '@burdenoff/fe-libs/ui';\nimport { Markdown } from '@burdenoff/fe-libs/shared/components';\nimport { GitBranch, Calendar, Clock, Server, Loader2 } from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\nimport { useParams } from 'react-router';\nimport { PersonName } from '../people/People';\nimport { ReleaseNotesCard } from '../releases/ReleaseNotesCard';\nimport { ReleaseHeaderActions } from '../controls/ReleaseControls';\nimport { ReleaseGatesCard } from '../releases/ReleaseGatesCard';\nimport { ReleaseReadinessCard } from '../releases/ReleaseReadinessCard';\nimport { ReleaseChecklistCard } from '../releases/ReleaseChecklistCard';\nimport { ReleaseWorkItemsCard } from '../releases/ReleaseWorkItemsCard';\n\nconst GET_RELEASE = gql`\n query GetRelease($id: ID!) {\n planmagnetRelease(id: $id) {\n id\n workspaceId\n projectId\n name\n description\n version\n status\n plannedDate\n releasedAt\n releaseNotes\n ownerId\n tags\n metadata\n createdAt\n updatedAt\n workItems {\n id\n title\n status\n type\n priority\n }\n }\n }\n`;\n\ninterface WorkItemSummary {\n id: string;\n title: string;\n status: string;\n type: string;\n priority: string;\n}\n\nconst statusColor: Record<string, string> = {\n DRAFT: 'bg-gray-100 text-gray-800',\n PLANNING: 'bg-yellow-100 text-yellow-800',\n IN_PROGRESS: 'bg-blue-100 text-blue-800',\n READY: 'bg-orange-100 text-orange-800',\n RELEASED: 'bg-green-100 text-green-800',\n CANCELLED: 'bg-red-100 text-red-800',\n ROLLED_BACK: 'bg-red-100 text-red-800',\n};\n\nexport function ProductsReleaseDetailPagePage() {\n const { workspaceId } = usePlanMagnet();\n const params = useParams<{ id: string }>();\n const releaseId = params.id ?? '';\n\n const {\n data,\n loading,\n error,\n } = // eslint-disable-next-line @typescript-eslint/no-explicit-any\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n useQuery<Record<string, any>>(GET_RELEASE, {\n variables: { id: releaseId },\n skip: !releaseId,\n });\n\n // Only before the first load: a refetch must not blank the page (it\n\n // unmounts every component on it and loses their state).\n\n if (loading && !data) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-muted-foreground\" />\n </div>\n );\n }\n\n if (error) {\n return <div className=\"p-6 text-destructive\">Failed to load release: {error.message}</div>;\n }\n\n const release = data?.planmagnetRelease;\n if (!release) return <div className=\"p-6 text-muted-foreground\">Release not found.</div>;\n\n const workItems: WorkItemSummary[] = release.workItems ?? [];\n // The release notes' classification (svc release-notes.ts): EPIC and STORY are features, BUG a fix, the rest other\n // — so these tiles agree with the notes on the same page and add up to the total (BOFF-7988).\n const featureItems = workItems.filter((w) => w.type === 'EPIC' || w.type === 'STORY');\n const bugItems = workItems.filter((w) => w.type === 'BUG');\n const otherItems = workItems.length - featureItems.length - bugItems.length;\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"flex items-center gap-2\">\n <GitBranch className=\"h-5 w-5 text-primary\" />\n <h1 className=\"text-2xl font-semibold\">{release.version}</h1>\n <span\n className={`text-xs px-2 py-0.5 rounded-full capitalize ${statusColor[release.status] ?? 'bg-gray-100'}`}\n >\n {release.status.toLowerCase().replace('_', ' ')}\n </span>\n </div>\n <p className=\"text-sm text-muted-foreground mt-1\">{release.name}</p>\n </div>\n {/* Status, Edit and Delete (BOFF-7952): nothing could release, edit or delete a release. */}\n <ReleaseHeaderActions\n releaseId={release.id}\n version={release.version}\n status={release.status}\n />\n </div>\n\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n <div className=\"lg:col-span-2 space-y-6\">\n <ReleaseReadinessCard\n releaseId={release.id}\n projectId={release.projectId || null}\n releaseStatus={release.status}\n plannedDate={release.plannedDate ?? null}\n />\n {/* PRM-19: the team's readiness criteria; a required one still open blocks releasing. */}\n <ReleaseChecklistCard releaseId={release.id} projectId={release.projectId || null} />\n <Card>\n <CardHeader>\n <CardTitle>Overview</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"text-sm prose prose-sm dark:prose-invert max-w-none\">\n {release.description ? (\n <Markdown>{release.description}</Markdown>\n ) : (\n <p>No description provided.</p>\n )}\n </div>\n <div className=\"grid grid-cols-4 gap-4\">\n <div className=\"text-center p-3 bg-muted rounded-md\">\n <p className=\"text-lg font-semibold mt-1\">{featureItems.length}</p>\n <p className=\"text-xs text-muted-foreground\">Features</p>\n </div>\n <div className=\"text-center p-3 bg-muted rounded-md\">\n <p className=\"text-lg font-semibold mt-1\">{bugItems.length}</p>\n <p className=\"text-xs text-muted-foreground\">Bug Fixes</p>\n </div>\n <div className=\"text-center p-3 bg-muted rounded-md\">\n <p className=\"text-lg font-semibold mt-1\">{otherItems}</p>\n <p className=\"text-xs text-muted-foreground\">Other</p>\n </div>\n <div className=\"text-center p-3 bg-muted rounded-md\">\n <p className=\"text-lg font-semibold mt-1\">{workItems.length}</p>\n <p className=\"text-xs text-muted-foreground\">Total Items</p>\n </div>\n </div>\n </CardContent>\n </Card>\n\n <ReleaseGatesCard\n releaseId={release.id}\n projectId={release.projectId ?? null}\n releaseStatus={release.status}\n />\n <ReleaseNotesCard releaseId={release.id} notes={release.releaseNotes ?? null} />\n\n <ReleaseWorkItemsCard\n releaseId={release.id}\n projectId={release.projectId || null}\n items={workItems}\n />\n </div>\n\n <div className=\"space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle>Timeline</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3 text-sm\">\n <div className=\"flex items-center gap-2\">\n <Calendar className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"text-muted-foreground\">Planned:</span>\n <span className=\"font-medium\">\n {release.plannedDate\n ? new Date(release.plannedDate).toLocaleDateString()\n : 'Not set'}\n </span>\n </div>\n {release.releasedAt && (\n <div className=\"flex items-center gap-2\">\n <Clock className=\"h-4 w-4 text-green-500\" />\n <span className=\"text-muted-foreground\">Released:</span>\n <span className=\"font-medium\">\n {new Date(release.releasedAt).toLocaleDateString()}\n </span>\n </div>\n )}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2 text-sm\">\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Version</span>\n <span className=\"font-medium\">{release.version}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Status</span>\n <Badge variant=\"outline\" className=\"text-xs capitalize\">\n {release.status.toLowerCase().replace('_', ' ')}\n </Badge>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Owner</span>\n <span>\n <PersonName id={release.ownerId} />\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Created</span>\n <span>{new Date(release.createdAt).toLocaleDateString()}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Updated</span>\n <span>{new Date(release.updatedAt).toLocaleDateString()}</span>\n </div>\n </CardContent>\n </Card>\n\n {release.tags?.length > 0 && (\n <Card>\n <CardHeader>\n <CardTitle>Tags</CardTitle>\n </CardHeader>\n <CardContent className=\"flex flex-wrap gap-1\">\n {release.tags.map((tag: string) => (\n <Badge key={tag} variant=\"outline\" className=\"text-xs\">\n {tag}\n </Badge>\n ))}\n </CardContent>\n </Card>\n )}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAiBA,IAAM,IAAc,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCjB,IAAsC;CAC1C,OAAO;CACP,UAAU;CACV,aAAa;CACb,OAAO;CACP,UAAU;CACV,WAAW;CACX,aAAa;CACd;AAED,SAAgB,IAAgC;CAC9C,IAAM,EAAE,mBAAgB,GAAe,EAEjC,IADS,GAA2B,CACjB,MAAM,IAEzB,EACJ,SACA,YACA,aAGA,EAA8B,GAAa;EACzC,WAAW,EAAE,IAAI,GAAW;EAC5B,MAAM,CAAC;EACR,CAAC;AAMJ,KAAI,KAAW,CAAC,EACd,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD,EAAS,WAAU,8CAA+C,CAAA;EAC9D,CAAA;AAIV,KAAI,EACF,QAAO,kBAAC,OAAD;EAAK,WAAU;YAAf,CAAsC,4BAAyB,EAAM,QAAc;;CAG5F,IAAM,IAAU,GAAM;AACtB,KAAI,CAAC,EAAS,QAAO,kBAAC,OAAD;EAAK,WAAU;YAA4B;EAAwB,CAAA;CAExF,IAAM,IAA+B,EAAQ,aAAa,EAAE,EAGtD,IAAe,EAAU,QAAQ,MAAM,EAAE,SAAS,UAAU,EAAE,SAAS,QAAQ,EAC/E,IAAW,EAAU,QAAQ,MAAM,EAAE,SAAS,MAAM,EACpD,IAAa,EAAU,SAAS,EAAa,SAAS,EAAS;AAErE,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD,EAAW,WAAU,wBAAyB,CAAA;KAC9C,kBAAC,MAAD;MAAI,WAAU;gBAA0B,EAAQ;MAAa,CAAA;KAC7D,kBAAC,QAAD;MACE,WAAW,+CAA+C,EAAY,EAAQ,WAAW;gBAExF,EAAQ,OAAO,aAAa,CAAC,QAAQ,KAAK,IAAI;MAC1C,CAAA;KACH;OACN,kBAAC,KAAD;IAAG,WAAU;cAAsC,EAAQ;IAAS,CAAA,CAChE,EAAA,CAAA,EAEN,kBAAC,GAAD;IACE,WAAW,EAAQ;IACnB,SAAS,EAAQ;IACjB,QAAQ,EAAQ;IAChB,CAAA,CACE;MAEN,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MACE,WAAW,EAAQ;MACnB,WAAW,EAAQ,aAAa;MAChC,eAAe,EAAQ;MACvB,aAAa,EAAQ,eAAe;MACpC,CAAA;KAEF,kBAAC,GAAD;MAAsB,WAAW,EAAQ;MAAI,WAAW,EAAQ,aAAa;MAAQ,CAAA;KACrF,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAW,YAAoB,CAAA,EACpB,CAAA,EACb,kBAAC,GAAD;MAAa,WAAU;gBAAvB,CACE,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAQ,cACP,kBAAC,GAAD,EAAA,UAAW,EAAQ,aAAuB,CAAA,GAE1C,kBAAC,KAAD,EAAA,UAAG,4BAA4B,CAAA;OAE7B,CAAA,EACN,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,KAAD;UAAG,WAAU;oBAA8B,EAAa;UAAW,CAAA,EACnE,kBAAC,KAAD;UAAG,WAAU;oBAAgC;UAAY,CAAA,CACrD;;QACN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,KAAD;UAAG,WAAU;oBAA8B,EAAS;UAAW,CAAA,EAC/D,kBAAC,KAAD;UAAG,WAAU;oBAAgC;UAAa,CAAA,CACtD;;QACN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,KAAD;UAAG,WAAU;oBAA8B;UAAe,CAAA,EAC1D,kBAAC,KAAD;UAAG,WAAU;oBAAgC;UAAS,CAAA,CAClD;;QACN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,KAAD;UAAG,WAAU;oBAA8B,EAAU;UAAW,CAAA,EAChE,kBAAC,KAAD;UAAG,WAAU;oBAAgC;UAAe,CAAA,CACxD;;QACF;SACM;QACT,EAAA,CAAA;KAEP,kBAAC,GAAD;MACE,WAAW,EAAQ;MACnB,WAAW,EAAQ,aAAa;MAChC,eAAe,EAAQ;MACvB,CAAA;KACF,kBAAC,GAAD;MAAkB,WAAW,EAAQ;MAAI,OAAO,EAAQ,gBAAgB;MAAQ,CAAA;KAEhF,kBAAC,GAAD;MACE,WAAW,EAAQ;MACnB,WAAW,EAAQ,aAAa;MAChC,OAAO;MACP,CAAA;KACE;OAEN,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAW,YAAoB,CAAA,EACpB,CAAA,EACb,kBAAC,GAAD;MAAa,WAAU;gBAAvB,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,GAAD,EAAU,WAAU,iCAAkC,CAAA;QACtD,kBAAC,QAAD;SAAM,WAAU;mBAAwB;SAAe,CAAA;QACvD,kBAAC,QAAD;SAAM,WAAU;mBACb,EAAQ,cACL,IAAI,KAAK,EAAQ,YAAY,CAAC,oBAAoB,GAClD;SACC,CAAA;QACH;UACL,EAAQ,cACP,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,GAAD,EAAO,WAAU,0BAA2B,CAAA;QAC5C,kBAAC,QAAD;SAAM,WAAU;mBAAwB;SAAgB,CAAA;QACxD,kBAAC,QAAD;SAAM,WAAU;mBACb,IAAI,KAAK,EAAQ,WAAW,CAAC,oBAAoB;SAC7C,CAAA;QACH;SAEI;QACT,EAAA,CAAA;KAEP,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAW,WAAmB,CAAA,EACnB,CAAA,EACb,kBAAC,GAAD;MAAa,WAAU;gBAAvB;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,QAAD;SAAM,WAAU;mBAAwB;SAAc,CAAA,EACtD,kBAAC,QAAD;SAAM,WAAU;mBAAe,EAAQ;SAAe,CAAA,CAClD;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,QAAD;SAAM,WAAU;mBAAwB;SAAa,CAAA,EACrD,kBAAC,GAAD;SAAO,SAAQ;SAAU,WAAU;mBAChC,EAAQ,OAAO,aAAa,CAAC,QAAQ,KAAK,IAAI;SACzC,CAAA,CACJ;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,QAAD;SAAM,WAAU;mBAAwB;SAAY,CAAA,EACpD,kBAAC,QAAD,EAAA,UACE,kBAAC,GAAD,EAAY,IAAI,EAAQ,SAAW,CAAA,EAC9B,CAAA,CACH;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,QAAD;SAAM,WAAU;mBAAwB;SAAc,CAAA,EACtD,kBAAC,QAAD,EAAA,UAAO,IAAI,KAAK,EAAQ,UAAU,CAAC,oBAAoB,EAAQ,CAAA,CAC3D;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,QAAD;SAAM,WAAU;mBAAwB;SAAc,CAAA,EACtD,kBAAC,QAAD,EAAA,UAAO,IAAI,KAAK,EAAQ,UAAU,CAAC,oBAAoB,EAAQ,CAAA,CAC3D;;OACM;QACT,EAAA,CAAA;KAEN,EAAQ,MAAM,SAAS,KACtB,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAW,QAAgB,CAAA,EAChB,CAAA,EACb,kBAAC,GAAD;MAAa,WAAU;gBACpB,EAAQ,KAAK,KAAK,MACjB,kBAAC,GAAD;OAAiB,SAAQ;OAAU,WAAU;iBAC1C;OACK,EAFI,EAEJ,CACR;MACU,CAAA,CACT,EAAA,CAAA;KAEL;MACF;KACF"}
1
+ {"version":3,"file":"ProductsReleaseDetailPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProductsReleaseDetailPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Badge } from '@burdenoff/fe-libs/ui';\nimport { Markdown } from '@burdenoff/fe-libs/shared/components';\nimport { GitBranch, Calendar, Clock, Server, Loader2 } from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\nimport { useParams } from 'react-router';\nimport { PersonName } from '../people/People';\nimport { ReleaseNotesCard } from '../releases/ReleaseNotesCard';\nimport { ReleaseHeaderActions } from '../controls/ReleaseControls';\nimport { ReleaseGatesCard } from '../releases/ReleaseGatesCard';\nimport { ReleaseReadinessCard } from '../releases/ReleaseReadinessCard';\nimport { ReleaseChecklistCard } from '../releases/ReleaseChecklistCard';\nimport { ReleaseWorkItemsCard } from '../releases/ReleaseWorkItemsCard';\nimport { SatisfactionSummaryCard } from '../satisfaction/SatisfactionSummaryCard';\n\nconst GET_RELEASE = gql`\n query GetRelease($id: ID!) {\n planmagnetRelease(id: $id) {\n id\n workspaceId\n projectId\n name\n description\n version\n status\n plannedDate\n releasedAt\n releaseNotes\n ownerId\n tags\n metadata\n createdAt\n updatedAt\n workItems {\n id\n title\n status\n type\n priority\n }\n }\n }\n`;\n\ninterface WorkItemSummary {\n id: string;\n title: string;\n status: string;\n type: string;\n priority: string;\n}\n\nconst statusColor: Record<string, string> = {\n DRAFT: 'bg-gray-100 text-gray-800',\n PLANNING: 'bg-yellow-100 text-yellow-800',\n IN_PROGRESS: 'bg-blue-100 text-blue-800',\n READY: 'bg-orange-100 text-orange-800',\n RELEASED: 'bg-green-100 text-green-800',\n CANCELLED: 'bg-red-100 text-red-800',\n ROLLED_BACK: 'bg-red-100 text-red-800',\n};\n\nexport function ProductsReleaseDetailPagePage() {\n const { workspaceId } = usePlanMagnet();\n const params = useParams<{ id: string }>();\n const releaseId = params.id ?? '';\n\n const {\n data,\n loading,\n error,\n } = // eslint-disable-next-line @typescript-eslint/no-explicit-any\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n useQuery<Record<string, any>>(GET_RELEASE, {\n variables: { id: releaseId },\n skip: !releaseId,\n });\n\n // Only before the first load: a refetch must not blank the page (it\n\n // unmounts every component on it and loses their state).\n\n if (loading && !data) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-muted-foreground\" />\n </div>\n );\n }\n\n if (error) {\n return <div className=\"p-6 text-destructive\">Failed to load release: {error.message}</div>;\n }\n\n const release = data?.planmagnetRelease;\n if (!release) return <div className=\"p-6 text-muted-foreground\">Release not found.</div>;\n\n const workItems: WorkItemSummary[] = release.workItems ?? [];\n // The release notes' classification (svc release-notes.ts): EPIC and STORY are features, BUG a fix, the rest other\n // — so these tiles agree with the notes on the same page and add up to the total (BOFF-7988).\n const featureItems = workItems.filter((w) => w.type === 'EPIC' || w.type === 'STORY');\n const bugItems = workItems.filter((w) => w.type === 'BUG');\n const otherItems = workItems.length - featureItems.length - bugItems.length;\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"flex items-center gap-2\">\n <GitBranch className=\"h-5 w-5 text-primary\" />\n <h1 className=\"text-2xl font-semibold\">{release.version}</h1>\n <span\n className={`text-xs px-2 py-0.5 rounded-full capitalize ${statusColor[release.status] ?? 'bg-gray-100'}`}\n >\n {release.status.toLowerCase().replace('_', ' ')}\n </span>\n </div>\n <p className=\"text-sm text-muted-foreground mt-1\">{release.name}</p>\n </div>\n {/* Status, Edit and Delete (BOFF-7952): nothing could release, edit or delete a release. */}\n <ReleaseHeaderActions\n releaseId={release.id}\n version={release.version}\n status={release.status}\n />\n </div>\n\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n <div className=\"lg:col-span-2 space-y-6\">\n <ReleaseReadinessCard\n releaseId={release.id}\n projectId={release.projectId || null}\n releaseStatus={release.status}\n plannedDate={release.plannedDate ?? null}\n />\n {/* PRM-19: the team's readiness criteria; a required one still open blocks releasing. */}\n <ReleaseChecklistCard releaseId={release.id} projectId={release.projectId || null} />\n <Card>\n <CardHeader>\n <CardTitle>Overview</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"text-sm prose prose-sm dark:prose-invert max-w-none\">\n {release.description ? (\n <Markdown>{release.description}</Markdown>\n ) : (\n <p>No description provided.</p>\n )}\n </div>\n <div className=\"grid grid-cols-4 gap-4\">\n <div className=\"text-center p-3 bg-muted rounded-md\">\n <p className=\"text-lg font-semibold mt-1\">{featureItems.length}</p>\n <p className=\"text-xs text-muted-foreground\">Features</p>\n </div>\n <div className=\"text-center p-3 bg-muted rounded-md\">\n <p className=\"text-lg font-semibold mt-1\">{bugItems.length}</p>\n <p className=\"text-xs text-muted-foreground\">Bug Fixes</p>\n </div>\n <div className=\"text-center p-3 bg-muted rounded-md\">\n <p className=\"text-lg font-semibold mt-1\">{otherItems}</p>\n <p className=\"text-xs text-muted-foreground\">Other</p>\n </div>\n <div className=\"text-center p-3 bg-muted rounded-md\">\n <p className=\"text-lg font-semibold mt-1\">{workItems.length}</p>\n <p className=\"text-xs text-muted-foreground\">Total Items</p>\n </div>\n </div>\n </CardContent>\n </Card>\n\n <ReleaseGatesCard\n releaseId={release.id}\n projectId={release.projectId ?? null}\n releaseStatus={release.status}\n />\n <ReleaseNotesCard releaseId={release.id} notes={release.releaseNotes ?? null} />\n\n <ReleaseWorkItemsCard\n releaseId={release.id}\n projectId={release.projectId || null}\n items={workItems}\n />\n </div>\n\n <div className=\"space-y-6\">\n {/* ANR-21: CSAT and NPS from responses about this release (its own query). */}\n <SatisfactionSummaryCard scope={{ releaseId: release.id }} />\n <Card>\n <CardHeader>\n <CardTitle>Timeline</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3 text-sm\">\n <div className=\"flex items-center gap-2\">\n <Calendar className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"text-muted-foreground\">Planned:</span>\n <span className=\"font-medium\">\n {release.plannedDate\n ? new Date(release.plannedDate).toLocaleDateString()\n : 'Not set'}\n </span>\n </div>\n {release.releasedAt && (\n <div className=\"flex items-center gap-2\">\n <Clock className=\"h-4 w-4 text-green-500\" />\n <span className=\"text-muted-foreground\">Released:</span>\n <span className=\"font-medium\">\n {new Date(release.releasedAt).toLocaleDateString()}\n </span>\n </div>\n )}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2 text-sm\">\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Version</span>\n <span className=\"font-medium\">{release.version}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Status</span>\n <Badge variant=\"outline\" className=\"text-xs capitalize\">\n {release.status.toLowerCase().replace('_', ' ')}\n </Badge>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Owner</span>\n <span>\n <PersonName id={release.ownerId} />\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Created</span>\n <span>{new Date(release.createdAt).toLocaleDateString()}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Updated</span>\n <span>{new Date(release.updatedAt).toLocaleDateString()}</span>\n </div>\n </CardContent>\n </Card>\n\n {release.tags?.length > 0 && (\n <Card>\n <CardHeader>\n <CardTitle>Tags</CardTitle>\n </CardHeader>\n <CardContent className=\"flex flex-wrap gap-1\">\n {release.tags.map((tag: string) => (\n <Badge key={tag} variant=\"outline\" className=\"text-xs\">\n {tag}\n </Badge>\n ))}\n </CardContent>\n </Card>\n )}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAkBA,IAAM,IAAc,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCjB,IAAsC;CAC1C,OAAO;CACP,UAAU;CACV,aAAa;CACb,OAAO;CACP,UAAU;CACV,WAAW;CACX,aAAa;CACd;AAED,SAAgB,IAAgC;CAC9C,IAAM,EAAE,mBAAgB,GAAe,EAEjC,IADS,GAA2B,CACjB,MAAM,IAEzB,EACJ,SACA,YACA,aAGA,EAA8B,GAAa;EACzC,WAAW,EAAE,IAAI,GAAW;EAC5B,MAAM,CAAC;EACR,CAAC;AAMJ,KAAI,KAAW,CAAC,EACd,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD,EAAS,WAAU,8CAA+C,CAAA;EAC9D,CAAA;AAIV,KAAI,EACF,QAAO,kBAAC,OAAD;EAAK,WAAU;YAAf,CAAsC,4BAAyB,EAAM,QAAc;;CAG5F,IAAM,IAAU,GAAM;AACtB,KAAI,CAAC,EAAS,QAAO,kBAAC,OAAD;EAAK,WAAU;YAA4B;EAAwB,CAAA;CAExF,IAAM,IAA+B,EAAQ,aAAa,EAAE,EAGtD,IAAe,EAAU,QAAQ,MAAM,EAAE,SAAS,UAAU,EAAE,SAAS,QAAQ,EAC/E,IAAW,EAAU,QAAQ,MAAM,EAAE,SAAS,MAAM,EACpD,IAAa,EAAU,SAAS,EAAa,SAAS,EAAS;AAErE,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD,EAAW,WAAU,wBAAyB,CAAA;KAC9C,kBAAC,MAAD;MAAI,WAAU;gBAA0B,EAAQ;MAAa,CAAA;KAC7D,kBAAC,QAAD;MACE,WAAW,+CAA+C,EAAY,EAAQ,WAAW;gBAExF,EAAQ,OAAO,aAAa,CAAC,QAAQ,KAAK,IAAI;MAC1C,CAAA;KACH;OACN,kBAAC,KAAD;IAAG,WAAU;cAAsC,EAAQ;IAAS,CAAA,CAChE,EAAA,CAAA,EAEN,kBAAC,GAAD;IACE,WAAW,EAAQ;IACnB,SAAS,EAAQ;IACjB,QAAQ,EAAQ;IAChB,CAAA,CACE;MAEN,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MACE,WAAW,EAAQ;MACnB,WAAW,EAAQ,aAAa;MAChC,eAAe,EAAQ;MACvB,aAAa,EAAQ,eAAe;MACpC,CAAA;KAEF,kBAAC,GAAD;MAAsB,WAAW,EAAQ;MAAI,WAAW,EAAQ,aAAa;MAAQ,CAAA;KACrF,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAW,YAAoB,CAAA,EACpB,CAAA,EACb,kBAAC,GAAD;MAAa,WAAU;gBAAvB,CACE,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAQ,cACP,kBAAC,GAAD,EAAA,UAAW,EAAQ,aAAuB,CAAA,GAE1C,kBAAC,KAAD,EAAA,UAAG,4BAA4B,CAAA;OAE7B,CAAA,EACN,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,KAAD;UAAG,WAAU;oBAA8B,EAAa;UAAW,CAAA,EACnE,kBAAC,KAAD;UAAG,WAAU;oBAAgC;UAAY,CAAA,CACrD;;QACN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,KAAD;UAAG,WAAU;oBAA8B,EAAS;UAAW,CAAA,EAC/D,kBAAC,KAAD;UAAG,WAAU;oBAAgC;UAAa,CAAA,CACtD;;QACN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,KAAD;UAAG,WAAU;oBAA8B;UAAe,CAAA,EAC1D,kBAAC,KAAD;UAAG,WAAU;oBAAgC;UAAS,CAAA,CAClD;;QACN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,KAAD;UAAG,WAAU;oBAA8B,EAAU;UAAW,CAAA,EAChE,kBAAC,KAAD;UAAG,WAAU;oBAAgC;UAAe,CAAA,CACxD;;QACF;SACM;QACT,EAAA,CAAA;KAEP,kBAAC,GAAD;MACE,WAAW,EAAQ;MACnB,WAAW,EAAQ,aAAa;MAChC,eAAe,EAAQ;MACvB,CAAA;KACF,kBAAC,GAAD;MAAkB,WAAW,EAAQ;MAAI,OAAO,EAAQ,gBAAgB;MAAQ,CAAA;KAEhF,kBAAC,GAAD;MACE,WAAW,EAAQ;MACnB,WAAW,EAAQ,aAAa;MAChC,OAAO;MACP,CAAA;KACE;OAEN,kBAAC,OAAD;IAAK,WAAU;cAAf;KAEE,kBAAC,GAAD,EAAyB,OAAO,EAAE,WAAW,EAAQ,IAAI,EAAI,CAAA;KAC7D,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAW,YAAoB,CAAA,EACpB,CAAA,EACb,kBAAC,GAAD;MAAa,WAAU;gBAAvB,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,GAAD,EAAU,WAAU,iCAAkC,CAAA;QACtD,kBAAC,QAAD;SAAM,WAAU;mBAAwB;SAAe,CAAA;QACvD,kBAAC,QAAD;SAAM,WAAU;mBACb,EAAQ,cACL,IAAI,KAAK,EAAQ,YAAY,CAAC,oBAAoB,GAClD;SACC,CAAA;QACH;UACL,EAAQ,cACP,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,GAAD,EAAO,WAAU,0BAA2B,CAAA;QAC5C,kBAAC,QAAD;SAAM,WAAU;mBAAwB;SAAgB,CAAA;QACxD,kBAAC,QAAD;SAAM,WAAU;mBACb,IAAI,KAAK,EAAQ,WAAW,CAAC,oBAAoB;SAC7C,CAAA;QACH;SAEI;QACT,EAAA,CAAA;KAEP,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAW,WAAmB,CAAA,EACnB,CAAA,EACb,kBAAC,GAAD;MAAa,WAAU;gBAAvB;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,QAAD;SAAM,WAAU;mBAAwB;SAAc,CAAA,EACtD,kBAAC,QAAD;SAAM,WAAU;mBAAe,EAAQ;SAAe,CAAA,CAClD;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,QAAD;SAAM,WAAU;mBAAwB;SAAa,CAAA,EACrD,kBAAC,GAAD;SAAO,SAAQ;SAAU,WAAU;mBAChC,EAAQ,OAAO,aAAa,CAAC,QAAQ,KAAK,IAAI;SACzC,CAAA,CACJ;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,QAAD;SAAM,WAAU;mBAAwB;SAAY,CAAA,EACpD,kBAAC,QAAD,EAAA,UACE,kBAAC,GAAD,EAAY,IAAI,EAAQ,SAAW,CAAA,EAC9B,CAAA,CACH;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,QAAD;SAAM,WAAU;mBAAwB;SAAc,CAAA,EACtD,kBAAC,QAAD,EAAA,UAAO,IAAI,KAAK,EAAQ,UAAU,CAAC,oBAAoB,EAAQ,CAAA,CAC3D;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,QAAD;SAAM,WAAU;mBAAwB;SAAc,CAAA,EACtD,kBAAC,QAAD,EAAA,UAAO,IAAI,KAAK,EAAQ,UAAU,CAAC,oBAAoB,EAAQ,CAAA,CAC3D;;OACM;QACT,EAAA,CAAA;KAEN,EAAQ,MAAM,SAAS,KACtB,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAW,QAAgB,CAAA,EAChB,CAAA,EACb,kBAAC,GAAD;MAAa,WAAU;gBACpB,EAAQ,KAAK,KAAK,MACjB,kBAAC,GAAD;OAAiB,SAAQ;OAAU,WAAU;iBAC1C;OACK,EAFI,EAEJ,CACR;MACU,CAAA,CACT,EAAA,CAAA;KAEL;MACF;KACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"ProjectsPlanningDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProjectsPlanningDetailPagePage.tsx"],"names":[],"mappings":"AA8FA,wBAAgB,8BAA8B,4CA0W7C"}
1
+ {"version":3,"file":"ProjectsPlanningDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProjectsPlanningDetailPagePage.tsx"],"names":[],"mappings":"AAuGA,wBAAgB,8BAA8B,4CA4X7C"}