@burdenoff/microfe-planmagnet 2026.930.25 → 2026.1001.2

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 (314) hide show
  1. package/dist/_virtual/__vite-browser-external.js +9 -0
  2. package/dist/_virtual/__vite-browser-external.js.map +1 -0
  3. package/dist/_virtual/_rolldown/runtime.js +5 -2
  4. package/dist/index.js +3 -1
  5. package/dist/node_modules/fflate/esm/browser.js +554 -0
  6. package/dist/node_modules/fflate/esm/browser.js.map +1 -0
  7. package/dist/node_modules/jszip/dist/jszip.min.js +3038 -0
  8. package/dist/node_modules/jszip/dist/jszip.min.js.map +1 -0
  9. package/dist/node_modules/pptxgenjs/dist/pptxgen.es.js +2151 -0
  10. package/dist/node_modules/pptxgenjs/dist/pptxgen.es.js.map +1 -0
  11. package/dist/node_modules/write-excel-file/browser/index.js +3 -0
  12. package/dist/node_modules/write-excel-file/modules/export/convertFileContentToUint8ArrayBrowser.js +13 -0
  13. package/dist/node_modules/write-excel-file/modules/export/convertFileContentToUint8ArrayBrowser.js.map +1 -0
  14. package/dist/node_modules/write-excel-file/modules/export/convertFilesContentToUint8Arrays.js +21 -0
  15. package/dist/node_modules/write-excel-file/modules/export/convertFilesContentToUint8Arrays.js.map +1 -0
  16. package/dist/node_modules/write-excel-file/modules/export/downloadBlob.js +11 -0
  17. package/dist/node_modules/write-excel-file/modules/export/downloadBlob.js.map +1 -0
  18. package/dist/node_modules/write-excel-file/modules/export/writeXlsxFileBrowser.js +23 -0
  19. package/dist/node_modules/write-excel-file/modules/export/writeXlsxFileBrowser.js.map +1 -0
  20. package/dist/node_modules/write-excel-file/modules/export/writeXlsxFileUniversal.js +22 -0
  21. package/dist/node_modules/write-excel-file/modules/export/writeXlsxFileUniversal.js.map +1 -0
  22. package/dist/node_modules/write-excel-file/modules/getSheetData/getSheetData.js +18 -0
  23. package/dist/node_modules/write-excel-file/modules/getSheetData/getSheetData.js.map +1 -0
  24. package/dist/node_modules/write-excel-file/modules/xlsx/features/conditionalFormatting.js +131 -0
  25. package/dist/node_modules/write-excel-file/modules/xlsx/features/conditionalFormatting.js.map +1 -0
  26. package/dist/node_modules/write-excel-file/modules/xlsx/features/images.js +188 -0
  27. package/dist/node_modules/write-excel-file/modules/xlsx/features/images.js.map +1 -0
  28. package/dist/node_modules/write-excel-file/modules/xlsx/features/stickyRowsOrColumns.js +52 -0
  29. package/dist/node_modules/write-excel-file/modules/xlsx/features/stickyRowsOrColumns.js.map +1 -0
  30. package/dist/node_modules/write-excel-file/modules/xlsx/files/_Content_Types_.xml.js +18 -0
  31. package/dist/node_modules/write-excel-file/modules/xlsx/files/_Content_Types_.xml.js.map +1 -0
  32. package/dist/node_modules/write-excel-file/modules/xlsx/files/drawing.xml.js +18 -0
  33. package/dist/node_modules/write-excel-file/modules/xlsx/files/drawing.xml.js.map +1 -0
  34. package/dist/node_modules/write-excel-file/modules/xlsx/files/drawing.xml.rels.js +17 -0
  35. package/dist/node_modules/write-excel-file/modules/xlsx/files/drawing.xml.rels.js.map +1 -0
  36. package/dist/node_modules/write-excel-file/modules/xlsx/files/rels.js +11 -0
  37. package/dist/node_modules/write-excel-file/modules/xlsx/files/rels.js.map +1 -0
  38. package/dist/node_modules/write-excel-file/modules/xlsx/files/sharedStrings.xml.js +42 -0
  39. package/dist/node_modules/write-excel-file/modules/xlsx/files/sharedStrings.xml.js.map +1 -0
  40. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/cell.js +102 -0
  41. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/cell.js.map +1 -0
  42. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/column.js +17 -0
  43. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/column.js.map +1 -0
  44. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/columns.js +15 -0
  45. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/columns.js.map +1 -0
  46. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/drawingReference.js +8 -0
  47. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/drawingReference.js.map +1 -0
  48. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/helpers/getCellStyleProperties.js +71 -0
  49. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/helpers/getCellStyleProperties.js.map +1 -0
  50. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/mergedCellsDescription.js +56 -0
  51. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/mergedCellsDescription.js.map +1 -0
  52. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/pageMargins.js +15 -0
  53. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/pageMargins.js.map +1 -0
  54. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/pageSetup.js +13 -0
  55. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/pageSetup.js.map +1 -0
  56. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/processMergedCells.js +44 -0
  57. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/processMergedCells.js.map +1 -0
  58. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/row.js +123 -0
  59. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/row.js.map +1 -0
  60. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/sheet.xml.js +41 -0
  61. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/sheet.xml.js.map +1 -0
  62. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/sheetData.js +11 -0
  63. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/sheetData.js.map +1 -0
  64. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/sheetViews.js +17 -0
  65. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/sheetViews.js.map +1 -0
  66. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml.rels.js +20 -0
  67. package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml.rels.js.map +1 -0
  68. package/dist/node_modules/write-excel-file/modules/xlsx/files/styles.xml.js +77 -0
  69. package/dist/node_modules/write-excel-file/modules/xlsx/files/styles.xml.js.map +1 -0
  70. package/dist/node_modules/write-excel-file/modules/xlsx/files/workbook.xml.js +22 -0
  71. package/dist/node_modules/write-excel-file/modules/xlsx/files/workbook.xml.js.map +1 -0
  72. package/dist/node_modules/write-excel-file/modules/xlsx/files/workbook.xml.rels.js +13 -0
  73. package/dist/node_modules/write-excel-file/modules/xlsx/files/workbook.xml.rels.js.map +1 -0
  74. package/dist/node_modules/write-excel-file/modules/xlsx/generateXlsxFileContents.js +242 -0
  75. package/dist/node_modules/write-excel-file/modules/xlsx/generateXlsxFileContents.js.map +1 -0
  76. package/dist/node_modules/write-excel-file/modules/xlsx/getFeatures.js +29 -0
  77. package/dist/node_modules/write-excel-file/modules/xlsx/getFeatures.js.map +1 -0
  78. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/convertDateToSerialNumber.js +9 -0
  79. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/convertDateToSerialNumber.js.map +1 -0
  80. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/features/getAdditionalContent.js +42 -0
  81. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/features/getAdditionalContent.js.map +1 -0
  82. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/features/getElementXml.js +43 -0
  83. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/features/getElementXml.js.map +1 -0
  84. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/features/getWrittenFiles.js +93 -0
  85. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/features/getWrittenFiles.js.map +1 -0
  86. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/features/transformContent.js +39 -0
  87. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/features/transformContent.js.map +1 -0
  88. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getAlignmentXml.js +17 -0
  89. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getAlignmentXml.js.map +1 -0
  90. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getBorderXml.js +29 -0
  91. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getBorderXml.js.map +1 -0
  92. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getCellAddress.js +14 -0
  93. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getCellAddress.js.map +1 -0
  94. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getFileExtensionForContentType.js +11 -0
  95. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getFileExtensionForContentType.js.map +1 -0
  96. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getFillXml.js +14 -0
  97. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getFillXml.js.map +1 -0
  98. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getFontXml.js +12 -0
  99. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getFontXml.js.map +1 -0
  100. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getOrderOfSiblings.js +24 -0
  101. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getOrderOfSiblings.js.map +1 -0
  102. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getXlsxColorForHexColor.js +9 -0
  103. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getXlsxColorForHexColor.js.map +1 -0
  104. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/hasAlignment.js +9 -0
  105. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/hasAlignment.js.map +1 -0
  106. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/hasBorder.js +9 -0
  107. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/hasBorder.js.map +1 -0
  108. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/hasFill.js +9 -0
  109. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/hasFill.js.map +1 -0
  110. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/hasFont.js +9 -0
  111. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/hasFont.js.map +1 -0
  112. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/isCellObject.js +9 -0
  113. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/isCellObject.js.map +1 -0
  114. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/isObject.js +9 -0
  115. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/isObject.js.map +1 -0
  116. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/orderOfSiblings.js +27 -0
  117. package/dist/node_modules/write-excel-file/modules/xlsx/helpers/orderOfSiblings.js.map +1 -0
  118. package/dist/node_modules/write-excel-file/modules/xlsx/initializeSharedStrings.js +17 -0
  119. package/dist/node_modules/write-excel-file/modules/xlsx/initializeSharedStrings.js.map +1 -0
  120. package/dist/node_modules/write-excel-file/modules/xlsx/initializeSheets.js +74 -0
  121. package/dist/node_modules/write-excel-file/modules/xlsx/initializeSheets.js.map +1 -0
  122. package/dist/node_modules/write-excel-file/modules/xlsx/initializeStyles.js +138 -0
  123. package/dist/node_modules/write-excel-file/modules/xlsx/initializeStyles.js.map +1 -0
  124. package/dist/node_modules/write-excel-file/modules/xlsx/validateSheetData.js +40 -0
  125. package/dist/node_modules/write-excel-file/modules/xlsx/validateSheetData.js.map +1 -0
  126. package/dist/node_modules/write-excel-file/modules/xlsx/validateSheetName.js +11 -0
  127. package/dist/node_modules/write-excel-file/modules/xlsx/validateSheetName.js.map +1 -0
  128. package/dist/node_modules/write-excel-file/modules/xml/appendMarkupInsideElement.js +9 -0
  129. package/dist/node_modules/write-excel-file/modules/xml/appendMarkupInsideElement.js.map +1 -0
  130. package/dist/node_modules/write-excel-file/modules/xml/applyEnclosingElementOffset.js +9 -0
  131. package/dist/node_modules/write-excel-file/modules/xml/applyEnclosingElementOffset.js.map +1 -0
  132. package/dist/node_modules/write-excel-file/modules/xml/escapeXmlSpecialCharacters.js +12 -0
  133. package/dist/node_modules/write-excel-file/modules/xml/escapeXmlSpecialCharacters.js.map +1 -0
  134. package/dist/node_modules/write-excel-file/modules/xml/findElement.js +12 -0
  135. package/dist/node_modules/write-excel-file/modules/xml/findElement.js.map +1 -0
  136. package/dist/node_modules/write-excel-file/modules/xml/findElementInsideElement.js +12 -0
  137. package/dist/node_modules/write-excel-file/modules/xml/findElementInsideElement.js.map +1 -0
  138. package/dist/node_modules/write-excel-file/modules/xml/findElementsNonRecursive_.js +41 -0
  139. package/dist/node_modules/write-excel-file/modules/xml/findElementsNonRecursive_.js.map +1 -0
  140. package/dist/node_modules/write-excel-file/modules/xml/getAttributesString.js +14 -0
  141. package/dist/node_modules/write-excel-file/modules/xml/getAttributesString.js.map +1 -0
  142. package/dist/node_modules/write-excel-file/modules/xml/getChildElements.js +42 -0
  143. package/dist/node_modules/write-excel-file/modules/xml/getChildElements.js.map +1 -0
  144. package/dist/node_modules/write-excel-file/modules/xml/getClosingTagMarkup.js +8 -0
  145. package/dist/node_modules/write-excel-file/modules/xml/getClosingTagMarkup.js.map +1 -0
  146. package/dist/node_modules/write-excel-file/modules/xml/getMarkupInsideElement.js +8 -0
  147. package/dist/node_modules/write-excel-file/modules/xml/getMarkupInsideElement.js.map +1 -0
  148. package/dist/node_modules/write-excel-file/modules/xml/getOpeningTagMarkup.js +9 -0
  149. package/dist/node_modules/write-excel-file/modules/xml/getOpeningTagMarkup.js.map +1 -0
  150. package/dist/node_modules/write-excel-file/modules/xml/getSelfClosingTagMarkup.js +9 -0
  151. package/dist/node_modules/write-excel-file/modules/xml/getSelfClosingTagMarkup.js.map +1 -0
  152. package/dist/node_modules/write-excel-file/modules/xml/insertElementMarkupAccordingToOrderOfSiblings.js +64 -0
  153. package/dist/node_modules/write-excel-file/modules/xml/insertElementMarkupAccordingToOrderOfSiblings.js.map +1 -0
  154. package/dist/node_modules/write-excel-file/modules/xml/prependMarkupInsideElement.js +9 -0
  155. package/dist/node_modules/write-excel-file/modules/xml/prependMarkupInsideElement.js.map +1 -0
  156. package/dist/node_modules/write-excel-file/modules/xml/removeInvalidXmlCharacters.js +9 -0
  157. package/dist/node_modules/write-excel-file/modules/xml/removeInvalidXmlCharacters.js.map +1 -0
  158. package/dist/node_modules/write-excel-file/modules/xml/replaceElement.js +8 -0
  159. package/dist/node_modules/write-excel-file/modules/xml/replaceElement.js.map +1 -0
  160. package/dist/node_modules/write-excel-file/modules/xml/sanitizeAttributeName.js +10 -0
  161. package/dist/node_modules/write-excel-file/modules/xml/sanitizeAttributeName.js.map +1 -0
  162. package/dist/node_modules/write-excel-file/modules/xml/sanitizeAttributeValue.js +11 -0
  163. package/dist/node_modules/write-excel-file/modules/xml/sanitizeAttributeValue.js.map +1 -0
  164. package/dist/node_modules/write-excel-file/modules/xml/sanitizeTextContent.js +11 -0
  165. package/dist/node_modules/write-excel-file/modules/xml/sanitizeTextContent.js.map +1 -0
  166. package/dist/node_modules/write-excel-file/modules/xml/setMarkupInsideElement.js +8 -0
  167. package/dist/node_modules/write-excel-file/modules/xml/setMarkupInsideElement.js.map +1 -0
  168. package/dist/node_modules/write-excel-file/modules/zip/zipToArrayBuffer.js +18 -0
  169. package/dist/node_modules/write-excel-file/modules/zip/zipToArrayBuffer.js.map +1 -0
  170. package/dist/planmagnet/PlanMagnetRoot.d.ts.map +1 -1
  171. package/dist/planmagnet/PlanMagnetRoot.js +160 -147
  172. package/dist/planmagnet/PlanMagnetRoot.js.map +1 -1
  173. package/dist/planmagnet/PlanMagnetRoutes.d.ts.map +1 -1
  174. package/dist/planmagnet/PlanMagnetRoutes.js +126 -106
  175. package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
  176. package/dist/planmagnet/comments/CommentThread.js +36 -36
  177. package/dist/planmagnet/comments/RoadmapComments.js +21 -21
  178. package/dist/planmagnet/controls/AutomationRuleControls.js +24 -24
  179. package/dist/planmagnet/controls/FeatureControls.js +60 -60
  180. package/dist/planmagnet/controls/Pickers.d.ts +10 -0
  181. package/dist/planmagnet/controls/Pickers.d.ts.map +1 -1
  182. package/dist/planmagnet/controls/Pickers.js +75 -27
  183. package/dist/planmagnet/controls/Pickers.js.map +1 -1
  184. package/dist/planmagnet/controls/SyncControls.js +59 -59
  185. package/dist/planmagnet/discussion/WorkItemDiscussionPanel.js +15 -15
  186. package/dist/planmagnet/docs/DocSuggestionsPanel.js +12 -12
  187. package/dist/planmagnet/docs/DocVersionCompare.js +3 -3
  188. package/dist/planmagnet/forecast/DeliveryForecastCard.d.ts +12 -0
  189. package/dist/planmagnet/forecast/DeliveryForecastCard.d.ts.map +1 -0
  190. package/dist/planmagnet/forecast/DeliveryForecastCard.js +208 -0
  191. package/dist/planmagnet/forecast/DeliveryForecastCard.js.map +1 -0
  192. package/dist/planmagnet/forecast/ProjectOutlookCard.d.ts +5 -0
  193. package/dist/planmagnet/forecast/ProjectOutlookCard.d.ts.map +1 -0
  194. package/dist/planmagnet/forecast/ProjectOutlookCard.js +190 -0
  195. package/dist/planmagnet/forecast/ProjectOutlookCard.js.map +1 -0
  196. package/dist/planmagnet/forecast/ProjectRiskSummaryCard.d.ts +5 -0
  197. package/dist/planmagnet/forecast/ProjectRiskSummaryCard.d.ts.map +1 -0
  198. package/dist/planmagnet/forecast/ProjectRiskSummaryCard.js +99 -0
  199. package/dist/planmagnet/forecast/ProjectRiskSummaryCard.js.map +1 -0
  200. package/dist/planmagnet/forecast/ResourceForecastCard.d.ts +8 -0
  201. package/dist/planmagnet/forecast/ResourceForecastCard.d.ts.map +1 -0
  202. package/dist/planmagnet/forecast/ResourceForecastCard.js +185 -0
  203. package/dist/planmagnet/forecast/ResourceForecastCard.js.map +1 -0
  204. package/dist/planmagnet/forecast/riskFlags.d.ts +35 -0
  205. package/dist/planmagnet/forecast/riskFlags.d.ts.map +1 -0
  206. package/dist/planmagnet/forecast/riskFlags.js +37 -0
  207. package/dist/planmagnet/forecast/riskFlags.js.map +1 -0
  208. package/dist/planmagnet/index.d.ts +2 -0
  209. package/dist/planmagnet/index.d.ts.map +1 -1
  210. package/dist/planmagnet/index.js +2 -0
  211. package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.d.ts.map +1 -1
  212. package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.js +216 -182
  213. package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
  214. package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.js +11 -11
  215. package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.js +4 -4
  216. package/dist/planmagnet/pages/DocsDocDetailPagePage.js +163 -163
  217. package/dist/planmagnet/pages/DocsDocDetailPagePage.js.map +1 -1
  218. package/dist/planmagnet/pages/IntegrationsNewSyncPagePage.js +165 -165
  219. package/dist/planmagnet/pages/IntegrationsNewSyncPagePage.js.map +1 -1
  220. package/dist/planmagnet/pages/ProjectsAtRiskPagePage.d.ts +2 -0
  221. package/dist/planmagnet/pages/ProjectsAtRiskPagePage.d.ts.map +1 -0
  222. package/dist/planmagnet/pages/ProjectsAtRiskPagePage.js +234 -0
  223. package/dist/planmagnet/pages/ProjectsAtRiskPagePage.js.map +1 -0
  224. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.d.ts.map +1 -1
  225. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js +206 -182
  226. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js.map +1 -1
  227. package/dist/planmagnet/pages/ReportsCreateReportPagePage.d.ts +6 -0
  228. package/dist/planmagnet/pages/ReportsCreateReportPagePage.d.ts.map +1 -1
  229. package/dist/planmagnet/pages/ReportsCreateReportPagePage.js +5 -177
  230. package/dist/planmagnet/pages/ReportsCreateReportPagePage.js.map +1 -1
  231. package/dist/planmagnet/pages/ReportsEditReportPagePage.d.ts +3 -0
  232. package/dist/planmagnet/pages/ReportsEditReportPagePage.d.ts.map +1 -0
  233. package/dist/planmagnet/pages/ReportsEditReportPagePage.js +15 -0
  234. package/dist/planmagnet/pages/ReportsEditReportPagePage.js.map +1 -0
  235. package/dist/planmagnet/pages/ReportsReportPagePage.d.ts +7 -0
  236. package/dist/planmagnet/pages/ReportsReportPagePage.d.ts.map +1 -0
  237. package/dist/planmagnet/pages/ReportsReportPagePage.js +226 -0
  238. package/dist/planmagnet/pages/ReportsReportPagePage.js.map +1 -0
  239. package/dist/planmagnet/pages/ReportsReportsPagePage.d.ts.map +1 -1
  240. package/dist/planmagnet/pages/ReportsReportsPagePage.js +224 -496
  241. package/dist/planmagnet/pages/ReportsReportsPagePage.js.map +1 -1
  242. package/dist/planmagnet/pages/TeamTeamDetailPagePage.d.ts.map +1 -1
  243. package/dist/planmagnet/pages/TeamTeamDetailPagePage.js +88 -83
  244. package/dist/planmagnet/pages/TeamTeamDetailPagePage.js.map +1 -1
  245. package/dist/planmagnet/pages/analytics/SprintDeliveryCards.d.ts.map +1 -1
  246. package/dist/planmagnet/pages/analytics/SprintDeliveryCards.js +139 -112
  247. package/dist/planmagnet/pages/analytics/SprintDeliveryCards.js.map +1 -1
  248. package/dist/planmagnet/pages/analytics/StatusFlowCard.js +21 -21
  249. package/dist/planmagnet/product/ProductControls.js +91 -91
  250. package/dist/planmagnet/reports/ExportMenu.d.ts +9 -0
  251. package/dist/planmagnet/reports/ExportMenu.d.ts.map +1 -0
  252. package/dist/planmagnet/reports/ExportMenu.js +116 -0
  253. package/dist/planmagnet/reports/ExportMenu.js.map +1 -0
  254. package/dist/planmagnet/reports/PrintReportView.d.ts +24 -0
  255. package/dist/planmagnet/reports/PrintReportView.d.ts.map +1 -0
  256. package/dist/planmagnet/reports/PrintReportView.js +75 -0
  257. package/dist/planmagnet/reports/PrintReportView.js.map +1 -0
  258. package/dist/planmagnet/reports/ReportBuilderCanvas.d.ts +8 -0
  259. package/dist/planmagnet/reports/ReportBuilderCanvas.d.ts.map +1 -0
  260. package/dist/planmagnet/reports/ReportBuilderCanvas.js +261 -0
  261. package/dist/planmagnet/reports/ReportBuilderCanvas.js.map +1 -0
  262. package/dist/planmagnet/reports/ReportBuilderPage.d.ts +5 -0
  263. package/dist/planmagnet/reports/ReportBuilderPage.d.ts.map +1 -0
  264. package/dist/planmagnet/reports/ReportBuilderPage.js +198 -0
  265. package/dist/planmagnet/reports/ReportBuilderPage.js.map +1 -0
  266. package/dist/planmagnet/reports/ReportRunHistory.d.ts +8 -0
  267. package/dist/planmagnet/reports/ReportRunHistory.d.ts.map +1 -0
  268. package/dist/planmagnet/reports/ReportRunHistory.js +63 -0
  269. package/dist/planmagnet/reports/ReportRunHistory.js.map +1 -0
  270. package/dist/planmagnet/reports/ReportWidgetRenderer.d.ts +7 -0
  271. package/dist/planmagnet/reports/ReportWidgetRenderer.d.ts.map +1 -0
  272. package/dist/planmagnet/reports/ReportWidgetRenderer.js +251 -0
  273. package/dist/planmagnet/reports/ReportWidgetRenderer.js.map +1 -0
  274. package/dist/planmagnet/reports/SchedulesPanel.d.ts +4 -0
  275. package/dist/planmagnet/reports/SchedulesPanel.d.ts.map +1 -0
  276. package/dist/planmagnet/reports/SchedulesPanel.js +457 -0
  277. package/dist/planmagnet/reports/SchedulesPanel.js.map +1 -0
  278. package/dist/planmagnet/reports/ShareDialog.d.ts +5 -0
  279. package/dist/planmagnet/reports/ShareDialog.d.ts.map +1 -0
  280. package/dist/planmagnet/reports/ShareDialog.js +234 -0
  281. package/dist/planmagnet/reports/ShareDialog.js.map +1 -0
  282. package/dist/planmagnet/reports/SharedReportPage.d.ts +4 -0
  283. package/dist/planmagnet/reports/SharedReportPage.d.ts.map +1 -0
  284. package/dist/planmagnet/reports/SharedReportPage.js +180 -0
  285. package/dist/planmagnet/reports/SharedReportPage.js.map +1 -0
  286. package/dist/planmagnet/reports/WidgetEditorDialog.d.ts +10 -0
  287. package/dist/planmagnet/reports/WidgetEditorDialog.d.ts.map +1 -0
  288. package/dist/planmagnet/reports/WidgetEditorDialog.js +220 -0
  289. package/dist/planmagnet/reports/WidgetEditorDialog.js.map +1 -0
  290. package/dist/planmagnet/reports/reportExportPptx.d.ts +4 -0
  291. package/dist/planmagnet/reports/reportExportPptx.d.ts.map +1 -0
  292. package/dist/planmagnet/reports/reportExportPptx.js +118 -0
  293. package/dist/planmagnet/reports/reportExportPptx.js.map +1 -0
  294. package/dist/planmagnet/reports/reportExportXlsx.d.ts +4 -0
  295. package/dist/planmagnet/reports/reportExportXlsx.d.ts.map +1 -0
  296. package/dist/planmagnet/reports/reportExportXlsx.js +42 -0
  297. package/dist/planmagnet/reports/reportExportXlsx.js.map +1 -0
  298. package/dist/planmagnet/reports/reportGraphql.d.ts +28 -0
  299. package/dist/planmagnet/reports/reportGraphql.d.ts.map +1 -0
  300. package/dist/planmagnet/reports/reportGraphql.js +360 -0
  301. package/dist/planmagnet/reports/reportGraphql.js.map +1 -0
  302. package/dist/planmagnet/reports/reportModel.d.ts +198 -0
  303. package/dist/planmagnet/reports/reportModel.d.ts.map +1 -0
  304. package/dist/planmagnet/reports/reportModel.js +328 -0
  305. package/dist/planmagnet/reports/reportModel.js.map +1 -0
  306. package/dist/planmagnet/reports/sharedReportRoute.d.ts +15 -0
  307. package/dist/planmagnet/reports/sharedReportRoute.d.ts.map +1 -0
  308. package/dist/planmagnet/reports/sharedReportRoute.js +9 -0
  309. package/dist/planmagnet/reports/sharedReportRoute.js.map +1 -0
  310. package/dist/planmagnet/roadmaps/RoadmapControls.js +60 -60
  311. package/dist/planmagnet/roadmaps/RoadmapNowNextLater.js +30 -30
  312. package/dist/planmagnet/roadmaps/RoadmapReviewPanel.js +21 -21
  313. package/dist/planmagnet/roadmaps/RoadmapVersionsPanel.js +22 -22
  314. package/package.json +6 -4
