@burdenoff/microfe-planmagnet 2026.930.25 → 2026.1001.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +160 -147
- package/dist/planmagnet/PlanMagnetRoot.js.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.js +126 -106
- package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
- package/dist/planmagnet/comments/CommentThread.js +36 -36
- package/dist/planmagnet/comments/RoadmapComments.js +21 -21
- package/dist/planmagnet/controls/AutomationRuleControls.js +24 -24
- package/dist/planmagnet/controls/FeatureControls.js +60 -60
- 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/controls/SyncControls.js +59 -59
- package/dist/planmagnet/discussion/WorkItemDiscussionPanel.js +15 -15
- package/dist/planmagnet/docs/DocSuggestionsPanel.js +12 -12
- package/dist/planmagnet/docs/DocVersionCompare.js +3 -3
- package/dist/planmagnet/forecast/DeliveryForecastCard.d.ts +12 -0
- package/dist/planmagnet/forecast/DeliveryForecastCard.d.ts.map +1 -0
- package/dist/planmagnet/forecast/DeliveryForecastCard.js +208 -0
- package/dist/planmagnet/forecast/DeliveryForecastCard.js.map +1 -0
- package/dist/planmagnet/forecast/ProjectOutlookCard.d.ts +5 -0
- package/dist/planmagnet/forecast/ProjectOutlookCard.d.ts.map +1 -0
- package/dist/planmagnet/forecast/ProjectOutlookCard.js +190 -0
- package/dist/planmagnet/forecast/ProjectOutlookCard.js.map +1 -0
- package/dist/planmagnet/forecast/ProjectRiskSummaryCard.d.ts +5 -0
- package/dist/planmagnet/forecast/ProjectRiskSummaryCard.d.ts.map +1 -0
- package/dist/planmagnet/forecast/ProjectRiskSummaryCard.js +99 -0
- package/dist/planmagnet/forecast/ProjectRiskSummaryCard.js.map +1 -0
- package/dist/planmagnet/forecast/ResourceForecastCard.d.ts +8 -0
- package/dist/planmagnet/forecast/ResourceForecastCard.d.ts.map +1 -0
- package/dist/planmagnet/forecast/ResourceForecastCard.js +185 -0
- package/dist/planmagnet/forecast/ResourceForecastCard.js.map +1 -0
- package/dist/planmagnet/forecast/riskFlags.d.ts +35 -0
- package/dist/planmagnet/forecast/riskFlags.d.ts.map +1 -0
- package/dist/planmagnet/forecast/riskFlags.js +37 -0
- package/dist/planmagnet/forecast/riskFlags.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/pages/AnalyticsAnalyticsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.js +216 -182
- package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.js +11 -11
- package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.js +4 -4
- package/dist/planmagnet/pages/DocsDocDetailPagePage.js +163 -163
- package/dist/planmagnet/pages/DocsDocDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/IntegrationsNewSyncPagePage.js +165 -165
- package/dist/planmagnet/pages/IntegrationsNewSyncPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsAtRiskPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProjectsAtRiskPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProjectsAtRiskPagePage.js +234 -0
- package/dist/planmagnet/pages/ProjectsAtRiskPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js +206 -182
- 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/TeamTeamDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TeamTeamDetailPagePage.js +88 -83
- package/dist/planmagnet/pages/TeamTeamDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/analytics/SprintDeliveryCards.d.ts.map +1 -1
- package/dist/planmagnet/pages/analytics/SprintDeliveryCards.js +139 -112
- package/dist/planmagnet/pages/analytics/SprintDeliveryCards.js.map +1 -1
- package/dist/planmagnet/pages/analytics/StatusFlowCard.js +21 -21
- package/dist/planmagnet/product/ProductControls.js +91 -91
- 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 +15 -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/roadmaps/RoadmapControls.js +60 -60
- package/dist/planmagnet/roadmaps/RoadmapNowNextLater.js +30 -30
- package/dist/planmagnet/roadmaps/RoadmapReviewPanel.js +21 -21
- package/dist/planmagnet/roadmaps/RoadmapVersionsPanel.js +22 -22
- package/package.json +6 -4
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { mutationErrorMessage as e } from "../utils/graphqlErrors.js";
|
|
2
|
+
import { throwOnError as t } from "../utils/mutationResult.js";
|
|
3
|
+
import { ConfirmButton as n, ErrorLine as r } from "../controls/ConfirmButton.js";
|
|
4
|
+
import { sharedReportLink as i } from "./sharedReportRoute.js";
|
|
5
|
+
import { CREATE_REPORT_SHARE as a, LIST_REPORT_SHARES as o, REVOKE_REPORT_SHARE as s } from "./reportGraphql.js";
|
|
6
|
+
import { useState as c } from "react";
|
|
7
|
+
import { Check as l, Copy as u, Share2 as d } from "lucide-react";
|
|
8
|
+
import { useMutation as f, useQuery as p } from "@apollo/client/react";
|
|
9
|
+
import { jsx as m, jsxs as h } from "react/jsx-runtime";
|
|
10
|
+
import { Badge as g, Button as _, Input as v, Label as y, ResponsiveDialog as b, ResponsiveDialogContent as x, ResponsiveDialogDescription as S, ResponsiveDialogFooter as C, ResponsiveDialogHeader as ee, ResponsiveDialogTitle as w, ResponsiveDialogTrigger as T } from "@burdenoff/fe-libs/ui";
|
|
11
|
+
import { copyTextToClipboard as E } from "@burdenoff/fe-libs/sharing";
|
|
12
|
+
//#region src/planmagnet/reports/ShareDialog.tsx
|
|
13
|
+
var D = 864e5, O = 7, k = 90;
|
|
14
|
+
function A(e) {
|
|
15
|
+
return new Date(Date.now() + e * D).toISOString().slice(0, 10);
|
|
16
|
+
}
|
|
17
|
+
function j(e) {
|
|
18
|
+
return new Date(e).toLocaleString();
|
|
19
|
+
}
|
|
20
|
+
function M({ reportId: D, runId: M }) {
|
|
21
|
+
let [N, P] = c(!1), [F, I] = c(() => A(O)), [L, R] = c(""), [z, B] = c(""), [V, H] = c(null), [U, W] = c(null), [G, K] = c(!1), q = p(o, {
|
|
22
|
+
variables: { reportId: D },
|
|
23
|
+
skip: !N
|
|
24
|
+
}), [J, Y] = f(a, { refetchQueries: [{
|
|
25
|
+
query: o,
|
|
26
|
+
variables: { reportId: D }
|
|
27
|
+
}] }), [X] = f(s, { refetchQueries: [{
|
|
28
|
+
query: o,
|
|
29
|
+
variables: { reportId: D }
|
|
30
|
+
}] }), Z = async () => {
|
|
31
|
+
if (M) {
|
|
32
|
+
H(null), W(null);
|
|
33
|
+
try {
|
|
34
|
+
let e = (await t(J({ variables: {
|
|
35
|
+
runId: M,
|
|
36
|
+
input: {
|
|
37
|
+
expiresAt: `${F}T23:59:59.999Z`,
|
|
38
|
+
password: L.trim() || void 0,
|
|
39
|
+
watermark: z.trim() || void 0
|
|
40
|
+
}
|
|
41
|
+
} }))).data?.planmagnetCreateReportShare;
|
|
42
|
+
e && (W(e), K(!1), R(""), B(""));
|
|
43
|
+
} catch (t) {
|
|
44
|
+
H(e(t, "The share link could not be created."));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}, Q = async (n) => {
|
|
48
|
+
H(null);
|
|
49
|
+
try {
|
|
50
|
+
await t(X({ variables: { id: n } })), U?.id === n && W(null);
|
|
51
|
+
} catch (t) {
|
|
52
|
+
H(e(t, "The share could not be revoked."));
|
|
53
|
+
}
|
|
54
|
+
}, te = async (e) => {
|
|
55
|
+
try {
|
|
56
|
+
await E(i(e)), K(!0);
|
|
57
|
+
} catch {
|
|
58
|
+
H("Could not copy — copy the link manually.");
|
|
59
|
+
}
|
|
60
|
+
}, $ = q.data?.planmagnetReportShares ?? [];
|
|
61
|
+
return /* @__PURE__ */ h(b, {
|
|
62
|
+
open: N,
|
|
63
|
+
onOpenChange: (e) => {
|
|
64
|
+
P(e), e || (W(null), H(null));
|
|
65
|
+
},
|
|
66
|
+
children: [/* @__PURE__ */ m(T, {
|
|
67
|
+
asChild: !0,
|
|
68
|
+
children: /* @__PURE__ */ h(_, {
|
|
69
|
+
size: "sm",
|
|
70
|
+
variant: "outline",
|
|
71
|
+
"data-testid": "report-share",
|
|
72
|
+
children: [/* @__PURE__ */ m(d, { className: "mr-1 h-4 w-4" }), "Share"]
|
|
73
|
+
})
|
|
74
|
+
}), /* @__PURE__ */ h(x, {
|
|
75
|
+
className: "max-h-[85vh] overflow-y-auto sm:max-w-lg",
|
|
76
|
+
children: [
|
|
77
|
+
/* @__PURE__ */ h(ee, { children: [/* @__PURE__ */ m(w, { children: "Share this report" }), /* @__PURE__ */ m(S, { children: "Anyone with the link can view the most recently shared run, read-only, without signing in." })] }),
|
|
78
|
+
!M && /* @__PURE__ */ m("p", {
|
|
79
|
+
className: "text-sm text-muted-foreground",
|
|
80
|
+
children: "Run this report at least once before sharing it — a share links to one specific run."
|
|
81
|
+
}),
|
|
82
|
+
M && /* @__PURE__ */ h("div", {
|
|
83
|
+
className: "space-y-3 rounded-md border border-border p-3",
|
|
84
|
+
children: [
|
|
85
|
+
/* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m(y, {
|
|
86
|
+
htmlFor: "share-expiry",
|
|
87
|
+
children: "Expires"
|
|
88
|
+
}), /* @__PURE__ */ m(v, {
|
|
89
|
+
id: "share-expiry",
|
|
90
|
+
type: "date",
|
|
91
|
+
className: "mt-1",
|
|
92
|
+
value: F,
|
|
93
|
+
min: A(1),
|
|
94
|
+
max: A(k),
|
|
95
|
+
onChange: (e) => I(e.target.value)
|
|
96
|
+
})] }),
|
|
97
|
+
/* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m(y, {
|
|
98
|
+
htmlFor: "share-password",
|
|
99
|
+
children: "Password (optional)"
|
|
100
|
+
}), /* @__PURE__ */ m(v, {
|
|
101
|
+
id: "share-password",
|
|
102
|
+
type: "password",
|
|
103
|
+
className: "mt-1",
|
|
104
|
+
value: L,
|
|
105
|
+
onChange: (e) => R(e.target.value),
|
|
106
|
+
placeholder: "Leave blank for no password"
|
|
107
|
+
})] }),
|
|
108
|
+
/* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m(y, {
|
|
109
|
+
htmlFor: "share-watermark",
|
|
110
|
+
children: "Watermark text (optional)"
|
|
111
|
+
}), /* @__PURE__ */ m(v, {
|
|
112
|
+
id: "share-watermark",
|
|
113
|
+
className: "mt-1",
|
|
114
|
+
value: z,
|
|
115
|
+
onChange: (e) => B(e.target.value),
|
|
116
|
+
placeholder: `Shared via PlanMagnet on ${(/* @__PURE__ */ new Date()).toLocaleDateString()}`
|
|
117
|
+
})] }),
|
|
118
|
+
/* @__PURE__ */ m(_, {
|
|
119
|
+
size: "sm",
|
|
120
|
+
onClick: Z,
|
|
121
|
+
disabled: Y.loading,
|
|
122
|
+
"data-testid": "report-share-create",
|
|
123
|
+
children: Y.loading ? "Creating…" : "Create share link"
|
|
124
|
+
})
|
|
125
|
+
]
|
|
126
|
+
}),
|
|
127
|
+
U?.token && /* @__PURE__ */ h("div", {
|
|
128
|
+
className: "space-y-2 rounded-md border border-primary bg-primary/5 p-3",
|
|
129
|
+
"data-testid": "report-share-link",
|
|
130
|
+
children: [
|
|
131
|
+
/* @__PURE__ */ m("p", {
|
|
132
|
+
className: "text-sm font-medium",
|
|
133
|
+
children: "Link created — copy it now."
|
|
134
|
+
}),
|
|
135
|
+
/* @__PURE__ */ m("p", {
|
|
136
|
+
className: "text-xs text-muted-foreground",
|
|
137
|
+
children: "You will not see this link again. If you lose it, revoke this share and create a new one."
|
|
138
|
+
}),
|
|
139
|
+
/* @__PURE__ */ h("div", {
|
|
140
|
+
className: "flex items-center gap-2",
|
|
141
|
+
children: [/* @__PURE__ */ m(v, {
|
|
142
|
+
readOnly: !0,
|
|
143
|
+
value: i(U.token),
|
|
144
|
+
className: "text-xs"
|
|
145
|
+
}), /* @__PURE__ */ h(_, {
|
|
146
|
+
size: "sm",
|
|
147
|
+
variant: "outline",
|
|
148
|
+
onClick: () => te(U.token),
|
|
149
|
+
children: [m(G ? l : u, { className: "h-4 w-4" }), G ? "Copied" : "Copy"]
|
|
150
|
+
})]
|
|
151
|
+
})
|
|
152
|
+
]
|
|
153
|
+
}),
|
|
154
|
+
V && /* @__PURE__ */ m(r, { message: V }),
|
|
155
|
+
/* @__PURE__ */ h("div", {
|
|
156
|
+
className: "space-y-2",
|
|
157
|
+
"data-testid": "report-shares",
|
|
158
|
+
children: [/* @__PURE__ */ m("h3", {
|
|
159
|
+
className: "text-sm font-semibold",
|
|
160
|
+
children: "Existing shares"
|
|
161
|
+
}), q.loading && !q.data ? /* @__PURE__ */ m("p", {
|
|
162
|
+
className: "text-sm text-muted-foreground",
|
|
163
|
+
children: "Loading…"
|
|
164
|
+
}) : $.length === 0 ? /* @__PURE__ */ m("p", {
|
|
165
|
+
className: "text-sm text-muted-foreground",
|
|
166
|
+
children: "No shares yet."
|
|
167
|
+
}) : /* @__PURE__ */ m("ul", {
|
|
168
|
+
className: "space-y-2",
|
|
169
|
+
children: $.map((e) => {
|
|
170
|
+
let t = !!e.revokedAt, r = !t && new Date(e.expiresAt).getTime() < (/* @__PURE__ */ new Date()).getTime();
|
|
171
|
+
return /* @__PURE__ */ h("li", {
|
|
172
|
+
className: "flex flex-wrap items-center justify-between gap-2 rounded-md border border-border p-2 text-xs",
|
|
173
|
+
children: [/* @__PURE__ */ h("div", {
|
|
174
|
+
className: "space-y-0.5",
|
|
175
|
+
children: [
|
|
176
|
+
/* @__PURE__ */ h("div", {
|
|
177
|
+
className: "flex items-center gap-1.5",
|
|
178
|
+
children: [/* @__PURE__ */ m(g, {
|
|
179
|
+
variant: t ? "secondary" : r ? "warning" : "success",
|
|
180
|
+
children: t ? "Revoked" : r ? "Expired" : "Active"
|
|
181
|
+
}), e.hasPassword && /* @__PURE__ */ m(g, {
|
|
182
|
+
variant: "outline",
|
|
183
|
+
children: "Password"
|
|
184
|
+
})]
|
|
185
|
+
}),
|
|
186
|
+
/* @__PURE__ */ h("p", {
|
|
187
|
+
className: "text-muted-foreground",
|
|
188
|
+
children: [
|
|
189
|
+
"Created ",
|
|
190
|
+
j(e.createdAt),
|
|
191
|
+
" · Expires",
|
|
192
|
+
" ",
|
|
193
|
+
j(e.expiresAt)
|
|
194
|
+
]
|
|
195
|
+
}),
|
|
196
|
+
/* @__PURE__ */ h("p", {
|
|
197
|
+
className: "text-muted-foreground",
|
|
198
|
+
children: [
|
|
199
|
+
"Accessed ",
|
|
200
|
+
e.accessCount,
|
|
201
|
+
" time",
|
|
202
|
+
e.accessCount === 1 ? "" : "s",
|
|
203
|
+
e.lastAccessedAt ? ` · last ${j(e.lastAccessedAt)}` : ""
|
|
204
|
+
]
|
|
205
|
+
})
|
|
206
|
+
]
|
|
207
|
+
}), !t && /* @__PURE__ */ m(n, {
|
|
208
|
+
label: "Revoke",
|
|
209
|
+
icon: null,
|
|
210
|
+
title: "Revoke this share?",
|
|
211
|
+
description: "Anyone with this link loses access immediately. This cannot be undone.",
|
|
212
|
+
confirmLabel: "Revoke",
|
|
213
|
+
destructive: !0,
|
|
214
|
+
variant: "outline",
|
|
215
|
+
disabled: !1,
|
|
216
|
+
onConfirm: () => void Q(e.id)
|
|
217
|
+
})]
|
|
218
|
+
}, e.id);
|
|
219
|
+
})
|
|
220
|
+
})]
|
|
221
|
+
}),
|
|
222
|
+
/* @__PURE__ */ m(C, { children: /* @__PURE__ */ m(_, {
|
|
223
|
+
variant: "outline",
|
|
224
|
+
onClick: () => P(!1),
|
|
225
|
+
children: "Close"
|
|
226
|
+
}) })
|
|
227
|
+
]
|
|
228
|
+
})]
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
//#endregion
|
|
232
|
+
export { M as ShareDialog };
|
|
233
|
+
|
|
234
|
+
//# sourceMappingURL=ShareDialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ShareDialog.js","names":[],"sources":["../../../src/planmagnet/reports/ShareDialog.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport {\n Badge,\n Button,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogTrigger,\n Input,\n Label,\n} from '@burdenoff/fe-libs/ui';\nimport { Check, Copy, Share2 } from 'lucide-react';\nimport { copyTextToClipboard } from '@burdenoff/fe-libs/sharing';\nimport { ConfirmButton, ErrorLine } from '../controls/ConfirmButton';\nimport { mutationErrorMessage } from '../utils/graphqlErrors';\nimport { throwOnError } from '../utils/mutationResult';\nimport { CREATE_REPORT_SHARE, LIST_REPORT_SHARES, REVOKE_REPORT_SHARE } from './reportGraphql';\nimport { sharedReportLink } from './sharedReportRoute';\nimport type { ReportShare } from './reportModel';\n\n/** Share links (ANR-16), owner-only — a report's owner creates a link to one persisted run; anyone with the\n * link (and the password, if set) can view that run's snapshot read-only at `/public/report/<token>`, no\n * workspace login required. The raw token is shown exactly once, right after creation. */\n\nconst DAY_MS = 86_400_000;\nconst DEFAULT_EXPIRY_DAYS = 7;\nconst MAX_EXPIRY_DAYS = 90;\n\nfunction dateInputValue(daysFromNow: number): string {\n return new Date(Date.now() + daysFromNow * DAY_MS).toISOString().slice(0, 10);\n}\n\nfunction formatDate(iso: string): string {\n return new Date(iso).toLocaleString();\n}\n\nexport function ShareDialog({ reportId, runId }: { reportId: string; runId: string | null }) {\n const [open, setOpen] = useState(false);\n const [expiresAt, setExpiresAt] = useState(() => dateInputValue(DEFAULT_EXPIRY_DAYS));\n const [password, setPassword] = useState('');\n const [watermark, setWatermark] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [justCreated, setJustCreated] = useState<ReportShare | null>(null);\n const [copied, setCopied] = useState(false);\n\n const shares = useQuery<{ planmagnetReportShares: ReportShare[] }>(LIST_REPORT_SHARES, {\n variables: { reportId },\n skip: !open,\n });\n const [createShare, createState] = useMutation(CREATE_REPORT_SHARE, {\n refetchQueries: [{ query: LIST_REPORT_SHARES, variables: { reportId } }],\n });\n const [revokeShare] = useMutation(REVOKE_REPORT_SHARE, {\n refetchQueries: [{ query: LIST_REPORT_SHARES, variables: { reportId } }],\n });\n\n const handleCreate = async () => {\n if (!runId) return;\n setError(null);\n setJustCreated(null);\n try {\n const result = await throwOnError(\n createShare({\n variables: {\n runId,\n input: {\n expiresAt: `${expiresAt}T23:59:59.999Z`,\n password: password.trim() || undefined,\n watermark: watermark.trim() || undefined,\n },\n },\n })\n );\n const share = (result.data as { planmagnetCreateReportShare?: ReportShare } | undefined)\n ?.planmagnetCreateReportShare;\n if (share) {\n setJustCreated(share);\n setCopied(false);\n setPassword('');\n setWatermark('');\n }\n } catch (e) {\n setError(mutationErrorMessage(e, 'The share link could not be created.'));\n }\n };\n\n const handleRevoke = async (id: string) => {\n setError(null);\n try {\n await throwOnError(revokeShare({ variables: { id } }));\n if (justCreated?.id === id) setJustCreated(null);\n } catch (e) {\n setError(mutationErrorMessage(e, 'The share could not be revoked.'));\n }\n };\n\n const copyLink = async (token: string) => {\n try {\n await copyTextToClipboard(sharedReportLink(token));\n setCopied(true);\n } catch {\n setError('Could not copy — copy the link manually.');\n }\n };\n\n const list = shares.data?.planmagnetReportShares ?? [];\n\n return (\n <ResponsiveDialog\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) {\n setJustCreated(null);\n setError(null);\n }\n }}\n >\n <ResponsiveDialogTrigger asChild>\n <Button size=\"sm\" variant=\"outline\" data-testid=\"report-share\">\n <Share2 className=\"mr-1 h-4 w-4\" />\n Share\n </Button>\n </ResponsiveDialogTrigger>\n <ResponsiveDialogContent className=\"max-h-[85vh] overflow-y-auto sm:max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Share this report</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Anyone with the link can view the most recently shared run, read-only, without signing\n in.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n {!runId && (\n <p className=\"text-sm text-muted-foreground\">\n Run this report at least once before sharing it — a share links to one specific run.\n </p>\n )}\n\n {runId && (\n <div className=\"space-y-3 rounded-md border border-border p-3\">\n <div>\n <Label htmlFor=\"share-expiry\">Expires</Label>\n <Input\n id=\"share-expiry\"\n type=\"date\"\n className=\"mt-1\"\n value={expiresAt}\n min={dateInputValue(1)}\n max={dateInputValue(MAX_EXPIRY_DAYS)}\n onChange={(e) => setExpiresAt(e.target.value)}\n />\n </div>\n <div>\n <Label htmlFor=\"share-password\">Password (optional)</Label>\n <Input\n id=\"share-password\"\n type=\"password\"\n className=\"mt-1\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n placeholder=\"Leave blank for no password\"\n />\n </div>\n <div>\n <Label htmlFor=\"share-watermark\">Watermark text (optional)</Label>\n <Input\n id=\"share-watermark\"\n className=\"mt-1\"\n value={watermark}\n onChange={(e) => setWatermark(e.target.value)}\n placeholder={`Shared via PlanMagnet on ${new Date().toLocaleDateString()}`}\n />\n </div>\n <Button\n size=\"sm\"\n onClick={handleCreate}\n disabled={createState.loading}\n data-testid=\"report-share-create\"\n >\n {createState.loading ? 'Creating…' : 'Create share link'}\n </Button>\n </div>\n )}\n\n {justCreated?.token && (\n <div\n className=\"space-y-2 rounded-md border border-primary bg-primary/5 p-3\"\n data-testid=\"report-share-link\"\n >\n <p className=\"text-sm font-medium\">Link created — copy it now.</p>\n <p className=\"text-xs text-muted-foreground\">\n You will not see this link again. If you lose it, revoke this share and create a new\n one.\n </p>\n <div className=\"flex items-center gap-2\">\n <Input readOnly value={sharedReportLink(justCreated.token)} className=\"text-xs\" />\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => copyLink(justCreated.token as string)}\n >\n {copied ? <Check className=\"h-4 w-4\" /> : <Copy className=\"h-4 w-4\" />}\n {copied ? 'Copied' : 'Copy'}\n </Button>\n </div>\n </div>\n )}\n\n {error && <ErrorLine message={error} />}\n\n <div className=\"space-y-2\" data-testid=\"report-shares\">\n <h3 className=\"text-sm font-semibold\">Existing shares</h3>\n {shares.loading && !shares.data ? (\n <p className=\"text-sm text-muted-foreground\">Loading…</p>\n ) : list.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">No shares yet.</p>\n ) : (\n <ul className=\"space-y-2\">\n {list.map((share) => {\n const revoked = !!share.revokedAt;\n const expired =\n !revoked && new Date(share.expiresAt).getTime() < new Date().getTime();\n return (\n <li\n key={share.id}\n className=\"flex flex-wrap items-center justify-between gap-2 rounded-md border border-border p-2 text-xs\"\n >\n <div className=\"space-y-0.5\">\n <div className=\"flex items-center gap-1.5\">\n <Badge variant={revoked ? 'secondary' : expired ? 'warning' : 'success'}>\n {revoked ? 'Revoked' : expired ? 'Expired' : 'Active'}\n </Badge>\n {share.hasPassword && <Badge variant=\"outline\">Password</Badge>}\n </div>\n <p className=\"text-muted-foreground\">\n Created {formatDate(share.createdAt)} · Expires{' '}\n {formatDate(share.expiresAt)}\n </p>\n <p className=\"text-muted-foreground\">\n Accessed {share.accessCount} time{share.accessCount === 1 ? '' : 's'}\n {share.lastAccessedAt ? ` · last ${formatDate(share.lastAccessedAt)}` : ''}\n </p>\n </div>\n {!revoked && (\n <ConfirmButton\n label=\"Revoke\"\n icon={null}\n title=\"Revoke this share?\"\n description=\"Anyone with this link loses access immediately. This cannot be undone.\"\n confirmLabel=\"Revoke\"\n destructive\n variant=\"outline\"\n disabled={false}\n onConfirm={() => void handleRevoke(share.id)}\n />\n )}\n </li>\n );\n })}\n </ul>\n )}\n </div>\n\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setOpen(false)}>\n Close\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SharedReportPage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/reports/SharedReportPage.tsx"],"names":[],"mappings":"AAyFA,wBAAgB,gBAAgB,CAAC,EAAE,aAAa,EAAE,GAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAO,2CA4JlF"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { PrintReportView as e } from "./PrintReportView.js";
|
|
2
|
+
import { useCallback as t, useEffect as n, useState as r } from "react";
|
|
3
|
+
import { Lock as i, ShieldOff as a } from "lucide-react";
|
|
4
|
+
import { useParams as o } from "react-router";
|
|
5
|
+
import { jsx as s, jsxs as c } from "react/jsx-runtime";
|
|
6
|
+
import { Button as l, Input as u, Label as d } from "@burdenoff/fe-libs/ui";
|
|
7
|
+
//#region src/planmagnet/reports/SharedReportPage.tsx
|
|
8
|
+
var f = "\n query PublicPlanmagnetSharedReport($token: String!, $password: String) {\n planmagnetSharedReport(token: $token, password: $password) {\n reportName\n generatedAt\n watermark\n widgets {\n widgetId\n source\n status\n message\n result\n }\n }\n }\n", p = "reportShare.errors.credentialRequired", m = "reportShare.errors.tooManyAttempts";
|
|
9
|
+
async function h(e, t, n) {
|
|
10
|
+
let r = `${e ?? ""}/workspaces/graphql`, i = await (await fetch(r, {
|
|
11
|
+
method: "POST",
|
|
12
|
+
headers: { "Content-Type": "application/json" },
|
|
13
|
+
body: JSON.stringify({
|
|
14
|
+
query: f,
|
|
15
|
+
variables: {
|
|
16
|
+
token: t,
|
|
17
|
+
password: n || null
|
|
18
|
+
}
|
|
19
|
+
})
|
|
20
|
+
})).json().catch(() => null), a = i?.errors?.[0]?.extensions?.i18nKey ?? (i?.errors?.length ? "unknown" : null);
|
|
21
|
+
return {
|
|
22
|
+
data: i?.data?.planmagnetSharedReport ?? null,
|
|
23
|
+
errorKey: a
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function g(e) {
|
|
27
|
+
return e.widgets.map((e, t) => ({
|
|
28
|
+
id: e.widgetId,
|
|
29
|
+
type: "CHART",
|
|
30
|
+
title: `Widget ${t + 1}`,
|
|
31
|
+
source: e.source,
|
|
32
|
+
params: {},
|
|
33
|
+
layout: {
|
|
34
|
+
x: 0,
|
|
35
|
+
y: 0,
|
|
36
|
+
w: 12,
|
|
37
|
+
h: 4
|
|
38
|
+
}
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
function _({ apiGatewayUrl: f } = {}) {
|
|
42
|
+
let { token: _ } = o(), [y, b] = r({ kind: "loading" }), [x, S] = r(""), [C, w] = r(!1), T = t((e, t, n) => {
|
|
43
|
+
b(e ? {
|
|
44
|
+
kind: "ready",
|
|
45
|
+
report: e
|
|
46
|
+
} : t === p ? {
|
|
47
|
+
kind: "needsPassword",
|
|
48
|
+
wrong: n
|
|
49
|
+
} : t === m ? { kind: "rateLimited" } : { kind: "invalid" });
|
|
50
|
+
}, []);
|
|
51
|
+
n(() => {
|
|
52
|
+
if (!_) return;
|
|
53
|
+
let e = !1;
|
|
54
|
+
return (async () => {
|
|
55
|
+
let { data: t, errorKey: n } = await h(f, _, "");
|
|
56
|
+
e || T(t, n, !1);
|
|
57
|
+
})().catch(() => {
|
|
58
|
+
e || b({ kind: "invalid" });
|
|
59
|
+
}), () => {
|
|
60
|
+
e = !0;
|
|
61
|
+
};
|
|
62
|
+
}, [
|
|
63
|
+
_,
|
|
64
|
+
f,
|
|
65
|
+
T
|
|
66
|
+
]);
|
|
67
|
+
let E = async (e) => {
|
|
68
|
+
if (_) {
|
|
69
|
+
w(!0);
|
|
70
|
+
try {
|
|
71
|
+
let { data: t, errorKey: n } = await h(f, _, e);
|
|
72
|
+
T(t, n, !0);
|
|
73
|
+
} catch {
|
|
74
|
+
b({ kind: "invalid" });
|
|
75
|
+
} finally {
|
|
76
|
+
w(!1);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
if (!_) return /* @__PURE__ */ s(v, { children: /* @__PURE__ */ c("div", {
|
|
81
|
+
className: "flex flex-col items-center gap-2 text-center",
|
|
82
|
+
"data-testid": "shared-report",
|
|
83
|
+
children: [/* @__PURE__ */ s(a, {
|
|
84
|
+
className: "h-8 w-8 text-muted-foreground",
|
|
85
|
+
"aria-hidden": !0
|
|
86
|
+
}), /* @__PURE__ */ s("p", {
|
|
87
|
+
className: "text-sm text-muted-foreground",
|
|
88
|
+
children: "This link is invalid or has expired."
|
|
89
|
+
})]
|
|
90
|
+
}) });
|
|
91
|
+
if (y.kind === "loading") return /* @__PURE__ */ s(v, { children: /* @__PURE__ */ s("p", {
|
|
92
|
+
className: "text-sm text-muted-foreground",
|
|
93
|
+
children: "Loading…"
|
|
94
|
+
}) });
|
|
95
|
+
if (y.kind === "invalid") return /* @__PURE__ */ s(v, { children: /* @__PURE__ */ c("div", {
|
|
96
|
+
className: "flex flex-col items-center gap-2 text-center",
|
|
97
|
+
"data-testid": "shared-report",
|
|
98
|
+
children: [/* @__PURE__ */ s(a, {
|
|
99
|
+
className: "h-8 w-8 text-muted-foreground",
|
|
100
|
+
"aria-hidden": !0
|
|
101
|
+
}), /* @__PURE__ */ s("p", {
|
|
102
|
+
className: "text-sm text-muted-foreground",
|
|
103
|
+
children: "This link is invalid or has expired."
|
|
104
|
+
})]
|
|
105
|
+
}) });
|
|
106
|
+
if (y.kind === "rateLimited") return /* @__PURE__ */ s(v, { children: /* @__PURE__ */ c("div", {
|
|
107
|
+
className: "flex flex-col items-center gap-2 text-center",
|
|
108
|
+
"data-testid": "shared-report",
|
|
109
|
+
children: [/* @__PURE__ */ s(i, {
|
|
110
|
+
className: "h-8 w-8 text-muted-foreground",
|
|
111
|
+
"aria-hidden": !0
|
|
112
|
+
}), /* @__PURE__ */ s("p", {
|
|
113
|
+
className: "text-sm text-muted-foreground",
|
|
114
|
+
children: "Too many attempts. Try again later."
|
|
115
|
+
})]
|
|
116
|
+
}) });
|
|
117
|
+
if (y.kind === "needsPassword") return /* @__PURE__ */ s(v, { children: /* @__PURE__ */ c("form", {
|
|
118
|
+
className: "mx-auto max-w-xs space-y-3",
|
|
119
|
+
"data-testid": "shared-report",
|
|
120
|
+
onSubmit: (e) => {
|
|
121
|
+
e.preventDefault(), E(x);
|
|
122
|
+
},
|
|
123
|
+
children: [
|
|
124
|
+
/* @__PURE__ */ c("div", {
|
|
125
|
+
className: "flex flex-col items-center gap-2 text-center",
|
|
126
|
+
children: [/* @__PURE__ */ s(i, {
|
|
127
|
+
className: "h-8 w-8 text-muted-foreground",
|
|
128
|
+
"aria-hidden": !0
|
|
129
|
+
}), /* @__PURE__ */ s("p", {
|
|
130
|
+
className: "text-sm",
|
|
131
|
+
children: y.wrong ? "That password didn't work — try again." : "This report is password-protected."
|
|
132
|
+
})]
|
|
133
|
+
}),
|
|
134
|
+
/* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s(d, {
|
|
135
|
+
htmlFor: "shared-report-password",
|
|
136
|
+
children: "Password"
|
|
137
|
+
}), /* @__PURE__ */ s(u, {
|
|
138
|
+
id: "shared-report-password",
|
|
139
|
+
type: "password",
|
|
140
|
+
className: "mt-1",
|
|
141
|
+
autoFocus: !0,
|
|
142
|
+
value: x,
|
|
143
|
+
onChange: (e) => S(e.target.value),
|
|
144
|
+
"aria-invalid": y.wrong,
|
|
145
|
+
"data-testid": "shared-report-password"
|
|
146
|
+
})] }),
|
|
147
|
+
/* @__PURE__ */ s(l, {
|
|
148
|
+
type: "submit",
|
|
149
|
+
className: "w-full",
|
|
150
|
+
disabled: C || !x,
|
|
151
|
+
children: C ? "Checking…" : "View report"
|
|
152
|
+
})
|
|
153
|
+
]
|
|
154
|
+
}) });
|
|
155
|
+
let D = g(y.report), O = new Map(y.report.widgets.map((e) => [e.widgetId, e]));
|
|
156
|
+
return /* @__PURE__ */ s(e, {
|
|
157
|
+
reportName: y.report.reportName,
|
|
158
|
+
generatedAt: y.report.generatedAt,
|
|
159
|
+
watermark: y.report.watermark,
|
|
160
|
+
widgets: D,
|
|
161
|
+
results: O,
|
|
162
|
+
onPrintNow: () => window.print()
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
function v({ children: e }) {
|
|
166
|
+
return /* @__PURE__ */ s("div", {
|
|
167
|
+
className: "flex min-h-screen items-center justify-center bg-background p-6 text-foreground",
|
|
168
|
+
children: /* @__PURE__ */ c("div", {
|
|
169
|
+
className: "w-full max-w-sm rounded-lg border border-border p-6",
|
|
170
|
+
children: [/* @__PURE__ */ s("p", {
|
|
171
|
+
className: "mb-4 text-center text-xs font-semibold uppercase tracking-wide text-primary",
|
|
172
|
+
children: "PlanMagnet"
|
|
173
|
+
}), e]
|
|
174
|
+
})
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
//#endregion
|
|
178
|
+
export { _ as SharedReportPage };
|
|
179
|
+
|
|
180
|
+
//# sourceMappingURL=SharedReportPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SharedReportPage.js","names":[],"sources":["../../../src/planmagnet/reports/SharedReportPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useState, type ReactNode } from 'react';\nimport { useParams } from 'react-router';\nimport { Button, Input, Label } from '@burdenoff/fe-libs/ui';\nimport { Lock, ShieldOff } from 'lucide-react';\nimport { PrintReportView } from './PrintReportView';\nimport type { ReportWidget, SharedReport } from './reportModel';\n\n/**\n * The public, unauthenticated view a share link resolves to (ANR-17). Exported standalone from the package\n * index so the host app can mount it OUTSIDE its auth guard/nav chrome, on its own top-level route\n * (`sharedReportRoute.ts`'s `SHARED_REPORT_ROUTE_PATH`) — it never touches `PlanMagnetProvider`/`usePlanMagnet`\n * (there is no workspace/actor context here) and issues a plain, unauthenticated `fetch` to the same\n * `/workspaces/graphql` path `PlanMagnetProvider.tsx` builds its Apollo client's `HttpLink` from — the viewer's\n * own token, if this happens to render inside an authenticated session, is never read or attached.\n *\n * `planmagnetSharedReport` carries no widget title/type (`PlanmagnetSharedReport`'s own schema doc: \"never any\n * actor id beyond what the snapshot's widget data already shows\" — deliberately minimal). Each result is given\n * a synthetic `CHART`-typed widget so `ReportWidgetRenderer` picks the richest generic presentation it can\n * (a chart when the data supports one, falling back to KPI tiles or its accessible data table otherwise).\n */\n\nconst QUERY = `\n query PublicPlanmagnetSharedReport($token: String!, $password: String) {\n planmagnetSharedReport(token: $token, password: $password) {\n reportName\n generatedAt\n watermark\n widgets {\n widgetId\n source\n status\n message\n result\n }\n }\n }\n`;\n\ninterface FetchResult {\n data: SharedReport | null;\n /** The i18nKey of the one GraphQL error, when there was one (see report-share.service.ts). */\n errorKey: string | null;\n}\n\n/** `report-share.service.ts`'s own error keys for the two refusals this page must tell apart from a plain\n * \"invalid or expired\" — same message/key for \"no password yet\" and \"wrong password\" (the server never\n * distinguishes the two), so this page tracks locally whether a password was already tried. */\nconst CREDENTIAL_REQUIRED_KEY = 'reportShare.errors.credentialRequired';\nconst RATE_LIMITED_KEY = 'reportShare.errors.tooManyAttempts';\n\nasync function fetchSharedReport(\n apiGatewayUrl: string | undefined,\n token: string,\n password: string\n): Promise<FetchResult> {\n const endpoint = `${apiGatewayUrl ?? ''}/workspaces/graphql`;\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ query: QUERY, variables: { token, password: password || null } }),\n });\n const body = (await response.json().catch(() => null)) as {\n data?: { planmagnetSharedReport: SharedReport | null };\n errors?: { message: string; extensions?: { i18nKey?: string } }[];\n } | null;\n const errorKey =\n body?.errors?.[0]?.extensions?.i18nKey ?? (body?.errors?.length ? 'unknown' : null);\n return { data: body?.data?.planmagnetSharedReport ?? null, errorKey };\n}\n\n/** Every result gets a synthetic `CHART` widget — see this file's header. */\nfunction syntheticWidgets(report: SharedReport): ReportWidget[] {\n return report.widgets.map((w, index) => ({\n id: w.widgetId,\n type: 'CHART',\n title: `Widget ${index + 1}`,\n source: w.source,\n params: {},\n layout: { x: 0, y: 0, w: 12, h: 4 },\n }));\n}\n\ntype ViewState =\n | { kind: 'loading' }\n | { kind: 'needsPassword'; wrong: boolean }\n | { kind: 'rateLimited' }\n | { kind: 'invalid' }\n | { kind: 'ready'; report: SharedReport };\n\nexport function SharedReportPage({ apiGatewayUrl }: { apiGatewayUrl?: string } = {}) {\n const { token } = useParams<{ token: string }>();\n const [state, setState] = useState<ViewState>({ kind: 'loading' });\n const [password, setPassword] = useState('');\n const [submitting, setSubmitting] = useState(false);\n\n /** Maps one `fetchSharedReport` outcome to the view state — shared by the initial load below and the\n * password-retry submit handler further down, so the two ways of arriving at a result agree exactly. */\n const applyResult = useCallback(\n (data: SharedReport | null, errorKey: string | null, triedPassword: boolean) => {\n if (data) {\n setState({ kind: 'ready', report: data });\n } else if (errorKey === CREDENTIAL_REQUIRED_KEY) {\n setState({ kind: 'needsPassword', wrong: triedPassword });\n } else if (errorKey === RATE_LIMITED_KEY) {\n setState({ kind: 'rateLimited' });\n } else {\n setState({ kind: 'invalid' });\n }\n },\n []\n );\n\n // The initial, unauthenticated (no password) load. Its only `setState` calls happen after the `await` —\n // matching `sprints/SprintControls.tsx`'s established pattern for an effect that fetches — so there is\n // nothing to reset to \"loading\" beforehand: the `useState` above already starts in that state.\n useEffect(() => {\n // No token at all (a misconfigured host route) renders as invalid directly from `token` below, without\n // this effect ever running a fetch or touching state.\n if (!token) return;\n let cancelled = false;\n (async () => {\n const { data, errorKey } = await fetchSharedReport(apiGatewayUrl, token, '');\n if (cancelled) return;\n applyResult(data, errorKey, false);\n })().catch(() => {\n if (!cancelled) setState({ kind: 'invalid' });\n });\n return () => {\n cancelled = true;\n };\n }, [token, apiGatewayUrl, applyResult]);\n\n // The password-retry path: an event handler (the form's `onSubmit` below), not an effect, so freely setting\n // `submitting` synchronously here is unrestricted.\n const submitPassword = async (withPassword: string) => {\n if (!token) return;\n setSubmitting(true);\n try {\n const { data, errorKey } = await fetchSharedReport(apiGatewayUrl, token, withPassword);\n applyResult(data, errorKey, true);\n } catch {\n setState({ kind: 'invalid' });\n } finally {\n setSubmitting(false);\n }\n };\n\n // No token at all (a misconfigured host route) renders exactly like an invalid/expired link — checked here,\n // once, rather than mixed into the `state.kind` checks below, so those narrow `state`'s discriminated union\n // cleanly (a compound `token && state.kind === …` guard does not let TypeScript conclude anything about\n // `state.kind` once `token` itself is later known to be truthy).\n if (!token) {\n return (\n <SharedReportShell>\n <div className=\"flex flex-col items-center gap-2 text-center\" data-testid=\"shared-report\">\n <ShieldOff className=\"h-8 w-8 text-muted-foreground\" aria-hidden={true} />\n <p className=\"text-sm text-muted-foreground\">This link is invalid or has expired.</p>\n </div>\n </SharedReportShell>\n );\n }\n\n if (state.kind === 'loading') {\n return (\n <SharedReportShell>\n <p className=\"text-sm text-muted-foreground\">Loading…</p>\n </SharedReportShell>\n );\n }\n\n if (state.kind === 'invalid') {\n return (\n <SharedReportShell>\n <div className=\"flex flex-col items-center gap-2 text-center\" data-testid=\"shared-report\">\n <ShieldOff className=\"h-8 w-8 text-muted-foreground\" aria-hidden={true} />\n <p className=\"text-sm text-muted-foreground\">This link is invalid or has expired.</p>\n </div>\n </SharedReportShell>\n );\n }\n\n if (state.kind === 'rateLimited') {\n return (\n <SharedReportShell>\n <div className=\"flex flex-col items-center gap-2 text-center\" data-testid=\"shared-report\">\n <Lock className=\"h-8 w-8 text-muted-foreground\" aria-hidden={true} />\n <p className=\"text-sm text-muted-foreground\">Too many attempts. Try again later.</p>\n </div>\n </SharedReportShell>\n );\n }\n\n if (state.kind === 'needsPassword') {\n return (\n <SharedReportShell>\n <form\n className=\"mx-auto max-w-xs space-y-3\"\n data-testid=\"shared-report\"\n onSubmit={(e) => {\n e.preventDefault();\n void submitPassword(password);\n }}\n >\n <div className=\"flex flex-col items-center gap-2 text-center\">\n <Lock className=\"h-8 w-8 text-muted-foreground\" aria-hidden={true} />\n <p className=\"text-sm\">\n {state.wrong\n ? \"That password didn't work — try again.\"\n : 'This report is password-protected.'}\n </p>\n </div>\n <div>\n <Label htmlFor=\"shared-report-password\">Password</Label>\n <Input\n id=\"shared-report-password\"\n type=\"password\"\n className=\"mt-1\"\n autoFocus\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n aria-invalid={state.wrong}\n data-testid=\"shared-report-password\"\n />\n </div>\n <Button type=\"submit\" className=\"w-full\" disabled={submitting || !password}>\n {submitting ? 'Checking…' : 'View report'}\n </Button>\n </form>\n </SharedReportShell>\n );\n }\n\n const widgets = syntheticWidgets(state.report);\n const results = new Map(state.report.widgets.map((w) => [w.widgetId, w]));\n\n return (\n <PrintReportView\n reportName={state.report.reportName}\n generatedAt={state.report.generatedAt}\n watermark={state.report.watermark}\n widgets={widgets}\n results={results}\n onPrintNow={() => window.print()}\n />\n );\n}\n\n/** No workspace chrome, no links into the app — just a centered card, for every non-\"ready\" state. */\nfunction SharedReportShell({ children }: { children: ReactNode }) {\n return (\n <div className=\"flex min-h-screen items-center justify-center bg-background p-6 text-foreground\">\n <div className=\"w-full max-w-sm rounded-lg border border-border p-6\">\n <p className=\"mb-4 text-center text-xs font-semibold uppercase tracking-wide text-primary\">\n PlanMagnet\n </p>\n {children}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ReportWidget } from './reportModel';
|
|
2
|
+
|
|
3
|
+
export declare function WidgetEditorDialog({ open, onOpenChange, widget, onSave, }: {
|
|
4
|
+
open: boolean;
|
|
5
|
+
onOpenChange: (open: boolean) => void;
|
|
6
|
+
/** The widget being edited, or null when adding a new one. */
|
|
7
|
+
widget: ReportWidget | null;
|
|
8
|
+
onSave: (widget: ReportWidget) => void;
|
|
9
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
//# sourceMappingURL=WidgetEditorDialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WidgetEditorDialog.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/reports/WidgetEditorDialog.tsx"],"names":[],"mappings":"AAmBA,OAAO,EAOL,KAAK,YAAY,EAElB,MAAM,eAAe,CAAC;AAkSvB,wBAAgB,kBAAkB,CAAC,EACjC,IAAI,EACJ,YAAY,EACZ,MAAM,EACN,MAAM,GACP,EAAE;IACD,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,8DAA8D;IAC9D,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,CAAC;CACxC,2CAoBA"}
|