synapse-react-client 4.0.9 → 4.0.10

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.
Files changed (543) hide show
  1. package/dist/SWC.index.d.ts +1 -0
  2. package/dist/SWC.index.d.ts.map +1 -1
  3. package/dist/SWC.index.js +2 -1
  4. package/dist/SWC.index.js.map +1 -1
  5. package/dist/aridhia-queries/aridhiaTokenExchange.js.map +1 -1
  6. package/dist/aridhia-queries/useGetAridhiaRequests.js.map +1 -1
  7. package/dist/assets/icons/TasksIcon.d.ts.map +1 -1
  8. package/dist/assets/icons/TasksIcon.js +6 -10
  9. package/dist/assets/icons/TasksIcon.js.map +1 -1
  10. package/dist/components/AccessRequirementAclEditor/AccessRequirementAclEditor.d.ts.map +1 -1
  11. package/dist/components/AccessRequirementAclEditor/AccessRequirementAclEditor.js +69 -63
  12. package/dist/components/AccessRequirementAclEditor/AccessRequirementAclEditor.js.map +1 -1
  13. package/dist/components/AccessRequirementList/AccessApprovalCheckMark.js.map +1 -1
  14. package/dist/components/AccessRequirementList/AccessRequirementList.js.map +1 -1
  15. package/dist/components/AccessRequirementList/AccessRequirementListUtils.js.map +1 -1
  16. package/dist/components/AccessRequirementList/ManagedACTAccessRequirementRequestFlow/DataAccessRequestAccessorsEditor.js.map +1 -1
  17. package/dist/components/AccessRequirementList/RequirementItem/SelfSignAccessRequirementItem.js.map +1 -1
  18. package/dist/components/AccessRequirementRelatedProjectsList/AccessRequirementRelatedProjectsList.js.map +1 -1
  19. package/dist/components/AccessTokenPage/AccessTokenCard/AccessTokenCard.js.map +1 -1
  20. package/dist/components/AcknowledgementsPage/StudyAcknowledgements.js.map +1 -1
  21. package/dist/components/AclEditor/PermissionLevelMenu.js.map +1 -1
  22. package/dist/components/AclEditor/ResourceAccessAndUserGroupHeader.js.map +1 -1
  23. package/dist/components/AclEditor/useSortResourceAccessList.js.map +1 -1
  24. package/dist/components/AclEditor/useUpdateAcl.js.map +1 -1
  25. package/dist/components/Aridhia/AridhiaAccessStatus.js.map +1 -1
  26. package/dist/components/Authentication/AuthenticationMethodSelection.d.ts.map +1 -1
  27. package/dist/components/Authentication/AuthenticationMethodSelection.js +38 -37
  28. package/dist/components/Authentication/AuthenticationMethodSelection.js.map +1 -1
  29. package/dist/components/Authentication/Constants.d.ts +1 -0
  30. package/dist/components/Authentication/Constants.d.ts.map +1 -1
  31. package/dist/components/Authentication/Constants.js +2 -2
  32. package/dist/components/Authentication/Constants.js.map +1 -1
  33. package/dist/components/Authentication/LastLoginInfo.js.map +1 -1
  34. package/dist/components/Authentication/RecoveryCodeForm.js.map +1 -1
  35. package/dist/components/Authentication/RecoveryCodeGrid.js.map +1 -1
  36. package/dist/components/Authentication/RegenerateBackupCodesWarning.js.map +1 -1
  37. package/dist/components/Authentication/Reset2FAWarning.js.map +1 -1
  38. package/dist/components/Authentication/StandaloneLoginForm.js +1 -1
  39. package/dist/components/Authentication/TwoFactorBackupCodes.js.map +1 -1
  40. package/dist/components/Authentication/TwoFactorEnrollmentForm.d.ts.map +1 -1
  41. package/dist/components/Authentication/TwoFactorEnrollmentForm.js +2 -1
  42. package/dist/components/Authentication/TwoFactorEnrollmentForm.js.map +1 -1
  43. package/dist/components/BasePortalCard/ColorfulPortalCardWithChips/ColorfulPortalCardWithChips.js.map +1 -1
  44. package/dist/components/CardContainer/CardContainer.js.map +1 -1
  45. package/dist/components/CardDeck/CardDeck.Mobile.js.map +1 -1
  46. package/dist/components/CardDeck/TableQueryCardDeck.js.map +1 -1
  47. package/dist/components/CertificationQuiz/CertificationQuiz.js.map +1 -1
  48. package/dist/components/ChallengeDataDownload/ChallengeDataDownload.js.map +1 -1
  49. package/dist/components/ChallengeSubmission/ChallengeSubmission.js.map +1 -1
  50. package/dist/components/ChallengeSubmission/ChallengeSubmissionStepper.js.map +1 -1
  51. package/dist/components/ChallengeSubmission/EvaluationQueueCurrentRoundInfo.js.map +1 -1
  52. package/dist/components/ChallengeSubmission/EvaluationQueueList.js.map +1 -1
  53. package/dist/components/ChallengeSubmission/SubmissionDirectoryList.js.map +1 -1
  54. package/dist/components/ChallengeTeamWizard/ChallengeTeamWizard.js.map +1 -1
  55. package/dist/components/ChallengeTeamWizard/CreateChallengeTeam.js.map +1 -1
  56. package/dist/components/ChangePassword/ChangePassword.js.map +1 -1
  57. package/dist/components/ChangePassword/ChangePasswordWithToken.js.map +1 -1
  58. package/dist/components/ChangePassword/useChangePasswordFormState.js +1 -1
  59. package/dist/components/ChangePassword/useChangePasswordFormState.js.map +1 -1
  60. package/dist/components/CitationPopover/CitationPopoverContent.js.map +1 -1
  61. package/dist/components/ColumnFilter/ColumnFilter.js.map +1 -1
  62. package/dist/components/ComponentCollapse.js.map +1 -1
  63. package/dist/components/CookiesNotification/CookiesNotification.js.map +1 -1
  64. package/dist/components/CreateProjectModal/CreateProjectModal.js.map +1 -1
  65. package/dist/components/CreateTableViewWizard/CreateTableViewWizardUtils.js.map +1 -1
  66. package/dist/components/DataGrid/DataGrid.d.ts +0 -1
  67. package/dist/components/DataGrid/DataGrid.d.ts.map +1 -1
  68. package/dist/components/DataGrid/DataGrid.js +72 -72
  69. package/dist/components/DataGrid/DataGrid.js.map +1 -1
  70. package/dist/components/DataGrid/DataGridWebSocket.d.ts +4 -0
  71. package/dist/components/DataGrid/DataGridWebSocket.d.ts.map +1 -1
  72. package/dist/components/DataGrid/DataGridWebSocket.js +9 -8
  73. package/dist/components/DataGrid/DataGridWebSocket.js.map +1 -1
  74. package/dist/components/DataGrid/SynapseGrid.d.ts.map +1 -1
  75. package/dist/components/DataGrid/SynapseGrid.js +326 -268
  76. package/dist/components/DataGrid/SynapseGrid.js.map +1 -1
  77. package/dist/components/DataGrid/columns/AutocompleteColumn.d.ts +2 -0
  78. package/dist/components/DataGrid/columns/AutocompleteColumn.d.ts.map +1 -1
  79. package/dist/components/DataGrid/columns/AutocompleteColumn.js +113 -67
  80. package/dist/components/DataGrid/columns/AutocompleteColumn.js.map +1 -1
  81. package/dist/components/DataGrid/columns/AutocompleteMultipleEnumColumn.d.ts +2 -1
  82. package/dist/components/DataGrid/columns/AutocompleteMultipleEnumColumn.d.ts.map +1 -1
  83. package/dist/components/DataGrid/columns/AutocompleteMultipleEnumColumn.js +126 -122
  84. package/dist/components/DataGrid/columns/AutocompleteMultipleEnumColumn.js.map +1 -1
  85. package/dist/components/DataGrid/columns/useGridAutocompleteState.d.ts +58 -0
  86. package/dist/components/DataGrid/columns/useGridAutocompleteState.d.ts.map +1 -0
  87. package/dist/components/DataGrid/columns/useGridAutocompleteState.js +52 -0
  88. package/dist/components/DataGrid/columns/useGridAutocompleteState.js.map +1 -0
  89. package/dist/components/DataGrid/components/ValidationAlert.d.ts +5 -2
  90. package/dist/components/DataGrid/components/ValidationAlert.d.ts.map +1 -1
  91. package/dist/components/DataGrid/components/ValidationAlert.js +429 -24
  92. package/dist/components/DataGrid/components/ValidationAlert.js.map +1 -1
  93. package/dist/components/DataGrid/hooks/useColumnResizeHandles.js.map +1 -1
  94. package/dist/components/DataGrid/hooks/useGetSchemaForGrid.js.map +1 -1
  95. package/dist/components/DataGrid/hooks/useGridUndoRedo.js.map +1 -1
  96. package/dist/components/DataGrid/hooks/useStack.js.map +1 -1
  97. package/dist/components/DataGrid/useCRDTModelView.js.map +1 -1
  98. package/dist/components/DataGrid/useDataGridWebsocket.d.ts +7 -0
  99. package/dist/components/DataGrid/useDataGridWebsocket.d.ts.map +1 -1
  100. package/dist/components/DataGrid/useDataGridWebsocket.js +16 -2
  101. package/dist/components/DataGrid/useDataGridWebsocket.js.map +1 -1
  102. package/dist/components/DataGrid/useInitializeGridConnection.js.map +1 -1
  103. package/dist/components/DataGrid/useMergeGridWithRecordSet.js.map +1 -1
  104. package/dist/components/DataGrid/useMergeGridWithSource.js.map +1 -1
  105. package/dist/components/DataGrid/useMergeGridWithTable.js.map +1 -1
  106. package/dist/components/DataGrid/utils/DataGridUtils.js.map +1 -1
  107. package/dist/components/DataGrid/utils/applyModelChange.js.map +1 -1
  108. package/dist/components/DataGrid/utils/columnFactory.js.map +1 -1
  109. package/dist/components/DataGrid/utils/computeReplicaSelectionModel.js.map +1 -1
  110. package/dist/components/DataGrid/utils/extractColumnValidationMessages.js.map +1 -1
  111. package/dist/components/DataGrid/utils/getCellClassName.d.ts.map +1 -1
  112. package/dist/components/DataGrid/utils/getCellClassName.js +8 -8
  113. package/dist/components/DataGrid/utils/getCellClassName.js.map +1 -1
  114. package/dist/components/DataGrid/utils/json-rx/JsonRx.js.map +1 -1
  115. package/dist/components/DataGrid/utils/modelRowsToGrid.js.map +1 -1
  116. package/dist/components/DataGrid/utils/parseFreeTextUsingJsonSchemaType.js.map +1 -1
  117. package/dist/components/DataGrid/utils/splitPatch.js.map +1 -1
  118. package/dist/components/DateTimePicker/DateTimePicker.js.map +1 -1
  119. package/dist/components/DirectDownload/DirectDownload.js.map +1 -1
  120. package/dist/components/DirectDownloadButton.js.map +1 -1
  121. package/dist/components/DownloadCart/CreatePackageV2.js.map +1 -1
  122. package/dist/components/DownloadCart/DownloadIneligibleForPackagingFilesFromListButton.js.map +1 -1
  123. package/dist/components/DownloadCart/DownloadListActionsRequired.js.map +1 -1
  124. package/dist/components/DownloadCart/DownloadListTable.js.map +1 -1
  125. package/dist/components/DownloadCart/fileNameUtils.js.map +1 -1
  126. package/dist/components/DraggableDialog/DraggableDialog.js.map +1 -1
  127. package/dist/components/DynamicForm/DynamicFormModal.js.map +1 -1
  128. package/dist/components/Ecosystem/TableQueryEcosystem.js.map +1 -1
  129. package/dist/components/EntityAclEditor/EntityAclEditor.d.ts.map +1 -1
  130. package/dist/components/EntityAclEditor/EntityAclEditor.js +103 -103
  131. package/dist/components/EntityAclEditor/EntityAclEditor.js.map +1 -1
  132. package/dist/components/EntityAclEditor/useNotifyNewACLUsers.js.map +1 -1
  133. package/dist/components/EntityBadgeIcons/EntityBadgeIcons.js.map +1 -1
  134. package/dist/components/EntityCitation/EntityCitation.js.map +1 -1
  135. package/dist/components/EntityDownloadButton/EntityDownloadButton.js.map +1 -1
  136. package/dist/components/EntityDownloadConfirmation/EntityDownloadConfirmation.d.ts.map +1 -1
  137. package/dist/components/EntityDownloadConfirmation/EntityDownloadConfirmation.js +36 -30
  138. package/dist/components/EntityDownloadConfirmation/EntityDownloadConfirmation.js.map +1 -1
  139. package/dist/components/EntityFinder/EntityFinder.js.map +1 -1
  140. package/dist/components/EntityFinder/VersionSelectionType.js.map +1 -1
  141. package/dist/components/EntityFinder/details/configurations/EntityChildrenDetails.js.map +1 -1
  142. package/dist/components/EntityFinder/details/configurations/FavoritesDetails.js.map +1 -1
  143. package/dist/components/EntityFinder/details/configurations/ProjectListDetails.js.map +1 -1
  144. package/dist/components/EntityFinder/details/view/DetailsView.js.map +1 -1
  145. package/dist/components/EntityFinder/tree/EntityTree.js.map +1 -1
  146. package/dist/components/EntityFinder/tree/VirtualizedTree.js.map +1 -1
  147. package/dist/components/EntityFinder/useEntitySelection.js.map +1 -1
  148. package/dist/components/EntityForm/EntityForm.js.map +1 -1
  149. package/dist/components/EntityHeaderTable/EntityHeaderTable.js.map +1 -1
  150. package/dist/components/EntityHeaderTable/Filter.js.map +1 -1
  151. package/dist/components/EntityHeaderTable/useEntityHeaderTableState.js.map +1 -1
  152. package/dist/components/EntitySubjectsSelector/EntitySubjectsSelector.js.map +1 -1
  153. package/dist/components/EntityTreeTable/components/IdColumnHeader.js.map +1 -1
  154. package/dist/components/EntityTreeTable/hooks/useEntityTreeState.js.map +1 -1
  155. package/dist/components/EntityTreeTable/hooks/useTableColumns.js.map +1 -1
  156. package/dist/components/EntityTreeTable/hooks/useTableData.js.map +1 -1
  157. package/dist/components/EntityTreeTable/hooks/useTreeOperationsWithDirectFetch.js.map +1 -1
  158. package/dist/components/EntityUpload/EntityUpload.js.map +1 -1
  159. package/dist/components/ExperimentalMode/ExperimentalMode.js.map +1 -1
  160. package/dist/components/ExternalFileHandleLink/ExternalFileHandleLink.js.map +1 -1
  161. package/dist/components/FeaturedDataTabs/FacetPlotsCard.js.map +1 -1
  162. package/dist/components/FeaturedDataTabs/QueryPerFacetPlotsCard.js.map +1 -1
  163. package/dist/components/FeaturedDataTabs/SingleQueryFacetPlotsCards.js.map +1 -1
  164. package/dist/components/FeaturedResearch/FeaturedResearch.js.map +1 -1
  165. package/dist/components/FeaturedToolsList/FeaturedToolsList.js.map +1 -1
  166. package/dist/components/FilePreview/FileHandleContentRenderer.js.map +1 -1
  167. package/dist/components/FilePreview/HtmlPreview/HtmlPreview.js.map +1 -1
  168. package/dist/components/FilePreview/PreviewRendererType.js.map +1 -1
  169. package/dist/components/Forum/DiscussionReply.js.map +1 -1
  170. package/dist/components/Forum/DiscussionSearchResult.js.map +1 -1
  171. package/dist/components/Forum/ForumTable.js.map +1 -1
  172. package/dist/components/Forum/ForumThreadEditor.js.map +1 -1
  173. package/dist/components/FullTextSearch/FullTextSearchUtils.js.map +1 -1
  174. package/dist/components/GenericCard/GenericCard.d.ts.map +1 -1
  175. package/dist/components/GenericCard/GenericCard.js +12 -7
  176. package/dist/components/GenericCard/GenericCard.js.map +1 -1
  177. package/dist/components/GenericCard/Linkify.js.map +1 -1
  178. package/dist/components/GenericCard/SynapseCardLabel.js.map +1 -1
  179. package/dist/components/GenericCard/TableRowGenericCard.js +105 -105
  180. package/dist/components/GenericCard/TableRowGenericCard.js.map +1 -1
  181. package/dist/components/Goals/Goals.Mobile.js.map +1 -1
  182. package/dist/components/Goals/Goals.js.map +1 -1
  183. package/dist/components/GoalsV2/GoalsV2.Mobile.js.map +1 -1
  184. package/dist/components/GoalsV2/GoalsV2.js.map +1 -1
  185. package/dist/components/GoalsV3/GoalsV3.Mobile.js.map +1 -1
  186. package/dist/components/GoalsV3/GoalsV3.js.map +1 -1
  187. package/dist/components/GoogleMap/SynapseUserMarker.js.map +1 -1
  188. package/dist/components/HasAccess/AccessIcon.js.map +1 -1
  189. package/dist/components/HasAccess/useHasAccess.js.map +1 -1
  190. package/dist/components/HeaderCard/HeaderCardV2.js.map +1 -1
  191. package/dist/components/HeaderCard.d.ts +6 -1
  192. package/dist/components/HeaderCard.d.ts.map +1 -1
  193. package/dist/components/HeaderCard.js +107 -76
  194. package/dist/components/HeaderCard.js.map +1 -1
  195. package/dist/components/HexGrid/HexGrid.js.map +1 -1
  196. package/dist/components/IconList.js.map +1 -1
  197. package/dist/components/ImageCardGridWithLinks/ImageCardGridWithLinks.js.map +1 -1
  198. package/dist/components/ImageFromSynapseTable.js.map +1 -1
  199. package/dist/components/JSONArrayEditor/useParseCsv.js.map +1 -1
  200. package/dist/components/JsonSchemaForm/templates/ArrayFieldDescriptionTemplate.js.map +1 -1
  201. package/dist/components/JsonSchemaForm/templates/ArrayFieldItemTemplate.js.map +1 -1
  202. package/dist/components/JsonSchemaForm/templates/BaseInputTemplate.js.map +1 -1
  203. package/dist/components/JsonSchemaForm/templates/FieldTemplate.js.map +1 -1
  204. package/dist/components/JsonSchemaForm/templates/RJSFInputLabel.js.map +1 -1
  205. package/dist/components/Markdown/MarkdownGithub.js.map +1 -1
  206. package/dist/components/Markdown/MarkdownSynapse.js.map +1 -1
  207. package/dist/components/Markdown/MarkdownUtils.js.map +1 -1
  208. package/dist/components/Markdown/SynapseWikiContext.js.map +1 -1
  209. package/dist/components/Markdown/UserMentionModal.js.map +1 -1
  210. package/dist/components/Markdown/widget/MarkdownProvenanceGraph.js.map +1 -1
  211. package/dist/components/MissingQueryResultsWarning/MissingQueryResultsWarning.js.map +1 -1
  212. package/dist/components/ModalDownload/ModalDownload.js.map +1 -1
  213. package/dist/components/OAuthClientAclEditor/OAuthClientAclEditor.d.ts.map +1 -1
  214. package/dist/components/OAuthClientAclEditor/OAuthClientAclEditor.js +45 -39
  215. package/dist/components/OAuthClientAclEditor/OAuthClientAclEditor.js.map +1 -1
  216. package/dist/components/OAuthClientManagement/OAuthManagement.js.map +1 -1
  217. package/dist/components/PageProgress/PageProgress.js.map +1 -1
  218. package/dist/components/Plot/DotPlot.js.map +1 -1
  219. package/dist/components/Plot/Plot.js.map +1 -1
  220. package/dist/components/Plot/SynapsePlot.js.map +1 -1
  221. package/dist/components/Plot/ThemesPlot.js.map +1 -1
  222. package/dist/components/Plot/UpsetPlot.js.map +1 -1
  223. package/dist/components/PortalAclEditor/PortalAclEditor.d.ts.map +1 -1
  224. package/dist/components/PortalAclEditor/PortalAclEditor.js +43 -41
  225. package/dist/components/PortalAclEditor/PortalAclEditor.js.map +1 -1
  226. package/dist/components/PortalFeaturedPartners/PortalFeaturedPartners.js.map +1 -1
  227. package/dist/components/PortalList/CreatePortalModal.js.map +1 -1
  228. package/dist/components/ProgrammaticInstructionsModal/ProgrammaticInstructionsModal.js.map +1 -1
  229. package/dist/components/ProgrammaticTableDownload/ProgrammaticTableDownload.js.map +1 -1
  230. package/dist/components/Programs/Programs.Mobile.js.map +1 -1
  231. package/dist/components/Programs/Programs.js.map +1 -1
  232. package/dist/components/ProvenanceGraph/ProvenanceExternalIcon.js.map +1 -1
  233. package/dist/components/ProvenanceGraph/ProvenanceGraph.js.map +1 -1
  234. package/dist/components/ProvenanceGraph/ProvenanceGraphUtils.js.map +1 -1
  235. package/dist/components/ProvenanceGraph/ProvenanceUtils.js.map +1 -1
  236. package/dist/components/QueryCount/QueryCount.js.map +1 -1
  237. package/dist/components/QueryCountButton/QueryCountButton.js.map +1 -1
  238. package/dist/components/QueryVisualizationWrapper/QueryVisualizationWrapper.js.map +1 -1
  239. package/dist/components/QueryWrapper/QueryWrapper.js.map +1 -1
  240. package/dist/components/QueryWrapper/TableQueryUseQueryOptions.js.map +1 -1
  241. package/dist/components/QueryWrapper/TableRowSelectionState.js.map +1 -1
  242. package/dist/components/QueryWrapper/generateEncodedPathAndQueryForSelectedFacetURL.js.map +1 -1
  243. package/dist/components/QueryWrapper/useGetQueryMetadata.js.map +1 -1
  244. package/dist/components/QueryWrapperErrorBoundary.js.map +1 -1
  245. package/dist/components/QueryWrapperPlotNav/QueryWrapperPlotNav.js.map +1 -1
  246. package/dist/components/QueryWrapperPlotNav/UseRowSet.js.map +1 -1
  247. package/dist/components/RecentPublicationsGrid/RecentPublicationsGrid.js.map +1 -1
  248. package/dist/components/ReleaseCard/ReleaseCardUtils.js.map +1 -1
  249. package/dist/components/ResizableContainer/hooks/useResizable.js.map +1 -1
  250. package/dist/components/Resources/Resources.Mobile.js.map +1 -1
  251. package/dist/components/Resources/Resources.js.map +1 -1
  252. package/dist/components/RowDataTable/RowDataTableWithQuery.js.map +1 -1
  253. package/dist/components/SageResourcesPopover/SageResourcesPopover.js.map +1 -1
  254. package/dist/components/SchemaDrivenAnnotationEditor/AnnotationEditorUtils.js.map +1 -1
  255. package/dist/components/SetAccessRequirementCommonFields/SetAccessRequirementCommonFields.js.map +1 -1
  256. package/dist/components/SetManagedAccessRequirementFields/SetManagedAccessRequirementFields.js.map +1 -1
  257. package/dist/components/SmartLink/SmartButton.js.map +1 -1
  258. package/dist/components/SmartLink/SmartLink.js.map +1 -1
  259. package/dist/components/SourceAppImage.js.map +1 -1
  260. package/dist/components/StandaloneQueryWrapper/StandaloneQueryWrapper.js.map +1 -1
  261. package/dist/components/StatisticsPlot.js.map +1 -1
  262. package/dist/components/StorybookComponentWrapper.js.map +1 -1
  263. package/dist/components/SubsectionRowRenderer/SubsectionRowRenderer.js.map +1 -1
  264. package/dist/components/SustainabilityScorecard/SustainabilityScorecard.js.map +1 -1
  265. package/dist/components/SynapseChat/GridAgentChat.js.map +1 -1
  266. package/dist/components/SynapseChat/SynapseChatInteraction.js.map +1 -1
  267. package/dist/components/SynapseChat/SynapseChatMessage.js.map +1 -1
  268. package/dist/components/SynapseChat/extractMessageFromTraceEvent.js.map +1 -1
  269. package/dist/components/SynapseForm/StepsSideNav.js.map +1 -1
  270. package/dist/components/SynapseForm/SummaryTable.js.map +1 -1
  271. package/dist/components/SynapseForm/SynapseForm.js +4 -2
  272. package/dist/components/SynapseForm/SynapseForm.js.map +1 -1
  273. package/dist/components/SynapseForm/SynapseFormWrapper.js.map +1 -1
  274. package/dist/components/SynapseHomepageV2/SynapseByTheNumbersItem.js.map +1 -1
  275. package/dist/components/SynapseHomepageV2/SynapseFeatureItem.js.map +1 -1
  276. package/dist/components/SynapseHomepageV2/SynapseHomepageChatSearch.js.map +1 -1
  277. package/dist/components/SynapseHomepageV2/SynapseHomepageSearch.js.map +1 -1
  278. package/dist/components/SynapseHomepageV2/SynapseInActionItem.js.map +1 -1
  279. package/dist/components/SynapseHomepageV2/SynapsePlans.js.map +1 -1
  280. package/dist/components/SynapseHomepageV2/SynapseTrendingProjects.js.map +1 -1
  281. package/dist/components/SynapseNavDrawer/SynapseNavDrawer.d.ts +8 -7
  282. package/dist/components/SynapseNavDrawer/SynapseNavDrawer.d.ts.map +1 -1
  283. package/dist/components/SynapseNavDrawer/SynapseNavDrawer.js +173 -164
  284. package/dist/components/SynapseNavDrawer/SynapseNavDrawer.js.map +1 -1
  285. package/dist/components/SynapsePortalBanners/SynapsePortalBanners.js.map +1 -1
  286. package/dist/components/SynapseSearchPageResults/SearchFacetPanel/SearchFacetPanel.js.map +1 -1
  287. package/dist/components/SynapseSearchPageResults/SearchFacetPanel/SearchFacetPanelUtils.js.map +1 -1
  288. package/dist/components/SynapseSearchPageResults/SynapseSearchPageResults.js.map +1 -1
  289. package/dist/components/SynapseTable/EntityIDColumnCopyIcon.js.map +1 -1
  290. package/dist/components/SynapseTable/NoContentPlaceholderType.js.map +1 -1
  291. package/dist/components/SynapseTable/RowSelection/RowSelectionControls.js.map +1 -1
  292. package/dist/components/SynapseTable/SynapseTableCell/SynapseTableCell.js.map +1 -1
  293. package/dist/components/SynapseTable/SynapseTableRenderers.js.map +1 -1
  294. package/dist/components/SynapseTable/datasets/DatasetItemsEditor.js.map +1 -1
  295. package/dist/components/SynapseTable/table-top/ColumnSelection.js.map +1 -1
  296. package/dist/components/SynapseTable/table-top/DownloadOptions.js.map +1 -1
  297. package/dist/components/SynapseTable/usePrefetchTableData.js.map +1 -1
  298. package/dist/components/TableColumnSchemaEditor/ColumnModelForm.js.map +1 -1
  299. package/dist/components/TableColumnSchemaEditor/ColumnModelFormFields/DefaultValueField.js.map +1 -1
  300. package/dist/components/TableColumnSchemaEditor/ImportTableColumnsButton.js.map +1 -1
  301. package/dist/components/TableColumnSchemaEditor/TableColumnSchemaEditorUtils.d.ts +1 -1
  302. package/dist/components/TableColumnSchemaEditor/TableColumnSchemaEditorUtils.d.ts.map +1 -1
  303. package/dist/components/TableColumnSchemaEditor/TableColumnSchemaEditorUtils.js.map +1 -1
  304. package/dist/components/TableColumnSchemaEditor/TableColumnSchemaForm.js.map +1 -1
  305. package/dist/components/TableColumnSchemaEditor/TableColumnSchemaFormReducer.js.map +1 -1
  306. package/dist/components/TableColumnSchemaEditor/Validators/ColumnModelValidator.js.map +1 -1
  307. package/dist/components/TableColumnSchemaEditor/Validators/DatetimeSchema.js.map +1 -1
  308. package/dist/components/TanStackTable/ColumnHeader.d.ts +1 -0
  309. package/dist/components/TanStackTable/ColumnHeader.d.ts.map +1 -1
  310. package/dist/components/TanStackTable/ColumnHeader.js +8 -8
  311. package/dist/components/TanStackTable/ColumnHeader.js.map +1 -1
  312. package/dist/components/TanStackTable/ColumnHeaderEnumFilter.js.map +1 -1
  313. package/dist/components/TanStackTable/TableBody.js.map +1 -1
  314. package/dist/components/TeamSubjectsSelector/TeamSubjectsSelector.js.map +1 -1
  315. package/dist/components/TextField/TextField.js.map +1 -1
  316. package/dist/components/TimelinePlot/TimelinePhase.js.map +1 -1
  317. package/dist/components/TimelinePlot/TimelinePlot.js.map +1 -1
  318. package/dist/components/TimelinePlot/TimelinePlotSpeciesSelector.js.map +1 -1
  319. package/dist/components/UserCard/Avatar.js.map +1 -1
  320. package/dist/components/UserCardList/UserCardList.js.map +1 -1
  321. package/dist/components/UserCardList/UserCardListGroups/UserCardListGroups.Mobile.js.map +1 -1
  322. package/dist/components/UserCardList/UserCardListRotate.js.map +1 -1
  323. package/dist/components/UserOrTeamBadge/useUserOrTeam.js.map +1 -1
  324. package/dist/components/UserProfileLinks/UserProjects.js.map +1 -1
  325. package/dist/components/UserSearchBox/UserSearchBox.js.map +1 -1
  326. package/dist/components/Webhook/WebhookDashboard.js.map +1 -1
  327. package/dist/components/WikiMarkdownEditor/WikiMarkdownEditor.js.map +1 -1
  328. package/dist/components/WikiMarkdownEditorButton/WikiMarkdownEditorButton.js.map +1 -1
  329. package/dist/components/dataaccess/AccessApprovalsTable.js.map +1 -1
  330. package/dist/components/dataaccess/AccessRequestSubmissionTable.js.map +1 -1
  331. package/dist/components/dataaccess/SubmissionPage/SubmissionPage.js.map +1 -1
  332. package/dist/components/dataaccess/UseAccessRequirementTable.js.map +1 -1
  333. package/dist/components/dataaccess/UserAccessRequestHistory/UserAccessRequestHistoryTable.js.map +1 -1
  334. package/dist/components/doi/CreateOrUpdateDoiModal.js.map +1 -1
  335. package/dist/components/entity/page/CreatedByModifiedBy.js.map +1 -1
  336. package/dist/components/entity/page/action_menu/EntityActionMenu.js.map +1 -1
  337. package/dist/components/entity/page/title_bar/useDataCiteUsage.js.map +1 -1
  338. package/dist/components/entity/page/title_bar/useGetMentions.js.map +1 -1
  339. package/dist/components/error/ErrorPage.js.map +1 -1
  340. package/dist/components/favorites/FavoritesPage.js.map +1 -1
  341. package/dist/components/file/upload/BasicFileHandleUpload.js.map +1 -1
  342. package/dist/components/layout/SWCHeader.d.ts +9 -0
  343. package/dist/components/layout/SWCHeader.d.ts.map +1 -0
  344. package/dist/components/layout/SWCHeader.js +19 -0
  345. package/dist/components/layout/SWCHeader.js.map +1 -0
  346. package/dist/components/layout/SWCPageLayout.d.ts +9 -0
  347. package/dist/components/layout/SWCPageLayout.d.ts.map +1 -0
  348. package/dist/components/layout/SWCPageLayout.js +14 -0
  349. package/dist/components/layout/SWCPageLayout.js.map +1 -0
  350. package/dist/components/menu/ComplexMenu.js.map +1 -1
  351. package/dist/components/row_renderers/utils/ChipContainer.js.map +1 -1
  352. package/dist/components/styled/StyledPopover.js.map +1 -1
  353. package/dist/components/table/CsvPreview/CsvPreview.js +2 -1
  354. package/dist/components/table/CsvPreview/CsvPreview.js.map +1 -1
  355. package/dist/components/table/CsvPreview/CsvPreviewDialog.js.map +1 -1
  356. package/dist/components/trash/TrashCanList.js.map +1 -1
  357. package/dist/components/widgets/FileHandleLink.js.map +1 -1
  358. package/dist/components/widgets/RangeSlider/RangeSlider.js.map +1 -1
  359. package/dist/components/widgets/SynapseVideo.js.map +1 -1
  360. package/dist/components/widgets/facet-nav/FacetNavPanel.js.map +1 -1
  361. package/dist/components/widgets/facet-nav/PlotsContainer.js.map +1 -1
  362. package/dist/components/widgets/facet-nav/SelectionCriteriaPills.js.map +1 -1
  363. package/dist/components/widgets/facet-nav/useFacetPlots.js.map +1 -1
  364. package/dist/components/widgets/query-filter/CombinedRangeFacetFilter.js.map +1 -1
  365. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilter.js.map +1 -1
  366. package/dist/components/widgets/query-filter/FacetFilterControls.js.map +1 -1
  367. package/dist/components/widgets/query-filter/RangeFacetFilter.js.map +1 -1
  368. package/dist/components/widgets/query-filter/RangeFacetFilterUI.js.map +1 -1
  369. package/dist/features/curator/GridPage/components/GridPageTitle.d.ts.map +1 -1
  370. package/dist/features/curator/GridPage/components/GridPageTitle.js +23 -30
  371. package/dist/features/curator/GridPage/components/GridPageTitle.js.map +1 -1
  372. package/dist/features/curator/dashboard/CuratorDashboard.d.ts +2 -0
  373. package/dist/features/curator/dashboard/CuratorDashboard.d.ts.map +1 -0
  374. package/dist/features/curator/dashboard/CuratorDashboard.js +45 -0
  375. package/dist/features/curator/dashboard/CuratorDashboard.js.map +1 -0
  376. package/dist/features/curator/dashboard/components/CurationTaskCard.css +1 -0
  377. package/dist/features/curator/dashboard/components/CurationTaskCard.d.ts +9 -0
  378. package/dist/features/curator/dashboard/components/CurationTaskCard.d.ts.map +1 -0
  379. package/dist/features/curator/dashboard/components/CurationTaskCard.js +106 -0
  380. package/dist/features/curator/dashboard/components/CurationTaskCard.js.map +1 -0
  381. package/dist/features/curator/dashboard/components/CurationTaskCard.module.js +12 -0
  382. package/dist/features/curator/dashboard/components/CurationTaskCard.module.js.map +1 -0
  383. package/dist/features/curator/dashboard/components/CurationTaskCard.module.scss +52 -0
  384. package/dist/features/curator/dashboard/components/NextStepButton.css +1 -0
  385. package/dist/features/curator/dashboard/components/NextStepButton.d.ts +14 -0
  386. package/dist/features/curator/dashboard/components/NextStepButton.d.ts.map +1 -0
  387. package/dist/features/curator/dashboard/components/NextStepButton.js +35 -0
  388. package/dist/features/curator/dashboard/components/NextStepButton.js.map +1 -0
  389. package/dist/features/curator/dashboard/components/NextStepButton.module.js +11 -0
  390. package/dist/features/curator/dashboard/components/NextStepButton.module.js.map +1 -0
  391. package/dist/features/curator/dashboard/components/NextStepButton.module.scss +57 -0
  392. package/dist/features/curator/dashboard/components/UserOrTeamChip.css +1 -1
  393. package/dist/features/curator/dashboard/components/UserOrTeamChip.module.js +1 -1
  394. package/dist/features/curator/dashboard/components/UserOrTeamChip.module.js.map +1 -1
  395. package/dist/features/curator/dashboard/components/UserOrTeamChip.module.scss +5 -5
  396. package/dist/features/curator/dashboard/components/shared.css +1 -0
  397. package/dist/features/curator/dashboard/components/shared.module.js +5 -0
  398. package/dist/features/curator/dashboard/components/shared.module.js.map +1 -0
  399. package/dist/features/curator/dashboard/components/shared.module.scss +8 -0
  400. package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.d.ts +0 -2
  401. package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.d.ts.map +1 -1
  402. package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.js +16 -34
  403. package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.js.map +1 -1
  404. package/dist/features/entity/metadata-task/components/MetadataTasksTableAssigneeCell.js.map +1 -1
  405. package/dist/features/entity/metadata-task/hooks/useGetOrCreateGridSessionForSource.js.map +1 -1
  406. package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask.js.map +1 -1
  407. package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask_legacy.js.map +1 -1
  408. package/dist/features/entity/metadata-task/hooks/useMetadataTaskTable.js +1 -1
  409. package/dist/features/entity/metadata-task/hooks/useMetadataTaskTable.js.map +1 -1
  410. package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.d.ts +10 -0
  411. package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.d.ts.map +1 -0
  412. package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.js +37 -0
  413. package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.js.map +1 -0
  414. package/dist/features/entity/metadata-task/utils/constants.d.ts +5 -0
  415. package/dist/features/entity/metadata-task/utils/constants.d.ts.map +1 -0
  416. package/dist/features/entity/metadata-task/utils/constants.js +6 -0
  417. package/dist/features/entity/metadata-task/utils/constants.js.map +1 -0
  418. package/dist/mocks/challenge/mockChallenge.js.map +1 -1
  419. package/dist/mocks/entity/mockDataset.js.map +1 -1
  420. package/dist/mocks/entity/mockDatasetCollection.js.map +1 -1
  421. package/dist/mocks/entity/mockFileEntity.js.map +1 -1
  422. package/dist/mocks/entity/mockFileView.js.map +1 -1
  423. package/dist/mocks/entity/mockGeneratedEntityData.js.map +1 -1
  424. package/dist/mocks/entity/mockProject.js.map +1 -1
  425. package/dist/mocks/entity/mockProjectView.js.map +1 -1
  426. package/dist/mocks/entity/mockRootEntity.js.map +1 -1
  427. package/dist/mocks/entity/mockTableEntity.js.map +1 -1
  428. package/dist/mocks/mockWiki.js.map +1 -1
  429. package/dist/mocks/msw/handlers/asyncJobHandlers.js.map +1 -1
  430. package/dist/mocks/msw/handlers/challengeHandlers.js.map +1 -1
  431. package/dist/mocks/msw/handlers/changePasswordHandlers.js.map +1 -1
  432. package/dist/mocks/msw/handlers/discussionHandlers.js.map +1 -1
  433. package/dist/mocks/msw/handlers/entityHandlers.js.map +1 -1
  434. package/dist/mocks/msw/handlers/fileHandlers.js.map +1 -1
  435. package/dist/mocks/msw/handlers/gridHandlers.js.map +1 -1
  436. package/dist/mocks/msw/handlers/personalAccessTokenHandlers.js.map +1 -1
  437. package/dist/mocks/msw/handlers/subscriptionHandlers.js.map +1 -1
  438. package/dist/mocks/msw/handlers/teamHandlers.js.map +1 -1
  439. package/dist/mocks/msw/handlers/userProfileHandlers.js.map +1 -1
  440. package/dist/mocks/msw/handlers/wikiHandlers.js.map +1 -1
  441. package/dist/mocks/provenance/mockActivity.js.map +1 -1
  442. package/dist/mocks/query/mockReleaseCardsTableQueryResultBundle.js.map +1 -1
  443. package/dist/ror-client/index.js.map +1 -1
  444. package/dist/style/components/_cards.scss +4 -0
  445. package/dist/style/components/_data-grid-extra.css +1 -1
  446. package/dist/style/components/_data-grid-extra.scss +2 -0
  447. package/dist/style/main.css +1 -1
  448. package/dist/synapse-client/HttpClient.js.map +1 -1
  449. package/dist/synapse-client/SynapseClient.js.map +1 -1
  450. package/dist/synapse-queries/QueryMatching.test-utils.js.map +1 -1
  451. package/dist/synapse-queries/auth/useTwoFactorEnrollment.js.map +1 -1
  452. package/dist/synapse-queries/curation/task/useCurationTask.d.ts +1 -1
  453. package/dist/synapse-queries/curation/task/useCurationTask.d.ts.map +1 -1
  454. package/dist/synapse-queries/curation/task/useCurationTask.js +1 -1
  455. package/dist/synapse-queries/curation/task/useCurationTask.js.map +1 -1
  456. package/dist/synapse-queries/dataaccess/useRestrictionInformation.js.map +1 -1
  457. package/dist/synapse-queries/doi/useDOI.js.map +1 -1
  458. package/dist/synapse-queries/download/useDownloadList.js.map +1 -1
  459. package/dist/synapse-queries/entity/useEntity.js.map +1 -1
  460. package/dist/synapse-queries/entity/useEntityBundle.js.map +1 -1
  461. package/dist/synapse-queries/entity/useExportTableQueryToAnalysisPlatform.js.map +1 -1
  462. package/dist/synapse-queries/entity/useExportToTerra.js.map +1 -1
  463. package/dist/synapse-queries/entity/useGetQueryResultBundle.js.map +1 -1
  464. package/dist/synapse-queries/entity/useSchema.js.map +1 -1
  465. package/dist/synapse-queries/file/UploadToS3.js.map +1 -1
  466. package/dist/synapse-queries/file/useDirectUploadToS3.js.map +1 -1
  467. package/dist/synapse-queries/file/useFiles.js.map +1 -1
  468. package/dist/synapse-queries/forum/useReply.js.map +1 -1
  469. package/dist/synapse-queries/forum/useThread.js.map +1 -1
  470. package/dist/synapse-queries/grid/useEstablishWebsocketConnection.d.ts +2 -0
  471. package/dist/synapse-queries/grid/useEstablishWebsocketConnection.d.ts.map +1 -1
  472. package/dist/synapse-queries/grid/useEstablishWebsocketConnection.js.map +1 -1
  473. package/dist/synapse-queries/grid/useExportGrid.js.map +1 -1
  474. package/dist/synapse-queries/grid/useGridSession.js.map +1 -1
  475. package/dist/synapse-queries/grid/useImportCsvIntoGrid.js.map +1 -1
  476. package/dist/synapse-queries/subscription/useSubscription.js.map +1 -1
  477. package/dist/synapse-queries/table/useGetCsvPreview.js.map +1 -1
  478. package/dist/synapse-queries/table/useTableUpdateTransaction.js.map +1 -1
  479. package/dist/synapse-queries/team/useTeamMembers.js.map +1 -1
  480. package/dist/synapse-queries/user/useGetUserChallenges.js.map +1 -1
  481. package/dist/synapse-queries/user/useUserBundle.js.map +1 -1
  482. package/dist/synapse-queries/user/useUserGroupHeader.js.map +1 -1
  483. package/dist/testutils/ReactQueryMockUtils.js.map +1 -1
  484. package/dist/theme/ThemeProvider.js.map +1 -1
  485. package/dist/tsconfig.build.tsbuildinfo +1 -1
  486. package/dist/utils/AppUtils/session/SynapseSessionManager.js.map +1 -1
  487. package/dist/utils/AppUtils/session/useSessionManager.js.map +1 -1
  488. package/dist/utils/PermissionLevelToAccessType.js.map +1 -1
  489. package/dist/utils/challenge/evaluation/EvaluationUtils.js.map +1 -1
  490. package/dist/utils/context/SynapseContext.js.map +1 -1
  491. package/dist/utils/functions/AccessControlListUtils.d.ts +4 -0
  492. package/dist/utils/functions/AccessControlListUtils.d.ts.map +1 -1
  493. package/dist/utils/functions/AccessControlListUtils.js +12 -1
  494. package/dist/utils/functions/AccessControlListUtils.js.map +1 -1
  495. package/dist/utils/functions/GridApiUtils.js.map +1 -1
  496. package/dist/utils/functions/QueryFilterUtils.js.map +1 -1
  497. package/dist/utils/functions/RealmUtils.d.ts +4 -0
  498. package/dist/utils/functions/RealmUtils.d.ts.map +1 -1
  499. package/dist/utils/functions/RealmUtils.js +9 -3
  500. package/dist/utils/functions/RealmUtils.js.map +1 -1
  501. package/dist/utils/functions/SanitizeHtmlUtils.js.map +1 -1
  502. package/dist/utils/functions/SanitizeHtmlUtils.test-utils.js.map +1 -1
  503. package/dist/utils/functions/SqlFunctions.js.map +1 -1
  504. package/dist/utils/functions/StringUtils.js.map +1 -1
  505. package/dist/utils/functions/deepLinkingUtils.js.map +1 -1
  506. package/dist/utils/functions/getDataFromFromStorage.js.map +1 -1
  507. package/dist/utils/functions/getEndpoint.js.map +1 -1
  508. package/dist/utils/functions/getUserData.js.map +1 -1
  509. package/dist/utils/functions/queryUtils.js.map +1 -1
  510. package/dist/utils/functions/testDownloadSpeed.js.map +1 -1
  511. package/dist/utils/hooks/useConfirmItems.js.map +1 -1
  512. package/dist/utils/hooks/useCookiePreferences.js.map +1 -1
  513. package/dist/utils/hooks/useCreateShortUrl.js.map +1 -1
  514. package/dist/utils/hooks/useDetectSSOCode.js.map +1 -1
  515. package/dist/utils/hooks/useDirectDownloadHandler.js.map +1 -1
  516. package/dist/utils/hooks/useGetGoalData.js.map +1 -1
  517. package/dist/utils/hooks/useGetInfoFromIds.js.map +1 -1
  518. package/dist/utils/hooks/useImageUrlUtils.js.map +1 -1
  519. package/dist/utils/hooks/useImmutableTableQuery/useImmutableTableQuery.js.map +1 -1
  520. package/dist/utils/hooks/useImmutableTableQuery/useTableQueryReducer.js.map +1 -1
  521. package/dist/utils/hooks/useIsBot.js.map +1 -1
  522. package/dist/utils/hooks/useListState.js.map +1 -1
  523. package/dist/utils/hooks/useLogin.d.ts.map +1 -1
  524. package/dist/utils/hooks/useLogin.js +53 -52
  525. package/dist/utils/hooks/useLogin.js.map +1 -1
  526. package/dist/utils/hooks/useMutuallyExclusiveState.js.map +1 -1
  527. package/dist/utils/hooks/useOverlay.js.map +1 -1
  528. package/dist/utils/hooks/usePreFetchResource.js.map +1 -1
  529. package/dist/utils/hooks/useQuerySearchParam.js.map +1 -1
  530. package/dist/utils/hooks/useScrollFadeTransition.js.map +1 -1
  531. package/dist/utils/hooks/useSet.js.map +1 -1
  532. package/dist/utils/hooks/useSourceAppConfigs.js.map +1 -1
  533. package/dist/utils/hooks/useTableImageUrl.js.map +1 -1
  534. package/dist/utils/hooks/useUploadFileEntity/useCreatePathsAndGetParentId.js.map +1 -1
  535. package/dist/utils/hooks/useUploadFileEntity/useLinkFileEntityToURL.js.map +1 -1
  536. package/dist/utils/hooks/useUploadFileEntity/usePrepareFileEntityUpload.js.map +1 -1
  537. package/dist/utils/hooks/useUploadFileEntity/useTrackFileUploads.js.map +1 -1
  538. package/dist/utils/hooks/useUploadFileEntity/useUploadFileEntities.js.map +1 -1
  539. package/dist/utils/hooks/useUploadFileEntity/useUploadFiles.js.map +1 -1
  540. package/dist/utils/hooks/useUploadFileEntity/willUploadsExceedStorageLimit.js.map +1 -1
  541. package/dist/utils/html/TargetEnum.js.map +1 -1
  542. package/dist/utils/jsonschema/SchemaAnnotationUtils.js.map +1 -1
  543. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"CsvPreviewDialog.js","names":[],"sources":["../../../../src/components/table/CsvPreview/CsvPreviewDialog.tsx"],"sourcesContent":["import { DialogBase } from '@/components/DialogBase'\nimport {\n BasicFileHandleUpload,\n FileUploadHandle,\n} from '@/components/file/upload/BasicFileHandleUpload'\nimport { ErrorBanner } from '@/components/index'\nimport CsvPreview from '@/components/table/CsvPreview/CsvPreview'\nimport CsvTableDescriptorForm, {\n CsvTableDescriptorFormHandle,\n} from '@/components/table/CsvTableDescriptorForm/CsvTableDescriptorForm'\nimport { RefreshTwoTone } from '@mui/icons-material'\nimport ExpandMoreIcon from '@mui/icons-material/ExpandMore'\nimport Accordion from '@mui/material/Accordion'\nimport AccordionDetails from '@mui/material/AccordionDetails'\nimport AccordionSummary from '@mui/material/AccordionSummary'\nimport Button from '@mui/material/Button'\nimport Stack from '@mui/material/Stack'\nimport Typography from '@mui/material/Typography'\nimport {\n ColumnModel,\n CsvTableDescriptor,\n UploadToTablePreviewResult,\n} from '@sage-bionetworks/synapse-client'\nimport { useCallback, useRef, useState } from 'react'\n\nenum CsvPreviewDialogStep {\n UPLOAD_CSV = 0,\n COLUMN_PREVIEW = 1,\n}\n\nexport type CsvPreviewDialogProps = {\n /** Whether the dialog is open */\n open: boolean\n /** Callback when the dialog is closed */\n onClose: () => void\n /** Callback when the user confirms the column models\n * @param dataFileHandleId - The file handle ID of the uploaded CSV\n * @param columnModels - The confirmed column models\n * */\n onConfirm: (\n dataFileHandleId: string,\n columnModels: ColumnModel[],\n csvTableDescriptor: CsvTableDescriptor,\n ) => void\n /** Whether the confirm action is pending */\n confirmIsPending?: boolean\n /** An optional error message to display */\n errorMessage?: string\n}\n\nexport default function CsvPreviewDialog(props: CsvPreviewDialogProps) {\n const { open, onClose, onConfirm, confirmIsPending, errorMessage } = props\n const [step, setStep] = useState(CsvPreviewDialogStep.UPLOAD_CSV)\n const [csvTableDescriptor, setCsvTableDescriptor] =\n useState<CsvTableDescriptor>({\n separator: ',',\n quoteCharacter: '\"',\n escapeCharacter: '\\\\',\n lineEnd: '\\n',\n isFirstLineHeader: true,\n })\n const [csvPreviewData, setCsvPreviewData] =\n useState<UploadToTablePreviewResult | null>(null)\n const [isLoadingPreview, setIsLoadingPreview] = useState(false)\n\n const [uploadedFileHandleId, setUploadedFileHandleId] = useState<\n string | null\n >(null)\n\n const onFileUploaded = useCallback((fileHandleId: string) => {\n setUploadedFileHandleId(fileHandleId)\n setStep(CsvPreviewDialogStep.COLUMN_PREVIEW)\n }, [])\n\n const uploadRef = useRef<FileUploadHandle | null>(null)\n const csvDescriptorFormRef = useRef<CsvTableDescriptorFormHandle | null>(null)\n\n const uploadStepContent = (\n <BasicFileHandleUpload\n ref={uploadRef}\n allowMultipleUpload={false}\n onFileUploadComplete={fileHandleId => {\n onFileUploaded(fileHandleId)\n }}\n disableDragAndDrop={true}\n />\n )\n\n const previewStepContent = (\n <Stack spacing={2}>\n {uploadedFileHandleId && (\n <CsvPreview\n fileHandleId={uploadedFileHandleId}\n csvTableDescriptor={csvTableDescriptor}\n onCsvPreviewDataChange={setCsvPreviewData}\n onIsLoadingChange={setIsLoadingPreview}\n />\n )}\n <Accordion>\n <AccordionSummary expandIcon={<ExpandMoreIcon />}>\n <Typography variant={'headline3'}>Show Options</Typography>\n </AccordionSummary>\n <AccordionDetails>\n <CsvTableDescriptorForm\n defaultValue={csvTableDescriptor}\n ref={csvDescriptorFormRef}\n />\n <Button\n variant={'outlined'}\n startIcon={<RefreshTwoTone />}\n sx={{ mt: 2 }}\n onClick={() => {\n // Get the state from the form and update local state, which will re-render the preview\n if (csvDescriptorFormRef.current) {\n setCsvTableDescriptor(\n csvDescriptorFormRef.current.getFormData(),\n )\n }\n }}\n >\n Refresh Preview\n </Button>\n </AccordionDetails>\n </Accordion>\n </Stack>\n )\n\n return (\n <DialogBase\n maxWidth={'lg'}\n title={'Upload CSV'}\n onCancel={onClose}\n open={open}\n content={\n <>\n {step === CsvPreviewDialogStep.UPLOAD_CSV && uploadStepContent}\n {step === CsvPreviewDialogStep.COLUMN_PREVIEW && previewStepContent}\n {errorMessage && <ErrorBanner error={errorMessage} />}\n </>\n }\n actions={\n <>\n <Button\n variant={'outlined'}\n disabled={isLoadingPreview}\n onClick={() => {\n onClose()\n }}\n >\n Cancel\n </Button>\n {step === CsvPreviewDialogStep.COLUMN_PREVIEW && (\n <Button\n disabled={isLoadingPreview}\n variant={'contained'}\n onClick={() => {\n onConfirm(\n uploadedFileHandleId!,\n csvPreviewData!.suggestedColumns!,\n csvTableDescriptor,\n )\n }}\n loading={confirmIsPending}\n >\n Confirm\n </Button>\n )}\n </>\n }\n />\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAyBA,IAAK,IAAL,yBAAA,GAAA;QACE,EAAA,EAAA,aAAA,KAAA,cACA,EAAA,EAAA,iBAAA,KAAA;EAFG,KAAA,EAAA,CAGJ;AAsBD,SAAwB,EAAiB,GAA8B;CACrE,IAAM,EAAE,SAAM,YAAS,cAAW,qBAAkB,oBAAiB,GAC/D,CAAC,GAAM,KAAW,EAAS,EAAqB,WAAW,EAC3D,CAAC,GAAoB,KACzB,EAA6B;EAC3B,WAAW;EACX,gBAAgB;EAChB,iBAAiB;EACjB,SAAS;EACT,mBAAmB;EACpB,CAAC,EACE,CAAC,GAAgB,KACrB,EAA4C,KAAK,EAC7C,CAAC,GAAkB,KAAuB,EAAS,GAAM,EAEzD,CAAC,GAAsB,KAA2B,EAEtD,KAAK,EAED,IAAiB,GAAa,MAAyB;AAE3D,EADA,EAAwB,EAAa,EACrC,EAAQ,EAAqB,eAAe;IAC3C,EAAE,CAAC,EAEA,IAAY,EAAgC,KAAK,EACjD,IAAuB,EAA4C,KAAK,EAExE,IACJ,kBAAC,GAAD;EACE,KAAK;EACL,qBAAqB;EACrB,uBAAsB,MAAgB;AACpC,KAAe,EAAa;;EAE9B,oBAAoB;EACpB,CAAA,EAGE,IACJ,kBAAC,GAAD;EAAO,SAAS;YAAhB,CACG,KACC,kBAAC,GAAD;GACE,cAAc;GACM;GACpB,wBAAwB;GACxB,mBAAmB;GACnB,CAAA,EAEJ,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;GAAkB,YAAY,kBAAC,GAAD,EAAkB,CAAA;aAC9C,kBAAC,GAAD;IAAY,SAAS;cAAa;IAAyB,CAAA;GAC1C,CAAA,EACnB,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;GACE,cAAc;GACd,KAAK;GACL,CAAA,EACF,kBAAC,GAAD;GACE,SAAS;GACT,WAAW,kBAAC,GAAD,EAAkB,CAAA;GAC7B,IAAI,EAAE,IAAI,GAAG;GACb,eAAe;AAEb,IAAI,EAAqB,WACvB,EACE,EAAqB,QAAQ,aAAa,CAC3C;;aAGN;GAEQ,CAAA,CACQ,EAAA,CAAA,CACT,EAAA,CAAA,CACN;;AAGV,QACE,kBAAC,GAAD;EACE,UAAU;EACV,OAAO;EACP,UAAU;EACJ;EACN,SACE,kBAAA,GAAA,EAAA,UAAA;GACG,MAAS,EAAqB,cAAc;GAC5C,MAAS,EAAqB,kBAAkB;GAChD,KAAgB,kBAAC,GAAD,EAAa,OAAO,GAAgB,CAAA;GACpD,EAAA,CAAA;EAEL,SACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;GACE,SAAS;GACT,UAAU;GACV,eAAe;AACb,OAAS;;aAEZ;GAEQ,CAAA,EACR,MAAS,EAAqB,kBAC7B,kBAAC,GAAD;GACE,UAAU;GACV,SAAS;GACT,eAAe;AACb,MACE,GACA,EAAgB,kBAChB,EACD;;GAEH,SAAS;aACV;GAEQ,CAAA,CAEV,EAAA,CAAA;EAEL,CAAA"}