@@ -1 +1 @@
1
- {"version":3,"file":"ProjectsProjectDetailPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProjectsProjectDetailPagePage.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 { Button, Card, CardContent, CardHeader, CardTitle, Badge } from '@burdenoff/fe-libs/ui';\nimport {\n Bot,\n FolderKanban,\n CheckSquare,\n Users,\n Zap,\n Calendar,\n LayoutTemplate,\n ShieldAlert,\n ShieldCheck,\n Route,\n} from 'lucide-react';\nimport { useEntityId } from '../hooks/useEntityId';\nimport { PersonName } from '../people/People';\nimport { ProjectHeaderActions } from '../controls/ProjectControls';\nimport { NewTemplateFromProjectDialog, NewRiskDialog } from '../create/CreateDialogs';\nimport { workProgress } from '../hooks/useCounts';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { ProjectBudgetsSummary } from '../budgets/ProjectBudgetsSummary';\nimport { ProjectComments } from '../comments/TargetComments';\nimport { ROW_LINK_CLASS, rowLinkProps, detailPath } from '../utils/rowNavigation';\nimport { enumLabel } from '../controls/WorkItemControls';\nimport { useLiveRefresh, combineLiveRefreshModes } from '../hooks/useLiveRefresh';\nimport { LiveStatus } from '../controls/LiveStatus';\nimport { usePresence } from '../hooks/usePresence';\nimport { PresenceAvatars } from '../presence/PresenceAvatars';\n\n/** This page's one query — GET_PROJECT_DETAIL nests the project's own fields plus its sprints and work items, so\n * a change on either (PDM-05 project events, PDM-21 sprint events, PDM-11 work item events, all scoped to this\n * project) means the same re-read. Milestones and risks are also nested here but have no event stream of their\n * own yet — out of scope (PDM-05/11/21 cover project/sprint/work item only). */\nconst PROJECT_DETAIL_QUERIES = ['GetProjectDetail'];\n\nconst GET_PROJECT_DETAIL = gql`\n query GetProjectDetail($id: ID!) {\n planmagnetProject(id: $id) {\n id\n name\n key\n description\n status\n methodology\n ownerId\n startDate\n endDate\n tags\n createdAt\n programId\n program {\n id\n name\n }\n sprints {\n id\n name\n status\n goal\n capacity\n velocity\n startDate\n endDate\n workItems {\n id\n status\n storyPoints\n }\n }\n milestones {\n id\n name\n description\n status\n dueDate\n ownerId\n }\n risks {\n id\n title\n severity\n status\n riskScore\n dueDate\n }\n workItems {\n id\n key\n title\n description\n status\n priority\n storyPoints\n assigneeId\n labels\n createdAt\n sprint {\n id\n name\n status\n team {\n id\n name\n }\n }\n }\n }\n }\n`;\n\nconst statusColor: Record<string, string> = {\n ACTIVE: 'bg-green-100 text-green-800',\n ON_HOLD: 'bg-orange-100 text-orange-800',\n CANCELLED: 'bg-red-100 text-red-800',\n COMPLETED: 'bg-blue-100 text-blue-800',\n PLANNING: 'bg-gray-100 text-gray-800',\n ARCHIVED: 'bg-gray-100 text-gray-800',\n};\n\nconst riskSeverityColor: Record<string, string> = {\n CRITICAL: 'bg-red-100 text-red-800',\n HIGH: 'bg-orange-100 text-orange-800',\n MEDIUM: 'bg-yellow-100 text-yellow-800',\n LOW: 'bg-blue-100 text-blue-800',\n NEGLIGIBLE: 'bg-gray-100 text-gray-800',\n};\nconst OPEN_RISK_STATUSES = new Set(['IDENTIFIED', 'ANALYZING', 'MITIGATING', 'ACCEPTED']);\n\nexport function ProjectsProjectDetailPagePage() {\n const projectId = useEntityId('projectId');\n const navigate = usePlanMagnetNavigate();\n const { workspaceId } = usePlanMagnet();\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_PROJECT_DETAIL, {\n variables: { id: projectId },\n skip: !projectId,\n });\n\n // Live updates (PDM-05/11/21): the project's own fields, its sprints and its work items — see\n // PROJECT_DETAIL_QUERIES above for why one re-read covers all three streams.\n const projectLive = useLiveRefresh({\n kind: 'project',\n projectId,\n queries: PROJECT_DETAIL_QUERIES,\n });\n const sprintLive = useLiveRefresh({\n kind: 'sprint',\n projectId,\n enabled: Boolean(projectId),\n queries: PROJECT_DETAIL_QUERIES,\n });\n const workItemLive = useLiveRefresh({\n kind: 'workItem',\n projectId,\n queries: PROJECT_DETAIL_QUERIES,\n });\n const liveMode = combineLiveRefreshModes(projectLive.mode, sprintLive.mode, workItemLive.mode);\n // CWF-24: who else is looking at this project right now, and who's mid-comment.\n const presence = usePresence('PROJECT', projectId);\n\n if (!projectId)\n return (\n <div className=\"p-6 text-muted-foreground\">No project selected. Open one from the list.</div>\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 <div className=\"animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full\" />\n </div>\n );\n if (error) return <div className=\"p-6 text-red-500\">Error loading project: {error.message}</div>;\n\n const project = data?.planmagnetProject;\n if (!project) return <div className=\"p-6 text-muted-foreground\">Project not found.</div>;\n\n const projectWorkItems = project.workItems ?? [];\n const projectSprints = project.sprints ?? [];\n const projectMilestones = project.milestones ?? [];\n const projectRisks = project.risks ?? [];\n const openRisks = projectRisks.filter((r: { status: string }) =>\n OPEN_RISK_STATUSES.has(r.status)\n );\n // Highest score first, so the register's top exposure is what a project owner sees without scrolling.\n const topRisks = [...openRisks]\n .sort((a: { riskScore: number }, b: { riskScore: number }) => b.riskScore - a.riskScore)\n .slice(0, 3);\n const activeSprint = projectSprints.find((s: { status: string }) => s.status === 'ACTIVE');\n // Velocity exists only for a COMPLETED sprint (BOFF-7944: this tile read the running sprint's velocity, which is\n // never set, so it always showed 0). Show the latest completed sprint's instead.\n const lastCompleted = projectSprints\n .filter(\n (s: { status: string; velocity: number | null }) =>\n s.status === 'COMPLETED' && s.velocity != null\n )\n .sort((a: { endDate: string | null }, b: { endDate: string | null }) =>\n (b.endDate ?? '').localeCompare(a.endDate ?? '')\n )[0];\n // Done over everything not cancelled (BOFF-7989), labelled as tasks — it sat under \"Duration\" as if it were time.\n // Weighted by storyPoints when the project has any (BOFF-7989 follow-up): mapping to { status } only dropped\n // storyPoints here, so this always fell back to a count-based percentage even though GET_PROJECT_DETAIL selects\n // storyPoints and workProgress already weights by it.\n const tasksDonePct = workProgress(\n projectWorkItems.map((wi: { status: string; storyPoints: number | null }) => ({\n status: wi.status,\n storyPoints: wi.storyPoints,\n }))\n );\n // The Work Items tile counts the same way as tasksDonePct: done over everything not cancelled (BOFF-7989).\n // project.workItems is every non-deleted item (no page cap), so these are exact.\n const liveWorkItems = projectWorkItems.filter(\n (wi: { status: string }) => wi.status !== 'CANCELLED'\n );\n const doneWorkItems = liveWorkItems.filter(\n (wi: { status: string }) => wi.status === 'DONE'\n ).length;\n // Newest first: the list is ordered oldest-first, so slice(0, 5) showed the five OLDEST items (BOFF-7993).\n const latestWorkItems = [...projectWorkItems]\n .sort((a: { createdAt: string }, b: { createdAt: string }) =>\n b.createdAt.localeCompare(a.createdAt)\n )\n .slice(0, 5);\n\n // BOFF-8044: this project's own sprints (project.sprints) structurally exclude team sprints — a\n // team sprint has no projectId. A work item from this project can still sit inside ANOTHER team's\n // sprint, invisibly, since nothing else on this page surfaces that. Grouped client-side over data\n // the Sprint.team field resolver already serves — no new backend query.\n const teamSprintGroups = Object.values(\n projectWorkItems.reduce(\n (\n acc: Record<\n string,\n {\n sprint: {\n id: string;\n name: string;\n status: string;\n team: { id: string; name: string };\n };\n items: { id: string; key: string; title: string }[];\n }\n >,\n wi: {\n id: string;\n key: string;\n title: string;\n sprint: {\n id: string;\n name: string;\n status: string;\n team: { id: string; name: string } | null;\n } | null;\n }\n ) => {\n if (!wi.sprint?.team) return acc;\n const entry = acc[wi.sprint.id] ?? {\n sprint: { ...wi.sprint, team: wi.sprint.team },\n items: [],\n };\n entry.items.push({ id: wi.id, key: wi.key, title: wi.title });\n acc[wi.sprint.id] = entry;\n return acc;\n },\n {}\n )\n );\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 <FolderKanban className=\"h-5 w-5 text-primary\" />\n <h1 className=\"text-2xl font-semibold\">{project.name}</h1>\n <span\n className={`text-xs px-2 py-0.5 rounded-full capitalize ${statusColor[project.status] ?? 'bg-gray-100'}`}\n >\n {project.status.toLowerCase().replace('_', ' ')}\n </span>\n <LiveStatus mode={liveMode} />\n </div>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {project.description ?? 'No description'}\n </p>\n <PresenceAvatars others={presence.others} />\n </div>\n <div className=\"flex flex-col items-end gap-2\">\n {/* Status, Edit and Delete (BOFF-7940): a project could never leave PLANNING from the UI. */}\n <ProjectHeaderActions\n projectId={project.id}\n name={project.name}\n status={project.status}\n />\n <div className=\"flex items-center gap-2\">\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => navigate('/automation/automation-rules-page')}\n data-testid=\"project-automation-rules\"\n >\n <Bot className=\"mr-1 h-4 w-4\" />\n Automation rules\n </Button>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() =>\n navigate(`/projects/quality-gates-page?projectId=${encodeURIComponent(project.id)}`)\n }\n data-testid=\"project-quality-gates\"\n >\n <ShieldCheck className=\"mr-1 h-4 w-4\" />\n Quality gates\n </Button>\n <NewTemplateFromProjectDialog\n projectId={project.id}\n projectName={project.name}\n onCreated={(id) => navigate(detailPath('/templates/edit-template-page', id))}\n trigger={\n <Button size=\"sm\" variant=\"outline\" data-testid=\"project-save-as-template\">\n <LayoutTemplate className=\"mr-1 h-4 w-4\" />\n Save as template\n </Button>\n }\n />\n </div>\n <Badge variant=\"outline\" className=\"capitalize\">\n {project.methodology.toLowerCase()}\n </Badge>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => navigate(detailPath('/projects/critical-path-page', project.id))}\n >\n <Route className=\"mr-1 h-4 w-4\" />\n Critical path\n </Button>\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 <CheckSquare className=\"h-4 w-4\" />\n Work Items\n </div>\n <p className=\"text-xl font-bold mt-1\">\n {doneWorkItems}/{liveWorkItems.length}\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 <Zap className=\"h-4 w-4\" />\n Sprints\n </div>\n <p className=\"text-xl font-bold mt-1\">{projectSprints.length}</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 Milestones\n </div>\n <p className=\"text-xl font-bold mt-1\">{projectMilestones.length}</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 <Users className=\"h-4 w-4\" />\n Owner\n </div>\n <p className=\"text-sm font-bold mt-1 truncate\">\n <PersonName id={project.ownerId} />\n </p>\n </CardContent>\n </Card>\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 <Card>\n <CardHeader>\n <CardTitle>Timeline</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"flex justify-between text-sm mb-2\">\n <span className=\"text-muted-foreground\">Tasks done</span>\n <span className=\"font-medium\">\n {tasksDonePct === null ? 'No open tasks' : `${tasksDonePct}%`}\n </span>\n </div>\n <div className=\"w-full h-4 rounded-full bg-muted overflow-hidden\">\n <div\n className=\"h-full bg-primary rounded-full\"\n style={{ width: `${tasksDonePct ?? 0}%` }}\n />\n </div>\n <div className=\"flex justify-between text-xs text-muted-foreground mt-2\">\n <span>\n {project.startDate ? new Date(project.startDate).toLocaleDateString() : 'Not set'}\n </span>\n <span>\n {project.endDate ? new Date(project.endDate).toLocaleDateString() : 'Not set'}\n </span>\n </div>\n </CardContent>\n </Card>\n\n {activeSprint && (\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Zap className=\"h-4 w-4 text-primary\" />\n Active Sprint\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <div className=\"flex justify-between\">\n <span className=\"font-medium\">{activeSprint.name}</span>\n <Badge>Active</Badge>\n </div>\n {activeSprint.goal && (\n <p className=\"text-sm text-muted-foreground\">{activeSprint.goal}</p>\n )}\n <div className=\"grid grid-cols-3 gap-4 text-center\">\n <div>\n <p className=\"text-lg font-semibold\">\n {activeSprint.workItems\n ?.filter((wi: { status: string }) => wi.status === 'DONE')\n .reduce(\n (s: number, wi: { storyPoints: number | null }) =>\n s + (wi.storyPoints ?? 0),\n 0\n )}\n /\n {activeSprint.workItems?.reduce(\n (s: number, wi: { storyPoints: number | null }) =>\n s + (wi.storyPoints ?? 0),\n 0\n ) ?? 0}\n </p>\n <p className=\"text-xs text-muted-foreground\">Points</p>\n </div>\n <div>\n <p className=\"text-lg font-semibold\">\n {activeSprint.workItems?.filter(\n (wi: { status: string }) => wi.status === 'DONE'\n ).length ?? 0}\n /{activeSprint.workItems?.length ?? 0}\n </p>\n <p className=\"text-xs text-muted-foreground\">Tasks</p>\n </div>\n <div>\n <p className=\"text-lg font-semibold\">\n {lastCompleted ? `${lastCompleted.velocity} pts` : '—'}\n </p>\n <p className=\"text-xs text-muted-foreground\">Velocity of the last sprint</p>\n </div>\n </div>\n </CardContent>\n </Card>\n )}\n\n <Card>\n <CardHeader>\n <CardTitle>\n Work items ({projectWorkItems.length})\n {projectWorkItems.length > 5 ? ' · latest 5' : ''}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n {latestWorkItems.map(\n (task: {\n id: string;\n key: string;\n description: string | null;\n status: string;\n storyPoints: number | null;\n labels: string[];\n }) => (\n <div\n key={task.id}\n {...rowLinkProps(\n () =>\n navigate(`/tasks/task-detail-page?taskId=${encodeURIComponent(task.id)}`),\n task.key\n )}\n className={`flex items-center justify-between border rounded-md p-2.5 ${ROW_LINK_CLASS}`}\n >\n <div>\n <p className=\"text-sm font-medium\">\n {task.key} <span className=\"font-normal\">{task.title}</span>\n </p>\n <div className=\"flex gap-1 mt-1\">\n {task.labels.map((l: string) => (\n <span key={l} className=\"text-[10px] px-1.5 py-0.5 rounded bg-muted\">\n {l}\n </span>\n ))}\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs text-muted-foreground\">\n {task.storyPoints ?? 0} pts\n </span>\n <Badge variant=\"secondary\" className=\"capitalize text-xs\">\n {task.status.toLowerCase().replace('_', ' ')}\n </Badge>\n </div>\n </div>\n )\n )}\n {projectWorkItems.length === 0 && (\n <p className=\"text-sm text-muted-foreground text-center py-4\">No work items yet.</p>\n )}\n </CardContent>\n </Card>\n\n <ProjectComments projectId={project.id} presence={presence} />\n </div>\n\n <div className=\"space-y-6\">\n <ProjectBudgetsSummary workspaceId={workspaceId} projectId={project.id} />\n <Card>\n <CardHeader>\n <CardTitle>Milestones ({projectMilestones.length})</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {projectMilestones.map(\n (ms: { id: string; name: string; status: string; dueDate: string | null }) => (\n <div key={ms.id} className=\"border-b pb-2 last:border-0\">\n <div className=\"flex justify-between\">\n <span className=\"text-sm font-medium\">{ms.name}</span>\n <Badge variant=\"outline\" className=\"text-xs capitalize\">\n {ms.status.toLowerCase().replace('_', ' ')}\n </Badge>\n </div>\n <div className=\"flex items-center gap-1 text-xs text-muted-foreground mt-1\">\n <Calendar className=\"h-3 w-3\" />\n {ms.dueDate ? new Date(ms.dueDate).toLocaleDateString() : 'No due date'}\n </div>\n </div>\n )\n )}\n {projectMilestones.length === 0 && (\n <p className=\"text-sm text-muted-foreground text-center py-2\">No milestones.</p>\n )}\n </CardContent>\n </Card>\n\n {teamSprintGroups.length > 0 && (\n <Card data-testid=\"team-sprint-work\">\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Users className=\"h-4 w-4\" />\n Team sprint work\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {/* BOFF-8044: an item from this project sitting in ANOTHER team's sprint — this\n project's own sprints (above) structurally exclude team sprints. */}\n {teamSprintGroups.map((group) => (\n <div key={group.sprint.id} className=\"border-b pb-2 last:border-0\">\n <button\n type=\"button\"\n className=\"text-sm font-medium hover:underline text-left\"\n onClick={() =>\n navigate(detailPath('/projects/planning-detail-page', group.sprint.id))\n }\n >\n {group.sprint.name}\n </button>\n <button\n type=\"button\"\n className=\"block text-xs text-muted-foreground hover:underline\"\n onClick={() =>\n navigate(detailPath('/team/team-detail-page', group.sprint.team.id))\n }\n >\n {group.items.length} item{group.items.length === 1 ? '' : 's'} &middot; team{' '}\n {group.sprint.team.name}\n </button>\n </div>\n ))}\n </CardContent>\n </Card>\n )}\n\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0\">\n <CardTitle className=\"flex items-center gap-2\">\n <ShieldAlert className=\"h-4 w-4 text-primary\" />\n Risks ({openRisks.length} open)\n </CardTitle>\n <NewRiskDialog\n projectId={project.id}\n onCreated={(id) => navigate(detailPath('/risks/risk-detail-page', id))}\n />\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {topRisks.map(\n (risk: {\n id: string;\n title: string;\n severity: string;\n status: string;\n riskScore: number;\n }) => (\n <div\n key={risk.id}\n {...rowLinkProps(\n () => navigate(detailPath('/risks/risk-detail-page', risk.id)),\n risk.title\n )}\n className={`border-b pb-2 last:border-0 ${ROW_LINK_CLASS}`}\n >\n <div className=\"flex justify-between gap-2\">\n <span className=\"text-sm font-medium truncate\">{risk.title}</span>\n <span\n className={`text-xs px-2 py-0.5 rounded-full shrink-0 ${riskSeverityColor[risk.severity] ?? 'bg-gray-100'}`}\n >\n {enumLabel(risk.severity)}\n </span>\n </div>\n <div className=\"text-xs text-muted-foreground mt-1\">\n Score {risk.riskScore} · {enumLabel(risk.status)}\n </div>\n </div>\n )\n )}\n {openRisks.length === 0 && (\n <p className=\"text-sm text-muted-foreground text-center py-2\">No open risks.</p>\n )}\n <button\n type=\"button\"\n className=\"text-xs text-primary hover:underline\"\n onClick={() =>\n navigate(`/risks/risk-register-page?projectId=${encodeURIComponent(project.id)}`)\n }\n >\n View risk register ({projectRisks.length}) →\n </button>\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\">Owner</span>\n <span>\n <PersonName id={project.ownerId} />\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Key</span>\n <span className=\"font-mono\">{project.key}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Methodology</span>\n <span className=\"capitalize\">{project.methodology.toLowerCase()}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Program</span>\n {project.program ? (\n <button\n type=\"button\"\n className=\"text-primary hover:underline underline-offset-2\"\n onClick={() =>\n navigate(detailPath('/products/program-detail-page', project.program.id))\n }\n >\n {project.program.name}\n </button>\n ) : (\n <span className=\"text-muted-foreground\">No program</span>\n )}\n </div>\n {project.tags.length > 0 && (\n <div className=\"flex justify-between items-start\">\n <span className=\"text-muted-foreground\">Tags</span>\n <div className=\"flex gap-1 flex-wrap justify-end\">\n {project.tags.map((tag: string) => (\n <Badge key={tag} variant=\"outline\" className=\"text-xs\">\n {tag}\n </Badge>\n ))}\n </div>\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ProjectsProjectDetailPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProjectsProjectDetailPagePage.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 { Button, Card, CardContent, CardHeader, CardTitle, Badge } from '@burdenoff/fe-libs/ui';\nimport {\n Bot,\n FolderKanban,\n CheckSquare,\n Users,\n Zap,\n Calendar,\n LayoutTemplate,\n ShieldAlert,\n ShieldCheck,\n Route,\n} from 'lucide-react';\nimport { useEntityId } from '../hooks/useEntityId';\nimport { PersonName } from '../people/People';\nimport { ProjectHeaderActions } from '../controls/ProjectControls';\nimport { NewTemplateFromProjectDialog, NewRiskDialog } from '../create/CreateDialogs';\nimport { workProgress } from '../hooks/useCounts';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { ProjectBudgetsSummary } from '../budgets/ProjectBudgetsSummary';\nimport { ProjectComments } from '../comments/TargetComments';\nimport { DeliveryForecastCard } from '../forecast/DeliveryForecastCard';\nimport { ProjectOutlookCard } from '../forecast/ProjectOutlookCard';\nimport { ResourceForecastCard } from '../forecast/ResourceForecastCard';\nimport { ProjectRiskSummaryCard } from '../forecast/ProjectRiskSummaryCard';\nimport { ROW_LINK_CLASS, rowLinkProps, detailPath } from '../utils/rowNavigation';\nimport { enumLabel } from '../controls/WorkItemControls';\nimport { useLiveRefresh, combineLiveRefreshModes } from '../hooks/useLiveRefresh';\nimport { LiveStatus } from '../controls/LiveStatus';\nimport { usePresence } from '../hooks/usePresence';\nimport { PresenceAvatars } from '../presence/PresenceAvatars';\n\n/** This page's one query — GET_PROJECT_DETAIL nests the project's own fields plus its sprints and work items, so\n * a change on either (PDM-05 project events, PDM-21 sprint events, PDM-11 work item events, all scoped to this\n * project) means the same re-read. Milestones and risks are also nested here but have no event stream of their\n * own yet — out of scope (PDM-05/11/21 cover project/sprint/work item only). */\nconst PROJECT_DETAIL_QUERIES = ['GetProjectDetail'];\n\nconst GET_PROJECT_DETAIL = gql`\n query GetProjectDetail($id: ID!) {\n planmagnetProject(id: $id) {\n id\n name\n key\n description\n status\n methodology\n ownerId\n startDate\n endDate\n tags\n createdAt\n programId\n program {\n id\n name\n }\n sprints {\n id\n name\n status\n goal\n capacity\n velocity\n startDate\n endDate\n workItems {\n id\n status\n storyPoints\n }\n }\n milestones {\n id\n name\n description\n status\n dueDate\n ownerId\n }\n risks {\n id\n title\n severity\n status\n riskScore\n dueDate\n }\n workItems {\n id\n key\n title\n description\n status\n priority\n storyPoints\n assigneeId\n labels\n createdAt\n sprint {\n id\n name\n status\n team {\n id\n name\n }\n }\n }\n }\n }\n`;\n\nconst statusColor: Record<string, string> = {\n ACTIVE: 'bg-green-100 text-green-800',\n ON_HOLD: 'bg-orange-100 text-orange-800',\n CANCELLED: 'bg-red-100 text-red-800',\n COMPLETED: 'bg-blue-100 text-blue-800',\n PLANNING: 'bg-gray-100 text-gray-800',\n ARCHIVED: 'bg-gray-100 text-gray-800',\n};\n\nconst riskSeverityColor: Record<string, string> = {\n CRITICAL: 'bg-red-100 text-red-800',\n HIGH: 'bg-orange-100 text-orange-800',\n MEDIUM: 'bg-yellow-100 text-yellow-800',\n LOW: 'bg-blue-100 text-blue-800',\n NEGLIGIBLE: 'bg-gray-100 text-gray-800',\n};\nconst OPEN_RISK_STATUSES = new Set(['IDENTIFIED', 'ANALYZING', 'MITIGATING', 'ACCEPTED']);\n\nexport function ProjectsProjectDetailPagePage() {\n const projectId = useEntityId('projectId');\n const navigate = usePlanMagnetNavigate();\n const { workspaceId } = usePlanMagnet();\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_PROJECT_DETAIL, {\n variables: { id: projectId },\n skip: !projectId,\n });\n\n // Live updates (PDM-05/11/21): the project's own fields, its sprints and its work items — see\n // PROJECT_DETAIL_QUERIES above for why one re-read covers all three streams.\n const projectLive = useLiveRefresh({\n kind: 'project',\n projectId,\n queries: PROJECT_DETAIL_QUERIES,\n });\n const sprintLive = useLiveRefresh({\n kind: 'sprint',\n projectId,\n enabled: Boolean(projectId),\n queries: PROJECT_DETAIL_QUERIES,\n });\n const workItemLive = useLiveRefresh({\n kind: 'workItem',\n projectId,\n queries: PROJECT_DETAIL_QUERIES,\n });\n const liveMode = combineLiveRefreshModes(projectLive.mode, sprintLive.mode, workItemLive.mode);\n // CWF-24: who else is looking at this project right now, and who's mid-comment.\n const presence = usePresence('PROJECT', projectId);\n\n if (!projectId)\n return (\n <div className=\"p-6 text-muted-foreground\">No project selected. Open one from the list.</div>\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 <div className=\"animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full\" />\n </div>\n );\n if (error) return <div className=\"p-6 text-red-500\">Error loading project: {error.message}</div>;\n\n const project = data?.planmagnetProject;\n if (!project) return <div className=\"p-6 text-muted-foreground\">Project not found.</div>;\n\n const projectWorkItems = project.workItems ?? [];\n const projectSprints = project.sprints ?? [];\n const projectMilestones = project.milestones ?? [];\n const projectRisks = project.risks ?? [];\n const openRisks = projectRisks.filter((r: { status: string }) =>\n OPEN_RISK_STATUSES.has(r.status)\n );\n // Highest score first, so the register's top exposure is what a project owner sees without scrolling.\n const topRisks = [...openRisks]\n .sort((a: { riskScore: number }, b: { riskScore: number }) => b.riskScore - a.riskScore)\n .slice(0, 3);\n const activeSprint = projectSprints.find((s: { status: string }) => s.status === 'ACTIVE');\n // Velocity exists only for a COMPLETED sprint (BOFF-7944: this tile read the running sprint's velocity, which is\n // never set, so it always showed 0). Show the latest completed sprint's instead.\n const lastCompleted = projectSprints\n .filter(\n (s: { status: string; velocity: number | null }) =>\n s.status === 'COMPLETED' && s.velocity != null\n )\n .sort((a: { endDate: string | null }, b: { endDate: string | null }) =>\n (b.endDate ?? '').localeCompare(a.endDate ?? '')\n )[0];\n // Done over everything not cancelled (BOFF-7989), labelled as tasks — it sat under \"Duration\" as if it were time.\n // Weighted by storyPoints when the project has any (BOFF-7989 follow-up): mapping to { status } only dropped\n // storyPoints here, so this always fell back to a count-based percentage even though GET_PROJECT_DETAIL selects\n // storyPoints and workProgress already weights by it.\n const tasksDonePct = workProgress(\n projectWorkItems.map((wi: { status: string; storyPoints: number | null }) => ({\n status: wi.status,\n storyPoints: wi.storyPoints,\n }))\n );\n // The Work Items tile counts the same way as tasksDonePct: done over everything not cancelled (BOFF-7989).\n // project.workItems is every non-deleted item (no page cap), so these are exact.\n const liveWorkItems = projectWorkItems.filter(\n (wi: { status: string }) => wi.status !== 'CANCELLED'\n );\n const doneWorkItems = liveWorkItems.filter(\n (wi: { status: string }) => wi.status === 'DONE'\n ).length;\n // Newest first: the list is ordered oldest-first, so slice(0, 5) showed the five OLDEST items (BOFF-7993).\n const latestWorkItems = [...projectWorkItems]\n .sort((a: { createdAt: string }, b: { createdAt: string }) =>\n b.createdAt.localeCompare(a.createdAt)\n )\n .slice(0, 5);\n\n // BOFF-8044: this project's own sprints (project.sprints) structurally exclude team sprints — a\n // team sprint has no projectId. A work item from this project can still sit inside ANOTHER team's\n // sprint, invisibly, since nothing else on this page surfaces that. Grouped client-side over data\n // the Sprint.team field resolver already serves — no new backend query.\n const teamSprintGroups = Object.values(\n projectWorkItems.reduce(\n (\n acc: Record<\n string,\n {\n sprint: {\n id: string;\n name: string;\n status: string;\n team: { id: string; name: string };\n };\n items: { id: string; key: string; title: string }[];\n }\n >,\n wi: {\n id: string;\n key: string;\n title: string;\n sprint: {\n id: string;\n name: string;\n status: string;\n team: { id: string; name: string } | null;\n } | null;\n }\n ) => {\n if (!wi.sprint?.team) return acc;\n const entry = acc[wi.sprint.id] ?? {\n sprint: { ...wi.sprint, team: wi.sprint.team },\n items: [],\n };\n entry.items.push({ id: wi.id, key: wi.key, title: wi.title });\n acc[wi.sprint.id] = entry;\n return acc;\n },\n {}\n )\n );\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 <FolderKanban className=\"h-5 w-5 text-primary\" />\n <h1 className=\"text-2xl font-semibold\">{project.name}</h1>\n <span\n className={`text-xs px-2 py-0.5 rounded-full capitalize ${statusColor[project.status] ?? 'bg-gray-100'}`}\n >\n {project.status.toLowerCase().replace('_', ' ')}\n </span>\n <LiveStatus mode={liveMode} />\n </div>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {project.description ?? 'No description'}\n </p>\n <PresenceAvatars others={presence.others} />\n </div>\n <div className=\"flex flex-col items-end gap-2\">\n {/* Status, Edit and Delete (BOFF-7940): a project could never leave PLANNING from the UI. */}\n <ProjectHeaderActions\n projectId={project.id}\n name={project.name}\n status={project.status}\n />\n <div className=\"flex items-center gap-2\">\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => navigate('/automation/automation-rules-page')}\n data-testid=\"project-automation-rules\"\n >\n <Bot className=\"mr-1 h-4 w-4\" />\n Automation rules\n </Button>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() =>\n navigate(`/projects/quality-gates-page?projectId=${encodeURIComponent(project.id)}`)\n }\n data-testid=\"project-quality-gates\"\n >\n <ShieldCheck className=\"mr-1 h-4 w-4\" />\n Quality gates\n </Button>\n <NewTemplateFromProjectDialog\n projectId={project.id}\n projectName={project.name}\n onCreated={(id) => navigate(detailPath('/templates/edit-template-page', id))}\n trigger={\n <Button size=\"sm\" variant=\"outline\" data-testid=\"project-save-as-template\">\n <LayoutTemplate className=\"mr-1 h-4 w-4\" />\n Save as template\n </Button>\n }\n />\n </div>\n <Badge variant=\"outline\" className=\"capitalize\">\n {project.methodology.toLowerCase()}\n </Badge>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => navigate(detailPath('/projects/critical-path-page', project.id))}\n >\n <Route className=\"mr-1 h-4 w-4\" />\n Critical path\n </Button>\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 <CheckSquare className=\"h-4 w-4\" />\n Work Items\n </div>\n <p className=\"text-xl font-bold mt-1\">\n {doneWorkItems}/{liveWorkItems.length}\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 <Zap className=\"h-4 w-4\" />\n Sprints\n </div>\n <p className=\"text-xl font-bold mt-1\">{projectSprints.length}</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 Milestones\n </div>\n <p className=\"text-xl font-bold mt-1\">{projectMilestones.length}</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 <Users className=\"h-4 w-4\" />\n Owner\n </div>\n <p className=\"text-sm font-bold mt-1 truncate\">\n <PersonName id={project.ownerId} />\n </p>\n </CardContent>\n </Card>\n </div>\n\n {/* ANR-02 / ANR-10: statistical delivery forecast (Monte Carlo) and the rule-based/heuristic\n outlook built on top of it — both project-scoped, both clearly labelled as not-AI. */}\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\n <DeliveryForecastCard\n workspaceId={workspaceId}\n projectId={project.id}\n sprintId={activeSprint?.id}\n sprintName={activeSprint?.name}\n />\n <ProjectOutlookCard workspaceId={workspaceId} projectId={project.id} />\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 <Card>\n <CardHeader>\n <CardTitle>Timeline</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"flex justify-between text-sm mb-2\">\n <span className=\"text-muted-foreground\">Tasks done</span>\n <span className=\"font-medium\">\n {tasksDonePct === null ? 'No open tasks' : `${tasksDonePct}%`}\n </span>\n </div>\n <div className=\"w-full h-4 rounded-full bg-muted overflow-hidden\">\n <div\n className=\"h-full bg-primary rounded-full\"\n style={{ width: `${tasksDonePct ?? 0}%` }}\n />\n </div>\n <div className=\"flex justify-between text-xs text-muted-foreground mt-2\">\n <span>\n {project.startDate ? new Date(project.startDate).toLocaleDateString() : 'Not set'}\n </span>\n <span>\n {project.endDate ? new Date(project.endDate).toLocaleDateString() : 'Not set'}\n </span>\n </div>\n </CardContent>\n </Card>\n\n {activeSprint && (\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Zap className=\"h-4 w-4 text-primary\" />\n Active Sprint\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <div className=\"flex justify-between\">\n <span className=\"font-medium\">{activeSprint.name}</span>\n <Badge>Active</Badge>\n </div>\n {activeSprint.goal && (\n <p className=\"text-sm text-muted-foreground\">{activeSprint.goal}</p>\n )}\n <div className=\"grid grid-cols-3 gap-4 text-center\">\n <div>\n <p className=\"text-lg font-semibold\">\n {activeSprint.workItems\n ?.filter((wi: { status: string }) => wi.status === 'DONE')\n .reduce(\n (s: number, wi: { storyPoints: number | null }) =>\n s + (wi.storyPoints ?? 0),\n 0\n )}\n /\n {activeSprint.workItems?.reduce(\n (s: number, wi: { storyPoints: number | null }) =>\n s + (wi.storyPoints ?? 0),\n 0\n ) ?? 0}\n </p>\n <p className=\"text-xs text-muted-foreground\">Points</p>\n </div>\n <div>\n <p className=\"text-lg font-semibold\">\n {activeSprint.workItems?.filter(\n (wi: { status: string }) => wi.status === 'DONE'\n ).length ?? 0}\n /{activeSprint.workItems?.length ?? 0}\n </p>\n <p className=\"text-xs text-muted-foreground\">Tasks</p>\n </div>\n <div>\n <p className=\"text-lg font-semibold\">\n {lastCompleted ? `${lastCompleted.velocity} pts` : '—'}\n </p>\n <p className=\"text-xs text-muted-foreground\">Velocity of the last sprint</p>\n </div>\n </div>\n </CardContent>\n </Card>\n )}\n\n <Card>\n <CardHeader>\n <CardTitle>\n Work items ({projectWorkItems.length})\n {projectWorkItems.length > 5 ? ' · latest 5' : ''}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n {latestWorkItems.map(\n (task: {\n id: string;\n key: string;\n description: string | null;\n status: string;\n storyPoints: number | null;\n labels: string[];\n }) => (\n <div\n key={task.id}\n {...rowLinkProps(\n () =>\n navigate(`/tasks/task-detail-page?taskId=${encodeURIComponent(task.id)}`),\n task.key\n )}\n className={`flex items-center justify-between border rounded-md p-2.5 ${ROW_LINK_CLASS}`}\n >\n <div>\n <p className=\"text-sm font-medium\">\n {task.key} <span className=\"font-normal\">{task.title}</span>\n </p>\n <div className=\"flex gap-1 mt-1\">\n {task.labels.map((l: string) => (\n <span key={l} className=\"text-[10px] px-1.5 py-0.5 rounded bg-muted\">\n {l}\n </span>\n ))}\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs text-muted-foreground\">\n {task.storyPoints ?? 0} pts\n </span>\n <Badge variant=\"secondary\" className=\"capitalize text-xs\">\n {task.status.toLowerCase().replace('_', ' ')}\n </Badge>\n </div>\n </div>\n )\n )}\n {projectWorkItems.length === 0 && (\n <p className=\"text-sm text-muted-foreground text-center py-4\">No work items yet.</p>\n )}\n </CardContent>\n </Card>\n\n <ProjectComments projectId={project.id} presence={presence} />\n </div>\n\n <div className=\"space-y-6\">\n <ProjectBudgetsSummary workspaceId={workspaceId} projectId={project.id} />\n {/* ANR-11: capacity vs. this project's own open backlog. */}\n <ResourceForecastCard workspaceId={workspaceId} projectId={project.id} />\n {/* AI-10: rule-based at-risk flags, with a link through to the full list. */}\n <ProjectRiskSummaryCard workspaceId={workspaceId} projectId={project.id} />\n <Card>\n <CardHeader>\n <CardTitle>Milestones ({projectMilestones.length})</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {projectMilestones.map(\n (ms: { id: string; name: string; status: string; dueDate: string | null }) => (\n <div key={ms.id} className=\"border-b pb-2 last:border-0\">\n <div className=\"flex justify-between\">\n <span className=\"text-sm font-medium\">{ms.name}</span>\n <Badge variant=\"outline\" className=\"text-xs capitalize\">\n {ms.status.toLowerCase().replace('_', ' ')}\n </Badge>\n </div>\n <div className=\"flex items-center gap-1 text-xs text-muted-foreground mt-1\">\n <Calendar className=\"h-3 w-3\" />\n {ms.dueDate ? new Date(ms.dueDate).toLocaleDateString() : 'No due date'}\n </div>\n </div>\n )\n )}\n {projectMilestones.length === 0 && (\n <p className=\"text-sm text-muted-foreground text-center py-2\">No milestones.</p>\n )}\n </CardContent>\n </Card>\n\n {teamSprintGroups.length > 0 && (\n <Card data-testid=\"team-sprint-work\">\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Users className=\"h-4 w-4\" />\n Team sprint work\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {/* BOFF-8044: an item from this project sitting in ANOTHER team's sprint — this\n project's own sprints (above) structurally exclude team sprints. */}\n {teamSprintGroups.map((group) => (\n <div key={group.sprint.id} className=\"border-b pb-2 last:border-0\">\n <button\n type=\"button\"\n className=\"text-sm font-medium hover:underline text-left\"\n onClick={() =>\n navigate(detailPath('/projects/planning-detail-page', group.sprint.id))\n }\n >\n {group.sprint.name}\n </button>\n <button\n type=\"button\"\n className=\"block text-xs text-muted-foreground hover:underline\"\n onClick={() =>\n navigate(detailPath('/team/team-detail-page', group.sprint.team.id))\n }\n >\n {group.items.length} item{group.items.length === 1 ? '' : 's'} &middot; team{' '}\n {group.sprint.team.name}\n </button>\n </div>\n ))}\n </CardContent>\n </Card>\n )}\n\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0\">\n <CardTitle className=\"flex items-center gap-2\">\n <ShieldAlert className=\"h-4 w-4 text-primary\" />\n Risks ({openRisks.length} open)\n </CardTitle>\n <NewRiskDialog\n projectId={project.id}\n onCreated={(id) => navigate(detailPath('/risks/risk-detail-page', id))}\n />\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {topRisks.map(\n (risk: {\n id: string;\n title: string;\n severity: string;\n status: string;\n riskScore: number;\n }) => (\n <div\n key={risk.id}\n {...rowLinkProps(\n () => navigate(detailPath('/risks/risk-detail-page', risk.id)),\n risk.title\n )}\n className={`border-b pb-2 last:border-0 ${ROW_LINK_CLASS}`}\n >\n <div className=\"flex justify-between gap-2\">\n <span className=\"text-sm font-medium truncate\">{risk.title}</span>\n <span\n className={`text-xs px-2 py-0.5 rounded-full shrink-0 ${riskSeverityColor[risk.severity] ?? 'bg-gray-100'}`}\n >\n {enumLabel(risk.severity)}\n </span>\n </div>\n <div className=\"text-xs text-muted-foreground mt-1\">\n Score {risk.riskScore} · {enumLabel(risk.status)}\n </div>\n </div>\n )\n )}\n {openRisks.length === 0 && (\n <p className=\"text-sm text-muted-foreground text-center py-2\">No open risks.</p>\n )}\n <button\n type=\"button\"\n className=\"text-xs text-primary hover:underline\"\n onClick={() =>\n navigate(`/risks/risk-register-page?projectId=${encodeURIComponent(project.id)}`)\n }\n >\n View risk register ({projectRisks.length}) →\n </button>\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\">Owner</span>\n <span>\n <PersonName id={project.ownerId} />\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Key</span>\n <span className=\"font-mono\">{project.key}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Methodology</span>\n <span className=\"capitalize\">{project.methodology.toLowerCase()}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Program</span>\n {project.program ? (\n <button\n type=\"button\"\n className=\"text-primary hover:underline underline-offset-2\"\n onClick={() =>\n navigate(detailPath('/products/program-detail-page', project.program.id))\n }\n >\n {project.program.name}\n </button>\n ) : (\n <span className=\"text-muted-foreground\">No program</span>\n )}\n </div>\n {project.tags.length > 0 && (\n <div className=\"flex justify-between items-start\">\n <span className=\"text-muted-foreground\">Tags</span>\n <div className=\"flex gap-1 flex-wrap justify-end\">\n {project.tags.map((tag: string) => (\n <Badge key={tag} variant=\"outline\" className=\"text-xs\">\n {tag}\n </Badge>\n ))}\n </div>\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,2 +1,8 @@
1
+ /**
2
+ * Create a report (ANR-13). Previously this page had nothing to save to (no Report model existed) and its
3
+ * submit control was permanently disabled — see git history / BOFF-7822. The report builder now backs a real
4
+ * `planmagnetCreateReport` mutation; the implementation lives in `ReportBuilderPage.tsx`, shared with
5
+ * `ReportsEditReportPagePage.tsx` (edit mode).
6
+ */
1
7
  export declare function ReportsCreateReportPagePage(): import("react/jsx-runtime").JSX.Element;
2
8
  //# sourceMappingURL=ReportsCreateReportPagePage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ReportsCreateReportPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ReportsCreateReportPagePage.tsx"],"names":[],"mappings":"AAgCA,wBAAgB,2BAA2B,4CAyJ1C"}
1
+ {"version":3,"file":"ReportsCreateReportPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ReportsCreateReportPagePage.tsx"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,wBAAgB,2BAA2B,4CAE1C"}
@@ -1,182 +1,10 @@
1
- import { usePlanMagnet as e, usePlanMagnetNavigate as t } from "../providers/PlanMagnetProvider.js";
2
- import { useState as n } from "react";
3
- import { BarChart3 as r, Save as i, X as a } from "lucide-react";
4
- import { gql as o } from "@apollo/client";
5
- import { useQuery as s } from "@apollo/client/react";
6
- import { jsx as c, jsxs as l } from "react/jsx-runtime";
7
- import { Button as u, Card as d, CardContent as f, CardHeader as p, CardTitle as m, Input as h } from "@burdenoff/fe-libs/ui";
1
+ import { ReportBuilderPage as e } from "../reports/ReportBuilderPage.js";
2
+ import { jsx as t } from "react/jsx-runtime";
8
3
  //#region src/planmagnet/pages/ReportsCreateReportPagePage.tsx
9
- var g = o`
10
- query GetProjectsForReport($workspaceId: ID!, $pagination: PlanmagnetPaginationInput) {
11
- planmagnetProjects(workspaceId: $workspaceId, pagination: $pagination) {
12
- items {
13
- id
14
- name
15
- key
16
- }
17
- totalCount
18
- }
19
- }
20
- `;
21
- function _() {
22
- let { workspaceId: o } = e(), _ = t(), { data: v, loading: y, error: b } = s(g, {
23
- variables: {
24
- workspaceId: o,
25
- pagination: { first: 100 }
26
- },
27
- skip: !o
28
- }), [x, S] = n({
29
- name: "",
30
- description: "",
31
- type: "velocity",
32
- projectId: "",
33
- schedule: "weekly"
34
- }), C = [
35
- "velocity",
36
- "burndown",
37
- "burnup",
38
- "cumulative_flow",
39
- "cycle_time",
40
- "lead_time",
41
- "custom"
42
- ], w = [
43
- "daily",
44
- "weekly",
45
- "monthly"
46
- ], T = v?.planmagnetProjects?.items ?? [];
47
- return y && !v ? /* @__PURE__ */ c("div", {
48
- className: "flex items-center justify-center p-12",
49
- children: /* @__PURE__ */ c("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
50
- }) : b ? /* @__PURE__ */ l("div", {
51
- className: "p-6 text-red-500",
52
- children: ["Error: ", b.message]
53
- }) : /* @__PURE__ */ l("div", {
54
- className: "space-y-6 p-6 max-w-4xl",
55
- children: [
56
- /* @__PURE__ */ l("div", {
57
- className: "flex items-center justify-between",
58
- children: [/* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("h1", {
59
- className: "text-2xl font-semibold",
60
- children: "Create Report"
61
- }), /* @__PURE__ */ c("p", {
62
- className: "text-sm text-muted-foreground",
63
- children: "Configure a new automated report."
64
- })] }), /* @__PURE__ */ l("div", {
65
- className: "flex gap-2",
66
- children: [/* @__PURE__ */ l(u, {
67
- variant: "outline",
68
- size: "sm",
69
- onClick: () => _("/reports/reports-page"),
70
- children: [/* @__PURE__ */ c(a, { className: "mr-1 h-4 w-4" }), "Cancel"]
71
- }), /* @__PURE__ */ l(u, {
72
- size: "sm",
73
- disabled: !0,
74
- title: "Not available yet — see the notice below",
75
- children: [/* @__PURE__ */ c(i, { className: "mr-1 h-4 w-4" }), "Create Report"]
76
- })]
77
- })]
78
- }),
79
- /* @__PURE__ */ l("div", {
80
- className: "rounded-md border border-border bg-muted p-4 text-sm text-muted-foreground",
81
- children: [/* @__PURE__ */ c("strong", {
82
- className: "text-foreground",
83
- children: "Not available yet."
84
- }), " Reports cannot be saved — there is no report model behind this form. It is shown so the fields and options are visible, but nothing entered here is stored. This page previously returned you to the list on submit, which looked like it had saved."]
85
- }),
86
- /* @__PURE__ */ l(d, { children: [/* @__PURE__ */ c(p, { children: /* @__PURE__ */ l(m, {
87
- className: "flex items-center gap-2",
88
- children: [/* @__PURE__ */ c(r, { className: "h-4 w-4" }), "Report Configuration"]
89
- }) }), /* @__PURE__ */ l(f, {
90
- className: "space-y-4",
91
- children: [
92
- /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
93
- className: "text-sm font-medium",
94
- children: "Report Name"
95
- }), /* @__PURE__ */ c(h, {
96
- value: x.name,
97
- onChange: (e) => S({
98
- ...x,
99
- name: e.target.value
100
- }),
101
- className: "mt-1",
102
- placeholder: "e.g. Sprint Velocity Report"
103
- })] }),
104
- /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
105
- className: "text-sm font-medium",
106
- children: "Description"
107
- }), /* @__PURE__ */ c("textarea", {
108
- className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[80px]",
109
- value: x.description,
110
- onChange: (e) => S({
111
- ...x,
112
- description: e.target.value
113
- }),
114
- placeholder: "What does this report track?"
115
- })] }),
116
- /* @__PURE__ */ l("div", {
117
- className: "grid grid-cols-3 gap-4",
118
- children: [
119
- /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
120
- className: "text-sm font-medium",
121
- children: "Type"
122
- }), /* @__PURE__ */ c("select", {
123
- className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm",
124
- value: x.type,
125
- onChange: (e) => S({
126
- ...x,
127
- type: e.target.value
128
- }),
129
- children: C.map((e) => /* @__PURE__ */ c("option", {
130
- value: e,
131
- children: e.replace("_", " ")
132
- }, e))
133
- })] }),
134
- /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
135
- className: "text-sm font-medium",
136
- children: "Project (optional)"
137
- }), /* @__PURE__ */ l("select", {
138
- className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm",
139
- value: x.projectId,
140
- onChange: (e) => S({
141
- ...x,
142
- projectId: e.target.value
143
- }),
144
- children: [/* @__PURE__ */ c("option", {
145
- value: "",
146
- children: "All projects"
147
- }), T.map((e) => /* @__PURE__ */ l("option", {
148
- value: e.id,
149
- children: [
150
- e.name,
151
- " (",
152
- e.key,
153
- ")"
154
- ]
155
- }, e.id))]
156
- })] }),
157
- /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
158
- className: "text-sm font-medium",
159
- children: "Schedule"
160
- }), /* @__PURE__ */ c("select", {
161
- className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm",
162
- value: x.schedule,
163
- onChange: (e) => S({
164
- ...x,
165
- schedule: e.target.value
166
- }),
167
- children: w.map((e) => /* @__PURE__ */ c("option", {
168
- value: e,
169
- children: e
170
- }, e))
171
- })] })
172
- ]
173
- })
174
- ]
175
- })] })
176
- ]
177
- });
4
+ function n() {
5
+ return /* @__PURE__ */ t(e, { mode: "create" });
178
6
  }
