@burdenoff/microfe-planmagnet 2026.930.24 → 2026.1001.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/__vite-browser-external.js +9 -0
- package/dist/_virtual/__vite-browser-external.js.map +1 -0
- package/dist/_virtual/_rolldown/runtime.js +5 -2
- package/dist/index.js +3 -1
- package/dist/node_modules/fflate/esm/browser.js +554 -0
- package/dist/node_modules/fflate/esm/browser.js.map +1 -0
- package/dist/node_modules/jszip/dist/jszip.min.js +3038 -0
- package/dist/node_modules/jszip/dist/jszip.min.js.map +1 -0
- package/dist/node_modules/pptxgenjs/dist/pptxgen.es.js +2151 -0
- package/dist/node_modules/pptxgenjs/dist/pptxgen.es.js.map +1 -0
- package/dist/node_modules/write-excel-file/browser/index.js +3 -0
- package/dist/node_modules/write-excel-file/modules/export/convertFileContentToUint8ArrayBrowser.js +13 -0
- package/dist/node_modules/write-excel-file/modules/export/convertFileContentToUint8ArrayBrowser.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/export/convertFilesContentToUint8Arrays.js +21 -0
- package/dist/node_modules/write-excel-file/modules/export/convertFilesContentToUint8Arrays.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/export/downloadBlob.js +11 -0
- package/dist/node_modules/write-excel-file/modules/export/downloadBlob.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/export/writeXlsxFileBrowser.js +23 -0
- package/dist/node_modules/write-excel-file/modules/export/writeXlsxFileBrowser.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/export/writeXlsxFileUniversal.js +22 -0
- package/dist/node_modules/write-excel-file/modules/export/writeXlsxFileUniversal.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/getSheetData/getSheetData.js +18 -0
- package/dist/node_modules/write-excel-file/modules/getSheetData/getSheetData.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/features/conditionalFormatting.js +131 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/features/conditionalFormatting.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/features/images.js +188 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/features/images.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/features/stickyRowsOrColumns.js +52 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/features/stickyRowsOrColumns.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/_Content_Types_.xml.js +18 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/_Content_Types_.xml.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/drawing.xml.js +18 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/drawing.xml.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/drawing.xml.rels.js +17 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/drawing.xml.rels.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/rels.js +11 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/rels.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sharedStrings.xml.js +42 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sharedStrings.xml.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/cell.js +102 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/cell.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/column.js +17 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/column.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/columns.js +15 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/columns.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/drawingReference.js +8 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/drawingReference.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/helpers/getCellStyleProperties.js +71 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/helpers/getCellStyleProperties.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/mergedCellsDescription.js +56 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/mergedCellsDescription.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/pageMargins.js +15 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/pageMargins.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/pageSetup.js +13 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/pageSetup.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/processMergedCells.js +44 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/processMergedCells.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/row.js +123 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/row.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/sheet.xml.js +41 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/sheet.xml.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/sheetData.js +11 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/sheetData.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/sheetViews.js +17 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml/sheetViews.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml.rels.js +20 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/sheet.xml.rels.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/styles.xml.js +77 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/styles.xml.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/workbook.xml.js +22 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/workbook.xml.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/workbook.xml.rels.js +13 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/files/workbook.xml.rels.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/generateXlsxFileContents.js +242 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/generateXlsxFileContents.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/getFeatures.js +29 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/getFeatures.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/convertDateToSerialNumber.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/convertDateToSerialNumber.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/features/getAdditionalContent.js +42 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/features/getAdditionalContent.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/features/getElementXml.js +43 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/features/getElementXml.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/features/getWrittenFiles.js +93 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/features/getWrittenFiles.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/features/transformContent.js +39 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/features/transformContent.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getAlignmentXml.js +17 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getAlignmentXml.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getBorderXml.js +29 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getBorderXml.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getCellAddress.js +14 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getCellAddress.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getFileExtensionForContentType.js +11 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getFileExtensionForContentType.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getFillXml.js +14 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getFillXml.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getFontXml.js +12 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getFontXml.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getOrderOfSiblings.js +24 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getOrderOfSiblings.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getXlsxColorForHexColor.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/getXlsxColorForHexColor.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/hasAlignment.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/hasAlignment.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/hasBorder.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/hasBorder.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/hasFill.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/hasFill.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/hasFont.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/hasFont.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/isCellObject.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/isCellObject.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/isObject.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/isObject.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/orderOfSiblings.js +27 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/helpers/orderOfSiblings.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/initializeSharedStrings.js +17 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/initializeSharedStrings.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/initializeSheets.js +74 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/initializeSheets.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/initializeStyles.js +138 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/initializeStyles.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/validateSheetData.js +40 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/validateSheetData.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/validateSheetName.js +11 -0
- package/dist/node_modules/write-excel-file/modules/xlsx/validateSheetName.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/appendMarkupInsideElement.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xml/appendMarkupInsideElement.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/applyEnclosingElementOffset.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xml/applyEnclosingElementOffset.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/escapeXmlSpecialCharacters.js +12 -0
- package/dist/node_modules/write-excel-file/modules/xml/escapeXmlSpecialCharacters.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/findElement.js +12 -0
- package/dist/node_modules/write-excel-file/modules/xml/findElement.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/findElementInsideElement.js +12 -0
- package/dist/node_modules/write-excel-file/modules/xml/findElementInsideElement.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/findElementsNonRecursive_.js +41 -0
- package/dist/node_modules/write-excel-file/modules/xml/findElementsNonRecursive_.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/getAttributesString.js +14 -0
- package/dist/node_modules/write-excel-file/modules/xml/getAttributesString.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/getChildElements.js +42 -0
- package/dist/node_modules/write-excel-file/modules/xml/getChildElements.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/getClosingTagMarkup.js +8 -0
- package/dist/node_modules/write-excel-file/modules/xml/getClosingTagMarkup.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/getMarkupInsideElement.js +8 -0
- package/dist/node_modules/write-excel-file/modules/xml/getMarkupInsideElement.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/getOpeningTagMarkup.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xml/getOpeningTagMarkup.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/getSelfClosingTagMarkup.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xml/getSelfClosingTagMarkup.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/insertElementMarkupAccordingToOrderOfSiblings.js +64 -0
- package/dist/node_modules/write-excel-file/modules/xml/insertElementMarkupAccordingToOrderOfSiblings.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/prependMarkupInsideElement.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xml/prependMarkupInsideElement.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/removeInvalidXmlCharacters.js +9 -0
- package/dist/node_modules/write-excel-file/modules/xml/removeInvalidXmlCharacters.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/replaceElement.js +8 -0
- package/dist/node_modules/write-excel-file/modules/xml/replaceElement.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/sanitizeAttributeName.js +10 -0
- package/dist/node_modules/write-excel-file/modules/xml/sanitizeAttributeName.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/sanitizeAttributeValue.js +11 -0
- package/dist/node_modules/write-excel-file/modules/xml/sanitizeAttributeValue.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/sanitizeTextContent.js +11 -0
- package/dist/node_modules/write-excel-file/modules/xml/sanitizeTextContent.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/xml/setMarkupInsideElement.js +8 -0
- package/dist/node_modules/write-excel-file/modules/xml/setMarkupInsideElement.js.map +1 -0
- package/dist/node_modules/write-excel-file/modules/zip/zipToArrayBuffer.js +18 -0
- package/dist/node_modules/write-excel-file/modules/zip/zipToArrayBuffer.js.map +1 -0
- package/dist/planmagnet/PlanMagnetRoot.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoot.js +154 -147
- package/dist/planmagnet/PlanMagnetRoot.js.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.js +122 -106
- package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
- package/dist/planmagnet/comments/CommentThread.d.ts +8 -1
- package/dist/planmagnet/comments/CommentThread.d.ts.map +1 -1
- package/dist/planmagnet/comments/CommentThread.js +188 -181
- package/dist/planmagnet/comments/CommentThread.js.map +1 -1
- package/dist/planmagnet/comments/TargetComments.d.ts +10 -2
- package/dist/planmagnet/comments/TargetComments.d.ts.map +1 -1
- package/dist/planmagnet/comments/TargetComments.js +10 -8
- package/dist/planmagnet/comments/TargetComments.js.map +1 -1
- package/dist/planmagnet/comments/WorkItemComments.d.ts +7 -1
- package/dist/planmagnet/comments/WorkItemComments.d.ts.map +1 -1
- package/dist/planmagnet/comments/WorkItemComments.js +5 -4
- package/dist/planmagnet/comments/WorkItemComments.js.map +1 -1
- package/dist/planmagnet/controls/Pickers.d.ts +10 -0
- package/dist/planmagnet/controls/Pickers.d.ts.map +1 -1
- package/dist/planmagnet/controls/Pickers.js +75 -27
- package/dist/planmagnet/controls/Pickers.js.map +1 -1
- package/dist/planmagnet/discussion/WorkItemDiscussionPanel.d.ts +8 -0
- package/dist/planmagnet/discussion/WorkItemDiscussionPanel.d.ts.map +1 -0
- package/dist/planmagnet/discussion/WorkItemDiscussionPanel.js +217 -0
- package/dist/planmagnet/discussion/WorkItemDiscussionPanel.js.map +1 -0
- package/dist/planmagnet/docs/DocDiffView.d.ts +26 -0
- package/dist/planmagnet/docs/DocDiffView.d.ts.map +1 -0
- package/dist/planmagnet/docs/DocDiffView.js +52 -0
- package/dist/planmagnet/docs/DocDiffView.js.map +1 -0
- package/dist/planmagnet/docs/DocSuggestionsPanel.d.ts +13 -0
- package/dist/planmagnet/docs/DocSuggestionsPanel.d.ts.map +1 -0
- package/dist/planmagnet/docs/DocSuggestionsPanel.js +308 -0
- package/dist/planmagnet/docs/DocSuggestionsPanel.js.map +1 -0
- package/dist/planmagnet/docs/DocVersionCompare.d.ts +7 -0
- package/dist/planmagnet/docs/DocVersionCompare.d.ts.map +1 -0
- package/dist/planmagnet/docs/DocVersionCompare.js +105 -0
- package/dist/planmagnet/docs/DocVersionCompare.js.map +1 -0
- package/dist/planmagnet/hooks/usePresence.d.ts +39 -0
- package/dist/planmagnet/hooks/usePresence.d.ts.map +1 -0
- package/dist/planmagnet/hooks/usePresence.js +146 -0
- package/dist/planmagnet/hooks/usePresence.js.map +1 -0
- package/dist/planmagnet/index.d.ts +2 -0
- package/dist/planmagnet/index.d.ts.map +1 -1
- package/dist/planmagnet/index.js +2 -0
- package/dist/planmagnet/links/CodeLinksPanel.d.ts +22 -0
- package/dist/planmagnet/links/CodeLinksPanel.d.ts.map +1 -0
- package/dist/planmagnet/links/CodeLinksPanel.js +94 -0
- package/dist/planmagnet/links/CodeLinksPanel.js.map +1 -0
- package/dist/planmagnet/pages/DocsDocDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/DocsDocDetailPagePage.js +488 -217
- package/dist/planmagnet/pages/DocsDocDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js +136 -130
- package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js +205 -196
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ReportsCreateReportPagePage.d.ts +6 -0
- package/dist/planmagnet/pages/ReportsCreateReportPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ReportsCreateReportPagePage.js +5 -177
- package/dist/planmagnet/pages/ReportsCreateReportPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ReportsEditReportPagePage.d.ts +3 -0
- package/dist/planmagnet/pages/ReportsEditReportPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ReportsEditReportPagePage.js +15 -0
- package/dist/planmagnet/pages/ReportsEditReportPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ReportsReportPagePage.d.ts +7 -0
- package/dist/planmagnet/pages/ReportsReportPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ReportsReportPagePage.js +226 -0
- package/dist/planmagnet/pages/ReportsReportPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ReportsReportsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ReportsReportsPagePage.js +224 -496
- package/dist/planmagnet/pages/ReportsReportsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.js +194 -160
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.js.map +1 -1
- package/dist/planmagnet/presence/PresenceAvatars.d.ts +16 -0
- package/dist/planmagnet/presence/PresenceAvatars.d.ts.map +1 -0
- package/dist/planmagnet/presence/PresenceAvatars.js +56 -0
- package/dist/planmagnet/presence/PresenceAvatars.js.map +1 -0
- package/dist/planmagnet/reports/ExportMenu.d.ts +9 -0
- package/dist/planmagnet/reports/ExportMenu.d.ts.map +1 -0
- package/dist/planmagnet/reports/ExportMenu.js +116 -0
- package/dist/planmagnet/reports/ExportMenu.js.map +1 -0
- package/dist/planmagnet/reports/PrintReportView.d.ts +24 -0
- package/dist/planmagnet/reports/PrintReportView.d.ts.map +1 -0
- package/dist/planmagnet/reports/PrintReportView.js +75 -0
- package/dist/planmagnet/reports/PrintReportView.js.map +1 -0
- package/dist/planmagnet/reports/ReportBuilderCanvas.d.ts +8 -0
- package/dist/planmagnet/reports/ReportBuilderCanvas.d.ts.map +1 -0
- package/dist/planmagnet/reports/ReportBuilderCanvas.js +261 -0
- package/dist/planmagnet/reports/ReportBuilderCanvas.js.map +1 -0
- package/dist/planmagnet/reports/ReportBuilderPage.d.ts +5 -0
- package/dist/planmagnet/reports/ReportBuilderPage.d.ts.map +1 -0
- package/dist/planmagnet/reports/ReportBuilderPage.js +198 -0
- package/dist/planmagnet/reports/ReportBuilderPage.js.map +1 -0
- package/dist/planmagnet/reports/ReportRunHistory.d.ts +8 -0
- package/dist/planmagnet/reports/ReportRunHistory.d.ts.map +1 -0
- package/dist/planmagnet/reports/ReportRunHistory.js +63 -0
- package/dist/planmagnet/reports/ReportRunHistory.js.map +1 -0
- package/dist/planmagnet/reports/ReportWidgetRenderer.d.ts +7 -0
- package/dist/planmagnet/reports/ReportWidgetRenderer.d.ts.map +1 -0
- package/dist/planmagnet/reports/ReportWidgetRenderer.js +251 -0
- package/dist/planmagnet/reports/ReportWidgetRenderer.js.map +1 -0
- package/dist/planmagnet/reports/SchedulesPanel.d.ts +4 -0
- package/dist/planmagnet/reports/SchedulesPanel.d.ts.map +1 -0
- package/dist/planmagnet/reports/SchedulesPanel.js +457 -0
- package/dist/planmagnet/reports/SchedulesPanel.js.map +1 -0
- package/dist/planmagnet/reports/ShareDialog.d.ts +5 -0
- package/dist/planmagnet/reports/ShareDialog.d.ts.map +1 -0
- package/dist/planmagnet/reports/ShareDialog.js +234 -0
- package/dist/planmagnet/reports/ShareDialog.js.map +1 -0
- package/dist/planmagnet/reports/SharedReportPage.d.ts +4 -0
- package/dist/planmagnet/reports/SharedReportPage.d.ts.map +1 -0
- package/dist/planmagnet/reports/SharedReportPage.js +180 -0
- package/dist/planmagnet/reports/SharedReportPage.js.map +1 -0
- package/dist/planmagnet/reports/WidgetEditorDialog.d.ts +10 -0
- package/dist/planmagnet/reports/WidgetEditorDialog.d.ts.map +1 -0
- package/dist/planmagnet/reports/WidgetEditorDialog.js +220 -0
- package/dist/planmagnet/reports/WidgetEditorDialog.js.map +1 -0
- package/dist/planmagnet/reports/reportExportPptx.d.ts +4 -0
- package/dist/planmagnet/reports/reportExportPptx.d.ts.map +1 -0
- package/dist/planmagnet/reports/reportExportPptx.js +118 -0
- package/dist/planmagnet/reports/reportExportPptx.js.map +1 -0
- package/dist/planmagnet/reports/reportExportXlsx.d.ts +4 -0
- package/dist/planmagnet/reports/reportExportXlsx.d.ts.map +1 -0
- package/dist/planmagnet/reports/reportExportXlsx.js +42 -0
- package/dist/planmagnet/reports/reportExportXlsx.js.map +1 -0
- package/dist/planmagnet/reports/reportGraphql.d.ts +28 -0
- package/dist/planmagnet/reports/reportGraphql.d.ts.map +1 -0
- package/dist/planmagnet/reports/reportGraphql.js +360 -0
- package/dist/planmagnet/reports/reportGraphql.js.map +1 -0
- package/dist/planmagnet/reports/reportModel.d.ts +198 -0
- package/dist/planmagnet/reports/reportModel.d.ts.map +1 -0
- package/dist/planmagnet/reports/reportModel.js +328 -0
- package/dist/planmagnet/reports/reportModel.js.map +1 -0
- package/dist/planmagnet/reports/sharedReportRoute.d.ts +14 -0
- package/dist/planmagnet/reports/sharedReportRoute.d.ts.map +1 -0
- package/dist/planmagnet/reports/sharedReportRoute.js +9 -0
- package/dist/planmagnet/reports/sharedReportRoute.js.map +1 -0
- package/dist/planmagnet/utils/graphqlErrors.d.ts +6 -0
- package/dist/planmagnet/utils/graphqlErrors.d.ts.map +1 -1
- package/dist/planmagnet/utils/graphqlErrors.js +5 -2
- package/dist/planmagnet/utils/graphqlErrors.js.map +1 -1
- package/dist/planmagnet/utils/lineDiff.d.ts +21 -0
- package/dist/planmagnet/utils/lineDiff.d.ts.map +1 -0
- package/dist/planmagnet/utils/lineDiff.js +36 -0
- package/dist/planmagnet/utils/lineDiff.js.map +1 -0
- package/package.json +6 -4
|
@@ -112,6 +112,54 @@ function m({ id: t, value: n, onChange: r, noneLabel: i }) {
|
|
|
112
112
|
});
|
|
113
113
|
}
|
|
114
114
|
var h = i`
|
|
115
|
+
query PickerSprints($workspaceId: ID!, $filter: PlanmagnetSprintFilter) {
|
|
116
|
+
planmagnetSprints(workspaceId: $workspaceId, filter: $filter, pagination: { first: 100 }) {
|
|
117
|
+
items {
|
|
118
|
+
id
|
|
119
|
+
name
|
|
120
|
+
status
|
|
121
|
+
}
|
|
122
|
+
totalCount
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
`;
|
|
126
|
+
function g({ id: t, value: n, onChange: r, projectId: i, noneLabel: c, disabled: u = !1 }) {
|
|
127
|
+
let { workspaceId: d } = e(), { data: f, loading: p, error: m } = a(h, {
|
|
128
|
+
variables: {
|
|
129
|
+
workspaceId: d ?? "",
|
|
130
|
+
filter: i ? { projectId: i } : void 0
|
|
131
|
+
},
|
|
132
|
+
skip: !d
|
|
133
|
+
}), g = f?.planmagnetSprints.items ?? [];
|
|
134
|
+
return /* @__PURE__ */ s("select", {
|
|
135
|
+
id: t,
|
|
136
|
+
"aria-label": t ? void 0 : "Sprint",
|
|
137
|
+
className: l,
|
|
138
|
+
value: n,
|
|
139
|
+
disabled: u,
|
|
140
|
+
onChange: (e) => r(e.target.value),
|
|
141
|
+
children: [
|
|
142
|
+
c !== void 0 && /* @__PURE__ */ o("option", {
|
|
143
|
+
value: "",
|
|
144
|
+
children: c
|
|
145
|
+
}),
|
|
146
|
+
g.length === 0 && c === void 0 && /* @__PURE__ */ o("option", {
|
|
147
|
+
value: "",
|
|
148
|
+
children: p && !f ? "Loading sprints…" : m ? "Sprints could not be loaded" : "No sprints yet"
|
|
149
|
+
}),
|
|
150
|
+
g.map((e) => /* @__PURE__ */ s("option", {
|
|
151
|
+
value: e.id,
|
|
152
|
+
children: [
|
|
153
|
+
e.name,
|
|
154
|
+
" (",
|
|
155
|
+
e.status.toLowerCase(),
|
|
156
|
+
")"
|
|
157
|
+
]
|
|
158
|
+
}, e.id))
|
|
159
|
+
]
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
var _ = i`
|
|
115
163
|
query PickerWorkItems($workspaceId: ID!, $filter: PlanmagnetWorkItemFilter) {
|
|
116
164
|
planmagnetWorkItems(workspaceId: $workspaceId, filter: $filter, pagination: { first: 20 }) {
|
|
117
165
|
items {
|
|
@@ -123,12 +171,12 @@ var h = i`
|
|
|
123
171
|
}
|
|
124
172
|
}
|
|
125
173
|
`;
|
|
126
|
-
function
|
|
127
|
-
let { workspaceId: p } = e(), [m,
|
|
174
|
+
function v({ id: n, projectId: i, value: u, onChange: d, exclude: f = [] }) {
|
|
175
|
+
let { workspaceId: p } = e(), [m, h] = r(""), g = t(m.trim()), { data: v, loading: y } = a(_, {
|
|
128
176
|
variables: {
|
|
129
177
|
workspaceId: p ?? "",
|
|
130
178
|
filter: {
|
|
131
|
-
...
|
|
179
|
+
...g && { search: g },
|
|
132
180
|
...i && { projectId: i }
|
|
133
181
|
}
|
|
134
182
|
},
|
|
@@ -141,7 +189,7 @@ function g({ id: n, projectId: i, value: u, onChange: d, exclude: f = [] }) {
|
|
|
141
189
|
"aria-label": "Search work items",
|
|
142
190
|
placeholder: "Search by key or title",
|
|
143
191
|
value: m,
|
|
144
|
-
onChange: (e) =>
|
|
192
|
+
onChange: (e) => h(e.target.value)
|
|
145
193
|
}),
|
|
146
194
|
/* @__PURE__ */ s("select", {
|
|
147
195
|
id: n,
|
|
@@ -180,7 +228,7 @@ function g({ id: n, projectId: i, value: u, onChange: d, exclude: f = [] }) {
|
|
|
180
228
|
]
|
|
181
229
|
});
|
|
182
230
|
}
|
|
183
|
-
var
|
|
231
|
+
var y = i`
|
|
184
232
|
query PickerDocs($workspaceId: String, $filter: PlanmagnetDocFilter) {
|
|
185
233
|
planmagnetDocs(workspaceId: $workspaceId, filter: $filter, pagination: { first: 20 }) {
|
|
186
234
|
items {
|
|
@@ -191,14 +239,14 @@ var _ = i`
|
|
|
191
239
|
}
|
|
192
240
|
}
|
|
193
241
|
`;
|
|
194
|
-
function
|
|
195
|
-
let { workspaceId: f } = e(), [p, m] = r(""), h = t(p.trim()), { data: g, loading:
|
|
242
|
+
function b({ id: n, value: i, onChange: u, exclude: d = [] }) {
|
|
243
|
+
let { workspaceId: f } = e(), [p, m] = r(""), h = t(p.trim()), { data: g, loading: _ } = a(y, {
|
|
196
244
|
variables: {
|
|
197
245
|
workspaceId: f ?? "",
|
|
198
246
|
filter: h ? { search: h } : void 0
|
|
199
247
|
},
|
|
200
248
|
skip: !f
|
|
201
|
-
}),
|
|
249
|
+
}), v = g?.planmagnetDocs.items ?? [], b = v.filter((e) => !d.includes(e.id)), x = g?.planmagnetDocs.totalCount ?? 0;
|
|
202
250
|
return /* @__PURE__ */ s("div", {
|
|
203
251
|
className: "space-y-1",
|
|
204
252
|
children: [
|
|
@@ -215,17 +263,17 @@ function v({ id: n, value: i, onChange: u, exclude: d = [] }) {
|
|
|
215
263
|
onChange: (e) => u(e.target.value),
|
|
216
264
|
children: [/* @__PURE__ */ o("option", {
|
|
217
265
|
value: "",
|
|
218
|
-
children:
|
|
266
|
+
children: _ && !g ? "Searching…" : b.length ? "Choose a doc" : "No match"
|
|
219
267
|
}), b.map((e) => /* @__PURE__ */ o("option", {
|
|
220
268
|
value: e.id,
|
|
221
269
|
children: e.title
|
|
222
270
|
}, e.id))]
|
|
223
271
|
}),
|
|
224
|
-
x >
|
|
272
|
+
x > v.length && /* @__PURE__ */ s("p", {
|
|
225
273
|
className: "text-xs text-muted-foreground",
|
|
226
274
|
children: [
|
|
227
275
|
"Showing ",
|
|
228
|
-
|
|
276
|
+
v.length,
|
|
229
277
|
" of ",
|
|
230
278
|
x,
|
|
231
279
|
" — type to narrow the list."
|
|
@@ -234,7 +282,7 @@ function v({ id: n, value: i, onChange: u, exclude: d = [] }) {
|
|
|
234
282
|
]
|
|
235
283
|
});
|
|
236
284
|
}
|
|
237
|
-
var
|
|
285
|
+
var x = i`
|
|
238
286
|
query PickerPrograms($workspaceId: ID!) {
|
|
239
287
|
planmagnetPrograms(workspaceId: $workspaceId, pagination: { first: 100 }) {
|
|
240
288
|
items {
|
|
@@ -245,8 +293,8 @@ var y = i`
|
|
|
245
293
|
}
|
|
246
294
|
}
|
|
247
295
|
`;
|
|
248
|
-
function
|
|
249
|
-
let { workspaceId: c } = e(), { data: u, loading: d, error: f } = a(
|
|
296
|
+
function S({ id: t, value: n, onChange: r, noneLabel: i }) {
|
|
297
|
+
let { workspaceId: c } = e(), { data: u, loading: d, error: f } = a(x, {
|
|
250
298
|
variables: { workspaceId: c ?? "" },
|
|
251
299
|
skip: !c
|
|
252
300
|
}), p = u?.planmagnetPrograms.items ?? [];
|
|
@@ -271,7 +319,7 @@ function b({ id: t, value: n, onChange: r, noneLabel: i }) {
|
|
|
271
319
|
]
|
|
272
320
|
});
|
|
273
321
|
}
|
|
274
|
-
var
|
|
322
|
+
var C = i`
|
|
275
323
|
query PickerPortfolios($workspaceId: ID!) {
|
|
276
324
|
planmagnetPortfolios(workspaceId: $workspaceId, pagination: { first: 100 }) {
|
|
277
325
|
items {
|
|
@@ -282,8 +330,8 @@ var x = i`
|
|
|
282
330
|
}
|
|
283
331
|
}
|
|
284
332
|
`;
|
|
285
|
-
function
|
|
286
|
-
let { workspaceId: c } = e(), { data: u, loading: d, error: f } = a(
|
|
333
|
+
function w({ id: t, value: n, onChange: r, noneLabel: i }) {
|
|
334
|
+
let { workspaceId: c } = e(), { data: u, loading: d, error: f } = a(C, {
|
|
287
335
|
variables: { workspaceId: c ?? "" },
|
|
288
336
|
skip: !c
|
|
289
337
|
}), p = u?.planmagnetPortfolios.items ?? [];
|
|
@@ -308,7 +356,7 @@ function S({ id: t, value: n, onChange: r, noneLabel: i }) {
|
|
|
308
356
|
]
|
|
309
357
|
});
|
|
310
358
|
}
|
|
311
|
-
var
|
|
359
|
+
var T = i`
|
|
312
360
|
query PickerCompetitors($workspaceId: ID!, $filter: PlanmagnetCompetitorFilter) {
|
|
313
361
|
planmagnetCompetitors(workspaceId: $workspaceId, filter: $filter, pagination: { first: 20 }) {
|
|
314
362
|
items {
|
|
@@ -319,8 +367,8 @@ var C = i`
|
|
|
319
367
|
}
|
|
320
368
|
}
|
|
321
369
|
`;
|
|
322
|
-
function
|
|
323
|
-
let { workspaceId: f } = e(), [p, m] = r(""), h = t(p.trim()), { data: g, loading: _ } = a(
|
|
370
|
+
function E({ id: n, value: i, onChange: u, exclude: d = [] }) {
|
|
371
|
+
let { workspaceId: f } = e(), [p, m] = r(""), h = t(p.trim()), { data: g, loading: _ } = a(T, {
|
|
324
372
|
variables: {
|
|
325
373
|
workspaceId: f ?? "",
|
|
326
374
|
filter: h ? { search: h } : void 0
|
|
@@ -362,7 +410,7 @@ function w({ id: n, value: i, onChange: u, exclude: d = [] }) {
|
|
|
362
410
|
]
|
|
363
411
|
});
|
|
364
412
|
}
|
|
365
|
-
var
|
|
413
|
+
var D = i`
|
|
366
414
|
query PickerProducts($workspaceId: ID!) {
|
|
367
415
|
planmagnetProducts(workspaceId: $workspaceId, pagination: { first: 100 }) {
|
|
368
416
|
items {
|
|
@@ -373,8 +421,8 @@ var T = i`
|
|
|
373
421
|
}
|
|
374
422
|
}
|
|
375
423
|
`;
|
|
376
|
-
function
|
|
377
|
-
let { workspaceId: c } = e(), { data: u, loading: d, error: f } = a(
|
|
424
|
+
function O({ id: t, value: n, onChange: r, noneLabel: i }) {
|
|
425
|
+
let { workspaceId: c } = e(), { data: u, loading: d, error: f } = a(D, {
|
|
378
426
|
variables: { workspaceId: c ?? "" },
|
|
379
427
|
skip: !c
|
|
380
428
|
}), p = u?.planmagnetProducts.items ?? [];
|
|
@@ -399,7 +447,7 @@ function E({ id: t, value: n, onChange: r, noneLabel: i }) {
|
|
|
399
447
|
]
|
|
400
448
|
});
|
|
401
449
|
}
|
|
402
|
-
var
|
|
450
|
+
var k = i`
|
|
403
451
|
query PickerRoadmaps($workspaceId: ID!, $filter: PlanmagnetRoadmapFilter) {
|
|
404
452
|
planmagnetRoadmaps(workspaceId: $workspaceId, filter: $filter, pagination: { first: 100 }) {
|
|
405
453
|
items {
|
|
@@ -410,8 +458,8 @@ var D = i`
|
|
|
410
458
|
}
|
|
411
459
|
}
|
|
412
460
|
`;
|
|
413
|
-
function
|
|
414
|
-
let { workspaceId: u } = e(), { data: d, loading: f, error: p } = a(
|
|
461
|
+
function A({ id: t, value: n, onChange: r, noneLabel: i, productId: c }) {
|
|
462
|
+
let { workspaceId: u } = e(), { data: d, loading: f, error: p } = a(k, {
|
|
415
463
|
variables: {
|
|
416
464
|
workspaceId: u ?? "",
|
|
417
465
|
filter: c ? { productId: c } : void 0
|
|
@@ -440,6 +488,6 @@ function O({ id: t, value: n, onChange: r, noneLabel: i, productId: c }) {
|
|
|
440
488
|
});
|
|
441
489
|
}
|
|
442
490
|
//#endregion
|
|
443
|
-
export {
|
|
491
|
+
export { E as CompetitorSearchSelect, b as DocSearchSelect, w as PortfolioSelect, O as ProductSelect, S as ProgramSelect, f as ProjectSelect, A as RoadmapSelect, g as SprintSelect, m as TeamSelect, v as WorkItemSearchSelect };
|
|
444
492
|
|
|
445
493
|
//# sourceMappingURL=Pickers.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Pickers.js","names":[],"sources":["../../../src/planmagnet/controls/Pickers.tsx"],"sourcesContent":["import { useDeferredValue, useEffect, useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Input } from '@burdenoff/fe-libs/ui';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\n\n/**\n * Record pickers shared by forms and dialogs: a project select, and search-then-pick selects for work items and\n * docs. Values are record ids. Search runs on the server (never \"the first page, filtered in the browser\"), so a\n * record past the first page can still be found.\n */\n\nconst selectClass =\n 'w-full rounded-md border border-input bg-background px-3 py-2 text-sm disabled:opacity-60';\n\nconst PICKER_PROJECTS = gql`\n query PickerProjects($workspaceId: ID!, $pagination: PlanmagnetPaginationInput) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: $pagination) {\n items {\n id\n name\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n totalCount\n }\n }\n`;\n\n/** Projects are read page by page up to this many, so the picker never silently stops at the first 100. */\nconst MAX_PROJECT_OPTIONS = 500;\n\n/** A project select. '' means \"no project\" when `noneLabel` is given. `exclude` hides ids already spoken for. */\nexport function ProjectSelect({\n id,\n value,\n onChange,\n noneLabel,\n exclude = [],\n disabled = false,\n}: {\n id?: string;\n value: string;\n onChange: (projectId: string) => void;\n noneLabel?: string;\n exclude?: string[];\n disabled?: boolean;\n}) {\n const { workspaceId } = usePlanMagnet();\n const { data, loading, error, fetchMore } = useQuery<{\n planmagnetProjects: {\n items: { id: string; name: string }[];\n pageInfo: { hasNextPage: boolean; endCursor: string | null };\n totalCount: number;\n };\n }>(PICKER_PROJECTS, {\n variables: { workspaceId: workspaceId ?? '', pagination: { first: 100 } },\n skip: !workspaceId,\n });\n const loaded = data?.planmagnetProjects.items ?? [];\n const hasNextPage = data?.planmagnetProjects.pageInfo.hasNextPage ?? false;\n const endCursor = data?.planmagnetProjects.pageInfo.endCursor ?? null;\n useEffect(() => {\n if (!hasNextPage || !endCursor || loaded.length >= MAX_PROJECT_OPTIONS) return;\n fetchMore({\n variables: { pagination: { first: 100, after: endCursor } },\n updateQuery: (prev, { fetchMoreResult }) => ({\n planmagnetProjects: {\n ...fetchMoreResult.planmagnetProjects,\n items: [...prev.planmagnetProjects.items, ...fetchMoreResult.planmagnetProjects.items],\n },\n }),\n }).catch(() => {\n // A failed extra page leaves the projects already loaded usable.\n });\n }, [hasNextPage, endCursor, loaded.length, fetchMore]);\n const projects = loaded.filter((p) => !exclude.includes(p.id));\n return (\n <select\n id={id}\n className={selectClass}\n value={value}\n disabled={disabled}\n onChange={(e) => onChange(e.target.value)}\n >\n {noneLabel !== undefined && <option value=\"\">{noneLabel}</option>}\n {projects.length === 0 && noneLabel === undefined && (\n <option value=\"\">\n {loading && !data\n ? 'Loading projects…'\n : error\n ? 'Projects could not be loaded'\n : 'No projects yet'}\n </option>\n )}\n {projects.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n {/* Never a silent cut-off: say so when the workspace has more projects than the picker lists. */}\n {hasNextPage && loaded.length >= MAX_PROJECT_OPTIONS && (\n <option value=\"\" disabled>\n {`Only the first ${MAX_PROJECT_OPTIONS} projects are listed`}\n </option>\n )}\n </select>\n );\n}\n\nconst PICKER_TEAMS = gql`\n query PickerTeams($workspaceId: ID!) {\n planmagnetTeams(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n }\n totalCount\n }\n }\n`;\n\n/** A team select (BOFF-8044). '' means \"no team\" when `noneLabel` is given. */\nexport function TeamSelect({\n id,\n value,\n onChange,\n noneLabel,\n}: {\n id?: string;\n value: string;\n onChange: (teamId: string) => void;\n noneLabel?: string;\n}) {\n const { workspaceId } = usePlanMagnet();\n const { data, loading, error } = useQuery<{\n planmagnetTeams: { items: { id: string; name: string }[]; totalCount: number };\n }>(PICKER_TEAMS, { variables: { workspaceId: workspaceId ?? '' }, skip: !workspaceId });\n const teams = data?.planmagnetTeams.items ?? [];\n return (\n <select\n id={id}\n aria-label={id ? undefined : 'Team'}\n className={selectClass}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n >\n {noneLabel !== undefined && <option value=\"\">{noneLabel}</option>}\n {teams.length === 0 && noneLabel === undefined && (\n <option value=\"\">\n {loading && !data\n ? 'Loading teams…'\n : error\n ? 'Teams could not be loaded'\n : 'No teams yet'}\n </option>\n )}\n {teams.map((t) => (\n <option key={t.id} value={t.id}>\n {t.name}\n </option>\n ))}\n </select>\n );\n}\n\nconst PICKER_WORK_ITEMS = gql`\n query PickerWorkItems($workspaceId: ID!, $filter: PlanmagnetWorkItemFilter) {\n planmagnetWorkItems(workspaceId: $workspaceId, filter: $filter, pagination: { first: 20 }) {\n items {\n id\n key\n title\n }\n totalCount\n }\n }\n`;\n\n/**\n * Search, then pick one work item. The server matches the key, title and description. `exclude` hides items that are\n * already linked (the result says how many more exist, so an empty list never claims \"nothing left\" falsely).\n */\nexport function WorkItemSearchSelect({\n id,\n projectId,\n value,\n onChange,\n exclude = [],\n}: {\n id: string;\n projectId?: string;\n value: string;\n onChange: (workItemId: string) => void;\n exclude?: string[];\n}) {\n const { workspaceId } = usePlanMagnet();\n const [search, setSearch] = useState('');\n const deferred = useDeferredValue(search.trim());\n const { data, loading } = useQuery<{\n planmagnetWorkItems: {\n items: { id: string; key: string; title: string }[];\n totalCount: number;\n };\n }>(PICKER_WORK_ITEMS, {\n variables: {\n workspaceId: workspaceId ?? '',\n filter: { ...(deferred && { search: deferred }), ...(projectId && { projectId }) },\n },\n skip: !workspaceId,\n });\n const found = data?.planmagnetWorkItems.items ?? [];\n const items = found.filter((w) => !exclude.includes(w.id));\n const total = data?.planmagnetWorkItems.totalCount ?? 0;\n return (\n <div className=\"space-y-1\">\n <Input\n aria-label=\"Search work items\"\n placeholder=\"Search by key or title\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n <select\n id={id}\n className={selectClass}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n >\n <option value=\"\">\n {loading && !data ? 'Searching…' : items.length ? 'Choose a work item' : 'No match'}\n </option>\n {/* The current value stays selectable (and visible) when it is not in this page of results. */}\n {value && !items.some((w) => w.id === value) && (\n <option value={value}>Currently linked work item</option>\n )}\n {items.map((w) => (\n <option key={w.id} value={w.id}>\n {w.key} — {w.title}\n </option>\n ))}\n </select>\n {total > found.length && (\n <p className=\"text-xs text-muted-foreground\">\n Showing {found.length} of {total} — type to narrow the list.\n </p>\n )}\n </div>\n );\n}\n\nconst PICKER_DOCS = gql`\n query PickerDocs($workspaceId: String, $filter: PlanmagnetDocFilter) {\n planmagnetDocs(workspaceId: $workspaceId, filter: $filter, pagination: { first: 20 }) {\n items {\n id\n title\n }\n totalCount\n }\n }\n`;\n\n/** Search, then pick one doc. */\nexport function DocSearchSelect({\n id,\n value,\n onChange,\n exclude = [],\n}: {\n id: string;\n value: string;\n onChange: (docId: string) => void;\n exclude?: string[];\n}) {\n const { workspaceId } = usePlanMagnet();\n const [search, setSearch] = useState('');\n const deferred = useDeferredValue(search.trim());\n const { data, loading } = useQuery<{\n planmagnetDocs: { items: { id: string; title: string }[]; totalCount: number };\n }>(PICKER_DOCS, {\n variables: {\n workspaceId: workspaceId ?? '',\n filter: deferred ? { search: deferred } : undefined,\n },\n skip: !workspaceId,\n });\n const found = data?.planmagnetDocs.items ?? [];\n const docs = found.filter((d) => !exclude.includes(d.id));\n const total = data?.planmagnetDocs.totalCount ?? 0;\n return (\n <div className=\"space-y-1\">\n <Input\n aria-label=\"Search docs\"\n placeholder=\"Search docs by title\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n <select\n id={id}\n className={selectClass}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n >\n <option value=\"\">\n {loading && !data ? 'Searching…' : docs.length ? 'Choose a doc' : 'No match'}\n </option>\n {docs.map((d) => (\n <option key={d.id} value={d.id}>\n {d.title}\n </option>\n ))}\n </select>\n {total > found.length && (\n <p className=\"text-xs text-muted-foreground\">\n Showing {found.length} of {total} — type to narrow the list.\n </p>\n )}\n </div>\n );\n}\n\nconst PICKER_PROGRAMS = gql`\n query PickerPrograms($workspaceId: ID!) {\n planmagnetPrograms(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n }\n totalCount\n }\n }\n`;\n\n/** A program select. '' means \"no program\" when `noneLabel` is given. */\nexport function ProgramSelect({\n id,\n value,\n onChange,\n noneLabel,\n}: {\n id?: string;\n value: string;\n onChange: (programId: string) => void;\n noneLabel?: string;\n}) {\n const { workspaceId } = usePlanMagnet();\n const { data, loading, error } = useQuery<{\n planmagnetPrograms: { items: { id: string; name: string }[]; totalCount: number };\n }>(PICKER_PROGRAMS, { variables: { workspaceId: workspaceId ?? '' }, skip: !workspaceId });\n const programs = data?.planmagnetPrograms.items ?? [];\n return (\n <select\n id={id}\n className={selectClass}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n >\n {noneLabel !== undefined && <option value=\"\">{noneLabel}</option>}\n {programs.length === 0 && noneLabel === undefined && (\n <option value=\"\">\n {loading && !data\n ? 'Loading programs…'\n : error\n ? 'Programs could not be loaded'\n : 'No programs yet'}\n </option>\n )}\n {programs.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n </select>\n );\n}\n\nconst PICKER_PORTFOLIOS = gql`\n query PickerPortfolios($workspaceId: ID!) {\n planmagnetPortfolios(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n }\n totalCount\n }\n }\n`;\n\n/** A portfolio select (BOFF-8047). '' means \"no portfolio\" when `noneLabel` is given. */\nexport function PortfolioSelect({\n id,\n value,\n onChange,\n noneLabel,\n}: {\n id?: string;\n value: string;\n onChange: (portfolioId: string) => void;\n noneLabel?: string;\n}) {\n const { workspaceId } = usePlanMagnet();\n const { data, loading, error } = useQuery<{\n planmagnetPortfolios: { items: { id: string; name: string }[]; totalCount: number };\n }>(PICKER_PORTFOLIOS, { variables: { workspaceId: workspaceId ?? '' }, skip: !workspaceId });\n const portfolios = data?.planmagnetPortfolios.items ?? [];\n return (\n <select\n id={id}\n className={selectClass}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n >\n {noneLabel !== undefined && <option value=\"\">{noneLabel}</option>}\n {portfolios.length === 0 && noneLabel === undefined && (\n <option value=\"\">\n {loading && !data\n ? 'Loading portfolios…'\n : error\n ? 'Portfolios could not be loaded'\n : 'No portfolios yet'}\n </option>\n )}\n {portfolios.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n </select>\n );\n}\n\nconst PICKER_COMPETITORS = gql`\n query PickerCompetitors($workspaceId: ID!, $filter: PlanmagnetCompetitorFilter) {\n planmagnetCompetitors(workspaceId: $workspaceId, filter: $filter, pagination: { first: 20 }) {\n items {\n id\n name\n }\n totalCount\n }\n }\n`;\n\n/** Search, then pick one competitor. `exclude` hides competitors already linked. */\nexport function CompetitorSearchSelect({\n id,\n value,\n onChange,\n exclude = [],\n}: {\n id: string;\n value: string;\n onChange: (competitorId: string) => void;\n exclude?: string[];\n}) {\n const { workspaceId } = usePlanMagnet();\n const [search, setSearch] = useState('');\n const deferred = useDeferredValue(search.trim());\n const { data, loading } = useQuery<{\n planmagnetCompetitors: { items: { id: string; name: string }[]; totalCount: number };\n }>(PICKER_COMPETITORS, {\n variables: {\n workspaceId: workspaceId ?? '',\n filter: deferred ? { search: deferred } : undefined,\n },\n skip: !workspaceId,\n });\n const found = data?.planmagnetCompetitors.items ?? [];\n const competitors = found.filter((c) => !exclude.includes(c.id));\n const total = data?.planmagnetCompetitors.totalCount ?? 0;\n return (\n <div className=\"space-y-1\">\n <Input\n aria-label=\"Search competitors\"\n placeholder=\"Search competitors by name\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n <select\n id={id}\n className={selectClass}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n >\n <option value=\"\">\n {loading && !data\n ? 'Searching…'\n : competitors.length\n ? 'Choose a competitor'\n : 'No match'}\n </option>\n {competitors.map((c) => (\n <option key={c.id} value={c.id}>\n {c.name}\n </option>\n ))}\n </select>\n {total > found.length && (\n <p className=\"text-xs text-muted-foreground\">\n Showing {found.length} of {total} — type to narrow the list.\n </p>\n )}\n </div>\n );\n}\n\nconst PICKER_PRODUCTS = gql`\n query PickerProducts($workspaceId: ID!) {\n planmagnetProducts(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n }\n totalCount\n }\n }\n`;\n\n/** A product select (PRM-27). '' means \"every product\" when `noneLabel` is given. */\nexport function ProductSelect({\n id,\n value,\n onChange,\n noneLabel,\n}: {\n id?: string;\n value: string;\n onChange: (productId: string) => void;\n noneLabel?: string;\n}) {\n const { workspaceId } = usePlanMagnet();\n const { data, loading, error } = useQuery<{\n planmagnetProducts: { items: { id: string; name: string }[]; totalCount: number };\n }>(PICKER_PRODUCTS, { variables: { workspaceId: workspaceId ?? '' }, skip: !workspaceId });\n const products = data?.planmagnetProducts.items ?? [];\n return (\n <select\n id={id}\n className={selectClass}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n >\n {noneLabel !== undefined && <option value=\"\">{noneLabel}</option>}\n {products.length === 0 && noneLabel === undefined && (\n <option value=\"\">\n {loading && !data\n ? 'Loading products…'\n : error\n ? 'Products could not be loaded'\n : 'No products yet'}\n </option>\n )}\n {products.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n </select>\n );\n}\n\nconst PICKER_ROADMAPS = gql`\n query PickerRoadmaps($workspaceId: ID!, $filter: PlanmagnetRoadmapFilter) {\n planmagnetRoadmaps(workspaceId: $workspaceId, filter: $filter, pagination: { first: 100 }) {\n items {\n id\n name\n }\n totalCount\n }\n }\n`;\n\n/**\n * A roadmap select (PRM-27). '' means \"every roadmap\" when `noneLabel` is given. `productId` narrows the list\n * to that product's roadmaps, same filter FeatureInitiativeCard uses for its own roadmap picker.\n */\nexport function RoadmapSelect({\n id,\n value,\n onChange,\n noneLabel,\n productId,\n}: {\n id?: string;\n value: string;\n onChange: (roadmapId: string) => void;\n noneLabel?: string;\n productId?: string;\n}) {\n const { workspaceId } = usePlanMagnet();\n const { data, loading, error } = useQuery<{\n planmagnetRoadmaps: { items: { id: string; name: string }[]; totalCount: number };\n }>(PICKER_ROADMAPS, {\n variables: { workspaceId: workspaceId ?? '', filter: productId ? { productId } : undefined },\n skip: !workspaceId,\n });\n const roadmaps = data?.planmagnetRoadmaps.items ?? [];\n return (\n <select\n id={id}\n className={selectClass}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n >\n {noneLabel !== undefined && <option value=\"\">{noneLabel}</option>}\n {roadmaps.length === 0 && noneLabel === undefined && (\n <option value=\"\">\n {loading && !data\n ? 'Loading roadmaps…'\n : error\n ? 'Roadmaps could not be loaded'\n : 'No roadmaps yet'}\n </option>\n )}\n {roadmaps.map((r) => (\n <option key={r.id} value={r.id}>\n {r.name}\n </option>\n ))}\n </select>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Pickers.js","names":[],"sources":["../../../src/planmagnet/controls/Pickers.tsx"],"sourcesContent":["import { useDeferredValue, useEffect, useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Input } from '@burdenoff/fe-libs/ui';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\n\n/**\n * Record pickers shared by forms and dialogs: a project select, and search-then-pick selects for work items and\n * docs. Values are record ids. Search runs on the server (never \"the first page, filtered in the browser\"), so a\n * record past the first page can still be found.\n */\n\nconst selectClass =\n 'w-full rounded-md border border-input bg-background px-3 py-2 text-sm disabled:opacity-60';\n\nconst PICKER_PROJECTS = gql`\n query PickerProjects($workspaceId: ID!, $pagination: PlanmagnetPaginationInput) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: $pagination) {\n items {\n id\n name\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n totalCount\n }\n }\n`;\n\n/** Projects are read page by page up to this many, so the picker never silently stops at the first 100. */\nconst MAX_PROJECT_OPTIONS = 500;\n\n/** A project select. '' means \"no project\" when `noneLabel` is given. `exclude` hides ids already spoken for. */\nexport function ProjectSelect({\n id,\n value,\n onChange,\n noneLabel,\n exclude = [],\n disabled = false,\n}: {\n id?: string;\n value: string;\n onChange: (projectId: string) => void;\n noneLabel?: string;\n exclude?: string[];\n disabled?: boolean;\n}) {\n const { workspaceId } = usePlanMagnet();\n const { data, loading, error, fetchMore } = useQuery<{\n planmagnetProjects: {\n items: { id: string; name: string }[];\n pageInfo: { hasNextPage: boolean; endCursor: string | null };\n totalCount: number;\n };\n }>(PICKER_PROJECTS, {\n variables: { workspaceId: workspaceId ?? '', pagination: { first: 100 } },\n skip: !workspaceId,\n });\n const loaded = data?.planmagnetProjects.items ?? [];\n const hasNextPage = data?.planmagnetProjects.pageInfo.hasNextPage ?? false;\n const endCursor = data?.planmagnetProjects.pageInfo.endCursor ?? null;\n useEffect(() => {\n if (!hasNextPage || !endCursor || loaded.length >= MAX_PROJECT_OPTIONS) return;\n fetchMore({\n variables: { pagination: { first: 100, after: endCursor } },\n updateQuery: (prev, { fetchMoreResult }) => ({\n planmagnetProjects: {\n ...fetchMoreResult.planmagnetProjects,\n items: [...prev.planmagnetProjects.items, ...fetchMoreResult.planmagnetProjects.items],\n },\n }),\n }).catch(() => {\n // A failed extra page leaves the projects already loaded usable.\n });\n }, [hasNextPage, endCursor, loaded.length, fetchMore]);\n const projects = loaded.filter((p) => !exclude.includes(p.id));\n return (\n <select\n id={id}\n className={selectClass}\n value={value}\n disabled={disabled}\n onChange={(e) => onChange(e.target.value)}\n >\n {noneLabel !== undefined && <option value=\"\">{noneLabel}</option>}\n {projects.length === 0 && noneLabel === undefined && (\n <option value=\"\">\n {loading && !data\n ? 'Loading projects…'\n : error\n ? 'Projects could not be loaded'\n : 'No projects yet'}\n </option>\n )}\n {projects.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n {/* Never a silent cut-off: say so when the workspace has more projects than the picker lists. */}\n {hasNextPage && loaded.length >= MAX_PROJECT_OPTIONS && (\n <option value=\"\" disabled>\n {`Only the first ${MAX_PROJECT_OPTIONS} projects are listed`}\n </option>\n )}\n </select>\n );\n}\n\nconst PICKER_TEAMS = gql`\n query PickerTeams($workspaceId: ID!) {\n planmagnetTeams(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n }\n totalCount\n }\n }\n`;\n\n/** A team select (BOFF-8044). '' means \"no team\" when `noneLabel` is given. */\nexport function TeamSelect({\n id,\n value,\n onChange,\n noneLabel,\n}: {\n id?: string;\n value: string;\n onChange: (teamId: string) => void;\n noneLabel?: string;\n}) {\n const { workspaceId } = usePlanMagnet();\n const { data, loading, error } = useQuery<{\n planmagnetTeams: { items: { id: string; name: string }[]; totalCount: number };\n }>(PICKER_TEAMS, { variables: { workspaceId: workspaceId ?? '' }, skip: !workspaceId });\n const teams = data?.planmagnetTeams.items ?? [];\n return (\n <select\n id={id}\n aria-label={id ? undefined : 'Team'}\n className={selectClass}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n >\n {noneLabel !== undefined && <option value=\"\">{noneLabel}</option>}\n {teams.length === 0 && noneLabel === undefined && (\n <option value=\"\">\n {loading && !data\n ? 'Loading teams…'\n : error\n ? 'Teams could not be loaded'\n : 'No teams yet'}\n </option>\n )}\n {teams.map((t) => (\n <option key={t.id} value={t.id}>\n {t.name}\n </option>\n ))}\n </select>\n );\n}\n\nconst PICKER_SPRINTS = gql`\n query PickerSprints($workspaceId: ID!, $filter: PlanmagnetSprintFilter) {\n planmagnetSprints(workspaceId: $workspaceId, filter: $filter, pagination: { first: 100 }) {\n items {\n id\n name\n status\n }\n totalCount\n }\n }\n`;\n\n/** A sprint select, optionally scoped to one project (report-builder widgets: BURNDOWN reads one sprint). '' means\n * \"no sprint\" when `noneLabel` is given. */\nexport function SprintSelect({\n id,\n value,\n onChange,\n projectId,\n noneLabel,\n disabled = false,\n}: {\n id?: string;\n value: string;\n onChange: (sprintId: string) => void;\n projectId?: string;\n noneLabel?: string;\n disabled?: boolean;\n}) {\n const { workspaceId } = usePlanMagnet();\n const { data, loading, error } = useQuery<{\n planmagnetSprints: {\n items: { id: string; name: string; status: string }[];\n totalCount: number;\n };\n }>(PICKER_SPRINTS, {\n variables: { workspaceId: workspaceId ?? '', filter: projectId ? { projectId } : undefined },\n skip: !workspaceId,\n });\n const sprints = data?.planmagnetSprints.items ?? [];\n return (\n <select\n id={id}\n aria-label={id ? undefined : 'Sprint'}\n className={selectClass}\n value={value}\n disabled={disabled}\n onChange={(e) => onChange(e.target.value)}\n >\n {noneLabel !== undefined && <option value=\"\">{noneLabel}</option>}\n {sprints.length === 0 && noneLabel === undefined && (\n <option value=\"\">\n {loading && !data\n ? 'Loading sprints…'\n : error\n ? 'Sprints could not be loaded'\n : 'No sprints yet'}\n </option>\n )}\n {sprints.map((s) => (\n <option key={s.id} value={s.id}>\n {s.name} ({s.status.toLowerCase()})\n </option>\n ))}\n </select>\n );\n}\n\nconst PICKER_WORK_ITEMS = gql`\n query PickerWorkItems($workspaceId: ID!, $filter: PlanmagnetWorkItemFilter) {\n planmagnetWorkItems(workspaceId: $workspaceId, filter: $filter, pagination: { first: 20 }) {\n items {\n id\n key\n title\n }\n totalCount\n }\n }\n`;\n\n/**\n * Search, then pick one work item. The server matches the key, title and description. `exclude` hides items that are\n * already linked (the result says how many more exist, so an empty list never claims \"nothing left\" falsely).\n */\nexport function WorkItemSearchSelect({\n id,\n projectId,\n value,\n onChange,\n exclude = [],\n}: {\n id: string;\n projectId?: string;\n value: string;\n onChange: (workItemId: string) => void;\n exclude?: string[];\n}) {\n const { workspaceId } = usePlanMagnet();\n const [search, setSearch] = useState('');\n const deferred = useDeferredValue(search.trim());\n const { data, loading } = useQuery<{\n planmagnetWorkItems: {\n items: { id: string; key: string; title: string }[];\n totalCount: number;\n };\n }>(PICKER_WORK_ITEMS, {\n variables: {\n workspaceId: workspaceId ?? '',\n filter: { ...(deferred && { search: deferred }), ...(projectId && { projectId }) },\n },\n skip: !workspaceId,\n });\n const found = data?.planmagnetWorkItems.items ?? [];\n const items = found.filter((w) => !exclude.includes(w.id));\n const total = data?.planmagnetWorkItems.totalCount ?? 0;\n return (\n <div className=\"space-y-1\">\n <Input\n aria-label=\"Search work items\"\n placeholder=\"Search by key or title\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n <select\n id={id}\n className={selectClass}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n >\n <option value=\"\">\n {loading && !data ? 'Searching…' : items.length ? 'Choose a work item' : 'No match'}\n </option>\n {/* The current value stays selectable (and visible) when it is not in this page of results. */}\n {value && !items.some((w) => w.id === value) && (\n <option value={value}>Currently linked work item</option>\n )}\n {items.map((w) => (\n <option key={w.id} value={w.id}>\n {w.key} — {w.title}\n </option>\n ))}\n </select>\n {total > found.length && (\n <p className=\"text-xs text-muted-foreground\">\n Showing {found.length} of {total} — type to narrow the list.\n </p>\n )}\n </div>\n );\n}\n\nconst PICKER_DOCS = gql`\n query PickerDocs($workspaceId: String, $filter: PlanmagnetDocFilter) {\n planmagnetDocs(workspaceId: $workspaceId, filter: $filter, pagination: { first: 20 }) {\n items {\n id\n title\n }\n totalCount\n }\n }\n`;\n\n/** Search, then pick one doc. */\nexport function DocSearchSelect({\n id,\n value,\n onChange,\n exclude = [],\n}: {\n id: string;\n value: string;\n onChange: (docId: string) => void;\n exclude?: string[];\n}) {\n const { workspaceId } = usePlanMagnet();\n const [search, setSearch] = useState('');\n const deferred = useDeferredValue(search.trim());\n const { data, loading } = useQuery<{\n planmagnetDocs: { items: { id: string; title: string }[]; totalCount: number };\n }>(PICKER_DOCS, {\n variables: {\n workspaceId: workspaceId ?? '',\n filter: deferred ? { search: deferred } : undefined,\n },\n skip: !workspaceId,\n });\n const found = data?.planmagnetDocs.items ?? [];\n const docs = found.filter((d) => !exclude.includes(d.id));\n const total = data?.planmagnetDocs.totalCount ?? 0;\n return (\n <div className=\"space-y-1\">\n <Input\n aria-label=\"Search docs\"\n placeholder=\"Search docs by title\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n <select\n id={id}\n className={selectClass}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n >\n <option value=\"\">\n {loading && !data ? 'Searching…' : docs.length ? 'Choose a doc' : 'No match'}\n </option>\n {docs.map((d) => (\n <option key={d.id} value={d.id}>\n {d.title}\n </option>\n ))}\n </select>\n {total > found.length && (\n <p className=\"text-xs text-muted-foreground\">\n Showing {found.length} of {total} — type to narrow the list.\n </p>\n )}\n </div>\n );\n}\n\nconst PICKER_PROGRAMS = gql`\n query PickerPrograms($workspaceId: ID!) {\n planmagnetPrograms(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n }\n totalCount\n }\n }\n`;\n\n/** A program select. '' means \"no program\" when `noneLabel` is given. */\nexport function ProgramSelect({\n id,\n value,\n onChange,\n noneLabel,\n}: {\n id?: string;\n value: string;\n onChange: (programId: string) => void;\n noneLabel?: string;\n}) {\n const { workspaceId } = usePlanMagnet();\n const { data, loading, error } = useQuery<{\n planmagnetPrograms: { items: { id: string; name: string }[]; totalCount: number };\n }>(PICKER_PROGRAMS, { variables: { workspaceId: workspaceId ?? '' }, skip: !workspaceId });\n const programs = data?.planmagnetPrograms.items ?? [];\n return (\n <select\n id={id}\n className={selectClass}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n >\n {noneLabel !== undefined && <option value=\"\">{noneLabel}</option>}\n {programs.length === 0 && noneLabel === undefined && (\n <option value=\"\">\n {loading && !data\n ? 'Loading programs…'\n : error\n ? 'Programs could not be loaded'\n : 'No programs yet'}\n </option>\n )}\n {programs.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n </select>\n );\n}\n\nconst PICKER_PORTFOLIOS = gql`\n query PickerPortfolios($workspaceId: ID!) {\n planmagnetPortfolios(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n }\n totalCount\n }\n }\n`;\n\n/** A portfolio select (BOFF-8047). '' means \"no portfolio\" when `noneLabel` is given. */\nexport function PortfolioSelect({\n id,\n value,\n onChange,\n noneLabel,\n}: {\n id?: string;\n value: string;\n onChange: (portfolioId: string) => void;\n noneLabel?: string;\n}) {\n const { workspaceId } = usePlanMagnet();\n const { data, loading, error } = useQuery<{\n planmagnetPortfolios: { items: { id: string; name: string }[]; totalCount: number };\n }>(PICKER_PORTFOLIOS, { variables: { workspaceId: workspaceId ?? '' }, skip: !workspaceId });\n const portfolios = data?.planmagnetPortfolios.items ?? [];\n return (\n <select\n id={id}\n className={selectClass}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n >\n {noneLabel !== undefined && <option value=\"\">{noneLabel}</option>}\n {portfolios.length === 0 && noneLabel === undefined && (\n <option value=\"\">\n {loading && !data\n ? 'Loading portfolios…'\n : error\n ? 'Portfolios could not be loaded'\n : 'No portfolios yet'}\n </option>\n )}\n {portfolios.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n </select>\n );\n}\n\nconst PICKER_COMPETITORS = gql`\n query PickerCompetitors($workspaceId: ID!, $filter: PlanmagnetCompetitorFilter) {\n planmagnetCompetitors(workspaceId: $workspaceId, filter: $filter, pagination: { first: 20 }) {\n items {\n id\n name\n }\n totalCount\n }\n }\n`;\n\n/** Search, then pick one competitor. `exclude` hides competitors already linked. */\nexport function CompetitorSearchSelect({\n id,\n value,\n onChange,\n exclude = [],\n}: {\n id: string;\n value: string;\n onChange: (competitorId: string) => void;\n exclude?: string[];\n}) {\n const { workspaceId } = usePlanMagnet();\n const [search, setSearch] = useState('');\n const deferred = useDeferredValue(search.trim());\n const { data, loading } = useQuery<{\n planmagnetCompetitors: { items: { id: string; name: string }[]; totalCount: number };\n }>(PICKER_COMPETITORS, {\n variables: {\n workspaceId: workspaceId ?? '',\n filter: deferred ? { search: deferred } : undefined,\n },\n skip: !workspaceId,\n });\n const found = data?.planmagnetCompetitors.items ?? [];\n const competitors = found.filter((c) => !exclude.includes(c.id));\n const total = data?.planmagnetCompetitors.totalCount ?? 0;\n return (\n <div className=\"space-y-1\">\n <Input\n aria-label=\"Search competitors\"\n placeholder=\"Search competitors by name\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n <select\n id={id}\n className={selectClass}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n >\n <option value=\"\">\n {loading && !data\n ? 'Searching…'\n : competitors.length\n ? 'Choose a competitor'\n : 'No match'}\n </option>\n {competitors.map((c) => (\n <option key={c.id} value={c.id}>\n {c.name}\n </option>\n ))}\n </select>\n {total > found.length && (\n <p className=\"text-xs text-muted-foreground\">\n Showing {found.length} of {total} — type to narrow the list.\n </p>\n )}\n </div>\n );\n}\n\nconst PICKER_PRODUCTS = gql`\n query PickerProducts($workspaceId: ID!) {\n planmagnetProducts(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n }\n totalCount\n }\n }\n`;\n\n/** A product select (PRM-27). '' means \"every product\" when `noneLabel` is given. */\nexport function ProductSelect({\n id,\n value,\n onChange,\n noneLabel,\n}: {\n id?: string;\n value: string;\n onChange: (productId: string) => void;\n noneLabel?: string;\n}) {\n const { workspaceId } = usePlanMagnet();\n const { data, loading, error } = useQuery<{\n planmagnetProducts: { items: { id: string; name: string }[]; totalCount: number };\n }>(PICKER_PRODUCTS, { variables: { workspaceId: workspaceId ?? '' }, skip: !workspaceId });\n const products = data?.planmagnetProducts.items ?? [];\n return (\n <select\n id={id}\n className={selectClass}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n >\n {noneLabel !== undefined && <option value=\"\">{noneLabel}</option>}\n {products.length === 0 && noneLabel === undefined && (\n <option value=\"\">\n {loading && !data\n ? 'Loading products…'\n : error\n ? 'Products could not be loaded'\n : 'No products yet'}\n </option>\n )}\n {products.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n </select>\n );\n}\n\nconst PICKER_ROADMAPS = gql`\n query PickerRoadmaps($workspaceId: ID!, $filter: PlanmagnetRoadmapFilter) {\n planmagnetRoadmaps(workspaceId: $workspaceId, filter: $filter, pagination: { first: 100 }) {\n items {\n id\n name\n }\n totalCount\n }\n }\n`;\n\n/**\n * A roadmap select (PRM-27). '' means \"every roadmap\" when `noneLabel` is given. `productId` narrows the list\n * to that product's roadmaps, same filter FeatureInitiativeCard uses for its own roadmap picker.\n */\nexport function RoadmapSelect({\n id,\n value,\n onChange,\n noneLabel,\n productId,\n}: {\n id?: string;\n value: string;\n onChange: (roadmapId: string) => void;\n noneLabel?: string;\n productId?: string;\n}) {\n const { workspaceId } = usePlanMagnet();\n const { data, loading, error } = useQuery<{\n planmagnetRoadmaps: { items: { id: string; name: string }[]; totalCount: number };\n }>(PICKER_ROADMAPS, {\n variables: { workspaceId: workspaceId ?? '', filter: productId ? { productId } : undefined },\n skip: !workspaceId,\n });\n const roadmaps = data?.planmagnetRoadmaps.items ?? [];\n return (\n <select\n id={id}\n className={selectClass}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n >\n {noneLabel !== undefined && <option value=\"\">{noneLabel}</option>}\n {roadmaps.length === 0 && noneLabel === undefined && (\n <option value=\"\">\n {loading && !data\n ? 'Loading roadmaps…'\n : error\n ? 'Roadmaps could not be loaded'\n : 'No roadmaps yet'}\n </option>\n )}\n {roadmaps.map((r) => (\n <option key={r.id} value={r.id}>\n {r.name}\n </option>\n ))}\n </select>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function WorkItemDiscussionPanel({ workItemId, workItemKey, workItemTitle, assigneeId, discussionConversationId, }: {
|
|
2
|
+
workItemId: string;
|
|
3
|
+
workItemKey: string;
|
|
4
|
+
workItemTitle: string;
|
|
5
|
+
assigneeId: string | null;
|
|
6
|
+
discussionConversationId: string | null;
|
|
7
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=WorkItemDiscussionPanel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkItemDiscussionPanel.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/discussion/WorkItemDiscussionPanel.tsx"],"names":[],"mappings":"AA2OA,wBAAgB,uBAAuB,CAAC,EACtC,UAAU,EACV,WAAW,EACX,aAAa,EACb,UAAU,EACV,wBAAwB,GACzB,EAAE;IACD,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,wBAAwB,EAAE,MAAM,GAAG,IAAI,CAAC;CACzC,2CA6DA"}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { usePlanMagnet as e } from "../providers/PlanMagnetProvider.js";
|
|
2
|
+
import { throwOnError as t } from "../utils/mutationResult.js";
|
|
3
|
+
import { ErrorLine as n } from "../controls/ConfirmButton.js";
|
|
4
|
+
import { isForbidden as r, mutationErrorMessage as i } from "../utils/graphqlErrors.js";
|
|
5
|
+
import { useDeferredValue as a, useEffect as o, useState as s } from "react";
|
|
6
|
+
import { ExternalLink as c, MessageCircle as l, MessagesSquare as u, Unlink as d } from "lucide-react";
|
|
7
|
+
import { gql as f } from "@apollo/client";
|
|
8
|
+
import { useMutation as p } from "@apollo/client/react";
|
|
9
|
+
import { jsx as m, jsxs as h } from "react/jsx-runtime";
|
|
10
|
+
import { Button as g, Card as _, CardContent as v, CardHeader as y, CardTitle as b, Checkbox as x, Input as S, ResponsiveDialog as C, ResponsiveDialogContent as w, ResponsiveDialogDescription as T, ResponsiveDialogFooter as E, ResponsiveDialogHeader as D, ResponsiveDialogTitle as O, ResponsiveDialogTrigger as k } from "@burdenoff/fe-libs/ui";
|
|
11
|
+
import { useWorkspaceDirectory as A } from "@burdenoff/fe-libs/sharing";
|
|
12
|
+
//#region src/planmagnet/discussion/WorkItemDiscussionPanel.tsx
|
|
13
|
+
var j = f`
|
|
14
|
+
mutation PlanmagnetSetWorkItemDiscussionLink($workItemId: ID!, $conversationId: ID) {
|
|
15
|
+
planmagnetSetWorkItemDiscussion(workItemId: $workItemId, conversationId: $conversationId) {
|
|
16
|
+
id
|
|
17
|
+
discussionConversationId
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
`, M = f`
|
|
21
|
+
mutation CreateWorkItemDiscussionConversation($input: CreateConversationInput!) {
|
|
22
|
+
createConversation(input: $input) {
|
|
23
|
+
success
|
|
24
|
+
conversation {
|
|
25
|
+
id
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
`, N = {
|
|
30
|
+
refetchQueries: ["GetWorkItemDetail"],
|
|
31
|
+
awaitRefetchQueries: !0
|
|
32
|
+
};
|
|
33
|
+
function P({ workItemId: c, workItemKey: l, workItemTitle: d, assigneeId: f }) {
|
|
34
|
+
let { workspaceId: _, authToken: v, apiGatewayUrl: y, currentUser: b } = e(), [P, F] = s(!1), [I, L] = s(""), R = a(I.trim()), [z, B] = s(/* @__PURE__ */ new Set()), [V, H] = s(null), U = A({
|
|
35
|
+
workspaceId: _ ?? "",
|
|
36
|
+
authToken: v ?? void 0,
|
|
37
|
+
apiGatewayUrl: y ?? void 0
|
|
38
|
+
}), { search: W } = U;
|
|
39
|
+
o(() => {
|
|
40
|
+
W(R);
|
|
41
|
+
}, [R, W]);
|
|
42
|
+
let [G, K] = p(M), [q, J] = p(j, N), Y = K.loading || J.loading, X = (e, t) => B((n) => {
|
|
43
|
+
let r = new Set(n);
|
|
44
|
+
return t ? r.add(e) : r.delete(e), r;
|
|
45
|
+
}), Z = async () => {
|
|
46
|
+
if (_) {
|
|
47
|
+
H(null);
|
|
48
|
+
try {
|
|
49
|
+
let e = await t(G({ variables: { input: {
|
|
50
|
+
workspaceId: _,
|
|
51
|
+
type: "GROUP",
|
|
52
|
+
title: `${l}: ${d}`,
|
|
53
|
+
participantIds: [...z]
|
|
54
|
+
} } })), n = e.data?.createConversation?.conversation?.id;
|
|
55
|
+
if (!e.data?.createConversation?.success || !n) throw Error("The conversation could not be created.");
|
|
56
|
+
await t(q({ variables: {
|
|
57
|
+
workItemId: c,
|
|
58
|
+
conversationId: n
|
|
59
|
+
} })), F(!1), L("");
|
|
60
|
+
} catch (e) {
|
|
61
|
+
H(r(e) ? "Your role cannot start a conversation in this workspace." : i(e, "The discussion could not be started."));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
return /* @__PURE__ */ h(C, {
|
|
66
|
+
open: P,
|
|
67
|
+
onOpenChange: (e) => {
|
|
68
|
+
if (F(e), e) {
|
|
69
|
+
let e = /* @__PURE__ */ new Set();
|
|
70
|
+
f && e.add(f), b?.id && e.add(b.id), B(e);
|
|
71
|
+
} else L(""), H(null);
|
|
72
|
+
},
|
|
73
|
+
children: [/* @__PURE__ */ m(k, {
|
|
74
|
+
asChild: !0,
|
|
75
|
+
children: /* @__PURE__ */ h(g, {
|
|
76
|
+
size: "sm",
|
|
77
|
+
"data-testid": "discussion-start",
|
|
78
|
+
children: [/* @__PURE__ */ m(u, {
|
|
79
|
+
className: "mr-1 h-4 w-4",
|
|
80
|
+
"aria-hidden": "true"
|
|
81
|
+
}), "Discuss in Conversations"]
|
|
82
|
+
})
|
|
83
|
+
}), /* @__PURE__ */ h(w, {
|
|
84
|
+
className: "max-w-lg",
|
|
85
|
+
children: [
|
|
86
|
+
/* @__PURE__ */ h(D, { children: [/* @__PURE__ */ m(O, { children: "Start a discussion" }), /* @__PURE__ */ m(T, { children: "Creates a group conversation for this task and links it back here. Add anyone else who should be in it." })] }),
|
|
87
|
+
/* @__PURE__ */ h("p", {
|
|
88
|
+
className: "text-sm font-medium",
|
|
89
|
+
children: [
|
|
90
|
+
l,
|
|
91
|
+
": ",
|
|
92
|
+
d
|
|
93
|
+
]
|
|
94
|
+
}),
|
|
95
|
+
/* @__PURE__ */ m(S, {
|
|
96
|
+
value: I,
|
|
97
|
+
onChange: (e) => L(e.target.value),
|
|
98
|
+
placeholder: "Search workspace members",
|
|
99
|
+
"aria-label": "Search workspace members"
|
|
100
|
+
}),
|
|
101
|
+
/* @__PURE__ */ h("div", {
|
|
102
|
+
className: "max-h-64 space-y-1 overflow-y-auto",
|
|
103
|
+
children: [
|
|
104
|
+
U.loading && U.members.length === 0 && /* @__PURE__ */ m("p", {
|
|
105
|
+
className: "py-4 text-center text-sm text-muted-foreground",
|
|
106
|
+
children: "Loading…"
|
|
107
|
+
}),
|
|
108
|
+
!U.loading && U.members.length === 0 && /* @__PURE__ */ m("p", {
|
|
109
|
+
className: "py-4 text-center text-sm text-muted-foreground",
|
|
110
|
+
children: "No matching members."
|
|
111
|
+
}),
|
|
112
|
+
U.members.map((e) => {
|
|
113
|
+
let t = `discussion-participant-${e.id}`;
|
|
114
|
+
return /* @__PURE__ */ h("label", {
|
|
115
|
+
htmlFor: t,
|
|
116
|
+
className: "flex cursor-pointer items-center gap-3 rounded-md border p-2 text-sm hover:bg-muted",
|
|
117
|
+
children: [/* @__PURE__ */ m(x, {
|
|
118
|
+
id: t,
|
|
119
|
+
checked: z.has(e.id),
|
|
120
|
+
onCheckedChange: (t) => X(e.id, t === !0)
|
|
121
|
+
}), /* @__PURE__ */ h("span", {
|
|
122
|
+
className: "min-w-0 flex-1 truncate",
|
|
123
|
+
children: [
|
|
124
|
+
e.name,
|
|
125
|
+
e.id === b?.id && /* @__PURE__ */ m("span", {
|
|
126
|
+
className: "text-muted-foreground",
|
|
127
|
+
children: " (you)"
|
|
128
|
+
}),
|
|
129
|
+
e.id === f && /* @__PURE__ */ m("span", {
|
|
130
|
+
className: "text-muted-foreground",
|
|
131
|
+
children: " · assignee"
|
|
132
|
+
})
|
|
133
|
+
]
|
|
134
|
+
})]
|
|
135
|
+
}, e.id);
|
|
136
|
+
}),
|
|
137
|
+
U.hasMore && /* @__PURE__ */ m("button", {
|
|
138
|
+
type: "button",
|
|
139
|
+
className: "w-full py-1 text-xs text-primary hover:underline",
|
|
140
|
+
onClick: U.fetchMore,
|
|
141
|
+
children: "Show more members"
|
|
142
|
+
})
|
|
143
|
+
]
|
|
144
|
+
}),
|
|
145
|
+
V && /* @__PURE__ */ m(n, { message: V }),
|
|
146
|
+
/* @__PURE__ */ m(E, { children: /* @__PURE__ */ m(g, {
|
|
147
|
+
onClick: () => void Z(),
|
|
148
|
+
disabled: z.size === 0 || Y,
|
|
149
|
+
"data-testid": "discussion-create-confirm",
|
|
150
|
+
children: Y ? "Starting…" : `Start discussion (${z.size})`
|
|
151
|
+
}) })
|
|
152
|
+
]
|
|
153
|
+
})]
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
function F({ workItemId: e, workItemKey: r, workItemTitle: a, assigneeId: o, discussionConversationId: u }) {
|
|
157
|
+
let [f, x] = p(j, N), [S, C] = s(null), w = async () => {
|
|
158
|
+
C(null);
|
|
159
|
+
try {
|
|
160
|
+
await t(f({ variables: {
|
|
161
|
+
workItemId: e,
|
|
162
|
+
conversationId: null
|
|
163
|
+
} }));
|
|
164
|
+
} catch (e) {
|
|
165
|
+
C(i(e, "The discussion could not be unlinked."));
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
return /* @__PURE__ */ h(_, {
|
|
169
|
+
"data-testid": "work-item-discussion",
|
|
170
|
+
children: [/* @__PURE__ */ m(y, { children: /* @__PURE__ */ h(b, {
|
|
171
|
+
className: "flex items-center gap-2",
|
|
172
|
+
children: [/* @__PURE__ */ m(l, {
|
|
173
|
+
className: "h-4 w-4",
|
|
174
|
+
"aria-hidden": "true"
|
|
175
|
+
}), "Discussion"]
|
|
176
|
+
}) }), /* @__PURE__ */ h(v, {
|
|
177
|
+
className: "space-y-3",
|
|
178
|
+
children: [S && /* @__PURE__ */ m(n, { message: S }), u ? /* @__PURE__ */ h("div", {
|
|
179
|
+
className: "flex flex-wrap items-center justify-between gap-2",
|
|
180
|
+
children: [/* @__PURE__ */ h("a", {
|
|
181
|
+
href: `/conversations/${encodeURIComponent(u)}`,
|
|
182
|
+
className: "inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline",
|
|
183
|
+
"data-testid": "discussion-open",
|
|
184
|
+
children: ["Open discussion", /* @__PURE__ */ m(c, {
|
|
185
|
+
className: "h-3.5 w-3.5",
|
|
186
|
+
"aria-hidden": "true"
|
|
187
|
+
})]
|
|
188
|
+
}), /* @__PURE__ */ h(g, {
|
|
189
|
+
size: "sm",
|
|
190
|
+
variant: "ghost",
|
|
191
|
+
disabled: x.loading,
|
|
192
|
+
onClick: () => void w(),
|
|
193
|
+
"data-testid": "discussion-unlink",
|
|
194
|
+
children: [/* @__PURE__ */ m(d, {
|
|
195
|
+
className: "mr-1 h-3.5 w-3.5",
|
|
196
|
+
"aria-hidden": "true"
|
|
197
|
+
}), "Unlink"]
|
|
198
|
+
})]
|
|
199
|
+
}) : /* @__PURE__ */ h("div", {
|
|
200
|
+
className: "space-y-2",
|
|
201
|
+
children: [/* @__PURE__ */ m("p", {
|
|
202
|
+
className: "text-sm text-muted-foreground",
|
|
203
|
+
children: "Not linked to a conversation yet. Starting one creates a group chat for this task in Conversations."
|
|
204
|
+
}), /* @__PURE__ */ m(P, {
|
|
205
|
+
workItemId: e,
|
|
206
|
+
workItemKey: r,
|
|
207
|
+
workItemTitle: a,
|
|
208
|
+
assigneeId: o
|
|
209
|
+
})]
|
|
210
|
+
})]
|
|
211
|
+
})]
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
//#endregion
|
|
215
|
+
export { F as WorkItemDiscussionPanel };
|
|
216
|
+
|
|
217
|
+
//# sourceMappingURL=WorkItemDiscussionPanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkItemDiscussionPanel.js","names":[],"sources":["../../../src/planmagnet/discussion/WorkItemDiscussionPanel.tsx"],"sourcesContent":["import { useDeferredValue, useEffect, useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation } from '@apollo/client/react';\nimport {\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Checkbox,\n Input,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogTrigger,\n} from '@burdenoff/fe-libs/ui';\nimport { useWorkspaceDirectory } from '@burdenoff/fe-libs/sharing';\nimport { ExternalLink, MessageCircle, MessagesSquare, Unlink as UnlinkIcon } from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\nimport { ErrorLine } from '../controls/ConfirmButton';\nimport { throwOnError } from '../utils/mutationResult';\nimport { isForbidden, mutationErrorMessage } from '../utils/graphqlErrors';\n\n/**\n * Discussion on a task (CWF-26): a link to a real group conversation in the platform Conversations product, not\n * a comment thread of its own. `WorkItem.discussionConversationId` only stores and validates the id — the\n * conversation itself is created HERE, as the signed-in user, through the Conversations subgraph's own\n * `createConversation` (a different subgraph than everything else on this page; see its schema doc comment).\n * Once created, `planmagnetSetWorkItemDiscussion` links it back to this item.\n *\n * \"Open discussion\" is a plain `<a>`, not this MFE's own `usePlanMagnetNavigate()` — that hook prepends THIS\n * microfrontend's basePath, and `/conversations/<id>` is a sibling app's own top-level route, not a planmagnet\n * page (there is, correctly, no such route in `PlanMagnetRoutes.tsx`).\n */\n\nconst SET_DISCUSSION = gql`\n mutation PlanmagnetSetWorkItemDiscussionLink($workItemId: ID!, $conversationId: ID) {\n planmagnetSetWorkItemDiscussion(workItemId: $workItemId, conversationId: $conversationId) {\n id\n discussionConversationId\n }\n }\n`;\n\nconst CREATE_DISCUSSION_CONVERSATION = gql`\n mutation CreateWorkItemDiscussionConversation($input: CreateConversationInput!) {\n createConversation(input: $input) {\n success\n conversation {\n id\n }\n }\n }\n`;\n\nconst DISCUSSION_REFETCH = { refetchQueries: ['GetWorkItemDetail'], awaitRefetchQueries: true };\n\n/** Create a group conversation for this task and link it — participants default to the assignee + the current\n * user, editable through the same search-then-checkbox workspace directory picker\n * `roadmaps/RoadmapReviewPanel.tsx`'s `RequestReviewDialog` uses for reviewers. */\nfunction StartDiscussionDialog({\n workItemId,\n workItemKey,\n workItemTitle,\n assigneeId,\n}: {\n workItemId: string;\n workItemKey: string;\n workItemTitle: string;\n assigneeId: string | null;\n}) {\n const { workspaceId, authToken, apiGatewayUrl, currentUser } = usePlanMagnet();\n const [open, setOpen] = useState(false);\n const [search, setSearch] = useState('');\n const deferredSearch = useDeferredValue(search.trim());\n const [selected, setSelected] = useState<Set<string>>(new Set());\n const [error, setError] = useState<string | null>(null);\n\n const directory = useWorkspaceDirectory({\n workspaceId: workspaceId ?? '',\n authToken: authToken ?? undefined,\n apiGatewayUrl: apiGatewayUrl ?? undefined,\n });\n const { search: setDirectoryFilter } = directory;\n useEffect(() => {\n setDirectoryFilter(deferredSearch);\n }, [deferredSearch, setDirectoryFilter]);\n\n const [createConversation, createState] = useMutation<{\n createConversation: { success: boolean; conversation: { id: string } | null };\n }>(CREATE_DISCUSSION_CONVERSATION);\n const [setDiscussion, setDiscussionState] = useMutation(SET_DISCUSSION, DISCUSSION_REFETCH);\n const busy = createState.loading || setDiscussionState.loading;\n\n const toggle = (id: string, checked: boolean) =>\n setSelected((prev) => {\n const next = new Set(prev);\n if (checked) next.add(id);\n else next.delete(id);\n return next;\n });\n\n const submit = async () => {\n if (!workspaceId) return;\n setError(null);\n try {\n const created = await throwOnError(\n createConversation({\n variables: {\n input: {\n workspaceId,\n type: 'GROUP',\n title: `${workItemKey}: ${workItemTitle}`,\n participantIds: [...selected],\n },\n },\n })\n );\n const conversationId = created.data?.createConversation?.conversation?.id;\n if (!created.data?.createConversation?.success || !conversationId) {\n throw new Error('The conversation could not be created.');\n }\n await throwOnError(setDiscussion({ variables: { workItemId, conversationId } }));\n setOpen(false);\n setSearch('');\n } catch (e) {\n setError(\n isForbidden(e)\n ? 'Your role cannot start a conversation in this workspace.'\n : mutationErrorMessage(e, 'The discussion could not be started.')\n );\n }\n };\n\n return (\n <ResponsiveDialog\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (next) {\n // Default selection (assignee + self), recomputed on every open so an earlier session's manual picks\n // never leak into a later one.\n const defaults = new Set<string>();\n if (assigneeId) defaults.add(assigneeId);\n if (currentUser?.id) defaults.add(currentUser.id);\n setSelected(defaults);\n } else {\n setSearch('');\n setError(null);\n }\n }}\n >\n <ResponsiveDialogTrigger asChild>\n <Button size=\"sm\" data-testid=\"discussion-start\">\n <MessagesSquare className=\"mr-1 h-4 w-4\" aria-hidden=\"true\" />\n Discuss in Conversations\n </Button>\n </ResponsiveDialogTrigger>\n <ResponsiveDialogContent className=\"max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Start a discussion</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Creates a group conversation for this task and links it back here. Add anyone else who\n should be in it.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <p className=\"text-sm font-medium\">\n {workItemKey}: {workItemTitle}\n </p>\n <Input\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder=\"Search workspace members\"\n aria-label=\"Search workspace members\"\n />\n <div className=\"max-h-64 space-y-1 overflow-y-auto\">\n {directory.loading && directory.members.length === 0 && (\n <p className=\"py-4 text-center text-sm text-muted-foreground\">Loading…</p>\n )}\n {!directory.loading && directory.members.length === 0 && (\n <p className=\"py-4 text-center text-sm text-muted-foreground\">No matching members.</p>\n )}\n {directory.members.map((member) => {\n const inputId = `discussion-participant-${member.id}`;\n return (\n <label\n key={member.id}\n htmlFor={inputId}\n className=\"flex cursor-pointer items-center gap-3 rounded-md border p-2 text-sm hover:bg-muted\"\n >\n <Checkbox\n id={inputId}\n checked={selected.has(member.id)}\n onCheckedChange={(checked) => toggle(member.id, checked === true)}\n />\n <span className=\"min-w-0 flex-1 truncate\">\n {member.name}\n {member.id === currentUser?.id && (\n <span className=\"text-muted-foreground\"> (you)</span>\n )}\n {member.id === assigneeId && (\n <span className=\"text-muted-foreground\"> · assignee</span>\n )}\n </span>\n </label>\n );\n })}\n {directory.hasMore && (\n <button\n type=\"button\"\n className=\"w-full py-1 text-xs text-primary hover:underline\"\n onClick={directory.fetchMore}\n >\n Show more members\n </button>\n )}\n </div>\n {error && <ErrorLine message={error} />}\n <ResponsiveDialogFooter>\n <Button\n onClick={() => void submit()}\n disabled={selected.size === 0 || busy}\n data-testid=\"discussion-create-confirm\"\n >\n {busy ? 'Starting…' : `Start discussion (${selected.size})`}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\nexport function WorkItemDiscussionPanel({\n workItemId,\n workItemKey,\n workItemTitle,\n assigneeId,\n discussionConversationId,\n}: {\n workItemId: string;\n workItemKey: string;\n workItemTitle: string;\n assigneeId: string | null;\n discussionConversationId: string | null;\n}) {\n const [unlink, unlinkState] = useMutation(SET_DISCUSSION, DISCUSSION_REFETCH);\n const [error, setError] = useState<string | null>(null);\n\n const doUnlink = async () => {\n setError(null);\n try {\n await throwOnError(unlink({ variables: { workItemId, conversationId: null } }));\n } catch (e) {\n setError(mutationErrorMessage(e, 'The discussion could not be unlinked.'));\n }\n };\n\n return (\n <Card data-testid=\"work-item-discussion\">\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <MessageCircle className=\"h-4 w-4\" aria-hidden=\"true\" />\n Discussion\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {error && <ErrorLine message={error} />}\n {discussionConversationId ? (\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <a\n href={`/conversations/${encodeURIComponent(discussionConversationId)}`}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline\"\n data-testid=\"discussion-open\"\n >\n Open discussion\n <ExternalLink className=\"h-3.5 w-3.5\" aria-hidden=\"true\" />\n </a>\n <Button\n size=\"sm\"\n variant=\"ghost\"\n disabled={unlinkState.loading}\n onClick={() => void doUnlink()}\n data-testid=\"discussion-unlink\"\n >\n <UnlinkIcon className=\"mr-1 h-3.5 w-3.5\" aria-hidden=\"true\" />\n Unlink\n </Button>\n </div>\n ) : (\n <div className=\"space-y-2\">\n <p className=\"text-sm text-muted-foreground\">\n Not linked to a conversation yet. Starting one creates a group chat for this task in\n Conversations.\n </p>\n <StartDiscussionDialog\n workItemId={workItemId}\n workItemKey={workItemKey}\n workItemTitle={workItemTitle}\n assigneeId={assigneeId}\n />\n </div>\n )}\n </CardContent>\n </Card>\n );\n}\n"],"mappings":"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"}
|