@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 @@
|
|
|
1
|
+
{"version":3,"file":"ProjectOutlookCard.js","names":[],"sources":["../../../src/planmagnet/forecast/ProjectOutlookCard.tsx"],"sourcesContent":["import { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Badge, Card, CardContent, CardHeader, CardTitle } from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Compass } from 'lucide-react';\nimport { usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { detailPath } from '../utils/rowNavigation';\nimport { isForbidden } from '../utils/graphqlErrors';\n\n/**\n * ANR-10: `planmagnetProjectOutlook` — a heuristic project health summary. Never an AI/LLM\n * call and never a made-up percentage: `successLikelihood` is HIGH/MEDIUM/LOW by the EXACT\n * rule in `successLikelihoodRule`, rendered verbatim so the badge is never unexplained.\n * Labelled HEURISTIC throughout, never presented as AI.\n */\n\nconst GET_PROJECT_OUTLOOK = gql`\n query PlanmagnetProjectOutlook($workspaceId: ID!, $projectId: ID!) {\n planmagnetProjectOutlook(workspaceId: $workspaceId, projectId: $projectId) {\n projectId\n method\n successLikelihood\n successLikelihoodRule\n timelineDeviationDays\n qualityTrend {\n recentDefectRatio\n priorDefectRatio\n trend\n }\n riskExposure {\n totalExposure\n topRisks {\n riskId\n title\n likelihood\n impact\n exposure\n }\n }\n budgetProjection {\n budgetId\n name\n spentAmount\n totalAmount\n burnRatePerDay\n projectedSpendAtForecastDate\n projectedOverage\n }\n inputs\n }\n }\n`;\n\ninterface ProjectOutlook {\n projectId: string;\n method: 'HEURISTIC';\n successLikelihood: 'HIGH' | 'MEDIUM' | 'LOW';\n successLikelihoodRule: string;\n timelineDeviationDays: number | null;\n qualityTrend: {\n recentDefectRatio: number | null;\n priorDefectRatio: number | null;\n trend: 'IMPROVING' | 'STABLE' | 'WORSENING' | 'UNKNOWN';\n };\n riskExposure: {\n totalExposure: number;\n topRisks: {\n riskId: string;\n title: string;\n likelihood: number | null;\n impact: number | null;\n exposure: number;\n }[];\n };\n budgetProjection:\n | {\n budgetId: string;\n name: string;\n spentAmount: number;\n totalAmount: number;\n burnRatePerDay: number;\n projectedSpendAtForecastDate: number | null;\n projectedOverage: number | null;\n }[]\n | null;\n inputs: string[];\n}\n\ninterface ProjectOutlookData {\n planmagnetProjectOutlook: ProjectOutlook;\n}\n\nconst LIKELIHOOD_BADGE: Record<\n ProjectOutlook['successLikelihood'],\n 'success' | 'warning' | 'destructive'\n> = {\n HIGH: 'success',\n MEDIUM: 'warning',\n LOW: 'destructive',\n};\n\nconst TREND_BADGE: Record<\n ProjectOutlook['qualityTrend']['trend'],\n 'success' | 'warning' | 'secondary' | 'outline'\n> = {\n IMPROVING: 'success',\n STABLE: 'secondary',\n WORSENING: 'warning',\n UNKNOWN: 'outline',\n};\n\nfunction pct(ratio: number | null): string {\n return ratio === null ? '—' : `${Math.round(ratio * 100)}%`;\n}\n\nexport function ProjectOutlookCard({\n workspaceId,\n projectId,\n}: {\n workspaceId?: string | null;\n projectId: string;\n}) {\n const { t } = useI18n();\n const navigate = usePlanMagnetNavigate();\n const { data, loading, error } = useQuery<ProjectOutlookData>(GET_PROJECT_OUTLOOK, {\n variables: { workspaceId, projectId },\n skip: !workspaceId || !projectId,\n });\n const outlook = data?.planmagnetProjectOutlook;\n\n return (\n <Card data-testid=\"outlook-card\">\n <CardHeader className=\"flex flex-row items-start justify-between space-y-0\">\n <div>\n <CardTitle className=\"flex items-center gap-2\">\n <Compass className=\"h-4 w-4\" />\n {t('planmagnet.forecast.outlook.title', 'Project outlook')}\n </CardTitle>\n <p className=\"text-xs text-muted-foreground\">\n {t(\n 'planmagnet.forecast.outlook.subtitle',\n 'Explicit rule-based heuristics over real data — never AI.'\n )}\n </p>\n </div>\n <Badge variant=\"outline\">{t('planmagnet.forecast.outlook.method', 'HEURISTIC')}</Badge>\n </CardHeader>\n <CardContent>\n {loading && !data ? (\n <div className=\"flex justify-center py-8\">\n <div className=\"animate-spin h-6 w-6 border-2 border-primary border-t-transparent rounded-full\" />\n </div>\n ) : error ? (\n <p className=\"text-sm text-status-error-text\">\n {isForbidden(error)\n ? t(\n 'planmagnet.forecast.outlook.forbidden',\n 'You do not have access to the outlook for this project.'\n )\n : `${t('planmagnet.forecast.outlook.error', 'Project outlook could not be loaded')}: ${error.message}`}\n </p>\n ) : !outlook ? null : (\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <Badge variant={LIKELIHOOD_BADGE[outlook.successLikelihood]}>\n {t(\n 'planmagnet.forecast.outlook.successLikelihood',\n 'Success likelihood: {{level}}',\n {\n level: outlook.successLikelihood,\n }\n )}\n </Badge>\n <span className=\"text-xs text-muted-foreground\">\n {t('planmagnet.forecast.outlook.timelineDeviation', 'Timeline: {{status}}', {\n status:\n outlook.timelineDeviationDays === null\n ? t(\n 'planmagnet.forecast.outlook.timelineUnknown',\n 'no forecast/target to compare'\n )\n : outlook.timelineDeviationDays > 0\n ? t('planmagnet.forecast.outlook.timelineLate', '{{days}} day(s) late', {\n days: outlook.timelineDeviationDays,\n })\n : outlook.timelineDeviationDays < 0\n ? t(\n 'planmagnet.forecast.outlook.timelineEarly',\n '{{days}} day(s) early',\n {\n days: Math.abs(outlook.timelineDeviationDays),\n }\n )\n : t('planmagnet.forecast.outlook.timelineOnTarget', 'on target'),\n })}\n </span>\n </div>\n {/* The rule text verbatim — the badge above is never unexplained. */}\n <p className=\"text-xs text-muted-foreground\">{outlook.successLikelihoodRule}</p>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div className=\"rounded-md border p-3\">\n <h3 className=\"mb-1 flex items-center gap-2 text-sm font-medium\">\n {t('planmagnet.forecast.outlook.quality', 'Quality trend')}\n <Badge variant={TREND_BADGE[outlook.qualityTrend.trend]}>\n {outlook.qualityTrend.trend}\n </Badge>\n </h3>\n <p className=\"text-xs text-muted-foreground\">\n {t(\n 'planmagnet.forecast.outlook.qualityRatios',\n 'Recent 4wk defect ratio {{recent}}, prior 4wk {{prior}}',\n {\n recent: pct(outlook.qualityTrend.recentDefectRatio),\n prior: pct(outlook.qualityTrend.priorDefectRatio),\n }\n )}\n </p>\n </div>\n <div className=\"rounded-md border p-3\">\n <h3 className=\"mb-1 text-sm font-medium\">\n {t('planmagnet.forecast.outlook.riskExposure', 'Risk exposure')}\n </h3>\n <p className=\"text-xs text-muted-foreground mb-1\">\n {t(\n 'planmagnet.forecast.outlook.totalExposure',\n 'Total (likelihood × impact): {{value}}',\n {\n value: outlook.riskExposure.totalExposure,\n }\n )}\n </p>\n <ul className=\"space-y-0.5\">\n {outlook.riskExposure.topRisks.map((risk) => (\n <li key={risk.riskId}>\n <button\n type=\"button\"\n className=\"truncate text-left text-xs text-primary hover:underline\"\n onClick={() => navigate(detailPath('/risks/risk-detail-page', risk.riskId))}\n >\n {risk.title} ({risk.exposure})\n </button>\n </li>\n ))}\n {outlook.riskExposure.topRisks.length === 0 && (\n <li className=\"text-xs text-muted-foreground\">\n {t('planmagnet.forecast.outlook.noOpenRisks', 'No open risks.')}\n </li>\n )}\n </ul>\n </div>\n </div>\n\n <div>\n <h3 className=\"mb-1 text-sm font-medium\">\n {t('planmagnet.forecast.outlook.budget', 'Budget projection')}\n </h3>\n {outlook.budgetProjection === null ? (\n <p className=\"text-xs text-muted-foreground\">\n {t('planmagnet.forecast.outlook.noBudgets', 'This project has no budgets.')}\n </p>\n ) : (\n <ul className=\"space-y-1.5\">\n {outlook.budgetProjection.map((b) => (\n <li\n key={b.budgetId}\n className=\"flex items-center justify-between gap-2 text-xs\"\n >\n <span className=\"truncate font-medium text-foreground\">{b.name}</span>\n <span\n className={`shrink-0 tabular-nums ${\n b.projectedOverage !== null && b.projectedOverage > 0\n ? 'text-status-error-text'\n : 'text-muted-foreground'\n }`}\n >\n {b.spentAmount.toLocaleString()} / {b.totalAmount.toLocaleString()}\n {b.projectedOverage !== null &&\n ` · ${\n b.projectedOverage > 0\n ? t(\n 'planmagnet.forecast.outlook.projectedOver',\n 'projected +{{amount}} over',\n {\n amount: Math.round(b.projectedOverage).toLocaleString(),\n }\n )\n : t(\n 'planmagnet.forecast.outlook.projectedUnder',\n 'projected within plan'\n )\n }`}\n </span>\n </li>\n ))}\n </ul>\n )}\n </div>\n\n {outlook.inputs.length > 0 && (\n <div>\n <h3 className=\"mb-1 text-sm font-medium\">\n {t('planmagnet.forecast.outlook.inputs', 'What this is based on')}\n </h3>\n <ul className=\"list-inside list-disc space-y-0.5 text-xs text-muted-foreground\">\n {outlook.inputs.map((note, i) => (\n // Plain-language notes carry no stable id of their own; the list is short and never reordered.\n <li key={`${i}-${note.slice(0, 24)}`}>{note}</li>\n ))}\n </ul>\n </div>\n )}\n </div>\n )}\n </CardContent>\n </Card>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProjectRiskSummaryCard.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/forecast/ProjectRiskSummaryCard.tsx"],"names":[],"mappings":"AAmDA,wBAAgB,sBAAsB,CAAC,EACrC,WAAW,EACX,SAAS,GACV,EAAE;IACD,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;CACnB,2CAkFA"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { usePlanMagnetNavigate as e } from "../providers/PlanMagnetProvider.js";
|
|
2
|
+
import { isForbidden as t } from "../utils/graphqlErrors.js";
|
|
3
|
+
import { enumLabel as n } from "../controls/WorkItemControls.js";
|
|
4
|
+
import { RISK_FLAG_KIND_ORDER as r, RISK_FLAG_SEVERITY_ORDER as i, riskFlagKindIcon as a, riskFlagSeverityBadgeVariant as o } from "./riskFlags.js";
|
|
5
|
+
import { ShieldAlert as s } from "lucide-react";
|
|
6
|
+
import { gql as c } from "@apollo/client";
|
|
7
|
+
import { useQuery as l } from "@apollo/client/react";
|
|
8
|
+
import { jsx as u, jsxs as d } from "react/jsx-runtime";
|
|
9
|
+
import { useI18n as f } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
10
|
+
import { Badge as p, Card as m, CardContent as h, CardHeader as g, CardTitle as _ } from "@burdenoff/fe-libs/ui";
|
|
11
|
+
//#region src/planmagnet/forecast/ProjectRiskSummaryCard.tsx
|
|
12
|
+
var v = c`
|
|
13
|
+
query PlanmagnetProjectRiskSummary($workspaceId: ID!, $projectId: ID!) {
|
|
14
|
+
planmagnetProjectRiskSummary(workspaceId: $workspaceId, projectId: $projectId) {
|
|
15
|
+
projectId
|
|
16
|
+
totalFlaggedItems
|
|
17
|
+
byKind {
|
|
18
|
+
kind
|
|
19
|
+
count
|
|
20
|
+
}
|
|
21
|
+
bySeverity {
|
|
22
|
+
severity
|
|
23
|
+
count
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
`;
|
|
28
|
+
function y({ workspaceId: c, projectId: y }) {
|
|
29
|
+
let { t: b } = f(), x = e(), { data: S, loading: C, error: w } = l(v, {
|
|
30
|
+
variables: {
|
|
31
|
+
workspaceId: c,
|
|
32
|
+
projectId: y
|
|
33
|
+
},
|
|
34
|
+
skip: !c || !y
|
|
35
|
+
}), T = S?.planmagnetProjectRiskSummary, E = new Map(T?.byKind.map((e) => [e.kind, e.count]) ?? []), D = new Map(T?.bySeverity.map((e) => [e.severity, e.count]) ?? []);
|
|
36
|
+
return /* @__PURE__ */ d(m, {
|
|
37
|
+
"data-testid": "risk-summary",
|
|
38
|
+
children: [/* @__PURE__ */ d(g, {
|
|
39
|
+
className: "flex flex-row items-start justify-between space-y-0",
|
|
40
|
+
children: [/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ d(_, {
|
|
41
|
+
className: "flex items-center gap-2",
|
|
42
|
+
children: [/* @__PURE__ */ u(s, { className: "h-4 w-4" }), b("planmagnet.forecast.riskSummary.title", "At-risk work")]
|
|
43
|
+
}), /* @__PURE__ */ u("p", {
|
|
44
|
+
className: "text-xs text-muted-foreground",
|
|
45
|
+
children: b("planmagnet.forecast.riskSummary.subtitle", "Explicit threshold rules — never AI.")
|
|
46
|
+
})] }), /* @__PURE__ */ u(p, {
|
|
47
|
+
variant: "outline",
|
|
48
|
+
children: b("planmagnet.forecast.riskSummary.method", "Rule-based")
|
|
49
|
+
})]
|
|
50
|
+
}), /* @__PURE__ */ u(h, { children: C && !S ? /* @__PURE__ */ u("p", {
|
|
51
|
+
className: "text-sm text-muted-foreground",
|
|
52
|
+
children: b("planmagnet.forecast.loading", "Loading…")
|
|
53
|
+
}) : w ? /* @__PURE__ */ u("p", {
|
|
54
|
+
className: "text-sm text-status-error-text",
|
|
55
|
+
children: t(w) ? b("planmagnet.forecast.riskSummary.forbidden", "You do not have access to at-risk work for this project.") : `${b("planmagnet.forecast.riskSummary.error", "At-risk summary could not be loaded")}: ${w.message}`
|
|
56
|
+
}) : T ? T.totalFlaggedItems === 0 ? /* @__PURE__ */ u("p", {
|
|
57
|
+
className: "text-sm text-muted-foreground",
|
|
58
|
+
children: b("planmagnet.forecast.riskSummary.empty", "No flagged work items right now.")
|
|
59
|
+
}) : /* @__PURE__ */ d("div", {
|
|
60
|
+
className: "space-y-3",
|
|
61
|
+
children: [
|
|
62
|
+
/* @__PURE__ */ u("div", {
|
|
63
|
+
className: "flex flex-wrap items-center gap-2",
|
|
64
|
+
children: i.filter((e) => (D.get(e) ?? 0) > 0).map((e) => /* @__PURE__ */ d(p, {
|
|
65
|
+
variant: o(e),
|
|
66
|
+
children: [
|
|
67
|
+
n(e),
|
|
68
|
+
": ",
|
|
69
|
+
D.get(e)
|
|
70
|
+
]
|
|
71
|
+
}, e))
|
|
72
|
+
}),
|
|
73
|
+
/* @__PURE__ */ u("ul", {
|
|
74
|
+
className: "space-y-1 text-xs",
|
|
75
|
+
children: r.filter((e) => (E.get(e) ?? 0) > 0).map((e) => /* @__PURE__ */ d("li", {
|
|
76
|
+
className: "flex items-center justify-between text-muted-foreground",
|
|
77
|
+
children: [/* @__PURE__ */ d("span", {
|
|
78
|
+
className: "flex items-center gap-1.5",
|
|
79
|
+
children: [/* @__PURE__ */ u(a(e), { className: "h-3.5 w-3.5" }), n(e)]
|
|
80
|
+
}), /* @__PURE__ */ u("span", {
|
|
81
|
+
className: "tabular-nums",
|
|
82
|
+
children: E.get(e)
|
|
83
|
+
})]
|
|
84
|
+
}, e))
|
|
85
|
+
}),
|
|
86
|
+
/* @__PURE__ */ u("button", {
|
|
87
|
+
type: "button",
|
|
88
|
+
className: "text-xs text-primary hover:underline",
|
|
89
|
+
onClick: () => x(`/projects/at-risk-page?projectId=${encodeURIComponent(y)}`),
|
|
90
|
+
children: b("planmagnet.forecast.riskSummary.viewAll", "View at-risk work ({{count}}) →", { count: T.totalFlaggedItems })
|
|
91
|
+
})
|
|
92
|
+
]
|
|
93
|
+
}) : null })]
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
export { y as ProjectRiskSummaryCard };
|
|
98
|
+
|
|
99
|
+
//# sourceMappingURL=ProjectRiskSummaryCard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProjectRiskSummaryCard.js","names":[],"sources":["../../../src/planmagnet/forecast/ProjectRiskSummaryCard.tsx"],"sourcesContent":["import { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Badge, Card, CardContent, CardHeader, CardTitle } from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { ShieldAlert } from 'lucide-react';\nimport { usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { isForbidden } from '../utils/graphqlErrors';\nimport { enumLabel } from '../controls/WorkItemControls';\nimport {\n RISK_FLAG_KIND_ORDER,\n RISK_FLAG_SEVERITY_ORDER,\n riskFlagKindIcon,\n riskFlagSeverityBadgeVariant,\n type RiskFlagKindValue,\n type RiskFlagSeverityValue,\n} from './riskFlags';\n\n/**\n * AI-10 at-risk counts (`planmagnetProjectRiskSummary`), compact — a project-page tile that\n * links through to the full At-risk work list (`ProjectsAtRiskPagePage`). Rule-based, never\n * AI/LLM: every count here is a deterministic threshold rule, same as `planmagnetAtRiskWorkItems`.\n */\n\nconst GET_PROJECT_RISK_SUMMARY = gql`\n query PlanmagnetProjectRiskSummary($workspaceId: ID!, $projectId: ID!) {\n planmagnetProjectRiskSummary(workspaceId: $workspaceId, projectId: $projectId) {\n projectId\n totalFlaggedItems\n byKind {\n kind\n count\n }\n bySeverity {\n severity\n count\n }\n }\n }\n`;\n\ninterface ProjectRiskSummary {\n projectId: string;\n totalFlaggedItems: number;\n byKind: { kind: RiskFlagKindValue; count: number }[];\n bySeverity: { severity: RiskFlagSeverityValue; count: number }[];\n}\n\ninterface ProjectRiskSummaryData {\n planmagnetProjectRiskSummary: ProjectRiskSummary;\n}\n\nexport function ProjectRiskSummaryCard({\n workspaceId,\n projectId,\n}: {\n workspaceId?: string | null;\n projectId: string;\n}) {\n const { t } = useI18n();\n const navigate = usePlanMagnetNavigate();\n const { data, loading, error } = useQuery<ProjectRiskSummaryData>(GET_PROJECT_RISK_SUMMARY, {\n variables: { workspaceId, projectId },\n skip: !workspaceId || !projectId,\n });\n const summary = data?.planmagnetProjectRiskSummary;\n const byKind = new Map(summary?.byKind.map((k) => [k.kind, k.count]) ?? []);\n const bySeverity = new Map(summary?.bySeverity.map((s) => [s.severity, s.count]) ?? []);\n\n return (\n <Card data-testid=\"risk-summary\">\n <CardHeader className=\"flex flex-row items-start justify-between space-y-0\">\n <div>\n <CardTitle className=\"flex items-center gap-2\">\n <ShieldAlert className=\"h-4 w-4\" />\n {t('planmagnet.forecast.riskSummary.title', 'At-risk work')}\n </CardTitle>\n <p className=\"text-xs text-muted-foreground\">\n {t('planmagnet.forecast.riskSummary.subtitle', 'Explicit threshold rules — never AI.')}\n </p>\n </div>\n <Badge variant=\"outline\">{t('planmagnet.forecast.riskSummary.method', 'Rule-based')}</Badge>\n </CardHeader>\n <CardContent>\n {loading && !data ? (\n <p className=\"text-sm text-muted-foreground\">\n {t('planmagnet.forecast.loading', 'Loading…')}\n </p>\n ) : error ? (\n <p className=\"text-sm text-status-error-text\">\n {isForbidden(error)\n ? t(\n 'planmagnet.forecast.riskSummary.forbidden',\n 'You do not have access to at-risk work for this project.'\n )\n : `${t('planmagnet.forecast.riskSummary.error', 'At-risk summary could not be loaded')}: ${error.message}`}\n </p>\n ) : !summary ? null : summary.totalFlaggedItems === 0 ? (\n <p className=\"text-sm text-muted-foreground\">\n {t('planmagnet.forecast.riskSummary.empty', 'No flagged work items right now.')}\n </p>\n ) : (\n <div className=\"space-y-3\">\n <div className=\"flex flex-wrap items-center gap-2\">\n {RISK_FLAG_SEVERITY_ORDER.filter((s) => (bySeverity.get(s) ?? 0) > 0).map((s) => (\n <Badge key={s} variant={riskFlagSeverityBadgeVariant(s)}>\n {enumLabel(s)}: {bySeverity.get(s)}\n </Badge>\n ))}\n </div>\n <ul className=\"space-y-1 text-xs\">\n {RISK_FLAG_KIND_ORDER.filter((k) => (byKind.get(k) ?? 0) > 0).map((k) => {\n const Icon = riskFlagKindIcon(k);\n return (\n <li key={k} className=\"flex items-center justify-between text-muted-foreground\">\n <span className=\"flex items-center gap-1.5\">\n <Icon className=\"h-3.5 w-3.5\" />\n {enumLabel(k)}\n </span>\n <span className=\"tabular-nums\">{byKind.get(k)}</span>\n </li>\n );\n })}\n </ul>\n <button\n type=\"button\"\n className=\"text-xs text-primary hover:underline\"\n onClick={() =>\n navigate(`/projects/at-risk-page?projectId=${encodeURIComponent(projectId)}`)\n }\n >\n {t('planmagnet.forecast.riskSummary.viewAll', 'View at-risk work ({{count}}) →', {\n count: summary.totalFlaggedItems,\n })}\n </button>\n </div>\n )}\n </CardContent>\n </Card>\n );\n}\n"],"mappings":";;;;;;;;;;;AAuBA,IAAM,IAA2B,CAAG;;;;;;;;;;;;;;;;AA4BpC,SAAgB,EAAuB,EACrC,gBACA,gBAIC;CACD,IAAM,EAAE,SAAM,GAAS,EACjB,IAAW,GAAuB,EAClC,EAAE,SAAM,YAAS,aAAU,EAAiC,GAA0B;EAC1F,WAAW;GAAE;GAAa;GAAW;EACrC,MAAM,CAAC,KAAe,CAAC;EACxB,CAAC,EACI,IAAU,GAAM,8BAChB,IAAS,IAAI,IAAI,GAAS,OAAO,KAAK,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,EACrE,IAAa,IAAI,IAAI,GAAS,WAAW,KAAK,MAAM,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;AAEvF,QACE,kBAAC,GAAD;EAAM,eAAY;YAAlB,CACE,kBAAC,GAAD;GAAY,WAAU;aAAtB,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,GAAD;IAAW,WAAU;cAArB,CACE,kBAAC,GAAD,EAAa,WAAU,WAAY,CAAA,EAClC,EAAE,yCAAyC,eAAe,CACjD;OACZ,kBAAC,KAAD;IAAG,WAAU;cACV,EAAE,4CAA4C,uCAAuC;IACpF,CAAA,CACA,EAAA,CAAA,EACN,kBAAC,GAAD;IAAO,SAAQ;cAAW,EAAE,0CAA0C,aAAa;IAAS,CAAA,CACjF;MACb,kBAAC,GAAD,EAAA,UACG,KAAW,CAAC,IACX,kBAAC,KAAD;GAAG,WAAU;aACV,EAAE,+BAA+B,WAAW;GAC3C,CAAA,GACF,IACF,kBAAC,KAAD;GAAG,WAAU;aACV,EAAY,EAAM,GACf,EACE,6CACA,2DACD,GACD,GAAG,EAAE,yCAAyC,sCAAsC,CAAC,IAAI,EAAM;GACjG,CAAA,GACD,IAAiB,EAAQ,sBAAsB,IAClD,kBAAC,KAAD;GAAG,WAAU;aACV,EAAE,yCAAyC,mCAAmC;GAC7E,CAAA,GAEJ,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAyB,QAAQ,OAAO,EAAW,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC,KAAK,MACzE,kBAAC,GAAD;MAAe,SAAS,EAA6B,EAAE;gBAAvD;OACG,EAAU,EAAE;OAAC;OAAG,EAAW,IAAI,EAAE;OAC5B;QAFI,EAEJ,CACR;KACE,CAAA;IACN,kBAAC,MAAD;KAAI,WAAU;eACX,EAAqB,QAAQ,OAAO,EAAO,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC,KAAK,MAG/D,kBAAC,MAAD;MAAY,WAAU;gBAAtB,CACE,kBAAC,QAAD;OAAM,WAAU;iBAAhB,CACE,kBAJO,EAAiB,EAAE,EAI1B,EAAM,WAAU,eAAgB,CAAA,EAC/B,EAAU,EAAE,CACR;UACP,kBAAC,QAAD;OAAM,WAAU;iBAAgB,EAAO,IAAI,EAAE;OAAQ,CAAA,CAClD;QANI,EAMJ,CAEP;KACC,CAAA;IACL,kBAAC,UAAD;KACE,MAAK;KACL,WAAU;KACV,eACE,EAAS,oCAAoC,mBAAmB,EAAU,GAAG;eAG9E,EAAE,2CAA2C,mCAAmC,EAC/E,OAAO,EAAQ,mBAChB,CAAC;KACK,CAAA;IACL;OAtCO,MAwCH,CAAA,CACT"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function ResourceForecastCard({ workspaceId, teamId, projectId, horizonSprints, }: {
|
|
2
|
+
workspaceId?: string | null;
|
|
3
|
+
/** Exactly one of teamId/projectId — the server requires it (`horizonSprints` schema doc). */
|
|
4
|
+
teamId?: string;
|
|
5
|
+
projectId?: string;
|
|
6
|
+
horizonSprints?: number;
|
|
7
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=ResourceForecastCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ResourceForecastCard.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/forecast/ResourceForecastCard.tsx"],"names":[],"mappings":"AAyEA,wBAAgB,oBAAoB,CAAC,EACnC,WAAW,EACX,MAAM,EACN,SAAS,EACT,cAAkB,GACnB,EAAE;IACD,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,8FAA8F;IAC9F,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,2CA6KA"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { isForbidden as e } from "../utils/graphqlErrors.js";
|
|
2
|
+
import { StatTile as t } from "../pages/analytics/DeliveryHealthCards.js";
|
|
3
|
+
import { Gauge as n } from "lucide-react";
|
|
4
|
+
import { gql as r } from "@apollo/client";
|
|
5
|
+
import { useQuery as i } from "@apollo/client/react";
|
|
6
|
+
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
7
|
+
import { useI18n as s } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
8
|
+
import { Card as c, CardContent as l, CardHeader as u, CardTitle as d } from "@burdenoff/fe-libs/ui";
|
|
9
|
+
//#region src/planmagnet/forecast/ResourceForecastCard.tsx
|
|
10
|
+
var f = r`
|
|
11
|
+
query PlanmagnetResourceForecast(
|
|
12
|
+
$workspaceId: ID!
|
|
13
|
+
$teamId: ID
|
|
14
|
+
$projectId: ID
|
|
15
|
+
$horizonSprints: Int
|
|
16
|
+
) {
|
|
17
|
+
planmagnetResourceForecast(
|
|
18
|
+
workspaceId: $workspaceId
|
|
19
|
+
teamId: $teamId
|
|
20
|
+
projectId: $projectId
|
|
21
|
+
horizonSprints: $horizonSprints
|
|
22
|
+
) {
|
|
23
|
+
scopeType
|
|
24
|
+
horizonSprints
|
|
25
|
+
openEstimatedPoints
|
|
26
|
+
unestimatedOpenItems
|
|
27
|
+
backlogTruncated
|
|
28
|
+
insufficientHistory
|
|
29
|
+
velocityP50
|
|
30
|
+
sprintsToClear
|
|
31
|
+
confidenceNote
|
|
32
|
+
capacityGaps {
|
|
33
|
+
sprintNumber
|
|
34
|
+
demandPoints
|
|
35
|
+
forecastCapacityPoints
|
|
36
|
+
gapPoints
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
`;
|
|
41
|
+
function p({ workspaceId: r, teamId: p, projectId: m, horizonSprints: h = 3 }) {
|
|
42
|
+
let { t: g } = s(), { data: _, loading: v, error: y } = i(f, {
|
|
43
|
+
variables: {
|
|
44
|
+
workspaceId: r,
|
|
45
|
+
teamId: p,
|
|
46
|
+
projectId: m,
|
|
47
|
+
horizonSprints: h
|
|
48
|
+
},
|
|
49
|
+
skip: !r || !p && !m
|
|
50
|
+
}), b = _?.planmagnetResourceForecast, x = Math.max(1, ...b?.capacityGaps.map((e) => Math.abs(e.gapPoints)) ?? [1]);
|
|
51
|
+
return /* @__PURE__ */ o(c, {
|
|
52
|
+
"data-testid": "resource-forecast",
|
|
53
|
+
children: [/* @__PURE__ */ o(u, { children: [/* @__PURE__ */ o(d, {
|
|
54
|
+
className: "flex items-center gap-2",
|
|
55
|
+
children: [/* @__PURE__ */ a(n, { className: "h-4 w-4" }), g("planmagnet.forecast.resource.title", "Resource forecast")]
|
|
56
|
+
}), /* @__PURE__ */ a("p", {
|
|
57
|
+
className: "text-xs text-muted-foreground",
|
|
58
|
+
children: g("planmagnet.forecast.resource.subtitle", "Open backlog vs. historical velocity, over the next {{count}} sprint(s).", { count: h })
|
|
59
|
+
})] }), /* @__PURE__ */ a(l, { children: !p && !m ? null : v && !_ ? /* @__PURE__ */ a("div", {
|
|
60
|
+
className: "flex justify-center py-8",
|
|
61
|
+
children: /* @__PURE__ */ a("div", { className: "animate-spin h-6 w-6 border-2 border-primary border-t-transparent rounded-full" })
|
|
62
|
+
}) : y ? /* @__PURE__ */ a("p", {
|
|
63
|
+
className: "text-sm text-status-error-text",
|
|
64
|
+
children: e(y) ? g("planmagnet.forecast.resource.forbidden", "You do not have access to the resource forecast for this scope.") : `${g("planmagnet.forecast.resource.error", "Resource forecast could not be loaded")}: ${y.message}`
|
|
65
|
+
}) : b ? /* @__PURE__ */ o("div", {
|
|
66
|
+
className: "space-y-4",
|
|
67
|
+
children: [
|
|
68
|
+
/* @__PURE__ */ o("div", {
|
|
69
|
+
className: "grid grid-cols-2 gap-3 sm:grid-cols-4",
|
|
70
|
+
children: [
|
|
71
|
+
/* @__PURE__ */ a(t, {
|
|
72
|
+
label: g("planmagnet.forecast.resource.openPoints", "Open est. points"),
|
|
73
|
+
value: String(b.openEstimatedPoints)
|
|
74
|
+
}),
|
|
75
|
+
/* @__PURE__ */ a(t, {
|
|
76
|
+
label: g("planmagnet.forecast.resource.unestimated", "Unestimated items"),
|
|
77
|
+
value: String(b.unestimatedOpenItems)
|
|
78
|
+
}),
|
|
79
|
+
/* @__PURE__ */ a(t, {
|
|
80
|
+
label: g("planmagnet.forecast.resource.velocity", "Velocity (p50)"),
|
|
81
|
+
value: b.velocityP50 === null ? "—" : String(Math.round(b.velocityP50))
|
|
82
|
+
}),
|
|
83
|
+
/* @__PURE__ */ a(t, {
|
|
84
|
+
label: g("planmagnet.forecast.resource.sprintsToClear", "Sprints to clear"),
|
|
85
|
+
value: b.sprintsToClear === null ? "—" : b.sprintsToClear.toFixed(1)
|
|
86
|
+
})
|
|
87
|
+
]
|
|
88
|
+
}),
|
|
89
|
+
b.insufficientHistory ? /* @__PURE__ */ a("p", {
|
|
90
|
+
className: "text-sm text-muted-foreground",
|
|
91
|
+
children: g("planmagnet.forecast.resource.insufficient", "Not enough completed-sprint history yet to forecast capacity for this scope.")
|
|
92
|
+
}) : /* @__PURE__ */ o("div", { children: [/* @__PURE__ */ a("h3", {
|
|
93
|
+
className: "mb-1 text-sm font-medium",
|
|
94
|
+
children: g("planmagnet.forecast.resource.capacityGaps", "Capacity vs. demand, by sprint")
|
|
95
|
+
}), /* @__PURE__ */ o("table", {
|
|
96
|
+
className: "w-full text-xs",
|
|
97
|
+
children: [/* @__PURE__ */ a("thead", { children: /* @__PURE__ */ o("tr", {
|
|
98
|
+
className: "text-left text-muted-foreground",
|
|
99
|
+
children: [
|
|
100
|
+
/* @__PURE__ */ a("th", {
|
|
101
|
+
className: "py-1 pr-2 font-normal",
|
|
102
|
+
children: g("planmagnet.forecast.resource.sprint", "Sprint")
|
|
103
|
+
}),
|
|
104
|
+
/* @__PURE__ */ a("th", {
|
|
105
|
+
className: "py-1 pr-2 text-right font-normal",
|
|
106
|
+
children: g("planmagnet.forecast.resource.demand", "Demand")
|
|
107
|
+
}),
|
|
108
|
+
/* @__PURE__ */ a("th", {
|
|
109
|
+
className: "py-1 pr-2 text-right font-normal",
|
|
110
|
+
children: g("planmagnet.forecast.resource.capacity", "Capacity")
|
|
111
|
+
}),
|
|
112
|
+
/* @__PURE__ */ a("th", {
|
|
113
|
+
className: "w-1/3 py-1 text-right font-normal",
|
|
114
|
+
children: g("planmagnet.forecast.resource.gap", "Gap")
|
|
115
|
+
})
|
|
116
|
+
]
|
|
117
|
+
}) }), /* @__PURE__ */ a("tbody", { children: b.capacityGaps.map((e) => {
|
|
118
|
+
let t = e.gapPoints > 0;
|
|
119
|
+
return /* @__PURE__ */ o("tr", {
|
|
120
|
+
className: "border-t align-middle",
|
|
121
|
+
children: [
|
|
122
|
+
/* @__PURE__ */ a("td", {
|
|
123
|
+
className: "py-1.5 pr-2",
|
|
124
|
+
children: g("planmagnet.forecast.resource.sprintN", "+{{n}}", { n: e.sprintNumber })
|
|
125
|
+
}),
|
|
126
|
+
/* @__PURE__ */ a("td", {
|
|
127
|
+
className: "py-1.5 pr-2 text-right tabular-nums",
|
|
128
|
+
children: e.demandPoints
|
|
129
|
+
}),
|
|
130
|
+
/* @__PURE__ */ a("td", {
|
|
131
|
+
className: "py-1.5 pr-2 text-right tabular-nums",
|
|
132
|
+
children: Math.round(e.forecastCapacityPoints)
|
|
133
|
+
}),
|
|
134
|
+
/* @__PURE__ */ o("td", {
|
|
135
|
+
className: "py-1.5",
|
|
136
|
+
children: [/* @__PURE__ */ a("div", {
|
|
137
|
+
role: "meter",
|
|
138
|
+
"aria-valuemin": 0,
|
|
139
|
+
"aria-valuemax": x,
|
|
140
|
+
"aria-valuenow": Math.abs(e.gapPoints),
|
|
141
|
+
"aria-label": `${t ? "short" : "surplus"} ${Math.abs(Math.round(e.gapPoints))} points`,
|
|
142
|
+
className: "flex h-2 w-full items-center overflow-hidden rounded-full bg-muted",
|
|
143
|
+
children: /* @__PURE__ */ a("div", {
|
|
144
|
+
className: `h-full rounded-full ${t ? "bg-status-error" : "bg-status-success"}`,
|
|
145
|
+
style: { width: `${Math.min(100, Math.abs(e.gapPoints) / x * 100)}%` }
|
|
146
|
+
})
|
|
147
|
+
}), /* @__PURE__ */ o("span", {
|
|
148
|
+
className: `text-right block tabular-nums ${t ? "text-status-error-text" : "text-status-success-text"}`,
|
|
149
|
+
children: [t ? "+" : "", Math.round(e.gapPoints)]
|
|
150
|
+
})]
|
|
151
|
+
})
|
|
152
|
+
]
|
|
153
|
+
}, e.sprintNumber);
|
|
154
|
+
}) })]
|
|
155
|
+
})] }),
|
|
156
|
+
b.backlogTruncated && /* @__PURE__ */ a("p", {
|
|
157
|
+
className: "text-xs text-status-warning-text",
|
|
158
|
+
children: g("planmagnet.forecast.resource.truncated", "This backlog is large enough that the scan stopped early — open points and unestimated items reflect only the first items found.")
|
|
159
|
+
}),
|
|
160
|
+
/* @__PURE__ */ a("p", {
|
|
161
|
+
className: "text-xs text-muted-foreground",
|
|
162
|
+
children: g("planmagnet.forecast.resource.skillsNote", "Skills demand is not modelled — this forecasts total story points only, not which skills the backlog actually needs.")
|
|
163
|
+
}),
|
|
164
|
+
/* @__PURE__ */ a("p", {
|
|
165
|
+
className: "text-xs text-muted-foreground",
|
|
166
|
+
children: b.confidenceNote
|
|
167
|
+
}),
|
|
168
|
+
/* @__PURE__ */ o("details", {
|
|
169
|
+
className: "text-xs text-muted-foreground",
|
|
170
|
+
children: [/* @__PURE__ */ a("summary", {
|
|
171
|
+
className: "cursor-pointer select-none font-medium text-foreground",
|
|
172
|
+
children: g("planmagnet.forecast.whatIsThis", "What is this?")
|
|
173
|
+
}), /* @__PURE__ */ a("p", {
|
|
174
|
+
className: "mt-1",
|
|
175
|
+
children: g("planmagnet.forecast.resource.explainer", "Statistical forecast (not AI-generated): capacity is the median of the trailing completed sprints’ real velocity; demand is today’s open backlog split evenly across the horizon. Never an AI/LLM call.")
|
|
176
|
+
})]
|
|
177
|
+
})
|
|
178
|
+
]
|
|
179
|
+
}) : null })]
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
//#endregion
|
|
183
|
+
export { p as ResourceForecastCard };
|
|
184
|
+
|
|
185
|
+
//# sourceMappingURL=ResourceForecastCard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ResourceForecastCard.js","names":[],"sources":["../../../src/planmagnet/forecast/ResourceForecastCard.tsx"],"sourcesContent":["import { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle } from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Gauge } from 'lucide-react';\nimport { isForbidden } from '../utils/graphqlErrors';\nimport { StatTile } from '../pages/analytics/DeliveryHealthCards';\n\n/**\n * ANR-11: `planmagnetResourceForecast` — open backlog vs historical velocity, and the resulting\n * per-sprint capacity gap over the horizon. Used on the team detail page (team scope) and the\n * project detail page (project scope) — same card either way, one of `teamId`/`projectId` set.\n *\n * Statistical, never AI/LLM: reuses the same trailing-sprint-velocity resolution\n * `planmagnetForecastDelivery` does. Demand is the CURRENT open backlog split evenly across the\n * horizon (not a burndown simulation) and capacity never trends — see the field doc comments in\n * graphql/wspace.graphql. Skills/roles are not modelled: this is a total-points forecast only.\n */\n\nconst GET_RESOURCE_FORECAST = gql`\n query PlanmagnetResourceForecast(\n $workspaceId: ID!\n $teamId: ID\n $projectId: ID\n $horizonSprints: Int\n ) {\n planmagnetResourceForecast(\n workspaceId: $workspaceId\n teamId: $teamId\n projectId: $projectId\n horizonSprints: $horizonSprints\n ) {\n scopeType\n horizonSprints\n openEstimatedPoints\n unestimatedOpenItems\n backlogTruncated\n insufficientHistory\n velocityP50\n sprintsToClear\n confidenceNote\n capacityGaps {\n sprintNumber\n demandPoints\n forecastCapacityPoints\n gapPoints\n }\n }\n }\n`;\n\ninterface ResourceForecast {\n scopeType: 'TEAM' | 'PROJECT';\n horizonSprints: number;\n openEstimatedPoints: number;\n unestimatedOpenItems: number;\n backlogTruncated: boolean;\n insufficientHistory: boolean;\n velocityP50: number | null;\n sprintsToClear: number | null;\n confidenceNote: string;\n capacityGaps: {\n sprintNumber: number;\n demandPoints: number;\n forecastCapacityPoints: number;\n gapPoints: number;\n }[];\n}\n\ninterface ResourceForecastData {\n planmagnetResourceForecast: ResourceForecast;\n}\n\nexport function ResourceForecastCard({\n workspaceId,\n teamId,\n projectId,\n horizonSprints = 3,\n}: {\n workspaceId?: string | null;\n /** Exactly one of teamId/projectId — the server requires it (`horizonSprints` schema doc). */\n teamId?: string;\n projectId?: string;\n horizonSprints?: number;\n}) {\n const { t } = useI18n();\n const { data, loading, error } = useQuery<ResourceForecastData>(GET_RESOURCE_FORECAST, {\n variables: { workspaceId, teamId, projectId, horizonSprints },\n skip: !workspaceId || (!teamId && !projectId),\n });\n const forecast = data?.planmagnetResourceForecast;\n const maxGapMagnitude = Math.max(\n 1,\n ...(forecast?.capacityGaps.map((g) => Math.abs(g.gapPoints)) ?? [1])\n );\n\n return (\n <Card data-testid=\"resource-forecast\">\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Gauge className=\"h-4 w-4\" />\n {t('planmagnet.forecast.resource.title', 'Resource forecast')}\n </CardTitle>\n <p className=\"text-xs text-muted-foreground\">\n {t(\n 'planmagnet.forecast.resource.subtitle',\n 'Open backlog vs. historical velocity, over the next {{count}} sprint(s).',\n { count: horizonSprints }\n )}\n </p>\n </CardHeader>\n <CardContent>\n {!teamId && !projectId ? null : loading && !data ? (\n <div className=\"flex justify-center py-8\">\n <div className=\"animate-spin h-6 w-6 border-2 border-primary border-t-transparent rounded-full\" />\n </div>\n ) : error ? (\n <p className=\"text-sm text-status-error-text\">\n {isForbidden(error)\n ? t(\n 'planmagnet.forecast.resource.forbidden',\n 'You do not have access to the resource forecast for this scope.'\n )\n : `${t('planmagnet.forecast.resource.error', 'Resource forecast could not be loaded')}: ${error.message}`}\n </p>\n ) : !forecast ? null : (\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <StatTile\n label={t('planmagnet.forecast.resource.openPoints', 'Open est. points')}\n value={String(forecast.openEstimatedPoints)}\n />\n <StatTile\n label={t('planmagnet.forecast.resource.unestimated', 'Unestimated items')}\n value={String(forecast.unestimatedOpenItems)}\n />\n <StatTile\n label={t('planmagnet.forecast.resource.velocity', 'Velocity (p50)')}\n value={\n forecast.velocityP50 === null ? '—' : String(Math.round(forecast.velocityP50))\n }\n />\n <StatTile\n label={t('planmagnet.forecast.resource.sprintsToClear', 'Sprints to clear')}\n value={forecast.sprintsToClear === null ? '—' : forecast.sprintsToClear.toFixed(1)}\n />\n </div>\n\n {forecast.insufficientHistory ? (\n <p className=\"text-sm text-muted-foreground\">\n {t(\n 'planmagnet.forecast.resource.insufficient',\n 'Not enough completed-sprint history yet to forecast capacity for this scope.'\n )}\n </p>\n ) : (\n <div>\n <h3 className=\"mb-1 text-sm font-medium\">\n {t('planmagnet.forecast.resource.capacityGaps', 'Capacity vs. demand, by sprint')}\n </h3>\n <table className=\"w-full text-xs\">\n <thead>\n <tr className=\"text-left text-muted-foreground\">\n <th className=\"py-1 pr-2 font-normal\">\n {t('planmagnet.forecast.resource.sprint', 'Sprint')}\n </th>\n <th className=\"py-1 pr-2 text-right font-normal\">\n {t('planmagnet.forecast.resource.demand', 'Demand')}\n </th>\n <th className=\"py-1 pr-2 text-right font-normal\">\n {t('planmagnet.forecast.resource.capacity', 'Capacity')}\n </th>\n <th className=\"w-1/3 py-1 text-right font-normal\">\n {t('planmagnet.forecast.resource.gap', 'Gap')}\n </th>\n </tr>\n </thead>\n <tbody>\n {forecast.capacityGaps.map((row) => {\n const short = row.gapPoints > 0;\n return (\n <tr key={row.sprintNumber} className=\"border-t align-middle\">\n <td className=\"py-1.5 pr-2\">\n {t('planmagnet.forecast.resource.sprintN', '+{{n}}', {\n n: row.sprintNumber,\n })}\n </td>\n <td className=\"py-1.5 pr-2 text-right tabular-nums\">\n {row.demandPoints}\n </td>\n <td className=\"py-1.5 pr-2 text-right tabular-nums\">\n {Math.round(row.forecastCapacityPoints)}\n </td>\n <td className=\"py-1.5\">\n <div\n role=\"meter\"\n aria-valuemin={0}\n aria-valuemax={maxGapMagnitude}\n aria-valuenow={Math.abs(row.gapPoints)}\n aria-label={`${short ? 'short' : 'surplus'} ${Math.abs(Math.round(row.gapPoints))} points`}\n className=\"flex h-2 w-full items-center overflow-hidden rounded-full bg-muted\"\n >\n <div\n className={`h-full rounded-full ${short ? 'bg-status-error' : 'bg-status-success'}`}\n style={{\n width: `${Math.min(100, (Math.abs(row.gapPoints) / maxGapMagnitude) * 100)}%`,\n }}\n />\n </div>\n <span\n className={`text-right block tabular-nums ${short ? 'text-status-error-text' : 'text-status-success-text'}`}\n >\n {short ? '+' : ''}\n {Math.round(row.gapPoints)}\n </span>\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n )}\n\n {forecast.backlogTruncated && (\n <p className=\"text-xs text-status-warning-text\">\n {t(\n 'planmagnet.forecast.resource.truncated',\n 'This backlog is large enough that the scan stopped early — open points and unestimated items reflect only the first items found.'\n )}\n </p>\n )}\n\n <p className=\"text-xs text-muted-foreground\">\n {t(\n 'planmagnet.forecast.resource.skillsNote',\n 'Skills demand is not modelled — this forecasts total story points only, not which skills the backlog actually needs.'\n )}\n </p>\n <p className=\"text-xs text-muted-foreground\">{forecast.confidenceNote}</p>\n\n <details className=\"text-xs text-muted-foreground\">\n <summary className=\"cursor-pointer select-none font-medium text-foreground\">\n {t('planmagnet.forecast.whatIsThis', 'What is this?')}\n </summary>\n <p className=\"mt-1\">\n {t(\n 'planmagnet.forecast.resource.explainer',\n 'Statistical forecast (not AI-generated): capacity is the median of the trailing completed sprints’ real velocity; demand is today’s open backlog split evenly across the horizon. Never an AI/LLM call.'\n )}\n </p>\n </details>\n </div>\n )}\n </CardContent>\n </Card>\n );\n}\n"],"mappings":";;;;;;;;;AAmBA,IAAM,IAAwB,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsDjC,SAAgB,EAAqB,EACnC,gBACA,WACA,cACA,oBAAiB,KAOhB;CACD,IAAM,EAAE,SAAM,GAAS,EACjB,EAAE,SAAM,YAAS,aAAU,EAA+B,GAAuB;EACrF,WAAW;GAAE;GAAa;GAAQ;GAAW;GAAgB;EAC7D,MAAM,CAAC,KAAgB,CAAC,KAAU,CAAC;EACpC,CAAC,EACI,IAAW,GAAM,4BACjB,IAAkB,KAAK,IAC3B,GACA,GAAI,GAAU,aAAa,KAAK,MAAM,KAAK,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,CACpE;AAED,QACE,kBAAC,GAAD;EAAM,eAAY;YAAlB,CACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;GAAW,WAAU;aAArB,CACE,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA,EAC5B,EAAE,sCAAsC,oBAAoB,CACnD;MACZ,kBAAC,KAAD;GAAG,WAAU;aACV,EACC,yCACA,4EACA,EAAE,OAAO,GAAgB,CAC1B;GACC,CAAA,CACO,EAAA,CAAA,EACb,kBAAC,GAAD,EAAA,UACG,CAAC,KAAU,CAAC,IAAY,OAAO,KAAW,CAAC,IAC1C,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,OAAD,EAAK,WAAU,kFAAmF,CAAA;GAC9F,CAAA,GACJ,IACF,kBAAC,KAAD;GAAG,WAAU;aACV,EAAY,EAAM,GACf,EACE,0CACA,kEACD,GACD,GAAG,EAAE,sCAAsC,wCAAwC,CAAC,IAAI,EAAM;GAChG,CAAA,GACD,IACH,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,GAAD;OACE,OAAO,EAAE,2CAA2C,mBAAmB;OACvE,OAAO,OAAO,EAAS,oBAAoB;OAC3C,CAAA;MACF,kBAAC,GAAD;OACE,OAAO,EAAE,4CAA4C,oBAAoB;OACzE,OAAO,OAAO,EAAS,qBAAqB;OAC5C,CAAA;MACF,kBAAC,GAAD;OACE,OAAO,EAAE,yCAAyC,iBAAiB;OACnE,OACE,EAAS,gBAAgB,OAAO,MAAM,OAAO,KAAK,MAAM,EAAS,YAAY,CAAC;OAEhF,CAAA;MACF,kBAAC,GAAD;OACE,OAAO,EAAE,+CAA+C,mBAAmB;OAC3E,OAAO,EAAS,mBAAmB,OAAO,MAAM,EAAS,eAAe,QAAQ,EAAE;OAClF,CAAA;MACE;;IAEL,EAAS,sBACR,kBAAC,KAAD;KAAG,WAAU;eACV,EACC,6CACA,+EACD;KACC,CAAA,GAEJ,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;eACX,EAAE,6CAA6C,iCAAiC;KAC9E,CAAA,EACL,kBAAC,SAAD;KAAO,WAAU;eAAjB,CACE,kBAAC,SAAD,EAAA,UACE,kBAAC,MAAD;MAAI,WAAU;gBAAd;OACE,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAE,uCAAuC,SAAS;QAChD,CAAA;OACL,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAE,uCAAuC,SAAS;QAChD,CAAA;OACL,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAE,yCAAyC,WAAW;QACpD,CAAA;OACL,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAE,oCAAoC,MAAM;QAC1C,CAAA;OACF;SACC,CAAA,EACR,kBAAC,SAAD,EAAA,UACG,EAAS,aAAa,KAAK,MAAQ;MAClC,IAAM,IAAQ,EAAI,YAAY;AAC9B,aACE,kBAAC,MAAD;OAA2B,WAAU;iBAArC;QACE,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAE,wCAAwC,UAAU,EACnD,GAAG,EAAI,cACR,CAAC;SACC,CAAA;QACL,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAI;SACF,CAAA;QACL,kBAAC,MAAD;SAAI,WAAU;mBACX,KAAK,MAAM,EAAI,uBAAuB;SACpC,CAAA;QACL,kBAAC,MAAD;SAAI,WAAU;mBAAd,CACE,kBAAC,OAAD;UACE,MAAK;UACL,iBAAe;UACf,iBAAe;UACf,iBAAe,KAAK,IAAI,EAAI,UAAU;UACtC,cAAY,GAAG,IAAQ,UAAU,UAAU,GAAG,KAAK,IAAI,KAAK,MAAM,EAAI,UAAU,CAAC,CAAC;UAClF,WAAU;oBAEV,kBAAC,OAAD;WACE,WAAW,uBAAuB,IAAQ,oBAAoB;WAC9D,OAAO,EACL,OAAO,GAAG,KAAK,IAAI,KAAM,KAAK,IAAI,EAAI,UAAU,GAAG,IAAmB,IAAI,CAAC,IAC5E;WACD,CAAA;UACE,CAAA,EACN,kBAAC,QAAD;UACE,WAAW,iCAAiC,IAAQ,2BAA2B;oBADjF,CAGG,IAAQ,MAAM,IACd,KAAK,MAAM,EAAI,UAAU,CACrB;YACJ;;QACF;SAnCI,EAAI,aAmCR;OAEP,EACI,CAAA,CACF;OACJ,EAAA,CAAA;IAGP,EAAS,oBACR,kBAAC,KAAD;KAAG,WAAU;eACV,EACC,0CACA,mIACD;KACC,CAAA;IAGN,kBAAC,KAAD;KAAG,WAAU;eACV,EACC,2CACA,uHACD;KACC,CAAA;IACJ,kBAAC,KAAD;KAAG,WAAU;eAAiC,EAAS;KAAmB,CAAA;IAE1E,kBAAC,WAAD;KAAS,WAAU;eAAnB,CACE,kBAAC,WAAD;MAAS,WAAU;gBAChB,EAAE,kCAAkC,gBAAgB;MAC7C,CAAA,EACV,kBAAC,KAAD;MAAG,WAAU;gBACV,EACC,0CACA,0MACD;MACC,CAAA,CACI;;IACN;OA/HQ,MAiIJ,CAAA,CACT"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ComponentType } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AI-10 at-risk work-item flags: shared between the project risk-summary tile
|
|
5
|
+
* (`ProjectRiskSummaryCard`) and the At-risk work page (`ProjectsAtRiskPagePage`), so the two
|
|
6
|
+
* surfaces never disagree about a flag kind's icon or a severity's badge color.
|
|
7
|
+
*
|
|
8
|
+
* Every flag kind and severity below is drawn 1:1 from `PlanmagnetRiskFlagKind` /
|
|
9
|
+
* `PlanmagnetRiskFlagSeverity` in graphql/wspace.graphql — see that file for exactly which rule
|
|
10
|
+
* (with its threshold) raises each one. These are explicit rules over real data, never an
|
|
11
|
+
* AI/LLM call: labelled "Rule-based" everywhere a flag is shown, per the reason text the API
|
|
12
|
+
* itself already returns alongside `kind`.
|
|
13
|
+
*/
|
|
14
|
+
export declare const RISK_FLAG_KINDS: readonly ["AT_RISK_MILESTONE", "BLOCKED", "OVERCOMMITTED_ASSIGNEE", "OVERDUE", "SCOPE_CREEP", "STALE"];
|
|
15
|
+
export type RiskFlagKindValue = (typeof RISK_FLAG_KINDS)[number];
|
|
16
|
+
export declare const RISK_FLAG_SEVERITIES: readonly ["HIGH", "MEDIUM", "LOW"];
|
|
17
|
+
export type RiskFlagSeverityValue = (typeof RISK_FLAG_SEVERITIES)[number];
|
|
18
|
+
export declare const RISK_FLAG_KIND_ICON: Record<RiskFlagKindValue, ComponentType<{
|
|
19
|
+
className?: string;
|
|
20
|
+
}>>;
|
|
21
|
+
/** A kind this map doesn't know yet falls back to a generic icon rather than throwing. */
|
|
22
|
+
export declare const RISK_FLAG_FALLBACK_ICON: import('react').ForwardRefExoticComponent<Omit<import('lucide-react').LucideProps, "ref"> & import('react').RefAttributes<SVGSVGElement>>;
|
|
23
|
+
export declare function riskFlagKindIcon(kind: string): ComponentType<{
|
|
24
|
+
className?: string;
|
|
25
|
+
}>;
|
|
26
|
+
/** fe-libs Badge `variant` — same HIGH/MEDIUM/LOW → error/warning/info convention
|
|
27
|
+
* `roadmaps/RoadmapNowNextLater.tsx` uses for its own risk levels. */
|
|
28
|
+
export declare const RISK_FLAG_SEVERITY_BADGE: Record<RiskFlagSeverityValue, 'destructive' | 'warning' | 'info'>;
|
|
29
|
+
export declare function riskFlagSeverityBadgeVariant(severity: string): 'destructive' | 'warning' | 'info' | 'secondary';
|
|
30
|
+
/** Fixed severity order for counts/legends — never re-derived from whichever severities happen
|
|
31
|
+
* to appear (same rule `utils/statusColor.ts` documents for status colors). */
|
|
32
|
+
export declare const RISK_FLAG_SEVERITY_ORDER: readonly RiskFlagSeverityValue[];
|
|
33
|
+
/** Fixed kind order, for the same reason. */
|
|
34
|
+
export declare const RISK_FLAG_KIND_ORDER: readonly RiskFlagKindValue[];
|
|
35
|
+
//# sourceMappingURL=riskFlags.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"riskFlags.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/forecast/riskFlags.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAG3C;;;;;;;;;;GAUG;AAEH,eAAO,MAAM,eAAe,wGAOlB,CAAC;AACX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjE,eAAO,MAAM,oBAAoB,oCAAqC,CAAC;AACvE,MAAM,MAAM,qBAAqB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1E,eAAO,MAAM,mBAAmB,EAAE,MAAM,CACtC,iBAAiB,EACjB,aAAa,CAAC;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAQtC,CAAC;AACF,0FAA0F;AAC1F,eAAO,MAAM,uBAAuB,2IAAe,CAAC;AAEpD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAAC;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAKpF;AAED;uEACuE;AACvE,eAAO,MAAM,wBAAwB,EAAE,MAAM,CAC3C,qBAAqB,EACrB,aAAa,GAAG,SAAS,GAAG,MAAM,CAKnC,CAAC;AAEF,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,MAAM,GACf,aAAa,GAAG,SAAS,GAAG,MAAM,GAAG,WAAW,CAKlD;AAED;gFACgF;AAChF,eAAO,MAAM,wBAAwB,EAAE,SAAS,qBAAqB,EAAyB,CAAC;AAE/F,6CAA6C;AAC7C,eAAO,MAAM,oBAAoB,EAAE,SAAS,iBAAiB,EAAoB,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { AlertOctagon as e, CalendarClock as t, Link2 as n, PlusCircle as r, Target as i, Timer as a, Users as o } from "lucide-react";
|
|
2
|
+
//#region src/planmagnet/forecast/riskFlags.ts
|
|
3
|
+
var s = [
|
|
4
|
+
"AT_RISK_MILESTONE",
|
|
5
|
+
"BLOCKED",
|
|
6
|
+
"OVERCOMMITTED_ASSIGNEE",
|
|
7
|
+
"OVERDUE",
|
|
8
|
+
"SCOPE_CREEP",
|
|
9
|
+
"STALE"
|
|
10
|
+
], c = [
|
|
11
|
+
"HIGH",
|
|
12
|
+
"MEDIUM",
|
|
13
|
+
"LOW"
|
|
14
|
+
], l = {
|
|
15
|
+
AT_RISK_MILESTONE: i,
|
|
16
|
+
BLOCKED: n,
|
|
17
|
+
OVERCOMMITTED_ASSIGNEE: o,
|
|
18
|
+
OVERDUE: t,
|
|
19
|
+
SCOPE_CREEP: r,
|
|
20
|
+
STALE: a
|
|
21
|
+
}, u = e;
|
|
22
|
+
function d(e) {
|
|
23
|
+
return l[e] ?? u;
|
|
24
|
+
}
|
|
25
|
+
var f = {
|
|
26
|
+
HIGH: "destructive",
|
|
27
|
+
MEDIUM: "warning",
|
|
28
|
+
LOW: "info"
|
|
29
|
+
};
|
|
30
|
+
function p(e) {
|
|
31
|
+
return f[e] ?? "secondary";
|
|
32
|
+
}
|
|
33
|
+
var m = c, h = s;
|
|
34
|
+
//#endregion
|
|
35
|
+
export { h as RISK_FLAG_KIND_ORDER, m as RISK_FLAG_SEVERITY_ORDER, d as riskFlagKindIcon, p as riskFlagSeverityBadgeVariant };
|
|
36
|
+
|
|
37
|
+
//# sourceMappingURL=riskFlags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"riskFlags.js","names":[],"sources":["../../../src/planmagnet/forecast/riskFlags.ts"],"sourcesContent":["import type { ComponentType } from 'react';\nimport { AlertOctagon, CalendarClock, Link2, PlusCircle, Target, Timer, Users } from 'lucide-react';\n\n/**\n * AI-10 at-risk work-item flags: shared between the project risk-summary tile\n * (`ProjectRiskSummaryCard`) and the At-risk work page (`ProjectsAtRiskPagePage`), so the two\n * surfaces never disagree about a flag kind's icon or a severity's badge color.\n *\n * Every flag kind and severity below is drawn 1:1 from `PlanmagnetRiskFlagKind` /\n * `PlanmagnetRiskFlagSeverity` in graphql/wspace.graphql — see that file for exactly which rule\n * (with its threshold) raises each one. These are explicit rules over real data, never an\n * AI/LLM call: labelled \"Rule-based\" everywhere a flag is shown, per the reason text the API\n * itself already returns alongside `kind`.\n */\n\nexport const RISK_FLAG_KINDS = [\n 'AT_RISK_MILESTONE',\n 'BLOCKED',\n 'OVERCOMMITTED_ASSIGNEE',\n 'OVERDUE',\n 'SCOPE_CREEP',\n 'STALE',\n] as const;\nexport type RiskFlagKindValue = (typeof RISK_FLAG_KINDS)[number];\n\nexport const RISK_FLAG_SEVERITIES = ['HIGH', 'MEDIUM', 'LOW'] as const;\nexport type RiskFlagSeverityValue = (typeof RISK_FLAG_SEVERITIES)[number];\n\nexport const RISK_FLAG_KIND_ICON: Record<\n RiskFlagKindValue,\n ComponentType<{ className?: string }>\n> = {\n AT_RISK_MILESTONE: Target,\n BLOCKED: Link2,\n OVERCOMMITTED_ASSIGNEE: Users,\n OVERDUE: CalendarClock,\n SCOPE_CREEP: PlusCircle,\n STALE: Timer,\n};\n/** A kind this map doesn't know yet falls back to a generic icon rather than throwing. */\nexport const RISK_FLAG_FALLBACK_ICON = AlertOctagon;\n\nexport function riskFlagKindIcon(kind: string): ComponentType<{ className?: string }> {\n return (\n (RISK_FLAG_KIND_ICON as Record<string, ComponentType<{ className?: string }>>)[kind] ??\n RISK_FLAG_FALLBACK_ICON\n );\n}\n\n/** fe-libs Badge `variant` — same HIGH/MEDIUM/LOW → error/warning/info convention\n * `roadmaps/RoadmapNowNextLater.tsx` uses for its own risk levels. */\nexport const RISK_FLAG_SEVERITY_BADGE: Record<\n RiskFlagSeverityValue,\n 'destructive' | 'warning' | 'info'\n> = {\n HIGH: 'destructive',\n MEDIUM: 'warning',\n LOW: 'info',\n};\n\nexport function riskFlagSeverityBadgeVariant(\n severity: string\n): 'destructive' | 'warning' | 'info' | 'secondary' {\n return (\n (RISK_FLAG_SEVERITY_BADGE as Record<string, 'destructive' | 'warning' | 'info'>)[severity] ??\n 'secondary'\n );\n}\n\n/** Fixed severity order for counts/legends — never re-derived from whichever severities happen\n * to appear (same rule `utils/statusColor.ts` documents for status colors). */\nexport const RISK_FLAG_SEVERITY_ORDER: readonly RiskFlagSeverityValue[] = RISK_FLAG_SEVERITIES;\n\n/** Fixed kind order, for the same reason. */\nexport const RISK_FLAG_KIND_ORDER: readonly RiskFlagKindValue[] = RISK_FLAG_KINDS;\n"],"mappings":";;AAeA,IAAa,IAAkB;CAC7B;CACA;CACA;CACA;CACA;CACA;CACD,EAGY,IAAuB;CAAC;CAAQ;CAAU;CAAM,EAGhD,IAGT;CACF,mBAAmB;CACnB,SAAS;CACT,wBAAwB;CACxB,SAAS;CACT,aAAa;CACb,OAAO;CACR,EAEY,IAA0B;AAEvC,SAAgB,EAAiB,GAAqD;AACpF,QACG,EAA8E,MAC/E;;AAMJ,IAAa,IAGT;CACF,MAAM;CACN,QAAQ;CACR,KAAK;CACN;AAED,SAAgB,EACd,GACkD;AAClD,QACG,EAAgF,MACjF;;AAMJ,IAAa,IAA6D,GAG7D,IAAqD"}
|
|
@@ -5,4 +5,6 @@ export { usePlanMagnet, usePlanMagnetNavigate } from './providers/PlanMagnetProv
|
|
|
5
5
|
export { usePlanMagnetStore } from './store/planmagnetStore';
|
|
6
6
|
export { INTEGRATIONS_SYNCS_PATH, INTEGRATIONS_NEW_SYNC_PATH, INTEGRATIONS_SYNC_DETAIL_PATH, integrationsSyncDetailPath, } from './integrations/routes';
|
|
7
7
|
export { PRIORITIZATION_PATH } from './product/routes';
|
|
8
|
+
export { SharedReportPage } from './reports/SharedReportPage';
|
|
9
|
+
export { SHARED_REPORT_ROUTE_PATH, SHARED_REPORT_BASE_PATH } from './reports/sharedReportRoute';
|
|
8
10
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/planmagnet/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,YAAY,EAAE,mBAAmB,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACtF,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAG7D,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,6BAA6B,EAC7B,0BAA0B,GAC3B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/planmagnet/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,YAAY,EAAE,mBAAmB,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACtF,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAG7D,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,6BAA6B,EAC7B,0BAA0B,GAC3B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAKvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC"}
|
package/dist/planmagnet/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnalyticsAnalyticsPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/AnalyticsAnalyticsPagePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AnalyticsAnalyticsPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/AnalyticsAnalyticsPagePage.tsx"],"names":[],"mappings":"AAiTA,wBAAgB,0BAA0B,4CA+uBzC"}
|