179
7
  //#endregion
180
- export { _ as ReportsCreateReportPagePage };
8
+ export { n as ReportsCreateReportPagePage };
181
9
 
182
10
  //# sourceMappingURL=ReportsCreateReportPagePage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ReportsCreateReportPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ReportsCreateReportPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Button, Input } from '@burdenoff/fe-libs/ui';\nimport { Save, X, BarChart3 } from 'lucide-react';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\n\nconst GET_PROJECTS_FOR_REPORT = gql`\n query GetProjectsForReport($workspaceId: ID!, $pagination: PlanmagnetPaginationInput) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: $pagination) {\n items {\n id\n name\n key\n }\n totalCount\n }\n }\n`;\n\ninterface ProjectNode {\n id: string;\n name: string;\n key: string;\n}\n\ninterface ProjectsData {\n projects: { items: ProjectNode[]; totalCount: number };\n}\n\nexport function ReportsCreateReportPagePage() {\n const { workspaceId } = usePlanMagnet();\n const navigate = usePlanMagnetNavigate();\n\n const { data, loading, error } = useQuery<ProjectsData>(GET_PROJECTS_FOR_REPORT, {\n variables: {\n workspaceId,\n pagination: { first: 100 },\n },\n skip: !workspaceId,\n });\n\n const [form, setForm] = useState({\n name: '',\n description: '',\n type: 'velocity',\n projectId: '',\n schedule: 'weekly',\n });\n const types = [\n 'velocity',\n 'burndown',\n 'burnup',\n 'cumulative_flow',\n 'cycle_time',\n 'lead_time',\n 'custom',\n ] as const;\n const schedules = ['daily', 'weekly', 'monthly'] as const;\n\n const projects = data?.planmagnetProjects?.items ?? [];\n\n // NOTE: there is no Report model in wspace-planmagnet-svc, so this form has nothing\n // to save to. It previously had a handler that navigated to '/reports' on submit,\n // which read as a successful save — the user filled the form, was redirected, and\n // nothing was persisted. The submit control is disabled until the model exists\n // (BOFF-7822); the notice above the form says so.\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 <div className=\"animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full\" />\n </div>\n );\n }\n\n if (error) {\n return <div className=\"p-6 text-red-500\">Error: {error.message}</div>;\n }\n\n 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 Report</h1>\n <p className=\"text-sm text-muted-foreground\">Configure a new automated report.</p>\n </div>\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={() => navigate('/reports/reports-page')}>\n <X className=\"mr-1 h-4 w-4\" />\n Cancel\n </Button>\n <Button size=\"sm\" disabled title=\"Not available yet — see the notice below\">\n <Save className=\"mr-1 h-4 w-4\" />\n Create Report\n </Button>\n </div>\n </div>\n <div className=\"rounded-md border border-border bg-muted p-4 text-sm text-muted-foreground\">\n <strong className=\"text-foreground\">Not available yet.</strong> Reports cannot be saved —\n there is no report model behind this form. It is shown so the fields and options are\n visible, but nothing entered here is stored. This page previously returned you to the list\n on submit, which looked like it had saved.\n </div>\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <BarChart3 className=\"h-4 w-4\" />\n Report Configuration\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label className=\"text-sm font-medium\">Report Name</label>\n <Input\n value={form.name}\n onChange={(e) => setForm({ ...form, name: e.target.value })}\n className=\"mt-1\"\n placeholder=\"e.g. Sprint Velocity Report\"\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-[80px]\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n placeholder=\"What does this report track?\"\n />\n </div>\n <div className=\"grid grid-cols-3 gap-4\">\n <div>\n <label className=\"text-sm font-medium\">Type</label>\n <select\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm\"\n value={form.type}\n onChange={(e) => setForm({ ...form, type: e.target.value })}\n >\n {types.map((t) => (\n <option key={t} value={t}>\n {t.replace('_', ' ')}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"text-sm font-medium\">Project (optional)</label>\n <select\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm\"\n value={form.projectId}\n onChange={(e) => setForm({ ...form, projectId: e.target.value })}\n >\n <option value=\"\">All projects</option>\n {projects.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name} ({p.key})\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"text-sm font-medium\">Schedule</label>\n <select\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm\"\n value={form.schedule}\n onChange={(e) => setForm({ ...form, schedule: e.target.value })}\n >\n {schedules.map((s) => (\n <option key={s} value={s}>\n {s}\n </option>\n ))}\n </select>\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ReportsCreateReportPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ReportsCreateReportPagePage.tsx"],"sourcesContent":["import { ReportBuilderPage } from '../reports/ReportBuilderPage';\n\n/**\n * Create a report (ANR-13). Previously this page had nothing to save to (no Report model existed) and its\n * submit control was permanently disabled — see git history / BOFF-7822. The report builder now backs a real\n * `planmagnetCreateReport` mutation; the implementation lives in `ReportBuilderPage.tsx`, shared with\n * `ReportsEditReportPagePage.tsx` (edit mode).\n */\nexport function ReportsCreateReportPagePage() {\n return <ReportBuilderPage mode=\"create\" />;\n}\n"],"mappings":";;;AAQA,SAAgB,IAA8B;AAC5C,QAAO,kBAAC,GAAD,EAAmB,MAAK,UAAW,CAAA"}
