@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
|
@@ -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 @@
|
|
|
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":";;;;;;;;;;;;;;AAgDA,SAAS,EAAiB,GAAmC;AAC3D,KAAI,CAAC,EAAsB,GAAG,EAAM,CAAE,QAAO;CAC7C,IAAM,IAAQ,EAAM,OAAO,IACrB,IAAQ,GAAO,YAAY;AAEjC,QADI,CAAC,KAAS,OAAO,KAAU,YAAY,CAAC,IAAc,OACnD;EAAE;EAAO,SAAS,EAAM;EAAS;;AAG1C,SAAS,EAAc,GAAsB;CAC3C,IAAM,IAA0C,EAAE;AAOlD,QANI,EAAO,OAAO,cAAW,EAAO,YAAY,EAAO,OAAO,YAC1D,EAAO,OAAO,aAAU,EAAO,WAAW,EAAO,OAAO,WACxD,EAAO,OAAO,WAAQ,EAAO,SAAS,EAAO,OAAO,SACpD,EAAO,OAAO,SAAM,EAAO,OAAO,EAAO,OAAO,OAChD,EAAO,OAAO,OAAI,EAAO,KAAK,EAAO,OAAO,KAC5C,EAAO,OAAO,UAAO,EAAO,QAAQ,EAAO,OAAO,QAC/C;EACL,IAAI,EAAO;EACX,MAAM,EAAO;EACb,OAAO,EAAO;EACd,QAAQ,EAAO;EACf;EACA,QAAQ,EAAO;EAChB;;AAGH,SAAS,EAAkB,EACzB,SACA,aACA,cAKC;CACD,IAAM,EAAE,mBAAgB,GAAe,EACjC,IAAW,GAAuB,EAElC,CAAC,GAAM,KAAW,EAAS,GAAS,QAAQ,GAAG,EAC/C,CAAC,GAAa,KAAkB,EAAS,GAAS,eAAe,GAAG,EACpE,CAAC,GAAY,KAAiB,EAA2B,GAAS,cAAc,UAAU,EAC1F,CAAC,GAAS,KAAc,QACtB,GAAS,WAAW,WAAW,CAAC,IAAa,CAAC,CACrD,EACK,CAAC,GAAS,KAAc,EAAS,GAAM,EACvC,CAAC,GAAa,KAAkB,EAA4B,KAAK,EACjE,CAAC,GAAW,KAAgB,EAAwB,KAAK,EAEzD,CAAC,GAAc,KAAe,EAAY,EAAc,EACxD,CAAC,GAAc,MAAe,EAAY,EAAc,EACxD,IAAS,EAAY,WAAW,GAAY,SAE5C,IAAc,EAAoB,EAAQ,EAC1C,IAAY,KAAW,CAAC,EAAK,MAAM,GAAG,6BAA6B,MACnE,KAAY,IAAc,CAAC,GAAG,GAAa,EAAY,GAAG,GAE1D,KAAa,YAAY;AAI7B,MAHA,EAAW,GAAK,EAChB,EAAa,KAAK,EAClB,EAAe,KAAK,EAChB,CAAC,EAAK,MAAM,IAAI,EAAY,SAAS,EAAG;EAC5C,IAAM,IAAa,EAAE,SAAS,EAAc,EAAQ,CAAC,IAAI,EAAc,EAAE;AACzE,MAAI;AACF,OAAI,MAAS,UAAU;AACrB,QAAI,CAAC,EAAa,OAAU,MAAM,yBAAyB;IAe3D,IAAM,KAdS,MAAM,EACnB,EAAa;KACX,WAAW;MACT;MACA,OAAO;OACL,MAAM,EAAK,MAAM;OACjB,aAAa,EAAY,MAAM,IAAI;OACnC;OACA;OACD;MACF;KACD,SAAS;KACV,CAAC,CACH,EACkB,MACf,wBAAwB;AAC5B,IAAI,KAAI,EAAS,EAAW,wBAAwB,EAAG,CAAC;UAC/C,MACT,MAAM,EACJ,EAAa;IACX,WAAW;KACT,IAAI;KACJ,OAAO;MACL,MAAM,EAAK,MAAM;MACjB,aAAa,EAAY,MAAM,IAAI;MACnC;MACA;MACD;KACF;IACD,SAAS;IACV,CAAC,CACH,EACD,EAAS,EAAW,wBAAwB,EAAS,CAAC;WAEjD,GAAG;GACV,IAAM,IAAQ,EAAiB,EAAE;AACjC,GAAI,KACF,EAAe,EAAM,EACrB,EAAa,2CAA2C,IAExD,EAAa,aAAa,QAAQ,EAAE,UAAU,iCAAiC;;;AAYrF,QACE,kBAAC,OAAD;EAAK,WAAU;EAAgB,eAAY;YAA3C;GACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;eACX,MAAS,WAAW,eAAe;KACjC,CAAA,EACL,kBAAC,KAAD;KAAG,WAAU;eAAgC;KAEzC,CAAA,CACA,EAAA,CAAA,EACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAQ,SAAQ;MAAU,MAAK;MAAK,eAlB1C,EACE,MAAS,UAAU,IACf,EAAW,wBAAwB,EAAS,GAC5C,wBACL;gBAcK,CACE,kBAAC,GAAD,EAAG,WAAU,gBAAiB,CAAA,EAAA,SAEvB;SACT,kBAAC,GAAD;MACE,MAAK;MACL,eAAe,KAAK,IAAY;MAChC,UAAU;MACV,eAAY;gBAJd,CAME,kBAAC,GAAD,EAAM,WAAU,gBAAiB,CAAA,EAChC,IAAS,YAAY,cACf;QACL;OACF;;GAEN,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAW,WAAmB,CAAA,EACnB,CAAA,EACb,kBAAC,GAAD;IAAa,WAAU;cAAvB;KACE,kBAAC,OAAD,EAAA,UAAA;MACE,kBAAC,SAAD;OAAO,SAAQ;OAAc,WAAU;iBAAsB;OAErD,CAAA;MACR,kBAAC,GAAD;OACE,IAAG;OACH,WAAU;OACV,OAAO;OACP,WAAW,MAAM,EAAQ,EAAE,OAAO,MAAM;OACxC,gBAAc,CAAC,CAAC;OAChB,CAAA;MACD,KAAa,kBAAC,KAAD;OAAG,WAAU;iBAAiC;OAAc,CAAA;MACtE,EAAA,CAAA;KACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;MAAO,SAAQ;MAAqB,WAAU;gBAAsB;MAE5D,CAAA,EACR,kBAAC,GAAD;MACE,IAAG;MACH,WAAU;MACV,OAAO;MACP,WAAW,MAAM,EAAe,EAAE,OAAO,MAAM;MAC/C,aAAY;MACZ,CAAA,CACE,EAAA,CAAA;KACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;MAAO,SAAQ;MAAoB,WAAU;gBAAsB;MAE3D,CAAA,EACR,kBAAC,GAAD;MAAQ,OAAO;MAAY,gBAAgB,MAAM,EAAc,EAAsB;gBAArF,CACE,kBAAC,IAAD;OAAe,IAAG;OAAoB,WAAU;iBAC9C,kBAAC,IAAD,EAAe,CAAA;OACD,CAAA,EAChB,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;OAAY,OAAM;iBAAU;OAA8B,CAAA,EAC1D,kBAAC,GAAD;OAAY,OAAM;iBAAY;OAA0C,CAAA,CAC1D,EAAA,CAAA,CACT;QACL,EAAA,CAAA;KACM;MACT,EAAA,CAAA;GAEP,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;IAAa,WAAU;cACrB,kBAAC,GAAD;KAA8B;KAAS,UAAU;KAAY,QAAQ;KAAa,CAAA;IACtE,CAAA,EACT,CAAA;GAEN,KAAa,kBAAC,GAAD,EAAW,SAAS,GAAa,CAAA;GAC3C;;;AAIV,SAAgB,EAAkB,EAChC,SACA,eAIC;CACD,IAAM,IAAW,GAAuB,EAElC,IAAW,EAAoD,GAAY;EAC/E,WAAW,EAAE,IAAI,KAAY,IAAI;EACjC,MAAM,MAAS,UAAU,CAAC;EAC3B,CAAC;AAEF,KAAI,MAAS,SACX,QAAO,kBAAC,GAAD;EAAmB,MAAK;EAAS,SAAS;EAAQ,CAAA;AAI3D,KAAI,EAAS,WAAW,CAAC,EAAS,KAChC,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD,EAAK,WAAU,kFAAmF,CAAA;EAC9F,CAAA;CAGV,IAAM,IAAS,EAAS,MAAM;AAgB9B,QAfK,IAeE,kBAAC,GAAD;EAAmC,MAAK;EAAiB;EAAU,SAAS;EAAU,EAA9D,EAAO,GAAuD,GAbzF,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,KAAD;GAAG,WAAU;aAAgC;GAEzC,CAAA,EACJ,kBAAC,GAAD;GAAQ,MAAK;GAAK,SAAQ;GAAU,eAAe,EAAS,wBAAwB;aAAE;GAE7E,CAAA,CACL"}
|
|
@@ -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"}
|