@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.
- package/dist/_virtual/__vite-browser-external.js +9 -0
- package/dist/_virtual/__vite-browser-external.js.map +1 -0
- package/dist/_virtual/_rolldown/runtime.js +5 -2
- package/dist/index.js +3 -1
- package/dist/node_modules/fflate/esm/browser.js +554 -0
- package/dist/node_modules/fflate/esm/browser.js.map +1 -0
- package/dist/node_modules/jszip/dist/jszip.min.js +3038 -0
- package/dist/node_modules/jszip/dist/jszip.min.js.map +1 -0
- package/dist/node_modules/pptxgenjs/dist/pptxgen.es.js +2151 -0
- package/dist/node_modules/pptxgenjs/dist/pptxgen.es.js.map +1 -0
- package/dist/node_modules/write-excel-file/browser/index.js +3 -0
- package/dist/node_modules/write-excel-file/modules/export/convertFileContentToUint8ArrayBrowser.js +13 -0
- package/dist/node_modules/write-excel-file/modules/export/convertFileContentToUint8ArrayBrowser.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/export/convertFilesContentToUint8Arrays.js +21 -0
- package/dist/node_modules/write-excel-file/modules/export/convertFilesContentToUint8Arrays.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/export/downloadBlob.js +11 -0
- package/dist/node_modules/write-excel-file/modules/export/downloadBlob.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/export/writeXlsxFileBrowser.js +23 -0
- package/dist/node_modules/write-excel-file/modules/export/writeXlsxFileBrowser.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/export/writeXlsxFileUniversal.js +22 -0
- package/dist/node_modules/write-excel-file/modules/export/writeXlsxFileUniversal.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/getSheetData/getSheetData.js +18 -0
- package/dist/node_modules/write-excel-file/modules/getSheetData/getSheetData.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/features/conditionalFormatting.js +131 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/features/conditionalFormatting.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/features/images.js +188 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/features/images.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/features/stickyRowsOrColumns.js +52 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/features/stickyRowsOrColumns.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/_Content_Types_.xml.js +18 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/_Content_Types_.xml.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/drawing.xml.js +18 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/drawing.xml.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/drawing.xml.rels.js +17 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/drawing.xml.rels.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/rels.js +11 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/rels.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sharedStrings.xml.js +42 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sharedStrings.xml.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/cell.js +102 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/cell.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/column.js +17 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/column.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/columns.js +15 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/columns.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/drawingReference.js +8 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/drawingReference.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/helpers/getCellStyleProperties.js +71 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/helpers/getCellStyleProperties.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/mergedCellsDescription.js +56 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/mergedCellsDescription.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/pageMargins.js +15 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/pageMargins.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/pageSetup.js +13 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/pageSetup.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/processMergedCells.js +44 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/processMergedCells.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/row.js +123 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/row.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/sheet.xml.js +41 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/sheet.xml.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/sheetData.js +11 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/sheetData.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/sheetViews.js +17 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/sheetViews.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml.rels.js +20 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml.rels.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/styles.xml.js +77 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/styles.xml.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/workbook.xml.js +22 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/workbook.xml.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/workbook.xml.rels.js +13 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/workbook.xml.rels.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/generateXlsxFileContents.js +242 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/generateXlsxFileContents.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/getFeatures.js +29 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/getFeatures.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/convertDateToSerialNumber.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/convertDateToSerialNumber.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/features/getAdditionalContent.js +42 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/features/getAdditionalContent.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/features/getElementXml.js +43 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/features/getElementXml.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/features/getWrittenFiles.js +93 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/features/getWrittenFiles.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/features/transformContent.js +39 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/features/transformContent.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getAlignmentXml.js +17 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getAlignmentXml.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getBorderXml.js +29 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getBorderXml.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getCellAddress.js +14 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getCellAddress.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getFileExtensionForContentType.js +11 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getFileExtensionForContentType.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getFillXml.js +14 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getFillXml.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getFontXml.js +12 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getFontXml.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getOrderOfSiblings.js +24 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getOrderOfSiblings.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getXlsxColorForHexColor.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getXlsxColorForHexColor.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/hasAlignment.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/hasAlignment.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/hasBorder.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/hasBorder.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/hasFill.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/hasFill.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/hasFont.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/hasFont.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/isCellObject.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/isCellObject.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/isObject.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/isObject.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/orderOfSiblings.js +27 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/orderOfSiblings.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/initializeSharedStrings.js +17 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/initializeSharedStrings.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/initializeSheets.js +74 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/initializeSheets.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/initializeStyles.js +138 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/initializeStyles.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/validateSheetData.js +40 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/validateSheetData.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/validateSheetName.js +11 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/validateSheetName.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/appendMarkupInsideElement.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xml/appendMarkupInsideElement.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/applyEnclosingElementOffset.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xml/applyEnclosingElementOffset.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/escapeXmlSpecialCharacters.js +12 -0
- package/dist/node_modules/write-excel-file/modules/xml/escapeXmlSpecialCharacters.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/findElement.js +12 -0
- package/dist/node_modules/write-excel-file/modules/xml/findElement.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/findElementInsideElement.js +12 -0
- package/dist/node_modules/write-excel-file/modules/xml/findElementInsideElement.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/findElementsNonRecursive_.js +41 -0
- package/dist/node_modules/write-excel-file/modules/xml/findElementsNonRecursive_.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/getAttributesString.js +14 -0
- package/dist/node_modules/write-excel-file/modules/xml/getAttributesString.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/getChildElements.js +42 -0
- package/dist/node_modules/write-excel-file/modules/xml/getChildElements.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/getClosingTagMarkup.js +8 -0
- package/dist/node_modules/write-excel-file/modules/xml/getClosingTagMarkup.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/getMarkupInsideElement.js +8 -0
- package/dist/node_modules/write-excel-file/modules/xml/getMarkupInsideElement.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/getOpeningTagMarkup.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xml/getOpeningTagMarkup.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/getSelfClosingTagMarkup.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xml/getSelfClosingTagMarkup.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/insertElementMarkupAccordingToOrderOfSiblings.js +64 -0
- package/dist/node_modules/write-excel-file/modules/xml/insertElementMarkupAccordingToOrderOfSiblings.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/prependMarkupInsideElement.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xml/prependMarkupInsideElement.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/removeInvalidXmlCharacters.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xml/removeInvalidXmlCharacters.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/replaceElement.js +8 -0
- package/dist/node_modules/write-excel-file/modules/xml/replaceElement.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/sanitizeAttributeName.js +10 -0
- package/dist/node_modules/write-excel-file/modules/xml/sanitizeAttributeName.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/sanitizeAttributeValue.js +11 -0
- package/dist/node_modules/write-excel-file/modules/xml/sanitizeAttributeValue.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/sanitizeTextContent.js +11 -0
- package/dist/node_modules/write-excel-file/modules/xml/sanitizeTextContent.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/setMarkupInsideElement.js +8 -0
- package/dist/node_modules/write-excel-file/modules/xml/setMarkupInsideElement.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/zip/zipToArrayBuffer.js +18 -0
- package/dist/node_modules/write-excel-file/modules/zip/zipToArrayBuffer.js.map +1 -0
- package/dist/planmagnet/PlanMagnetRoot.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoot.js +154 -147
- package/dist/planmagnet/PlanMagnetRoot.js.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.js +122 -106
- package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
- package/dist/planmagnet/comments/CommentThread.d.ts +8 -1
- package/dist/planmagnet/comments/CommentThread.d.ts.map +1 -1
- package/dist/planmagnet/comments/CommentThread.js +188 -181
- package/dist/planmagnet/comments/CommentThread.js.map +1 -1
- package/dist/planmagnet/comments/TargetComments.d.ts +10 -2
- package/dist/planmagnet/comments/TargetComments.d.ts.map +1 -1
- package/dist/planmagnet/comments/TargetComments.js +10 -8
- package/dist/planmagnet/comments/TargetComments.js.map +1 -1
- package/dist/planmagnet/comments/WorkItemComments.d.ts +7 -1
- package/dist/planmagnet/comments/WorkItemComments.d.ts.map +1 -1
- package/dist/planmagnet/comments/WorkItemComments.js +5 -4
- package/dist/planmagnet/comments/WorkItemComments.js.map +1 -1
- package/dist/planmagnet/controls/Pickers.d.ts +10 -0
- package/dist/planmagnet/controls/Pickers.d.ts.map +1 -1
- package/dist/planmagnet/controls/Pickers.js +75 -27
- package/dist/planmagnet/controls/Pickers.js.map +1 -1
- package/dist/planmagnet/discussion/WorkItemDiscussionPanel.d.ts +8 -0
- package/dist/planmagnet/discussion/WorkItemDiscussionPanel.d.ts.map +1 -0
- package/dist/planmagnet/discussion/WorkItemDiscussionPanel.js +217 -0
- package/dist/planmagnet/discussion/WorkItemDiscussionPanel.js.map +1 -0
- package/dist/planmagnet/docs/DocDiffView.d.ts +26 -0
- package/dist/planmagnet/docs/DocDiffView.d.ts.map +1 -0
- package/dist/planmagnet/docs/DocDiffView.js +52 -0
- package/dist/planmagnet/docs/DocDiffView.js.map +1 -0
- package/dist/planmagnet/docs/DocSuggestionsPanel.d.ts +13 -0
- package/dist/planmagnet/docs/DocSuggestionsPanel.d.ts.map +1 -0
- package/dist/planmagnet/docs/DocSuggestionsPanel.js +308 -0
- package/dist/planmagnet/docs/DocSuggestionsPanel.js.map +1 -0
- package/dist/planmagnet/docs/DocVersionCompare.d.ts +7 -0
- package/dist/planmagnet/docs/DocVersionCompare.d.ts.map +1 -0
- package/dist/planmagnet/docs/DocVersionCompare.js +105 -0
- package/dist/planmagnet/docs/DocVersionCompare.js.map +1 -0
- package/dist/planmagnet/hooks/usePresence.d.ts +39 -0
- package/dist/planmagnet/hooks/usePresence.d.ts.map +1 -0
- package/dist/planmagnet/hooks/usePresence.js +146 -0
- package/dist/planmagnet/hooks/usePresence.js.map +1 -0
- package/dist/planmagnet/index.d.ts +2 -0
- package/dist/planmagnet/index.d.ts.map +1 -1
- package/dist/planmagnet/index.js +2 -0
- package/dist/planmagnet/links/CodeLinksPanel.d.ts +22 -0
- package/dist/planmagnet/links/CodeLinksPanel.d.ts.map +1 -0
- package/dist/planmagnet/links/CodeLinksPanel.js +94 -0
- package/dist/planmagnet/links/CodeLinksPanel.js.map +1 -0
- package/dist/planmagnet/pages/DocsDocDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/DocsDocDetailPagePage.js +488 -217
- package/dist/planmagnet/pages/DocsDocDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js +136 -130
- package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js +205 -196
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ReportsCreateReportPagePage.d.ts +6 -0
- package/dist/planmagnet/pages/ReportsCreateReportPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ReportsCreateReportPagePage.js +5 -177
- package/dist/planmagnet/pages/ReportsCreateReportPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ReportsEditReportPagePage.d.ts +3 -0
- package/dist/planmagnet/pages/ReportsEditReportPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ReportsEditReportPagePage.js +15 -0
- package/dist/planmagnet/pages/ReportsEditReportPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ReportsReportPagePage.d.ts +7 -0
- package/dist/planmagnet/pages/ReportsReportPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ReportsReportPagePage.js +226 -0
- package/dist/planmagnet/pages/ReportsReportPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ReportsReportsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ReportsReportsPagePage.js +224 -496
- package/dist/planmagnet/pages/ReportsReportsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.js +194 -160
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.js.map +1 -1
- package/dist/planmagnet/presence/PresenceAvatars.d.ts +16 -0
- package/dist/planmagnet/presence/PresenceAvatars.d.ts.map +1 -0
- package/dist/planmagnet/presence/PresenceAvatars.js +56 -0
- package/dist/planmagnet/presence/PresenceAvatars.js.map +1 -0
- package/dist/planmagnet/reports/ExportMenu.d.ts +9 -0
- package/dist/planmagnet/reports/ExportMenu.d.ts.map +1 -0
- package/dist/planmagnet/reports/ExportMenu.js +116 -0
- package/dist/planmagnet/reports/ExportMenu.js.map +1 -0
- package/dist/planmagnet/reports/PrintReportView.d.ts +24 -0
- package/dist/planmagnet/reports/PrintReportView.d.ts.map +1 -0
- package/dist/planmagnet/reports/PrintReportView.js +75 -0
- package/dist/planmagnet/reports/PrintReportView.js.map +1 -0
- package/dist/planmagnet/reports/ReportBuilderCanvas.d.ts +8 -0
- package/dist/planmagnet/reports/ReportBuilderCanvas.d.ts.map +1 -0
- package/dist/planmagnet/reports/ReportBuilderCanvas.js +261 -0
- package/dist/planmagnet/reports/ReportBuilderCanvas.js.map +1 -0
- package/dist/planmagnet/reports/ReportBuilderPage.d.ts +5 -0
- package/dist/planmagnet/reports/ReportBuilderPage.d.ts.map +1 -0
- package/dist/planmagnet/reports/ReportBuilderPage.js +198 -0
- package/dist/planmagnet/reports/ReportBuilderPage.js.map +1 -0
- package/dist/planmagnet/reports/ReportRunHistory.d.ts +8 -0
- package/dist/planmagnet/reports/ReportRunHistory.d.ts.map +1 -0
- package/dist/planmagnet/reports/ReportRunHistory.js +63 -0
- package/dist/planmagnet/reports/ReportRunHistory.js.map +1 -0
- package/dist/planmagnet/reports/ReportWidgetRenderer.d.ts +7 -0
- package/dist/planmagnet/reports/ReportWidgetRenderer.d.ts.map +1 -0
- package/dist/planmagnet/reports/ReportWidgetRenderer.js +251 -0
- package/dist/planmagnet/reports/ReportWidgetRenderer.js.map +1 -0
- package/dist/planmagnet/reports/SchedulesPanel.d.ts +4 -0
- package/dist/planmagnet/reports/SchedulesPanel.d.ts.map +1 -0
- package/dist/planmagnet/reports/SchedulesPanel.js +457 -0
- package/dist/planmagnet/reports/SchedulesPanel.js.map +1 -0
- package/dist/planmagnet/reports/ShareDialog.d.ts +5 -0
- package/dist/planmagnet/reports/ShareDialog.d.ts.map +1 -0
- package/dist/planmagnet/reports/ShareDialog.js +234 -0
- package/dist/planmagnet/reports/ShareDialog.js.map +1 -0
- package/dist/planmagnet/reports/SharedReportPage.d.ts +4 -0
- package/dist/planmagnet/reports/SharedReportPage.d.ts.map +1 -0
- package/dist/planmagnet/reports/SharedReportPage.js +180 -0
- package/dist/planmagnet/reports/SharedReportPage.js.map +1 -0
- package/dist/planmagnet/reports/WidgetEditorDialog.d.ts +10 -0
- package/dist/planmagnet/reports/WidgetEditorDialog.d.ts.map +1 -0
- package/dist/planmagnet/reports/WidgetEditorDialog.js +220 -0
- package/dist/planmagnet/reports/WidgetEditorDialog.js.map +1 -0
- package/dist/planmagnet/reports/reportExportPptx.d.ts +4 -0
- package/dist/planmagnet/reports/reportExportPptx.d.ts.map +1 -0
- package/dist/planmagnet/reports/reportExportPptx.js +118 -0
- package/dist/planmagnet/reports/reportExportPptx.js.map +1 -0
- package/dist/planmagnet/reports/reportExportXlsx.d.ts +4 -0
- package/dist/planmagnet/reports/reportExportXlsx.d.ts.map +1 -0
- package/dist/planmagnet/reports/reportExportXlsx.js +42 -0
- package/dist/planmagnet/reports/reportExportXlsx.js.map +1 -0
- package/dist/planmagnet/reports/reportGraphql.d.ts +28 -0
- package/dist/planmagnet/reports/reportGraphql.d.ts.map +1 -0
- package/dist/planmagnet/reports/reportGraphql.js +360 -0
- package/dist/planmagnet/reports/reportGraphql.js.map +1 -0
- package/dist/planmagnet/reports/reportModel.d.ts +198 -0
- package/dist/planmagnet/reports/reportModel.d.ts.map +1 -0
- package/dist/planmagnet/reports/reportModel.js +328 -0
- package/dist/planmagnet/reports/reportModel.js.map +1 -0
- package/dist/planmagnet/reports/sharedReportRoute.d.ts +14 -0
- package/dist/planmagnet/reports/sharedReportRoute.d.ts.map +1 -0
- package/dist/planmagnet/reports/sharedReportRoute.js +9 -0
- package/dist/planmagnet/reports/sharedReportRoute.js.map +1 -0
- package/dist/planmagnet/utils/graphqlErrors.d.ts +6 -0
- package/dist/planmagnet/utils/graphqlErrors.d.ts.map +1 -1
- package/dist/planmagnet/utils/graphqlErrors.js +5 -2
- package/dist/planmagnet/utils/graphqlErrors.js.map +1 -1
- package/dist/planmagnet/utils/lineDiff.d.ts +21 -0
- package/dist/planmagnet/utils/lineDiff.d.ts.map +1 -0
- package/dist/planmagnet/utils/lineDiff.js +36 -0
- package/dist/planmagnet/utils/lineDiff.js.map +1 -0
- package/package.json +6 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TasksTaskDetailPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/TasksTaskDetailPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { throwOnError } from '../utils/mutationResult';\nimport { WorkItemComments } from '../comments/WorkItemComments';\nimport { WorkItemActivity } from '../comments/WorkItemActivity';\nimport { TaskTimePanel } from '../time/TaskTimePanel';\nimport { PersonName } from '../people/People';\nimport { DocSearchSelect } from '../controls/Pickers';\nimport { CustomFieldsPanel } from '../controls/CustomFieldValuesPanel';\nimport { DependencyPanel } from '../dependency/DependencyPanel';\nimport { IssueLinksPanel } from '../links/IssueLinksPanel';\nimport { WorkItemMilestoneSelect } from '../milestones/MilestoneControls';\nimport {\n WORK_ITEM_PRIORITIES,\n WorkItemStatusSelect,\n WorkItemAssigneeSelect,\n WorkItemEnumSelect,\n WorkItemHeaderActions,\n} from '../controls/WorkItemControls';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport {\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Badge,\n Button,\n Input,\n} from '@burdenoff/fe-libs/ui';\nimport { FileText, Link2, Plus, X } from 'lucide-react';\nimport { MarkdownEditor } from '#src/components/MarkdownEditor';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\n\nconst GET_WORK_ITEM = gql`\n query GetWorkItemDetail($workItemId: ID!) {\n planmagnetWorkItem(id: $workItemId) {\n id\n projectId\n title\n description\n type\n status\n priority\n key\n assigneeId\n reporterId\n createdBy\n sprintId\n milestoneId\n storyPoints\n estimateMinutes\n dueDate\n labels\n tags\n createdAt\n updatedAt\n customFieldValues {\n id\n definitionId\n value\n }\n }\n }\n`;\n\nconst GET_WORK_ITEM_DOCS = gql`\n query GetWorkItemDocs($workItemId: ID!) {\n planmagnetWorkItemDocs(workItemId: $workItemId) {\n id\n title\n status\n version\n updatedAt\n }\n }\n`;\n\nconst CREATE_DOC = gql`\n mutation CreateDocForWorkItem($input: PlanmagnetCreateDocInput!) {\n planmagnetCreateDoc(input: $input) {\n id\n }\n }\n`;\n\nconst LINK_DOC_TO_WORK_ITEM = gql`\n mutation LinkDocToWorkItem($docId: ID!, $workItemId: ID!) {\n planmagnetLinkDocToWorkItem(docId: $docId, workItemId: $workItemId) {\n id\n }\n }\n`;\n\nconst UNLINK_DOC_FROM_WORK_ITEM = gql`\n mutation UnlinkDocFromWorkItem($docId: ID!, $workItemId: ID!) {\n planmagnetUnlinkDocFromWorkItem(docId: $docId, workItemId: $workItemId)\n }\n`;\n\ninterface WorkItemNode {\n id: string;\n title: string;\n description: string | null;\n type: string;\n status: string;\n priority: string;\n key: string;\n assigneeId: string | null;\n reporterId: string | null;\n createdBy: string;\n sprintId: string | null;\n milestoneId: string | null;\n storyPoints: number | null;\n estimateMinutes: number | null;\n dueDate: string | null;\n labels: string[];\n tags: string[];\n createdAt: string;\n updatedAt: string;\n customFieldValues: { id: string; definitionId: string; value: unknown }[];\n}\n\ninterface WorkItemDocNode {\n id: string;\n title: string;\n status: string;\n version: number;\n updatedAt: string;\n}\n\nconst docStatusColor: Record<string, string> = {\n DRAFT: 'bg-gray-100 text-gray-800',\n PUBLISHED: 'bg-green-100 text-green-800',\n ARCHIVED: 'bg-gray-100 text-gray-500',\n};\n\n/**\n * Linked-docs panel (BOFF-4443): create a doc and link it to this work item\n * in one action, view currently-linked docs, and unlink one. Reads/writes go\n * through the real planmagnetWorkItemDocs / planmagnetCreateDoc /\n * planmagnetLinkDocToWorkItem / planmagnetUnlinkDocFromWorkItem GraphQL\n * fields — no fabricated data. Full doc editing (revisions, revert) lives on\n * a dedicated doc detail view; this panel is scoped to linking.\n */\nfunction LinkedDocsPanel({ workItemId }: { workItemId: string }) {\n const navigate = usePlanMagnetNavigate();\n const [isComposing, setIsComposing] = useState(false);\n // BOFF-7961: only \"New Doc\" existed, so a doc written on the Docs page could never be linked to a task.\n const [isLinking, setIsLinking] = useState(false);\n const [existingDocId, setExistingDocId] = useState('');\n const [newTitle, setNewTitle] = useState('');\n const [newContent, setNewContent] = useState('');\n\n const { data, loading, error, refetch } = useQuery<{\n planmagnetWorkItemDocs: WorkItemDocNode[];\n }>(GET_WORK_ITEM_DOCS, {\n variables: { workItemId },\n skip: !workItemId,\n });\n\n const [createDoc, { loading: creating }] = useMutation(CREATE_DOC);\n const [linkDoc, { loading: linking }] = useMutation(LINK_DOC_TO_WORK_ITEM);\n const [unlinkDoc, { loading: unlinking }] = useMutation(UNLINK_DOC_FROM_WORK_ITEM);\n // A refused mutation resolves with { error } (fe-libs errorPolicy 'all');\n // the composer used to clear itself as if the doc had been saved.\n const [actionError, setActionError] = useState<string | null>(null);\n\n const docs = data?.planmagnetWorkItemDocs ?? [];\n\n const handleCreateAndLink = async () => {\n if (!newTitle.trim() || !newContent.trim()) return;\n setActionError(null);\n try {\n const result = await throwOnError(\n createDoc({ variables: { input: { title: newTitle.trim(), content: newContent.trim() } } })\n );\n const docId = result.data?.planmagnetCreateDoc?.id;\n if (docId) {\n await throwOnError(linkDoc({ variables: { docId, workItemId } }));\n }\n } catch (e) {\n setActionError(e instanceof Error ? e.message : 'The doc could not be saved.');\n return;\n }\n setNewTitle('');\n setNewContent('');\n setIsComposing(false);\n void refetch();\n };\n\n const handleLinkExisting = async () => {\n if (!existingDocId) return;\n setActionError(null);\n try {\n await throwOnError(linkDoc({ variables: { docId: existingDocId, workItemId } }));\n } catch (e) {\n setActionError(e instanceof Error ? e.message : 'The doc could not be linked.');\n return;\n }\n setExistingDocId('');\n setIsLinking(false);\n void refetch();\n };\n\n const handleUnlink = async (docId: string) => {\n setActionError(null);\n try {\n await throwOnError(unlinkDoc({ variables: { docId, workItemId } }));\n } catch (e) {\n setActionError(e instanceof Error ? e.message : 'The doc could not be unlinked.');\n return;\n }\n void refetch();\n };\n\n return (\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0\">\n <CardTitle>Linked Docs</CardTitle>\n {!isComposing && !isLinking && (\n <div className=\"flex gap-2\">\n <Button size=\"sm\" variant=\"outline\" onClick={() => setIsLinking(true)}>\n <Link2 className=\"h-4 w-4 mr-1\" />\n Link existing doc\n </Button>\n <Button size=\"sm\" variant=\"outline\" onClick={() => setIsComposing(true)}>\n <Plus className=\"h-4 w-4 mr-1\" />\n New Doc\n </Button>\n </div>\n )}\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {isLinking && (\n <div className=\"space-y-2 rounded-md border border-input p-3\">\n <DocSearchSelect\n id=\"task-link-doc\"\n value={existingDocId}\n onChange={setExistingDocId}\n exclude={docs.map((d) => d.id)}\n />\n <div className=\"flex gap-2 justify-end\">\n <Button\n size=\"sm\"\n variant=\"ghost\"\n onClick={() => {\n setIsLinking(false);\n setExistingDocId('');\n }}\n >\n Cancel\n </Button>\n <Button size=\"sm\" disabled={!existingDocId || linking} onClick={handleLinkExisting}>\n {linking ? 'Linking...' : 'Link'}\n </Button>\n </div>\n </div>\n )}\n {isComposing && (\n <div className=\"space-y-3 rounded-md border border-input p-3\">\n <Input\n placeholder=\"Doc title\"\n value={newTitle}\n onChange={(e) => setNewTitle(e.target.value)}\n />\n <MarkdownEditor\n value={newContent}\n onChange={setNewContent}\n placeholder=\"Write the spec/doc content...\"\n minHeight={140}\n />\n <div className=\"flex gap-2 justify-end\">\n <Button\n size=\"sm\"\n variant=\"ghost\"\n onClick={() => {\n setIsComposing(false);\n setNewTitle('');\n setNewContent('');\n }}\n >\n Cancel\n </Button>\n <Button\n size=\"sm\"\n disabled={creating || !newTitle.trim() || !newContent.trim()}\n onClick={handleCreateAndLink}\n >\n {creating ? 'Creating...' : 'Create & Link'}\n </Button>\n </div>\n </div>\n )}\n\n {loading && <p className=\"text-sm text-muted-foreground\">Loading docs...</p>}\n {error && <p className=\"text-sm text-red-500\">Error: {error.message}</p>}\n {actionError && (\n <p role=\"alert\" className=\"text-sm text-destructive\">\n {actionError}\n </p>\n )}\n {!loading && !error && docs.length === 0 && !isComposing && !isLinking && (\n <p className=\"text-sm text-muted-foreground\">No docs linked to this work item yet.</p>\n )}\n {docs.map((doc) => (\n <div\n key={doc.id}\n className=\"flex items-center justify-between gap-3 rounded-md border border-input p-3\"\n >\n <div className=\"flex items-center gap-2 min-w-0\">\n <FileText className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <div className=\"min-w-0\">\n <button\n type=\"button\"\n className=\"block max-w-full truncate text-left text-sm font-medium hover:underline\"\n onClick={() =>\n navigate(`/docs/doc-detail-page?docId=${encodeURIComponent(doc.id)}`)\n }\n >\n {doc.title}\n </button>\n <p className=\"text-xs text-muted-foreground\">v{doc.version}</p>\n </div>\n </div>\n <div className=\"flex items-center gap-2 shrink-0\">\n <span\n className={`text-xs px-2 py-0.5 rounded-full capitalize ${docStatusColor[doc.status] ?? ''}`}\n >\n {doc.status.toLowerCase()}\n </span>\n <Button\n size=\"icon\"\n variant=\"ghost\"\n disabled={unlinking}\n onClick={() => handleUnlink(doc.id)}\n aria-label={`Unlink ${doc.title}`}\n >\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n );\n}\n\nexport function TasksTaskDetailPagePage() {\n const { workspaceId } = usePlanMagnet();\n\n // In a real app, workItemId comes from route params.\n const workItemId = new URLSearchParams(window.location.search).get('taskId') ?? '';\n\n const { data, loading, error } = useQuery<{\n planmagnetWorkItem: WorkItemNode;\n }>(GET_WORK_ITEM, {\n variables: { workItemId },\n skip: !workspaceId || !workItemId,\n });\n\n // Only before the first load: a refetch must not blank the page (it\n\n // unmounts every component on it and loses their state).\n\n if (loading && !data) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <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 const task = data?.planmagnetWorkItem;\n if (!task) return <div className=\"p-6 text-muted-foreground\">Task not found.</div>;\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-start justify-between gap-4\">\n <div>\n <h1 className=\"text-2xl font-semibold\">{task.title}</h1>\n <p className=\"text-sm text-muted-foreground\">\n {task.key} · {task.type.toLowerCase()}\n </p>\n </div>\n <WorkItemHeaderActions workItemId={task.id} title={task.title} />\n </div>\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>Description</CardTitle>\n </CardHeader>\n <CardContent>\n <p className=\"text-sm\">{task.description ?? 'No description provided.'}</p>\n </CardContent>\n </Card>\n <CustomFieldsPanel\n workItemId={task.id}\n projectId={task.projectId}\n values={task.customFieldValues ?? []}\n />\n <LinkedDocsPanel workItemId={task.id} />\n <TaskTimePanel\n workspaceId={workspaceId}\n workItemId={task.id}\n projectId={task.projectId}\n taskLabel={`${task.key} — ${task.title}`}\n />\n <DependencyPanel\n workspaceId={workspaceId ?? ''}\n workItemId={task.id}\n projectId={task.projectId}\n />\n {/* PDM-24: semantic links (blocks / duplicates / causes / relates to), not scheduling. */}\n <IssueLinksPanel workItemId={task.id} />\n <WorkItemComments workItemId={task.id} />\n <WorkItemActivity workItemId={task.id} />\n </div>\n <div className=\"space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle>Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3 text-sm\">\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"text-muted-foreground\">Status</span>\n <WorkItemStatusSelect\n workItemId={task.id}\n projectId={task.projectId}\n value={task.status}\n />\n </div>\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"text-muted-foreground\">Priority</span>\n <WorkItemEnumSelect\n workItemId={task.id}\n field=\"priority\"\n value={task.priority}\n options={WORK_ITEM_PRIORITIES}\n label=\"Priority\"\n />\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Type</span>\n <Badge variant=\"outline\" className=\"capitalize\">\n {task.type.toLowerCase()}\n </Badge>\n </div>\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"text-muted-foreground\">Milestone</span>\n {/* PDM-22: a milestone of this task's project, or none. */}\n <WorkItemMilestoneSelect\n workItemId={task.id}\n projectId={task.projectId}\n milestoneId={task.milestoneId}\n />\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Story Points</span>\n <span className=\"font-medium\">{task.storyPoints ?? 0}</span>\n </div>\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"text-muted-foreground\">Assignee</span>\n {/* Members by name (BOFF-7946); choosing one assigns the task (BOFF-7938). */}\n <WorkItemAssigneeSelect workItemId={task.id} assigneeId={task.assigneeId} />\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Reporter</span>\n {/* No PlanMagnet form sets reporterId, so a UI-created task has none; its creator reported it. */}\n <PersonName id={task.reporterId ?? task.createdBy} />\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Key</span>\n <span>{task.key}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Due Date</span>\n <span>{task.dueDate ?? 'Not set'}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Created</span>\n <span>{task.createdAt}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Updated</span>\n <span>{task.updatedAt}</span>\n </div>\n <div>\n <span className=\"text-muted-foreground text-xs\">Labels</span>\n <div className=\"flex gap-1 mt-1 flex-wrap\">\n {(task.labels ?? []).map((l) => (\n <span key={l} className=\"text-xs px-2 py-0.5 rounded bg-muted\">\n {l}\n </span>\n ))}\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TasksTaskDetailPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/TasksTaskDetailPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { throwOnError } from '../utils/mutationResult';\nimport { WorkItemComments } from '../comments/WorkItemComments';\nimport { WorkItemActivity } from '../comments/WorkItemActivity';\nimport { TaskTimePanel } from '../time/TaskTimePanel';\nimport { PersonName } from '../people/People';\nimport { DocSearchSelect } from '../controls/Pickers';\nimport { CustomFieldsPanel } from '../controls/CustomFieldValuesPanel';\nimport { DependencyPanel } from '../dependency/DependencyPanel';\nimport { IssueLinksPanel } from '../links/IssueLinksPanel';\nimport { WorkItemMilestoneSelect } from '../milestones/MilestoneControls';\nimport {\n WORK_ITEM_PRIORITIES,\n WorkItemStatusSelect,\n WorkItemAssigneeSelect,\n WorkItemEnumSelect,\n WorkItemHeaderActions,\n} from '../controls/WorkItemControls';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport {\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Badge,\n Button,\n Input,\n} from '@burdenoff/fe-libs/ui';\nimport { FileText, Link2, Plus, X } from 'lucide-react';\nimport { MarkdownEditor } from '#src/components/MarkdownEditor';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { usePresence } from '../hooks/usePresence';\nimport { PresenceAvatars } from '../presence/PresenceAvatars';\nimport { WorkItemDiscussionPanel } from '../discussion/WorkItemDiscussionPanel';\nimport { CodeLinksPanel, type WorkItemCodeLink } from '../links/CodeLinksPanel';\n\nconst GET_WORK_ITEM = gql`\n query GetWorkItemDetail($workItemId: ID!) {\n planmagnetWorkItem(id: $workItemId) {\n id\n projectId\n title\n description\n type\n status\n priority\n key\n assigneeId\n reporterId\n createdBy\n sprintId\n milestoneId\n storyPoints\n estimateMinutes\n dueDate\n labels\n tags\n createdAt\n updatedAt\n customFieldValues {\n id\n definitionId\n value\n }\n discussionConversationId\n codeLinks {\n id\n kind\n title\n url\n state\n number\n authorLogin\n mergedAt\n ref\n }\n }\n }\n`;\n\nconst GET_WORK_ITEM_DOCS = gql`\n query GetWorkItemDocs($workItemId: ID!) {\n planmagnetWorkItemDocs(workItemId: $workItemId) {\n id\n title\n status\n version\n updatedAt\n }\n }\n`;\n\nconst CREATE_DOC = gql`\n mutation CreateDocForWorkItem($input: PlanmagnetCreateDocInput!) {\n planmagnetCreateDoc(input: $input) {\n id\n }\n }\n`;\n\nconst LINK_DOC_TO_WORK_ITEM = gql`\n mutation LinkDocToWorkItem($docId: ID!, $workItemId: ID!) {\n planmagnetLinkDocToWorkItem(docId: $docId, workItemId: $workItemId) {\n id\n }\n }\n`;\n\nconst UNLINK_DOC_FROM_WORK_ITEM = gql`\n mutation UnlinkDocFromWorkItem($docId: ID!, $workItemId: ID!) {\n planmagnetUnlinkDocFromWorkItem(docId: $docId, workItemId: $workItemId)\n }\n`;\n\ninterface WorkItemNode {\n id: string;\n title: string;\n description: string | null;\n type: string;\n status: string;\n priority: string;\n key: string;\n assigneeId: string | null;\n reporterId: string | null;\n createdBy: string;\n sprintId: string | null;\n milestoneId: string | null;\n storyPoints: number | null;\n estimateMinutes: number | null;\n dueDate: string | null;\n labels: string[];\n tags: string[];\n createdAt: string;\n updatedAt: string;\n customFieldValues: { id: string; definitionId: string; value: unknown }[];\n discussionConversationId: string | null;\n codeLinks: WorkItemCodeLink[];\n}\n\ninterface WorkItemDocNode {\n id: string;\n title: string;\n status: string;\n version: number;\n updatedAt: string;\n}\n\nconst docStatusColor: Record<string, string> = {\n DRAFT: 'bg-gray-100 text-gray-800',\n PUBLISHED: 'bg-green-100 text-green-800',\n ARCHIVED: 'bg-gray-100 text-gray-500',\n};\n\n/**\n * Linked-docs panel (BOFF-4443): create a doc and link it to this work item\n * in one action, view currently-linked docs, and unlink one. Reads/writes go\n * through the real planmagnetWorkItemDocs / planmagnetCreateDoc /\n * planmagnetLinkDocToWorkItem / planmagnetUnlinkDocFromWorkItem GraphQL\n * fields — no fabricated data. Full doc editing (revisions, revert) lives on\n * a dedicated doc detail view; this panel is scoped to linking.\n */\nfunction LinkedDocsPanel({ workItemId }: { workItemId: string }) {\n const navigate = usePlanMagnetNavigate();\n const [isComposing, setIsComposing] = useState(false);\n // BOFF-7961: only \"New Doc\" existed, so a doc written on the Docs page could never be linked to a task.\n const [isLinking, setIsLinking] = useState(false);\n const [existingDocId, setExistingDocId] = useState('');\n const [newTitle, setNewTitle] = useState('');\n const [newContent, setNewContent] = useState('');\n\n const { data, loading, error, refetch } = useQuery<{\n planmagnetWorkItemDocs: WorkItemDocNode[];\n }>(GET_WORK_ITEM_DOCS, {\n variables: { workItemId },\n skip: !workItemId,\n });\n\n const [createDoc, { loading: creating }] = useMutation(CREATE_DOC);\n const [linkDoc, { loading: linking }] = useMutation(LINK_DOC_TO_WORK_ITEM);\n const [unlinkDoc, { loading: unlinking }] = useMutation(UNLINK_DOC_FROM_WORK_ITEM);\n // A refused mutation resolves with { error } (fe-libs errorPolicy 'all');\n // the composer used to clear itself as if the doc had been saved.\n const [actionError, setActionError] = useState<string | null>(null);\n\n const docs = data?.planmagnetWorkItemDocs ?? [];\n\n const handleCreateAndLink = async () => {\n if (!newTitle.trim() || !newContent.trim()) return;\n setActionError(null);\n try {\n const result = await throwOnError(\n createDoc({ variables: { input: { title: newTitle.trim(), content: newContent.trim() } } })\n );\n const docId = result.data?.planmagnetCreateDoc?.id;\n if (docId) {\n await throwOnError(linkDoc({ variables: { docId, workItemId } }));\n }\n } catch (e) {\n setActionError(e instanceof Error ? e.message : 'The doc could not be saved.');\n return;\n }\n setNewTitle('');\n setNewContent('');\n setIsComposing(false);\n void refetch();\n };\n\n const handleLinkExisting = async () => {\n if (!existingDocId) return;\n setActionError(null);\n try {\n await throwOnError(linkDoc({ variables: { docId: existingDocId, workItemId } }));\n } catch (e) {\n setActionError(e instanceof Error ? e.message : 'The doc could not be linked.');\n return;\n }\n setExistingDocId('');\n setIsLinking(false);\n void refetch();\n };\n\n const handleUnlink = async (docId: string) => {\n setActionError(null);\n try {\n await throwOnError(unlinkDoc({ variables: { docId, workItemId } }));\n } catch (e) {\n setActionError(e instanceof Error ? e.message : 'The doc could not be unlinked.');\n return;\n }\n void refetch();\n };\n\n return (\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0\">\n <CardTitle>Linked Docs</CardTitle>\n {!isComposing && !isLinking && (\n <div className=\"flex gap-2\">\n <Button size=\"sm\" variant=\"outline\" onClick={() => setIsLinking(true)}>\n <Link2 className=\"h-4 w-4 mr-1\" />\n Link existing doc\n </Button>\n <Button size=\"sm\" variant=\"outline\" onClick={() => setIsComposing(true)}>\n <Plus className=\"h-4 w-4 mr-1\" />\n New Doc\n </Button>\n </div>\n )}\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {isLinking && (\n <div className=\"space-y-2 rounded-md border border-input p-3\">\n <DocSearchSelect\n id=\"task-link-doc\"\n value={existingDocId}\n onChange={setExistingDocId}\n exclude={docs.map((d) => d.id)}\n />\n <div className=\"flex gap-2 justify-end\">\n <Button\n size=\"sm\"\n variant=\"ghost\"\n onClick={() => {\n setIsLinking(false);\n setExistingDocId('');\n }}\n >\n Cancel\n </Button>\n <Button size=\"sm\" disabled={!existingDocId || linking} onClick={handleLinkExisting}>\n {linking ? 'Linking...' : 'Link'}\n </Button>\n </div>\n </div>\n )}\n {isComposing && (\n <div className=\"space-y-3 rounded-md border border-input p-3\">\n <Input\n placeholder=\"Doc title\"\n value={newTitle}\n onChange={(e) => setNewTitle(e.target.value)}\n />\n <MarkdownEditor\n value={newContent}\n onChange={setNewContent}\n placeholder=\"Write the spec/doc content...\"\n minHeight={140}\n />\n <div className=\"flex gap-2 justify-end\">\n <Button\n size=\"sm\"\n variant=\"ghost\"\n onClick={() => {\n setIsComposing(false);\n setNewTitle('');\n setNewContent('');\n }}\n >\n Cancel\n </Button>\n <Button\n size=\"sm\"\n disabled={creating || !newTitle.trim() || !newContent.trim()}\n onClick={handleCreateAndLink}\n >\n {creating ? 'Creating...' : 'Create & Link'}\n </Button>\n </div>\n </div>\n )}\n\n {loading && <p className=\"text-sm text-muted-foreground\">Loading docs...</p>}\n {error && <p className=\"text-sm text-red-500\">Error: {error.message}</p>}\n {actionError && (\n <p role=\"alert\" className=\"text-sm text-destructive\">\n {actionError}\n </p>\n )}\n {!loading && !error && docs.length === 0 && !isComposing && !isLinking && (\n <p className=\"text-sm text-muted-foreground\">No docs linked to this work item yet.</p>\n )}\n {docs.map((doc) => (\n <div\n key={doc.id}\n className=\"flex items-center justify-between gap-3 rounded-md border border-input p-3\"\n >\n <div className=\"flex items-center gap-2 min-w-0\">\n <FileText className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <div className=\"min-w-0\">\n <button\n type=\"button\"\n className=\"block max-w-full truncate text-left text-sm font-medium hover:underline\"\n onClick={() =>\n navigate(`/docs/doc-detail-page?docId=${encodeURIComponent(doc.id)}`)\n }\n >\n {doc.title}\n </button>\n <p className=\"text-xs text-muted-foreground\">v{doc.version}</p>\n </div>\n </div>\n <div className=\"flex items-center gap-2 shrink-0\">\n <span\n className={`text-xs px-2 py-0.5 rounded-full capitalize ${docStatusColor[doc.status] ?? ''}`}\n >\n {doc.status.toLowerCase()}\n </span>\n <Button\n size=\"icon\"\n variant=\"ghost\"\n disabled={unlinking}\n onClick={() => handleUnlink(doc.id)}\n aria-label={`Unlink ${doc.title}`}\n >\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n );\n}\n\nexport function TasksTaskDetailPagePage() {\n const { workspaceId } = usePlanMagnet();\n\n // In a real app, workItemId comes from route params.\n const workItemId = new URLSearchParams(window.location.search).get('taskId') ?? '';\n\n const { data, loading, error } = useQuery<{\n planmagnetWorkItem: WorkItemNode;\n }>(GET_WORK_ITEM, {\n variables: { workItemId },\n skip: !workspaceId || !workItemId,\n });\n\n // CWF-24: who else is looking at this task right now, and who's mid-comment.\n const presence = usePresence('WORK_ITEM', workItemId || null);\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 const task = data?.planmagnetWorkItem;\n if (!task) return <div className=\"p-6 text-muted-foreground\">Task not found.</div>;\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-start justify-between gap-4\">\n <div>\n <h1 className=\"text-2xl font-semibold\">{task.title}</h1>\n <p className=\"text-sm text-muted-foreground\">\n {task.key} · {task.type.toLowerCase()}\n </p>\n <PresenceAvatars others={presence.others} />\n </div>\n <WorkItemHeaderActions workItemId={task.id} title={task.title} />\n </div>\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>Description</CardTitle>\n </CardHeader>\n <CardContent>\n <p className=\"text-sm\">{task.description ?? 'No description provided.'}</p>\n </CardContent>\n </Card>\n <CustomFieldsPanel\n workItemId={task.id}\n projectId={task.projectId}\n values={task.customFieldValues ?? []}\n />\n <LinkedDocsPanel workItemId={task.id} />\n <TaskTimePanel\n workspaceId={workspaceId}\n workItemId={task.id}\n projectId={task.projectId}\n taskLabel={`${task.key} — ${task.title}`}\n />\n <DependencyPanel\n workspaceId={workspaceId ?? ''}\n workItemId={task.id}\n projectId={task.projectId}\n />\n {/* PDM-24: semantic links (blocks / duplicates / causes / relates to), not scheduling. */}\n <IssueLinksPanel workItemId={task.id} />\n {/* CWF-26: a real group conversation in Conversations, not a comment thread of its own. */}\n <WorkItemDiscussionPanel\n workItemId={task.id}\n workItemKey={task.key}\n workItemTitle={task.title}\n assigneeId={task.assigneeId}\n discussionConversationId={task.discussionConversationId}\n />\n {/* AUT-12: PRs/commits/releases GitHub sync discovered that mention this item's key. */}\n <CodeLinksPanel codeLinks={task.codeLinks ?? []} />\n <WorkItemComments\n workItemId={task.id}\n presence={{\n typingActorIds: presence.typingActorIds,\n notifyTyping: presence.notifyTyping,\n }}\n />\n <WorkItemActivity workItemId={task.id} />\n </div>\n <div className=\"space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle>Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3 text-sm\">\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"text-muted-foreground\">Status</span>\n <WorkItemStatusSelect\n workItemId={task.id}\n projectId={task.projectId}\n value={task.status}\n />\n </div>\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"text-muted-foreground\">Priority</span>\n <WorkItemEnumSelect\n workItemId={task.id}\n field=\"priority\"\n value={task.priority}\n options={WORK_ITEM_PRIORITIES}\n label=\"Priority\"\n />\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Type</span>\n <Badge variant=\"outline\" className=\"capitalize\">\n {task.type.toLowerCase()}\n </Badge>\n </div>\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"text-muted-foreground\">Milestone</span>\n {/* PDM-22: a milestone of this task's project, or none. */}\n <WorkItemMilestoneSelect\n workItemId={task.id}\n projectId={task.projectId}\n milestoneId={task.milestoneId}\n />\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Story Points</span>\n <span className=\"font-medium\">{task.storyPoints ?? 0}</span>\n </div>\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"text-muted-foreground\">Assignee</span>\n {/* Members by name (BOFF-7946); choosing one assigns the task (BOFF-7938). */}\n <WorkItemAssigneeSelect workItemId={task.id} assigneeId={task.assigneeId} />\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Reporter</span>\n {/* No PlanMagnet form sets reporterId, so a UI-created task has none; its creator reported it. */}\n <PersonName id={task.reporterId ?? task.createdBy} />\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Key</span>\n <span>{task.key}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Due Date</span>\n <span>{task.dueDate ?? 'Not set'}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Created</span>\n <span>{task.createdAt}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">Updated</span>\n <span>{task.updatedAt}</span>\n </div>\n <div>\n <span className=\"text-muted-foreground text-xs\">Labels</span>\n <div className=\"flex gap-1 mt-1 flex-wrap\">\n {(task.labels ?? []).map((l) => (\n <span key={l} className=\"text-xs px-2 py-0.5 rounded bg-muted\">\n {l}\n </span>\n ))}\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { PresenceOther } from '../hooks/usePresence';
|
|
2
|
+
|
|
3
|
+
export declare function PresenceAvatars({ others }: {
|
|
4
|
+
others: readonly PresenceOther[];
|
|
5
|
+
}): import("react/jsx-runtime").JSX.Element | null;
|
|
6
|
+
/**
|
|
7
|
+
* "Ada is typing…" (CWF-24), inside a comment thread. A live region (polite — a typing flip is not urgent enough
|
|
8
|
+
* to interrupt) so the line appearing/disappearing/changing names is announced without extra chrome. Renders an
|
|
9
|
+
* (invisible-to-sighted-users but still present) empty live region rather than nothing at all when no one is
|
|
10
|
+
* typing, so the region already exists in the accessibility tree before the first announcement — inserting a
|
|
11
|
+
* brand-new `aria-live` node right as it needs to speak is unreliable across screen readers.
|
|
12
|
+
*/
|
|
13
|
+
export declare function TypingLine({ typingActorIds }: {
|
|
14
|
+
typingActorIds: readonly string[];
|
|
15
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
//# sourceMappingURL=PresenceAvatars.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PresenceAvatars.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/presence/PresenceAvatars.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAe1D,wBAAgB,eAAe,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,SAAS,aAAa,EAAE,CAAA;CAAE,kDA6B/E;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,EAAE,cAAc,EAAE,EAAE;IAAE,cAAc,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,2CAsBnF"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { PersonAvatar as e, PersonName as t } from "../people/People.js";
|
|
2
|
+
import { Fragment as n } from "react";
|
|
3
|
+
import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
4
|
+
//#region src/planmagnet/presence/PresenceAvatars.tsx
|
|
5
|
+
var a = 5;
|
|
6
|
+
function o({ others: t }) {
|
|
7
|
+
if (t.length === 0) return null;
|
|
8
|
+
let n = t.slice(0, a), o = t.length - n.length;
|
|
9
|
+
return /* @__PURE__ */ i("div", {
|
|
10
|
+
role: "group",
|
|
11
|
+
"aria-label": `Also here: ${t.length} other${t.length === 1 ? "" : "s"}`,
|
|
12
|
+
"data-testid": "presence-avatars",
|
|
13
|
+
className: "flex items-center gap-1.5",
|
|
14
|
+
children: [
|
|
15
|
+
/* @__PURE__ */ r("span", {
|
|
16
|
+
className: "text-xs text-muted-foreground",
|
|
17
|
+
children: "Also here:"
|
|
18
|
+
}),
|
|
19
|
+
/* @__PURE__ */ r("div", {
|
|
20
|
+
className: "flex -space-x-2",
|
|
21
|
+
children: n.map((t) => /* @__PURE__ */ r(e, {
|
|
22
|
+
id: t.actorId,
|
|
23
|
+
className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-full border-2 border-bg-surface bg-muted text-[10px] font-medium text-foreground"
|
|
24
|
+
}, t.actorId))
|
|
25
|
+
}),
|
|
26
|
+
o > 0 && /* @__PURE__ */ i("span", {
|
|
27
|
+
className: "text-xs text-muted-foreground",
|
|
28
|
+
"data-testid": "presence-avatars-overflow",
|
|
29
|
+
children: ["+", o]
|
|
30
|
+
})
|
|
31
|
+
]
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function s({ typingActorIds: e }) {
|
|
35
|
+
let [a, o] = e;
|
|
36
|
+
return /* @__PURE__ */ i("p", {
|
|
37
|
+
role: "status",
|
|
38
|
+
"aria-live": "polite",
|
|
39
|
+
"data-testid": "presence-typing",
|
|
40
|
+
className: "min-h-[1rem] text-xs italic text-muted-foreground",
|
|
41
|
+
children: [
|
|
42
|
+
e.length === 1 && /* @__PURE__ */ i(n, { children: [/* @__PURE__ */ r(t, { id: a }), " is typing…"] }),
|
|
43
|
+
e.length === 2 && /* @__PURE__ */ i(n, { children: [
|
|
44
|
+
/* @__PURE__ */ r(t, { id: a }),
|
|
45
|
+
" and ",
|
|
46
|
+
/* @__PURE__ */ r(t, { id: o }),
|
|
47
|
+
" are typing…"
|
|
48
|
+
] }),
|
|
49
|
+
e.length > 2 && `${e.length} people are typing…`
|
|
50
|
+
]
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
//#endregion
|
|
54
|
+
export { o as PresenceAvatars, s as TypingLine };
|
|
55
|
+
|
|
56
|
+
//# sourceMappingURL=PresenceAvatars.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PresenceAvatars.js","names":[],"sources":["../../../src/planmagnet/presence/PresenceAvatars.tsx"],"sourcesContent":["import { Fragment } from 'react';\nimport { PersonAvatar, PersonName } from '../people/People';\nimport type { PresenceOther } from '../hooks/usePresence';\n\n/**\n * \"Also here: …\" (CWF-24) — everyone else currently present on a task/doc/roadmap/project, up to 5 initials\n * bubbles plus a \"+N\" overflow count. `others` is expected to already exclude the caller — `usePresence` does\n * that — so this never needs its own id to filter against. Renders nothing when nobody else is here: an empty\n * \"Also here:\" row would be noise, not information.\n *\n * Each bubble is a `PersonAvatar`, which already carries its own resolved-name `aria-label`/tooltip (People.tsx),\n * so wrapping this in `role=\"group\"` with a visible label is enough for the set to read sensibly to a screen\n * reader — there is no second, separately-maintained list of names to keep in sync with the bubbles.\n */\n\nconst MAX_SHOWN = 5;\n\nexport function PresenceAvatars({ others }: { others: readonly PresenceOther[] }) {\n if (others.length === 0) return null;\n const shown = others.slice(0, MAX_SHOWN);\n const overflow = others.length - shown.length;\n\n return (\n <div\n role=\"group\"\n aria-label={`Also here: ${others.length} other${others.length === 1 ? '' : 's'}`}\n data-testid=\"presence-avatars\"\n className=\"flex items-center gap-1.5\"\n >\n <span className=\"text-xs text-muted-foreground\">Also here:</span>\n <div className=\"flex -space-x-2\">\n {shown.map((entry) => (\n <PersonAvatar\n key={entry.actorId}\n id={entry.actorId}\n className=\"flex h-6 w-6 shrink-0 items-center justify-center rounded-full border-2 border-bg-surface bg-muted text-[10px] font-medium text-foreground\"\n />\n ))}\n </div>\n {overflow > 0 && (\n <span className=\"text-xs text-muted-foreground\" data-testid=\"presence-avatars-overflow\">\n +{overflow}\n </span>\n )}\n </div>\n );\n}\n\n/**\n * \"Ada is typing…\" (CWF-24), inside a comment thread. A live region (polite — a typing flip is not urgent enough\n * to interrupt) so the line appearing/disappearing/changing names is announced without extra chrome. Renders an\n * (invisible-to-sighted-users but still present) empty live region rather than nothing at all when no one is\n * typing, so the region already exists in the accessibility tree before the first announcement — inserting a\n * brand-new `aria-live` node right as it needs to speak is unreliable across screen readers.\n */\nexport function TypingLine({ typingActorIds }: { typingActorIds: readonly string[] }) {\n const [first, second] = typingActorIds;\n return (\n <p\n role=\"status\"\n aria-live=\"polite\"\n data-testid=\"presence-typing\"\n className=\"min-h-[1rem] text-xs italic text-muted-foreground\"\n >\n {typingActorIds.length === 1 && (\n <Fragment>\n <PersonName id={first} /> is typing…\n </Fragment>\n )}\n {typingActorIds.length === 2 && (\n <Fragment>\n <PersonName id={first} /> and <PersonName id={second} /> are typing…\n </Fragment>\n )}\n {typingActorIds.length > 2 && `${typingActorIds.length} people are typing…`}\n </p>\n );\n}\n"],"mappings":";;;;AAeA,IAAM,IAAY;AAElB,SAAgB,EAAgB,EAAE,aAAgD;AAChF,KAAI,EAAO,WAAW,EAAG,QAAO;CAChC,IAAM,IAAQ,EAAO,MAAM,GAAG,EAAU,EAClC,IAAW,EAAO,SAAS,EAAM;AAEvC,QACE,kBAAC,OAAD;EACE,MAAK;EACL,cAAY,cAAc,EAAO,OAAO,QAAQ,EAAO,WAAW,IAAI,KAAK;EAC3E,eAAY;EACZ,WAAU;YAJZ;GAME,kBAAC,QAAD;IAAM,WAAU;cAAgC;IAAiB,CAAA;GACjE,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAM,KAAK,MACV,kBAAC,GAAD;KAEE,IAAI,EAAM;KACV,WAAU;KACV,EAHK,EAAM,QAGX,CACF;IACE,CAAA;GACL,IAAW,KACV,kBAAC,QAAD;IAAM,WAAU;IAAgC,eAAY;cAA5D,CAAwF,KACpF,EACG;;GAEL;;;AAWV,SAAgB,EAAW,EAAE,qBAAyD;CACpF,IAAM,CAAC,GAAO,KAAU;AACxB,QACE,kBAAC,KAAD;EACE,MAAK;EACL,aAAU;EACV,eAAY;EACZ,WAAU;YAJZ;GAMG,EAAe,WAAW,KACzB,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAY,IAAI,GAAS,CAAA,EAAA,cAChB,EAAA,CAAA;GAEZ,EAAe,WAAW,KACzB,kBAAC,GAAD,EAAA,UAAA;IACE,kBAAC,GAAD,EAAY,IAAI,GAAS,CAAA;;IAAK,kBAAC,GAAD,EAAY,IAAI,GAAU,CAAA;;IAC/C,EAAA,CAAA;GAEZ,EAAe,SAAS,KAAK,GAAG,EAAe,OAAO;GACrD"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ReportRun, ReportWidget } from './reportModel';
|
|
2
|
+
|
|
3
|
+
export declare function ExportMenu({ reportName, widgets, run, onPrint, }: {
|
|
4
|
+
reportName: string;
|
|
5
|
+
widgets: ReportWidget[];
|
|
6
|
+
run: ReportRun | null;
|
|
7
|
+
onPrint: () => void;
|
|
8
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
//# sourceMappingURL=ExportMenu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExportMenu.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/reports/ExportMenu.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAsB,SAAS,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AA+BjF,wBAAgB,UAAU,CAAC,EACzB,UAAU,EACV,OAAO,EACP,GAAG,EACH,OAAO,GACR,EAAE;IACD,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,GAAG,EAAE,SAAS,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,2CAyFA"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { mutationErrorMessage as e } from "../utils/graphqlErrors.js";
|
|
2
|
+
import { EXPORT_REPORT_RUN as t } from "./reportGraphql.js";
|
|
3
|
+
import { useState as n } from "react";
|
|
4
|
+
import { Download as r, Printer as i } from "lucide-react";
|
|
5
|
+
import { useApolloClient as a } from "@apollo/client/react";
|
|
6
|
+
import { jsx as o, jsxs as s } from "react/jsx-runtime";
|
|
7
|
+
import { Button as c, DropdownMenu as l, DropdownMenuContent as u, DropdownMenuItem as d, DropdownMenuLabel as f, DropdownMenuSeparator as p, DropdownMenuTrigger as m } from "@burdenoff/fe-libs/ui";
|
|
8
|
+
//#region src/planmagnet/reports/ExportMenu.tsx
|
|
9
|
+
function h(e) {
|
|
10
|
+
return e.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "report";
|
|
11
|
+
}
|
|
12
|
+
function g(e, t, n) {
|
|
13
|
+
let r = new Blob([n], { type: t || "text/plain;charset=utf-8" }), i = URL.createObjectURL(r), a = document.createElement("a");
|
|
14
|
+
a.href = i, a.download = e, document.body.appendChild(a), a.click(), a.remove(), URL.revokeObjectURL(i);
|
|
15
|
+
}
|
|
16
|
+
function _({ reportName: _, widgets: v, run: y, onPrint: b }) {
|
|
17
|
+
let x = a(), [S, C] = n(null), [w, T] = n(null), E = `${h(_)}-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`, D = !y, O = async (n) => {
|
|
18
|
+
if (y) {
|
|
19
|
+
C(n), T(null);
|
|
20
|
+
try {
|
|
21
|
+
let e = await x.query({
|
|
22
|
+
query: t,
|
|
23
|
+
variables: {
|
|
24
|
+
runId: y.id,
|
|
25
|
+
format: n
|
|
26
|
+
},
|
|
27
|
+
fetchPolicy: "network-only"
|
|
28
|
+
});
|
|
29
|
+
if (e.error) throw e.error;
|
|
30
|
+
let r = e.data?.planmagnetExportReportRun;
|
|
31
|
+
if (!r) throw Error("The export could not be generated.");
|
|
32
|
+
g(r.filename, r.contentType, r.content);
|
|
33
|
+
} catch (t) {
|
|
34
|
+
T(e(t, "The export failed."));
|
|
35
|
+
} finally {
|
|
36
|
+
C(null);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}, k = async () => {
|
|
40
|
+
if (y) {
|
|
41
|
+
C("XLSX"), T(null);
|
|
42
|
+
try {
|
|
43
|
+
let { exportReportRunToXlsx: e } = await import("./reportExportXlsx.js");
|
|
44
|
+
await e(v, y, E);
|
|
45
|
+
} catch (t) {
|
|
46
|
+
T(e(t, "The Excel export failed."));
|
|
47
|
+
} finally {
|
|
48
|
+
C(null);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}, A = async () => {
|
|
52
|
+
if (y) {
|
|
53
|
+
C("PPTX"), T(null);
|
|
54
|
+
try {
|
|
55
|
+
let { exportReportRunToPptx: e } = await import("./reportExportPptx.js");
|
|
56
|
+
await e(v, y, E, _);
|
|
57
|
+
} catch (t) {
|
|
58
|
+
T(e(t, "The PowerPoint export failed."));
|
|
59
|
+
} finally {
|
|
60
|
+
C(null);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
return /* @__PURE__ */ s("div", {
|
|
65
|
+
className: "flex items-center gap-2",
|
|
66
|
+
children: [/* @__PURE__ */ s(l, { children: [/* @__PURE__ */ o(m, {
|
|
67
|
+
asChild: !0,
|
|
68
|
+
children: /* @__PURE__ */ s(c, {
|
|
69
|
+
size: "sm",
|
|
70
|
+
variant: "outline",
|
|
71
|
+
disabled: D,
|
|
72
|
+
"data-testid": "report-export",
|
|
73
|
+
children: [/* @__PURE__ */ o(r, { className: "mr-1 h-4 w-4" }), S ? `Exporting ${S}…` : "Export"]
|
|
74
|
+
})
|
|
75
|
+
}), /* @__PURE__ */ s(u, {
|
|
76
|
+
align: "end",
|
|
77
|
+
children: [
|
|
78
|
+
/* @__PURE__ */ o(f, { children: "Data" }),
|
|
79
|
+
/* @__PURE__ */ o(d, {
|
|
80
|
+
onSelect: () => void O("CSV"),
|
|
81
|
+
children: "CSV"
|
|
82
|
+
}),
|
|
83
|
+
/* @__PURE__ */ o(d, {
|
|
84
|
+
onSelect: () => void O("JSON"),
|
|
85
|
+
children: "JSON"
|
|
86
|
+
}),
|
|
87
|
+
/* @__PURE__ */ o(d, {
|
|
88
|
+
onSelect: () => void O("XML"),
|
|
89
|
+
children: "XML"
|
|
90
|
+
}),
|
|
91
|
+
/* @__PURE__ */ o(p, {}),
|
|
92
|
+
/* @__PURE__ */ o(f, { children: "Documents" }),
|
|
93
|
+
/* @__PURE__ */ o(d, {
|
|
94
|
+
onSelect: () => void k(),
|
|
95
|
+
children: "Excel (.xlsx)"
|
|
96
|
+
}),
|
|
97
|
+
/* @__PURE__ */ o(d, {
|
|
98
|
+
onSelect: () => void A(),
|
|
99
|
+
children: "PowerPoint (.pptx)"
|
|
100
|
+
}),
|
|
101
|
+
/* @__PURE__ */ s(d, {
|
|
102
|
+
onSelect: b,
|
|
103
|
+
children: [/* @__PURE__ */ o(i, { className: "mr-1 h-3.5 w-3.5" }), "PDF (print)"]
|
|
104
|
+
})
|
|
105
|
+
]
|
|
106
|
+
})] }), w && /* @__PURE__ */ o("span", {
|
|
107
|
+
role: "alert",
|
|
108
|
+
className: "text-xs text-destructive",
|
|
109
|
+
children: w
|
|
110
|
+
})]
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
//#endregion
|
|
114
|
+
export { _ as ExportMenu };
|
|
115
|
+
|
|
116
|
+
//# sourceMappingURL=ExportMenu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExportMenu.js","names":[],"sources":["../../../src/planmagnet/reports/ExportMenu.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useApolloClient } from '@apollo/client/react';\nimport {\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '@burdenoff/fe-libs/ui';\nimport { Download, Printer } from 'lucide-react';\nimport { mutationErrorMessage } from '../utils/graphqlErrors';\nimport { EXPORT_REPORT_RUN } from './reportGraphql';\nimport type { ReportExportFormat, ReportRun, ReportWidget } from './reportModel';\n\n/**\n * Export a run (ANR-16). CSV/JSON/XML are rendered server-side (`planmagnetExportReportRun`) and downloaded as\n * given. Excel/PowerPoint are built client-side from the same already-fetched run, via a dynamic `import()` so\n * `write-excel-file`/`pptxgenjs` only ever load when actually used. PDF is a print-optimised view + the\n * browser's own \"Save as PDF\" (`onPrint`) — no PDF library.\n */\n\nfunction slugify(name: string): string {\n return (\n name\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '') || 'report'\n );\n}\n\nfunction downloadTextFile(filename: string, contentType: string, content: string): void {\n const blob = new Blob([content], { type: contentType || 'text/plain;charset=utf-8' });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n document.body.appendChild(link);\n link.click();\n link.remove();\n URL.revokeObjectURL(url);\n}\n\nexport function ExportMenu({\n reportName,\n widgets,\n run,\n onPrint,\n}: {\n reportName: string;\n widgets: ReportWidget[];\n run: ReportRun | null;\n onPrint: () => void;\n}) {\n const client = useApolloClient();\n const [busy, setBusy] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n const fileNameBase = `${slugify(reportName)}-${new Date().toISOString().slice(0, 10)}`;\n const disabled = !run;\n\n const exportServerFormat = async (format: ReportExportFormat) => {\n if (!run) return;\n setBusy(format);\n setError(null);\n try {\n const result = await client.query<{\n planmagnetExportReportRun: { filename: string; contentType: string; content: string };\n }>({\n query: EXPORT_REPORT_RUN,\n variables: { runId: run.id, format },\n fetchPolicy: 'network-only',\n });\n if (result.error) throw result.error;\n const file = result.data?.planmagnetExportReportRun;\n if (!file) throw new Error('The export could not be generated.');\n downloadTextFile(file.filename, file.contentType, file.content);\n } catch (e) {\n setError(mutationErrorMessage(e, 'The export failed.'));\n } finally {\n setBusy(null);\n }\n };\n\n const exportXlsx = async () => {\n if (!run) return;\n setBusy('XLSX');\n setError(null);\n try {\n const { exportReportRunToXlsx } = await import('./reportExportXlsx');\n await exportReportRunToXlsx(widgets, run, fileNameBase);\n } catch (e) {\n setError(mutationErrorMessage(e, 'The Excel export failed.'));\n } finally {\n setBusy(null);\n }\n };\n\n const exportPptx = async () => {\n if (!run) return;\n setBusy('PPTX');\n setError(null);\n try {\n const { exportReportRunToPptx } = await import('./reportExportPptx');\n await exportReportRunToPptx(widgets, run, fileNameBase, reportName);\n } catch (e) {\n setError(mutationErrorMessage(e, 'The PowerPoint export failed.'));\n } finally {\n setBusy(null);\n }\n };\n\n return (\n <div className=\"flex items-center gap-2\">\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button size=\"sm\" variant=\"outline\" disabled={disabled} data-testid=\"report-export\">\n <Download className=\"mr-1 h-4 w-4\" />\n {busy ? `Exporting ${busy}…` : 'Export'}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuLabel>Data</DropdownMenuLabel>\n <DropdownMenuItem onSelect={() => void exportServerFormat('CSV')}>CSV</DropdownMenuItem>\n <DropdownMenuItem onSelect={() => void exportServerFormat('JSON')}>JSON</DropdownMenuItem>\n <DropdownMenuItem onSelect={() => void exportServerFormat('XML')}>XML</DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuLabel>Documents</DropdownMenuLabel>\n <DropdownMenuItem onSelect={() => void exportXlsx()}>Excel (.xlsx)</DropdownMenuItem>\n <DropdownMenuItem onSelect={() => void exportPptx()}>PowerPoint (.pptx)</DropdownMenuItem>\n <DropdownMenuItem onSelect={onPrint}>\n <Printer className=\"mr-1 h-3.5 w-3.5\" />\n PDF (print)\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n {error && (\n <span role=\"alert\" className=\"text-xs text-destructive\">\n {error}\n </span>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ReportWidget, WidgetRunResult } from './reportModel';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The print-optimised view (ANR-16's PDF export — a print stylesheet, not a PDF library: `window.print()` lets
|
|
5
|
+
* the browser's own "Save as PDF" do the rendering). Reused by both the in-app Export ▸ PDF flow
|
|
6
|
+
* (`ReportsReportPagePage.tsx`, the owner's own widgets/results) and the public `SharedReportPage` (a synthetic
|
|
7
|
+
* `CHART`-typed widget per result, since a share's snapshot carries no widget title/type — see that file).
|
|
8
|
+
*
|
|
9
|
+
* The toolbar (`print:hidden`) never appears in the printed/PDF output, only on screen. The watermark, when
|
|
10
|
+
* set, is `aria-hidden` (decorative) but rendered both on screen and in print via a fixed, tiled overlay —
|
|
11
|
+
* never only in a `@media print` block this package cannot ship (Tailwind utility classes only, per this
|
|
12
|
+
* repo's design constraints).
|
|
13
|
+
*/
|
|
14
|
+
export declare function PrintReportView({ reportName, generatedAt, watermark, widgets, results, onClose, onPrintNow, }: {
|
|
15
|
+
reportName: string;
|
|
16
|
+
generatedAt: string;
|
|
17
|
+
watermark?: string | null;
|
|
18
|
+
widgets: ReportWidget[];
|
|
19
|
+
results: Map<string, WidgetRunResult>;
|
|
20
|
+
/** Omit for the public shared view, which has no "back to the builder" to return to. */
|
|
21
|
+
onClose?: () => void;
|
|
22
|
+
onPrintNow: () => void;
|
|
23
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
//# sourceMappingURL=PrintReportView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PrintReportView.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/reports/PrintReportView.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEnE;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,EAC9B,UAAU,EACV,WAAW,EACX,SAAS,EACT,OAAO,EACP,OAAO,EACP,OAAO,EACP,UAAU,GACX,EAAE;IACD,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACtC,wFAAwF;IACxF,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB,2CA+DA"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { ReportWidgetRenderer as e } from "./ReportWidgetRenderer.js";
|
|
2
|
+
import { Printer as t, X as n } from "lucide-react";
|
|
3
|
+
import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
4
|
+
import { Button as a } from "@burdenoff/fe-libs/ui";
|
|
5
|
+
//#region src/planmagnet/reports/PrintReportView.tsx
|
|
6
|
+
function o({ reportName: o, generatedAt: s, watermark: c, widgets: l, results: u, onClose: d, onPrintNow: f }) {
|
|
7
|
+
return /* @__PURE__ */ i("div", {
|
|
8
|
+
className: "relative mx-auto max-w-4xl bg-background p-6 text-foreground",
|
|
9
|
+
"data-testid": "print-report-view",
|
|
10
|
+
children: [
|
|
11
|
+
c && /* @__PURE__ */ r("div", {
|
|
12
|
+
"aria-hidden": !0,
|
|
13
|
+
className: "pointer-events-none fixed inset-0 z-50 flex flex-wrap content-around justify-around gap-16 overflow-hidden opacity-10 print:opacity-20",
|
|
14
|
+
children: Array.from({ length: 24 }, (e, t) => /* @__PURE__ */ r("span", {
|
|
15
|
+
className: "whitespace-nowrap rotate-[-30deg] text-2xl font-semibold text-foreground",
|
|
16
|
+
children: c
|
|
17
|
+
}, t))
|
|
18
|
+
}),
|
|
19
|
+
/* @__PURE__ */ i("div", {
|
|
20
|
+
className: "mb-4 flex items-center justify-between gap-2 print:hidden",
|
|
21
|
+
children: [/* @__PURE__ */ r("p", {
|
|
22
|
+
className: "text-xs text-muted-foreground",
|
|
23
|
+
children: "Use your browser’s print dialog to save this as a PDF."
|
|
24
|
+
}), /* @__PURE__ */ i("div", {
|
|
25
|
+
className: "flex gap-2",
|
|
26
|
+
children: [/* @__PURE__ */ i(a, {
|
|
27
|
+
size: "sm",
|
|
28
|
+
onClick: f,
|
|
29
|
+
"data-testid": "print-report-now",
|
|
30
|
+
children: [/* @__PURE__ */ r(t, { className: "mr-1 h-4 w-4" }), "Print / Save as PDF"]
|
|
31
|
+
}), d && /* @__PURE__ */ i(a, {
|
|
32
|
+
size: "sm",
|
|
33
|
+
variant: "outline",
|
|
34
|
+
onClick: d,
|
|
35
|
+
children: [/* @__PURE__ */ r(n, { className: "mr-1 h-4 w-4" }), "Close"]
|
|
36
|
+
})]
|
|
37
|
+
})]
|
|
38
|
+
}),
|
|
39
|
+
/* @__PURE__ */ i("header", {
|
|
40
|
+
className: "mb-6 border-b border-border pb-4",
|
|
41
|
+
children: [
|
|
42
|
+
/* @__PURE__ */ r("p", {
|
|
43
|
+
className: "text-xs font-semibold uppercase tracking-wide text-primary",
|
|
44
|
+
children: "PlanMagnet"
|
|
45
|
+
}),
|
|
46
|
+
/* @__PURE__ */ r("h1", {
|
|
47
|
+
className: "text-2xl font-bold",
|
|
48
|
+
children: o
|
|
49
|
+
}),
|
|
50
|
+
/* @__PURE__ */ i("p", {
|
|
51
|
+
className: "text-sm text-muted-foreground",
|
|
52
|
+
children: ["Generated ", new Date(s).toLocaleString()]
|
|
53
|
+
})
|
|
54
|
+
]
|
|
55
|
+
}),
|
|
56
|
+
/* @__PURE__ */ r("div", {
|
|
57
|
+
className: "space-y-6",
|
|
58
|
+
children: l.map((t) => /* @__PURE__ */ i("section", {
|
|
59
|
+
className: "break-inside-avoid rounded-md border border-border p-4",
|
|
60
|
+
children: [t.type !== "TEXT" && /* @__PURE__ */ r("h2", {
|
|
61
|
+
className: "mb-2 text-base font-semibold",
|
|
62
|
+
children: t.title
|
|
63
|
+
}), /* @__PURE__ */ r(e, {
|
|
64
|
+
widget: t,
|
|
65
|
+
runResult: u.get(t.id)
|
|
66
|
+
})]
|
|
67
|
+
}, t.id))
|
|
68
|
+
})
|
|
69
|
+
]
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
//#endregion
|
|
73
|
+
export { o as PrintReportView };
|
|
74
|
+
|
|
75
|
+
//# sourceMappingURL=PrintReportView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PrintReportView.js","names":[],"sources":["../../../src/planmagnet/reports/PrintReportView.tsx"],"sourcesContent":["import { Button } from '@burdenoff/fe-libs/ui';\nimport { Printer, X } from 'lucide-react';\nimport { ReportWidgetRenderer } from './ReportWidgetRenderer';\nimport type { ReportWidget, WidgetRunResult } from './reportModel';\n\n/**\n * The print-optimised view (ANR-16's PDF export — a print stylesheet, not a PDF library: `window.print()` lets\n * the browser's own \"Save as PDF\" do the rendering). Reused by both the in-app Export ▸ PDF flow\n * (`ReportsReportPagePage.tsx`, the owner's own widgets/results) and the public `SharedReportPage` (a synthetic\n * `CHART`-typed widget per result, since a share's snapshot carries no widget title/type — see that file).\n *\n * The toolbar (`print:hidden`) never appears in the printed/PDF output, only on screen. The watermark, when\n * set, is `aria-hidden` (decorative) but rendered both on screen and in print via a fixed, tiled overlay —\n * never only in a `@media print` block this package cannot ship (Tailwind utility classes only, per this\n * repo's design constraints).\n */\nexport function PrintReportView({\n reportName,\n generatedAt,\n watermark,\n widgets,\n results,\n onClose,\n onPrintNow,\n}: {\n reportName: string;\n generatedAt: string;\n watermark?: string | null;\n widgets: ReportWidget[];\n results: Map<string, WidgetRunResult>;\n /** Omit for the public shared view, which has no \"back to the builder\" to return to. */\n onClose?: () => void;\n onPrintNow: () => void;\n}) {\n return (\n <div\n className=\"relative mx-auto max-w-4xl bg-background p-6 text-foreground\"\n data-testid=\"print-report-view\"\n >\n {watermark && (\n <div\n aria-hidden={true}\n className=\"pointer-events-none fixed inset-0 z-50 flex flex-wrap content-around justify-around gap-16 overflow-hidden opacity-10 print:opacity-20\"\n >\n {Array.from({ length: 24 }, (_, i) => (\n <span\n key={i}\n className=\"whitespace-nowrap rotate-[-30deg] text-2xl font-semibold text-foreground\"\n >\n {watermark}\n </span>\n ))}\n </div>\n )}\n\n <div className=\"mb-4 flex items-center justify-between gap-2 print:hidden\">\n <p className=\"text-xs text-muted-foreground\">\n Use your browser’s print dialog to save this as a PDF.\n </p>\n <div className=\"flex gap-2\">\n <Button size=\"sm\" onClick={onPrintNow} data-testid=\"print-report-now\">\n <Printer className=\"mr-1 h-4 w-4\" />\n Print / Save as PDF\n </Button>\n {onClose && (\n <Button size=\"sm\" variant=\"outline\" onClick={onClose}>\n <X className=\"mr-1 h-4 w-4\" />\n Close\n </Button>\n )}\n </div>\n </div>\n\n <header className=\"mb-6 border-b border-border pb-4\">\n <p className=\"text-xs font-semibold uppercase tracking-wide text-primary\">PlanMagnet</p>\n <h1 className=\"text-2xl font-bold\">{reportName}</h1>\n <p className=\"text-sm text-muted-foreground\">\n Generated {new Date(generatedAt).toLocaleString()}\n </p>\n </header>\n\n <div className=\"space-y-6\">\n {widgets.map((widget) => (\n <section\n key={widget.id}\n className=\"break-inside-avoid rounded-md border border-border p-4\"\n >\n {widget.type !== 'TEXT' && (\n <h2 className=\"mb-2 text-base font-semibold\">{widget.title}</h2>\n )}\n <ReportWidgetRenderer widget={widget} runResult={results.get(widget.id)} />\n </section>\n ))}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;AAgBA,SAAgB,EAAgB,EAC9B,eACA,gBACA,cACA,YACA,YACA,YACA,iBAUC;AACD,QACE,kBAAC,OAAD;EACE,WAAU;EACV,eAAY;YAFd;GAIG,KACC,kBAAC,OAAD;IACE,eAAa;IACb,WAAU;cAET,MAAM,KAAK,EAAE,QAAQ,IAAI,GAAG,GAAG,MAC9B,kBAAC,QAAD;KAEE,WAAU;eAET;KACI,EAJA,EAIA,CACP;IACE,CAAA;GAGR,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,KAAD;KAAG,WAAU;eAAgC;KAEzC,CAAA,EACJ,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAQ,MAAK;MAAK,SAAS;MAAY,eAAY;gBAAnD,CACE,kBAAC,GAAD,EAAS,WAAU,gBAAiB,CAAA,EAAA,sBAE7B;SACR,KACC,kBAAC,GAAD;MAAQ,MAAK;MAAK,SAAQ;MAAU,SAAS;gBAA7C,CACE,kBAAC,GAAD,EAAG,WAAU,gBAAiB,CAAA,EAAA,QAEvB;QAEP;OACF;;GAEN,kBAAC,UAAD;IAAQ,WAAU;cAAlB;KACE,kBAAC,KAAD;MAAG,WAAU;gBAA6D;MAAc,CAAA;KACxF,kBAAC,MAAD;MAAI,WAAU;gBAAsB;MAAgB,CAAA;KACpD,kBAAC,KAAD;MAAG,WAAU;gBAAb,CAA6C,cAChC,IAAI,KAAK,EAAY,CAAC,gBAAgB,CAC/C;;KACG;;GAET,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAQ,KAAK,MACZ,kBAAC,WAAD;KAEE,WAAU;eAFZ,CAIG,EAAO,SAAS,UACf,kBAAC,MAAD;MAAI,WAAU;gBAAgC,EAAO;MAAW,CAAA,EAElE,kBAAC,GAAD;MAA8B;MAAQ,WAAW,EAAQ,IAAI,EAAO,GAAG;MAAI,CAAA,CACnE;OAPH,EAAO,GAOJ,CACV;IACE,CAAA;GACF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { FieldError, ReportWidget } from './reportModel';
|
|
2
|
+
|
|
3
|
+
export declare function ReportBuilderCanvas({ widgets, onChange, errors, }: {
|
|
4
|
+
widgets: ReportWidget[];
|
|
5
|
+
onChange: (widgets: ReportWidget[]) => void;
|
|
6
|
+
errors: FieldError[];
|
|
7
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=ReportBuilderCanvas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReportBuilderCanvas.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/reports/ReportBuilderCanvas.tsx"],"names":[],"mappings":"AAIA,OAAO,EAOL,KAAK,UAAU,EACf,KAAK,YAAY,EAElB,MAAM,eAAe,CAAC;AA8OvB,wBAAgB,mBAAmB,CAAC,EAClC,OAAO,EACP,QAAQ,EACR,MAAM,GACP,EAAE;IACD,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,QAAQ,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;IAC5C,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB,2CAsGA"}
|