@burdenoff/microfe-planmagnet 2026.930.24 → 2026.1001.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 (318) 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 +154 -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 +122 -106
  175. package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
  176. package/dist/planmagnet/comments/CommentThread.d.ts +8 -1
  177. package/dist/planmagnet/comments/CommentThread.d.ts.map +1 -1
  178. package/dist/planmagnet/comments/CommentThread.js +188 -181
  179. package/dist/planmagnet/comments/CommentThread.js.map +1 -1
  180. package/dist/planmagnet/comments/TargetComments.d.ts +10 -2
  181. package/dist/planmagnet/comments/TargetComments.d.ts.map +1 -1
  182. package/dist/planmagnet/comments/TargetComments.js +10 -8
  183. package/dist/planmagnet/comments/TargetComments.js.map +1 -1
  184. package/dist/planmagnet/comments/WorkItemComments.d.ts +7 -1
  185. package/dist/planmagnet/comments/WorkItemComments.d.ts.map +1 -1
  186. package/dist/planmagnet/comments/WorkItemComments.js +5 -4
  187. package/dist/planmagnet/comments/WorkItemComments.js.map +1 -1
  188. package/dist/planmagnet/controls/Pickers.d.ts +10 -0
  189. package/dist/planmagnet/controls/Pickers.d.ts.map +1 -1
  190. package/dist/planmagnet/controls/Pickers.js +75 -27
  191. package/dist/planmagnet/controls/Pickers.js.map +1 -1
  192. package/dist/planmagnet/discussion/WorkItemDiscussionPanel.d.ts +8 -0
  193. package/dist/planmagnet/discussion/WorkItemDiscussionPanel.d.ts.map +1 -0
  194. package/dist/planmagnet/discussion/WorkItemDiscussionPanel.js +217 -0
  195. package/dist/planmagnet/discussion/WorkItemDiscussionPanel.js.map +1 -0
  196. package/dist/planmagnet/docs/DocDiffView.d.ts +26 -0
  197. package/dist/planmagnet/docs/DocDiffView.d.ts.map +1 -0
  198. package/dist/planmagnet/docs/DocDiffView.js +52 -0
  199. package/dist/planmagnet/docs/DocDiffView.js.map +1 -0
  200. package/dist/planmagnet/docs/DocSuggestionsPanel.d.ts +13 -0
  201. package/dist/planmagnet/docs/DocSuggestionsPanel.d.ts.map +1 -0
  202. package/dist/planmagnet/docs/DocSuggestionsPanel.js +308 -0
  203. package/dist/planmagnet/docs/DocSuggestionsPanel.js.map +1 -0
  204. package/dist/planmagnet/docs/DocVersionCompare.d.ts +7 -0
  205. package/dist/planmagnet/docs/DocVersionCompare.d.ts.map +1 -0
  206. package/dist/planmagnet/docs/DocVersionCompare.js +105 -0
  207. package/dist/planmagnet/docs/DocVersionCompare.js.map +1 -0
  208. package/dist/planmagnet/hooks/usePresence.d.ts +39 -0
  209. package/dist/planmagnet/hooks/usePresence.d.ts.map +1 -0
  210. package/dist/planmagnet/hooks/usePresence.js +146 -0
  211. package/dist/planmagnet/hooks/usePresence.js.map +1 -0
  212. package/dist/planmagnet/index.d.ts +2 -0
  213. package/dist/planmagnet/index.d.ts.map +1 -1
  214. package/dist/planmagnet/index.js +2 -0
  215. package/dist/planmagnet/links/CodeLinksPanel.d.ts +22 -0
  216. package/dist/planmagnet/links/CodeLinksPanel.d.ts.map +1 -0
  217. package/dist/planmagnet/links/CodeLinksPanel.js +94 -0
  218. package/dist/planmagnet/links/CodeLinksPanel.js.map +1 -0
  219. package/dist/planmagnet/pages/DocsDocDetailPagePage.d.ts.map +1 -1
  220. package/dist/planmagnet/pages/DocsDocDetailPagePage.js +488 -217
  221. package/dist/planmagnet/pages/DocsDocDetailPagePage.js.map +1 -1
  222. package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.d.ts.map +1 -1
  223. package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js +136 -130
  224. package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js.map +1 -1
  225. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.d.ts.map +1 -1
  226. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js +205 -196
  227. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js.map +1 -1
  228. package/dist/planmagnet/pages/ReportsCreateReportPagePage.d.ts +6 -0
  229. package/dist/planmagnet/pages/ReportsCreateReportPagePage.d.ts.map +1 -1
  230. package/dist/planmagnet/pages/ReportsCreateReportPagePage.js +5 -177
  231. package/dist/planmagnet/pages/ReportsCreateReportPagePage.js.map +1 -1
  232. package/dist/planmagnet/pages/ReportsEditReportPagePage.d.ts +3 -0
  233. package/dist/planmagnet/pages/ReportsEditReportPagePage.d.ts.map +1 -0
  234. package/dist/planmagnet/pages/ReportsEditReportPagePage.js +15 -0
  235. package/dist/planmagnet/pages/ReportsEditReportPagePage.js.map +1 -0
  236. package/dist/planmagnet/pages/ReportsReportPagePage.d.ts +7 -0
  237. package/dist/planmagnet/pages/ReportsReportPagePage.d.ts.map +1 -0
  238. package/dist/planmagnet/pages/ReportsReportPagePage.js +226 -0
  239. package/dist/planmagnet/pages/ReportsReportPagePage.js.map +1 -0
  240. package/dist/planmagnet/pages/ReportsReportsPagePage.d.ts.map +1 -1
  241. package/dist/planmagnet/pages/ReportsReportsPagePage.js +224 -496
  242. package/dist/planmagnet/pages/ReportsReportsPagePage.js.map +1 -1
  243. package/dist/planmagnet/pages/TasksTaskDetailPagePage.d.ts.map +1 -1
  244. package/dist/planmagnet/pages/TasksTaskDetailPagePage.js +194 -160
  245. package/dist/planmagnet/pages/TasksTaskDetailPagePage.js.map +1 -1
  246. package/dist/planmagnet/presence/PresenceAvatars.d.ts +16 -0
  247. package/dist/planmagnet/presence/PresenceAvatars.d.ts.map +1 -0
  248. package/dist/planmagnet/presence/PresenceAvatars.js +56 -0
  249. package/dist/planmagnet/presence/PresenceAvatars.js.map +1 -0
  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 +14 -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/utils/graphqlErrors.d.ts +6 -0
  311. package/dist/planmagnet/utils/graphqlErrors.d.ts.map +1 -1
  312. package/dist/planmagnet/utils/graphqlErrors.js +5 -2
  313. package/dist/planmagnet/utils/graphqlErrors.js.map +1 -1
  314. package/dist/planmagnet/utils/lineDiff.d.ts +21 -0
  315. package/dist/planmagnet/utils/lineDiff.d.ts.map +1 -0
  316. package/dist/planmagnet/utils/lineDiff.js +36 -0
  317. package/dist/planmagnet/utils/lineDiff.js.map +1 -0
  318. package/package.json +6 -4