1
+ {"version":3,"file":"CsvPreviewDialog.js","names":[],"sources":["../../../../src/components/table/CsvPreview/CsvPreviewDialog.tsx"],"sourcesContent":["import { DialogBase } from '@/components/DialogBase'\nimport {\n BasicFileHandleUpload,\n FileUploadHandle,\n} from '@/components/file/upload/BasicFileHandleUpload'\nimport { ErrorBanner } from '@/components/index'\nimport CsvPreview from '@/components/table/CsvPreview/CsvPreview'\nimport CsvTableDescriptorForm, {\n CsvTableDescriptorFormHandle,\n} from '@/components/table/CsvTableDescriptorForm/CsvTableDescriptorForm'\nimport { RefreshTwoTone } from '@mui/icons-material'\nimport ExpandMoreIcon from '@mui/icons-material/ExpandMore'\nimport Accordion from '@mui/material/Accordion'\nimport AccordionDetails from '@mui/material/AccordionDetails'\nimport AccordionSummary from '@mui/material/AccordionSummary'\nimport Button from '@mui/material/Button'\nimport Stack from '@mui/material/Stack'\nimport Typography from '@mui/material/Typography'\nimport {\n ColumnModel,\n CsvTableDescriptor,\n UploadToTablePreviewResult,\n} from '@sage-bionetworks/synapse-client'\nimport { useCallback, useRef, useState } from 'react'\n\nenum CsvPreviewDialogStep {\n UPLOAD_CSV = 0,\n COLUMN_PREVIEW = 1,\n}\n\nexport type CsvPreviewDialogProps = {\n /** Whether the dialog is open */\n open: boolean\n /** Callback when the dialog is closed */\n onClose: () => void\n /** Callback when the user confirms the column models\n * @param dataFileHandleId - The file handle ID of the uploaded CSV\n * @param columnModels - The confirmed column models\n * */\n onConfirm: (\n dataFileHandleId: string,\n columnModels: ColumnModel[],\n csvTableDescriptor: CsvTableDescriptor,\n ) => void\n /** Whether the confirm action is pending */\n confirmIsPending?: boolean\n /** An optional error message to display */\n errorMessage?: string\n}\n\nexport default function CsvPreviewDialog(props: CsvPreviewDialogProps) {\n const { open, onClose, onConfirm, confirmIsPending, errorMessage } = props\n const [step, setStep] = useState(CsvPreviewDialogStep.UPLOAD_CSV)\n const [csvTableDescriptor, setCsvTableDescriptor] =\n useState<CsvTableDescriptor>({\n separator: ',',\n quoteCharacter: '\"',\n escapeCharacter: '\\\\',\n lineEnd: '\\n',\n isFirstLineHeader: true,\n })\n const [csvPreviewData, setCsvPreviewData] =\n useState<UploadToTablePreviewResult | null>(null)\n const [isLoadingPreview, setIsLoadingPreview] = useState(false)\n\n const [uploadedFileHandleId, setUploadedFileHandleId] = useState<\n string | null\n >(null)\n\n const onFileUploaded = useCallback((fileHandleId: string) => {\n setUploadedFileHandleId(fileHandleId)\n setStep(CsvPreviewDialogStep.COLUMN_PREVIEW)\n }, [])\n\n const uploadRef = useRef<FileUploadHandle | null>(null)\n const csvDescriptorFormRef = useRef<CsvTableDescriptorFormHandle | null>(null)\n\n const uploadStepContent = (\n <BasicFileHandleUpload\n ref={uploadRef}\n allowMultipleUpload={false}\n onFileUploadComplete={fileHandleId => {\n onFileUploaded(fileHandleId)\n }}\n disableDragAndDrop={true}\n />\n )\n\n const previewStepContent = (\n <Stack spacing={2}>\n {uploadedFileHandleId && (\n <CsvPreview\n fileHandleId={uploadedFileHandleId}\n csvTableDescriptor={csvTableDescriptor}\n onCsvPreviewDataChange={setCsvPreviewData}\n onIsLoadingChange={setIsLoadingPreview}\n />\n )}\n <Accordion>\n <AccordionSummary expandIcon={<ExpandMoreIcon />}>\n <Typography variant={'headline3'}>Show Options</Typography>\n </AccordionSummary>\n <AccordionDetails>\n <CsvTableDescriptorForm\n defaultValue={csvTableDescriptor}\n ref={csvDescriptorFormRef}\n />\n <Button\n variant={'outlined'}\n startIcon={<RefreshTwoTone />}\n sx={{ mt: 2 }}\n onClick={() => {\n // Get the state from the form and update local state, which will re-render the preview\n if (csvDescriptorFormRef.current) {\n setCsvTableDescriptor(\n csvDescriptorFormRef.current.getFormData(),\n )\n }\n }}\n >\n Refresh Preview\n </Button>\n </AccordionDetails>\n </Accordion>\n </Stack>\n )\n\n return (\n <DialogBase\n maxWidth={'lg'}\n title={'Upload CSV'}\n onCancel={onClose}\n open={open}\n content={\n <>\n {step === CsvPreviewDialogStep.UPLOAD_CSV && uploadStepContent}\n {step === CsvPreviewDialogStep.COLUMN_PREVIEW && previewStepContent}\n {errorMessage && <ErrorBanner error={errorMessage} />}\n </>\n }\n actions={\n <>\n <Button\n variant={'outlined'}\n disabled={isLoadingPreview}\n onClick={() => {\n onClose()\n }}\n >\n Cancel\n </Button>\n {step === CsvPreviewDialogStep.COLUMN_PREVIEW && (\n <Button\n disabled={isLoadingPreview}\n variant={'contained'}\n onClick={() => {\n onConfirm(\n uploadedFileHandleId!,\n csvPreviewData!.suggestedColumns!,\n csvTableDescriptor,\n )\n }}\n loading={confirmIsPending}\n >\n Confirm\n </Button>\n )}\n </>\n }\n />\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAyBA,IAAK,IAAL,yBAAA,GAAA;QACE,EAAA,EAAA,aAAa,KAAA,cACb,EAAA,EAAA,iBAAiB,KAAA;EAFd,KAAA,EAAA,CAGJ;AAsBD,SAAwB,EAAiB,GAA8B;CACrE,IAAM,EAAE,SAAM,YAAS,cAAW,qBAAkB,oBAAiB,GAC/D,CAAC,GAAM,KAAW,EAAS,EAAqB,WAAW,EAC3D,CAAC,GAAoB,KACzB,EAA6B;EAC3B,WAAW;EACX,gBAAgB;EAChB,iBAAiB;EACjB,SAAS;EACT,mBAAmB;EACpB,CAAC,EACE,CAAC,GAAgB,KACrB,EAA4C,KAAK,EAC7C,CAAC,GAAkB,KAAuB,EAAS,GAAM,EAEzD,CAAC,GAAsB,KAA2B,EAEtD,KAAK,EAED,IAAiB,GAAa,MAAyB;AAE3D,EADA,EAAwB,EAAa,EACrC,EAAQ,EAAqB,eAAe;IAC3C,EAAE,CAAC,EAEA,IAAY,EAAgC,KAAK,EACjD,IAAuB,EAA4C,KAAK,EAExE,IACJ,kBAAC,GAAD;EACE,KAAK;EACL,qBAAqB;EACrB,uBAAsB,MAAgB;AACpC,KAAe,EAAa;;EAE9B,oBAAoB;EACpB,CAAA,EAGE,IACJ,kBAAC,GAAD;EAAO,SAAS;YAAhB,CACG,KACC,kBAAC,GAAD;GACE,cAAc;GACM;GACpB,wBAAwB;GACxB,mBAAmB;GACnB,CAAA,EAEJ,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;GAAkB,YAAY,kBAAC,GAAD,EAAkB,CAAA;aAC9C,kBAAC,GAAD;IAAY,SAAS;cAAa;IAAyB,CAAA;GAC1C,CAAA,EACnB,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;GACE,cAAc;GACd,KAAK;GACL,CAAA,EACF,kBAAC,GAAD;GACE,SAAS;GACT,WAAW,kBAAC,GAAD,EAAkB,CAAA;GAC7B,IAAI,EAAE,IAAI,GAAG;GACb,eAAe;AAEb,IAAI,EAAqB,WACvB,EACE,EAAqB,QAAQ,aAAa,CAC3C;;aAGN;GAEQ,CAAA,CACQ,EAAA,CAAA,CACT,EAAA,CAAA,CACN;;AAGV,QACE,kBAAC,GAAD;EACE,UAAU;EACV,OAAO;EACP,UAAU;EACJ;EACN,SACE,kBAAA,GAAA,EAAA,UAAA;GACG,MAAS,EAAqB,cAAc;GAC5C,MAAS,EAAqB,kBAAkB;GAChD,KAAgB,kBAAC,GAAD,EAAa,OAAO,GAAgB,CAAA;GACpD,EAAA,CAAA;EAEL,SACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;GACE,SAAS;GACT,UAAU;GACV,eAAe;AACb,OAAS;;aAEZ;GAEQ,CAAA,EACR,MAAS,EAAqB,kBAC7B,kBAAC,GAAD;GACE,UAAU;GACV,SAAS;GACT,eAAe;AACb,MACE,GACA,EAAgB,kBAChB,EACD;;GAEH,SAAS;aACV;GAEQ,CAAA,CAEV,EAAA,CAAA;EAEL,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"TrashCanList.js","names":[],"sources":["../../../src/components/trash/TrashCanList.tsx"],"sourcesContent":["import {\n useGetItemsInTrashCanInfinite,\n usePurgeEntities,\n useRestoreEntities,\n} from '@/synapse-queries/trash/useTrashCan'\nimport { formatDate } from '@/utils/functions/DateFormatter'\nimport { entityTypeToFriendlyName } from '@/utils/functions/EntityTypeUtils'\nimport { Alert, Box, Button, Typography } from '@mui/material'\nimport { SynapseClientError } from '@sage-bionetworks/synapse-client/util/SynapseClientError'\nimport { TrashedEntity } from '@sage-bionetworks/synapse-types'\nimport {\n ColumnDef,\n createColumnHelper,\n getCoreRowModel,\n RowSelectionState,\n Table,\n useReactTable,\n} from '@tanstack/react-table'\nimport dayjs from 'dayjs'\nimport { useMemo, useState } from 'react'\nimport {\n CheckBoxCell,\n CheckBoxHeader,\n} from '../EntityHeaderTable/EntityHeaderTableCellRenderers'\nimport { EntityLink } from '../EntityLink'\nimport { BlockingLoader, SynapseSpinner } from '../LoadingScreen/LoadingScreen'\nimport WarningDialog from '../SynapseForm/WarningDialog'\nimport StyledTanStackTable from '../TanStackTable/StyledTanStackTable'\n\n/**\n * Convert an array of Promise results to an array of errors\n */\nfunction toSynapseClientErrorList(\n results: PromiseSettledResult<void>[],\n): SynapseClientError[] {\n return results\n .filter(\n (result): result is PromiseRejectedResult => result.status === 'rejected',\n )\n .map(result => result.reason as SynapseClientError)\n}\n\nconst columnHelper = createColumnHelper<TrashedEntity>()\n\nfunction getTrashCanColumns(\n onRestore: (entityId: string) => void,\n): ColumnDef<TrashedEntity, any>[] {\n return [\n {\n id: 'select',\n header: CheckBoxHeader,\n cell: CheckBoxCell,\n maxSize: 50,\n },\n columnHelper.accessor('entityId', {\n header: 'ID',\n }),\n columnHelper.accessor('entityName', {\n header: 'Name',\n }),\n columnHelper.accessor('entityType', {\n header: 'Entity Type',\n cell: info => entityTypeToFriendlyName(info.getValue()),\n }),\n columnHelper.accessor('originalParentId', {\n header: 'Location',\n cell: info => (\n <>\n {info.getValue() && <EntityLink entity={info.getValue()} />} (\n {info.getValue()})\n </>\n ),\n size: 200,\n }),\n columnHelper.accessor('deletedOn', {\n header: 'Deleted On',\n cell: info => formatDate(dayjs(info.getValue())),\n }),\n {\n id: 'restoreButton',\n header: '',\n cell: ({ row }) => (\n <Button\n size=\"small\"\n variant=\"outlined\"\n onClick={() => {\n onRestore(row.original.entityId)\n row.toggleSelected(false)\n }}\n >\n Restore\n </Button>\n ),\n maxSize: 100,\n },\n ]\n}\n\nexport function TrashCanList() {\n const [showDeleteConfirmation, setShowDeleteConfirmation] = useState(false)\n const [errors, setErrors] = useState<SynapseClientError[]>([])\n const [rowSelection, setRowSelection] = useState<RowSelectionState>({})\n\n /**\n * When a mutation operation settles, update the list of errors and clear the selected set\n */\n function onMutateSettled(\n results?: PromiseSettledResult<void>[],\n error?: SynapseClientError | null,\n ) {\n if (results) {\n setErrors(toSynapseClientErrorList(results))\n } else if (error) {\n setErrors([error])\n }\n setRowSelection({})\n }\n\n const { mutate: restore, isPending: isPendingRestore } = useRestoreEntities({\n onSettled: onMutateSettled,\n })\n const { mutate: purge, isPending: isPendingPurge } = usePurgeEntities({\n onSettled: onMutateSettled,\n })\n\n const isMutating = isPendingRestore || isPendingPurge\n\n const { data, isLoading, hasNextPage, fetchNextPage, isFetchingNextPage } =\n useGetItemsInTrashCanInfinite({\n throwOnError: true,\n })\n const items = useMemo(\n () => data?.pages.flatMap(page => page.results) ?? [],\n [data],\n )\n\n const columns = useMemo<ColumnDef<TrashedEntity, any>[]>(\n () =>\n getTrashCanColumns(entityId => {\n restore(entityId)\n }),\n [restore],\n )\n\n const table: Table<TrashedEntity> = useReactTable<TrashedEntity>({\n data: items,\n columns,\n state: {\n rowSelection: rowSelection,\n },\n getRowId: row => row.entityId,\n enableRowSelection: true,\n onRowSelectionChange: setRowSelection,\n getCoreRowModel: getCoreRowModel(),\n columnResizeMode: 'onChange',\n })\n\n const selectedEntityIds = table\n .getSelectedRowModel()\n .rows.map(row => row.original.entityId)\n\n return (\n <div>\n <BlockingLoader\n show={isMutating}\n headlineText={isPendingPurge ? 'Deleting...' : 'Restoring...'}\n />\n <Typography variant=\"body1\">\n The trash can contains items that were recently deleted. You can recover\n deleted items in the trash can by clicking &quot;Restore&quot;. Items\n will remain in the trash can for 30 days before being automatically\n purged.\n </Typography>\n <WarningDialog\n title=\"Delete selected items from your Trash?\"\n content={\n <Typography variant=\"body1\">\n You can&apos;t undo this action.\n </Typography>\n }\n confirmButtonText=\"Delete\"\n confirmButtonColor=\"error\"\n onConfirm={() => {\n purge(selectedEntityIds)\n setShowDeleteConfirmation(false)\n }}\n onCancel={() => {\n setShowDeleteConfirmation(false)\n }}\n open={showDeleteConfirmation}\n />\n {isLoading && <SynapseSpinner />}\n {!isLoading && items.length === 0 && (\n <Alert severity={'info'} sx={{ my: 2 }}>\n <Typography variant=\"body1\">\n Your trash can is currently empty.\n </Typography>\n </Alert>\n )}\n {!isLoading && items.length > 0 && (\n <>\n <StyledTanStackTable\n table={table}\n styledTableContainerProps={{ sx: { my: 4 } }}\n />\n {errors.length > 0 && (\n <Alert severity={'error'} sx={{ mb: 1 }}>\n The following errors were encountered:\n <ul style={{ marginBottom: 0 }}>\n {errors.map(error => (\n <li key={error.message}>{error.message}</li>\n ))}\n </ul>\n </Alert>\n )}\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'flex-end',\n gap: 2,\n }}\n >\n {hasNextPage && (\n <Button\n variant=\"contained\"\n disabled={isFetchingNextPage}\n onClick={() => {\n fetchNextPage()\n }}\n >\n Load More\n </Button>\n )}\n <div style={{ margin: 'auto' }} />\n <Button\n variant=\"contained\"\n color=\"error\"\n disabled={selectedEntityIds.length === 0}\n onClick={() => {\n setShowDeleteConfirmation(true)\n }}\n >\n Delete Selected\n </Button>\n <Button\n variant=\"outlined\"\n disabled={selectedEntityIds.length === 0}\n onClick={() => {\n restore(selectedEntityIds)\n }}\n >\n Restore Selected\n </Button>\n </Box>\n </>\n )}\n </div>\n )\n}\n\nexport default TrashCanList\n"],"mappings":";;;;;;;;;;;;;;AAgCA,SAAS,EACP,GACsB;AACtB,QAAO,EACJ,QACE,MAA4C,EAAO,WAAW,WAChE,CACA,KAAI,MAAU,EAAO,OAA6B;;AAGvD,IAAM,IAAe,GAAmC;AAExD,SAAS,EACP,GACiC;AACjC,QAAO;EACL;GACE,IAAI;GACJ,QAAQ;GACR,MAAM;GACN,SAAS;GACV;EACD,EAAa,SAAS,YAAY,EAChC,QAAQ,MACT,CAAC;EACF,EAAa,SAAS,cAAc,EAClC,QAAQ,QACT,CAAC;EACF,EAAa,SAAS,cAAc;GAClC,QAAQ;GACR,OAAM,MAAQ,EAAyB,EAAK,UAAU,CAAC;GACxD,CAAC;EACF,EAAa,SAAS,oBAAoB;GACxC,QAAQ;GACR,OAAM,MACJ,kBAAA,GAAA,EAAA,UAAA;IACG,EAAK,UAAU,IAAI,kBAAC,GAAD,EAAY,QAAQ,EAAK,UAAU,EAAI,CAAA;IAAC;IAC3D,EAAK,UAAU;IAAC;IAChB,EAAA,CAAA;GAEL,MAAM;GACP,CAAC;EACF,EAAa,SAAS,aAAa;GACjC,QAAQ;GACR,OAAM,MAAQ,EAAW,EAAM,EAAK,UAAU,CAAC,CAAC;GACjD,CAAC;EACF;GACE,IAAI;GACJ,QAAQ;GACR,OAAO,EAAE,aACP,kBAAC,GAAD;IACE,MAAK;IACL,SAAQ;IACR,eAAe;AAEb,KADA,EAAU,EAAI,SAAS,SAAS,EAChC,EAAI,eAAe,GAAM;;cAE5B;IAEQ,CAAA;GAEX,SAAS;GACV;EACF;;AAGH,SAAgB,IAAe;CAC7B,IAAM,CAAC,GAAwB,KAA6B,EAAS,GAAM,EACrE,CAAC,GAAQ,KAAa,EAA+B,EAAE,CAAC,EACxD,CAAC,GAAc,KAAmB,EAA4B,EAAE,CAAC;CAKvE,SAAS,EACP,GACA,GACA;AAMA,EALI,IACF,EAAU,EAAyB,EAAQ,CAAC,GACnC,KACT,EAAU,CAAC,EAAM,CAAC,EAEpB,EAAgB,EAAE,CAAC;;CAGrB,IAAM,EAAE,QAAQ,GAAS,WAAW,MAAqB,EAAmB,EAC1E,WAAW,GACZ,CAAC,EACI,EAAE,QAAQ,GAAO,WAAW,MAAmB,EAAiB,EACpE,WAAW,GACZ,CAAC,EAEI,IAAa,KAAoB,GAEjC,EAAE,SAAM,cAAW,gBAAa,kBAAe,0BACnD,EAA8B,EAC5B,cAAc,IACf,CAAC,EACE,IAAQ,QACN,GAAM,MAAM,SAAQ,MAAQ,EAAK,QAAQ,IAAI,EAAE,EACrD,CAAC,EAAK,CACP,EAUK,IAA8B,EAA6B;EAC/D,MAAM;EACN,SAVc,QAEZ,GAAmB,MAAY;AAC7B,KAAQ,EAAS;IACjB,EACJ,CAAC,EAAQ,CACV;EAKC,OAAO,EACS,iBACf;EACD,WAAU,MAAO,EAAI;EACrB,oBAAoB;EACpB,sBAAsB;EACtB,iBAAiB,GAAiB;EAClC,kBAAkB;EACnB,CAAC,EAEI,IAAoB,EACvB,qBAAqB,CACrB,KAAK,KAAI,MAAO,EAAI,SAAS,SAAS;AAEzC,QACE,kBAAC,OAAD,EAAA,UAAA;EACE,kBAAC,GAAD;GACE,MAAM;GACN,cAAc,IAAiB,gBAAgB;GAC/C,CAAA;EACF,kBAAC,GAAD;GAAY,SAAQ;aAAQ;GAKf,CAAA;EACb,kBAAC,GAAD;GACE,OAAM;GACN,SACE,kBAAC,GAAD;IAAY,SAAQ;cAAQ;IAEf,CAAA;GAEf,mBAAkB;GAClB,oBAAmB;GACnB,iBAAiB;AAEf,IADA,EAAM,EAAkB,EACxB,EAA0B,GAAM;;GAElC,gBAAgB;AACd,MAA0B,GAAM;;GAElC,MAAM;GACN,CAAA;EACD,KAAa,kBAAC,GAAD,EAAkB,CAAA;EAC/B,CAAC,KAAa,EAAM,WAAW,KAC9B,kBAAC,GAAD;GAAO,UAAU;GAAQ,IAAI,EAAE,IAAI,GAAG;aACpC,kBAAC,GAAD;IAAY,SAAQ;cAAQ;IAEf,CAAA;GACP,CAAA;EAET,CAAC,KAAa,EAAM,SAAS,KAC5B,kBAAA,GAAA,EAAA,UAAA;GACE,kBAAC,GAAD;IACS;IACP,2BAA2B,EAAE,IAAI,EAAE,IAAI,GAAG,EAAE;IAC5C,CAAA;GACD,EAAO,SAAS,KACf,kBAAC,GAAD;IAAO,UAAU;IAAS,IAAI,EAAE,IAAI,GAAG;cAAvC,CAAyC,0CAEvC,kBAAC,MAAD;KAAI,OAAO,EAAE,cAAc,GAAG;eAC3B,EAAO,KAAI,MACV,kBAAC,MAAD,EAAA,UAAyB,EAAM,SAAa,EAAnC,EAAM,QAA6B,CAC5C;KACC,CAAA,CACC;;GAEV,kBAAC,GAAD;IACE,IAAI;KACF,SAAS;KACT,gBAAgB;KAChB,KAAK;KACN;cALH;KAOG,KACC,kBAAC,GAAD;MACE,SAAQ;MACR,UAAU;MACV,eAAe;AACb,UAAe;;gBAElB;MAEQ,CAAA;KAEX,kBAAC,OAAD,EAAK,OAAO,EAAE,QAAQ,QAAQ,EAAI,CAAA;KAClC,kBAAC,GAAD;MACE,SAAQ;MACR,OAAM;MACN,UAAU,EAAkB,WAAW;MACvC,eAAe;AACb,SAA0B,GAAK;;gBAElC;MAEQ,CAAA;KACT,kBAAC,GAAD;MACE,SAAQ;MACR,UAAU,EAAkB,WAAW;MACvC,eAAe;AACb,SAAQ,EAAkB;;gBAE7B;MAEQ,CAAA;KACL;;GACL,EAAA,CAAA;EAED,EAAA,CAAA"}
1
+ {"version":3,"file":"TrashCanList.js","names":[],"sources":["../../../src/components/trash/TrashCanList.tsx"],"sourcesContent":["import {\n useGetItemsInTrashCanInfinite,\n usePurgeEntities,\n useRestoreEntities,\n} from '@/synapse-queries/trash/useTrashCan'\nimport { formatDate } from '@/utils/functions/DateFormatter'\nimport { entityTypeToFriendlyName } from '@/utils/functions/EntityTypeUtils'\nimport { Alert, Box, Button, Typography } from '@mui/material'\nimport { SynapseClientError } from '@sage-bionetworks/synapse-client/util/SynapseClientError'\nimport { TrashedEntity } from '@sage-bionetworks/synapse-types'\nimport {\n ColumnDef,\n createColumnHelper,\n getCoreRowModel,\n RowSelectionState,\n Table,\n useReactTable,\n} from '@tanstack/react-table'\nimport dayjs from 'dayjs'\nimport { useMemo, useState } from 'react'\nimport {\n CheckBoxCell,\n CheckBoxHeader,\n} from '../EntityHeaderTable/EntityHeaderTableCellRenderers'\nimport { EntityLink } from '../EntityLink'\nimport { BlockingLoader, SynapseSpinner } from '../LoadingScreen/LoadingScreen'\nimport WarningDialog from '../SynapseForm/WarningDialog'\nimport StyledTanStackTable from '../TanStackTable/StyledTanStackTable'\n\n/**\n * Convert an array of Promise results to an array of errors\n */\nfunction toSynapseClientErrorList(\n results: PromiseSettledResult<void>[],\n): SynapseClientError[] {\n return results\n .filter(\n (result): result is PromiseRejectedResult => result.status === 'rejected',\n )\n .map(result => result.reason as SynapseClientError)\n}\n\nconst columnHelper = createColumnHelper<TrashedEntity>()\n\nfunction getTrashCanColumns(\n onRestore: (entityId: string) => void,\n): ColumnDef<TrashedEntity, any>[] {\n return [\n {\n id: 'select',\n header: CheckBoxHeader,\n cell: CheckBoxCell,\n maxSize: 50,\n },\n columnHelper.accessor('entityId', {\n header: 'ID',\n }),\n columnHelper.accessor('entityName', {\n header: 'Name',\n }),\n columnHelper.accessor('entityType', {\n header: 'Entity Type',\n cell: info => entityTypeToFriendlyName(info.getValue()),\n }),\n columnHelper.accessor('originalParentId', {\n header: 'Location',\n cell: info => (\n <>\n {info.getValue() && <EntityLink entity={info.getValue()} />} (\n {info.getValue()})\n </>\n ),\n size: 200,\n }),\n columnHelper.accessor('deletedOn', {\n header: 'Deleted On',\n cell: info => formatDate(dayjs(info.getValue())),\n }),\n {\n id: 'restoreButton',\n header: '',\n cell: ({ row }) => (\n <Button\n size=\"small\"\n variant=\"outlined\"\n onClick={() => {\n onRestore(row.original.entityId)\n row.toggleSelected(false)\n }}\n >\n Restore\n </Button>\n ),\n maxSize: 100,\n },\n ]\n}\n\nexport function TrashCanList() {\n const [showDeleteConfirmation, setShowDeleteConfirmation] = useState(false)\n const [errors, setErrors] = useState<SynapseClientError[]>([])\n const [rowSelection, setRowSelection] = useState<RowSelectionState>({})\n\n /**\n * When a mutation operation settles, update the list of errors and clear the selected set\n */\n function onMutateSettled(\n results?: PromiseSettledResult<void>[],\n error?: SynapseClientError | null,\n ) {\n if (results) {\n setErrors(toSynapseClientErrorList(results))\n } else if (error) {\n setErrors([error])\n }\n setRowSelection({})\n }\n\n const { mutate: restore, isPending: isPendingRestore } = useRestoreEntities({\n onSettled: onMutateSettled,\n })\n const { mutate: purge, isPending: isPendingPurge } = usePurgeEntities({\n onSettled: onMutateSettled,\n })\n\n const isMutating = isPendingRestore || isPendingPurge\n\n const { data, isLoading, hasNextPage, fetchNextPage, isFetchingNextPage } =\n useGetItemsInTrashCanInfinite({\n throwOnError: true,\n })\n const items = useMemo(\n () => data?.pages.flatMap(page => page.results) ?? [],\n [data],\n )\n\n const columns = useMemo<ColumnDef<TrashedEntity, any>[]>(\n () =>\n getTrashCanColumns(entityId => {\n restore(entityId)\n }),\n [restore],\n )\n\n const table: Table<TrashedEntity> = useReactTable<TrashedEntity>({\n data: items,\n columns,\n state: {\n rowSelection: rowSelection,\n },\n getRowId: row => row.entityId,\n enableRowSelection: true,\n onRowSelectionChange: setRowSelection,\n getCoreRowModel: getCoreRowModel(),\n columnResizeMode: 'onChange',\n })\n\n const selectedEntityIds = table\n .getSelectedRowModel()\n .rows.map(row => row.original.entityId)\n\n return (\n <div>\n <BlockingLoader\n show={isMutating}\n headlineText={isPendingPurge ? 'Deleting...' : 'Restoring...'}\n />\n <Typography variant=\"body1\">\n The trash can contains items that were recently deleted. You can recover\n deleted items in the trash can by clicking &quot;Restore&quot;. Items\n will remain in the trash can for 30 days before being automatically\n purged.\n </Typography>\n <WarningDialog\n title=\"Delete selected items from your Trash?\"\n content={\n <Typography variant=\"body1\">\n You can&apos;t undo this action.\n </Typography>\n }\n confirmButtonText=\"Delete\"\n confirmButtonColor=\"error\"\n onConfirm={() => {\n purge(selectedEntityIds)\n setShowDeleteConfirmation(false)\n }}\n onCancel={() => {\n setShowDeleteConfirmation(false)\n }}\n open={showDeleteConfirmation}\n />\n {isLoading && <SynapseSpinner />}\n {!isLoading && items.length === 0 && (\n <Alert severity={'info'} sx={{ my: 2 }}>\n <Typography variant=\"body1\">\n Your trash can is currently empty.\n </Typography>\n </Alert>\n )}\n {!isLoading && items.length > 0 && (\n <>\n <StyledTanStackTable\n table={table}\n styledTableContainerProps={{ sx: { my: 4 } }}\n />\n {errors.length > 0 && (\n <Alert severity={'error'} sx={{ mb: 1 }}>\n The following errors were encountered:\n <ul style={{ marginBottom: 0 }}>\n {errors.map(error => (\n <li key={error.message}>{error.message}</li>\n ))}\n </ul>\n </Alert>\n )}\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'flex-end',\n gap: 2,\n }}\n >\n {hasNextPage && (\n <Button\n variant=\"contained\"\n disabled={isFetchingNextPage}\n onClick={() => {\n fetchNextPage()\n }}\n >\n Load More\n </Button>\n )}\n <div style={{ margin: 'auto' }} />\n <Button\n variant=\"contained\"\n color=\"error\"\n disabled={selectedEntityIds.length === 0}\n onClick={() => {\n setShowDeleteConfirmation(true)\n }}\n >\n Delete Selected\n </Button>\n <Button\n variant=\"outlined\"\n disabled={selectedEntityIds.length === 0}\n onClick={() => {\n restore(selectedEntityIds)\n }}\n >\n Restore Selected\n </Button>\n </Box>\n </>\n )}\n </div>\n )\n}\n\nexport default TrashCanList\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"FileHandleLink.js","names":[],"sources":["../../../src/components/widgets/FileHandleLink.tsx"],"sourcesContent":["import React from 'react'\nimport SynapseClient from '@/synapse-client'\nimport { SynapseConstants } from '@/utils'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport {\n BatchFileRequest,\n BatchFileResult,\n FileHandleAssociation,\n} from '@sage-bionetworks/synapse-types'\nimport { useEffect, useState } from 'react'\nimport IconSvg from '../IconSvg/IconSvg'\n\ntype FileHandleLinkProps = {\n fileHandleAssociation: FileHandleAssociation\n redirect?: boolean\n showDownloadIcon: boolean\n displayValue?: string\n}\nexport const FileHandleLink = (props: FileHandleLinkProps): React.ReactNode => {\n const {\n fileHandleAssociation,\n showDownloadIcon,\n redirect = false,\n displayValue,\n } = props\n const { accessToken } = useSynapseContext()\n\n const [batchFileResult, setBatchFileResult] = useState<\n BatchFileResult | undefined\n >()\n\n useEffect(() => {\n if (displayValue === undefined) {\n const getFiles = async () => {\n const batchFileRequest: BatchFileRequest = {\n requestedFiles: [fileHandleAssociation],\n includeFileHandles: true,\n includePreSignedURLs: false,\n includePreviewPreSignedURLs: false,\n }\n setBatchFileResult(\n await SynapseClient.getFiles(batchFileRequest, accessToken),\n )\n }\n getFiles()\n }\n }, [accessToken, displayValue, fileHandleAssociation])\n\n let fileName: string | undefined = undefined\n if (batchFileResult) {\n fileName = batchFileResult.requestedFiles[0].fileHandle?.fileName\n }\n\n return (\n <button\n onClick={() => {\n if (accessToken && fileHandleAssociation) {\n SynapseClient.getActualFileHandleByIdURL(\n fileHandleAssociation.fileHandleId,\n accessToken,\n fileHandleAssociation.associateObjectType,\n fileHandleAssociation.associateObjectId,\n redirect,\n )\n .then(url => {\n window.open(url, '_blank')\n })\n .catch(err => {\n console.error('Error on retrieving file handle url ', err)\n })\n }\n }}\n className={`SRC-primary-text-color ${SynapseConstants.SRC_SIGN_IN_CLASS}`}\n type=\"button\"\n style={{ padding: 0 }}\n >\n {displayValue ?? fileName ?? fileHandleAssociation.fileHandleId}\n {showDownloadIcon && <IconSvg icon=\"download\" />}\n </button>\n )\n}\n"],"mappings":";;;;;;;;AAkBA,IAAa,KAAkB,MAAgD;CAC7E,IAAM,EACJ,0BACA,qBACA,cAAW,IACX,oBACE,GACE,EAAE,mBAAgB,GAAmB,EAErC,CAAC,GAAiB,KAAsB,GAE3C;AAEH,SAAgB;AACd,EAAI,MAAiB,KAAA,MACF,YAAY;GAC3B,IAAM,IAAqC;IACzC,gBAAgB,CAAC,EAAsB;IACvC,oBAAoB;IACpB,sBAAsB;IACtB,6BAA6B;IAC9B;AACD,KACE,MAAM,EAAc,SAAS,GAAkB,EAAY,CAC5D;MAEO;IAEX;EAAC;EAAa;EAAc;EAAsB,CAAC;CAEtD,IAAI;AAKJ,QAJI,MACF,IAAW,EAAgB,eAAe,GAAG,YAAY,WAIzD,kBAAC,UAAD;EACE,eAAe;AACb,GAAI,KAAe,KACjB,EAAc,2BACZ,EAAsB,cACtB,GACA,EAAsB,qBACtB,EAAsB,mBACtB,EACD,CACE,MAAK,MAAO;AACX,WAAO,KAAK,GAAK,SAAS;KAC1B,CACD,OAAM,MAAO;AACZ,YAAQ,MAAM,wCAAwC,EAAI;KAC1D;;EAGR,WAAW,0BAA0B;EACrC,MAAK;EACL,OAAO,EAAE,SAAS,GAAG;YApBvB,CAsBG,KAAgB,KAAY,EAAsB,cAClD,KAAoB,kBAAC,GAAD,EAAS,MAAK,YAAa,CAAA,CACzC"}
1
+ {"version":3,"file":"FileHandleLink.js","names":[],"sources":["../../../src/components/widgets/FileHandleLink.tsx"],"sourcesContent":["import React from 'react'\nimport SynapseClient from '@/synapse-client'\nimport { SynapseConstants } from '@/utils'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport {\n BatchFileRequest,\n BatchFileResult,\n FileHandleAssociation,\n} from '@sage-bionetworks/synapse-types'\nimport { useEffect, useState } from 'react'\nimport IconSvg from '../IconSvg/IconSvg'\n\ntype FileHandleLinkProps = {\n fileHandleAssociation: FileHandleAssociation\n redirect?: boolean\n showDownloadIcon: boolean\n displayValue?: string\n}\nexport const FileHandleLink = (props: FileHandleLinkProps): React.ReactNode => {\n const {\n fileHandleAssociation,\n showDownloadIcon,\n redirect = false,\n displayValue,\n } = props\n const { accessToken } = useSynapseContext()\n\n const [batchFileResult, setBatchFileResult] = useState<\n BatchFileResult | undefined\n >()\n\n useEffect(() => {\n if (displayValue === undefined) {\n const getFiles = async () => {\n const batchFileRequest: BatchFileRequest = {\n requestedFiles: [fileHandleAssociation],\n includeFileHandles: true,\n includePreSignedURLs: false,\n includePreviewPreSignedURLs: false,\n }\n setBatchFileResult(\n await SynapseClient.getFiles(batchFileRequest, accessToken),\n )\n }\n getFiles()\n }\n }, [accessToken, displayValue, fileHandleAssociation])\n\n let fileName: string | undefined = undefined\n if (batchFileResult) {\n fileName = batchFileResult.requestedFiles[0].fileHandle?.fileName\n }\n\n return (\n <button\n onClick={() => {\n if (accessToken && fileHandleAssociation) {\n SynapseClient.getActualFileHandleByIdURL(\n fileHandleAssociation.fileHandleId,\n accessToken,\n fileHandleAssociation.associateObjectType,\n fileHandleAssociation.associateObjectId,\n redirect,\n )\n .then(url => {\n window.open(url, '_blank')\n })\n .catch(err => {\n console.error('Error on retrieving file handle url ', err)\n })\n }\n }}\n className={`SRC-primary-text-color ${SynapseConstants.SRC_SIGN_IN_CLASS}`}\n type=\"button\"\n style={{ padding: 0 }}\n >\n {displayValue ?? fileName ?? fileHandleAssociation.fileHandleId}\n {showDownloadIcon && <IconSvg icon=\"download\" />}\n </button>\n )\n}\n"],"mappings":";;;;;;;;AAkBA,IAAa,KAAkB,MAAgD;CAC7E,IAAM,EACJ,0BACA,qBACA,cAAW,IACX,oBACE,GACE,EAAE,mBAAgB,GAAmB,EAErC,CAAC,GAAiB,KAAsB,GAE3C;AAEH,SAAgB;AACd,EAAI,MAAiB,KAAA,MAYnB,YAX6B;GAC3B,IAAM,IAAqC;IACzC,gBAAgB,CAAC,EAAsB;IACvC,oBAAoB;IACpB,sBAAsB;IACtB,6BAA6B;IAC9B;AACD,KACE,MAAM,EAAc,SAAS,GAAkB,EAAY,CAC5D;MAEO;IAEX;EAAC;EAAa;EAAc;EAAsB,CAAC;CAEtD,IAAI;AAKJ,QAJI,MACF,IAAW,EAAgB,eAAe,GAAG,YAAY,WAIzD,kBAAC,UAAD;EACE,eAAe;AACb,GAAI,KAAe,KACjB,EAAc,2BACZ,EAAsB,cACtB,GACA,EAAsB,qBACtB,EAAsB,mBACtB,EACD,CACE,MAAK,MAAO;AACX,WAAO,KAAK,GAAK,SAAS;KAC1B,CACD,OAAM,MAAO;AACZ,YAAQ,MAAM,wCAAwC,EAAI;KAC1D;;EAGR,WAAW,0BAA0B;EACrC,MAAK;EACL,OAAO,EAAE,SAAS,GAAG;YApBvB,CAsBG,KAAgB,KAAY,EAAsB,cAClD,KAAoB,kBAAC,GAAD,EAAS,MAAK,YAAa,CAAA,CACzC"}
@@ -1 +1 @@
1
- {"version":3,"file":"RangeSlider.js","names":[],"sources":["../../../../src/components/widgets/RangeSlider/RangeSlider.tsx"],"sourcesContent":["import { RangeValues } from '../Range'\nimport { PropsWithChildren, useState } from 'react'\nimport {\n Box,\n Button,\n Slider,\n SliderValueLabelProps,\n Tooltip,\n Typography,\n} from '@mui/material'\n\nexport type RangeSliderProps = PropsWithChildren<{\n domain: string[]\n initialValues: RangeValues\n step: number\n onChange?: (values: RangeValues) => void\n onApplyClicked?: (values: RangeValues) => void\n}>\n\nfunction ValueLabelComponent(props: SliderValueLabelProps) {\n const { children, value } = props\n\n return (\n <Tooltip enterTouchDelay={0} placement=\"top\" title={value}>\n {children}\n </Tooltip>\n )\n}\n\nfunction getInitialValues(initialValues: RangeValues, domain: string[]) {\n const result = [\n initialValues.min ? Number(initialValues.min) : Number(domain[0]),\n initialValues.max ? Number(initialValues.max) : Number(domain[1]),\n ]\n return result\n}\n\nfunction RangeSlider(props: RangeSliderProps) {\n const { onApplyClicked, onChange, step } = props\n const stringArrToNumArr = (inputArr: string[]) =>\n inputArr.map(value => Number(value))\n\n const [values, setValues] = useState<number[]>(() =>\n getInitialValues(props.initialValues, props.domain),\n )\n\n const numDomain = stringArrToNumArr(props.domain)\n\n const handleSliderChange = (values: readonly number[]) => {\n setValues([...values])\n if (onChange) {\n onChange({ min: values[0], max: values[1] })\n }\n }\n\n return (\n <Box sx={{ ml: 1 }}>\n <Typography variant=\"smallText1\">\n {values[0]} - {values[1]}\n </Typography>\n <Box\n sx={{\n display: 'flex',\n gap: 3,\n ml: 1,\n }}\n >\n <Slider\n marks={[\n { value: numDomain[0], label: props.domain[0] },\n { value: numDomain[1], label: props.domain[1] },\n ]}\n min={numDomain[0]}\n max={numDomain[1]}\n value={values}\n onChange={(_, newValues) => handleSliderChange(newValues)}\n step={step}\n valueLabelDisplay=\"auto\"\n slots={{\n valueLabel: ValueLabelComponent,\n }}\n />\n {onApplyClicked && (\n <Box>\n <Button\n size=\"small\"\n variant=\"outlined\"\n onClick={() => onApplyClicked({ min: values[0], max: values[1] })}\n sx={{ fontSize: 16 }}\n >\n Apply\n </Button>\n </Box>\n )}\n </Box>\n </Box>\n )\n}\n\nexport default RangeSlider\n"],"mappings":";;;;AAmBA,SAAS,EAAoB,GAA8B;CACzD,IAAM,EAAE,aAAU,aAAU;AAE5B,QACE,kBAAC,GAAD;EAAS,iBAAiB;EAAG,WAAU;EAAM,OAAO;EACjD;EACO,CAAA;;AAId,SAAS,EAAiB,GAA4B,GAAkB;AAKtE,QAJe,CACb,EAAc,MAAM,OAAO,EAAc,IAAI,GAAG,OAAO,EAAO,GAAG,EACjE,EAAc,MAAM,OAAO,EAAc,IAAI,GAAG,OAAO,EAAO,GAAG,CAClE;;AAIH,SAAS,EAAY,GAAyB;CAC5C,IAAM,EAAE,mBAAgB,aAAU,YAAS,GACrC,KAAqB,MACzB,EAAS,KAAI,MAAS,OAAO,EAAM,CAAC,EAEhC,CAAC,GAAQ,KAAa,QAC1B,EAAiB,EAAM,eAAe,EAAM,OAAO,CACpD,EAEK,IAAY,EAAkB,EAAM,OAAO,EAE3C,KAAsB,MAA8B;AAExD,EADA,EAAU,CAAC,GAAG,EAAO,CAAC,EAClB,KACF,EAAS;GAAE,KAAK,EAAO;GAAI,KAAK,EAAO;GAAI,CAAC;;AAIhD,QACE,kBAAC,GAAD;EAAK,IAAI,EAAE,IAAI,GAAG;YAAlB,CACE,kBAAC,GAAD;GAAY,SAAQ;aAApB;IACG,EAAO;IAAG;IAAI,EAAO;IACX;MACb,kBAAC,GAAD;GACE,IAAI;IACF,SAAS;IACT,KAAK;IACL,IAAI;IACL;aALH,CAOE,kBAAC,GAAD;IACE,OAAO,CACL;KAAE,OAAO,EAAU;KAAI,OAAO,EAAM,OAAO;KAAI,EAC/C;KAAE,OAAO,EAAU;KAAI,OAAO,EAAM,OAAO;KAAI,CAChD;IACD,KAAK,EAAU;IACf,KAAK,EAAU;IACf,OAAO;IACP,WAAW,GAAG,MAAc,EAAmB,EAAU;IACnD;IACN,mBAAkB;IAClB,OAAO,EACL,YAAY,GACb;IACD,CAAA,EACD,KACC,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;IACE,MAAK;IACL,SAAQ;IACR,eAAe,EAAe;KAAE,KAAK,EAAO;KAAI,KAAK,EAAO;KAAI,CAAC;IACjE,IAAI,EAAE,UAAU,IAAI;cACrB;IAEQ,CAAA,EACL,CAAA,CAEJ;KACF"}
1
+ {"version":3,"file":"RangeSlider.js","names":[],"sources":["../../../../src/components/widgets/RangeSlider/RangeSlider.tsx"],"sourcesContent":["import { RangeValues } from '../Range'\nimport { PropsWithChildren, useState } from 'react'\nimport {\n Box,\n Button,\n Slider,\n SliderValueLabelProps,\n Tooltip,\n Typography,\n} from '@mui/material'\n\nexport type RangeSliderProps = PropsWithChildren<{\n domain: string[]\n initialValues: RangeValues\n step: number\n onChange?: (values: RangeValues) => void\n onApplyClicked?: (values: RangeValues) => void\n}>\n\nfunction ValueLabelComponent(props: SliderValueLabelProps) {\n const { children, value } = props\n\n return (\n <Tooltip enterTouchDelay={0} placement=\"top\" title={value}>\n {children}\n </Tooltip>\n )\n}\n\nfunction getInitialValues(initialValues: RangeValues, domain: string[]) {\n const result = [\n initialValues.min ? Number(initialValues.min) : Number(domain[0]),\n initialValues.max ? Number(initialValues.max) : Number(domain[1]),\n ]\n return result\n}\n\nfunction RangeSlider(props: RangeSliderProps) {\n const { onApplyClicked, onChange, step } = props\n const stringArrToNumArr = (inputArr: string[]) =>\n inputArr.map(value => Number(value))\n\n const [values, setValues] = useState<number[]>(() =>\n getInitialValues(props.initialValues, props.domain),\n )\n\n const numDomain = stringArrToNumArr(props.domain)\n\n const handleSliderChange = (values: readonly number[]) => {\n setValues([...values])\n if (onChange) {\n onChange({ min: values[0], max: values[1] })\n }\n }\n\n return (\n <Box sx={{ ml: 1 }}>\n <Typography variant=\"smallText1\">\n {values[0]} - {values[1]}\n </Typography>\n <Box\n sx={{\n display: 'flex',\n gap: 3,\n ml: 1,\n }}\n >\n <Slider\n marks={[\n { value: numDomain[0], label: props.domain[0] },\n { value: numDomain[1], label: props.domain[1] },\n ]}\n min={numDomain[0]}\n max={numDomain[1]}\n value={values}\n onChange={(_, newValues) => handleSliderChange(newValues)}\n step={step}\n valueLabelDisplay=\"auto\"\n slots={{\n valueLabel: ValueLabelComponent,\n }}\n />\n {onApplyClicked && (\n <Box>\n <Button\n size=\"small\"\n variant=\"outlined\"\n onClick={() => onApplyClicked({ min: values[0], max: values[1] })}\n sx={{ fontSize: 16 }}\n >\n Apply\n </Button>\n </Box>\n )}\n </Box>\n </Box>\n )\n}\n\nexport default RangeSlider\n"],"mappings":";;;;AAmBA,SAAS,EAAoB,GAA8B;CACzD,IAAM,EAAE,aAAU,aAAU;AAE5B,QACE,kBAAC,GAAD;EAAS,iBAAiB;EAAG,WAAU;EAAM,OAAO;EACjD;EACO,CAAA;;AAId,SAAS,EAAiB,GAA4B,GAAkB;AAKtE,QAAO,CAHL,EAAc,MAAM,OAAO,EAAc,IAAI,GAAG,OAAO,EAAO,GAAG,EACjE,EAAc,MAAM,OAAO,EAAc,IAAI,GAAG,OAAO,EAAO,GAAG,CAE5D;;AAGT,SAAS,EAAY,GAAyB;CAC5C,IAAM,EAAE,mBAAgB,aAAU,YAAS,GACrC,KAAqB,MACzB,EAAS,KAAI,MAAS,OAAO,EAAM,CAAC,EAEhC,CAAC,GAAQ,KAAa,QAC1B,EAAiB,EAAM,eAAe,EAAM,OAAO,CACpD,EAEK,IAAY,EAAkB,EAAM,OAAO,EAE3C,KAAsB,MAA8B;AAExD,EADA,EAAU,CAAC,GAAG,EAAO,CAAC,EAClB,KACF,EAAS;GAAE,KAAK,EAAO;GAAI,KAAK,EAAO;GAAI,CAAC;;AAIhD,QACE,kBAAC,GAAD;EAAK,IAAI,EAAE,IAAI,GAAG;YAAlB,CACE,kBAAC,GAAD;GAAY,SAAQ;aAApB;IACG,EAAO;IAAG;IAAI,EAAO;IACX;MACb,kBAAC,GAAD;GACE,IAAI;IACF,SAAS;IACT,KAAK;IACL,IAAI;IACL;aALH,CAOE,kBAAC,GAAD;IACE,OAAO,CACL;KAAE,OAAO,EAAU;KAAI,OAAO,EAAM,OAAO;KAAI,EAC/C;KAAE,OAAO,EAAU;KAAI,OAAO,EAAM,OAAO;KAAI,CAChD;IACD,KAAK,EAAU;IACf,KAAK,EAAU;IACf,OAAO;IACP,WAAW,GAAG,MAAc,EAAmB,EAAU;IACnD;IACN,mBAAkB;IAClB,OAAO,EACL,YAAY,GACb;IACD,CAAA,EACD,KACC,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;IACE,MAAK;IACL,SAAQ;IACR,eAAe,EAAe;KAAE,KAAK,EAAO;KAAI,KAAK,EAAO;KAAI,CAAC;IACjE,IAAI,EAAE,UAAU,IAAI;cACrB;IAEQ,CAAA,EACL,CAAA,CAEJ;KACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"SynapseVideo.js","names":[],"sources":["../../../src/components/widgets/SynapseVideo.tsx"],"sourcesContent":["import { getEntity, getFiles } from '@/synapse-client/SynapseClient'\nimport { SynapseConstants } from '@/utils'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport {\n BatchFileRequest,\n BatchFileResult,\n FileEntity,\n FileHandleAssociateType,\n FileHandleAssociation,\n} from '@sage-bionetworks/synapse-types'\nimport { useEffect, useState } from 'react'\n\nexport type SynapseVideoProps = {\n params: {\n width?: string\n height?: string\n videoId?: string\n vimeoId?: string\n oggSynapseId?: string\n mp4SynapseId?: string\n webmSynapseId?: string\n vttSynapseId?: string\n }\n}\n\nexport default function SynapseVideo({ params }: SynapseVideoProps) {\n const { accessToken, isAuthenticated } = useSynapseContext()\n const [externalVideoUrl, setExternalVideoUrl] = useState<string>()\n const [synapseVideoPresignedUrl, setSynapseVideoPresignedUrl] =\n useState<string>()\n const [synapseVideoVttPresignedUrl, setSynapseVideoVttPresignedUrl] =\n useState<string>()\n\n const videoWidth = params.width ?? ''\n const videoHeight = params.height ?? ''\n useEffect(() => {\n const getVideo = async () => {\n if (params.videoId)\n setExternalVideoUrl(`https://www.youtube.com/embed/${params.videoId}`)\n else if (params.vimeoId)\n setExternalVideoUrl(`https://player.vimeo.com/video/${params.vimeoId}`)\n else {\n const videoKey =\n params.oggSynapseId || params.mp4SynapseId || params.webmSynapseId\n\n const videoEntity = await getEntity<FileEntity>(accessToken, videoKey!)\n const fileHandleAssociationList: FileHandleAssociation[] = [\n {\n associateObjectId: videoKey!,\n associateObjectType: FileHandleAssociateType.FileEntity,\n fileHandleId: videoEntity.dataFileHandleId,\n },\n ]\n\n let vttFileHandleId: string | undefined\n if (params.vttSynapseId) {\n const vttEntity = await getEntity<FileEntity>(\n accessToken,\n params.vttSynapseId,\n )\n vttFileHandleId = vttEntity.dataFileHandleId\n fileHandleAssociationList.push({\n associateObjectId: params.vttSynapseId,\n associateObjectType: FileHandleAssociateType.FileEntity,\n fileHandleId: vttEntity.dataFileHandleId,\n })\n }\n\n getSynapseFiles(\n fileHandleAssociationList,\n videoEntity.dataFileHandleId,\n vttFileHandleId,\n )\n }\n }\n\n const getSynapseFiles = (\n fileHandleAssociationList: FileHandleAssociation[],\n videoFileHandleId: string,\n vttFileHandleId?: string,\n ) => {\n const request: BatchFileRequest = {\n includeFileHandles: false,\n includePreSignedURLs: true,\n includePreviewPreSignedURLs: false,\n requestedFiles: fileHandleAssociationList,\n }\n\n getFiles(request, accessToken)\n .then((data: BatchFileResult) => {\n const videoFile = data.requestedFiles.find(\n el => el.fileHandleId === videoFileHandleId,\n )\n if (videoFile?.preSignedURL) {\n setSynapseVideoPresignedUrl(videoFile.preSignedURL)\n }\n\n if (vttFileHandleId) {\n const vttFile = data.requestedFiles.find(\n el => el.fileHandleId === vttFileHandleId,\n )\n if (vttFile?.preSignedURL) {\n setSynapseVideoVttPresignedUrl(vttFile.preSignedURL)\n }\n }\n })\n .catch(err => {\n console.error('Error on getting video ', err)\n })\n }\n getVideo()\n }, [externalVideoUrl, params, accessToken, videoHeight, videoWidth])\n\n if (!isAuthenticated && !externalVideoUrl) {\n // if not logged in, show login button\n return (\n <p>\n You will need to\n <button\n data-testid=\"video-login\"\n className={`${SynapseConstants.SRC_SIGN_IN_CLASS} sign-in-btn default\n `}\n >\n Sign in\n </button>\n in for access to that resource.\n </p>\n )\n }\n if (synapseVideoPresignedUrl) {\n return (\n <video\n controls\n width={videoWidth}\n height={videoHeight}\n data-testid=\"synapse-video-url\"\n crossOrigin=\"anonymous\"\n >\n <source src={synapseVideoPresignedUrl} />\n {synapseVideoVttPresignedUrl && (\n <track src={synapseVideoVttPresignedUrl} kind=\"subtitles\" default />\n )}\n It does not support the HTML5 Video element.\n </video>\n )\n } else if (externalVideoUrl) {\n return (\n <iframe\n title=\"video frame\"\n src={externalVideoUrl}\n width={videoWidth}\n height={videoHeight}\n ></iframe>\n )\n } else {\n return <></>\n }\n}\n"],"mappings":";;;;;;;;AAyBA,SAAwB,EAAa,EAAE,aAA6B;CAClE,IAAM,EAAE,gBAAa,uBAAoB,GAAmB,EACtD,CAAC,GAAkB,KAAuB,GAAkB,EAC5D,CAAC,GAA0B,KAC/B,GAAkB,EACd,CAAC,GAA6B,KAClC,GAAkB,EAEd,IAAa,EAAO,SAAS,IAC7B,IAAc,EAAO,UAAU;AAyHnC,QAxHF,QAAgB;EACd,IAAM,IAAW,YAAY;AAC3B,OAAI,EAAO,QACT,GAAoB,iCAAiC,EAAO,UAAU;YAC/D,EAAO,QACd,GAAoB,kCAAkC,EAAO,UAAU;QACpE;IACH,IAAM,IACJ,EAAO,gBAAgB,EAAO,gBAAgB,EAAO,eAEjD,IAAc,MAAM,EAAsB,GAAa,EAAU,EACjE,IAAqD,CACzD;KACE,mBAAmB;KACnB,qBAAqB,EAAwB;KAC7C,cAAc,EAAY;KAC3B,CACF,EAEG;AACJ,QAAI,EAAO,cAAc;KACvB,IAAM,IAAY,MAAM,EACtB,GACA,EAAO,aACR;AAED,KADA,IAAkB,EAAU,kBAC5B,EAA0B,KAAK;MAC7B,mBAAmB,EAAO;MAC1B,qBAAqB,EAAwB;MAC7C,cAAc,EAAU;MACzB,CAAC;;AAGJ,MACE,GACA,EAAY,kBACZ,EACD;;KAIC,KACJ,GACA,GACA,MACG;AAQH,KAPkC;IAChC,oBAAoB;IACpB,sBAAsB;IACtB,6BAA6B;IAC7B,gBAAgB;IACjB,EAEiB,EAAY,CAC3B,MAAM,MAA0B;IAC/B,IAAM,IAAY,EAAK,eAAe,MACpC,MAAM,EAAG,iBAAiB,EAC3B;AAKD,QAJI,GAAW,gBACb,EAA4B,EAAU,aAAa,EAGjD,GAAiB;KACnB,IAAM,IAAU,EAAK,eAAe,MAClC,MAAM,EAAG,iBAAiB,EAC3B;AACD,KAAI,GAAS,gBACX,EAA+B,EAAQ,aAAa;;KAGxD,CACD,OAAM,MAAO;AACZ,YAAQ,MAAM,2BAA2B,EAAI;KAC7C;;AAEN,KAAU;IACT;EAAC;EAAkB;EAAQ;EAAa;EAAa;EAAW,CAAC,EAEhE,CAAC,KAAmB,CAAC,IAGrB,kBAAC,KAAD,EAAA,UAAA;EAAG;EAED,kBAAC,UAAD;GACE,eAAY;GACZ,WAAW,GAAG,EAAmC;;aAElD;GAEQ,CAAA;;EAEP,EAAA,CAAA,GAGJ,IAEA,kBAAC,SAAD;EACE,UAAA;EACA,OAAO;EACP,QAAQ;EACR,eAAY;EACZ,aAAY;YALd;GAOE,kBAAC,UAAD,EAAQ,KAAK,GAA4B,CAAA;GACxC,KACC,kBAAC,SAAD;IAAO,KAAK;IAA6B,MAAK;IAAY,SAAA;IAAU,CAAA;GACpE;GAEI;MAED,IAEP,kBAAC,UAAD;EACE,OAAM;EACN,KAAK;EACL,OAAO;EACP,QAAQ;EACA,CAAA,GAGL,kBAAA,GAAA,EAAK,CAAA"}
1
+ {"version":3,"file":"SynapseVideo.js","names":[],"sources":["../../../src/components/widgets/SynapseVideo.tsx"],"sourcesContent":["import { getEntity, getFiles } from '@/synapse-client/SynapseClient'\nimport { SynapseConstants } from '@/utils'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport {\n BatchFileRequest,\n BatchFileResult,\n FileEntity,\n FileHandleAssociateType,\n FileHandleAssociation,\n} from '@sage-bionetworks/synapse-types'\nimport { useEffect, useState } from 'react'\n\nexport type SynapseVideoProps = {\n params: {\n width?: string\n height?: string\n videoId?: string\n vimeoId?: string\n oggSynapseId?: string\n mp4SynapseId?: string\n webmSynapseId?: string\n vttSynapseId?: string\n }\n}\n\nexport default function SynapseVideo({ params }: SynapseVideoProps) {\n const { accessToken, isAuthenticated } = useSynapseContext()\n const [externalVideoUrl, setExternalVideoUrl] = useState<string>()\n const [synapseVideoPresignedUrl, setSynapseVideoPresignedUrl] =\n useState<string>()\n const [synapseVideoVttPresignedUrl, setSynapseVideoVttPresignedUrl] =\n useState<string>()\n\n const videoWidth = params.width ?? ''\n const videoHeight = params.height ?? ''\n useEffect(() => {\n const getVideo = async () => {\n if (params.videoId)\n setExternalVideoUrl(`https://www.youtube.com/embed/${params.videoId}`)\n else if (params.vimeoId)\n setExternalVideoUrl(`https://player.vimeo.com/video/${params.vimeoId}`)\n else {\n const videoKey =\n params.oggSynapseId || params.mp4SynapseId || params.webmSynapseId\n\n const videoEntity = await getEntity<FileEntity>(accessToken, videoKey!)\n const fileHandleAssociationList: FileHandleAssociation[] = [\n {\n associateObjectId: videoKey!,\n associateObjectType: FileHandleAssociateType.FileEntity,\n fileHandleId: videoEntity.dataFileHandleId,\n },\n ]\n\n let vttFileHandleId: string | undefined\n if (params.vttSynapseId) {\n const vttEntity = await getEntity<FileEntity>(\n accessToken,\n params.vttSynapseId,\n )\n vttFileHandleId = vttEntity.dataFileHandleId\n fileHandleAssociationList.push({\n associateObjectId: params.vttSynapseId,\n associateObjectType: FileHandleAssociateType.FileEntity,\n fileHandleId: vttEntity.dataFileHandleId,\n })\n }\n\n getSynapseFiles(\n fileHandleAssociationList,\n videoEntity.dataFileHandleId,\n vttFileHandleId,\n )\n }\n }\n\n const getSynapseFiles = (\n fileHandleAssociationList: FileHandleAssociation[],\n videoFileHandleId: string,\n vttFileHandleId?: string,\n ) => {\n const request: BatchFileRequest = {\n includeFileHandles: false,\n includePreSignedURLs: true,\n includePreviewPreSignedURLs: false,\n requestedFiles: fileHandleAssociationList,\n }\n\n getFiles(request, accessToken)\n .then((data: BatchFileResult) => {\n const videoFile = data.requestedFiles.find(\n el => el.fileHandleId === videoFileHandleId,\n )\n if (videoFile?.preSignedURL) {\n setSynapseVideoPresignedUrl(videoFile.preSignedURL)\n }\n\n if (vttFileHandleId) {\n const vttFile = data.requestedFiles.find(\n el => el.fileHandleId === vttFileHandleId,\n )\n if (vttFile?.preSignedURL) {\n setSynapseVideoVttPresignedUrl(vttFile.preSignedURL)\n }\n }\n })\n .catch(err => {\n console.error('Error on getting video ', err)\n })\n }\n getVideo()\n }, [externalVideoUrl, params, accessToken, videoHeight, videoWidth])\n\n if (!isAuthenticated && !externalVideoUrl) {\n // if not logged in, show login button\n return (\n <p>\n You will need to\n <button\n data-testid=\"video-login\"\n className={`${SynapseConstants.SRC_SIGN_IN_CLASS} sign-in-btn default\n `}\n >\n Sign in\n </button>\n in for access to that resource.\n </p>\n )\n }\n if (synapseVideoPresignedUrl) {\n return (\n <video\n controls\n width={videoWidth}\n height={videoHeight}\n data-testid=\"synapse-video-url\"\n crossOrigin=\"anonymous\"\n >\n <source src={synapseVideoPresignedUrl} />\n {synapseVideoVttPresignedUrl && (\n <track src={synapseVideoVttPresignedUrl} kind=\"subtitles\" default />\n )}\n It does not support the HTML5 Video element.\n </video>\n )\n } else if (externalVideoUrl) {\n return (\n <iframe\n title=\"video frame\"\n src={externalVideoUrl}\n width={videoWidth}\n height={videoHeight}\n ></iframe>\n )\n } else {\n return <></>\n }\n}\n"],"mappings":";;;;;;;;AAyBA,SAAwB,EAAa,EAAE,aAA6B;CAClE,IAAM,EAAE,gBAAa,uBAAoB,GAAmB,EACtD,CAAC,GAAkB,KAAuB,GAAkB,EAC5D,CAAC,GAA0B,KAC/B,GAAkB,EACd,CAAC,GAA6B,KAClC,GAAkB,EAEd,IAAa,EAAO,SAAS,IAC7B,IAAc,EAAO,UAAU;AAyHnC,QAxHF,QAAgB;EACd,IAAM,IAAW,YAAY;AAC3B,OAAI,EAAO,QACT,GAAoB,iCAAiC,EAAO,UAAU;YAC/D,EAAO,QACd,GAAoB,kCAAkC,EAAO,UAAU;QACpE;IACH,IAAM,IACJ,EAAO,gBAAgB,EAAO,gBAAgB,EAAO,eAEjD,IAAc,MAAM,EAAsB,GAAa,EAAU,EACjE,IAAqD,CACzD;KACE,mBAAmB;KACnB,qBAAqB,EAAwB;KAC7C,cAAc,EAAY;KAC3B,CACF,EAEG;AACJ,QAAI,EAAO,cAAc;KACvB,IAAM,IAAY,MAAM,EACtB,GACA,EAAO,aACR;AAED,KADA,IAAkB,EAAU,kBAC5B,EAA0B,KAAK;MAC7B,mBAAmB,EAAO;MAC1B,qBAAqB,EAAwB;MAC7C,cAAc,EAAU;MACzB,CAAC;;AAGJ,MACE,GACA,EAAY,kBACZ,EACD;;KAIC,KACJ,GACA,GACA,MACG;AAQH,KAAS;IANP,oBAAoB;IACpB,sBAAsB;IACtB,6BAA6B;IAC7B,gBAAgB;IAGT,EAAS,EAAY,CAC3B,MAAM,MAA0B;IAC/B,IAAM,IAAY,EAAK,eAAe,MACpC,MAAM,EAAG,iBAAiB,EAC3B;AAKD,QAJI,GAAW,gBACb,EAA4B,EAAU,aAAa,EAGjD,GAAiB;KACnB,IAAM,IAAU,EAAK,eAAe,MAClC,MAAM,EAAG,iBAAiB,EAC3B;AACD,KAAI,GAAS,gBACX,EAA+B,EAAQ,aAAa;;KAGxD,CACD,OAAM,MAAO;AACZ,YAAQ,MAAM,2BAA2B,EAAI;KAC7C;;AAEN,KAAU;IACT;EAAC;EAAkB;EAAQ;EAAa;EAAa;EAAW,CAAC,EAEhE,CAAC,KAAmB,CAAC,IAGrB,kBAAC,KAAD,EAAA,UAAA;EAAG;EAED,kBAAC,UAAD;GACE,eAAY;GACZ,WAAW,GAAG,EAAmC;;aAElD;GAEQ,CAAA;;EAEP,EAAA,CAAA,GAGJ,IAEA,kBAAC,SAAD;EACE,UAAA;EACA,OAAO;EACP,QAAQ;EACR,eAAY;EACZ,aAAY;YALd;GAOE,kBAAC,UAAD,EAAQ,KAAK,GAA4B,CAAA;GACxC,KACC,kBAAC,SAAD;IAAO,KAAK;IAA6B,MAAK;IAAY,SAAA;IAAU,CAAA;GACpE;GAEI;MAED,IAEP,kBAAC,UAAD;EACE,OAAM;EACN,KAAK;EACL,OAAO;EACP,QAAQ;EACA,CAAA,GAGL,kBAAA,GAAA,EAAK,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"FacetNavPanel.js","names":[],"sources":["../../../../src/components/widgets/facet-nav/FacetNavPanel.tsx"],"sourcesContent":["import StyledFormControl from '@/components/styled/StyledFormControl'\nimport SynapseClient from '@/synapse-client'\nimport { SynapseConstants } from '@/utils'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport { getCorrespondingColumnForFacet } from '@/utils/functions/queryUtils'\nimport { InfoOutlined } from '@mui/icons-material'\nimport {\n Box,\n InputLabel,\n MenuItem,\n Select,\n Stack,\n Tooltip,\n} from '@mui/material'\nimport {\n ColumnTypeEnum,\n FacetColumnRequest,\n FacetColumnResultValueCount,\n FacetColumnResultValues,\n} from '@sage-bionetworks/synapse-types'\nimport { useQuery } from '@tanstack/react-query'\nimport type Plotly from 'plotly.js-basic-dist'\nimport { useMemo, useState } from 'react'\nimport { getContrastColorPalette } from '../../ColorGradient/ColorGradient'\nimport { ConfirmationDialog } from '../../ConfirmationDialog/ConfirmationDialog'\nimport loadingScreen from '../../LoadingScreen/LoadingScreen'\nimport Plot from '../../Plot/Plot'\nimport PlotPanelHeader from '../../Plot/PlotPanelHeader'\nimport { useQueryVisualizationContext } from '../../QueryVisualizationWrapper'\nimport { useGetQueryMetadata } from '../../QueryWrapper/useGetQueryMetadata'\nimport { EnumFacetFilter } from '../query-filter/EnumFacetFilter/EnumFacetFilter'\nimport { FacetPlotLegendList } from './FacetPlotLegendList'\nimport { FacetWithLabel, truncate } from './FacetPlotLegendUtils'\nimport { useMeasure } from '@react-hookz/web'\n\nexport type FacetNavPanelProps = {\n applyChangesToGraphSlice: (\n facet: FacetColumnResultValues,\n value: FacetColumnResultValueCount | undefined,\n isSelected: boolean,\n ) => void\n applyChangesToFacetFilter: (facets: FacetColumnRequest[]) => void\n index: number\n facetToPlot: FacetColumnResultValues\n plotType: PlotType\n onSetPlotType: (plotType: PlotType) => void\n onHide: () => void\n isModalView: boolean\n onCloseModal?: () => void\n}\n\nconst maxLabelLength: number = 19\n\n// STACKED_HORIZONTAL_BAR corresponds to a bar chart where we just want to show the proportion (like a pie chart)\nexport type PlotType = 'PIE' | 'BAR' | 'STACKED_HORIZONTAL_BAR'\n\nconst layout: Partial<Plotly.Layout> = {\n showlegend: false,\n annotations: [],\n margin: { l: 0, r: 0, b: 0, t: 0, pad: 0 },\n yaxis: {\n visible: false,\n showgrid: false,\n },\n xaxis: {\n visible: false,\n showgrid: false,\n },\n}\n\nexport type GraphData = {\n data: Plotly.Data[]\n labels: FacetWithLabel[]\n colors: string[]\n}\n\nexport async function extractPlotDataArray(\n facetToPlot: FacetColumnResultValues,\n columnType: ColumnTypeEnum | undefined,\n index: number,\n plotType: PlotType,\n accessToken?: string,\n) {\n const colorPalette = getContrastColorPalette(\n // Use only the odd palette, using the same offset for all plots until palettes are improved.\n // See PORTALS-2916\n 'odd', // index % 2 === 0 ? 'even' : 'odd',\n 0, // Math.floor(index / 2),\n facetToPlot.facetValues.length,\n )\n\n const getLabels = async (\n facetValues: FacetColumnResultValueCount[],\n columnType?: ColumnTypeEnum,\n accessToken?: string,\n ) => {\n const map = new Map<string, string>()\n map.set(\n SynapseConstants.VALUE_NOT_SET,\n SynapseConstants.FRIENDLY_VALUE_NOT_SET,\n )\n // Filter out empties\n const filteredValues = facetValues\n .map(value => value.value)\n .filter(val => val !== SynapseConstants.VALUE_NOT_SET)\n if (\n columnType === ColumnTypeEnum.ENTITYID ||\n columnType === ColumnTypeEnum.ENTITYID_LIST\n ) {\n // TODO: Pagination\n const response = await SynapseClient.getEntityHeadersByIds(\n filteredValues,\n accessToken,\n )\n for (const header of response.results) {\n map.set(header.id, header.name)\n }\n } else if (\n columnType === ColumnTypeEnum.USERID ||\n columnType === ColumnTypeEnum.USERID_LIST\n ) {\n const response = await SynapseClient.getGroupHeadersBatch(\n filteredValues,\n accessToken,\n )\n for (const header of response.children) {\n map.set(header.ownerId, header.userName)\n }\n }\n\n return facetValues.map(facetValue => ({\n facet: facetValue,\n label: getLabel(facetValue, false, map),\n truncatedLabel: getLabel(facetValue, true, map),\n count: facetValue.count,\n }))\n }\n\n const getLabel = (\n facetValue: FacetColumnResultValueCount,\n truncateFlag: boolean,\n labelMap: Map<string, string>,\n ): string => {\n let label = labelMap.get(facetValue.value) ?? facetValue.value\n if (truncateFlag) {\n label = truncate(label, maxLabelLength)!\n }\n return label\n }\n\n const labels = await getLabels(\n facetToPlot.facetValues,\n columnType,\n accessToken,\n )\n const text = labels.map(el => el.truncatedLabel)\n\n const anyFacetsSelected = facetToPlot.facetValues.some(\n value => value.isSelected,\n )\n const selectionAwareColorPalette = anyFacetsSelected\n ? facetToPlot.facetValues.map((facetValue, index) =>\n facetValue.isSelected\n ? colorPalette[index]\n : colorPalette[index]\n .replace('rgb(', 'rgba(')\n .replace(')', ', 0.25)'),\n )\n : colorPalette\n const counts: Plotly.Datum[] = facetToPlot.facetValues.map(\n facet => facet.count,\n )\n let x: Plotly.Datum[] | Plotly.Datum[][] | Plotly.TypedArray | undefined\n\n if (plotType === 'BAR') {\n x = facetToPlot.facetValues.map(\n facet =>\n labels.find(label => label.facet === facet)?.label ?? facet.value,\n )\n } else if (plotType === 'STACKED_HORIZONTAL_BAR') {\n x = counts\n }\n\n let y: Plotly.Datum[] | Plotly.Datum[][] | Plotly.TypedArray | undefined\n if (plotType === 'BAR') {\n y = facetToPlot.facetValues.map(facet => facet.count)\n } else if (plotType === 'STACKED_HORIZONTAL_BAR') {\n y = Array(x?.length).fill('Proportional') // single value for every x value\n }\n\n const singleChartData: Plotly.Data = {\n values: plotType === 'PIE' ? counts : undefined,\n labels: labels.map(el => el.label),\n text,\n x,\n y,\n orientation: plotType === 'STACKED_HORIZONTAL_BAR' ? 'h' : 'v',\n // @ts-expect-error\n facetEnumerationValues: facetToPlot.facetValues.map(\n facetValue => facetValue.value,\n ),\n name: facetToPlot.columnName,\n textposition:\n plotType === 'STACKED_HORIZONTAL_BAR' || plotType === 'BAR'\n ? 'none'\n : 'inside',\n hovertemplate:\n plotType === 'PIE'\n ? '<b>%{text}</b><br>%{value} (%{percent})<br><extra></extra>'\n : '<b>%{text}: </b><br>%{value} <br><extra></extra>',\n textinfo: 'none',\n type: plotType === 'PIE' ? 'pie' : 'bar',\n pull:\n plotType === 'PIE'\n ? facetToPlot.facetValues.map(facetValue =>\n facetValue.isSelected ? 0.1 : 0,\n )\n : undefined,\n selectedpoints: anyFacetsSelected\n ? facetToPlot.facetValues\n .map((facetValue, index) => (facetValue.isSelected ? index : -1))\n .filter(index => index !== -1)\n : undefined,\n selected: { marker: { opacity: 1 } },\n unselected: { marker: { opacity: 0.25 } },\n\n marker: {\n colors: plotType === 'PIE' ? selectionAwareColorPalette : undefined,\n color: plotType === 'PIE' ? undefined : selectionAwareColorPalette,\n },\n }\n const result = {\n data: [singleChartData],\n labels,\n colors:\n plotType === 'PIE'\n ? ((singleChartData as any).marker?.colors as string[])\n : ((singleChartData as any).marker?.color as string[]),\n }\n return result\n}\n\nconst applyFacetFilter = (\n event: Plotly.PlotMouseEvent,\n allFacetValues: FacetColumnResultValues,\n callbackApplyFn: FacetNavPanelProps['applyChangesToGraphSlice'],\n) => {\n if (event.points && event.points[0]) {\n const plotPointData: any = event.points[0]\n const facetValueClickedValue =\n plotPointData.data.facetEnumerationValues[plotPointData.pointNumber]\n const facetValueClicked = allFacetValues.facetValues.find(\n facet => facet.value === facetValueClickedValue,\n )\n callbackApplyFn(\n allFacetValues,\n facetValueClicked,\n !facetValueClicked!.isSelected,\n )\n }\n}\n\nexport function getPlotStyle(\n parentWidth: number | null | undefined,\n plotType: PlotType,\n maxHeight: number,\n): { width: string; height: string } {\n if (parentWidth != undefined) {\n let quotient = 1\n switch (plotType) {\n case 'BAR':\n quotient = 0.8\n break\n case 'PIE':\n quotient = 0.6\n break\n case 'STACKED_HORIZONTAL_BAR':\n quotient = 1\n break\n }\n const width = parentWidth ? parentWidth * quotient : 200\n let height = plotType === 'PIE' ? width : width / 3\n // max height of .PlotsContainer row col* is 200px, so the effective plot height max is around 150 unless it's expanded\n if (height > maxHeight) {\n height = maxHeight\n }\n return {\n width: `${width}px`,\n height: `${height}px`,\n }\n }\n //else parent width is undefined\n return {\n width: '100%',\n height: `${maxHeight}px`,\n }\n}\n\nfunction FacetNavPanel(props: FacetNavPanelProps) {\n const {\n onHide,\n isModalView,\n applyChangesToGraphSlice,\n index,\n facetToPlot,\n plotType,\n onSetPlotType,\n } = props\n const { accessToken } = useSynapseContext()\n const { data: queryMetadata, isLoading: isLoadingQueryMetadata } =\n useGetQueryMetadata()\n\n const [plotContainerMeasurements, plotContainerRef] =\n useMeasure<HTMLDivElement>()\n const { getColumnDisplayName } = useQueryVisualizationContext()\n\n const [showModal, setShowModal] = useState(false)\n\n const plotTitle = getColumnDisplayName(\n facetToPlot.columnName,\n facetToPlot.jsonPath,\n )\n\n const columnModel = useMemo(\n () =>\n getCorrespondingColumnForFacet(\n facetToPlot,\n queryMetadata?.columnModels ?? [],\n ),\n [queryMetadata?.columnModels, facetToPlot],\n )\n const columnType = columnModel?.columnType as ColumnTypeEnum\n\n const { data: plotData } = useQuery({\n queryKey: [\n 'extractPlotDataArray',\n facetToPlot,\n columnType,\n index,\n plotType,\n accessToken,\n ],\n\n queryFn: () =>\n extractPlotDataArray(\n facetToPlot,\n columnType,\n index,\n plotType,\n accessToken,\n ),\n\n enabled: !!facetToPlot,\n })\n\n /* rendering functions */\n const chartSelectionToggle = (\n <StyledFormControl fullWidth>\n <InputLabel>Chart Type</InputLabel>\n <Select\n value={plotType}\n onChange={e => {\n onSetPlotType(e.target.value as PlotType)\n }}\n >\n <MenuItem value={'BAR'}>Bar Chart</MenuItem>\n <MenuItem value={'PIE'}>Pie Chart</MenuItem>\n </Select>\n </StyledFormControl>\n )\n\n if (\n (!queryMetadata && isLoadingQueryMetadata) ||\n !facetToPlot ||\n !columnModel\n ) {\n return (\n <div className=\"SRC-loadingContainer SRC-centerContentColumn\">\n {loadingScreen}\n </div>\n )\n } else {\n return (\n <>\n <ConfirmationDialog\n open={showModal}\n onCancel={() => setShowModal(false)}\n title={plotTitle ?? ''}\n content={<FacetNavPanel {...props} isModalView={true} />}\n hasCancelButton={false}\n confirmButtonProps={{ children: 'Apply Filters' }}\n onConfirm={() => setShowModal(false)}\n maxWidth={'md'}\n />\n <div\n role=\"figure\"\n className={`FacetNavPanel${isModalView ? '--expanded' : ''}`}\n >\n {!isModalView && (\n <PlotPanelHeader\n data={queryMetadata}\n isLoading={isLoadingQueryMetadata}\n title={plotTitle}\n facetToPlot={facetToPlot}\n onHide={onHide}\n setShowModal={setShowModal}\n />\n )}\n {isModalView && (\n <Stack\n sx={{\n gap: 2,\n }}\n >\n <StyledFormControl>\n <InputLabel\n sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}\n >\n <span>Filter All Data By</span>\n <Tooltip title=\"Selecting items in this dropdown will affect all facets on the Explore page.\">\n <InfoOutlined className=\"SRC-hand-cursor SRC-secondary-text-color\" />\n </Tooltip>\n </InputLabel>\n <EnumFacetFilter\n facet={facetToPlot}\n containerAs=\"Dropdown\"\n dropdownType=\"SelectBox\"\n />\n </StyledFormControl>\n {chartSelectionToggle}\n </Stack>\n )}\n <Box\n sx={{\n display: 'grid',\n gridTemplateColumns: '50% 50%',\n alignItems: 'center',\n }}\n role=\"graphics-object\"\n className=\"FacetNavPanel__body\"\n >\n <div ref={plotContainerRef}>\n <Plot\n key={`${facetToPlot.columnName}-${facetToPlot.jsonPath}-${plotType}-${plotContainerMeasurements?.width}`}\n layout={layout}\n data={plotData?.data ?? []}\n style={getPlotStyle(\n plotContainerMeasurements?.width,\n plotType,\n isModalView ? 300 : 150,\n )}\n config={{ displayModeBar: false }}\n onClick={evt =>\n applyFacetFilter(evt, facetToPlot, applyChangesToGraphSlice)\n }\n />\n </div>\n <FacetPlotLegendList\n labels={plotData?.labels}\n colors={plotData?.colors}\n isExpanded={isModalView}\n />\n </Box>\n </div>\n </>\n )\n }\n}\n\nexport default FacetNavPanel\n"],"mappings":"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"}
1
+ {"version":3,"file":"FacetNavPanel.js","names":[],"sources":["../../../../src/components/widgets/facet-nav/FacetNavPanel.tsx"],"sourcesContent":["import StyledFormControl from '@/components/styled/StyledFormControl'\nimport SynapseClient from '@/synapse-client'\nimport { SynapseConstants } from '@/utils'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport { getCorrespondingColumnForFacet } from '@/utils/functions/queryUtils'\nimport { InfoOutlined } from '@mui/icons-material'\nimport {\n Box,\n InputLabel,\n MenuItem,\n Select,\n Stack,\n Tooltip,\n} from '@mui/material'\nimport {\n ColumnTypeEnum,\n FacetColumnRequest,\n FacetColumnResultValueCount,\n FacetColumnResultValues,\n} from '@sage-bionetworks/synapse-types'\nimport { useQuery } from '@tanstack/react-query'\nimport type Plotly from 'plotly.js-basic-dist'\nimport { useMemo, useState } from 'react'\nimport { getContrastColorPalette } from '../../ColorGradient/ColorGradient'\nimport { ConfirmationDialog } from '../../ConfirmationDialog/ConfirmationDialog'\nimport loadingScreen from '../../LoadingScreen/LoadingScreen'\nimport Plot from '../../Plot/Plot'\nimport PlotPanelHeader from '../../Plot/PlotPanelHeader'\nimport { useQueryVisualizationContext } from '../../QueryVisualizationWrapper'\nimport { useGetQueryMetadata } from '../../QueryWrapper/useGetQueryMetadata'\nimport { EnumFacetFilter } from '../query-filter/EnumFacetFilter/EnumFacetFilter'\nimport { FacetPlotLegendList } from './FacetPlotLegendList'\nimport { FacetWithLabel, truncate } from './FacetPlotLegendUtils'\nimport { useMeasure } from '@react-hookz/web'\n\nexport type FacetNavPanelProps = {\n applyChangesToGraphSlice: (\n facet: FacetColumnResultValues,\n value: FacetColumnResultValueCount | undefined,\n isSelected: boolean,\n ) => void\n applyChangesToFacetFilter: (facets: FacetColumnRequest[]) => void\n index: number\n facetToPlot: FacetColumnResultValues\n plotType: PlotType\n onSetPlotType: (plotType: PlotType) => void\n onHide: () => void\n isModalView: boolean\n onCloseModal?: () => void\n}\n\nconst maxLabelLength: number = 19\n\n// STACKED_HORIZONTAL_BAR corresponds to a bar chart where we just want to show the proportion (like a pie chart)\nexport type PlotType = 'PIE' | 'BAR' | 'STACKED_HORIZONTAL_BAR'\n\nconst layout: Partial<Plotly.Layout> = {\n showlegend: false,\n annotations: [],\n margin: { l: 0, r: 0, b: 0, t: 0, pad: 0 },\n yaxis: {\n visible: false,\n showgrid: false,\n },\n xaxis: {\n visible: false,\n showgrid: false,\n },\n}\n\nexport type GraphData = {\n data: Plotly.Data[]\n labels: FacetWithLabel[]\n colors: string[]\n}\n\nexport async function extractPlotDataArray(\n facetToPlot: FacetColumnResultValues,\n columnType: ColumnTypeEnum | undefined,\n index: number,\n plotType: PlotType,\n accessToken?: string,\n) {\n const colorPalette = getContrastColorPalette(\n // Use only the odd palette, using the same offset for all plots until palettes are improved.\n // See PORTALS-2916\n 'odd', // index % 2 === 0 ? 'even' : 'odd',\n 0, // Math.floor(index / 2),\n facetToPlot.facetValues.length,\n )\n\n const getLabels = async (\n facetValues: FacetColumnResultValueCount[],\n columnType?: ColumnTypeEnum,\n accessToken?: string,\n ) => {\n const map = new Map<string, string>()\n map.set(\n SynapseConstants.VALUE_NOT_SET,\n SynapseConstants.FRIENDLY_VALUE_NOT_SET,\n )\n // Filter out empties\n const filteredValues = facetValues\n .map(value => value.value)\n .filter(val => val !== SynapseConstants.VALUE_NOT_SET)\n if (\n columnType === ColumnTypeEnum.ENTITYID ||\n columnType === ColumnTypeEnum.ENTITYID_LIST\n ) {\n // TODO: Pagination\n const response = await SynapseClient.getEntityHeadersByIds(\n filteredValues,\n accessToken,\n )\n for (const header of response.results) {\n map.set(header.id, header.name)\n }\n } else if (\n columnType === ColumnTypeEnum.USERID ||\n columnType === ColumnTypeEnum.USERID_LIST\n ) {\n const response = await SynapseClient.getGroupHeadersBatch(\n filteredValues,\n accessToken,\n )\n for (const header of response.children) {\n map.set(header.ownerId, header.userName)\n }\n }\n\n return facetValues.map(facetValue => ({\n facet: facetValue,\n label: getLabel(facetValue, false, map),\n truncatedLabel: getLabel(facetValue, true, map),\n count: facetValue.count,\n }))\n }\n\n const getLabel = (\n facetValue: FacetColumnResultValueCount,\n truncateFlag: boolean,\n labelMap: Map<string, string>,\n ): string => {\n let label = labelMap.get(facetValue.value) ?? facetValue.value\n if (truncateFlag) {\n label = truncate(label, maxLabelLength)!\n }\n return label\n }\n\n const labels = await getLabels(\n facetToPlot.facetValues,\n columnType,\n accessToken,\n )\n const text = labels.map(el => el.truncatedLabel)\n\n const anyFacetsSelected = facetToPlot.facetValues.some(\n value => value.isSelected,\n )\n const selectionAwareColorPalette = anyFacetsSelected\n ? facetToPlot.facetValues.map((facetValue, index) =>\n facetValue.isSelected\n ? colorPalette[index]\n : colorPalette[index]\n .replace('rgb(', 'rgba(')\n .replace(')', ', 0.25)'),\n )\n : colorPalette\n const counts: Plotly.Datum[] = facetToPlot.facetValues.map(\n facet => facet.count,\n )\n let x: Plotly.Datum[] | Plotly.Datum[][] | Plotly.TypedArray | undefined\n\n if (plotType === 'BAR') {\n x = facetToPlot.facetValues.map(\n facet =>\n labels.find(label => label.facet === facet)?.label ?? facet.value,\n )\n } else if (plotType === 'STACKED_HORIZONTAL_BAR') {\n x = counts\n }\n\n let y: Plotly.Datum[] | Plotly.Datum[][] | Plotly.TypedArray | undefined\n if (plotType === 'BAR') {\n y = facetToPlot.facetValues.map(facet => facet.count)\n } else if (plotType === 'STACKED_HORIZONTAL_BAR') {\n y = Array(x?.length).fill('Proportional') // single value for every x value\n }\n\n const singleChartData: Plotly.Data = {\n values: plotType === 'PIE' ? counts : undefined,\n labels: labels.map(el => el.label),\n text,\n x,\n y,\n orientation: plotType === 'STACKED_HORIZONTAL_BAR' ? 'h' : 'v',\n // @ts-expect-error\n facetEnumerationValues: facetToPlot.facetValues.map(\n facetValue => facetValue.value,\n ),\n name: facetToPlot.columnName,\n textposition:\n plotType === 'STACKED_HORIZONTAL_BAR' || plotType === 'BAR'\n ? 'none'\n : 'inside',\n hovertemplate:\n plotType === 'PIE'\n ? '<b>%{text}</b><br>%{value} (%{percent})<br><extra></extra>'\n : '<b>%{text}: </b><br>%{value} <br><extra></extra>',\n textinfo: 'none',\n type: plotType === 'PIE' ? 'pie' : 'bar',\n pull:\n plotType === 'PIE'\n ? facetToPlot.facetValues.map(facetValue =>\n facetValue.isSelected ? 0.1 : 0,\n )\n : undefined,\n selectedpoints: anyFacetsSelected\n ? facetToPlot.facetValues\n .map((facetValue, index) => (facetValue.isSelected ? index : -1))\n .filter(index => index !== -1)\n : undefined,\n selected: { marker: { opacity: 1 } },\n unselected: { marker: { opacity: 0.25 } },\n\n marker: {\n colors: plotType === 'PIE' ? selectionAwareColorPalette : undefined,\n color: plotType === 'PIE' ? undefined : selectionAwareColorPalette,\n },\n }\n const result = {\n data: [singleChartData],\n labels,\n colors:\n plotType === 'PIE'\n ? ((singleChartData as any).marker?.colors as string[])\n : ((singleChartData as any).marker?.color as string[]),\n }\n return result\n}\n\nconst applyFacetFilter = (\n event: Plotly.PlotMouseEvent,\n allFacetValues: FacetColumnResultValues,\n callbackApplyFn: FacetNavPanelProps['applyChangesToGraphSlice'],\n) => {\n if (event.points && event.points[0]) {\n const plotPointData: any = event.points[0]\n const facetValueClickedValue =\n plotPointData.data.facetEnumerationValues[plotPointData.pointNumber]\n const facetValueClicked = allFacetValues.facetValues.find(\n facet => facet.value === facetValueClickedValue,\n )\n callbackApplyFn(\n allFacetValues,\n facetValueClicked,\n !facetValueClicked!.isSelected,\n )\n }\n}\n\nexport function getPlotStyle(\n parentWidth: number | null | undefined,\n plotType: PlotType,\n maxHeight: number,\n): { width: string; height: string } {\n if (parentWidth != undefined) {\n let quotient = 1\n switch (plotType) {\n case 'BAR':\n quotient = 0.8\n break\n case 'PIE':\n quotient = 0.6\n break\n case 'STACKED_HORIZONTAL_BAR':\n quotient = 1\n break\n }\n const width = parentWidth ? parentWidth * quotient : 200\n let height = plotType === 'PIE' ? width : width / 3\n // max height of .PlotsContainer row col* is 200px, so the effective plot height max is around 150 unless it's expanded\n if (height > maxHeight) {\n height = maxHeight\n }\n return {\n width: `${width}px`,\n height: `${height}px`,\n }\n }\n //else parent width is undefined\n return {\n width: '100%',\n height: `${maxHeight}px`,\n }\n}\n\nfunction FacetNavPanel(props: FacetNavPanelProps) {\n const {\n onHide,\n isModalView,\n applyChangesToGraphSlice,\n index,\n facetToPlot,\n plotType,\n onSetPlotType,\n } = props\n const { accessToken } = useSynapseContext()\n const { data: queryMetadata, isLoading: isLoadingQueryMetadata } =\n useGetQueryMetadata()\n\n const [plotContainerMeasurements, plotContainerRef] =\n useMeasure<HTMLDivElement>()\n const { getColumnDisplayName } = useQueryVisualizationContext()\n\n const [showModal, setShowModal] = useState(false)\n\n const plotTitle = getColumnDisplayName(\n facetToPlot.columnName,\n facetToPlot.jsonPath,\n )\n\n const columnModel = useMemo(\n () =>\n getCorrespondingColumnForFacet(\n facetToPlot,\n queryMetadata?.columnModels ?? [],\n ),\n [queryMetadata?.columnModels, facetToPlot],\n )\n const columnType = columnModel?.columnType as ColumnTypeEnum\n\n const { data: plotData } = useQuery({\n queryKey: [\n 'extractPlotDataArray',\n facetToPlot,\n columnType,\n index,\n plotType,\n accessToken,\n ],\n\n queryFn: () =>\n extractPlotDataArray(\n facetToPlot,\n columnType,\n index,\n plotType,\n accessToken,\n ),\n\n enabled: !!facetToPlot,\n })\n\n /* rendering functions */\n const chartSelectionToggle = (\n <StyledFormControl fullWidth>\n <InputLabel>Chart Type</InputLabel>\n <Select\n value={plotType}\n onChange={e => {\n onSetPlotType(e.target.value as PlotType)\n }}\n >\n <MenuItem value={'BAR'}>Bar Chart</MenuItem>\n <MenuItem value={'PIE'}>Pie Chart</MenuItem>\n </Select>\n </StyledFormControl>\n )\n\n if (\n (!queryMetadata && isLoadingQueryMetadata) ||\n !facetToPlot ||\n !columnModel\n ) {\n return (\n <div className=\"SRC-loadingContainer SRC-centerContentColumn\">\n {loadingScreen}\n </div>\n )\n } else {\n return (\n <>\n <ConfirmationDialog\n open={showModal}\n onCancel={() => setShowModal(false)}\n title={plotTitle ?? ''}\n content={<FacetNavPanel {...props} isModalView={true} />}\n hasCancelButton={false}\n confirmButtonProps={{ children: 'Apply Filters' }}\n onConfirm={() => setShowModal(false)}\n maxWidth={'md'}\n />\n <div\n role=\"figure\"\n className={`FacetNavPanel${isModalView ? '--expanded' : ''}`}\n >\n {!isModalView && (\n <PlotPanelHeader\n data={queryMetadata}\n isLoading={isLoadingQueryMetadata}\n title={plotTitle}\n facetToPlot={facetToPlot}\n onHide={onHide}\n setShowModal={setShowModal}\n />\n )}\n {isModalView && (\n <Stack\n sx={{\n gap: 2,\n }}\n >\n <StyledFormControl>\n <InputLabel\n sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}\n >\n <span>Filter All Data By</span>\n <Tooltip title=\"Selecting items in this dropdown will affect all facets on the Explore page.\">\n <InfoOutlined className=\"SRC-hand-cursor SRC-secondary-text-color\" />\n </Tooltip>\n </InputLabel>\n <EnumFacetFilter\n facet={facetToPlot}\n containerAs=\"Dropdown\"\n dropdownType=\"SelectBox\"\n />\n </StyledFormControl>\n {chartSelectionToggle}\n </Stack>\n )}\n <Box\n sx={{\n display: 'grid',\n gridTemplateColumns: '50% 50%',\n alignItems: 'center',\n }}\n role=\"graphics-object\"\n className=\"FacetNavPanel__body\"\n >\n <div ref={plotContainerRef}>\n <Plot\n key={`${facetToPlot.columnName}-${facetToPlot.jsonPath}-${plotType}-${plotContainerMeasurements?.width}`}\n layout={layout}\n data={plotData?.data ?? []}\n style={getPlotStyle(\n plotContainerMeasurements?.width,\n plotType,\n isModalView ? 300 : 150,\n )}\n config={{ displayModeBar: false }}\n onClick={evt =>\n applyFacetFilter(evt, facetToPlot, applyChangesToGraphSlice)\n }\n />\n </div>\n <FacetPlotLegendList\n labels={plotData?.labels}\n colors={plotData?.colors}\n isExpanded={isModalView}\n />\n </Box>\n </div>\n </>\n )\n }\n}\n\nexport default FacetNavPanel\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"PlotsContainer.js","names":[],"sources":["../../../../src/components/widgets/facet-nav/PlotsContainer.tsx"],"sourcesContent":["import { UniqueFacetIdentifier } from '@/utils'\nimport { facetObjectMatchesDefinition } from '@/utils/functions/queryUtils'\nimport { Box, Button } from '@mui/material'\nimport type { PlotType as PlotlyPlotType } from 'plotly.js-basic-dist'\nimport { Suspense, useEffect, useMemo, useState } from 'react'\nimport { useQueryVisualizationContext } from '../../QueryVisualizationWrapper'\nimport { useSuspenseGetQueryMetadata } from '../../QueryWrapper/useGetQueryMetadata'\nimport QueryWrapperSynapsePlot, {\n QueryWrapperSynapsePlotProps,\n} from '../../QueryWrapperPlotNav/QueryWrapperSynapsePlot'\nimport FacetNavPanel, {\n FacetNavPanelProps,\n PlotType,\n} from '../facet-nav/FacetNavPanel'\nimport { PlotsContainerSkeleton } from './PlotsContainerSkeleton'\nimport useFacetPlots, { getFacets } from './useFacetPlots'\n\nconst DEFAULT_VISIBLE_PLOTS = 2\ntype ShowMoreState = 'MORE' | 'LESS' | 'NONE'\nexport type PlotsContainerProps = {\n facetsToPlot?: string[]\n customPlots?: QueryWrapperSynapsePlotProps[]\n initialPlotTypeByFacetColumnName?: Record<string, PlotType>\n}\ntype CustomPlotIdentifier = {\n title: string\n __custom: true\n}\nexport type PlotIdentifier = UniqueFacetIdentifier | CustomPlotIdentifier\n\nexport type UiPlotState = {\n plotId: PlotIdentifier\n isHidden: boolean\n plotType: PlotType\n index?: number\n}\nconst plotMatchesDefinition = (\n definition: PlotIdentifier,\n plotId: PlotIdentifier,\n) => {\n if ('__custom' in plotId && '__custom' in definition) {\n return definition.title == plotId.title\n } else if (!('__custom' in plotId) && !('__custom' in definition)) {\n return facetObjectMatchesDefinition(definition, plotId)\n } else {\n return false\n }\n}\n\nfunction convertPlotlyPlotTypeToFacetNavPlotType(\n plotlyPlotType: PlotlyPlotType,\n): PlotType {\n if (plotlyPlotType === 'bar') {\n return 'BAR'\n } else if (plotlyPlotType === 'pie') {\n return 'PIE'\n }\n return 'PIE'\n}\n\nconst generatePlotKey = (plotUiState: UiPlotState) => {\n if ('__custom' in plotUiState.plotId) {\n // For custom plots\n return `custom-${plotUiState.plotId.title}`\n } else {\n // For facet plots\n return `facet-${plotUiState.plotId.columnName}-${plotUiState.plotId.jsonPath}`\n }\n}\n\nconst isPlotInState = (\n plotId: PlotIdentifier,\n plotUiStateArray: UiPlotState[],\n): boolean => {\n return !!plotUiStateArray.find(plot => {\n return plotMatchesDefinition(plot.plotId, plotId)\n })\n}\n\nconst getCustomPlotIdentifier = (\n customPlot: QueryWrapperSynapsePlotProps,\n): PlotIdentifier => {\n return { __custom: true, title: customPlot.title ?? '' }\n}\n\nconst getCombinedNewPlots = (\n customPlots: QueryWrapperSynapsePlotProps[] = [],\n facetNavPanelPropsArray: Pick<\n FacetNavPanelProps,\n 'applyChangesToFacetFilter' | 'applyChangesToGraphSlice' | 'facetToPlot'\n >[] = [],\n initialPlotTypeByFacetColumnName?: Record<string, PlotType>,\n): UiPlotState[] => [\n ...customPlots.map((plotProps, index) => ({\n plotId: getCustomPlotIdentifier(plotProps),\n isHidden: index >= DEFAULT_VISIBLE_PLOTS,\n plotType: convertPlotlyPlotTypeToFacetNavPlotType(plotProps.type),\n })),\n ...facetNavPanelPropsArray.map((facetPlotProps, index) => ({\n plotId: facetPlotProps.facetToPlot,\n isHidden: index + customPlots.length >= DEFAULT_VISIBLE_PLOTS,\n plotType:\n initialPlotTypeByFacetColumnName?.[\n facetPlotProps.facetToPlot.columnName\n ] ?? DEFAULT_PLOT_TYPE,\n })),\n]\n\n// Remove plots that are no longer in props from prevPlots\nconst isPlotStillPresent = (\n prevPlot: UiPlotState,\n customPlots: QueryWrapperSynapsePlotProps[],\n facetNavPanelProps: Pick<\n FacetNavPanelProps,\n 'applyChangesToFacetFilter' | 'applyChangesToGraphSlice' | 'facetToPlot'\n >[],\n): boolean => {\n return (\n customPlots.some(customPlot =>\n plotMatchesDefinition(\n getCustomPlotIdentifier(customPlot),\n prevPlot.plotId,\n ),\n ) ||\n facetNavPanelProps.some(facetPlot =>\n plotMatchesDefinition(facetPlot.facetToPlot, prevPlot.plotId),\n )\n )\n} // fn returns true iff the plot id is in customPlots or facetNavPanelPropsArray\n\nconst DEFAULT_PLOT_TYPE: PlotType = 'PIE'\n\nconst DEFAULT_FACETS_TO_PLOT: string[] = []\nconst DEFAULT_CUSTOM_PLOTS: QueryWrapperSynapsePlotProps[] = []\n\nfunction PlotsContainer(props: PlotsContainerProps) {\n const {\n facetsToPlot = DEFAULT_FACETS_TO_PLOT,\n customPlots = DEFAULT_CUSTOM_PLOTS,\n initialPlotTypeByFacetColumnName,\n } = props\n const { data: queryMetadata } = useSuspenseGetQueryMetadata()\n const { showPlots: showPlotVisualization } = useQueryVisualizationContext()\n const [plotUiStateArray, setPlotUiStateArray] = useState<UiPlotState[]>([])\n const facetNavPanelPropsArray = useFacetPlots(facetsToPlot)\n\n const getPlotType = (plotId: PlotIdentifier): PlotType => {\n const plotType = plotUiStateArray.find(item =>\n plotMatchesDefinition(plotId, item.plotId),\n )?.plotType\n return plotType ?? DEFAULT_PLOT_TYPE\n }\n\n useEffect(() => {\n const combinedNewPlots = getCombinedNewPlots(\n customPlots,\n facetNavPanelPropsArray,\n initialPlotTypeByFacetColumnName,\n )\n\n // Update the state with new plots\n setPlotUiStateArray(prevPlots => {\n // Filter to only include new plots\n const newPlots = combinedNewPlots.filter(plot => {\n const inState = isPlotInState(plot.plotId, prevPlots)\n return !inState\n })\n\n const updatedPlots = prevPlots.filter(prevPlot =>\n isPlotStillPresent(prevPlot, customPlots, facetNavPanelPropsArray),\n )\n\n // Append new plots\n const combinedPlots = [...updatedPlots, ...newPlots]\n return combinedPlots\n })\n }, [customPlots, facetNavPanelPropsArray, initialPlotTypeByFacetColumnName])\n\n // when 'show more/less' is clicked\n const onShowMoreClick = (shouldShowMore: boolean) => {\n setPlotUiStateArray(plotUiStateArray => {\n return plotUiStateArray.map((item, index) => {\n if (shouldShowMore) {\n // show everything\n return { ...item, isHidden: false }\n }\n // otherwise hide everything except the first few items\n return { ...item, isHidden: index >= DEFAULT_VISIBLE_PLOTS }\n })\n })\n }\n\n const isPlotHiddenInGrid = (plotId: PlotIdentifier) => {\n const itemHidden = plotUiStateArray.find(\n item =>\n plotMatchesDefinition(plotId, item.plotId) && item.isHidden === true,\n )\n const result = itemHidden !== undefined\n return result\n }\n\n const showMoreButtonState = useMemo<ShowMoreState>(() => {\n if (\n // if at least one item is hidden\n plotUiStateArray.find(item => item.isHidden === true)\n ) {\n return 'MORE'\n } else if (plotUiStateArray.length <= DEFAULT_VISIBLE_PLOTS) {\n return 'NONE'\n } else {\n return 'LESS'\n }\n }, [plotUiStateArray])\n\n // hides plot graph\n const hidePlotInGrid = (plotId: PlotIdentifier) => {\n setUiPropertyForPlot(plotId, 'isHidden', true)\n }\n\n const setPlotType = (plotId: PlotIdentifier, plotType: PlotType) => {\n setUiPropertyForPlot(plotId, 'plotType', plotType)\n }\n\n const setUiPropertyForPlot = (\n plotId: PlotIdentifier,\n propName: keyof UiPlotState,\n value: boolean | PlotType, // 'the possible values of the above type' (currently can't be specified in TS using symbols)\n ) => {\n setPlotUiStateArray(plotUiStateArray =>\n plotUiStateArray.map(item =>\n plotMatchesDefinition(plotId, item.plotId)\n ? { ...item, [propName]: value }\n : item,\n ),\n )\n }\n\n const colorTracker: { facet: PlotIdentifier; colorIndex: number }[] =\n // TODO: customPlots should use the color index\n // additionally, it is unclear why this object is created\n // We can probably just pass the index from `plotUiStateArray.map)\n getFacets(queryMetadata, facetsToPlot).map((el, index) => {\n return {\n facet: { columnName: el.columnName, jsonPath: el.jsonPath },\n colorIndex: index,\n }\n })\n\n return (\n <>\n {plotUiStateArray.length > 0 && (\n <div\n className={`PlotsContainer ${showPlotVisualization ? '' : 'hidden'} ${\n showMoreButtonState === 'LESS' ? 'less' : ''\n }`}\n >\n <div className=\"PlotsContainer__row\" role=\"list\">\n {plotUiStateArray.map(plotUiState => {\n const isCustomPlot = '__custom' in plotUiState.plotId\n const customPlotProps = customPlots.find(customPlot =>\n plotMatchesDefinition(\n getCustomPlotIdentifier(customPlot),\n plotUiState.plotId,\n ),\n )\n const facetNavPanelProps = facetNavPanelPropsArray.find(props =>\n plotMatchesDefinition(props.facetToPlot, plotUiState.plotId),\n )\n\n return (\n <div\n className={\n plotUiState.plotType === 'BAR'\n ? 'PlotsContainer__row__item--full-width'\n : undefined\n }\n style={{\n minWidth: '435px',\n display: isPlotHiddenInGrid(plotUiState.plotId)\n ? 'none'\n : 'block',\n }}\n key={generatePlotKey(plotUiState)}\n >\n {isCustomPlot && customPlotProps && (\n <QueryWrapperSynapsePlot\n {...customPlotProps}\n onHide={() => hidePlotInGrid(plotUiState.plotId)}\n />\n )}\n {!isCustomPlot && facetNavPanelProps && (\n <FacetNavPanel\n index={\n colorTracker.find(el =>\n plotMatchesDefinition(el.facet, plotUiState.plotId),\n )?.colorIndex!\n }\n onHide={() => hidePlotInGrid(plotUiState.plotId)}\n plotType={getPlotType(plotUiState.plotId)}\n onSetPlotType={(plotType: PlotType) =>\n setPlotType(plotUiState.plotId, plotType)\n }\n isModalView={false}\n {...facetNavPanelProps}\n />\n )}\n </div>\n )\n })}\n </div>\n {showMoreButtonState !== 'NONE' && (\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'center',\n backgroundColor: 'grey.100',\n p: 2,\n mt: 2,\n }}\n >\n <Button\n variant=\"contained\"\n color=\"secondary\"\n onClick={() => onShowMoreClick(showMoreButtonState === 'MORE')}\n sx={{ width: '150px' }}\n >\n {showMoreButtonState === 'LESS'\n ? 'Hide Charts'\n : 'View All Charts'}\n </Button>\n </Box>\n )}\n </div>\n )}\n </>\n )\n}\n\nexport default function PlotsContainerWithSuspense(props: PlotsContainerProps) {\n const { showPlots } = useQueryVisualizationContext()\n return (\n <Suspense fallback={showPlots ? <PlotsContainerSkeleton /> : null}>\n <PlotsContainer {...props} />\n </Suspense>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"PlotsContainer.js","names":[],"sources":["../../../../src/components/widgets/facet-nav/PlotsContainer.tsx"],"sourcesContent":["import { UniqueFacetIdentifier } from '@/utils'\nimport { facetObjectMatchesDefinition } from '@/utils/functions/queryUtils'\nimport { Box, Button } from '@mui/material'\nimport type { PlotType as PlotlyPlotType } from 'plotly.js-basic-dist'\nimport { Suspense, useEffect, useMemo, useState } from 'react'\nimport { useQueryVisualizationContext } from '../../QueryVisualizationWrapper'\nimport { useSuspenseGetQueryMetadata } from '../../QueryWrapper/useGetQueryMetadata'\nimport QueryWrapperSynapsePlot, {\n QueryWrapperSynapsePlotProps,\n} from '../../QueryWrapperPlotNav/QueryWrapperSynapsePlot'\nimport FacetNavPanel, {\n FacetNavPanelProps,\n PlotType,\n} from '../facet-nav/FacetNavPanel'\nimport { PlotsContainerSkeleton } from './PlotsContainerSkeleton'\nimport useFacetPlots, { getFacets } from './useFacetPlots'\n\nconst DEFAULT_VISIBLE_PLOTS = 2\ntype ShowMoreState = 'MORE' | 'LESS' | 'NONE'\nexport type PlotsContainerProps = {\n facetsToPlot?: string[]\n customPlots?: QueryWrapperSynapsePlotProps[]\n initialPlotTypeByFacetColumnName?: Record<string, PlotType>\n}\ntype CustomPlotIdentifier = {\n title: string\n __custom: true\n}\nexport type PlotIdentifier = UniqueFacetIdentifier | CustomPlotIdentifier\n\nexport type UiPlotState = {\n plotId: PlotIdentifier\n isHidden: boolean\n plotType: PlotType\n index?: number\n}\nconst plotMatchesDefinition = (\n definition: PlotIdentifier,\n plotId: PlotIdentifier,\n) => {\n if ('__custom' in plotId && '__custom' in definition) {\n return definition.title == plotId.title\n } else if (!('__custom' in plotId) && !('__custom' in definition)) {\n return facetObjectMatchesDefinition(definition, plotId)\n } else {\n return false\n }\n}\n\nfunction convertPlotlyPlotTypeToFacetNavPlotType(\n plotlyPlotType: PlotlyPlotType,\n): PlotType {\n if (plotlyPlotType === 'bar') {\n return 'BAR'\n } else if (plotlyPlotType === 'pie') {\n return 'PIE'\n }\n return 'PIE'\n}\n\nconst generatePlotKey = (plotUiState: UiPlotState) => {\n if ('__custom' in plotUiState.plotId) {\n // For custom plots\n return `custom-${plotUiState.plotId.title}`\n } else {\n // For facet plots\n return `facet-${plotUiState.plotId.columnName}-${plotUiState.plotId.jsonPath}`\n }\n}\n\nconst isPlotInState = (\n plotId: PlotIdentifier,\n plotUiStateArray: UiPlotState[],\n): boolean => {\n return !!plotUiStateArray.find(plot => {\n return plotMatchesDefinition(plot.plotId, plotId)\n })\n}\n\nconst getCustomPlotIdentifier = (\n customPlot: QueryWrapperSynapsePlotProps,\n): PlotIdentifier => {\n return { __custom: true, title: customPlot.title ?? '' }\n}\n\nconst getCombinedNewPlots = (\n customPlots: QueryWrapperSynapsePlotProps[] = [],\n facetNavPanelPropsArray: Pick<\n FacetNavPanelProps,\n 'applyChangesToFacetFilter' | 'applyChangesToGraphSlice' | 'facetToPlot'\n >[] = [],\n initialPlotTypeByFacetColumnName?: Record<string, PlotType>,\n): UiPlotState[] => [\n ...customPlots.map((plotProps, index) => ({\n plotId: getCustomPlotIdentifier(plotProps),\n isHidden: index >= DEFAULT_VISIBLE_PLOTS,\n plotType: convertPlotlyPlotTypeToFacetNavPlotType(plotProps.type),\n })),\n ...facetNavPanelPropsArray.map((facetPlotProps, index) => ({\n plotId: facetPlotProps.facetToPlot,\n isHidden: index + customPlots.length >= DEFAULT_VISIBLE_PLOTS,\n plotType:\n initialPlotTypeByFacetColumnName?.[\n facetPlotProps.facetToPlot.columnName\n ] ?? DEFAULT_PLOT_TYPE,\n })),\n]\n\n// Remove plots that are no longer in props from prevPlots\nconst isPlotStillPresent = (\n prevPlot: UiPlotState,\n customPlots: QueryWrapperSynapsePlotProps[],\n facetNavPanelProps: Pick<\n FacetNavPanelProps,\n 'applyChangesToFacetFilter' | 'applyChangesToGraphSlice' | 'facetToPlot'\n >[],\n): boolean => {\n return (\n customPlots.some(customPlot =>\n plotMatchesDefinition(\n getCustomPlotIdentifier(customPlot),\n prevPlot.plotId,\n ),\n ) ||\n facetNavPanelProps.some(facetPlot =>\n plotMatchesDefinition(facetPlot.facetToPlot, prevPlot.plotId),\n )\n )\n} // fn returns true iff the plot id is in customPlots or facetNavPanelPropsArray\n\nconst DEFAULT_PLOT_TYPE: PlotType = 'PIE'\n\nconst DEFAULT_FACETS_TO_PLOT: string[] = []\nconst DEFAULT_CUSTOM_PLOTS: QueryWrapperSynapsePlotProps[] = []\n\nfunction PlotsContainer(props: PlotsContainerProps) {\n const {\n facetsToPlot = DEFAULT_FACETS_TO_PLOT,\n customPlots = DEFAULT_CUSTOM_PLOTS,\n initialPlotTypeByFacetColumnName,\n } = props\n const { data: queryMetadata } = useSuspenseGetQueryMetadata()\n const { showPlots: showPlotVisualization } = useQueryVisualizationContext()\n const [plotUiStateArray, setPlotUiStateArray] = useState<UiPlotState[]>([])\n const facetNavPanelPropsArray = useFacetPlots(facetsToPlot)\n\n const getPlotType = (plotId: PlotIdentifier): PlotType => {\n const plotType = plotUiStateArray.find(item =>\n plotMatchesDefinition(plotId, item.plotId),\n )?.plotType\n return plotType ?? DEFAULT_PLOT_TYPE\n }\n\n useEffect(() => {\n const combinedNewPlots = getCombinedNewPlots(\n customPlots,\n facetNavPanelPropsArray,\n initialPlotTypeByFacetColumnName,\n )\n\n // Update the state with new plots\n setPlotUiStateArray(prevPlots => {\n // Filter to only include new plots\n const newPlots = combinedNewPlots.filter(plot => {\n const inState = isPlotInState(plot.plotId, prevPlots)\n return !inState\n })\n\n const updatedPlots = prevPlots.filter(prevPlot =>\n isPlotStillPresent(prevPlot, customPlots, facetNavPanelPropsArray),\n )\n\n // Append new plots\n const combinedPlots = [...updatedPlots, ...newPlots]\n return combinedPlots\n })\n }, [customPlots, facetNavPanelPropsArray, initialPlotTypeByFacetColumnName])\n\n // when 'show more/less' is clicked\n const onShowMoreClick = (shouldShowMore: boolean) => {\n setPlotUiStateArray(plotUiStateArray => {\n return plotUiStateArray.map((item, index) => {\n if (shouldShowMore) {\n // show everything\n return { ...item, isHidden: false }\n }\n // otherwise hide everything except the first few items\n return { ...item, isHidden: index >= DEFAULT_VISIBLE_PLOTS }\n })\n })\n }\n\n const isPlotHiddenInGrid = (plotId: PlotIdentifier) => {\n const itemHidden = plotUiStateArray.find(\n item =>\n plotMatchesDefinition(plotId, item.plotId) && item.isHidden === true,\n )\n const result = itemHidden !== undefined\n return result\n }\n\n const showMoreButtonState = useMemo<ShowMoreState>(() => {\n if (\n // if at least one item is hidden\n plotUiStateArray.find(item => item.isHidden === true)\n ) {\n return 'MORE'\n } else if (plotUiStateArray.length <= DEFAULT_VISIBLE_PLOTS) {\n return 'NONE'\n } else {\n return 'LESS'\n }\n }, [plotUiStateArray])\n\n // hides plot graph\n const hidePlotInGrid = (plotId: PlotIdentifier) => {\n setUiPropertyForPlot(plotId, 'isHidden', true)\n }\n\n const setPlotType = (plotId: PlotIdentifier, plotType: PlotType) => {\n setUiPropertyForPlot(plotId, 'plotType', plotType)\n }\n\n const setUiPropertyForPlot = (\n plotId: PlotIdentifier,\n propName: keyof UiPlotState,\n value: boolean | PlotType, // 'the possible values of the above type' (currently can't be specified in TS using symbols)\n ) => {\n setPlotUiStateArray(plotUiStateArray =>\n plotUiStateArray.map(item =>\n plotMatchesDefinition(plotId, item.plotId)\n ? { ...item, [propName]: value }\n : item,\n ),\n )\n }\n\n const colorTracker: { facet: PlotIdentifier; colorIndex: number }[] =\n // TODO: customPlots should use the color index\n // additionally, it is unclear why this object is created\n // We can probably just pass the index from `plotUiStateArray.map)\n getFacets(queryMetadata, facetsToPlot).map((el, index) => {\n return {\n facet: { columnName: el.columnName, jsonPath: el.jsonPath },\n colorIndex: index,\n }\n })\n\n return (\n <>\n {plotUiStateArray.length > 0 && (\n <div\n className={`PlotsContainer ${showPlotVisualization ? '' : 'hidden'} ${\n showMoreButtonState === 'LESS' ? 'less' : ''\n }`}\n >\n <div className=\"PlotsContainer__row\" role=\"list\">\n {plotUiStateArray.map(plotUiState => {\n const isCustomPlot = '__custom' in plotUiState.plotId\n const customPlotProps = customPlots.find(customPlot =>\n plotMatchesDefinition(\n getCustomPlotIdentifier(customPlot),\n plotUiState.plotId,\n ),\n )\n const facetNavPanelProps = facetNavPanelPropsArray.find(props =>\n plotMatchesDefinition(props.facetToPlot, plotUiState.plotId),\n )\n\n return (\n <div\n className={\n plotUiState.plotType === 'BAR'\n ? 'PlotsContainer__row__item--full-width'\n : undefined\n }\n style={{\n minWidth: '435px',\n display: isPlotHiddenInGrid(plotUiState.plotId)\n ? 'none'\n : 'block',\n }}\n key={generatePlotKey(plotUiState)}\n >\n {isCustomPlot && customPlotProps && (\n <QueryWrapperSynapsePlot\n {...customPlotProps}\n onHide={() => hidePlotInGrid(plotUiState.plotId)}\n />\n )}\n {!isCustomPlot && facetNavPanelProps && (\n <FacetNavPanel\n index={\n colorTracker.find(el =>\n plotMatchesDefinition(el.facet, plotUiState.plotId),\n )?.colorIndex!\n }\n onHide={() => hidePlotInGrid(plotUiState.plotId)}\n plotType={getPlotType(plotUiState.plotId)}\n onSetPlotType={(plotType: PlotType) =>\n setPlotType(plotUiState.plotId, plotType)\n }\n isModalView={false}\n {...facetNavPanelProps}\n />\n )}\n </div>\n )\n })}\n </div>\n {showMoreButtonState !== 'NONE' && (\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'center',\n backgroundColor: 'grey.100',\n p: 2,\n mt: 2,\n }}\n >\n <Button\n variant=\"contained\"\n color=\"secondary\"\n onClick={() => onShowMoreClick(showMoreButtonState === 'MORE')}\n sx={{ width: '150px' }}\n >\n {showMoreButtonState === 'LESS'\n ? 'Hide Charts'\n : 'View All Charts'}\n </Button>\n </Box>\n )}\n </div>\n )}\n </>\n )\n}\n\nexport default function PlotsContainerWithSuspense(props: PlotsContainerProps) {\n const { showPlots } = useQueryVisualizationContext()\n return (\n <Suspense fallback={showPlots ? <PlotsContainerSkeleton /> : null}>\n <PlotsContainer {...props} />\n </Suspense>\n )\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"SelectionCriteriaPills.js","names":[],"sources":["../../../../src/components/widgets/facet-nav/SelectionCriteriaPills.tsx"],"sourcesContent":["import {\n isColumnMultiValueFunctionQueryFilter,\n isColumnSingleValueQueryFilter,\n isFacetColumnRangeRequest,\n isFacetColumnValuesRequest,\n isTextMatchesQueryFilter,\n LockedColumn,\n} from '@/utils'\nimport { FRIENDLY_VALUE_NOT_SET, VALUE_NOT_SET } from '@/utils/SynapseConstants'\nimport {\n ColumnModel,\n ColumnMultiValueFunctionQueryFilter,\n ColumnSingleValueQueryFilter,\n FacetColumnRangeRequest,\n FacetColumnRequest,\n QueryFilter,\n TextMatchesQueryFilter,\n} from '@sage-bionetworks/synapse-types'\nimport pluralize from 'pluralize'\nimport { ReadonlyDeep } from 'type-fest'\nimport { QueryContextType, useQueryContext } from '../../QueryContext'\nimport {\n QueryVisualizationContextType,\n useQueryVisualizationContext,\n} from '../../QueryVisualizationWrapper'\nimport { useGetQueryMetadata } from '../../QueryWrapper/useGetQueryMetadata'\nimport SelectionCriteriaPill, {\n SelectionCriteriaPillProps,\n} from './SelectionCriteriaPill'\nimport { getSearchTextFromBooleanModeSearchExpression } from '@/components/FullTextSearch/FullTextSearchUtils'\n\nconst MAX_VALUES_IN_FILTER_FOR_INDIVIDUAL_PILLS = 4\n\nfunction getPillPropsFromColumnQueryFilter(\n queryFilter:\n | ColumnSingleValueQueryFilter\n | ColumnMultiValueFunctionQueryFilter,\n queryContext: QueryContextType,\n columnModel: ColumnModel | undefined,\n queryVisualizationContext: QueryVisualizationContextType,\n): SelectionCriteriaPillProps[] {\n const { getColumnDisplayName } = queryVisualizationContext\n // ColumnSingleValueQueryFilter and ColumnMultiValueQueryFilter both allow for a list of values\n // If there are more than _n_ values, consolidate to one pill\n if (\n queryFilter.values.length > MAX_VALUES_IN_FILTER_FOR_INDIVIDUAL_PILLS ||\n !columnModel\n ) {\n const text = `${pluralize(\n getColumnDisplayName(queryFilter.columnName),\n )} (${queryFilter.values.length.toLocaleString()})`\n\n return [\n {\n key: `queryFilter-${queryFilter.concreteType}-${queryFilter.columnName}`,\n innerText: text,\n tooltipText: text,\n onRemoveFilter: () => {\n queryContext.removeQueryFilter(queryFilter)\n },\n },\n ]\n }\n\n // otherwise render one pill per value\n return queryFilter.values.map(value => {\n let filterValue = value\n\n if (value?.startsWith('%') && value?.endsWith('%')) {\n // strip '%' wildcard character when using a LIKE condition\n filterValue = filterValue.substring(1, filterValue.length - 1)\n }\n filterValue = queryVisualizationContext.getDisplayValue(\n filterValue,\n columnModel.columnType,\n )\n const text = `${getColumnDisplayName(\n queryFilter.columnName,\n )}: ${filterValue}`\n return {\n key: `queryFilter-${queryFilter.concreteType}-${queryFilter.columnName}-${value}`,\n innerText: text,\n tooltipText: text,\n onRemoveFilter: () => {\n queryContext.removeValueFromQueryFilter(queryFilter, value)\n },\n }\n })\n}\n\nexport function getPillPropsFromTextMatchesQueryFilter(\n queryFilter: TextMatchesQueryFilter,\n queryContext: QueryContextType,\n): SelectionCriteriaPillProps {\n let innerText = queryFilter.searchExpression\n if (queryFilter.searchMode == 'BOOLEAN') {\n innerText = getSearchTextFromBooleanModeSearchExpression(\n queryFilter.searchExpression,\n )\n }\n\n return {\n key: `queryFilter-${queryFilter.concreteType}-${queryFilter.searchExpression}`,\n innerText,\n tooltipText: `Text matches: \"${innerText}\"`,\n onRemoveFilter: () => {\n queryContext.removeQueryFilter(queryFilter)\n },\n }\n}\n\nfunction getPillPropsFromQueryFilters(\n queryFilters: ReadonlyDeep<QueryFilter[]>,\n queryContext: QueryContextType,\n columnModels: ColumnModel[],\n queryVisualizationContext: QueryVisualizationContextType,\n lockedColumn?: LockedColumn,\n): SelectionCriteriaPillProps[] {\n return queryFilters.flatMap(queryFilter => {\n if (\n isColumnSingleValueQueryFilter(queryFilter) ||\n isColumnMultiValueFunctionQueryFilter(queryFilter)\n ) {\n const columnModel = columnModels.find(\n cm => cm.name === queryFilter.columnName,\n )\n if (\n queryFilter.columnName.toLowerCase() ===\n lockedColumn?.columnName?.toLowerCase()\n ) {\n return []\n }\n return getPillPropsFromColumnQueryFilter(\n queryFilter,\n queryContext,\n columnModel,\n queryVisualizationContext,\n )\n } else if (isTextMatchesQueryFilter(queryFilter)) {\n return [getPillPropsFromTextMatchesQueryFilter(queryFilter, queryContext)]\n } else {\n console.log('Unknown query filter type', queryFilter)\n return []\n }\n })\n}\n\nfunction getRangeFacetInnerText(min?: string, max?: string) {\n if (min == undefined && max == undefined) {\n return 'Any value'\n } else if (min == undefined) {\n return `Up to ${max}`\n } else if (max == undefined) {\n return `${min} or greater`\n } else if (min === VALUE_NOT_SET && max === VALUE_NOT_SET) {\n return FRIENDLY_VALUE_NOT_SET\n } else {\n return `${min} - ${max}`\n }\n}\n\nfunction getPillPropsFromFacetFilters(\n selectedFacets: ReadonlyDeep<FacetColumnRequest[]>,\n queryContext: QueryContextType,\n columnModels: ColumnModel[],\n queryVisualizationContext: QueryVisualizationContextType,\n lockedColumn?: LockedColumn,\n): SelectionCriteriaPillProps[] {\n return selectedFacets.flatMap(selectedFacet => {\n if (\n selectedFacet.columnName.toLowerCase() ===\n lockedColumn?.columnName?.toLowerCase()\n ) {\n return []\n }\n const columnModel = columnModels.find(\n cm => cm.name === selectedFacet.columnName,\n )\n const { getColumnDisplayName, getDisplayValue } = queryVisualizationContext\n if (isFacetColumnValuesRequest(selectedFacet)) {\n // If there are more than _n_ values, consolidate to one pill\n if (\n selectedFacet.facetValues.length >\n MAX_VALUES_IN_FILTER_FOR_INDIVIDUAL_PILLS ||\n !columnModel\n ) {\n const text = `${pluralize(\n getColumnDisplayName(\n selectedFacet.columnName,\n selectedFacet.jsonPath,\n ),\n )} (${selectedFacet.facetValues.length.toLocaleString()})`\n return [\n {\n key: `facet-${selectedFacet.concreteType}-${selectedFacet.columnName}`,\n innerText: text,\n tooltipText: text,\n onRemoveFilter: () => {\n queryContext.removeSelectedFacet(selectedFacet)\n },\n },\n ]\n }\n\n // otherwise render one pill per value\n\n return selectedFacet.facetValues.map(facetValue => {\n const innerText = getDisplayValue(facetValue, columnModel.columnType)\n return {\n key: `facet-${selectedFacet.concreteType}-${selectedFacet.columnName}-${facetValue}`,\n innerText: innerText,\n tooltipText: `${getColumnDisplayName(\n selectedFacet.columnName,\n selectedFacet.jsonPath,\n )}: ${innerText}`,\n onRemoveFilter: () => {\n queryContext.removeValueFromSelectedFacet(selectedFacet, facetValue)\n },\n }\n })\n } else if (isFacetColumnRangeRequest(selectedFacet)) {\n // Include a single pill for both facet filters if a combined range facet filter config is defined\n const { combineRangeFacetConfig } = queryContext\n if (\n combineRangeFacetConfig &&\n (selectedFacet.columnName == combineRangeFacetConfig.minFacetColumn ||\n selectedFacet.columnName == combineRangeFacetConfig.maxFacetColumn)\n ) {\n if (\n selectedFacet.columnName == combineRangeFacetConfig.minFacetColumn\n ) {\n return []\n } else {\n // find the min facet also\n const maxFacet = selectedFacet\n const minFacet = selectedFacets.find(\n v => v.columnName == combineRangeFacetConfig.minFacetColumn,\n ) as FacetColumnRangeRequest\n const innerText = getRangeFacetInnerText(maxFacet.min, minFacet.max)\n return [\n {\n key: `facet-${selectedFacet.concreteType}-${selectedFacet.columnName}-${innerText}`,\n innerText: innerText,\n tooltipText: `${combineRangeFacetConfig.label}: ${innerText}`,\n onRemoveFilter: () => {\n // Remove both facets on pill click\n queryContext.removeSelectedFacet([minFacet, maxFacet])\n },\n },\n ]\n }\n }\n\n const innerText = getRangeFacetInnerText(\n selectedFacet.min,\n selectedFacet.max,\n )\n\n return [\n {\n key: `facet-${selectedFacet.concreteType}-${selectedFacet.columnName}-${selectedFacet.min}-${selectedFacet.max}`,\n innerText: innerText,\n tooltipText: `${getColumnDisplayName(\n selectedFacet.columnName,\n selectedFacet.jsonPath,\n )}: ${innerText}`,\n onRemoveFilter: () => {\n queryContext.removeSelectedFacet(selectedFacet)\n },\n },\n ]\n } else {\n console.log(\n 'Unknown facet type',\n (selectedFacet as unknown as FacetColumnRequest).concreteType,\n )\n return []\n }\n })\n}\n\nfunction SelectionCriteriaPills() {\n const queryContext = useQueryContext()\n const lockedColumn = queryContext.lockedColumn\n const queryVisualizationContext = useQueryVisualizationContext()\n const { currentQueryRequest } = queryContext\n const { data: queryMetadata } = useGetQueryMetadata()\n\n const queryFilterPillProps = getPillPropsFromQueryFilters(\n currentQueryRequest.query?.additionalFilters ?? [],\n queryContext,\n queryMetadata?.columnModels || [],\n queryVisualizationContext,\n lockedColumn,\n )\n\n const facetPillProps = getPillPropsFromFacetFilters(\n currentQueryRequest.query.selectedFacets ?? [],\n queryContext,\n queryMetadata?.columnModels || [],\n queryVisualizationContext,\n lockedColumn,\n )\n\n const allPills = [...queryFilterPillProps, ...facetPillProps]\n\n return (\n <>\n {allPills.map(pillProps => {\n // Encode the key because the facet may include an illegal character\n const key = encodeURIComponent(pillProps.key)\n return <SelectionCriteriaPill {...pillProps} key={key} />\n })}\n </>\n )\n}\n\nexport default SelectionCriteriaPills\n"],"mappings":";;;;;;;;;;;;;;AA+BA,IAAM,IAA4C;AAElD,SAAS,EACP,GAGA,GACA,GACA,GAC8B;CAC9B,IAAM,EAAE,4BAAyB;AAGjC,KACE,EAAY,OAAO,SAAS,KAC5B,CAAC,GACD;EACA,IAAM,IAAO,GAAG,EACd,EAAqB,EAAY,WAAW,CAC7C,CAAC,IAAI,EAAY,OAAO,OAAO,gBAAgB,CAAC;AAEjD,SAAO,CACL;GACE,KAAK,eAAe,EAAY,aAAa,GAAG,EAAY;GAC5D,WAAW;GACX,aAAa;GACb,sBAAsB;AACpB,MAAa,kBAAkB,EAAY;;GAE9C,CACF;;AAIH,QAAO,EAAY,OAAO,KAAI,MAAS;EACrC,IAAI,IAAc;AAMlB,EAJI,GAAO,WAAW,IAAI,IAAI,GAAO,SAAS,IAAI,KAEhD,IAAc,EAAY,UAAU,GAAG,EAAY,SAAS,EAAE,GAEhE,IAAc,EAA0B,gBACtC,GACA,EAAY,WACb;EACD,IAAM,IAAO,GAAG,EACd,EAAY,WACb,CAAC,IAAI;AACN,SAAO;GACL,KAAK,eAAe,EAAY,aAAa,GAAG,EAAY,WAAW,GAAG;GAC1E,WAAW;GACX,aAAa;GACb,sBAAsB;AACpB,MAAa,2BAA2B,GAAa,EAAM;;GAE9D;GACD;;AAGJ,SAAgB,EACd,GACA,GAC4B;CAC5B,IAAI,IAAY,EAAY;AAO5B,QANI,EAAY,cAAc,cAC5B,IAAY,EACV,EAAY,iBACb,GAGI;EACL,KAAK,eAAe,EAAY,aAAa,GAAG,EAAY;EAC5D;EACA,aAAa,kBAAkB,EAAU;EACzC,sBAAsB;AACpB,KAAa,kBAAkB,EAAY;;EAE9C;;AAGH,SAAS,EACP,GACA,GACA,GACA,GACA,GAC8B;AAC9B,QAAO,EAAa,SAAQ,MAAe;AACzC,MACE,EAA+B,EAAY,IAC3C,EAAsC,EAAY,EAClD;GACA,IAAM,IAAc,EAAa,MAC/B,MAAM,EAAG,SAAS,EAAY,WAC/B;AAOD,UALE,EAAY,WAAW,aAAa,KACpC,GAAc,YAAY,aAAa,GAEhC,EAAE,GAEJ,EACL,GACA,GACA,GACA,EACD;aACQ,EAAyB,EAAY,CAC9C,QAAO,CAAC,EAAuC,GAAa,EAAa,CAAC;MAG1E,QADA,QAAQ,IAAI,6BAA6B,EAAY,EAC9C,EAAE;GAEX;;AAGJ,SAAS,EAAuB,GAAc,GAAc;AAUxD,QATE,KAAO,QAAa,KAAO,OACtB,cACE,KAAO,OACT,SAAS,MACP,KAAO,OACT,GAAG,EAAI,eACL,MAAA,+CAAyB,MAAA,8CAC3B,IAEA,GAAG,EAAI,KAAK;;AAIvB,SAAS,EACP,GACA,GACA,GACA,GACA,GAC8B;AAC9B,QAAO,EAAe,SAAQ,MAAiB;AAC7C,MACE,EAAc,WAAW,aAAa,KACtC,GAAc,YAAY,aAAa,CAEvC,QAAO,EAAE;EAEX,IAAM,IAAc,EAAa,MAC/B,MAAM,EAAG,SAAS,EAAc,WACjC,EACK,EAAE,yBAAsB,uBAAoB;AAClD,MAAI,EAA2B,EAAc,EAAE;AAE7C,OACE,EAAc,YAAY,SACxB,KACF,CAAC,GACD;IACA,IAAM,IAAO,GAAG,EACd,EACE,EAAc,YACd,EAAc,SACf,CACF,CAAC,IAAI,EAAc,YAAY,OAAO,gBAAgB,CAAC;AACxD,WAAO,CACL;KACE,KAAK,SAAS,EAAc,aAAa,GAAG,EAAc;KAC1D,WAAW;KACX,aAAa;KACb,sBAAsB;AACpB,QAAa,oBAAoB,EAAc;;KAElD,CACF;;AAKH,UAAO,EAAc,YAAY,KAAI,MAAc;IACjD,IAAM,IAAY,EAAgB,GAAY,EAAY,WAAW;AACrE,WAAO;KACL,KAAK,SAAS,EAAc,aAAa,GAAG,EAAc,WAAW,GAAG;KAC7D;KACX,aAAa,GAAG,EACd,EAAc,YACd,EAAc,SACf,CAAC,IAAI;KACN,sBAAsB;AACpB,QAAa,6BAA6B,GAAe,EAAW;;KAEvE;KACD;aACO,EAA0B,EAAc,EAAE;GAEnD,IAAM,EAAE,+BAA4B;AACpC,OACE,MACC,EAAc,cAAc,EAAwB,kBACnD,EAAc,cAAc,EAAwB,iBAEtD;QACE,EAAc,cAAc,EAAwB,eAEpD,QAAO,EAAE;IACJ;KAEL,IAAM,IAAW,GACX,IAAW,EAAe,MAC9B,MAAK,EAAE,cAAc,EAAwB,eAC9C,EACK,IAAY,EAAuB,EAAS,KAAK,EAAS,IAAI;AACpE,YAAO,CACL;MACE,KAAK,SAAS,EAAc,aAAa,GAAG,EAAc,WAAW,GAAG;MAC7D;MACX,aAAa,GAAG,EAAwB,MAAM,IAAI;MAClD,sBAAsB;AAEpB,SAAa,oBAAoB,CAAC,GAAU,EAAS,CAAC;;MAEzD,CACF;;;GAIL,IAAM,IAAY,EAChB,EAAc,KACd,EAAc,IACf;AAED,UAAO,CACL;IACE,KAAK,SAAS,EAAc,aAAa,GAAG,EAAc,WAAW,GAAG,EAAc,IAAI,GAAG,EAAc;IAChG;IACX,aAAa,GAAG,EACd,EAAc,YACd,EAAc,SACf,CAAC,IAAI;IACN,sBAAsB;AACpB,OAAa,oBAAoB,EAAc;;IAElD,CACF;QAMD,QAJA,QAAQ,IACN,sBACC,EAAgD,aAClD,EACM,EAAE;GAEX;;AAGJ,SAAS,IAAyB;CAChC,IAAM,IAAe,GAAiB,EAChC,IAAe,EAAa,cAC5B,IAA4B,GAA8B,EAC1D,EAAE,2BAAwB,GAC1B,EAAE,MAAM,MAAkB,GAAqB,EAE/C,IAAuB,EAC3B,EAAoB,OAAO,qBAAqB,EAAE,EAClD,GACA,GAAe,gBAAgB,EAAE,EACjC,GACA,EACD,EAEK,IAAiB,EACrB,EAAoB,MAAM,kBAAkB,EAAE,EAC9C,GACA,GAAe,gBAAgB,EAAE,EACjC,GACA,EACD;AAID,QACE,kBAAA,GAAA,EAAA,UAHe,CAAC,GAAG,GAAsB,GAAG,EAAe,CAI/C,KAAI,MAAa;EAEzB,IAAM,IAAM,mBAAmB,EAAU,IAAI;AAC7C,SAAO,kBAAC,GAAD;GAAuB,GAAI;GAAgB;GAAO,CAAA;GACzD,EACD,CAAA"}
1
+ {"version":3,"file":"SelectionCriteriaPills.js","names":[],"sources":["../../../../src/components/widgets/facet-nav/SelectionCriteriaPills.tsx"],"sourcesContent":["import {\n isColumnMultiValueFunctionQueryFilter,\n isColumnSingleValueQueryFilter,\n isFacetColumnRangeRequest,\n isFacetColumnValuesRequest,\n isTextMatchesQueryFilter,\n LockedColumn,\n} from '@/utils'\nimport { FRIENDLY_VALUE_NOT_SET, VALUE_NOT_SET } from '@/utils/SynapseConstants'\nimport {\n ColumnModel,\n ColumnMultiValueFunctionQueryFilter,\n ColumnSingleValueQueryFilter,\n FacetColumnRangeRequest,\n FacetColumnRequest,\n QueryFilter,\n TextMatchesQueryFilter,\n} from '@sage-bionetworks/synapse-types'\nimport pluralize from 'pluralize'\nimport { ReadonlyDeep } from 'type-fest'\nimport { QueryContextType, useQueryContext } from '../../QueryContext'\nimport {\n QueryVisualizationContextType,\n useQueryVisualizationContext,\n} from '../../QueryVisualizationWrapper'\nimport { useGetQueryMetadata } from '../../QueryWrapper/useGetQueryMetadata'\nimport SelectionCriteriaPill, {\n SelectionCriteriaPillProps,\n} from './SelectionCriteriaPill'\nimport { getSearchTextFromBooleanModeSearchExpression } from '@/components/FullTextSearch/FullTextSearchUtils'\n\nconst MAX_VALUES_IN_FILTER_FOR_INDIVIDUAL_PILLS = 4\n\nfunction getPillPropsFromColumnQueryFilter(\n queryFilter:\n | ColumnSingleValueQueryFilter\n | ColumnMultiValueFunctionQueryFilter,\n queryContext: QueryContextType,\n columnModel: ColumnModel | undefined,\n queryVisualizationContext: QueryVisualizationContextType,\n): SelectionCriteriaPillProps[] {\n const { getColumnDisplayName } = queryVisualizationContext\n // ColumnSingleValueQueryFilter and ColumnMultiValueQueryFilter both allow for a list of values\n // If there are more than _n_ values, consolidate to one pill\n if (\n queryFilter.values.length > MAX_VALUES_IN_FILTER_FOR_INDIVIDUAL_PILLS ||\n !columnModel\n ) {\n const text = `${pluralize(\n getColumnDisplayName(queryFilter.columnName),\n )} (${queryFilter.values.length.toLocaleString()})`\n\n return [\n {\n key: `queryFilter-${queryFilter.concreteType}-${queryFilter.columnName}`,\n innerText: text,\n tooltipText: text,\n onRemoveFilter: () => {\n queryContext.removeQueryFilter(queryFilter)\n },\n },\n ]\n }\n\n // otherwise render one pill per value\n return queryFilter.values.map(value => {\n let filterValue = value\n\n if (value?.startsWith('%') && value?.endsWith('%')) {\n // strip '%' wildcard character when using a LIKE condition\n filterValue = filterValue.substring(1, filterValue.length - 1)\n }\n filterValue = queryVisualizationContext.getDisplayValue(\n filterValue,\n columnModel.columnType,\n )\n const text = `${getColumnDisplayName(\n queryFilter.columnName,\n )}: ${filterValue}`\n return {\n key: `queryFilter-${queryFilter.concreteType}-${queryFilter.columnName}-${value}`,\n innerText: text,\n tooltipText: text,\n onRemoveFilter: () => {\n queryContext.removeValueFromQueryFilter(queryFilter, value)\n },\n }\n })\n}\n\nexport function getPillPropsFromTextMatchesQueryFilter(\n queryFilter: TextMatchesQueryFilter,\n queryContext: QueryContextType,\n): SelectionCriteriaPillProps {\n let innerText = queryFilter.searchExpression\n if (queryFilter.searchMode == 'BOOLEAN') {\n innerText = getSearchTextFromBooleanModeSearchExpression(\n queryFilter.searchExpression,\n )\n }\n\n return {\n key: `queryFilter-${queryFilter.concreteType}-${queryFilter.searchExpression}`,\n innerText,\n tooltipText: `Text matches: \"${innerText}\"`,\n onRemoveFilter: () => {\n queryContext.removeQueryFilter(queryFilter)\n },\n }\n}\n\nfunction getPillPropsFromQueryFilters(\n queryFilters: ReadonlyDeep<QueryFilter[]>,\n queryContext: QueryContextType,\n columnModels: ColumnModel[],\n queryVisualizationContext: QueryVisualizationContextType,\n lockedColumn?: LockedColumn,\n): SelectionCriteriaPillProps[] {\n return queryFilters.flatMap(queryFilter => {\n if (\n isColumnSingleValueQueryFilter(queryFilter) ||\n isColumnMultiValueFunctionQueryFilter(queryFilter)\n ) {\n const columnModel = columnModels.find(\n cm => cm.name === queryFilter.columnName,\n )\n if (\n queryFilter.columnName.toLowerCase() ===\n lockedColumn?.columnName?.toLowerCase()\n ) {\n return []\n }\n return getPillPropsFromColumnQueryFilter(\n queryFilter,\n queryContext,\n columnModel,\n queryVisualizationContext,\n )\n } else if (isTextMatchesQueryFilter(queryFilter)) {\n return [getPillPropsFromTextMatchesQueryFilter(queryFilter, queryContext)]\n } else {\n console.log('Unknown query filter type', queryFilter)\n return []\n }\n })\n}\n\nfunction getRangeFacetInnerText(min?: string, max?: string) {\n if (min == undefined && max == undefined) {\n return 'Any value'\n } else if (min == undefined) {\n return `Up to ${max}`\n } else if (max == undefined) {\n return `${min} or greater`\n } else if (min === VALUE_NOT_SET && max === VALUE_NOT_SET) {\n return FRIENDLY_VALUE_NOT_SET\n } else {\n return `${min} - ${max}`\n }\n}\n\nfunction getPillPropsFromFacetFilters(\n selectedFacets: ReadonlyDeep<FacetColumnRequest[]>,\n queryContext: QueryContextType,\n columnModels: ColumnModel[],\n queryVisualizationContext: QueryVisualizationContextType,\n lockedColumn?: LockedColumn,\n): SelectionCriteriaPillProps[] {\n return selectedFacets.flatMap(selectedFacet => {\n if (\n selectedFacet.columnName.toLowerCase() ===\n lockedColumn?.columnName?.toLowerCase()\n ) {\n return []\n }\n const columnModel = columnModels.find(\n cm => cm.name === selectedFacet.columnName,\n )\n const { getColumnDisplayName, getDisplayValue } = queryVisualizationContext\n if (isFacetColumnValuesRequest(selectedFacet)) {\n // If there are more than _n_ values, consolidate to one pill\n if (\n selectedFacet.facetValues.length >\n MAX_VALUES_IN_FILTER_FOR_INDIVIDUAL_PILLS ||\n !columnModel\n ) {\n const text = `${pluralize(\n getColumnDisplayName(\n selectedFacet.columnName,\n selectedFacet.jsonPath,\n ),\n )} (${selectedFacet.facetValues.length.toLocaleString()})`\n return [\n {\n key: `facet-${selectedFacet.concreteType}-${selectedFacet.columnName}`,\n innerText: text,\n tooltipText: text,\n onRemoveFilter: () => {\n queryContext.removeSelectedFacet(selectedFacet)\n },\n },\n ]\n }\n\n // otherwise render one pill per value\n\n return selectedFacet.facetValues.map(facetValue => {\n const innerText = getDisplayValue(facetValue, columnModel.columnType)\n return {\n key: `facet-${selectedFacet.concreteType}-${selectedFacet.columnName}-${facetValue}`,\n innerText: innerText,\n tooltipText: `${getColumnDisplayName(\n selectedFacet.columnName,\n selectedFacet.jsonPath,\n )}: ${innerText}`,\n onRemoveFilter: () => {\n queryContext.removeValueFromSelectedFacet(selectedFacet, facetValue)\n },\n }\n })\n } else if (isFacetColumnRangeRequest(selectedFacet)) {\n // Include a single pill for both facet filters if a combined range facet filter config is defined\n const { combineRangeFacetConfig } = queryContext\n if (\n combineRangeFacetConfig &&\n (selectedFacet.columnName == combineRangeFacetConfig.minFacetColumn ||\n selectedFacet.columnName == combineRangeFacetConfig.maxFacetColumn)\n ) {\n if (\n selectedFacet.columnName == combineRangeFacetConfig.minFacetColumn\n ) {\n return []\n } else {\n // find the min facet also\n const maxFacet = selectedFacet\n const minFacet = selectedFacets.find(\n v => v.columnName == combineRangeFacetConfig.minFacetColumn,\n ) as FacetColumnRangeRequest\n const innerText = getRangeFacetInnerText(maxFacet.min, minFacet.max)\n return [\n {\n key: `facet-${selectedFacet.concreteType}-${selectedFacet.columnName}-${innerText}`,\n innerText: innerText,\n tooltipText: `${combineRangeFacetConfig.label}: ${innerText}`,\n onRemoveFilter: () => {\n // Remove both facets on pill click\n queryContext.removeSelectedFacet([minFacet, maxFacet])\n },\n },\n ]\n }\n }\n\n const innerText = getRangeFacetInnerText(\n selectedFacet.min,\n selectedFacet.max,\n )\n\n return [\n {\n key: `facet-${selectedFacet.concreteType}-${selectedFacet.columnName}-${selectedFacet.min}-${selectedFacet.max}`,\n innerText: innerText,\n tooltipText: `${getColumnDisplayName(\n selectedFacet.columnName,\n selectedFacet.jsonPath,\n )}: ${innerText}`,\n onRemoveFilter: () => {\n queryContext.removeSelectedFacet(selectedFacet)\n },\n },\n ]\n } else {\n console.log(\n 'Unknown facet type',\n (selectedFacet as unknown as FacetColumnRequest).concreteType,\n )\n return []\n }\n })\n}\n\nfunction SelectionCriteriaPills() {\n const queryContext = useQueryContext()\n const lockedColumn = queryContext.lockedColumn\n const queryVisualizationContext = useQueryVisualizationContext()\n const { currentQueryRequest } = queryContext\n const { data: queryMetadata } = useGetQueryMetadata()\n\n const queryFilterPillProps = getPillPropsFromQueryFilters(\n currentQueryRequest.query?.additionalFilters ?? [],\n queryContext,\n queryMetadata?.columnModels || [],\n queryVisualizationContext,\n lockedColumn,\n )\n\n const facetPillProps = getPillPropsFromFacetFilters(\n currentQueryRequest.query.selectedFacets ?? [],\n queryContext,\n queryMetadata?.columnModels || [],\n queryVisualizationContext,\n lockedColumn,\n )\n\n const allPills = [...queryFilterPillProps, ...facetPillProps]\n\n return (\n <>\n {allPills.map(pillProps => {\n // Encode the key because the facet may include an illegal character\n const key = encodeURIComponent(pillProps.key)\n return <SelectionCriteriaPill {...pillProps} key={key} />\n })}\n </>\n )\n}\n\nexport default SelectionCriteriaPills\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"useFacetPlots.js","names":[],"sources":["../../../../src/components/widgets/facet-nav/useFacetPlots.ts"],"sourcesContent":["import { isSingleNotSetValue } from '@/utils/functions/queryUtils'\nimport {\n FacetColumnRequest,\n FacetColumnResult,\n FacetColumnResultValueCount,\n FacetColumnResultValues,\n QueryResultBundle,\n} from '@sage-bionetworks/synapse-types'\nimport { useCallback, useMemo } from 'react'\nimport { useQueryContext } from '../../QueryContext'\nimport { useSuspenseGetQueryMetadata } from '../../QueryWrapper/useGetQueryMetadata'\nimport { applyChangesToValuesColumn } from '../query-filter/FacetFilterControls'\nimport { FacetNavPanelProps } from './FacetNavPanel'\n\n// Custom hook for generating properties for FacetNavPanel components with filter controls based on the given facets\nexport default function useFacetPlots(\n facetsToPlot: string[],\n): Pick<\n FacetNavPanelProps,\n 'applyChangesToFacetFilter' | 'applyChangesToGraphSlice' | 'facetToPlot'\n>[] {\n const { getCurrentQueryRequest, executeQueryRequest } = useQueryContext()\n\n const { data: queryMetadata } = useSuspenseGetQueryMetadata()\n\n const lastQueryRequest = useMemo(\n () => getCurrentQueryRequest(),\n [getCurrentQueryRequest],\n )\n const facets = useMemo(\n () => getFacets(queryMetadata, facetsToPlot),\n [queryMetadata, facetsToPlot],\n )\n\n const applyChangesFromQueryFilter = useCallback(\n (facets: FacetColumnRequest[]) => {\n executeQueryRequest(\n lastQueryRequest => {\n lastQueryRequest.query.selectedFacets = facets\n lastQueryRequest.query.offset = 0\n return lastQueryRequest\n },\n { debounce: true },\n )\n },\n [executeQueryRequest],\n )\n\n const facetNavPanelProps = useMemo(\n () =>\n facets.map(facet => {\n return {\n facetToPlot: facet as FacetColumnResultValues,\n\n applyChangesToFacetFilter: applyChangesFromQueryFilter,\n\n applyChangesToGraphSlice: (\n facet: FacetColumnResultValues,\n value: FacetColumnResultValueCount | undefined,\n isSelected: boolean,\n ) =>\n applyChangesToValuesColumn(\n lastQueryRequest,\n facet,\n applyChangesFromQueryFilter,\n value?.value,\n isSelected,\n ),\n }\n }),\n [facets, applyChangesFromQueryFilter, lastQueryRequest],\n )\n return facetNavPanelProps\n}\n\nexport function getFacets(\n data: QueryResultBundle | undefined,\n facetsToPlot?: string[],\n): FacetColumnResult[] {\n const result =\n data?.facets?.filter(item => {\n const isFacetToPlot =\n item.facetType === 'enumeration' &&\n (!facetsToPlot?.length || facetsToPlot.indexOf(item.columnName) > -1)\n // PORTALS-1993: only plot if the facet has count data\n return (\n isFacetToPlot &&\n item.facetValues.length > 0 &&\n !isSingleNotSetValue(item)\n )\n }) ?? []\n if (facetsToPlot?.length) {\n result.sort(\n (a, b) =>\n facetsToPlot.indexOf(a.columnName) - facetsToPlot.indexOf(b.columnName),\n )\n }\n return result\n}\n"],"mappings":";;;;;;;AAeA,SAAwB,EACtB,GAIE;CACF,IAAM,EAAE,2BAAwB,2BAAwB,GAAiB,EAEnE,EAAE,MAAM,MAAkB,GAA6B,EAEvD,IAAmB,QACjB,GAAwB,EAC9B,CAAC,EAAuB,CACzB,EACK,IAAS,QACP,EAAU,GAAe,EAAa,EAC5C,CAAC,GAAe,EAAa,CAC9B,EAEK,IAA8B,GACjC,MAAiC;AAChC,KACE,OACE,EAAiB,MAAM,iBAAiB,GACxC,EAAiB,MAAM,SAAS,GACzB,IAET,EAAE,UAAU,IAAM,CACnB;IAEH,CAAC,EAAoB,CACtB;AA0BD,QAxB2B,QAEvB,EAAO,KAAI,OACF;EACL,aAAa;EAEb,2BAA2B;EAE3B,2BACE,GACA,GACA,MAEA,EACE,GACA,GACA,GACA,GAAO,OACP,EACD;EACJ,EACD,EACJ;EAAC;EAAQ;EAA6B;EAAiB,CACxD;;AAIH,SAAgB,EACd,GACA,GACqB;CACrB,IAAM,IACJ,GAAM,QAAQ,QAAO,MAEjB,EAAK,cAAc,kBAClB,CAAC,GAAc,UAAU,EAAa,QAAQ,EAAK,WAAW,GAAG,OAIlE,EAAK,YAAY,SAAS,KAC1B,CAAC,EAAoB,EAAK,CAE5B,IAAI,EAAE;AAOV,QANI,GAAc,UAChB,EAAO,MACJ,GAAG,MACF,EAAa,QAAQ,EAAE,WAAW,GAAG,EAAa,QAAQ,EAAE,WAAW,CAC1E,EAEI"}
1
+ {"version":3,"file":"useFacetPlots.js","names":[],"sources":["../../../../src/components/widgets/facet-nav/useFacetPlots.ts"],"sourcesContent":["import { isSingleNotSetValue } from '@/utils/functions/queryUtils'\nimport {\n FacetColumnRequest,\n FacetColumnResult,\n FacetColumnResultValueCount,\n FacetColumnResultValues,\n QueryResultBundle,\n} from '@sage-bionetworks/synapse-types'\nimport { useCallback, useMemo } from 'react'\nimport { useQueryContext } from '../../QueryContext'\nimport { useSuspenseGetQueryMetadata } from '../../QueryWrapper/useGetQueryMetadata'\nimport { applyChangesToValuesColumn } from '../query-filter/FacetFilterControls'\nimport { FacetNavPanelProps } from './FacetNavPanel'\n\n// Custom hook for generating properties for FacetNavPanel components with filter controls based on the given facets\nexport default function useFacetPlots(\n facetsToPlot: string[],\n): Pick<\n FacetNavPanelProps,\n 'applyChangesToFacetFilter' | 'applyChangesToGraphSlice' | 'facetToPlot'\n>[] {\n const { getCurrentQueryRequest, executeQueryRequest } = useQueryContext()\n\n const { data: queryMetadata } = useSuspenseGetQueryMetadata()\n\n const lastQueryRequest = useMemo(\n () => getCurrentQueryRequest(),\n [getCurrentQueryRequest],\n )\n const facets = useMemo(\n () => getFacets(queryMetadata, facetsToPlot),\n [queryMetadata, facetsToPlot],\n )\n\n const applyChangesFromQueryFilter = useCallback(\n (facets: FacetColumnRequest[]) => {\n executeQueryRequest(\n lastQueryRequest => {\n lastQueryRequest.query.selectedFacets = facets\n lastQueryRequest.query.offset = 0\n return lastQueryRequest\n },\n { debounce: true },\n )\n },\n [executeQueryRequest],\n )\n\n const facetNavPanelProps = useMemo(\n () =>\n facets.map(facet => {\n return {\n facetToPlot: facet as FacetColumnResultValues,\n\n applyChangesToFacetFilter: applyChangesFromQueryFilter,\n\n applyChangesToGraphSlice: (\n facet: FacetColumnResultValues,\n value: FacetColumnResultValueCount | undefined,\n isSelected: boolean,\n ) =>\n applyChangesToValuesColumn(\n lastQueryRequest,\n facet,\n applyChangesFromQueryFilter,\n value?.value,\n isSelected,\n ),\n }\n }),\n [facets, applyChangesFromQueryFilter, lastQueryRequest],\n )\n return facetNavPanelProps\n}\n\nexport function getFacets(\n data: QueryResultBundle | undefined,\n facetsToPlot?: string[],\n): FacetColumnResult[] {\n const result =\n data?.facets?.filter(item => {\n const isFacetToPlot =\n item.facetType === 'enumeration' &&\n (!facetsToPlot?.length || facetsToPlot.indexOf(item.columnName) > -1)\n // PORTALS-1993: only plot if the facet has count data\n return (\n isFacetToPlot &&\n item.facetValues.length > 0 &&\n !isSingleNotSetValue(item)\n )\n }) ?? []\n if (facetsToPlot?.length) {\n result.sort(\n (a, b) =>\n facetsToPlot.indexOf(a.columnName) - facetsToPlot.indexOf(b.columnName),\n )\n }\n return result\n}\n"],"mappings":";;;;;;;AAeA,SAAwB,EACtB,GAIE;CACF,IAAM,EAAE,2BAAwB,2BAAwB,GAAiB,EAEnE,EAAE,MAAM,MAAkB,GAA6B,EAEvD,IAAmB,QACjB,GAAwB,EAC9B,CAAC,EAAuB,CACzB,EACK,IAAS,QACP,EAAU,GAAe,EAAa,EAC5C,CAAC,GAAe,EAAa,CAC9B,EAEK,IAA8B,GACjC,MAAiC;AAChC,KACE,OACE,EAAiB,MAAM,iBAAiB,GACxC,EAAiB,MAAM,SAAS,GACzB,IAET,EAAE,UAAU,IAAM,CACnB;IAEH,CAAC,EAAoB,CACtB;AA0BD,QAxB2B,QAEvB,EAAO,KAAI,OACF;EACL,aAAa;EAEb,2BAA2B;EAE3B,2BACE,GACA,GACA,MAEA,EACE,GACA,GACA,GACA,GAAO,OACP,EACD;EACJ,EACD,EACJ;EAAC;EAAQ;EAA6B;EAAiB,CAElD;;AAGT,SAAgB,EACd,GACA,GACqB;CACrB,IAAM,IACJ,GAAM,QAAQ,QAAO,MAEjB,EAAK,cAAc,kBAClB,CAAC,GAAc,UAAU,EAAa,QAAQ,EAAK,WAAW,GAAG,OAIlE,EAAK,YAAY,SAAS,KAC1B,CAAC,EAAoB,EAAK,CAE5B,IAAI,EAAE;AAOV,QANI,GAAc,UAChB,EAAO,MACJ,GAAG,MACF,EAAa,QAAQ,EAAE,WAAW,GAAG,EAAa,QAAQ,EAAE,WAAW,CAC1E,EAEI"}
@@ -1 +1 @@
1
- {"version":3,"file":"CombinedRangeFacetFilter.js","names":[],"sources":["../../../../src/components/widgets/query-filter/CombinedRangeFacetFilter.tsx"],"sourcesContent":["import { useGetQueryResultBundleWithAsyncStatus } from '@/synapse-queries'\nimport { SynapseConstants } from '@/utils'\nimport { VALUE_NOT_SET } from '@/utils/SynapseConstants'\nimport { Skeleton } from '@mui/material'\nimport {\n ColumnType,\n FacetColumnResultRange,\n} from '@sage-bionetworks/synapse-types'\nimport { isNumber } from 'lodash-es'\nimport { useMemo } from 'react'\nimport { useQueryContext } from '../../QueryContext'\nimport { useQueryVisualizationContext } from '../../QueryVisualizationWrapper'\nimport { RangeValues } from '../Range'\nimport { RangeFacetFilterUI } from './RangeFacetFilterUI'\n\nexport type CombinedRangeFacetFilterProps = {\n facetResults: FacetColumnResultRange[]\n label: string\n columnType: ColumnType\n}\n\n/**\n * Inclusive range selector across two columns\n * Written for the ELITE portal cohort builder, may have other uses.\n * The following diagram shows how the Range Selector min and max values are used\n * to define the facet range values:\n * \n\n Range Selector \n min ├────────────────────────┤ max\n \n Min Column facet \n Column Min value ◄────────────────────────────┤ Range Selector max\n \n Max Column facet\n Range Selector min ├────────────────────────────► Column Max value\n \n\n*/\nexport function CombinedRangeFacetFilter({\n facetResults,\n label,\n columnType,\n}: CombinedRangeFacetFilterProps) {\n const { getCurrentQueryRequest, setRangeFacetValue, removeSelectedFacet } =\n useQueryContext()\n const { getColumnDisplayName } = useQueryVisualizationContext()\n\n const {\n columnName: col1Name,\n // columnMax: col1Max // not used\n // selectedMin: col1SelectedMin // not used\n selectedMax: col1SelectedMax,\n } = facetResults[0]\n const {\n columnName: col2Name,\n //columnMin: col2Min, // not used\n selectedMin: col2SelectedMin,\n // selectedMax: col2SelectedMax, // not used\n } = facetResults[1]\n\n // Also query for the facet columns full range (without any selected facets), to set the range selector range\n const queryBundleRequest = useMemo(() => {\n const requestCopy = getCurrentQueryRequest()\n requestCopy.partMask = SynapseConstants.BUNDLE_MASK_QUERY_FACETS\n const { selectedFacets } = requestCopy.query\n requestCopy.query.selectedFacets = selectedFacets\n ? selectedFacets.filter(\n facetRequest =>\n facetRequest.columnName !== col1Name &&\n facetRequest.columnName !== col2Name,\n )\n : []\n return requestCopy\n }, [col1Name, col2Name, getCurrentQueryRequest])\n\n const { data: queryResultFacetResponse, isLoading: isLoadingFacetStats } =\n useGetQueryResultBundleWithAsyncStatus(queryBundleRequest)\n\n const fullFacetStats = queryResultFacetResponse?.responseBody?.facets\n\n const col1Facet = fullFacetStats?.find(facet => facet.columnName === col1Name)\n const col2Facet = fullFacetStats?.find(facet => facet.columnName === col2Name)\n const col1GlobalMin = (col1Facet as FacetColumnResultRange)?.columnMin\n const col2GlobalMax = (col2Facet as FacetColumnResultRange)?.columnMax\n const selectedMin = col2SelectedMin\n const selectedMax = col1SelectedMax\n\n if (isLoadingFacetStats || !col1Facet || !col2Facet) {\n return <Skeleton variant=\"rectangular\" width=\"100\" />\n }\n return (\n <RangeFacetFilterUI\n label={getColumnDisplayName(label)}\n facetResult={{\n columnMin: col1GlobalMin,\n columnMax: col2GlobalMax,\n selectedMin: selectedMin,\n selectedMax: selectedMax,\n }}\n columnType={columnType}\n onRangeValueSelected={(values: RangeValues) => {\n setRangeFacetValue(\n col1Facet,\n col1GlobalMin,\n isNumber(values.max) ? String(values.max) : values.max,\n { noCommit: true },\n )\n\n setRangeFacetValue(\n col2Facet,\n isNumber(values.min) ? String(values.min) : values.min,\n col2GlobalMax,\n )\n }}\n onNotSetSelected={() => {\n setRangeFacetValue(col1Facet, VALUE_NOT_SET, VALUE_NOT_SET)\n setRangeFacetValue(col2Facet, VALUE_NOT_SET, VALUE_NOT_SET)\n }}\n onAnySelected={() => {\n removeSelectedFacet(col1Facet)\n removeSelectedFacet(col2Facet)\n }}\n />\n )\n}\n"],"mappings":";;;;;;;;;;;;;;AAuCA,SAAgB,EAAyB,EACvC,iBACA,UACA,iBACgC;CAChC,IAAM,EAAE,2BAAwB,uBAAoB,2BAClD,GAAiB,EACb,EAAE,4BAAyB,GAA8B,EAEzD,EACJ,YAAY,GAGZ,aAAa,MACX,EAAa,IACX,EACJ,YAAY,GAEZ,aAAa,MAEX,EAAa,IAiBX,EAAE,MAAM,GAA0B,WAAW,MACjD,EAfyB,QAAc;EACvC,IAAM,IAAc,GAAwB;AAC5C,IAAY,WAAW;EACvB,IAAM,EAAE,sBAAmB,EAAY;AAQvC,SAPA,EAAY,MAAM,iBAAiB,IAC/B,EAAe,QACb,MACE,EAAa,eAAe,KAC5B,EAAa,eAAe,EAC/B,GACD,EAAE,EACC;IACN;EAAC;EAAU;EAAU;EAAuB,CAAC,CAGY,EAEtD,IAAiB,GAA0B,cAAc,QAEzD,IAAY,GAAgB,MAAK,MAAS,EAAM,eAAe,EAAS,EACxE,IAAY,GAAgB,MAAK,MAAS,EAAM,eAAe,EAAS,EACxE,IAAiB,GAAsC,WACvD,IAAiB,GAAsC,WACvD,IAAc,GACd,IAAc;AAKpB,QAHI,KAAuB,CAAC,KAAa,CAAC,IACjC,kBAAC,GAAD;EAAU,SAAQ;EAAc,OAAM;EAAQ,CAAA,GAGrD,kBAAC,GAAD;EACE,OAAO,EAAqB,EAAM;EAClC,aAAa;GACX,WAAW;GACX,WAAW;GACE;GACA;GACd;EACW;EACZ,uBAAuB,MAAwB;AAQ7C,GAPA,EACE,GACA,GACA,EAAS,EAAO,IAAI,GAAG,OAAO,EAAO,IAAI,GAAG,EAAO,KACnD,EAAE,UAAU,IAAM,CACnB,EAED,EACE,GACA,EAAS,EAAO,IAAI,GAAG,OAAO,EAAO,IAAI,GAAG,EAAO,KACnD,EACD;;EAEH,wBAAwB;AAEtB,GADA,EAAmB,GAAW,GAAe,EAAc,EAC3D,EAAmB,GAAW,GAAe,EAAc;;EAE7D,qBAAqB;AAEnB,GADA,EAAoB,EAAU,EAC9B,EAAoB,EAAU;;EAEhC,CAAA"}
1
+ {"version":3,"file":"CombinedRangeFacetFilter.js","names":[],"sources":["../../../../src/components/widgets/query-filter/CombinedRangeFacetFilter.tsx"],"sourcesContent":["import { useGetQueryResultBundleWithAsyncStatus } from '@/synapse-queries'\nimport { SynapseConstants } from '@/utils'\nimport { VALUE_NOT_SET } from '@/utils/SynapseConstants'\nimport { Skeleton } from '@mui/material'\nimport {\n ColumnType,\n FacetColumnResultRange,\n} from '@sage-bionetworks/synapse-types'\nimport { isNumber } from 'lodash-es'\nimport { useMemo } from 'react'\nimport { useQueryContext } from '../../QueryContext'\nimport { useQueryVisualizationContext } from '../../QueryVisualizationWrapper'\nimport { RangeValues } from '../Range'\nimport { RangeFacetFilterUI } from './RangeFacetFilterUI'\n\nexport type CombinedRangeFacetFilterProps = {\n facetResults: FacetColumnResultRange[]\n label: string\n columnType: ColumnType\n}\n\n/**\n * Inclusive range selector across two columns\n * Written for the ELITE portal cohort builder, may have other uses.\n * The following diagram shows how the Range Selector min and max values are used\n * to define the facet range values:\n * \n\n Range Selector \n min ├────────────────────────┤ max\n \n Min Column facet \n Column Min value ◄────────────────────────────┤ Range Selector max\n \n Max Column facet\n Range Selector min ├────────────────────────────► Column Max value\n \n\n*/\nexport function CombinedRangeFacetFilter({\n facetResults,\n label,\n columnType,\n}: CombinedRangeFacetFilterProps) {\n const { getCurrentQueryRequest, setRangeFacetValue, removeSelectedFacet } =\n useQueryContext()\n const { getColumnDisplayName } = useQueryVisualizationContext()\n\n const {\n columnName: col1Name,\n // columnMax: col1Max // not used\n // selectedMin: col1SelectedMin // not used\n selectedMax: col1SelectedMax,\n } = facetResults[0]\n const {\n columnName: col2Name,\n //columnMin: col2Min, // not used\n selectedMin: col2SelectedMin,\n // selectedMax: col2SelectedMax, // not used\n } = facetResults[1]\n\n // Also query for the facet columns full range (without any selected facets), to set the range selector range\n const queryBundleRequest = useMemo(() => {\n const requestCopy = getCurrentQueryRequest()\n requestCopy.partMask = SynapseConstants.BUNDLE_MASK_QUERY_FACETS\n const { selectedFacets } = requestCopy.query\n requestCopy.query.selectedFacets = selectedFacets\n ? selectedFacets.filter(\n facetRequest =>\n facetRequest.columnName !== col1Name &&\n facetRequest.columnName !== col2Name,\n )\n : []\n return requestCopy\n }, [col1Name, col2Name, getCurrentQueryRequest])\n\n const { data: queryResultFacetResponse, isLoading: isLoadingFacetStats } =\n useGetQueryResultBundleWithAsyncStatus(queryBundleRequest)\n\n const fullFacetStats = queryResultFacetResponse?.responseBody?.facets\n\n const col1Facet = fullFacetStats?.find(facet => facet.columnName === col1Name)\n const col2Facet = fullFacetStats?.find(facet => facet.columnName === col2Name)\n const col1GlobalMin = (col1Facet as FacetColumnResultRange)?.columnMin\n const col2GlobalMax = (col2Facet as FacetColumnResultRange)?.columnMax\n const selectedMin = col2SelectedMin\n const selectedMax = col1SelectedMax\n\n if (isLoadingFacetStats || !col1Facet || !col2Facet) {\n return <Skeleton variant=\"rectangular\" width=\"100\" />\n }\n return (\n <RangeFacetFilterUI\n label={getColumnDisplayName(label)}\n facetResult={{\n columnMin: col1GlobalMin,\n columnMax: col2GlobalMax,\n selectedMin: selectedMin,\n selectedMax: selectedMax,\n }}\n columnType={columnType}\n onRangeValueSelected={(values: RangeValues) => {\n setRangeFacetValue(\n col1Facet,\n col1GlobalMin,\n isNumber(values.max) ? String(values.max) : values.max,\n { noCommit: true },\n )\n\n setRangeFacetValue(\n col2Facet,\n isNumber(values.min) ? String(values.min) : values.min,\n col2GlobalMax,\n )\n }}\n onNotSetSelected={() => {\n setRangeFacetValue(col1Facet, VALUE_NOT_SET, VALUE_NOT_SET)\n setRangeFacetValue(col2Facet, VALUE_NOT_SET, VALUE_NOT_SET)\n }}\n onAnySelected={() => {\n removeSelectedFacet(col1Facet)\n removeSelectedFacet(col2Facet)\n }}\n />\n )\n}\n"],"mappings":";;;;;;;;;;;;;;AAuCA,SAAgB,EAAyB,EACvC,iBACA,UACA,iBACgC;CAChC,IAAM,EAAE,2BAAwB,uBAAoB,2BAClD,GAAiB,EACb,EAAE,4BAAyB,GAA8B,EAEzD,EACJ,YAAY,GAGZ,aAAa,MACX,EAAa,IACX,EACJ,YAAY,GAEZ,aAAa,MAEX,EAAa,IAiBX,EAAE,MAAM,GAA0B,WAAW,MACjD,EAfyB,QAAc;EACvC,IAAM,IAAc,GAAwB;AAC5C,IAAY,WAAW;EACvB,IAAM,EAAE,sBAAmB,EAAY;AAQvC,SAPA,EAAY,MAAM,iBAAiB,IAC/B,EAAe,QACb,MACE,EAAa,eAAe,KAC5B,EAAa,eAAe,EAC/B,GACD,EAAE,EACC;IACN;EAAC;EAAU;EAAU;EAAuB,CAGN,CAAmB,EAEtD,IAAiB,GAA0B,cAAc,QAEzD,IAAY,GAAgB,MAAK,MAAS,EAAM,eAAe,EAAS,EACxE,IAAY,GAAgB,MAAK,MAAS,EAAM,eAAe,EAAS,EACxE,IAAiB,GAAsC,WACvD,IAAiB,GAAsC,WACvD,IAAc,GACd,IAAc;AAKpB,QAHI,KAAuB,CAAC,KAAa,CAAC,IACjC,kBAAC,GAAD;EAAU,SAAQ;EAAc,OAAM;EAAQ,CAAA,GAGrD,kBAAC,GAAD;EACE,OAAO,EAAqB,EAAM;EAClC,aAAa;GACX,WAAW;GACX,WAAW;GACE;GACA;GACd;EACW;EACZ,uBAAuB,MAAwB;AAQ7C,GAPA,EACE,GACA,GACA,EAAS,EAAO,IAAI,GAAG,OAAO,EAAO,IAAI,GAAG,EAAO,KACnD,EAAE,UAAU,IAAM,CACnB,EAED,EACE,GACA,EAAS,EAAO,IAAI,GAAG,OAAO,EAAO,IAAI,GAAG,EAAO,KACnD,EACD;;EAEH,wBAAwB;AAEtB,GADA,EAAmB,GAAW,GAAe,EAAc,EAC3D,EAAmB,GAAW,GAAe,EAAc;;EAE7D,qBAAqB;AAEnB,GADA,EAAoB,EAAU,EAC9B,EAAoB,EAAU;;EAEhC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"EnumFacetFilter.js","names":[],"sources":["../../../../../src/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilter.tsx"],"sourcesContent":["import { isFacetColumnValuesRequest, SynapseConstants } from '@/utils'\nimport {\n getCorrespondingColumnForFacet,\n getCorrespondingSelectedFacet,\n} from '@/utils/functions/queryUtils'\nimport useGetInfoFromIds from '@/utils/hooks/useGetInfoFromIds'\nimport {\n ColumnTypeEnum,\n EntityHeader,\n Evaluation,\n FacetColumnRequest,\n FacetColumnResultValueCount,\n FacetColumnResultValues,\n FacetColumnValuesRequest,\n QueryBundleRequest,\n UserGroupHeader,\n} from '@sage-bionetworks/synapse-types'\nimport { cloneDeep, partition, pick, sortBy } from 'lodash-es'\nimport { Suspense, useMemo } from 'react'\nimport { useQueryContext } from '../../../QueryContext'\nimport { useQueryVisualizationContext } from '../../../QueryVisualizationWrapper'\nimport { useSuspenseGetQueryMetadata } from '../../../QueryWrapper/useGetQueryMetadata'\nimport { EnumFacetFilterSkeleton } from './EnumFacetFilterSkeleton'\nimport EnumFacetFilterUI, { RenderedFacetValue } from './EnumFacetFilterUI'\nimport { getAllIsSelected, valueToLabel } from './EnumFacetFilterUtils'\n\nexport type EnumFacetFilterProps = {\n facet: FacetColumnResultValues\n containerAs?: 'Collapsible' | 'Dropdown'\n dropdownType?: 'Icon' | 'SelectBox'\n hideCollapsible?: boolean\n defaultShowAllValues?: boolean\n}\n\nfunction EnumFacetFilterInternal(props: EnumFacetFilterProps) {\n const {\n facet,\n containerAs = 'Collapsible',\n dropdownType = 'Icon',\n hideCollapsible = false,\n defaultShowAllValues = false,\n } = props\n const {\n nextQueryRequest,\n addValueToSelectedFacet,\n removeSelectedFacet,\n removeValueFromSelectedFacet,\n resetDebounceTimer,\n } = useQueryContext()\n\n const { data: queryMetadata } = useSuspenseGetQueryMetadata()\n const { getColumnDisplayName } = useQueryVisualizationContext()\n\n const currentSelectedFacet: FacetColumnValuesRequest | undefined =\n useMemo(() => {\n const facetColumnRequest = getCorrespondingSelectedFacet(\n facet,\n cloneDeep(nextQueryRequest.query.selectedFacets) as\n | FacetColumnRequest[]\n | undefined,\n )\n\n if (\n facetColumnRequest &&\n !isFacetColumnValuesRequest(facetColumnRequest)\n ) {\n console.error(\n `The facet rendered in EnumFacetFilter is not a FacetColumnValuesRequest`,\n facet,\n )\n return undefined\n }\n return facetColumnRequest\n }, [facet, nextQueryRequest.query.selectedFacets])\n\n // Must compare the known facet values to the \"uncommitted\" current query\n const allIsSelected = getAllIsSelected(\n cloneDeep(nextQueryRequest) as QueryBundleRequest,\n facet,\n )\n\n const columnModel = queryMetadata.columnModels\n ? getCorrespondingColumnForFacet(facet, queryMetadata.columnModels)\n : undefined\n\n const isNumberColumnType = useMemo(() => {\n switch (columnModel?.columnType) {\n case ColumnTypeEnum.DOUBLE:\n case ColumnTypeEnum.DATE:\n case ColumnTypeEnum.INTEGER:\n return true\n default:\n return false\n }\n }, [columnModel])\n\n const userIds =\n columnModel?.columnType === ColumnTypeEnum.USERID ||\n columnModel?.columnType === ColumnTypeEnum.USERID_LIST\n ? facet.facetValues.map(facet => facet.value)\n : []\n const userGroupHeaders = useGetInfoFromIds<UserGroupHeader>({\n ids: userIds,\n type: 'USER_PROFILE',\n })\n\n const entityIds =\n columnModel?.columnType === ColumnTypeEnum.ENTITYID ||\n columnModel?.columnType === ColumnTypeEnum.ENTITYID_LIST\n ? facet.facetValues.map(facet => facet.value)\n : []\n const entityHeaders = useGetInfoFromIds<EntityHeader>({\n ids: entityIds,\n type: 'ENTITY_HEADER',\n })\n\n const evaluationIds =\n columnModel?.columnType === ColumnTypeEnum.EVALUATIONID\n ? facet.facetValues.map(facet => facet.value)\n : []\n const evaluations = useGetInfoFromIds<Evaluation>({\n ids: evaluationIds,\n type: 'EVALUATION_QUEUE',\n })\n\n const displayedFacetValues: RenderedFacetValue[] = useMemo(() => {\n const renderedFacetValues = facet.facetValues.map(\n (facetValue: FacetColumnResultValueCount): RenderedFacetValue => {\n return {\n ...facetValue,\n // Selected status should be based on the 'nextQuery', not the result data\n // This ensures the checkboxes respond instantly to user interaction, like while waiting for multiple changes to debounce\n isSelected:\n currentSelectedFacet?.facetValues.includes(facetValue.value) ??\n false,\n displayText: valueToLabel(\n facetValue,\n userGroupHeaders,\n entityHeaders,\n evaluations,\n ),\n }\n },\n )\n //Abby V's suggestion, always show the VALUE_NOT_SET facet value on the bottom of this sorted list\n const partitions = partition(\n renderedFacetValues,\n facet => facet.value === SynapseConstants.VALUE_NOT_SET,\n )\n const valueNotSetFacetArray = partitions[0]\n const restOfFacetValuesArray = partitions[1]\n\n // Apply client-side sorting if no server-side sort is specified\n let sortedValues: RenderedFacetValue[] = restOfFacetValuesArray\n const isClientSideSort =\n columnModel == undefined || columnModel.facetSortConfig == undefined\n if (isClientSideSort) {\n if (isNumberColumnType) {\n sortedValues = sortBy(restOfFacetValuesArray, fv => Number(fv.value))\n } else {\n sortedValues = sortBy(restOfFacetValuesArray, fv =>\n fv.displayText.toLowerCase(),\n )\n }\n }\n\n return [...sortedValues, ...valueNotSetFacetArray]\n }, [\n facet.facetValues,\n columnModel,\n currentSelectedFacet?.facetValues,\n userGroupHeaders,\n entityHeaders,\n evaluations,\n isNumberColumnType,\n ])\n\n if (!columnModel) {\n return <></>\n }\n\n return (\n <EnumFacetFilterUI\n facetTitle={getColumnDisplayName(facet.columnName, facet.jsonPath)}\n filterIsActive={!allIsSelected}\n facetValues={displayedFacetValues}\n containerAs={containerAs}\n dropdownType={dropdownType}\n hideCollapsible={hideCollapsible}\n defaultShowAllValues={defaultShowAllValues}\n onHoverOverValue={() => {\n // SWC-6698: delay the query execution (via the debounce) when an item is hovered over\n resetDebounceTimer()\n }}\n onAddValueToSelection={value => {\n addValueToSelectedFacet(\n pick(facet, ['columnName', 'jsonPath']),\n value,\n { debounce: true },\n )\n }}\n onRemoveValueFromSelection={value => {\n removeValueFromSelectedFacet(\n pick(facet, ['columnName', 'jsonPath']),\n value,\n { debounce: true },\n )\n }}\n onRemoveAllFacetSelections={() =>\n removeSelectedFacet(pick(facet, ['columnName', 'jsonPath']))\n }\n canMultiSelect={true}\n />\n )\n}\n\nexport function EnumFacetFilter(props: EnumFacetFilterProps) {\n const { containerAs = 'Collapsible', dropdownType = 'Icon' } = props\n return (\n <Suspense\n fallback={\n <EnumFacetFilterSkeleton\n containerAs={containerAs}\n dropdownType={dropdownType}\n />\n }\n >\n <EnumFacetFilterInternal {...props} />\n </Suspense>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"EnumFacetFilter.js","names":[],"sources":["../../../../../src/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilter.tsx"],"sourcesContent":["import { isFacetColumnValuesRequest, SynapseConstants } from '@/utils'\nimport {\n getCorrespondingColumnForFacet,\n getCorrespondingSelectedFacet,\n} from '@/utils/functions/queryUtils'\nimport useGetInfoFromIds from '@/utils/hooks/useGetInfoFromIds'\nimport {\n ColumnTypeEnum,\n EntityHeader,\n Evaluation,\n FacetColumnRequest,\n FacetColumnResultValueCount,\n FacetColumnResultValues,\n FacetColumnValuesRequest,\n QueryBundleRequest,\n UserGroupHeader,\n} from '@sage-bionetworks/synapse-types'\nimport { cloneDeep, partition, pick, sortBy } from 'lodash-es'\nimport { Suspense, useMemo } from 'react'\nimport { useQueryContext } from '../../../QueryContext'\nimport { useQueryVisualizationContext } from '../../../QueryVisualizationWrapper'\nimport { useSuspenseGetQueryMetadata } from '../../../QueryWrapper/useGetQueryMetadata'\nimport { EnumFacetFilterSkeleton } from './EnumFacetFilterSkeleton'\nimport EnumFacetFilterUI, { RenderedFacetValue } from './EnumFacetFilterUI'\nimport { getAllIsSelected, valueToLabel } from './EnumFacetFilterUtils'\n\nexport type EnumFacetFilterProps = {\n facet: FacetColumnResultValues\n containerAs?: 'Collapsible' | 'Dropdown'\n dropdownType?: 'Icon' | 'SelectBox'\n hideCollapsible?: boolean\n defaultShowAllValues?: boolean\n}\n\nfunction EnumFacetFilterInternal(props: EnumFacetFilterProps) {\n const {\n facet,\n containerAs = 'Collapsible',\n dropdownType = 'Icon',\n hideCollapsible = false,\n defaultShowAllValues = false,\n } = props\n const {\n nextQueryRequest,\n addValueToSelectedFacet,\n removeSelectedFacet,\n removeValueFromSelectedFacet,\n resetDebounceTimer,\n } = useQueryContext()\n\n const { data: queryMetadata } = useSuspenseGetQueryMetadata()\n const { getColumnDisplayName } = useQueryVisualizationContext()\n\n const currentSelectedFacet: FacetColumnValuesRequest | undefined =\n useMemo(() => {\n const facetColumnRequest = getCorrespondingSelectedFacet(\n facet,\n cloneDeep(nextQueryRequest.query.selectedFacets) as\n | FacetColumnRequest[]\n | undefined,\n )\n\n if (\n facetColumnRequest &&\n !isFacetColumnValuesRequest(facetColumnRequest)\n ) {\n console.error(\n `The facet rendered in EnumFacetFilter is not a FacetColumnValuesRequest`,\n facet,\n )\n return undefined\n }\n return facetColumnRequest\n }, [facet, nextQueryRequest.query.selectedFacets])\n\n // Must compare the known facet values to the \"uncommitted\" current query\n const allIsSelected = getAllIsSelected(\n cloneDeep(nextQueryRequest) as QueryBundleRequest,\n facet,\n )\n\n const columnModel = queryMetadata.columnModels\n ? getCorrespondingColumnForFacet(facet, queryMetadata.columnModels)\n : undefined\n\n const isNumberColumnType = useMemo(() => {\n switch (columnModel?.columnType) {\n case ColumnTypeEnum.DOUBLE:\n case ColumnTypeEnum.DATE:\n case ColumnTypeEnum.INTEGER:\n return true\n default:\n return false\n }\n }, [columnModel])\n\n const userIds =\n columnModel?.columnType === ColumnTypeEnum.USERID ||\n columnModel?.columnType === ColumnTypeEnum.USERID_LIST\n ? facet.facetValues.map(facet => facet.value)\n : []\n const userGroupHeaders = useGetInfoFromIds<UserGroupHeader>({\n ids: userIds,\n type: 'USER_PROFILE',\n })\n\n const entityIds =\n columnModel?.columnType === ColumnTypeEnum.ENTITYID ||\n columnModel?.columnType === ColumnTypeEnum.ENTITYID_LIST\n ? facet.facetValues.map(facet => facet.value)\n : []\n const entityHeaders = useGetInfoFromIds<EntityHeader>({\n ids: entityIds,\n type: 'ENTITY_HEADER',\n })\n\n const evaluationIds =\n columnModel?.columnType === ColumnTypeEnum.EVALUATIONID\n ? facet.facetValues.map(facet => facet.value)\n : []\n const evaluations = useGetInfoFromIds<Evaluation>({\n ids: evaluationIds,\n type: 'EVALUATION_QUEUE',\n })\n\n const displayedFacetValues: RenderedFacetValue[] = useMemo(() => {\n const renderedFacetValues = facet.facetValues.map(\n (facetValue: FacetColumnResultValueCount): RenderedFacetValue => {\n return {\n ...facetValue,\n // Selected status should be based on the 'nextQuery', not the result data\n // This ensures the checkboxes respond instantly to user interaction, like while waiting for multiple changes to debounce\n isSelected:\n currentSelectedFacet?.facetValues.includes(facetValue.value) ??\n false,\n displayText: valueToLabel(\n facetValue,\n userGroupHeaders,\n entityHeaders,\n evaluations,\n ),\n }\n },\n )\n //Abby V's suggestion, always show the VALUE_NOT_SET facet value on the bottom of this sorted list\n const partitions = partition(\n renderedFacetValues,\n facet => facet.value === SynapseConstants.VALUE_NOT_SET,\n )\n const valueNotSetFacetArray = partitions[0]\n const restOfFacetValuesArray = partitions[1]\n\n // Apply client-side sorting if no server-side sort is specified\n let sortedValues: RenderedFacetValue[] = restOfFacetValuesArray\n const isClientSideSort =\n columnModel == undefined || columnModel.facetSortConfig == undefined\n if (isClientSideSort) {\n if (isNumberColumnType) {\n sortedValues = sortBy(restOfFacetValuesArray, fv => Number(fv.value))\n } else {\n sortedValues = sortBy(restOfFacetValuesArray, fv =>\n fv.displayText.toLowerCase(),\n )\n }\n }\n\n return [...sortedValues, ...valueNotSetFacetArray]\n }, [\n facet.facetValues,\n columnModel,\n currentSelectedFacet?.facetValues,\n userGroupHeaders,\n entityHeaders,\n evaluations,\n isNumberColumnType,\n ])\n\n if (!columnModel) {\n return <></>\n }\n\n return (\n <EnumFacetFilterUI\n facetTitle={getColumnDisplayName(facet.columnName, facet.jsonPath)}\n filterIsActive={!allIsSelected}\n facetValues={displayedFacetValues}\n containerAs={containerAs}\n dropdownType={dropdownType}\n hideCollapsible={hideCollapsible}\n defaultShowAllValues={defaultShowAllValues}\n onHoverOverValue={() => {\n // SWC-6698: delay the query execution (via the debounce) when an item is hovered over\n resetDebounceTimer()\n }}\n onAddValueToSelection={value => {\n addValueToSelectedFacet(\n pick(facet, ['columnName', 'jsonPath']),\n value,\n { debounce: true },\n )\n }}\n onRemoveValueFromSelection={value => {\n removeValueFromSelectedFacet(\n pick(facet, ['columnName', 'jsonPath']),\n value,\n { debounce: true },\n )\n }}\n onRemoveAllFacetSelections={() =>\n removeSelectedFacet(pick(facet, ['columnName', 'jsonPath']))\n }\n canMultiSelect={true}\n />\n )\n}\n\nexport function EnumFacetFilter(props: EnumFacetFilterProps) {\n const { containerAs = 'Collapsible', dropdownType = 'Icon' } = props\n return (\n <Suspense\n fallback={\n <EnumFacetFilterSkeleton\n containerAs={containerAs}\n dropdownType={dropdownType}\n />\n }\n >\n <EnumFacetFilterInternal {...props} />\n </Suspense>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAkCA,SAAS,EAAwB,GAA6B;CAC5D,IAAM,EACJ,UACA,iBAAc,eACd,kBAAe,QACf,qBAAkB,IAClB,0BAAuB,OACrB,GACE,EACJ,qBACA,4BACA,wBACA,iCACA,0BACE,GAAiB,EAEf,EAAE,MAAM,MAAkB,GAA6B,EACvD,EAAE,4BAAyB,GAA8B,EAEzD,IACJ,QAAc;EACZ,IAAM,IAAqB,EACzB,GACA,EAAU,EAAiB,MAAM,eAAe,CAGjD;AAED,MACE,KACA,CAAC,EAA2B,EAAmB,EAC/C;AACA,WAAQ,MACN,2EACA,EACD;AACD;;AAEF,SAAO;IACN,CAAC,GAAO,EAAiB,MAAM,eAAe,CAAC,EAG9C,IAAgB,EACpB,EAAU,EAAiB,EAC3B,EACD,EAEK,IAAc,EAAc,eAC9B,EAA+B,GAAO,EAAc,aAAa,GACjE,KAAA,GAEE,IAAqB,QAAc;AACvC,UAAQ,GAAa,YAArB;GACE,KAAK,EAAe;GACpB,KAAK,EAAe;GACpB,KAAK,EAAe,QAClB,QAAO;GACT,QACE,QAAO;;IAEV,CAAC,EAAY,CAAC,EAOX,IAAmB,EAAmC;EAC1D,KALA,GAAa,eAAe,EAAe,UAC3C,GAAa,eAAe,EAAe,cACvC,EAAM,YAAY,KAAI,MAAS,EAAM,MAAM,GAC3C,EAAE;EAGN,MAAM;EACP,CAAC,EAOI,IAAgB,EAAgC;EACpD,KALA,GAAa,eAAe,EAAe,YAC3C,GAAa,eAAe,EAAe,gBACvC,EAAM,YAAY,KAAI,MAAS,EAAM,MAAM,GAC3C,EAAE;EAGN,MAAM;EACP,CAAC,EAMI,IAAc,EAA8B;EAChD,KAJA,GAAa,eAAe,EAAe,eACvC,EAAM,YAAY,KAAI,MAAS,EAAM,MAAM,GAC3C,EAAE;EAGN,MAAM;EACP,CAAC,EAEI,IAA6C,QAAc;EAoB/D,IAAM,IAAa,EAnBS,EAAM,YAAY,KAC3C,OACQ;GACL,GAAG;GAGH,YACE,GAAsB,YAAY,SAAS,EAAW,MAAM,IAC5D;GACF,aAAa,EACX,GACA,GACA,GACA,EACD;GACF,EAKH,GACA,MAAS,EAAM,UAAU,EAC1B,EACK,IAAwB,EAAW,IACnC,IAAyB,EAAW,IAGtC,IAAqC;AAazC,UAXE,KAAe,QAAa,EAAY,mBAAmB,UAE3D,AAGE,IAHE,IACa,EAAO,IAAwB,MAAM,OAAO,EAAG,MAAM,CAAC,GAEtD,EAAO,IAAwB,MAC5C,EAAG,YAAY,aAAa,CAC7B,GAIE,CAAC,GAAG,GAAc,GAAG,EAAsB;IACjD;EACD,EAAM;EACN;EACA,GAAsB;EACtB;EACA;EACA;EACA;EACD,CAAC;AAMF,QAJK,IAKH,kBAAC,GAAD;EACE,YAAY,EAAqB,EAAM,YAAY,EAAM,SAAS;EAClE,gBAAgB,CAAC;EACjB,aAAa;EACA;EACC;EACG;EACK;EACtB,wBAAwB;AAEtB,MAAoB;;EAEtB,wBAAuB,MAAS;AAC9B,KACE,EAAK,GAAO,CAAC,cAAc,WAAW,CAAC,EACvC,GACA,EAAE,UAAU,IAAM,CACnB;;EAEH,6BAA4B,MAAS;AACnC,KACE,EAAK,GAAO,CAAC,cAAc,WAAW,CAAC,EACvC,GACA,EAAE,UAAU,IAAM,CACnB;;EAEH,kCACE,EAAoB,EAAK,GAAO,CAAC,cAAc,WAAW,CAAC,CAAC;EAE9D,gBAAgB;EAChB,CAAA,GAlCK,kBAAA,GAAA,EAAK,CAAA;;AAsChB,SAAgB,EAAgB,GAA6B;CAC3D,IAAM,EAAE,iBAAc,eAAe,kBAAe,WAAW;AAC/D,QACE,kBAAC,GAAD;EACE,UACE,kBAAC,GAAD;GACe;GACC;GACd,CAAA;YAGJ,kBAAC,GAAD,EAAyB,GAAI,GAAS,CAAA;EAC7B,CAAA"}