@@ -0,0 +1,3 @@
1
+ /** Edit an existing report (ANR-13) — same builder as create, loaded with the report's current definition. */
2
+ export declare function ReportsEditReportPagePage(): import("react/jsx-runtime").JSX.Element;
3
+ //# sourceMappingURL=ReportsEditReportPagePage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReportsEditReportPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ReportsEditReportPagePage.tsx"],"names":[],"mappings":"AAGA,8GAA8G;AAC9G,wBAAgB,yBAAyB,4CAGxC"}
@@ -0,0 +1,15 @@
1
+ import { ReportBuilderPage as e } from "../reports/ReportBuilderPage.js";
2
+ import { useParams as t } from "react-router";
3
+ import { jsx as n } from "react/jsx-runtime";
4
+ //#region src/planmagnet/pages/ReportsEditReportPagePage.tsx
5
+ function r() {
6
+ let { id: r } = t();
7
+ return /* @__PURE__ */ n(e, {
8
+ mode: "edit",
9
+ reportId: r
10
+ });
11
+ }
12
+ //#endregion
13
+ export { r as ReportsEditReportPagePage };
14
+
15
+ //# sourceMappingURL=ReportsEditReportPagePage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReportsEditReportPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ReportsEditReportPagePage.tsx"],"sourcesContent":["import { useParams } from 'react-router';\nimport { ReportBuilderPage } from '../reports/ReportBuilderPage';\n\n/** Edit an existing report (ANR-13) — same builder as create, loaded with the report's current definition. */\nexport function ReportsEditReportPagePage() {\n const { id } = useParams<{ id: string }>();\n return <ReportBuilderPage mode=\"edit\" reportId={id} />;\n}\n"],"mappings":";;;;AAIA,SAAgB,IAA4B;CAC1C,IAAM,EAAE,UAAO,GAA2B;AAC1C,QAAO,kBAAC,GAAD;EAAmB,MAAK;EAAO,UAAU;EAAM,CAAA"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * View + run a report (ANR-13/15/16). "Run now" persists a new `ReportRun` snapshot (not a live view — see
3
+ * `PlanmagnetReportRun`'s own schema doc): re-running the same report later never changes what an earlier run
4
+ * showed. Older runs are opened from `ReportRunHistory` via `planmagnetReportRun`.
5
+ */
6
+ export declare function ReportsReportPagePage(): import("react/jsx-runtime").JSX.Element;
7
+ //# sourceMappingURL=ReportsReportPagePage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReportsReportPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ReportsReportPagePage.tsx"],"names":[],"mappings":"AA2BA;;;;GAIG;AACH,wBAAgB,qBAAqB,4CA4PpC"}