@@ -0,0 +1,261 @@
1
+ import { PARAM_LABELS as e, REPORT_SOURCE_SPECS as t, repackWidgets as n, widgetIndexFromField as r } from "./reportModel.js";
2
+ import { WidgetEditorDialog as i } from "./WidgetEditorDialog.js";
3
+ import { useState as a } from "react";
4
+ import { ArrowDown as o, ArrowUp as s, GripVertical as c, Minus as l, Pencil as u, Plus as d, Trash2 as f } from "lucide-react";
5
+ import { jsx as p, jsxs as m } from "react/jsx-runtime";
6
+ import { Badge as h, Button as g } from "@burdenoff/fe-libs/ui";
7
+ //#region src/planmagnet/reports/ReportBuilderCanvas.tsx
8
+ var _ = [
9
+ "projectId",
10
+ "sprintId",
11
+ "teamId",
12
+ "from",
13
+ "to",
14
+ "limit"
15
+ ];
16
+ function v(e, t, n) {
17
+ if (n < 0 || n >= e.length) return e;
18
+ let r = e.slice(), [i] = r.splice(t, 1);
19
+ return i === void 0 ? e : (r.splice(n, 0, i), r);
20
+ }
21
+ function y(t) {
22
+ let n = _.filter((e) => {
23
+ let n = t.params[e];
24
+ return n != null && n !== "";
25
+ }).map((n) => {
26
+ let r = t.params[n], i = n === "from" || n === "to" ? String(r).slice(0, 10) : String(r);
27
+ return `${e[n]}: ${i}`;
28
+ });
29
+ return n.length ? n.join(" · ") : null;
30
+ }
31
+ function b({ widget: e, index: n, total: i, errors: l, onEdit: d, onRemove: _, onMoveUp: v, onMoveDown: b, onResize: S, onDragStart: C, onDropBefore: w }) {
32
+ let [T, E] = a(!1), D = l.filter((e) => r(e.field) === n);
33
+ return /* @__PURE__ */ p("div", {
34
+ style: { width: `${e.layout.w / 12 * 100}%` },
35
+ className: "p-1.5",
36
+ "data-testid": "report-widget",
37
+ children: /* @__PURE__ */ m("div", {
38
+ draggable: !0,
39
+ onDragStart: C,
40
+ onDragOver: (e) => {
41
+ e.preventDefault(), E(!0);
42
+ },
43
+ onDragLeave: () => E(!1),
44
+ onDrop: (e) => {
45
+ E(!1), w(e);
46
+ },
47
+ className: `flex h-full flex-col gap-2 rounded-md border bg-background p-3 ${T ? "ring-2 ring-primary" : "border-border"} ${D.length ? "border-destructive" : ""}`,
48
+ children: [
49
+ /* @__PURE__ */ m("div", {
50
+ className: "flex items-start justify-between gap-2",
51
+ children: [/* @__PURE__ */ m("div", {
52
+ className: "flex min-w-0 items-start gap-1.5",
53
+ children: [/* @__PURE__ */ p(c, {
54
+ className: "mt-0.5 h-4 w-4 shrink-0 cursor-grab text-muted-foreground",
55
+ "aria-hidden": !0
56
+ }), /* @__PURE__ */ m("div", {
57
+ className: "min-w-0",
58
+ children: [/* @__PURE__ */ p("p", {
59
+ className: "truncate text-sm font-medium",
60
+ title: e.title,
61
+ children: e.title
62
+ }), /* @__PURE__ */ m("div", {
63
+ className: "mt-0.5 flex flex-wrap items-center gap-1",
64
+ children: [/* @__PURE__ */ p(h, {
65
+ variant: "outline",
66
+ className: "text-[10px]",
67
+ children: e.type
68
+ }), e.type !== "TEXT" && /* @__PURE__ */ p(h, {
69
+ variant: "secondary",
70
+ className: "text-[10px]",
71
+ children: t[e.source].label
72
+ })]
73
+ })]
74
+ })]
75
+ }), /* @__PURE__ */ m("div", {
76
+ className: "flex shrink-0 items-center gap-0.5",
77
+ draggable: !1,
78
+ onMouseDown: (e) => e.stopPropagation(),
79
+ onDragStart: (e) => e.stopPropagation(),
80
+ children: [
81
+ /* @__PURE__ */ p(g, {
82
+ size: "sm",
83
+ variant: "outline",
84
+ className: "h-7 w-7 p-0",
85
+ "aria-label": "Move widget earlier",
86
+ disabled: n === 0,
87
+ onClick: v,
88
+ children: /* @__PURE__ */ p(s, { className: "h-3.5 w-3.5" })
89
+ }),
90
+ /* @__PURE__ */ p(g, {
91
+ size: "sm",
92
+ variant: "outline",
93
+ className: "h-7 w-7 p-0",
94
+ "aria-label": "Move widget later",
95
+ disabled: n === i - 1,
96
+ onClick: b,
97
+ children: /* @__PURE__ */ p(o, { className: "h-3.5 w-3.5" })
98
+ }),
99
+ /* @__PURE__ */ p(g, {
100
+ size: "sm",
101
+ variant: "outline",
102
+ className: "h-7 w-7 p-0",
103
+ "aria-label": `Edit ${e.title}`,
104
+ onClick: d,
105
+ children: /* @__PURE__ */ p(u, { className: "h-3.5 w-3.5" })
106
+ }),
107
+ /* @__PURE__ */ p(g, {
108
+ size: "sm",
109
+ variant: "outline",
110
+ className: "h-7 w-7 p-0",
111
+ "aria-label": `Remove ${e.title}`,
112
+ onClick: _,
113
+ children: /* @__PURE__ */ p(f, { className: "h-3.5 w-3.5" })
114
+ })
115
+ ]
116
+ })]
117
+ }),
118
+ e.type !== "TEXT" && y(e) && /* @__PURE__ */ p("p", {
119
+ className: "text-xs text-muted-foreground",
120
+ children: y(e)
121
+ }),
122
+ /* @__PURE__ */ m("div", {
123
+ className: "mt-auto flex flex-wrap items-center gap-3 border-t border-border pt-2 text-xs text-muted-foreground",
124
+ draggable: !1,
125
+ onMouseDown: (e) => e.stopPropagation(),
126
+ onDragStart: (e) => e.stopPropagation(),
127
+ children: [/* @__PURE__ */ p(x, {
128
+ label: "Width",
129
+ value: e.layout.w,
130
+ min: 1,
131
+ max: 12,
132
+ onChange: (e) => S({ w: e })
133
+ }), /* @__PURE__ */ p(x, {
134
+ label: "Height",
135
+ value: e.layout.h,
136
+ min: 1,
137
+ max: 12,
138
+ onChange: (e) => S({ h: e })
139
+ })]
140
+ }),
141
+ D.length > 0 && /* @__PURE__ */ p("ul", {
142
+ className: "space-y-0.5 text-xs text-destructive",
143
+ role: "alert",
144
+ children: D.map((e) => /* @__PURE__ */ p("li", { children: e.message }, e.field))
145
+ })
146
+ ]
147
+ })
148
+ });
149
+ }
150
+ function x({ label: e, value: t, min: n, max: r, onChange: i }) {
151
+ return /* @__PURE__ */ m("div", {
152
+ className: "flex items-center gap-1",
153
+ children: [
154
+ /* @__PURE__ */ p("span", { children: e }),
155
+ /* @__PURE__ */ p(g, {
156
+ size: "sm",
157
+ variant: "outline",
158
+ className: "h-6 w-6 p-0",
159
+ "aria-label": `Decrease ${e.toLowerCase()}`,
160
+ disabled: t <= n,
161
+ onClick: () => i(Math.max(n, t - 1)),
162
+ children: /* @__PURE__ */ p(l, { className: "h-3 w-3" })
163
+ }),
164
+ /* @__PURE__ */ p("span", {
165
+ className: "w-4 text-center tabular-nums",
166
+ children: t
167
+ }),
168
+ /* @__PURE__ */ p(g, {
169
+ size: "sm",
170
+ variant: "outline",
171
+ className: "h-6 w-6 p-0",
172
+ "aria-label": `Increase ${e.toLowerCase()}`,
173
+ disabled: t >= r,
174
+ onClick: () => i(Math.min(r, t + 1)),
175
+ children: /* @__PURE__ */ p(d, { className: "h-3 w-3" })
176
+ })
177
+ ]
178
+ });
179
+ }
180
+ function S({ widgets: e, onChange: t, errors: o }) {
181
+ let [s, c] = a(!1), [l, u] = a(null), [f, _] = a(null), y = (e) => t(n(e)), x = () => {
182
+ u(null), c(!0);
183
+ }, S = (e) => {
184
+ u(e), c(!0);
185
+ }, C = (t) => {
186
+ y(l === null ? [...e, t] : e.map((e, n) => n === l ? t : e));
187
+ }, w = o.filter((e) => r(e.field) === null);
188
+ return /* @__PURE__ */ m("div", {
189
+ className: "space-y-3",
190
+ children: [
191
+ /* @__PURE__ */ m("div", {
192
+ className: "flex items-center justify-between",
193
+ children: [/* @__PURE__ */ m("div", {
194
+ className: "flex items-center gap-2",
195
+ children: [/* @__PURE__ */ p("h2", {
196
+ className: "text-sm font-semibold",
197
+ children: "Widgets"
198
+ }), /* @__PURE__ */ m(h, {
199
+ variant: e.length > 24 ? "destructive" : "outline",
200
+ children: [
201
+ e.length,
202
+ " / ",
203
+ 24
204
+ ]
205
+ })]
206
+ }), /* @__PURE__ */ m(g, {
207
+ size: "sm",
208
+ onClick: x,
209
+ disabled: e.length >= 24,
210
+ "data-testid": "report-add-widget-trigger",
211
+ children: [/* @__PURE__ */ p(d, { className: "mr-1 h-4 w-4" }), "Add widget"]
212
+ })]
213
+ }),
214
+ w.length > 0 && /* @__PURE__ */ p("ul", {
215
+ className: "space-y-0.5 text-sm text-destructive",
216
+ role: "alert",
217
+ children: w.map((e) => /* @__PURE__ */ p("li", { children: e.message }, e.field))
218
+ }),
219
+ e.length === 0 ? /* @__PURE__ */ p("div", {
220
+ className: "rounded-md border border-dashed border-border p-8 text-center text-sm text-muted-foreground",
221
+ children: "No widgets yet. Add one to start building this report."
222
+ }) : /* @__PURE__ */ p("div", {
223
+ className: "flex flex-wrap",
224
+ "data-testid": "report-builder",
225
+ children: e.map((t, n) => /* @__PURE__ */ p(b, {
226
+ widget: t,
227
+ index: n,
228
+ total: e.length,
229
+ errors: o,
230
+ onEdit: () => S(n),
231
+ onRemove: () => y(e.filter((e, t) => t !== n)),
232
+ onMoveUp: () => y(v(e, n, n - 1)),
233
+ onMoveDown: () => y(v(e, n, n + 1)),
234
+ onResize: (t) => y(e.map((e, r) => r === n ? {
235
+ ...e,
236
+ layout: {
237
+ ...e.layout,
238
+ ...t
239
+ }
240
+ } : e)),
241
+ onDragStart: (e) => {
242
+ _(n), e.dataTransfer.effectAllowed = "move", e.dataTransfer.setData("text/plain", t.id);
243
+ },
244
+ onDropBefore: (t) => {
245
+ t.preventDefault(), !(f === null || f === n) && (y(v(e, f, n)), _(null));
246
+ }
247
+ }, t.id))
248
+ }),
249
+ /* @__PURE__ */ p(i, {
250
+ open: s,
251
+ onOpenChange: c,
252
+ widget: l === null ? null : e[l] ?? null,
253
+ onSave: C
254
+ })
255
+ ]
256
+ });
257
+ }
258
+ //#endregion
259
+ export { S as ReportBuilderCanvas };
260
+
261
+ //# sourceMappingURL=ReportBuilderCanvas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReportBuilderCanvas.js","names":[],"sources":["../../../src/planmagnet/reports/ReportBuilderCanvas.tsx"],"sourcesContent":["import { useState, type DragEvent } from 'react';\nimport { Badge, Button } from '@burdenoff/fe-libs/ui';\nimport { ArrowDown, ArrowUp, GripVertical, Minus, Pencil, Plus, Trash2 } from 'lucide-react';\nimport { WidgetEditorDialog } from './WidgetEditorDialog';\nimport {\n GRID_COLUMNS,\n MAX_WIDGETS,\n PARAM_LABELS,\n REPORT_SOURCE_SPECS,\n repackWidgets,\n widgetIndexFromField,\n type FieldError,\n type ReportWidget,\n type WidgetParamKey,\n} from './reportModel';\n\n/**\n * The builder's 12-column grid canvas (ANR-13). There is no free-form drag-to-position: a widget's place comes\n * from its order in the list (reordered by drag-and-drop or the keyboard up/down buttons) and its own width,\n * packed left-to-right with wraparound (`packLayout` in `reportModel.ts`) — the same rule the flex-wrap layout\n * below renders visually, so the canvas preview and the persisted `layout` never disagree, and every layout\n * this UI can produce already satisfies the server's grid bounds.\n */\n\nconst PARAM_KEYS_ORDER: WidgetParamKey[] = [\n 'projectId',\n 'sprintId',\n 'teamId',\n 'from',\n 'to',\n 'limit',\n];\n\nfunction moveItem<T>(list: T[], from: number, to: number): T[] {\n if (to < 0 || to >= list.length) return list;\n const next = list.slice();\n const [item] = next.splice(from, 1);\n if (item === undefined) return list;\n next.splice(to, 0, item);\n return next;\n}\n\nfunction paramSummary(widget: ReportWidget): string | null {\n const parts = PARAM_KEYS_ORDER.filter((key) => {\n const value = widget.params[key];\n return value !== undefined && value !== null && value !== '';\n }).map((key) => {\n const value = widget.params[key];\n const text = key === 'from' || key === 'to' ? String(value).slice(0, 10) : String(value);\n return `${PARAM_LABELS[key]}: ${text}`;\n });\n return parts.length ? parts.join(' · ') : null;\n}\n\nfunction WidgetCard({\n widget,\n index,\n total,\n errors,\n onEdit,\n onRemove,\n onMoveUp,\n onMoveDown,\n onResize,\n onDragStart,\n onDropBefore,\n}: {\n widget: ReportWidget;\n index: number;\n total: number;\n errors: FieldError[];\n onEdit: () => void;\n onRemove: () => void;\n onMoveUp: () => void;\n onMoveDown: () => void;\n onResize: (dims: Partial<{ w: number; h: number }>) => void;\n onDragStart: (event: DragEvent<HTMLDivElement>) => void;\n onDropBefore: (event: DragEvent<HTMLDivElement>) => void;\n}) {\n const [dragOver, setDragOver] = useState(false);\n const cardErrors = errors.filter((e) => widgetIndexFromField(e.field) === index);\n\n return (\n <div\n style={{ width: `${(widget.layout.w / GRID_COLUMNS) * 100}%` }}\n className=\"p-1.5\"\n data-testid=\"report-widget\"\n >\n <div\n draggable\n onDragStart={onDragStart}\n onDragOver={(e) => {\n e.preventDefault();\n setDragOver(true);\n }}\n onDragLeave={() => setDragOver(false)}\n onDrop={(e) => {\n setDragOver(false);\n onDropBefore(e);\n }}\n className={`flex h-full flex-col gap-2 rounded-md border bg-background p-3 ${\n dragOver ? 'ring-2 ring-primary' : 'border-border'\n } ${cardErrors.length ? 'border-destructive' : ''}`}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex min-w-0 items-start gap-1.5\">\n <GripVertical\n className=\"mt-0.5 h-4 w-4 shrink-0 cursor-grab text-muted-foreground\"\n aria-hidden={true}\n />\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium\" title={widget.title}>\n {widget.title}\n </p>\n <div className=\"mt-0.5 flex flex-wrap items-center gap-1\">\n <Badge variant=\"outline\" className=\"text-[10px]\">\n {widget.type}\n </Badge>\n {widget.type !== 'TEXT' && (\n <Badge variant=\"secondary\" className=\"text-[10px]\">\n {REPORT_SOURCE_SPECS[widget.source].label}\n </Badge>\n )}\n </div>\n </div>\n </div>\n <div\n className=\"flex shrink-0 items-center gap-0.5\"\n draggable={false}\n onMouseDown={(e) => e.stopPropagation()}\n onDragStart={(e) => e.stopPropagation()}\n >\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7 w-7 p-0\"\n aria-label=\"Move widget earlier\"\n disabled={index === 0}\n onClick={onMoveUp}\n >\n <ArrowUp className=\"h-3.5 w-3.5\" />\n </Button>\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7 w-7 p-0\"\n aria-label=\"Move widget later\"\n disabled={index === total - 1}\n onClick={onMoveDown}\n >\n <ArrowDown className=\"h-3.5 w-3.5\" />\n </Button>\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7 w-7 p-0\"\n aria-label={`Edit ${widget.title}`}\n onClick={onEdit}\n >\n <Pencil className=\"h-3.5 w-3.5\" />\n </Button>\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7 w-7 p-0\"\n aria-label={`Remove ${widget.title}`}\n onClick={onRemove}\n >\n <Trash2 className=\"h-3.5 w-3.5\" />\n </Button>\n </div>\n </div>\n\n {widget.type !== 'TEXT' && paramSummary(widget) && (\n <p className=\"text-xs text-muted-foreground\">{paramSummary(widget)}</p>\n )}\n\n <div\n className=\"mt-auto flex flex-wrap items-center gap-3 border-t border-border pt-2 text-xs text-muted-foreground\"\n draggable={false}\n onMouseDown={(e) => e.stopPropagation()}\n onDragStart={(e) => e.stopPropagation()}\n >\n <SizeStepper\n label=\"Width\"\n value={widget.layout.w}\n min={1}\n max={GRID_COLUMNS}\n onChange={(w) => onResize({ w })}\n />\n <SizeStepper\n label=\"Height\"\n value={widget.layout.h}\n min={1}\n max={GRID_COLUMNS}\n onChange={(h) => onResize({ h })}\n />\n </div>\n\n {cardErrors.length > 0 && (\n <ul className=\"space-y-0.5 text-xs text-destructive\" role=\"alert\">\n {cardErrors.map((e) => (\n <li key={e.field}>{e.message}</li>\n ))}\n </ul>\n )}\n </div>\n </div>\n );\n}\n\nfunction SizeStepper({\n label,\n value,\n min,\n max,\n onChange,\n}: {\n label: string;\n value: number;\n min: number;\n max: number;\n onChange: (value: number) => void;\n}) {\n return (\n <div className=\"flex items-center gap-1\">\n <span>{label}</span>\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-6 w-6 p-0\"\n aria-label={`Decrease ${label.toLowerCase()}`}\n disabled={value <= min}\n onClick={() => onChange(Math.max(min, value - 1))}\n >\n <Minus className=\"h-3 w-3\" />\n </Button>\n <span className=\"w-4 text-center tabular-nums\">{value}</span>\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-6 w-6 p-0\"\n aria-label={`Increase ${label.toLowerCase()}`}\n disabled={value >= max}\n onClick={() => onChange(Math.min(max, value + 1))}\n >\n <Plus className=\"h-3 w-3\" />\n </Button>\n </div>\n );\n}\n\nexport function ReportBuilderCanvas({\n widgets,\n onChange,\n errors,\n}: {\n widgets: ReportWidget[];\n onChange: (widgets: ReportWidget[]) => void;\n errors: FieldError[];\n}) {\n const [editorOpen, setEditorOpen] = useState(false);\n const [editingIndex, setEditingIndex] = useState<number | null>(null);\n const [dragIndex, setDragIndex] = useState<number | null>(null);\n\n const apply = (next: ReportWidget[]) => onChange(repackWidgets(next));\n\n const openAdd = () => {\n setEditingIndex(null);\n setEditorOpen(true);\n };\n const openEdit = (index: number) => {\n setEditingIndex(index);\n setEditorOpen(true);\n };\n\n const handleSave = (widget: ReportWidget) => {\n if (editingIndex === null) {\n apply([...widgets, widget]);\n } else {\n apply(widgets.map((w, i) => (i === editingIndex ? widget : w)));\n }\n };\n\n const reportLevelErrors = errors.filter((e) => widgetIndexFromField(e.field) === null);\n\n return (\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <h2 className=\"text-sm font-semibold\">Widgets</h2>\n <Badge variant={widgets.length > MAX_WIDGETS ? 'destructive' : 'outline'}>\n {widgets.length} / {MAX_WIDGETS}\n </Badge>\n </div>\n <Button\n size=\"sm\"\n onClick={openAdd}\n disabled={widgets.length >= MAX_WIDGETS}\n data-testid=\"report-add-widget-trigger\"\n >\n <Plus className=\"mr-1 h-4 w-4\" />\n Add widget\n </Button>\n </div>\n\n {reportLevelErrors.length > 0 && (\n <ul className=\"space-y-0.5 text-sm text-destructive\" role=\"alert\">\n {reportLevelErrors.map((e) => (\n <li key={e.field}>{e.message}</li>\n ))}\n </ul>\n )}\n\n {widgets.length === 0 ? (\n <div className=\"rounded-md border border-dashed border-border p-8 text-center text-sm text-muted-foreground\">\n No widgets yet. Add one to start building this report.\n </div>\n ) : (\n <div className=\"flex flex-wrap\" data-testid=\"report-builder\">\n {widgets.map((widget, index) => (\n <WidgetCard\n key={widget.id}\n widget={widget}\n index={index}\n total={widgets.length}\n errors={errors}\n onEdit={() => openEdit(index)}\n onRemove={() => apply(widgets.filter((_, i) => i !== index))}\n onMoveUp={() => apply(moveItem(widgets, index, index - 1))}\n onMoveDown={() => apply(moveItem(widgets, index, index + 1))}\n onResize={(dims) =>\n apply(\n widgets.map((w, i) =>\n i === index ? { ...w, layout: { ...w.layout, ...dims } } : w\n )\n )\n }\n onDragStart={(e) => {\n setDragIndex(index);\n e.dataTransfer.effectAllowed = 'move';\n e.dataTransfer.setData('text/plain', widget.id);\n }}\n onDropBefore={(e) => {\n e.preventDefault();\n if (dragIndex === null || dragIndex === index) return;\n apply(moveItem(widgets, dragIndex, index));\n setDragIndex(null);\n }}\n />\n ))}\n </div>\n )}\n\n <WidgetEditorDialog\n open={editorOpen}\n onOpenChange={setEditorOpen}\n widget={editingIndex === null ? null : (widgets[editingIndex] ?? null)}\n onSave={handleSave}\n />\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare function ReportBuilderPage({ mode, reportId, }: {
2
+ mode: 'create' | 'edit';
3
+ reportId?: string;
4
+ }): import("react/jsx-runtime").JSX.Element;
5
+ //# sourceMappingURL=ReportBuilderPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReportBuilderPage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/reports/ReportBuilderPage.tsx"],"names":[],"mappings":"AA2PA,wBAAgB,iBAAiB,CAAC,EAChC,IAAI,EACJ,QAAQ,GACT,EAAE;IACD,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,2CAqCA"}
@@ -0,0 +1,198 @@
1
+ import { CombinedGraphQLErrors as e } from "../../node_modules/@apollo/client/errors/CombinedGraphQLErrors.js";
2
+ import { usePlanMagnet as t, usePlanMagnetNavigate as n } from "../providers/PlanMagnetProvider.js";
3
+ import { LEAVES_PAGE_CONTEXT as r, throwOnError as i } from "../utils/mutationResult.js";
4
+ import { ErrorLine as a } from "../controls/ConfirmButton.js";
5
+ import { detailPath as o } from "../utils/rowNavigation.js";
6
+ import { blankWidget as ee, repackWidgets as s, validateReportDraft as c } from "./reportModel.js";
7
+ import { ReportBuilderCanvas as l } from "./ReportBuilderCanvas.js";
8
+ import { CREATE_REPORT as u, GET_REPORT as d, UPDATE_REPORT as f } from "./reportGraphql.js";
9
+ import { useState as p } from "react";
10
+ import { Save as m, X as h } from "lucide-react";
11
+ import { useMutation as g, useQuery as _ } from "@apollo/client/react";
12
+ import { jsx as v, jsxs as y } from "react/jsx-runtime";
13
+ import { Button as b, Card as x, CardContent as S, CardHeader as C, CardTitle as w, Input as T, Select as E, SelectContent as D, SelectItem as O, SelectTrigger as te, SelectValue as ne, Textarea as k } from "@burdenoff/fe-libs/ui";
14
+ //#region src/planmagnet/reports/ReportBuilderPage.tsx
15
+ function A(t) {
16
+ if (!e.is(t)) return null;
17
+ let n = t.errors[0], r = n?.extensions?.field;
18
+ return !n || typeof r != "string" || !r ? null : {
19
+ field: r,
20
+ message: n.message
21
+ };
22
+ }
23
+ function j(e) {
24
+ let t = {};
25
+ return e.params.projectId && (t.projectId = e.params.projectId), e.params.sprintId && (t.sprintId = e.params.sprintId), e.params.teamId && (t.teamId = e.params.teamId), e.params.from && (t.from = e.params.from), e.params.to && (t.to = e.params.to), e.params.limit && (t.limit = e.params.limit), {
26
+ id: e.id,
27
+ type: e.type,
28
+ title: e.title,
29
+ source: e.source,
30
+ params: t,
31
+ layout: e.layout
32
+ };
33
+ }
34
+ function M({ mode: e, reportId: d, initial: _ }) {
35
+ let { workspaceId: M } = t(), N = n(), [P, F] = p(_?.name ?? ""), [I, L] = p(_?.description ?? ""), [R, z] = p(_?.visibility ?? "PRIVATE"), [B, V] = p(() => _?.definition.widgets ?? [ee()]), [H, U] = p(!1), [W, G] = p(null), [K, q] = p(null), [J, Y] = g(u), [X, re] = g(f), Z = Y.loading || re.loading, Q = c(B), $ = H && !P.trim() ? "Give this report a name." : null, ie = W ? [...Q, W] : Q, ae = async () => {
36
+ if (U(!0), q(null), G(null), !P.trim() || Q.length > 0) return;
37
+ let t = { widgets: s(B).map(j) };
38
+ try {
39
+ if (e === "create") {
40
+ if (!M) throw Error("No workspace selected.");
41
+ let e = (await i(J({
42
+ variables: {
43
+ workspaceId: M,
44
+ input: {
45
+ name: P.trim(),
46
+ description: I.trim() || null,
47
+ visibility: R,
48
+ definition: t
49
+ }
50
+ },
51
+ context: r
52
+ }))).data?.planmagnetCreateReport?.id;
53
+ e && N(o("/reports/report-page", e));
54
+ } else d && (await i(X({
55
+ variables: {
56
+ id: d,
57
+ input: {
58
+ name: P.trim(),
59
+ description: I.trim() || null,
60
+ visibility: R,
61
+ definition: t
62
+ }
63
+ },
64
+ context: r
65
+ })), N(o("/reports/report-page", d)));
66
+ } catch (e) {
67
+ let t = A(e);
68
+ t ? (G(t), q("Fix the highlighted field and try again.")) : q(e instanceof Error ? e.message : "The report could not be saved.");
69
+ }
70
+ };
71
+ return /* @__PURE__ */ y("div", {
72
+ className: "space-y-6 p-6",
73
+ "data-testid": "report-builder-page",
74
+ children: [
75
+ /* @__PURE__ */ y("div", {
76
+ className: "flex items-center justify-between",
77
+ children: [/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("h1", {
78
+ className: "text-2xl font-semibold",
79
+ children: e === "create" ? "New report" : "Edit report"
80
+ }), /* @__PURE__ */ v("p", {
81
+ className: "text-sm text-muted-foreground",
82
+ children: "Build a report from widgets over your live PlanMagnet data."
83
+ })] }), /* @__PURE__ */ y("div", {
84
+ className: "flex gap-2",
85
+ children: [/* @__PURE__ */ y(b, {
86
+ variant: "outline",
87
+ size: "sm",
88
+ onClick: () => N(e === "edit" && d ? o("/reports/report-page", d) : "/reports/reports-page"),
89
+ children: [/* @__PURE__ */ v(h, { className: "mr-1 h-4 w-4" }), "Cancel"]
90
+ }), /* @__PURE__ */ y(b, {
91
+ size: "sm",
92
+ onClick: () => void ae(),
93
+ disabled: Z,
94
+ "data-testid": "report-save",
95
+ children: [/* @__PURE__ */ v(m, { className: "mr-1 h-4 w-4" }), Z ? "Saving…" : "Save report"]
96
+ })]
97
+ })]
98
+ }),
99
+ /* @__PURE__ */ y(x, { children: [/* @__PURE__ */ v(C, { children: /* @__PURE__ */ v(w, { children: "Details" }) }), /* @__PURE__ */ y(S, {
100
+ className: "space-y-4",
101
+ children: [
102
+ /* @__PURE__ */ y("div", { children: [
103
+ /* @__PURE__ */ v("label", {
104
+ htmlFor: "report-name",
105
+ className: "text-sm font-medium",
106
+ children: "Name"
107
+ }),
108
+ /* @__PURE__ */ v(T, {
109
+ id: "report-name",
110
+ className: "mt-1",
111
+ value: P,
112
+ onChange: (e) => F(e.target.value),
113
+ "aria-invalid": !!$
114
+ }),
115
+ $ && /* @__PURE__ */ v("p", {
116
+ className: "mt-1 text-xs text-destructive",
117
+ children: $
118
+ })
119
+ ] }),
120
+ /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
121
+ htmlFor: "report-description",
122
+ className: "text-sm font-medium",
123
+ children: "Description"
124
+ }), /* @__PURE__ */ v(k, {
125
+ id: "report-description",
126
+ className: "mt-1",
127
+ value: I,
128
+ onChange: (e) => L(e.target.value),
129
+ placeholder: "What does this report show, and who is it for?"
130
+ })] }),
131
+ /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
132
+ htmlFor: "report-visibility",
133
+ className: "text-sm font-medium",
134
+ children: "Visibility"
135
+ }), /* @__PURE__ */ y(E, {
136
+ value: R,
137
+ onValueChange: (e) => z(e),
138
+ children: [/* @__PURE__ */ v(te, {
139
+ id: "report-visibility",
140
+ className: "mt-1 w-64",
141
+ children: /* @__PURE__ */ v(ne, {})
142
+ }), /* @__PURE__ */ y(D, { children: [/* @__PURE__ */ v(O, {
143
+ value: "PRIVATE",
144
+ children: "Private — only me"
145
+ }), /* @__PURE__ */ v(O, {
146
+ value: "WORKSPACE",
147
+ children: "Workspace — everyone can view"
148
+ })] })]
149
+ })] })
150
+ ]
151
+ })] }),
152
+ /* @__PURE__ */ v(x, { children: /* @__PURE__ */ v(S, {
153
+ className: "pt-6",
154
+ children: /* @__PURE__ */ v(l, {
155
+ widgets: B,
156
+ onChange: V,
157
+ errors: ie
158
+ })
159
+ }) }),
160
+ K && /* @__PURE__ */ v(a, { message: K })
161
+ ]
162
+ });
163
+ }
164
+ function N({ mode: e, reportId: t }) {
165
+ let r = n(), i = _(d, {
166
+ variables: { id: t ?? "" },
167
+ skip: e !== "edit" || !t
168
+ });
169
+ if (e === "create") return /* @__PURE__ */ v(M, {
170
+ mode: "create",
171
+ initial: null
172
+ });
173
+ if (i.loading && !i.data) return /* @__PURE__ */ v("div", {
174
+ className: "flex items-center justify-center p-12",
175
+ children: /* @__PURE__ */ v("div", { className: "h-8 w-8 animate-spin rounded-full border-2 border-primary border-t-transparent" })
176
+ });
177
+ let a = i.data?.planmagnetReport;
178
+ return a ? /* @__PURE__ */ v(M, {
179
+ mode: "edit",
180
+ reportId: t,
181
+ initial: a
182
+ }, a.id) : /* @__PURE__ */ y("div", {
183
+ className: "space-y-3 p-6",
184
+ children: [/* @__PURE__ */ v("p", {
185
+ className: "text-sm text-muted-foreground",
186
+ children: "This report does not exist, or you do not have access to it."
187
+ }), /* @__PURE__ */ v(b, {
188
+ size: "sm",
189
+ variant: "outline",
190
+ onClick: () => r("/reports/reports-page"),
191
+ children: "Back to reports"
192
+ })]
193
+ });
194
+ }
195
+ //#endregion
196
+ export { N as ReportBuilderPage };
197
+
198
+ //# sourceMappingURL=ReportBuilderPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReportBuilderPage.js","names":[],"sources":["../../../src/planmagnet/reports/ReportBuilderPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { CombinedGraphQLErrors } from '@apollo/client/errors';\nimport {\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Input,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\nimport { Save, X } from 'lucide-react';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { detailPath } from '../utils/rowNavigation';\nimport { ErrorLine } from '../controls/ConfirmButton';\nimport { LEAVES_PAGE_CONTEXT, throwOnError } from '../utils/mutationResult';\nimport { ReportBuilderCanvas } from './ReportBuilderCanvas';\nimport { CREATE_REPORT, GET_REPORT, UPDATE_REPORT } from './reportGraphql';\nimport {\n blankWidget,\n repackWidgets,\n validateReportDraft,\n type FieldError,\n type ReportRecord,\n type ReportVisibility,\n type ReportWidget,\n} from './reportModel';\n\n/**\n * The report builder (ANR-13): name/description/visibility + the widget grid canvas, shared between create\n * (`ReportsCreateReportPagePage.tsx`, no report yet) and edit (`ReportsEditReportPagePage.tsx`, an existing\n * `id`). A server `BAD_USER_INPUT` this form's own `validateReportDraft` didn't already catch still lands on\n * the right field — `serverFieldError` reads its `extensions.field`, which matches\n * `definition.widgets[i].…` exactly as `report-definition.ts` sets it.\n *\n * `ReportBuilderPage` only loads data (and shows the first-load/not-found states); `ReportBuilderForm` is\n * mounted exactly once real initial data exists (`initial: ReportRecord | null` — always non-null before mount\n * in edit mode) and seeds every field from it via a lazy `useState` initializer, never an effect: there is\n * nothing to resynchronize afterwards; an in-cache `GET_REPORT` refetch while the user is mid-edit must not\n * stomp their unsaved changes, which an effect keyed on the query result would risk doing.\n */\n\nfunction serverFieldError(error: unknown): FieldError | null {\n if (!CombinedGraphQLErrors.is(error)) return null;\n const first = error.errors[0];\n const field = first?.extensions?.field;\n if (!first || typeof field !== 'string' || !field) return null;\n return { field, message: first.message };\n}\n\nfunction toWidgetInput(widget: ReportWidget) {\n const params: Record<string, string | number> = {};\n if (widget.params.projectId) params.projectId = widget.params.projectId;\n if (widget.params.sprintId) params.sprintId = widget.params.sprintId;\n if (widget.params.teamId) params.teamId = widget.params.teamId;\n if (widget.params.from) params.from = widget.params.from;\n if (widget.params.to) params.to = widget.params.to;\n if (widget.params.limit) params.limit = widget.params.limit;\n return {\n id: widget.id,\n type: widget.type,\n title: widget.title,\n source: widget.source,\n params,\n layout: widget.layout,\n };\n}\n\nfunction ReportBuilderForm({\n mode,\n reportId,\n initial,\n}: {\n mode: 'create' | 'edit';\n reportId?: string;\n initial: ReportRecord | null;\n}) {\n const { workspaceId } = usePlanMagnet();\n const navigate = usePlanMagnetNavigate();\n\n const [name, setName] = useState(initial?.name ?? '');\n const [description, setDescription] = useState(initial?.description ?? '');\n const [visibility, setVisibility] = useState<ReportVisibility>(initial?.visibility ?? 'PRIVATE');\n const [widgets, setWidgets] = useState<ReportWidget[]>(\n () => initial?.definition.widgets ?? [blankWidget()]\n );\n const [touched, setTouched] = useState(false);\n const [serverError, setServerError] = useState<FieldError | null>(null);\n const [saveError, setSaveError] = useState<string | null>(null);\n\n const [createReport, createState] = useMutation(CREATE_REPORT);\n const [updateReport, updateState] = useMutation(UPDATE_REPORT);\n const saving = createState.loading || updateState.loading;\n\n const draftErrors = validateReportDraft(widgets);\n const nameError = touched && !name.trim() ? 'Give this report a name.' : null;\n const allErrors = serverError ? [...draftErrors, serverError] : draftErrors;\n\n const handleSave = async () => {\n setTouched(true);\n setSaveError(null);\n setServerError(null);\n if (!name.trim() || draftErrors.length > 0) return;\n const definition = { widgets: repackWidgets(widgets).map(toWidgetInput) };\n try {\n if (mode === 'create') {\n if (!workspaceId) throw new Error('No workspace selected.');\n const result = await throwOnError(\n createReport({\n variables: {\n workspaceId,\n input: {\n name: name.trim(),\n description: description.trim() || null,\n visibility,\n definition,\n },\n },\n context: LEAVES_PAGE_CONTEXT,\n })\n );\n const id = (result.data as { planmagnetCreateReport?: { id: string } } | undefined)\n ?.planmagnetCreateReport?.id;\n if (id) navigate(detailPath('/reports/report-page', id));\n } else if (reportId) {\n await throwOnError(\n updateReport({\n variables: {\n id: reportId,\n input: {\n name: name.trim(),\n description: description.trim() || null,\n visibility,\n definition,\n },\n },\n context: LEAVES_PAGE_CONTEXT,\n })\n );\n navigate(detailPath('/reports/report-page', reportId));\n }\n } catch (e) {\n const field = serverFieldError(e);\n if (field) {\n setServerError(field);\n setSaveError('Fix the highlighted field and try again.');\n } else {\n setSaveError(e instanceof Error ? e.message : 'The report could not be saved.');\n }\n }\n };\n\n const cancel = () =>\n navigate(\n mode === 'edit' && reportId\n ? detailPath('/reports/report-page', reportId)\n : '/reports/reports-page'\n );\n\n return (\n <div className=\"space-y-6 p-6\" data-testid=\"report-builder-page\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n {mode === 'create' ? 'New report' : 'Edit report'}\n </h1>\n <p className=\"text-sm text-muted-foreground\">\n Build a report from widgets over your live PlanMagnet data.\n </p>\n </div>\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={cancel}>\n <X className=\"mr-1 h-4 w-4\" />\n Cancel\n </Button>\n <Button\n size=\"sm\"\n onClick={() => void handleSave()}\n disabled={saving}\n data-testid=\"report-save\"\n >\n <Save className=\"mr-1 h-4 w-4\" />\n {saving ? 'Saving…' : 'Save report'}\n </Button>\n </div>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle>Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label htmlFor=\"report-name\" className=\"text-sm font-medium\">\n Name\n </label>\n <Input\n id=\"report-name\"\n className=\"mt-1\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n aria-invalid={!!nameError}\n />\n {nameError && <p className=\"mt-1 text-xs text-destructive\">{nameError}</p>}\n </div>\n <div>\n <label htmlFor=\"report-description\" className=\"text-sm font-medium\">\n Description\n </label>\n <Textarea\n id=\"report-description\"\n className=\"mt-1\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"What does this report show, and who is it for?\"\n />\n </div>\n <div>\n <label htmlFor=\"report-visibility\" className=\"text-sm font-medium\">\n Visibility\n </label>\n <Select value={visibility} onValueChange={(v) => setVisibility(v as ReportVisibility)}>\n <SelectTrigger id=\"report-visibility\" className=\"mt-1 w-64\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"PRIVATE\">Private — only me</SelectItem>\n <SelectItem value=\"WORKSPACE\">Workspace — everyone can view</SelectItem>\n </SelectContent>\n </Select>\n </div>\n </CardContent>\n </Card>\n\n <Card>\n <CardContent className=\"pt-6\">\n <ReportBuilderCanvas widgets={widgets} onChange={setWidgets} errors={allErrors} />\n </CardContent>\n </Card>\n\n {saveError && <ErrorLine message={saveError} />}\n </div>\n );\n}\n\nexport function ReportBuilderPage({\n mode,\n reportId,\n}: {\n mode: 'create' | 'edit';\n reportId?: string;\n}) {\n const navigate = usePlanMagnetNavigate();\n\n const existing = useQuery<{ planmagnetReport: ReportRecord | null }>(GET_REPORT, {\n variables: { id: reportId ?? '' },\n skip: mode !== 'edit' || !reportId,\n });\n\n if (mode === 'create') {\n return <ReportBuilderForm mode=\"create\" initial={null} />;\n }\n\n // Only before the first load: a refetch must not blank the page.\n if (existing.loading && !existing.data) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <div className=\"h-8 w-8 animate-spin rounded-full border-2 border-primary border-t-transparent\" />\n </div>\n );\n }\n const report = existing.data?.planmagnetReport;\n if (!report) {\n return (\n <div className=\"space-y-3 p-6\">\n <p className=\"text-sm text-muted-foreground\">\n This report does not exist, or you do not have access to it.\n </p>\n <Button size=\"sm\" variant=\"outline\" onClick={() => navigate('/reports/reports-page')}>\n Back to reports\n </Button>\n </div>\n );\n }\n\n // Keyed by id: switching to a different report's edit page (a fresh navigation, not a refetch of this one)\n // mounts a new form with that report's own data, rather than reusing in-progress state from another report.\n return <ReportBuilderForm key={report.id} mode=\"edit\" reportId={reportId} initial={report} />;\n}\n"],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /** Past runs of a report (ANR-15) — a run is a snapshot, so re-opening an older one shows exactly what it
2
+ * showed when it ran, even if the underlying data has since changed. */
3
+ export declare function ReportRunHistory({ reportId, selectedRunId, onSelect, }: {
4
+ reportId: string;
5
+ selectedRunId: string | null;
6
+ onSelect: (runId: string) => void;
7
+ }): import("react/jsx-runtime").JSX.Element;
8
+ //# sourceMappingURL=ReportRunHistory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReportRunHistory.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/reports/ReportRunHistory.tsx"],"names":[],"mappings":"AAeA;yEACyE;AACzE,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,aAAa,EACb,QAAQ,GACT,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC,2CAsDA"}
@@ -0,0 +1,63 @@
1
+ import { PersonName as e } from "../people/People.js";
2
+ import { rowLinkProps as t } from "../utils/rowNavigation.js";
3
+ import { LIST_REPORT_RUNS as n } from "./reportGraphql.js";
4
+ import { History as r } from "lucide-react";
5
+ import { useQuery as i } from "@apollo/client/react";
6
+ import { jsx as a, jsxs as o } from "react/jsx-runtime";
7
+ import { Badge as s } from "@burdenoff/fe-libs/ui";
8
+ //#region src/planmagnet/reports/ReportRunHistory.tsx
9
+ function c({ reportId: c, selectedRunId: l, onSelect: u }) {
10
+ let { data: d, loading: f, error: p } = i(n, { variables: {
11
+ reportId: c,
12
+ pagination: { first: 25 }
13
+ } }), m = d?.planmagnetReportRuns.items ?? [];
14
+ return /* @__PURE__ */ o("div", {
15
+ className: "space-y-2",
16
+ "data-testid": "report-run-history",
17
+ children: [/* @__PURE__ */ o("h2", {
18
+ className: "flex items-center gap-1.5 text-sm font-semibold",
19
+ children: [/* @__PURE__ */ a(r, {
20
+ className: "h-4 w-4",
21
+ "aria-hidden": !0
22
+ }), "Run history"]
23
+ }), f && !d ? /* @__PURE__ */ a("p", {
24
+ className: "text-sm text-muted-foreground",
25
+ children: "Loading…"
26
+ }) : p ? /* @__PURE__ */ a("p", {
27
+ className: "text-sm text-destructive",
28
+ children: "Run history could not be loaded."
29
+ }) : m.length === 0 ? /* @__PURE__ */ a("p", {
30
+ className: "text-sm text-muted-foreground",
31
+ children: "No runs yet."
32
+ }) : /* @__PURE__ */ a("ul", {
33
+ className: "space-y-1",
34
+ children: m.map((n) => {
35
+ let r = n.id === l;
36
+ return /* @__PURE__ */ a("li", { children: /* @__PURE__ */ o("div", {
37
+ ...t(() => u(n.id), `Open run from ${new Date(n.generatedAt).toLocaleString()}`),
38
+ className: `flex items-center justify-between gap-2 rounded-md border p-2 text-xs ${r ? "border-primary bg-primary/5" : "border-border"}`,
39
+ children: [/* @__PURE__ */ o("div", { children: [/* @__PURE__ */ a("p", {
40
+ className: "font-medium",
41
+ children: new Date(n.generatedAt).toLocaleString()
42
+ }), /* @__PURE__ */ o("p", {
43
+ className: "text-muted-foreground",
44
+ children: [
45
+ n.trigger === "SCHEDULE" ? "Scheduled" : "Manual",
46
+ " · by",
47
+ " ",
48
+ /* @__PURE__ */ a(e, { id: n.generatedBy })
49
+ ]
50
+ })] }), n.deliveryStatus === "PENDING_NOTIFICATIONS" && /* @__PURE__ */ a(s, {
51
+ variant: "outline",
52
+ className: "shrink-0 text-[10px]",
53
+ children: "No email yet"
54
+ })]
55
+ }) }, n.id);
56
+ })
57
+ })]
58
+ });
59
+ }
60
+ //#endregion
61
+ export { c as ReportRunHistory };
62
+
63
+ //# sourceMappingURL=ReportRunHistory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReportRunHistory.js","names":[],"sources":["../../../src/planmagnet/reports/ReportRunHistory.tsx"],"sourcesContent":["import { useQuery } from '@apollo/client/react';\nimport { Badge } from '@burdenoff/fe-libs/ui';\nimport { History } from 'lucide-react';\nimport { PersonName } from '../people/People';\nimport { rowLinkProps } from '../utils/rowNavigation';\nimport { LIST_REPORT_RUNS } from './reportGraphql';\n\ninterface RunListItem {\n id: string;\n trigger: 'MANUAL' | 'SCHEDULE';\n generatedAt: string;\n generatedBy: string;\n deliveryStatus: 'PENDING_NOTIFICATIONS' | null;\n}\n\n/** Past runs of a report (ANR-15) — a run is a snapshot, so re-opening an older one shows exactly what it\n * showed when it ran, even if the underlying data has since changed. */\nexport function ReportRunHistory({\n reportId,\n selectedRunId,\n onSelect,\n}: {\n reportId: string;\n selectedRunId: string | null;\n onSelect: (runId: string) => void;\n}) {\n const { data, loading, error } = useQuery<{\n planmagnetReportRuns: { items: RunListItem[]; totalCount: number };\n }>(LIST_REPORT_RUNS, { variables: { reportId, pagination: { first: 25 } } });\n\n const runs = data?.planmagnetReportRuns.items ?? [];\n\n return (\n <div className=\"space-y-2\" data-testid=\"report-run-history\">\n <h2 className=\"flex items-center gap-1.5 text-sm font-semibold\">\n <History className=\"h-4 w-4\" aria-hidden={true} />\n Run history\n </h2>\n {loading && !data ? (\n <p className=\"text-sm text-muted-foreground\">Loading…</p>\n ) : error ? (\n <p className=\"text-sm text-destructive\">Run history could not be loaded.</p>\n ) : runs.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">No runs yet.</p>\n ) : (\n <ul className=\"space-y-1\">\n {runs.map((run) => {\n const selected = run.id === selectedRunId;\n return (\n <li key={run.id}>\n <div\n {...rowLinkProps(\n () => onSelect(run.id),\n `Open run from ${new Date(run.generatedAt).toLocaleString()}`\n )}\n className={`flex items-center justify-between gap-2 rounded-md border p-2 text-xs ${\n selected ? 'border-primary bg-primary/5' : 'border-border'\n }`}\n >\n <div>\n <p className=\"font-medium\">{new Date(run.generatedAt).toLocaleString()}</p>\n <p className=\"text-muted-foreground\">\n {run.trigger === 'SCHEDULE' ? 'Scheduled' : 'Manual'} · by{' '}\n <PersonName id={run.generatedBy} />\n </p>\n </div>\n {run.deliveryStatus === 'PENDING_NOTIFICATIONS' && (\n <Badge variant=\"outline\" className=\"shrink-0 text-[10px]\">\n No email yet\n </Badge>\n )}\n </div>\n </li>\n );\n })}\n </ul>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;AAiBA,SAAgB,EAAiB,EAC/B,aACA,kBACA,eAKC;CACD,IAAM,EAAE,SAAM,YAAS,aAAU,EAE9B,GAAkB,EAAE,WAAW;EAAE;EAAU,YAAY,EAAE,OAAO,IAAI;EAAE,EAAE,CAAC,EAEtE,IAAO,GAAM,qBAAqB,SAAS,EAAE;AAEnD,QACE,kBAAC,OAAD;EAAK,WAAU;EAAY,eAAY;YAAvC,CACE,kBAAC,MAAD;GAAI,WAAU;aAAd,CACE,kBAAC,GAAD;IAAS,WAAU;IAAU,eAAa;IAAQ,CAAA,EAAA,cAE/C;MACJ,KAAW,CAAC,IACX,kBAAC,KAAD;GAAG,WAAU;aAAgC;GAAY,CAAA,GACvD,IACF,kBAAC,KAAD;GAAG,WAAU;aAA2B;GAAoC,CAAA,GAC1E,EAAK,WAAW,IAClB,kBAAC,KAAD;GAAG,WAAU;aAAgC;GAAgB,CAAA,GAE7D,kBAAC,MAAD;GAAI,WAAU;aACX,EAAK,KAAK,MAAQ;IACjB,IAAM,IAAW,EAAI,OAAO;AAC5B,WACE,kBAAC,MAAD,EAAA,UACE,kBAAC,OAAD;KACE,GAAI,QACI,EAAS,EAAI,GAAG,EACtB,iBAAiB,IAAI,KAAK,EAAI,YAAY,CAAC,gBAAgB,GAC5D;KACD,WAAW,yEACT,IAAW,gCAAgC;eAN/C,CASE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;MAAG,WAAU;gBAAe,IAAI,KAAK,EAAI,YAAY,CAAC,gBAAgB;MAAK,CAAA,EAC3E,kBAAC,KAAD;MAAG,WAAU;gBAAb;OACG,EAAI,YAAY,aAAa,cAAc;OAAS;OAAM;OAC3D,kBAAC,GAAD,EAAY,IAAI,EAAI,aAAe,CAAA;OACjC;QACA,EAAA,CAAA,EACL,EAAI,mBAAmB,2BACtB,kBAAC,GAAD;MAAO,SAAQ;MAAU,WAAU;gBAAuB;MAElD,CAAA,CAEN;QACH,EAvBI,EAAI,GAuBR;KAEP;GACC,CAAA,CAEH"}
@@ -0,0 +1,7 @@
1
+ import { ReportWidget, WidgetRunResult } from './reportModel';
2
+
3
+ export declare function ReportWidgetRenderer({ widget, runResult, }: {
4
+ widget: ReportWidget;
5
+ runResult: WidgetRunResult | undefined;
6
+ }): import("react/jsx-runtime").JSX.Element | null;
7
+ //# sourceMappingURL=ReportWidgetRenderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReportWidgetRenderer.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/reports/ReportWidgetRenderer.tsx"],"names":[],"mappings":"AAqBA,OAAO,EAML,KAAK,YAAY,EAEjB,KAAK,eAAe,EACrB,MAAM,eAAe,CAAC;AAkRvB,wBAAgB,oBAAoB,CAAC,EACnC,MAAM,EACN,SAAS,GACV,EAAE;IACD,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,EAAE,eAAe,GAAG,SAAS,CAAC;CACxC,kDAkDA"}