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":"SynapseNavDrawer.js","names":[],"sources":["../../../src/components/SynapseNavDrawer/SynapseNavDrawer.tsx"],"sourcesContent":["import React from 'react'\nimport SynapseIconWhite from '@/assets/icons/SynapseIconWhite'\nimport SynapseLogoName from '@/assets/icons/SynapseLogoName'\nimport {\n useGetCurrentUserBundle,\n useGetDownloadListStatistics,\n useSearchAccessSubmissionsInfinite,\n} from '@/synapse-queries'\nimport {\n storeRedirectURLForOneSageLoginAndGotoURL,\n useApplicationSessionContext,\n useSynapseContext,\n} from '@/utils'\nimport { useOneSageURL } from '@/utils/hooks/useOneSageURL'\nimport {\n Badge,\n Drawer,\n InputAdornment,\n List,\n ListItemButton,\n TextField,\n Tooltip,\n} from '@mui/material'\nimport {\n Direction,\n SubmissionSortField,\n SubmissionState,\n} from '@sage-bionetworks/synapse-types'\nimport { KeyboardEvent, ReactNode, useState } from 'react'\nimport { CreateProjectModal } from '../CreateProjectModal/CreateProjectModal'\nimport IconSvg, { IconName } from '../IconSvg/IconSvg'\nimport { PLANS_LINK } from '../SynapseHomepageV2/SynapseHomepageNavBar'\nimport UserCard from '../UserCard/UserCard'\nimport { DEFAULT_SEARCH_QUERY } from '@/utils/searchDefaults'\n\nexport type SynapseNavDrawerProps = {\n initIsOpen?: boolean\n gotoPlace: (href: string) => void\n}\n\ntype MenuItemParams = {\n tooltip: string\n iconName?: IconName\n onClickOpenNavMenu?: NavItem\n onClickGoToPlace?: () => void\n additionalChildren?: ReactNode\n badgeContent?: string | number\n isCurrentlySelectedItem?: boolean\n handleDrawerClose: () => void\n handleDrawerOpen: (navItem?: NavItem) => void\n}\n\nexport enum NavItem {\n PROJECTS,\n FAVORITES,\n TEAMS,\n CHALLENGES,\n DOWNLOADS,\n SEARCH,\n PROFILE,\n HELP,\n}\n\nexport const getSearchToken = (queryTerm: string[]) => {\n const searchQuery = {\n ...DEFAULT_SEARCH_QUERY,\n queryTerm,\n }\n return encodeURIComponent(JSON.stringify(searchQuery))\n}\n\nconst projectSearchJson = {\n // To support project search, we send this json object in the url.\n // We update the queryTerm array based on user input.\n ...DEFAULT_SEARCH_QUERY,\n booleanQuery: [\n {\n key: 'node_type',\n value: 'project',\n },\n ],\n}\nconst getProjectSearchToken = (queryTerm: string[]) => {\n const searchQuery = {\n ...projectSearchJson,\n queryTerm,\n }\n return encodeURIComponent(JSON.stringify(searchQuery))\n}\n\nconst NavDrawerListItem = (props: MenuItemParams): React.ReactNode => {\n const {\n tooltip,\n iconName,\n onClickOpenNavMenu,\n onClickGoToPlace,\n additionalChildren,\n badgeContent,\n isCurrentlySelectedItem = false,\n handleDrawerClose,\n handleDrawerOpen,\n } = props\n const handler =\n isCurrentlySelectedItem || onClickGoToPlace\n ? handleDrawerClose\n : () => {\n handleDrawerOpen(onClickOpenNavMenu)\n }\n const item = iconName ? (\n <>\n <IconSvg icon={iconName} /> {additionalChildren}{' '}\n </>\n ) : (\n additionalChildren\n )\n\n const listItem = (\n <Tooltip title={tooltip} placement=\"right\">\n <ListItemButton\n key={iconName}\n onClick={handler}\n className=\"SRC-whiteText\"\n selected={isCurrentlySelectedItem}\n >\n <Badge badgeContent={badgeContent} color=\"secondary\">\n {item}\n </Badge>\n </ListItemButton>\n </Tooltip>\n )\n\n return onClickGoToPlace ? (\n <li>\n <a\n onClick={onClickGoToPlace}\n rel=\"noopener noreferrer\"\n className=\"SRC-whiteText\"\n >\n {listItem}\n </a>\n </li>\n ) : (\n <li>{listItem}</li>\n )\n}\n\n/**\n * Displays the Synapse navigational drawer on the left side of the page. Has links to various areas if logged in.\n */\nexport function SynapseNavDrawer({\n initIsOpen = false,\n gotoPlace,\n}: SynapseNavDrawerProps) {\n const [isOpen, setOpen] = useState(initIsOpen)\n const [selectedItem, setSelectedItem] = useState<NavItem>()\n const [projectSearchText, setProjectSearchText] = useState<string>('')\n const [docSiteSearchText, setDocSiteSearchText] = useState<string>('')\n const [isShowingCreateProjectModal, setIsShowingCreateProjectModal] =\n useState<boolean>(false)\n\n const { clearSession } = useApplicationSessionContext()\n\n const { isAuthenticated } = useSynapseContext()\n\n const { data: currentUserBundle } = useGetCurrentUserBundle()\n\n // If the user is logged out, the UserBundle provides an \"anonymous\" user profile, so override that case with undefined\n const currentUserProfile =\n isAuthenticated && currentUserBundle\n ? currentUserBundle.userProfile\n : undefined\n\n const { data: downloadListStatistics } = useGetDownloadListStatistics({\n enabled: isAuthenticated,\n })\n\n const numberOfFilesInDownloadList = downloadListStatistics?.totalNumberOfFiles\n\n const { data: openSubmissionData } = useSearchAccessSubmissionsInfinite(\n {\n submissionState: SubmissionState.SUBMITTED,\n sort: [\n {\n field: SubmissionSortField.CREATED_ON,\n direction: Direction.DESC,\n },\n ],\n },\n {\n enabled: currentUserBundle?.isARReviewer,\n },\n )\n\n let countOfOpenSubmissionsForReview: number | string =\n openSubmissionData?.pages[0].results.length ?? 0\n if (openSubmissionData?.pages[0].nextPageToken) {\n countOfOpenSubmissionsForReview = `${countOfOpenSubmissionsForReview}+`\n }\n\n const handleDrawerOpen = (navItem?: NavItem) => {\n setOpen(true)\n setSelectedItem(navItem)\n }\n\n const handleDrawerClose = () => {\n setOpen(false)\n setSelectedItem(undefined)\n }\n\n const onProjectSearch = (searchTerm: string) => {\n gotoPlace(\n `/SearchV2:default?query=${getProjectSearchToken(\n searchTerm.split(/[ ,]+/),\n )}`,\n )\n }\n\n const oneSageURL = useOneSageURL()\n const accountSettingsURL = useOneSageURL('/authenticated/myaccount')\n\n return (\n <>\n <div className=\"SynapseNavDrawer\">\n <Drawer\n variant=\"permanent\"\n className={`SynapseNavDrawerMenu ${isOpen ? 'tempDrawerOpen' : ''}`}\n >\n <div onClick={handleDrawerClose}>\n <a\n className=\"synapseIcon\"\n rel=\"noopener noreferrer\"\n onClick={() => gotoPlace('/Home:x')}\n aria-label=\"Synapse Home\"\n >\n <SynapseIconWhite />\n </a>\n </div>\n <List>\n {isAuthenticated && currentUserProfile && (\n <>\n <NavDrawerListItem\n tooltip=\"Projects\"\n iconName=\"dashboard\"\n onClickOpenNavMenu={NavItem.PROJECTS}\n isCurrentlySelectedItem={selectedItem == NavItem.PROJECTS}\n handleDrawerClose={handleDrawerClose}\n handleDrawerOpen={handleDrawerOpen}\n />\n <NavDrawerListItem\n tooltip=\"Favorites\"\n iconName=\"favTwoTone\"\n onClickGoToPlace={() =>\n gotoPlace(\n `/Profile:${currentUserProfile.ownerId}/favorites`,\n )\n }\n handleDrawerClose={handleDrawerClose}\n handleDrawerOpen={handleDrawerOpen}\n />\n <NavDrawerListItem\n tooltip=\"Teams\"\n iconName=\"peopleTwoTone\"\n onClickGoToPlace={() =>\n gotoPlace(`/Profile:${currentUserProfile.ownerId}/teams`)\n }\n handleDrawerClose={handleDrawerClose}\n handleDrawerOpen={handleDrawerOpen}\n />\n <NavDrawerListItem\n tooltip=\"Challenges\"\n iconName=\"challengesTwoTone\"\n onClickGoToPlace={() =>\n gotoPlace(\n `/Profile:${currentUserProfile.ownerId}/challenges`,\n )\n }\n handleDrawerClose={handleDrawerClose}\n handleDrawerOpen={handleDrawerOpen}\n />\n <NavDrawerListItem\n tooltip=\"Download List\"\n iconName=\"download\"\n onClickGoToPlace={() => gotoPlace('/DownloadCart:0')}\n badgeContent={numberOfFilesInDownloadList}\n handleDrawerClose={handleDrawerClose}\n handleDrawerOpen={handleDrawerOpen}\n />\n <NavDrawerListItem\n tooltip=\"Trash Can\"\n iconName=\"delete\"\n onClickGoToPlace={() => gotoPlace('/Trash:0')}\n handleDrawerClose={handleDrawerClose}\n handleDrawerOpen={handleDrawerOpen}\n />\n {currentUserBundle?.isARReviewer && (\n <NavDrawerListItem\n tooltip=\"Data Access Management\"\n iconName=\"accessManagement\"\n onClickGoToPlace={() =>\n gotoPlace('/DataAccessManagement:default/Submissions')\n }\n badgeContent={countOfOpenSubmissionsForReview}\n handleDrawerClose={handleDrawerClose}\n handleDrawerOpen={handleDrawerOpen}\n />\n )}\n </>\n )}\n <NavDrawerListItem\n tooltip=\"Search\"\n iconName=\"search\"\n onClickGoToPlace={() => gotoPlace('/SearchV2:default')}\n handleDrawerClose={handleDrawerClose}\n handleDrawerOpen={handleDrawerOpen}\n />\n </List>\n <div className=\"filler\" />\n <List>\n {isAuthenticated && currentUserProfile && (\n <NavDrawerListItem\n tooltip=\"Your Account\"\n onClickOpenNavMenu={NavItem.PROFILE}\n additionalChildren={\n <UserCard\n userProfile={currentUserProfile}\n size=\"AVATAR\"\n avatarSize=\"SMALL\"\n />\n }\n isCurrentlySelectedItem={selectedItem == NavItem.PROFILE}\n handleDrawerClose={handleDrawerClose}\n handleDrawerOpen={handleDrawerOpen}\n />\n )}\n {!isAuthenticated && (\n <NavDrawerListItem\n tooltip=\"Sign in\"\n iconName=\"login\"\n onClickGoToPlace={() =>\n storeRedirectURLForOneSageLoginAndGotoURL(\n oneSageURL.toString(),\n )\n }\n handleDrawerClose={handleDrawerClose}\n handleDrawerOpen={handleDrawerOpen}\n />\n )}\n <NavDrawerListItem\n tooltip=\"Help\"\n iconName=\"helpOutlined\"\n onClickOpenNavMenu={NavItem.HELP}\n isCurrentlySelectedItem={selectedItem == NavItem.HELP}\n handleDrawerClose={handleDrawerClose}\n handleDrawerOpen={handleDrawerOpen}\n />\n </List>\n </Drawer>\n <Drawer\n variant=\"temporary\"\n open={isOpen}\n className={`SynapseNavContentDrawer`}\n onClose={handleDrawerClose}\n >\n <div className=\"synapseLogoNameContainer\">\n <SynapseLogoName />\n </div>\n <div className=\"navContentContainer\">\n {selectedItem == NavItem.PROJECTS && (\n <>\n <div className=\"header projectHeader\">Projects</div>\n <Tooltip title=\"Create a New Project\" placement=\"right\">\n <a\n className=\"createProjectLink\"\n onClick={() => {\n setIsShowingCreateProjectModal(true)\n handleDrawerClose()\n }}\n >\n <IconSvg icon=\"addCircleOutline\" />\n </a>\n </Tooltip>\n <TextField\n type=\"search\"\n placeholder=\"Search All Projects\"\n value={projectSearchText}\n onChange={event => {\n setProjectSearchText(event.target.value)\n }}\n onKeyDown={(event: KeyboardEvent<HTMLInputElement>) => {\n if (event.key === 'Enter') {\n if ((event.target as HTMLInputElement).value !== '') {\n setProjectSearchText('')\n handleDrawerClose()\n onProjectSearch(\n (event.target as HTMLInputElement).value,\n )\n }\n }\n }}\n slotProps={{\n input: {\n startAdornment: (\n <InputAdornment position=\"start\">\n <IconSvg icon=\"searchOutlined\" />\n </InputAdornment>\n ),\n },\n }}\n />\n <div className=\"linkList\" onClick={handleDrawerClose}>\n <a\n className=\"SRC-whiteText\"\n onClick={() =>\n gotoPlace(\n `/Profile:${currentUserProfile?.ownerId}/projects/all`,\n )\n }\n rel=\"noopener noreferrer\"\n >\n All\n </a>\n <a\n className=\"SRC-whiteText\"\n onClick={() =>\n gotoPlace(\n `/Profile:${currentUserProfile?.ownerId}/projects/created_by_me`,\n )\n }\n rel=\"noopener noreferrer\"\n >\n Created By Me\n </a>\n <a\n className=\"SRC-whiteText\"\n onClick={() =>\n gotoPlace(\n `/Profile:${currentUserProfile?.ownerId}/projects/favorites`,\n )\n }\n rel=\"noopener noreferrer\"\n >\n Favorite Projects\n </a>\n <a\n className=\"SRC-whiteText\"\n onClick={() =>\n gotoPlace(\n `/Profile:${currentUserProfile?.ownerId}/projects/shared_directly_with_me`,\n )\n }\n rel=\"noopener noreferrer\"\n >\n Shared With Me\n </a>\n <a\n className=\"SRC-whiteText\"\n onClick={() =>\n gotoPlace(\n `/Profile:${currentUserProfile?.ownerId}/projects/all_my_team_projects`,\n )\n }\n rel=\"noopener noreferrer\"\n >\n Team Projects\n </a>\n </div>\n </>\n )}\n {selectedItem == NavItem.PROFILE && (\n <>\n <div className=\"header\">\n Welcome Back,\n <br />\n {currentUserProfile?.userName}!\n </div>\n <div className=\"linkList\" onClick={handleDrawerClose}>\n <a\n className=\"SRC-whiteText\"\n onClick={() =>\n gotoPlace(\n `/Profile:${currentUserProfile?.ownerId}/profile`,\n )\n }\n rel=\"noopener noreferrer\"\n >\n View Profile\n </a>\n <a\n className=\"SRC-whiteText\"\n href={accountSettingsURL.toString()}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Account Settings\n </a>\n <a\n className=\"SRC-whiteText\"\n onClick={() => gotoPlace(`/RequestHistory:default`)}\n rel=\"noopener noreferrer\"\n >\n Access Requests\n </a>\n <a\n className=\"SRC-whiteText\"\n onClick={() => gotoPlace(`/Following:0`)}\n rel=\"noopener noreferrer\"\n >\n Following\n </a>\n <a\n className=\"SRC-whiteText\"\n onClick={() => {\n void clearSession()\n }}\n rel=\"noopener noreferrer\"\n >\n Sign Out\n </a>\n </div>\n </>\n )}\n {selectedItem == NavItem.HELP && (\n <>\n <div className=\"header\">Help</div>\n <TextField\n type=\"search\"\n placeholder=\"Search Documentation\"\n value={docSiteSearchText}\n onChange={event => {\n setDocSiteSearchText(event.target.value)\n }}\n onKeyDown={event => {\n if (event.key === 'Enter') {\n if ((event.target as HTMLInputElement).value !== '') {\n window.open(\n `https://help.synapse.org/search.html?max=10&s=docs&q=${encodeURI(\n (event.target as HTMLInputElement).value,\n )}`,\n )\n setDocSiteSearchText('')\n handleDrawerClose()\n }\n }\n }}\n slotProps={{\n input: {\n startAdornment: (\n <InputAdornment position=\"start\">\n <IconSvg icon=\"searchOutlined\" />\n </InputAdornment>\n ),\n },\n }}\n />\n\n <div className=\"linkList\" onClick={handleDrawerClose}>\n <a\n className=\"SRC-whiteText\"\n href=\"https://help.synapse.org/docs/Getting-Started.2055471150.html\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Getting Started\n </a>\n <a\n className=\"SRC-whiteText\"\n onClick={() => gotoPlace(PLANS_LINK)}\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Plans\n </a>\n <a\n className=\"SRC-whiteText\"\n href=\"https://help.synapse.org/docs/\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Synapse Web Documentation\n </a>\n <a\n className=\"SRC-whiteText\"\n href=\"https://python-docs.synapse.org/en/stable/\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Python Client Documentation\n </a>\n <a\n className=\"SRC-whiteText\"\n href=\"https://r-docs.synapse.org/\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n R Client Documentation\n </a>\n <a\n className=\"SRC-whiteText\"\n href=\"https://blog.synapse.org/\"\n rel=\"noopener noreferrer\"\n >\n Blog\n </a>\n <a\n className=\"SRC-whiteText\"\n href=\"https://sagebionetworks.jira.com/servicedesk/customer/portals/\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Contact Us\n </a>\n </div>\n </>\n )}\n </div>\n </Drawer>\n </div>\n <CreateProjectModal\n onClose={() => setIsShowingCreateProjectModal(false)}\n isShowingModal={isShowingCreateProjectModal}\n />\n </>\n )\n}\n\nexport default SynapseNavDrawer\n"],"mappings":"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"}
1
+ {"version":3,"file":"SynapseNavDrawer.js","names":[],"sources":["../../../src/components/SynapseNavDrawer/SynapseNavDrawer.tsx"],"sourcesContent":["import React from 'react'\nimport SynapseIconWhite from '@/assets/icons/SynapseIconWhite'\nimport SynapseLogoName from '@/assets/icons/SynapseLogoName'\nimport {\n useGetCurrentUserBundle,\n useGetDownloadListStatistics,\n useSearchAccessSubmissionsInfinite,\n} from '@/synapse-queries'\nimport {\n storeRedirectURLForOneSageLoginAndGotoURL,\n useApplicationSessionContext,\n useSynapseContext,\n} from '@/utils'\nimport { useOneSageURL } from '@/utils/hooks/useOneSageURL'\nimport {\n Badge,\n Drawer,\n InputAdornment,\n List,\n ListItemButton,\n TextField,\n Tooltip,\n} from '@mui/material'\nimport {\n Direction,\n SubmissionSortField,\n SubmissionState,\n} from '@sage-bionetworks/synapse-types'\nimport { KeyboardEvent, ReactNode, useState } from 'react'\nimport { CreateProjectModal } from '../CreateProjectModal/CreateProjectModal'\nimport IconSvg, { IconName } from '../IconSvg/IconSvg'\nimport { PLANS_LINK } from '../SynapseHomepageV2/SynapseHomepageNavBar'\nimport UserCard from '../UserCard/UserCard'\nimport { DEFAULT_SEARCH_QUERY } from '@/utils/searchDefaults'\nimport { useGetCurationTasksInfinite } from '@/synapse-queries/curation/task/useCurationTask'\n\nexport type SynapseNavDrawerProps = {\n initIsOpen?: boolean\n gotoPlace: (href: string) => void\n}\n\ntype MenuItemParams = {\n tooltip: string\n iconName?: IconName\n onClickOpenNavMenu?: NavItem\n onClickGoToPlace?: () => void\n additionalChildren?: ReactNode\n badgeContent?: string | number\n isCurrentlySelectedItem?: boolean\n handleDrawerClose: () => void\n handleDrawerOpen: (navItem?: NavItem) => void\n}\n\nexport enum NavItem {\n PROJECTS,\n CURATOR_DASHBOARD,\n FAVORITES,\n TEAMS,\n CHALLENGES,\n DOWNLOADS,\n SEARCH,\n PROFILE,\n HELP,\n}\n\nexport const getSearchToken = (queryTerm: string[]) => {\n const searchQuery = {\n ...DEFAULT_SEARCH_QUERY,\n queryTerm,\n }\n return encodeURIComponent(JSON.stringify(searchQuery))\n}\n\nconst projectSearchJson = {\n // To support project search, we send this json object in the url.\n // We update the queryTerm array based on user input.\n ...DEFAULT_SEARCH_QUERY,\n booleanQuery: [\n {\n key: 'node_type',\n value: 'project',\n },\n ],\n}\nconst getProjectSearchToken = (queryTerm: string[]) => {\n const searchQuery = {\n ...projectSearchJson,\n queryTerm,\n }\n return encodeURIComponent(JSON.stringify(searchQuery))\n}\n\nconst NavDrawerListItem = (props: MenuItemParams): React.ReactNode => {\n const {\n tooltip,\n iconName,\n onClickOpenNavMenu,\n onClickGoToPlace,\n additionalChildren,\n badgeContent,\n isCurrentlySelectedItem = false,\n handleDrawerClose,\n handleDrawerOpen,\n } = props\n const handler =\n isCurrentlySelectedItem || onClickGoToPlace\n ? handleDrawerClose\n : () => {\n handleDrawerOpen(onClickOpenNavMenu)\n }\n const item = iconName ? (\n <>\n <IconSvg icon={iconName} /> {additionalChildren}{' '}\n </>\n ) : (\n additionalChildren\n )\n\n const listItem = (\n <Tooltip title={tooltip} placement=\"right\">\n <ListItemButton\n key={iconName}\n onClick={handler}\n className=\"SRC-whiteText\"\n selected={isCurrentlySelectedItem}\n >\n <Badge badgeContent={badgeContent} color=\"secondary\">\n {item}\n </Badge>\n </ListItemButton>\n </Tooltip>\n )\n\n return onClickGoToPlace ? (\n <li>\n <a\n onClick={onClickGoToPlace}\n rel=\"noopener noreferrer\"\n className=\"SRC-whiteText\"\n >\n {listItem}\n </a>\n </li>\n ) : (\n <li>{listItem}</li>\n )\n}\n\n/**\n * Displays the Synapse navigational drawer on the left side of the page. Has links to various areas if logged in.\n */\nexport function SynapseNavDrawer({\n initIsOpen = false,\n gotoPlace,\n}: SynapseNavDrawerProps) {\n const [isOpen, setOpen] = useState(initIsOpen)\n const [selectedItem, setSelectedItem] = useState<NavItem>()\n const [projectSearchText, setProjectSearchText] = useState<string>('')\n const [docSiteSearchText, setDocSiteSearchText] = useState<string>('')\n const [isShowingCreateProjectModal, setIsShowingCreateProjectModal] =\n useState<boolean>(false)\n\n const { clearSession } = useApplicationSessionContext()\n\n const { isAuthenticated } = useSynapseContext()\n\n const { data: currentUserBundle } = useGetCurrentUserBundle()\n\n // If the user is logged out, the UserBundle provides an \"anonymous\" user profile, so override that case with undefined\n const currentUserProfile =\n isAuthenticated && currentUserBundle\n ? currentUserBundle.userProfile\n : undefined\n\n const { data: downloadListStatistics } = useGetDownloadListStatistics({\n enabled: isAuthenticated,\n })\n\n const numberOfFilesInDownloadList = downloadListStatistics?.totalNumberOfFiles\n\n const { data: openSubmissionData } = useSearchAccessSubmissionsInfinite(\n {\n submissionState: SubmissionState.SUBMITTED,\n sort: [\n {\n field: SubmissionSortField.CREATED_ON,\n direction: Direction.DESC,\n },\n ],\n },\n {\n enabled: currentUserBundle?.isARReviewer,\n },\n )\n\n let countOfOpenSubmissionsForReview: number | string =\n openSubmissionData?.pages[0].results.length ?? 0\n if (openSubmissionData?.pages[0].nextPageToken) {\n countOfOpenSubmissionsForReview = `${countOfOpenSubmissionsForReview}+`\n }\n\n const { data: curationTasksAssignedToCurrentUser } =\n useGetCurationTasksInfinite(\n { assignedToMe: true },\n { enabled: isAuthenticated },\n )\n const hasCurationTasksAssignedToCurrentUser = Boolean(\n curationTasksAssignedToCurrentUser?.pages.some(\n page => page.bundlePage && page.bundlePage.length > 0,\n ),\n )\n\n const handleDrawerOpen = (navItem?: NavItem) => {\n setOpen(true)\n setSelectedItem(navItem)\n }\n\n const handleDrawerClose = () => {\n setOpen(false)\n setSelectedItem(undefined)\n }\n\n const onProjectSearch = (searchTerm: string) => {\n gotoPlace(\n `/SearchV2:default?query=${getProjectSearchToken(\n searchTerm.split(/[ ,]+/),\n )}`,\n )\n }\n\n const oneSageURL = useOneSageURL()\n const accountSettingsURL = useOneSageURL('/authenticated/myaccount')\n\n return (\n <>\n <div className=\"SynapseNavDrawer\">\n <Drawer\n variant=\"permanent\"\n className={`SynapseNavDrawerMenu ${isOpen ? 'tempDrawerOpen' : ''}`}\n >\n <div onClick={handleDrawerClose}>\n <a\n className=\"synapseIcon\"\n rel=\"noopener noreferrer\"\n onClick={() => gotoPlace('/Home:x')}\n aria-label=\"Synapse Home\"\n >\n <SynapseIconWhite />\n </a>\n </div>\n <List>\n {isAuthenticated && currentUserProfile && (\n <>\n <NavDrawerListItem\n tooltip=\"Projects\"\n iconName=\"dashboard\"\n onClickOpenNavMenu={NavItem.PROJECTS}\n isCurrentlySelectedItem={selectedItem == NavItem.PROJECTS}\n handleDrawerClose={handleDrawerClose}\n handleDrawerOpen={handleDrawerOpen}\n />\n {hasCurationTasksAssignedToCurrentUser && (\n <NavDrawerListItem\n tooltip=\"Curator Dashboard\"\n iconName=\"tasks\"\n onClickGoToPlace={() => gotoPlace('/CuratorDashboard:0')}\n isCurrentlySelectedItem={\n selectedItem == NavItem.CURATOR_DASHBOARD\n }\n handleDrawerClose={handleDrawerClose}\n handleDrawerOpen={handleDrawerOpen}\n />\n )}\n <NavDrawerListItem\n tooltip=\"Favorites\"\n iconName=\"favTwoTone\"\n onClickGoToPlace={() =>\n gotoPlace(\n `/Profile:${currentUserProfile.ownerId}/favorites`,\n )\n }\n handleDrawerClose={handleDrawerClose}\n handleDrawerOpen={handleDrawerOpen}\n />\n <NavDrawerListItem\n tooltip=\"Teams\"\n iconName=\"peopleTwoTone\"\n onClickGoToPlace={() =>\n gotoPlace(`/Profile:${currentUserProfile.ownerId}/teams`)\n }\n handleDrawerClose={handleDrawerClose}\n handleDrawerOpen={handleDrawerOpen}\n />\n <NavDrawerListItem\n tooltip=\"Challenges\"\n iconName=\"challengesTwoTone\"\n onClickGoToPlace={() =>\n gotoPlace(\n `/Profile:${currentUserProfile.ownerId}/challenges`,\n )\n }\n handleDrawerClose={handleDrawerClose}\n handleDrawerOpen={handleDrawerOpen}\n />\n <NavDrawerListItem\n tooltip=\"Download List\"\n iconName=\"download\"\n onClickGoToPlace={() => gotoPlace('/DownloadCart:0')}\n badgeContent={numberOfFilesInDownloadList}\n handleDrawerClose={handleDrawerClose}\n handleDrawerOpen={handleDrawerOpen}\n />\n <NavDrawerListItem\n tooltip=\"Trash Can\"\n iconName=\"delete\"\n onClickGoToPlace={() => gotoPlace('/Trash:0')}\n handleDrawerClose={handleDrawerClose}\n handleDrawerOpen={handleDrawerOpen}\n />\n {currentUserBundle?.isARReviewer && (\n <NavDrawerListItem\n tooltip=\"Data Access Management\"\n iconName=\"accessManagement\"\n onClickGoToPlace={() =>\n gotoPlace('/DataAccessManagement:default/Submissions')\n }\n badgeContent={countOfOpenSubmissionsForReview}\n handleDrawerClose={handleDrawerClose}\n handleDrawerOpen={handleDrawerOpen}\n />\n )}\n </>\n )}\n <NavDrawerListItem\n tooltip=\"Search\"\n iconName=\"search\"\n onClickGoToPlace={() => gotoPlace('/SearchV2:default')}\n handleDrawerClose={handleDrawerClose}\n handleDrawerOpen={handleDrawerOpen}\n />\n </List>\n <div className=\"filler\" />\n <List>\n {isAuthenticated && currentUserProfile && (\n <NavDrawerListItem\n tooltip=\"Your Account\"\n onClickOpenNavMenu={NavItem.PROFILE}\n additionalChildren={\n <UserCard\n userProfile={currentUserProfile}\n size=\"AVATAR\"\n avatarSize=\"SMALL\"\n />\n }\n isCurrentlySelectedItem={selectedItem == NavItem.PROFILE}\n handleDrawerClose={handleDrawerClose}\n handleDrawerOpen={handleDrawerOpen}\n />\n )}\n {!isAuthenticated && (\n <NavDrawerListItem\n tooltip=\"Sign in\"\n iconName=\"login\"\n onClickGoToPlace={() =>\n storeRedirectURLForOneSageLoginAndGotoURL(\n oneSageURL.toString(),\n )\n }\n handleDrawerClose={handleDrawerClose}\n handleDrawerOpen={handleDrawerOpen}\n />\n )}\n <NavDrawerListItem\n tooltip=\"Help\"\n iconName=\"helpOutlined\"\n onClickOpenNavMenu={NavItem.HELP}\n isCurrentlySelectedItem={selectedItem == NavItem.HELP}\n handleDrawerClose={handleDrawerClose}\n handleDrawerOpen={handleDrawerOpen}\n />\n </List>\n </Drawer>\n <Drawer\n variant=\"temporary\"\n open={isOpen}\n className={`SynapseNavContentDrawer`}\n onClose={handleDrawerClose}\n >\n <div className=\"synapseLogoNameContainer\">\n <SynapseLogoName />\n </div>\n <div className=\"navContentContainer\">\n {selectedItem == NavItem.PROJECTS && (\n <>\n <div className=\"header projectHeader\">Projects</div>\n <Tooltip title=\"Create a New Project\" placement=\"right\">\n <a\n className=\"createProjectLink\"\n onClick={() => {\n setIsShowingCreateProjectModal(true)\n handleDrawerClose()\n }}\n >\n <IconSvg icon=\"addCircleOutline\" />\n </a>\n </Tooltip>\n <TextField\n type=\"search\"\n placeholder=\"Search All Projects\"\n value={projectSearchText}\n onChange={event => {\n setProjectSearchText(event.target.value)\n }}\n onKeyDown={(event: KeyboardEvent<HTMLInputElement>) => {\n if (event.key === 'Enter') {\n if ((event.target as HTMLInputElement).value !== '') {\n setProjectSearchText('')\n handleDrawerClose()\n onProjectSearch(\n (event.target as HTMLInputElement).value,\n )\n }\n }\n }}\n slotProps={{\n input: {\n startAdornment: (\n <InputAdornment position=\"start\">\n <IconSvg icon=\"searchOutlined\" />\n </InputAdornment>\n ),\n },\n }}\n />\n <div className=\"linkList\" onClick={handleDrawerClose}>\n <a\n className=\"SRC-whiteText\"\n onClick={() =>\n gotoPlace(\n `/Profile:${currentUserProfile?.ownerId}/projects/all`,\n )\n }\n rel=\"noopener noreferrer\"\n >\n All\n </a>\n <a\n className=\"SRC-whiteText\"\n onClick={() =>\n gotoPlace(\n `/Profile:${currentUserProfile?.ownerId}/projects/created_by_me`,\n )\n }\n rel=\"noopener noreferrer\"\n >\n Created By Me\n </a>\n <a\n className=\"SRC-whiteText\"\n onClick={() =>\n gotoPlace(\n `/Profile:${currentUserProfile?.ownerId}/projects/favorites`,\n )\n }\n rel=\"noopener noreferrer\"\n >\n Favorite Projects\n </a>\n <a\n className=\"SRC-whiteText\"\n onClick={() =>\n gotoPlace(\n `/Profile:${currentUserProfile?.ownerId}/projects/shared_directly_with_me`,\n )\n }\n rel=\"noopener noreferrer\"\n >\n Shared With Me\n </a>\n <a\n className=\"SRC-whiteText\"\n onClick={() =>\n gotoPlace(\n `/Profile:${currentUserProfile?.ownerId}/projects/all_my_team_projects`,\n )\n }\n rel=\"noopener noreferrer\"\n >\n Team Projects\n </a>\n </div>\n </>\n )}\n {selectedItem == NavItem.PROFILE && (\n <>\n <div className=\"header\">\n Welcome Back,\n <br />\n {currentUserProfile?.userName}!\n </div>\n <div className=\"linkList\" onClick={handleDrawerClose}>\n <a\n className=\"SRC-whiteText\"\n onClick={() =>\n gotoPlace(\n `/Profile:${currentUserProfile?.ownerId}/profile`,\n )\n }\n rel=\"noopener noreferrer\"\n >\n View Profile\n </a>\n <a\n className=\"SRC-whiteText\"\n href={accountSettingsURL.toString()}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Account Settings\n </a>\n <a\n className=\"SRC-whiteText\"\n onClick={() => gotoPlace(`/RequestHistory:default`)}\n rel=\"noopener noreferrer\"\n >\n Access Requests\n </a>\n <a\n className=\"SRC-whiteText\"\n onClick={() => gotoPlace(`/Following:0`)}\n rel=\"noopener noreferrer\"\n >\n Following\n </a>\n <a\n className=\"SRC-whiteText\"\n onClick={() => {\n void clearSession()\n }}\n rel=\"noopener noreferrer\"\n >\n Sign Out\n </a>\n </div>\n </>\n )}\n {selectedItem == NavItem.HELP && (\n <>\n <div className=\"header\">Help</div>\n <TextField\n type=\"search\"\n placeholder=\"Search Documentation\"\n value={docSiteSearchText}\n onChange={event => {\n setDocSiteSearchText(event.target.value)\n }}\n onKeyDown={event => {\n if (event.key === 'Enter') {\n if ((event.target as HTMLInputElement).value !== '') {\n window.open(\n `https://help.synapse.org/search.html?max=10&s=docs&q=${encodeURI(\n (event.target as HTMLInputElement).value,\n )}`,\n )\n setDocSiteSearchText('')\n handleDrawerClose()\n }\n }\n }}\n slotProps={{\n input: {\n startAdornment: (\n <InputAdornment position=\"start\">\n <IconSvg icon=\"searchOutlined\" />\n </InputAdornment>\n ),\n },\n }}\n />\n\n <div className=\"linkList\" onClick={handleDrawerClose}>\n <a\n className=\"SRC-whiteText\"\n href=\"https://help.synapse.org/docs/Getting-Started.2055471150.html\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Getting Started\n </a>\n <a\n className=\"SRC-whiteText\"\n onClick={() => gotoPlace(PLANS_LINK)}\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Plans\n </a>\n <a\n className=\"SRC-whiteText\"\n href=\"https://help.synapse.org/docs/\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Synapse Web Documentation\n </a>\n <a\n className=\"SRC-whiteText\"\n href=\"https://python-docs.synapse.org/en/stable/\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Python Client Documentation\n </a>\n <a\n className=\"SRC-whiteText\"\n href=\"https://r-docs.synapse.org/\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n R Client Documentation\n </a>\n <a\n className=\"SRC-whiteText\"\n href=\"https://blog.synapse.org/\"\n rel=\"noopener noreferrer\"\n >\n Blog\n </a>\n <a\n className=\"SRC-whiteText\"\n href=\"https://sagebionetworks.jira.com/servicedesk/customer/portals/\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Contact Us\n </a>\n </div>\n </>\n )}\n </div>\n </Drawer>\n </div>\n <CreateProjectModal\n onClose={() => setIsShowingCreateProjectModal(false)}\n isShowingModal={isShowingCreateProjectModal}\n />\n </>\n )\n}\n\nexport default SynapseNavDrawer\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAqDA,IAAY,IAAL,yBAAA,GAAA;QACL,EAAA,EAAA,WAAA,KAAA,YACA,EAAA,EAAA,oBAAA,KAAA,qBACA,EAAA,EAAA,YAAA,KAAA,aACA,EAAA,EAAA,QAAA,KAAA,SACA,EAAA,EAAA,aAAA,KAAA,cACA,EAAA,EAAA,YAAA,KAAA,aACA,EAAA,EAAA,SAAA,KAAA,UACA,EAAA,EAAA,UAAA,KAAA,WACA,EAAA,EAAA,OAAA,KAAA;KACD,EAEY,KAAkB,MAAwB;CACrD,IAAM,IAAc;EAClB,GAAG;EACH;EACD;AACD,QAAO,mBAAmB,KAAK,UAAU,EAAY,CAAC;GAGlD,IAAoB;CAGxB,GAAG;CACH,cAAc,CACZ;EACE,KAAK;EACL,OAAO;EACR,CACF;CACF,EACK,KAAyB,MAAwB;CACrD,IAAM,IAAc;EAClB,GAAG;EACH;EACD;AACD,QAAO,mBAAmB,KAAK,UAAU,EAAY,CAAC;GAGlD,KAAqB,MAA2C;CACpE,IAAM,EACJ,YACA,aACA,uBACA,qBACA,uBACA,iBACA,6BAA0B,IAC1B,sBACA,wBACE,GAeE,IACJ,kBAAC,GAAD;EAAS,OAAO;EAAS,WAAU;YACjC,kBAAC,GAAD;GAEE,SAjBJ,KAA2B,IACvB,UACM;AACJ,MAAiB,EAAmB;;GAetC,WAAU;GACV,UAAU;aAEV,kBAAC,GAAD;IAAqB;IAAc,OAAM;cAhBlC,IACX,kBAAA,GAAA,EAAA,UAAA;KACE,kBAAC,GAAD,EAAS,MAAM,GAAY,CAAA;;KAAE;KAAoB;KAChD,EAAA,CAAA,GAEH;IAaY,CAAA;GACO,EARV,EAQU;EACT,CAAA;AAGZ,QAAO,IACL,kBAAC,MAAD,EAAA,UACE,kBAAC,KAAD;EACE,SAAS;EACT,KAAI;EACJ,WAAU;YAET;EACC,CAAA,EACD,CAAA,GAEL,kBAAC,MAAD,EAAA,UAAK,GAAc,CAAA;;AAOvB,SAAgB,EAAiB,EAC/B,gBAAa,IACb,gBACwB;CACxB,IAAM,CAAC,GAAQ,KAAW,EAAS,EAAW,EACxC,CAAC,GAAc,KAAmB,GAAmB,EACrD,CAAC,GAAmB,KAAwB,EAAiB,GAAG,EAChE,CAAC,GAAmB,KAAwB,EAAiB,GAAG,EAChE,CAAC,GAA6B,KAClC,EAAkB,GAAM,EAEpB,EAAE,oBAAiB,GAA8B,EAEjD,EAAE,uBAAoB,GAAmB,EAEzC,EAAE,MAAM,MAAsB,GAAyB,EAGvD,IACJ,KAAmB,IACf,EAAkB,cAClB,KAAA,GAEA,EAAE,MAAM,MAA2B,EAA6B,EACpE,SAAS,GACV,CAAC,EAEI,IAA8B,GAAwB,oBAEtD,EAAE,MAAM,MAAuB,EACnC;EACE,iBAAiB,EAAgB;EACjC,MAAM,CACJ;GACE,OAAO,EAAoB;GAC3B,WAAW,EAAU;GACtB,CACF;EACF,EACD,EACE,SAAS,GAAmB,cAC7B,CACF,EAEG,IACF,GAAoB,MAAM,GAAG,QAAQ,UAAU;AACjD,CAAI,GAAoB,MAAM,GAAG,kBAC/B,IAAkC,GAAG,EAAgC;CAGvE,IAAM,EAAE,MAAM,MACZ,EACE,EAAE,cAAc,IAAM,EACtB,EAAE,SAAS,GAAiB,CAC7B,EACG,IAAwC,EAC5C,GAAoC,MAAM,MACxC,MAAQ,EAAK,cAAc,EAAK,WAAW,SAAS,EACrD,EAGG,KAAoB,MAAsB;AAE9C,EADA,EAAQ,GAAK,EACb,EAAgB,EAAQ;IAGpB,UAA0B;AAE9B,EADA,EAAQ,GAAM,EACd,EAAgB,KAAA,EAAU;IAGtB,KAAmB,MAAuB;AAC9C,IACE,2BAA2B,EACzB,EAAW,MAAM,QAAQ,CAC1B,GACF;IAGG,IAAa,GAAe,EAC5B,KAAqB,EAAc,2BAA2B;AAEpE,QACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,GAAD;GACE,SAAQ;GACR,WAAW,wBAAwB,IAAS,mBAAmB;aAFjE;IAIE,kBAAC,OAAD;KAAK,SAAS;eACZ,kBAAC,KAAD;MACE,WAAU;MACV,KAAI;MACJ,eAAe,EAAU,UAAU;MACnC,cAAW;gBAEX,kBAAC,GAAD,EAAoB,CAAA;MAClB,CAAA;KACA,CAAA;IACN,kBAAC,GAAD,EAAA,UAAA,CACG,KAAmB,KAClB,kBAAA,GAAA,EAAA,UAAA;KACE,kBAAC,GAAD;MACE,SAAQ;MACR,UAAS;MACT,oBAAoB,EAAQ;MAC5B,yBAAyB,KAAgB,EAAQ;MAC9B;MACD;MAClB,CAAA;KACD,KACC,kBAAC,GAAD;MACE,SAAQ;MACR,UAAS;MACT,wBAAwB,EAAU,sBAAsB;MACxD,yBACE,KAAgB,EAAQ;MAEP;MACD;MAClB,CAAA;KAEJ,kBAAC,GAAD;MACE,SAAQ;MACR,UAAS;MACT,wBACE,EACE,YAAY,EAAmB,QAAQ,YACxC;MAEgB;MACD;MAClB,CAAA;KACF,kBAAC,GAAD;MACE,SAAQ;MACR,UAAS;MACT,wBACE,EAAU,YAAY,EAAmB,QAAQ,QAAQ;MAExC;MACD;MAClB,CAAA;KACF,kBAAC,GAAD;MACE,SAAQ;MACR,UAAS;MACT,wBACE,EACE,YAAY,EAAmB,QAAQ,aACxC;MAEgB;MACD;MAClB,CAAA;KACF,kBAAC,GAAD;MACE,SAAQ;MACR,UAAS;MACT,wBAAwB,EAAU,kBAAkB;MACpD,cAAc;MACK;MACD;MAClB,CAAA;KACF,kBAAC,GAAD;MACE,SAAQ;MACR,UAAS;MACT,wBAAwB,EAAU,WAAW;MAC1B;MACD;MAClB,CAAA;KACD,GAAmB,gBAClB,kBAAC,GAAD;MACE,SAAQ;MACR,UAAS;MACT,wBACE,EAAU,4CAA4C;MAExD,cAAc;MACK;MACD;MAClB,CAAA;KAEH,EAAA,CAAA,EAEL,kBAAC,GAAD;KACE,SAAQ;KACR,UAAS;KACT,wBAAwB,EAAU,oBAAoB;KACnC;KACD;KAClB,CAAA,CACG,EAAA,CAAA;IACP,kBAAC,OAAD,EAAK,WAAU,UAAW,CAAA;IAC1B,kBAAC,GAAD,EAAA,UAAA;KACG,KAAmB,KAClB,kBAAC,GAAD;MACE,SAAQ;MACR,oBAAoB,EAAQ;MAC5B,oBACE,kBAAC,GAAD;OACE,aAAa;OACb,MAAK;OACL,YAAW;OACX,CAAA;MAEJ,yBAAyB,KAAgB,EAAQ;MAC9B;MACD;MAClB,CAAA;KAEH,CAAC,KACA,kBAAC,GAAD;MACE,SAAQ;MACR,UAAS;MACT,wBACE,EACE,EAAW,UAAU,CACtB;MAEgB;MACD;MAClB,CAAA;KAEJ,kBAAC,GAAD;MACE,SAAQ;MACR,UAAS;MACT,oBAAoB,EAAQ;MAC5B,yBAAyB,KAAgB,EAAQ;MAC9B;MACD;MAClB,CAAA;KACG,EAAA,CAAA;IACA;MACT,kBAAC,GAAD;GACE,SAAQ;GACR,MAAM;GACN,WAAW;GACX,SAAS;aAJX,CAME,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD,EAAmB,CAAA;IACf,CAAA,EACN,kBAAC,OAAD;IAAK,WAAU;cAAf;KACG,KAAgB,EAAQ,YACvB,kBAAA,GAAA,EAAA,UAAA;MACE,kBAAC,OAAD;OAAK,WAAU;iBAAuB;OAAc,CAAA;MACpD,kBAAC,GAAD;OAAS,OAAM;OAAuB,WAAU;iBAC9C,kBAAC,KAAD;QACE,WAAU;QACV,eAAe;AAEb,SADA,EAA+B,GAAK,EACpC,GAAmB;;kBAGrB,kBAAC,GAAD,EAAS,MAAK,oBAAqB,CAAA;QACjC,CAAA;OACI,CAAA;MACV,kBAAC,GAAD;OACE,MAAK;OACL,aAAY;OACZ,OAAO;OACP,WAAU,MAAS;AACjB,UAAqB,EAAM,OAAO,MAAM;;OAE1C,YAAY,MAA2C;AACrD,QAAI,EAAM,QAAQ,WACX,EAAM,OAA4B,UAAU,OAC/C,EAAqB,GAAG,EACxB,GAAmB,EACnB,EACG,EAAM,OAA4B,MACpC;;OAIP,WAAW,EACT,OAAO,EACL,gBACE,kBAAC,GAAD;QAAgB,UAAS;kBACvB,kBAAC,GAAD,EAAS,MAAK,kBAAmB,CAAA;QAClB,CAAA,EAEpB,EACF;OACD,CAAA;MACF,kBAAC,OAAD;OAAK,WAAU;OAAW,SAAS;iBAAnC;QACE,kBAAC,KAAD;SACE,WAAU;SACV,eACE,EACE,YAAY,GAAoB,QAAQ,eACzC;SAEH,KAAI;mBACL;SAEG,CAAA;QACJ,kBAAC,KAAD;SACE,WAAU;SACV,eACE,EACE,YAAY,GAAoB,QAAQ,yBACzC;SAEH,KAAI;mBACL;SAEG,CAAA;QACJ,kBAAC,KAAD;SACE,WAAU;SACV,eACE,EACE,YAAY,GAAoB,QAAQ,qBACzC;SAEH,KAAI;mBACL;SAEG,CAAA;QACJ,kBAAC,KAAD;SACE,WAAU;SACV,eACE,EACE,YAAY,GAAoB,QAAQ,mCACzC;SAEH,KAAI;mBACL;SAEG,CAAA;QACJ,kBAAC,KAAD;SACE,WAAU;SACV,eACE,EACE,YAAY,GAAoB,QAAQ,gCACzC;SAEH,KAAI;mBACL;SAEG,CAAA;QACA;;MACL,EAAA,CAAA;KAEJ,KAAgB,EAAQ,WACvB,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OAAwB;OAEtB,kBAAC,MAAD,EAAM,CAAA;OACL,GAAoB;OAAS;OAC1B;SACN,kBAAC,OAAD;MAAK,WAAU;MAAW,SAAS;gBAAnC;OACE,kBAAC,KAAD;QACE,WAAU;QACV,eACE,EACE,YAAY,GAAoB,QAAQ,UACzC;QAEH,KAAI;kBACL;QAEG,CAAA;OACJ,kBAAC,KAAD;QACE,WAAU;QACV,MAAM,GAAmB,UAAU;QACnC,QAAO;QACP,KAAI;kBACL;QAEG,CAAA;OACJ,kBAAC,KAAD;QACE,WAAU;QACV,eAAe,EAAU,0BAA0B;QACnD,KAAI;kBACL;QAEG,CAAA;OACJ,kBAAC,KAAD;QACE,WAAU;QACV,eAAe,EAAU,eAAe;QACxC,KAAI;kBACL;QAEG,CAAA;OACJ,kBAAC,KAAD;QACE,WAAU;QACV,eAAe;AACR,YAAc;;QAErB,KAAI;kBACL;QAEG,CAAA;OACA;QACL,EAAA,CAAA;KAEJ,KAAgB,EAAQ,QACvB,kBAAA,GAAA,EAAA,UAAA;MACE,kBAAC,OAAD;OAAK,WAAU;iBAAS;OAAU,CAAA;MAClC,kBAAC,GAAD;OACE,MAAK;OACL,aAAY;OACZ,OAAO;OACP,WAAU,MAAS;AACjB,UAAqB,EAAM,OAAO,MAAM;;OAE1C,YAAW,MAAS;AAClB,QAAI,EAAM,QAAQ,WACX,EAAM,OAA4B,UAAU,OAC/C,OAAO,KACL,wDAAwD,UACrD,EAAM,OAA4B,MACpC,GACF,EACD,EAAqB,GAAG,EACxB,GAAmB;;OAIzB,WAAW,EACT,OAAO,EACL,gBACE,kBAAC,GAAD;QAAgB,UAAS;kBACvB,kBAAC,GAAD,EAAS,MAAK,kBAAmB,CAAA;QAClB,CAAA,EAEpB,EACF;OACD,CAAA;MAEF,kBAAC,OAAD;OAAK,WAAU;OAAW,SAAS;iBAAnC;QACE,kBAAC,KAAD;SACE,WAAU;SACV,MAAK;SACL,KAAI;SACJ,QAAO;mBACR;SAEG,CAAA;QACJ,kBAAC,KAAD;SACE,WAAU;SACV,eAAe,EAAA,WAAqB;SACpC,KAAI;SACJ,QAAO;mBACR;SAEG,CAAA;QACJ,kBAAC,KAAD;SACE,WAAU;SACV,MAAK;SACL,KAAI;SACJ,QAAO;mBACR;SAEG,CAAA;QACJ,kBAAC,KAAD;SACE,WAAU;SACV,MAAK;SACL,KAAI;SACJ,QAAO;mBACR;SAEG,CAAA;QACJ,kBAAC,KAAD;SACE,WAAU;SACV,MAAK;SACL,KAAI;SACJ,QAAO;mBACR;SAEG,CAAA;QACJ,kBAAC,KAAD;SACE,WAAU;SACV,MAAK;SACL,KAAI;mBACL;SAEG,CAAA;QACJ,kBAAC,KAAD;SACE,WAAU;SACV,MAAK;SACL,KAAI;SACJ,QAAO;mBACR;SAEG,CAAA;QACA;;MACL,EAAA,CAAA;KAED;MACC;KACL;KACN,kBAAC,GAAD;EACE,eAAe,EAA+B,GAAM;EACpD,gBAAgB;EAChB,CAAA,CACD,EAAA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"SynapsePortalBanners.js","names":[],"sources":["../../../src/components/SynapsePortalBanners/SynapsePortalBanners.tsx"],"sourcesContent":["import {\n useGetEntityPath,\n useGetQueryResultBundleWithAsyncStatus,\n} from '@/synapse-queries'\nimport { useSourceAppConfigs } from '@/utils/hooks'\nimport { BUNDLE_MASK_QUERY_RESULTS } from '@/utils/SynapseConstants'\nimport { ChevronRightTwoTone } from '@mui/icons-material'\nimport { Box, Typography } from '@mui/material'\nimport {\n ColumnSingleValueQueryFilter,\n ColumnSingleValueFilterOperator,\n} from '@sage-bionetworks/synapse-types'\n\nexport type SynapsePortalBannersProps = {\n entityId: string\n dataCatalogEntityId?: string\n sourceAppConfigTableID?: string\n}\n\n/**\n *\n * @param props\n */\nexport default function SynapsePortalBanners({\n entityId,\n dataCatalogEntityId = 'syn61609402',\n sourceAppConfigTableID = 'syn45291362',\n}: SynapsePortalBannersProps) {\n const { data: entityPathData } = useGetEntityPath(entityId)\n // get all EntityHeader ids in the entity path data in a string array\n // Note: we remove the first item from entityPathData.path as it is always the root Synapse folder which we don't want to include\n const entityIdValues: string[] = entityPathData\n ? entityPathData.path.map(header => header.id).slice(1)\n : [entityId]\n\n const dataCatalogAdditionalFilters: ColumnSingleValueQueryFilter[] =\n entityIdValues\n ? [\n {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n columnName: 'id',\n operator: ColumnSingleValueFilterOperator.IN,\n values: entityIdValues,\n },\n ]\n : []\n const { data: dataCatalogData } = useGetQueryResultBundleWithAsyncStatus(\n {\n entityId: dataCatalogEntityId,\n query: {\n sql: `SELECT appId, link FROM ${dataCatalogEntityId}`,\n additionalFilters: dataCatalogAdditionalFilters,\n },\n partMask: BUNDLE_MASK_QUERY_RESULTS,\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n },\n {\n enabled: !!entityPathData,\n },\n )\n\n const rowSet = dataCatalogData?.responseBody?.queryResult?.queryResults\n const hasPortalBanners = !!rowSet && rowSet?.rows.length > 0\n\n const appIds = rowSet?.rows.map(row => row.values[0]) as string[]\n const hasAppIds = appIds && appIds.length > 0\n\n const sourceAppConfigFilters: ColumnSingleValueQueryFilter[] = hasAppIds\n ? [\n {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n columnName: 'appId',\n operator: ColumnSingleValueFilterOperator.EQUAL,\n values: appIds,\n },\n ]\n : []\n const sourceAppConfigs = useSourceAppConfigs(\n sourceAppConfigTableID,\n sourceAppConfigFilters,\n )\n const hasSourceAppConfigs = !!sourceAppConfigs && sourceAppConfigs.length > 0\n\n if (!hasAppIds || !hasPortalBanners || !hasSourceAppConfigs) {\n return <></>\n }\n\n // we have source app configs associated to this entity, let's render the banners\n return (\n <Box\n sx={{\n display: 'flex',\n flexWrap: 'wrap',\n gap: '20px',\n width: '100%',\n alignItems: 'center',\n }}\n >\n {sourceAppConfigs.map((appConfig, index) => {\n const dataCatalogRow = rowSet.rows.find(row => {\n return row.values[0] === appConfig.appId\n })\n const link = dataCatalogRow?.values[1] || appConfig.appURL\n return (\n <Box\n key={index}\n component=\"a\"\n href={link}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n flex={1}\n sx={{\n display: 'flex',\n flexWrap: 'nowrap',\n padding: '16px',\n justifyContent: 'space-between',\n border: '1px solid #ccc',\n borderRadius: '8px',\n backgroundColor: '#f9f9f9',\n textDecoration: 'none',\n pointer: 'cursor',\n '&:hover': {\n textDecoration: 'none !important',\n },\n width: '100%',\n alignItems: 'center',\n mt: '10px',\n mb: '10px',\n }}\n >\n <Box\n flex={1}\n sx={{\n display: 'flex',\n flexWrap: 'wrap',\n justifyContent: 'space-between',\n gap: '10px',\n }}\n >\n <Box\n sx={{\n '> *': {\n height: '60px',\n },\n }}\n >\n {appConfig?.logo}\n </Box>\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n mr: '10px',\n }}\n >\n <Typography variant=\"body1\" sx={{ fontWeight: 700 }}>\n This resource is part of a Portal\n </Typography>\n <Typography variant=\"body1\">\n {' '}\n Access it on the {appConfig.friendlyName}\n </Typography>\n </Box>\n </Box>\n <ChevronRightTwoTone />\n </Box>\n )\n })}\n </Box>\n )\n}\n"],"mappings":";;;;;;;;;;;AAuBA,SAAwB,EAAqB,EAC3C,aACA,yBAAsB,eACtB,4BAAyB,iBACG;CAC5B,IAAM,EAAE,MAAM,MAAmB,EAAiB,EAAS,EAGrD,IAA2B,IAC7B,EAAe,KAAK,KAAI,MAAU,EAAO,GAAG,CAAC,MAAM,EAAE,GACrD,CAAC,EAAS,EAER,IACJ,IACI,CACE;EACE,cACE;EACF,YAAY;EACZ,UAAU,EAAgC;EAC1C,QAAQ;EACT,CACF,GACD,EAAE,EACF,EAAE,MAAM,MAAoB,EAChC;EACE,UAAU;EACV,OAAO;GACL,KAAK,2BAA2B;GAChC,mBAAmB;GACpB;EACD,UAAA;EACA,cAAc;EACf,EACD,EACE,SAAS,CAAC,CAAC,GACZ,CACF,EAEK,IAAS,GAAiB,cAAc,aAAa,cACrD,IAAmB,CAAC,CAAC,KAAU,GAAQ,KAAK,SAAS,GAErD,IAAS,GAAQ,KAAK,KAAI,MAAO,EAAI,OAAO,GAAG,EAC/C,IAAY,KAAU,EAAO,SAAS,GAatC,IAAmB,EACvB,GAZ6D,IAC3D,CACE;EACE,cACE;EACF,YAAY;EACZ,UAAU,EAAgC;EAC1C,QAAQ;EACT,CACF,GACD,EAAE,CAIL,EACK,IAAsB,CAAC,CAAC,KAAoB,EAAiB,SAAS;AAO5E,QALI,CAAC,KAAa,CAAC,KAAoB,CAAC,IAC/B,kBAAA,GAAA,EAAK,CAAA,GAKZ,kBAAC,GAAD;EACE,IAAI;GACF,SAAS;GACT,UAAU;GACV,KAAK;GACL,OAAO;GACP,YAAY;GACb;YAEA,EAAiB,KAAK,GAAW,MAM9B,kBAAC,GAAD;GAEE,WAAU;GACV,MARmB,EAAO,KAAK,MAAK,MAC/B,EAAI,OAAO,OAAO,EAAU,MACnC,EAC2B,OAAO,MAAM,EAAU;GAMhD,QAAO;GACP,KAAI;GACJ,MAAM;GACN,IAAI;IACF,SAAS;IACT,UAAU;IACV,SAAS;IACT,gBAAgB;IAChB,QAAQ;IACR,cAAc;IACd,iBAAiB;IACjB,gBAAgB;IAChB,SAAS;IACT,WAAW,EACT,gBAAgB,mBACjB;IACD,OAAO;IACP,YAAY;IACZ,IAAI;IACJ,IAAI;IACL;aAxBH,CA0BE,kBAAC,GAAD;IACE,MAAM;IACN,IAAI;KACF,SAAS;KACT,UAAU;KACV,gBAAgB;KAChB,KAAK;KACN;cAPH,CASE,kBAAC,GAAD;KACE,IAAI,EACF,OAAO,EACL,QAAQ,QACT,EACF;eAEA,GAAW;KACR,CAAA,EACN,kBAAC,GAAD;KACE,IAAI;MACF,SAAS;MACT,eAAe;MACf,gBAAgB;MAChB,IAAI;MACL;eANH,CAQE,kBAAC,GAAD;MAAY,SAAQ;MAAQ,IAAI,EAAE,YAAY,KAAK;gBAAE;MAExC,CAAA,EACb,kBAAC,GAAD;MAAY,SAAQ;gBAApB;OACG;OAAI;OACa,EAAU;OACjB;QACT;OACF;OACN,kBAAC,GAAD,EAAuB,CAAA,CACnB;KA7DC,EA6DD,CAER;EACE,CAAA"}
1
+ {"version":3,"file":"SynapsePortalBanners.js","names":[],"sources":["../../../src/components/SynapsePortalBanners/SynapsePortalBanners.tsx"],"sourcesContent":["import {\n useGetEntityPath,\n useGetQueryResultBundleWithAsyncStatus,\n} from '@/synapse-queries'\nimport { useSourceAppConfigs } from '@/utils/hooks'\nimport { BUNDLE_MASK_QUERY_RESULTS } from '@/utils/SynapseConstants'\nimport { ChevronRightTwoTone } from '@mui/icons-material'\nimport { Box, Typography } from '@mui/material'\nimport {\n ColumnSingleValueQueryFilter,\n ColumnSingleValueFilterOperator,\n} from '@sage-bionetworks/synapse-types'\n\nexport type SynapsePortalBannersProps = {\n entityId: string\n dataCatalogEntityId?: string\n sourceAppConfigTableID?: string\n}\n\n/**\n *\n * @param props\n */\nexport default function SynapsePortalBanners({\n entityId,\n dataCatalogEntityId = 'syn61609402',\n sourceAppConfigTableID = 'syn45291362',\n}: SynapsePortalBannersProps) {\n const { data: entityPathData } = useGetEntityPath(entityId)\n // get all EntityHeader ids in the entity path data in a string array\n // Note: we remove the first item from entityPathData.path as it is always the root Synapse folder which we don't want to include\n const entityIdValues: string[] = entityPathData\n ? entityPathData.path.map(header => header.id).slice(1)\n : [entityId]\n\n const dataCatalogAdditionalFilters: ColumnSingleValueQueryFilter[] =\n entityIdValues\n ? [\n {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n columnName: 'id',\n operator: ColumnSingleValueFilterOperator.IN,\n values: entityIdValues,\n },\n ]\n : []\n const { data: dataCatalogData } = useGetQueryResultBundleWithAsyncStatus(\n {\n entityId: dataCatalogEntityId,\n query: {\n sql: `SELECT appId, link FROM ${dataCatalogEntityId}`,\n additionalFilters: dataCatalogAdditionalFilters,\n },\n partMask: BUNDLE_MASK_QUERY_RESULTS,\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n },\n {\n enabled: !!entityPathData,\n },\n )\n\n const rowSet = dataCatalogData?.responseBody?.queryResult?.queryResults\n const hasPortalBanners = !!rowSet && rowSet?.rows.length > 0\n\n const appIds = rowSet?.rows.map(row => row.values[0]) as string[]\n const hasAppIds = appIds && appIds.length > 0\n\n const sourceAppConfigFilters: ColumnSingleValueQueryFilter[] = hasAppIds\n ? [\n {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n columnName: 'appId',\n operator: ColumnSingleValueFilterOperator.EQUAL,\n values: appIds,\n },\n ]\n : []\n const sourceAppConfigs = useSourceAppConfigs(\n sourceAppConfigTableID,\n sourceAppConfigFilters,\n )\n const hasSourceAppConfigs = !!sourceAppConfigs && sourceAppConfigs.length > 0\n\n if (!hasAppIds || !hasPortalBanners || !hasSourceAppConfigs) {\n return <></>\n }\n\n // we have source app configs associated to this entity, let's render the banners\n return (\n <Box\n sx={{\n display: 'flex',\n flexWrap: 'wrap',\n gap: '20px',\n width: '100%',\n alignItems: 'center',\n }}\n >\n {sourceAppConfigs.map((appConfig, index) => {\n const dataCatalogRow = rowSet.rows.find(row => {\n return row.values[0] === appConfig.appId\n })\n const link = dataCatalogRow?.values[1] || appConfig.appURL\n return (\n <Box\n key={index}\n component=\"a\"\n href={link}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n flex={1}\n sx={{\n display: 'flex',\n flexWrap: 'nowrap',\n padding: '16px',\n justifyContent: 'space-between',\n border: '1px solid #ccc',\n borderRadius: '8px',\n backgroundColor: '#f9f9f9',\n textDecoration: 'none',\n pointer: 'cursor',\n '&:hover': {\n textDecoration: 'none !important',\n },\n width: '100%',\n alignItems: 'center',\n mt: '10px',\n mb: '10px',\n }}\n >\n <Box\n flex={1}\n sx={{\n display: 'flex',\n flexWrap: 'wrap',\n justifyContent: 'space-between',\n gap: '10px',\n }}\n >\n <Box\n sx={{\n '> *': {\n height: '60px',\n },\n }}\n >\n {appConfig?.logo}\n </Box>\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n mr: '10px',\n }}\n >\n <Typography variant=\"body1\" sx={{ fontWeight: 700 }}>\n This resource is part of a Portal\n </Typography>\n <Typography variant=\"body1\">\n {' '}\n Access it on the {appConfig.friendlyName}\n </Typography>\n </Box>\n </Box>\n <ChevronRightTwoTone />\n </Box>\n )\n })}\n </Box>\n )\n}\n"],"mappings":";;;;;;;;;;;AAuBA,SAAwB,EAAqB,EAC3C,aACA,yBAAsB,eACtB,4BAAyB,iBACG;CAC5B,IAAM,EAAE,MAAM,MAAmB,EAAiB,EAAS,EAGrD,IAA2B,IAC7B,EAAe,KAAK,KAAI,MAAU,EAAO,GAAG,CAAC,MAAM,EAAE,GACrD,CAAC,EAAS,EAER,IACJ,IACI,CACE;EACE,cACE;EACF,YAAY;EACZ,UAAU,EAAgC;EAC1C,QAAQ;EACT,CACF,GACD,EAAE,EACF,EAAE,MAAM,MAAoB,EAChC;EACE,UAAU;EACV,OAAO;GACL,KAAK,2BAA2B;GAChC,mBAAmB;GACpB;EACD,UAAA;EACA,cAAc;EACf,EACD,EACE,SAAS,CAAC,CAAC,GACZ,CACF,EAEK,IAAS,GAAiB,cAAc,aAAa,cACrD,IAAmB,CAAC,CAAC,KAAU,GAAQ,KAAK,SAAS,GAErD,IAAS,GAAQ,KAAK,KAAI,MAAO,EAAI,OAAO,GAAG,EAC/C,IAAY,KAAU,EAAO,SAAS,GAatC,IAAmB,EACvB,GAZ6D,IAC3D,CACE;EACE,cACE;EACF,YAAY;EACZ,UAAU,EAAgC;EAC1C,QAAQ;EACT,CACF,GACD,EAAE,CAIL,EACK,IAAsB,CAAC,CAAC,KAAoB,EAAiB,SAAS;AAO5E,QALI,CAAC,KAAa,CAAC,KAAoB,CAAC,IAC/B,kBAAA,GAAA,EAAK,CAAA,GAKZ,kBAAC,GAAD;EACE,IAAI;GACF,SAAS;GACT,UAAU;GACV,KAAK;GACL,OAAO;GACP,YAAY;GACb;YAEA,EAAiB,KAAK,GAAW,MAM9B,kBAAC,GAAD;GAEE,WAAU;GACV,MARmB,EAAO,KAAK,MAAK,MAC/B,EAAI,OAAO,OAAO,EAAU,MAExB,EAAgB,OAAO,MAAM,EAAU;GAMhD,QAAO;GACP,KAAI;GACJ,MAAM;GACN,IAAI;IACF,SAAS;IACT,UAAU;IACV,SAAS;IACT,gBAAgB;IAChB,QAAQ;IACR,cAAc;IACd,iBAAiB;IACjB,gBAAgB;IAChB,SAAS;IACT,WAAW,EACT,gBAAgB,mBACjB;IACD,OAAO;IACP,YAAY;IACZ,IAAI;IACJ,IAAI;IACL;aAxBH,CA0BE,kBAAC,GAAD;IACE,MAAM;IACN,IAAI;KACF,SAAS;KACT,UAAU;KACV,gBAAgB;KAChB,KAAK;KACN;cAPH,CASE,kBAAC,GAAD;KACE,IAAI,EACF,OAAO,EACL,QAAQ,QACT,EACF;eAEA,GAAW;KACR,CAAA,EACN,kBAAC,GAAD;KACE,IAAI;MACF,SAAS;MACT,eAAe;MACf,gBAAgB;MAChB,IAAI;MACL;eANH,CAQE,kBAAC,GAAD;MAAY,SAAQ;MAAQ,IAAI,EAAE,YAAY,KAAK;gBAAE;MAExC,CAAA,EACb,kBAAC,GAAD;MAAY,SAAQ;gBAApB;OACG;OAAI;OACa,EAAU;OACjB;QACT;OACF;OACN,kBAAC,GAAD,EAAuB,CAAA,CACnB;KA7DC,EA6DD,CAER;EACE,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"SearchFacetPanel.js","names":[],"sources":["../../../../src/components/SynapseSearchPageResults/SearchFacetPanel/SearchFacetPanel.tsx"],"sourcesContent":["import { useState } from 'react'\nimport styles from './SearchFacetPanel.module.scss'\nimport dayjs from 'dayjs'\nimport { EntityType } from '@sage-bionetworks/synapse-client'\nimport { entityTypeToFriendlyName } from '../../../utils/functions/EntityTypeUtils'\nimport {\n Box,\n FormControlLabel,\n Button,\n RadioGroup,\n Radio,\n Typography,\n Chip,\n Tooltip,\n Collapse,\n} from '@mui/material'\nimport UTurnLeftIcon from '@mui/icons-material/UTurnLeft'\nimport CloseIcon from '@mui/icons-material/Close'\nimport {\n SearchQuery,\n Facet,\n FacetTypeNames,\n} from '@sage-bionetworks/synapse-types'\nimport { UserBadge } from '../../UserCard/UserBadge'\nimport {\n MAX_FACET_VALUES_SHOWN,\n FACET_DISPLAY_ORDER,\n getFacetDisplayName,\n shouldRenderFacet,\n timeRanges,\n getSelectedTimeRangeId,\n formatTimeRangeDisplayValue,\n isUserFacet,\n shouldShowFacetValue,\n getAllFacetLabel,\n} from './SearchFacetPanelUtils'\n\ntype SearchFacetPanelProps = {\n query: SearchQuery\n setQuery: (newQuery: SearchQuery) => void\n facets: Facet[]\n disabled?: boolean\n expanded: boolean\n onCollapse: () => void\n onAddFacet: (facetName: string, facetValue: string) => void\n onRemoveFacet: (facetName: string, facetValue: string) => void\n onSetRangeFacet: (facetName: string, minValue: string) => void\n onRemoveRangeFacet: (facetName: string) => void\n isRangeFacetApplied: (facetName: string) => boolean\n getAppliedRangeFacet: (facetName: string) => { min: string } | undefined\n}\n\n/**\n * Main facet panel component that displays all available facets\n */\nexport function SearchFacetPanel({\n query,\n setQuery,\n facets,\n disabled = false,\n onAddFacet,\n onRemoveFacet,\n onSetRangeFacet,\n onRemoveRangeFacet,\n isRangeFacetApplied,\n getAppliedRangeFacet,\n expanded,\n onCollapse,\n}: SearchFacetPanelProps) {\n const hasAppliedFacets =\n (query.booleanQuery && query.booleanQuery.length > 0) ||\n (query.rangeQuery && query.rangeQuery.length > 0)\n\n const handleResetFilters = () => {\n setQuery({\n ...query,\n booleanQuery: [],\n rangeQuery: [],\n start: 0,\n })\n }\n\n return (\n <Collapse\n in={expanded}\n id=\"filter-search-results-panel\"\n aria-labelledby=\"filter-results-button-label\"\n >\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n <Box sx={{ display: 'flex', alignItems: 'center' }}>\n {hasAppliedFacets && (\n <Button\n onClick={handleResetFilters}\n variant=\"text\"\n size=\"small\"\n className={styles.resetFilterButton}\n disabled={disabled}\n >\n <UTurnLeftIcon sx={{ transform: 'rotate(90deg)' }} />\n <Typography sx={{ fontSize: '16px', fontWeight: 700 }}>\n Reset Filters\n </Typography>\n </Button>\n )}\n <CloseIcon\n sx={{ marginLeft: 'auto', cursor: 'pointer' }}\n onClick={onCollapse}\n aria-expanded={expanded}\n aria-controls=\"filter-search-results-panel\"\n />\n </Box>\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'row',\n gap: 3,\n flexWrap: 'wrap',\n }}\n >\n {FACET_DISPLAY_ORDER.map(facetName => {\n const facet = facets.find(f => f.name === facetName)\n\n if (!facet || !shouldRenderFacet(facet)) {\n return null\n }\n\n return (\n <SearchFacetGroup\n disabled={disabled}\n key={facet.name}\n facet={facet}\n query={query}\n onAddFacet={onAddFacet}\n onRemoveFacet={onRemoveFacet}\n onSetRangeFacet={onSetRangeFacet}\n onRemoveRangeFacet={onRemoveRangeFacet}\n isRangeFacetApplied={isRangeFacetApplied}\n getAppliedRangeFacet={getAppliedRangeFacet}\n />\n )\n })}\n </Box>\n </Box>\n </Collapse>\n )\n}\n\ntype SearchFacetGroupProps = {\n facet: Facet\n query: SearchQuery\n disabled?: boolean\n onAddFacet: (facetName: string, facetValue: string) => void\n onRemoveFacet: (facetName: string, facetValue: string) => void\n onSetRangeFacet: (facetName: string, minValue: string) => void\n onRemoveRangeFacet: (facetName: string) => void\n isRangeFacetApplied: (facetName: string) => boolean\n getAppliedRangeFacet: (facetName: string) => { min: string } | undefined\n}\n\n/**\n * Component for a facet group\n * (ex: Entity Type facet with values 'dataset', 'file', etc)\n */\nfunction SearchFacetGroup({\n facet,\n disabled = false,\n query,\n onAddFacet,\n onRemoveFacet,\n onSetRangeFacet,\n onRemoveRangeFacet,\n isRangeFacetApplied,\n getAppliedRangeFacet,\n}: SearchFacetGroupProps) {\n const displayName = getFacetDisplayName(facet.name)\n\n return (\n <Box sx={{ display: 'flex', flexDirection: 'column', minWidth: '200px' }}>\n <Typography variant=\"smallText2\" className={styles.displayName}>\n {displayName}\n </Typography>\n {facet.type === FacetTypeNames.LITERAL ? (\n <LiteralFacetValues // checkbox list for literal facets\n disabled={disabled}\n facet={facet}\n query={query}\n onAddFacet={onAddFacet}\n onRemoveFacet={onRemoveFacet}\n />\n ) : (\n <DateRangeFacetValues // radio buttons for date/continuous facets (can only select one range at a time)\n disabled={disabled}\n facet={facet}\n query={query}\n onSetRangeFacet={onSetRangeFacet}\n onRemoveRangeFacet={onRemoveRangeFacet}\n isRangeFacetApplied={isRangeFacetApplied}\n getAppliedRangeFacet={getAppliedRangeFacet}\n />\n )}\n </Box>\n )\n}\n\ntype LiteralFacetValuesProps = {\n facet: Facet\n query: SearchQuery\n disabled?: boolean\n onAddFacet: (facetName: string, facetValue: string) => void\n onRemoveFacet: (facetName: string, facetValue: string) => void\n}\n\nconst ALL_FACET_VALUE = '__all__'\n\n/**\n * Component for rendering literal facet values as radio buttons since the backend ANDs boolean query values\n */\nfunction LiteralFacetValues({\n facet,\n query,\n disabled = false,\n onAddFacet,\n onRemoveFacet,\n}: LiteralFacetValuesProps) {\n const [showAll, setShowAll] = useState(false)\n\n // Get values from the search query (url)\n const appliedValues =\n query.booleanQuery\n ?.filter(kv => kv.key === facet.name)\n .map(kv => kv.value) || []\n\n const selectedValue = appliedValues[0] ?? ALL_FACET_VALUE\n\n // Get values returned by the search results response\n const availableValues = facet.constraints.map(c => c.value)\n\n const allValues = Array.from(new Set([...appliedValues, ...availableValues]))\n\n const filteredValues = allValues.filter(value =>\n shouldShowFacetValue(facet.name, value),\n )\n\n const displayValues = showAll\n ? filteredValues\n : filteredValues.slice(0, MAX_FACET_VALUES_SHOWN)\n\n const handleChange = (newValue: string) => {\n appliedValues.forEach(v => onRemoveFacet(facet.name, v))\n if (newValue !== ALL_FACET_VALUE) {\n onAddFacet(facet.name, newValue)\n }\n }\n\n return (\n <RadioGroup\n name={`literal-facet-${facet.name}`}\n value={selectedValue}\n onChange={e => handleChange(e.target.value)}\n >\n <FormControlLabel\n sx={{ mb: '8px' }}\n disabled={disabled}\n value={ALL_FACET_VALUE}\n control={<Radio size=\"small\" />}\n label={\n <Typography variant=\"smallText1\" sx={{ lineHeight: '20px' }}>\n {getAllFacetLabel(facet.name)}\n </Typography>\n }\n />\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'column',\n ...(showAll && { maxHeight: '280px', overflowY: 'auto' }),\n }}\n >\n {displayValues.map(value => (\n <FormControlLabel\n disabled={disabled}\n key={value}\n value={value}\n control={<Radio size=\"small\" />}\n label={\n isUserFacet(facet.name) ? (\n <UserBadge userId={value} />\n ) : (\n <Typography variant=\"smallText1\" sx={{ lineHeight: '20px' }}>\n {facet.name === 'node_type'\n ? entityTypeToFriendlyName(value as EntityType) || value\n : value}\n </Typography>\n )\n }\n />\n ))}\n </Box>\n {filteredValues.length > MAX_FACET_VALUES_SHOWN && !showAll && (\n <Button\n disabled={disabled}\n onClick={() => setShowAll(true)}\n variant=\"text\"\n size=\"small\"\n sx={{ alignSelf: 'flex-start' }}\n >\n Show all {filteredValues.length}\n </Button>\n )}\n </RadioGroup>\n )\n}\n\ntype DateRangeFacetValuesProps = {\n facet: Facet\n query: SearchQuery\n disabled?: boolean\n onSetRangeFacet: (facetName: string, minValue: string) => void\n onRemoveRangeFacet: (facetName: string) => void\n isRangeFacetApplied: (facetName: string) => boolean\n getAppliedRangeFacet: (facetName: string) => { min: string } | undefined\n}\n\n/**\n * Component for rendering date/continuous range facet values\n * Uses dayjs's built-in relative time thresholds to determine selection\n */\nfunction DateRangeFacetValues({\n facet,\n disabled = false,\n onSetRangeFacet,\n onRemoveRangeFacet,\n getAppliedRangeFacet,\n}: DateRangeFacetValuesProps) {\n const appliedRangeFacet = getAppliedRangeFacet(facet.name)\n\n // Use dayjs's built-in logic to determine which preset matches the stored timestamp (min - Unix timestamp currently in the URL/Search Query)\n const selectedValue = appliedRangeFacet?.min\n ? getSelectedTimeRangeId(appliedRangeFacet.min)\n : 'ANY_TIME'\n\n const handleChange = (rangeId: string) => {\n const selectedTimeRange = timeRanges.find(r => r.id === rangeId)\n\n if (!selectedTimeRange?.range) {\n onRemoveRangeFacet(facet.name)\n return\n }\n\n // Always calculate 'min' relative to the moment of the click.\n // Use dayjs unit-aware subtraction so month/year account for varying lengths.\n const unitMap: Record<string, dayjs.ManipulateType> = {\n PAST_HOUR: 'hour',\n PAST_DAY: 'day',\n PAST_WEEK: 'week',\n PAST_MONTH: 'month',\n PAST_YEAR: 'year',\n }\n\n /**\n * We use dayjs.subtract() instead of fixed seconds to handle\n * calendar irregularities. dayjs correctly calculates \"one month ago\"\n * whether the current month has 28, 30, or 31 days.\n */\n const minValue = String(dayjs().subtract(1, unitMap[rangeId]).unix())\n onSetRangeFacet(facet.name, minValue)\n }\n\n return (\n <RadioGroup\n name={`range-facet-${facet.name}`}\n value={selectedValue}\n onChange={e => handleChange(e.target.value)}\n >\n {timeRanges.map(range => (\n <FormControlLabel\n disabled={disabled}\n key={range.label}\n value={range.id}\n control={<Radio size=\"small\" />}\n label={range.label}\n sx={{ mb: 0.5 }}\n />\n ))}\n </RadioGroup>\n )\n}\n\ntype AppliedFacetsChipsProps = {\n query: SearchQuery\n onRemoveFacet: (facetName: string, facetValue: string) => void\n onRemoveRangeFacet: (facetName: string) => void\n}\n\n/**\n * Component that displays applied facets as chips with delete icons\n */\nexport function AppliedFacetsChips({\n query,\n onRemoveFacet,\n onRemoveRangeFacet,\n}: AppliedFacetsChipsProps) {\n const booleanQuery = query.booleanQuery || []\n const rangeQuery = query.rangeQuery || []\n const hasAppliedFacets = booleanQuery.length > 0 || rangeQuery.length > 0\n\n if (!hasAppliedFacets) {\n return null\n }\n\n return (\n <Box\n sx={{\n display: 'flex',\n flexWrap: 'wrap',\n gap: 1,\n alignItems: 'center',\n }}\n >\n {booleanQuery.map((kv, index) => {\n if (!shouldShowFacetValue(kv.key, kv.value)) {\n return null\n }\n\n return (\n <Chip\n key={`${kv.key}-${kv.value}-${index}`}\n className={styles.chipStyles}\n deleteIcon={<CloseIcon className={styles.closeIcon} />}\n onDelete={() => onRemoveFacet(kv.key, kv.value)}\n label={\n isUserFacet(kv.key) ? (\n <Box\n sx={{\n '& .MuiTypography-root': {\n color: 'var(--synapse-white)',\n },\n }}\n >\n <UserBadge userId={kv.value} />\n </Box>\n ) : (\n <Typography variant=\"smallText1\">\n {kv.key === 'node_type'\n ? entityTypeToFriendlyName(kv.value as EntityType) ||\n kv.value\n : kv.value}\n </Typography>\n )\n }\n />\n )\n })}\n\n {rangeQuery.map((kr, index) => {\n const displayValue = formatTimeRangeDisplayValue(kr.min)\n const startDate = dayjs(parseInt(kr.min) * 1000).format('MMMM D, YYYY')\n\n return (\n <Tooltip\n title={`Since ${startDate}`}\n arrow\n key={`${kr.key}-${kr.min}-${index}`}\n >\n <Chip\n className={styles.chipStyles}\n label={`${displayValue}`}\n deleteIcon={<CloseIcon className={styles.closeIcon} />}\n onDelete={() => onRemoveRangeFacet(kr.key)}\n />\n </Tooltip>\n )\n })}\n </Box>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"SearchFacetPanel.js","names":[],"sources":["../../../../src/components/SynapseSearchPageResults/SearchFacetPanel/SearchFacetPanel.tsx"],"sourcesContent":["import { useState } from 'react'\nimport styles from './SearchFacetPanel.module.scss'\nimport dayjs from 'dayjs'\nimport { EntityType } from '@sage-bionetworks/synapse-client'\nimport { entityTypeToFriendlyName } from '../../../utils/functions/EntityTypeUtils'\nimport {\n Box,\n FormControlLabel,\n Button,\n RadioGroup,\n Radio,\n Typography,\n Chip,\n Tooltip,\n Collapse,\n} from '@mui/material'\nimport UTurnLeftIcon from '@mui/icons-material/UTurnLeft'\nimport CloseIcon from '@mui/icons-material/Close'\nimport {\n SearchQuery,\n Facet,\n FacetTypeNames,\n} from '@sage-bionetworks/synapse-types'\nimport { UserBadge } from '../../UserCard/UserBadge'\nimport {\n MAX_FACET_VALUES_SHOWN,\n FACET_DISPLAY_ORDER,\n getFacetDisplayName,\n shouldRenderFacet,\n timeRanges,\n getSelectedTimeRangeId,\n formatTimeRangeDisplayValue,\n isUserFacet,\n shouldShowFacetValue,\n getAllFacetLabel,\n} from './SearchFacetPanelUtils'\n\ntype SearchFacetPanelProps = {\n query: SearchQuery\n setQuery: (newQuery: SearchQuery) => void\n facets: Facet[]\n disabled?: boolean\n expanded: boolean\n onCollapse: () => void\n onAddFacet: (facetName: string, facetValue: string) => void\n onRemoveFacet: (facetName: string, facetValue: string) => void\n onSetRangeFacet: (facetName: string, minValue: string) => void\n onRemoveRangeFacet: (facetName: string) => void\n isRangeFacetApplied: (facetName: string) => boolean\n getAppliedRangeFacet: (facetName: string) => { min: string } | undefined\n}\n\n/**\n * Main facet panel component that displays all available facets\n */\nexport function SearchFacetPanel({\n query,\n setQuery,\n facets,\n disabled = false,\n onAddFacet,\n onRemoveFacet,\n onSetRangeFacet,\n onRemoveRangeFacet,\n isRangeFacetApplied,\n getAppliedRangeFacet,\n expanded,\n onCollapse,\n}: SearchFacetPanelProps) {\n const hasAppliedFacets =\n (query.booleanQuery && query.booleanQuery.length > 0) ||\n (query.rangeQuery && query.rangeQuery.length > 0)\n\n const handleResetFilters = () => {\n setQuery({\n ...query,\n booleanQuery: [],\n rangeQuery: [],\n start: 0,\n })\n }\n\n return (\n <Collapse\n in={expanded}\n id=\"filter-search-results-panel\"\n aria-labelledby=\"filter-results-button-label\"\n >\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n <Box sx={{ display: 'flex', alignItems: 'center' }}>\n {hasAppliedFacets && (\n <Button\n onClick={handleResetFilters}\n variant=\"text\"\n size=\"small\"\n className={styles.resetFilterButton}\n disabled={disabled}\n >\n <UTurnLeftIcon sx={{ transform: 'rotate(90deg)' }} />\n <Typography sx={{ fontSize: '16px', fontWeight: 700 }}>\n Reset Filters\n </Typography>\n </Button>\n )}\n <CloseIcon\n sx={{ marginLeft: 'auto', cursor: 'pointer' }}\n onClick={onCollapse}\n aria-expanded={expanded}\n aria-controls=\"filter-search-results-panel\"\n />\n </Box>\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'row',\n gap: 3,\n flexWrap: 'wrap',\n }}\n >\n {FACET_DISPLAY_ORDER.map(facetName => {\n const facet = facets.find(f => f.name === facetName)\n\n if (!facet || !shouldRenderFacet(facet)) {\n return null\n }\n\n return (\n <SearchFacetGroup\n disabled={disabled}\n key={facet.name}\n facet={facet}\n query={query}\n onAddFacet={onAddFacet}\n onRemoveFacet={onRemoveFacet}\n onSetRangeFacet={onSetRangeFacet}\n onRemoveRangeFacet={onRemoveRangeFacet}\n isRangeFacetApplied={isRangeFacetApplied}\n getAppliedRangeFacet={getAppliedRangeFacet}\n />\n )\n })}\n </Box>\n </Box>\n </Collapse>\n )\n}\n\ntype SearchFacetGroupProps = {\n facet: Facet\n query: SearchQuery\n disabled?: boolean\n onAddFacet: (facetName: string, facetValue: string) => void\n onRemoveFacet: (facetName: string, facetValue: string) => void\n onSetRangeFacet: (facetName: string, minValue: string) => void\n onRemoveRangeFacet: (facetName: string) => void\n isRangeFacetApplied: (facetName: string) => boolean\n getAppliedRangeFacet: (facetName: string) => { min: string } | undefined\n}\n\n/**\n * Component for a facet group\n * (ex: Entity Type facet with values 'dataset', 'file', etc)\n */\nfunction SearchFacetGroup({\n facet,\n disabled = false,\n query,\n onAddFacet,\n onRemoveFacet,\n onSetRangeFacet,\n onRemoveRangeFacet,\n isRangeFacetApplied,\n getAppliedRangeFacet,\n}: SearchFacetGroupProps) {\n const displayName = getFacetDisplayName(facet.name)\n\n return (\n <Box sx={{ display: 'flex', flexDirection: 'column', minWidth: '200px' }}>\n <Typography variant=\"smallText2\" className={styles.displayName}>\n {displayName}\n </Typography>\n {facet.type === FacetTypeNames.LITERAL ? (\n <LiteralFacetValues // checkbox list for literal facets\n disabled={disabled}\n facet={facet}\n query={query}\n onAddFacet={onAddFacet}\n onRemoveFacet={onRemoveFacet}\n />\n ) : (\n <DateRangeFacetValues // radio buttons for date/continuous facets (can only select one range at a time)\n disabled={disabled}\n facet={facet}\n query={query}\n onSetRangeFacet={onSetRangeFacet}\n onRemoveRangeFacet={onRemoveRangeFacet}\n isRangeFacetApplied={isRangeFacetApplied}\n getAppliedRangeFacet={getAppliedRangeFacet}\n />\n )}\n </Box>\n )\n}\n\ntype LiteralFacetValuesProps = {\n facet: Facet\n query: SearchQuery\n disabled?: boolean\n onAddFacet: (facetName: string, facetValue: string) => void\n onRemoveFacet: (facetName: string, facetValue: string) => void\n}\n\nconst ALL_FACET_VALUE = '__all__'\n\n/**\n * Component for rendering literal facet values as radio buttons since the backend ANDs boolean query values\n */\nfunction LiteralFacetValues({\n facet,\n query,\n disabled = false,\n onAddFacet,\n onRemoveFacet,\n}: LiteralFacetValuesProps) {\n const [showAll, setShowAll] = useState(false)\n\n // Get values from the search query (url)\n const appliedValues =\n query.booleanQuery\n ?.filter(kv => kv.key === facet.name)\n .map(kv => kv.value) || []\n\n const selectedValue = appliedValues[0] ?? ALL_FACET_VALUE\n\n // Get values returned by the search results response\n const availableValues = facet.constraints.map(c => c.value)\n\n const allValues = Array.from(new Set([...appliedValues, ...availableValues]))\n\n const filteredValues = allValues.filter(value =>\n shouldShowFacetValue(facet.name, value),\n )\n\n const displayValues = showAll\n ? filteredValues\n : filteredValues.slice(0, MAX_FACET_VALUES_SHOWN)\n\n const handleChange = (newValue: string) => {\n appliedValues.forEach(v => onRemoveFacet(facet.name, v))\n if (newValue !== ALL_FACET_VALUE) {\n onAddFacet(facet.name, newValue)\n }\n }\n\n return (\n <RadioGroup\n name={`literal-facet-${facet.name}`}\n value={selectedValue}\n onChange={e => handleChange(e.target.value)}\n >\n <FormControlLabel\n sx={{ mb: '8px' }}\n disabled={disabled}\n value={ALL_FACET_VALUE}\n control={<Radio size=\"small\" />}\n label={\n <Typography variant=\"smallText1\" sx={{ lineHeight: '20px' }}>\n {getAllFacetLabel(facet.name)}\n </Typography>\n }\n />\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'column',\n ...(showAll && { maxHeight: '280px', overflowY: 'auto' }),\n }}\n >\n {displayValues.map(value => (\n <FormControlLabel\n disabled={disabled}\n key={value}\n value={value}\n control={<Radio size=\"small\" />}\n label={\n isUserFacet(facet.name) ? (\n <UserBadge userId={value} />\n ) : (\n <Typography variant=\"smallText1\" sx={{ lineHeight: '20px' }}>\n {facet.name === 'node_type'\n ? entityTypeToFriendlyName(value as EntityType) || value\n : value}\n </Typography>\n )\n }\n />\n ))}\n </Box>\n {filteredValues.length > MAX_FACET_VALUES_SHOWN && !showAll && (\n <Button\n disabled={disabled}\n onClick={() => setShowAll(true)}\n variant=\"text\"\n size=\"small\"\n sx={{ alignSelf: 'flex-start' }}\n >\n Show all {filteredValues.length}\n </Button>\n )}\n </RadioGroup>\n )\n}\n\ntype DateRangeFacetValuesProps = {\n facet: Facet\n query: SearchQuery\n disabled?: boolean\n onSetRangeFacet: (facetName: string, minValue: string) => void\n onRemoveRangeFacet: (facetName: string) => void\n isRangeFacetApplied: (facetName: string) => boolean\n getAppliedRangeFacet: (facetName: string) => { min: string } | undefined\n}\n\n/**\n * Component for rendering date/continuous range facet values\n * Uses dayjs's built-in relative time thresholds to determine selection\n */\nfunction DateRangeFacetValues({\n facet,\n disabled = false,\n onSetRangeFacet,\n onRemoveRangeFacet,\n getAppliedRangeFacet,\n}: DateRangeFacetValuesProps) {\n const appliedRangeFacet = getAppliedRangeFacet(facet.name)\n\n // Use dayjs's built-in logic to determine which preset matches the stored timestamp (min - Unix timestamp currently in the URL/Search Query)\n const selectedValue = appliedRangeFacet?.min\n ? getSelectedTimeRangeId(appliedRangeFacet.min)\n : 'ANY_TIME'\n\n const handleChange = (rangeId: string) => {\n const selectedTimeRange = timeRanges.find(r => r.id === rangeId)\n\n if (!selectedTimeRange?.range) {\n onRemoveRangeFacet(facet.name)\n return\n }\n\n // Always calculate 'min' relative to the moment of the click.\n // Use dayjs unit-aware subtraction so month/year account for varying lengths.\n const unitMap: Record<string, dayjs.ManipulateType> = {\n PAST_HOUR: 'hour',\n PAST_DAY: 'day',\n PAST_WEEK: 'week',\n PAST_MONTH: 'month',\n PAST_YEAR: 'year',\n }\n\n /**\n * We use dayjs.subtract() instead of fixed seconds to handle\n * calendar irregularities. dayjs correctly calculates \"one month ago\"\n * whether the current month has 28, 30, or 31 days.\n */\n const minValue = String(dayjs().subtract(1, unitMap[rangeId]).unix())\n onSetRangeFacet(facet.name, minValue)\n }\n\n return (\n <RadioGroup\n name={`range-facet-${facet.name}`}\n value={selectedValue}\n onChange={e => handleChange(e.target.value)}\n >\n {timeRanges.map(range => (\n <FormControlLabel\n disabled={disabled}\n key={range.label}\n value={range.id}\n control={<Radio size=\"small\" />}\n label={range.label}\n sx={{ mb: 0.5 }}\n />\n ))}\n </RadioGroup>\n )\n}\n\ntype AppliedFacetsChipsProps = {\n query: SearchQuery\n onRemoveFacet: (facetName: string, facetValue: string) => void\n onRemoveRangeFacet: (facetName: string) => void\n}\n\n/**\n * Component that displays applied facets as chips with delete icons\n */\nexport function AppliedFacetsChips({\n query,\n onRemoveFacet,\n onRemoveRangeFacet,\n}: AppliedFacetsChipsProps) {\n const booleanQuery = query.booleanQuery || []\n const rangeQuery = query.rangeQuery || []\n const hasAppliedFacets = booleanQuery.length > 0 || rangeQuery.length > 0\n\n if (!hasAppliedFacets) {\n return null\n }\n\n return (\n <Box\n sx={{\n display: 'flex',\n flexWrap: 'wrap',\n gap: 1,\n alignItems: 'center',\n }}\n >\n {booleanQuery.map((kv, index) => {\n if (!shouldShowFacetValue(kv.key, kv.value)) {\n return null\n }\n\n return (\n <Chip\n key={`${kv.key}-${kv.value}-${index}`}\n className={styles.chipStyles}\n deleteIcon={<CloseIcon className={styles.closeIcon} />}\n onDelete={() => onRemoveFacet(kv.key, kv.value)}\n label={\n isUserFacet(kv.key) ? (\n <Box\n sx={{\n '& .MuiTypography-root': {\n color: 'var(--synapse-white)',\n },\n }}\n >\n <UserBadge userId={kv.value} />\n </Box>\n ) : (\n <Typography variant=\"smallText1\">\n {kv.key === 'node_type'\n ? entityTypeToFriendlyName(kv.value as EntityType) ||\n kv.value\n : kv.value}\n </Typography>\n )\n }\n />\n )\n })}\n\n {rangeQuery.map((kr, index) => {\n const displayValue = formatTimeRangeDisplayValue(kr.min)\n const startDate = dayjs(parseInt(kr.min) * 1000).format('MMMM D, YYYY')\n\n return (\n <Tooltip\n title={`Since ${startDate}`}\n arrow\n key={`${kr.key}-${kr.min}-${index}`}\n >\n <Chip\n className={styles.chipStyles}\n label={`${displayValue}`}\n deleteIcon={<CloseIcon className={styles.closeIcon} />}\n onDelete={() => onRemoveRangeFacet(kr.key)}\n />\n </Tooltip>\n )\n })}\n </Box>\n )\n}\n"],"mappings":";;;;;;;;;;;;AAuDA,SAAgB,EAAiB,EAC/B,UACA,aACA,WACA,cAAW,IACX,eACA,kBACA,oBACA,uBACA,wBACA,yBACA,aACA,iBACwB;AAcxB,QACE,kBAAC,GAAD;EACE,IAAI;EACJ,IAAG;EACH,mBAAgB;YAEhB,kBAAC,GAAD;GAAK,IAAI;IAAE,SAAS;IAAQ,eAAe;IAAU,KAAK;IAAG;aAA7D,CACE,kBAAC,GAAD;IAAK,IAAI;KAAE,SAAS;KAAQ,YAAY;KAAU;cAAlD,EAnBH,EAAM,gBAAgB,EAAM,aAAa,SAAS,KAClD,EAAM,cAAc,EAAM,WAAW,SAAS,MAoBvC,kBAAC,GAAD;KACE,eAnBqB;AAC/B,QAAS;OACP,GAAG;OACH,cAAc,EAAE;OAChB,YAAY,EAAE;OACd,OAAO;OACR,CAAC;;KAcQ,SAAQ;KACR,MAAK;KACL,WAAW,EAAO;KACR;eALZ,CAOE,kBAAC,GAAD,EAAe,IAAI,EAAE,WAAW,iBAAiB,EAAI,CAAA,EACrD,kBAAC,GAAD;MAAY,IAAI;OAAE,UAAU;OAAQ,YAAY;OAAK;gBAAE;MAE1C,CAAA,CACN;QAEX,kBAAC,GAAD;KACE,IAAI;MAAE,YAAY;MAAQ,QAAQ;MAAW;KAC7C,SAAS;KACT,iBAAe;KACf,iBAAc;KACd,CAAA,CACE;OACN,kBAAC,GAAD;IACE,IAAI;KACF,SAAS;KACT,eAAe;KACf,KAAK;KACL,UAAU;KACX;cAEA,EAAoB,KAAI,MAAa;KACpC,IAAM,IAAQ,EAAO,MAAK,MAAK,EAAE,SAAS,EAAU;AAMpD,YAJI,CAAC,KAAS,CAAC,EAAkB,EAAM,GAC9B,OAIP,kBAAC,GAAD;MACY;MAEH;MACA;MACK;MACG;MACE;MACG;MACC;MACC;MACtB,EATK,EAAM,KASX;MAEJ;IACE,CAAA,CACF;;EACG,CAAA;;AAoBf,SAAS,EAAiB,EACxB,UACA,cAAW,IACX,UACA,eACA,kBACA,oBACA,uBACA,wBACA,2BACwB;CACxB,IAAM,IAAc,EAAoB,EAAM,KAAK;AAEnD,QACE,kBAAC,GAAD;EAAK,IAAI;GAAE,SAAS;GAAQ,eAAe;GAAU,UAAU;GAAS;YAAxE,CACE,kBAAC,GAAD;GAAY,SAAQ;GAAa,WAAW,EAAO;aAChD;GACU,CAAA,EACZ,EAAM,SAAS,EAAe,UAC7B,kBAAC,GAAD;GACY;GACH;GACA;GACK;GACG;GACf,CAAA,GAEF,kBAAC,GAAD;GACY;GACH;GACA;GACU;GACG;GACC;GACC;GACtB,CAAA,CAEA;;;AAYV,IAAM,IAAkB;AAKxB,SAAS,EAAmB,EAC1B,UACA,UACA,cAAW,IACX,eACA,oBAC0B;CAC1B,IAAM,CAAC,GAAS,KAAc,EAAS,GAAM,EAGvC,IACJ,EAAM,cACF,QAAO,MAAM,EAAG,QAAQ,EAAM,KAAK,CACpC,KAAI,MAAM,EAAG,MAAM,IAAI,EAAE,EAExB,IAAgB,EAAc,MAAM,GAGpC,IAAkB,EAAM,YAAY,KAAI,MAAK,EAAE,MAAM,EAIrD,IAFY,MAAM,KAAK,IAAI,IAAI,CAAC,GAAG,GAAe,GAAG,EAAgB,CAAC,CAErD,CAAU,QAAO,MACtC,EAAqB,EAAM,MAAM,EAAM,CACxC,EAEK,IAAgB,IAClB,IACA,EAAe,MAAM,GAAA,GAA0B,EAE7C,KAAgB,MAAqB;AAEzC,EADA,EAAc,SAAQ,MAAK,EAAc,EAAM,MAAM,EAAE,CAAC,EACpD,MAAa,KACf,EAAW,EAAM,MAAM,EAAS;;AAIpC,QACE,kBAAC,GAAD;EACE,MAAM,iBAAiB,EAAM;EAC7B,OAAO;EACP,WAAU,MAAK,EAAa,EAAE,OAAO,MAAM;YAH7C;GAKE,kBAAC,GAAD;IACE,IAAI,EAAE,IAAI,OAAO;IACP;IACV,OAAO;IACP,SAAS,kBAAC,GAAD,EAAO,MAAK,SAAU,CAAA;IAC/B,OACE,kBAAC,GAAD;KAAY,SAAQ;KAAa,IAAI,EAAE,YAAY,QAAQ;eACxD,EAAiB,EAAM,KAAK;KAClB,CAAA;IAEf,CAAA;GACF,kBAAC,GAAD;IACE,IAAI;KACF,SAAS;KACT,eAAe;KACf,GAAI,KAAW;MAAE,WAAW;MAAS,WAAW;MAAQ;KACzD;cAEA,EAAc,KAAI,MACjB,kBAAC,GAAD;KACY;KAEH;KACP,SAAS,kBAAC,GAAD,EAAO,MAAK,SAAU,CAAA;KAC/B,OACE,EAAY,EAAM,KAAK,GACrB,kBAAC,GAAD,EAAW,QAAQ,GAAS,CAAA,GAE5B,kBAAC,GAAD;MAAY,SAAQ;MAAa,IAAI,EAAE,YAAY,QAAQ;gBACxD,EAAM,SAAS,eACZ,EAAyB,EAAoB,IAC7C;MACO,CAAA;KAGjB,EAdK,EAcL,CACF;IACE,CAAA;GACL,EAAe,SAAA,MAAmC,CAAC,KAClD,kBAAC,GAAD;IACY;IACV,eAAe,EAAW,GAAK;IAC/B,SAAQ;IACR,MAAK;IACL,IAAI,EAAE,WAAW,cAAc;cALjC,CAMC,aACW,EAAe,OAClB;;GAEA;;;AAkBjB,SAAS,EAAqB,EAC5B,UACA,cAAW,IACX,oBACA,uBACA,2BAC4B;CAC5B,IAAM,IAAoB,EAAqB,EAAM,KAAK,EAGpD,IAAgB,GAAmB,MACrC,EAAuB,EAAkB,IAAI,GAC7C,YAEE,KAAgB,MAAoB;AAGxC,MAAI,CAFsB,EAAW,MAAK,MAAK,EAAE,OAAO,EAEnD,EAAmB,OAAO;AAC7B,KAAmB,EAAM,KAAK;AAC9B;;EAkBF,IAAM,IAAW,OAAO,GAAO,CAAC,SAAS,GAAG;GAZ1C,WAAW;GACX,UAAU;GACV,WAAW;GACX,YAAY;GACZ,WAAW;GAQ+B,CAAQ,GAAS,CAAC,MAAM,CAAC;AACrE,IAAgB,EAAM,MAAM,EAAS;;AAGvC,QACE,kBAAC,GAAD;EACE,MAAM,eAAe,EAAM;EAC3B,OAAO;EACP,WAAU,MAAK,EAAa,EAAE,OAAO,MAAM;YAE1C,EAAW,KAAI,MACd,kBAAC,GAAD;GACY;GAEV,OAAO,EAAM;GACb,SAAS,kBAAC,GAAD,EAAO,MAAK,SAAU,CAAA;GAC/B,OAAO,EAAM;GACb,IAAI,EAAE,IAAI,IAAK;GACf,EALK,EAAM,MAKX,CACF;EACS,CAAA;;AAajB,SAAgB,EAAmB,EACjC,UACA,kBACA,yBAC0B;CAC1B,IAAM,IAAe,EAAM,gBAAgB,EAAE,EACvC,IAAa,EAAM,cAAc,EAAE;AAOzC,QANyB,EAAa,SAAS,KAAK,EAAW,SAAS,IAOtE,kBAAC,GAAD;EACE,IAAI;GACF,SAAS;GACT,UAAU;GACV,KAAK;GACL,YAAY;GACb;YANH,CAQG,EAAa,KAAK,GAAI,MAChB,EAAqB,EAAG,KAAK,EAAG,MAAM,GAKzC,kBAAC,GAAD;GAEE,WAAW,EAAO;GAClB,YAAY,kBAAC,GAAD,EAAW,WAAW,EAAO,WAAa,CAAA;GACtD,gBAAgB,EAAc,EAAG,KAAK,EAAG,MAAM;GAC/C,OACE,EAAY,EAAG,IAAI,GACjB,kBAAC,GAAD;IACE,IAAI,EACF,yBAAyB,EACvB,OAAO,wBACR,EACF;cAED,kBAAC,GAAD,EAAW,QAAQ,EAAG,OAAS,CAAA;IAC3B,CAAA,GAEN,kBAAC,GAAD;IAAY,SAAQ;cACjB,EAAG,QAAQ,eACR,EAAyB,EAAG,MAAoB,IAEhD,EAAG;IACI,CAAA;GAGjB,EAxBK,GAAG,EAAG,IAAI,GAAG,EAAG,MAAM,GAAG,IAwB9B,GA7BK,KA+BT,EAED,EAAW,KAAK,GAAI,MAAU;GAC7B,IAAM,IAAe,EAA4B,EAAG,IAAI;AAGxD,UACE,kBAAC,GAAD;IACE,OAAO,SAJO,EAAM,SAAS,EAAG,IAAI,GAAG,IAAK,CAAC,OAAO,eAIpC;IAChB,OAAA;cAGA,kBAAC,GAAD;KACE,WAAW,EAAO;KAClB,OAAO,GAAG;KACV,YAAY,kBAAC,GAAD,EAAW,WAAW,EAAO,WAAa,CAAA;KACtD,gBAAgB,EAAmB,EAAG,IAAI;KAC1C,CAAA;IACM,EARH,GAAG,EAAG,IAAI,GAAG,EAAG,IAAI,GAAG,IAQpB;IAEZ,CACE;MAlEC"}
@@ -1 +1 @@
1
- {"version":3,"file":"SearchFacetPanelUtils.js","names":[],"sources":["../../../../src/components/SynapseSearchPageResults/SearchFacetPanel/SearchFacetPanelUtils.ts"],"sourcesContent":["import { Facet } from '@sage-bionetworks/synapse-types'\nimport dayjs from 'dayjs'\n\n// Constants\nexport const MAX_FACET_VALUES_SHOWN = 10\n\nconst MINUTE_IN_SEC = 60\nconst HOUR_IN_SEC = MINUTE_IN_SEC * 60\nconst DAY_IN_SEC = HOUR_IN_SEC * 24\nconst WEEK_IN_SEC = DAY_IN_SEC * 7\nconst MONTH_IN_SEC = DAY_IN_SEC * 30\nconst YEAR_IN_SEC = DAY_IN_SEC * 365\n\n// 'range' is the approximate duration in seconds used to match a stored URL timestamp back to a preset.\n// null (ANY_TIME) means no date filter is applied.\nexport const timeRanges = [\n { id: 'ANY_TIME', label: 'Any Time', range: null },\n { id: 'PAST_HOUR', label: 'Past Hour', range: HOUR_IN_SEC },\n { id: 'PAST_DAY', label: 'Past 24 Hours', range: DAY_IN_SEC },\n { id: 'PAST_WEEK', label: 'Past Week', range: WEEK_IN_SEC },\n { id: 'PAST_MONTH', label: 'Past Month', range: MONTH_IN_SEC },\n { id: 'PAST_YEAR', label: 'Past Year', range: YEAR_IN_SEC },\n]\n\n// User-friendly display names\nexport const FACET_DISPLAY_NAMES: Record<string, string> = {\n node_type: 'Entity Type',\n modified_by: 'Last Modified By',\n}\n\n// Facet display order\nexport const FACET_DISPLAY_ORDER = [\n 'node_type',\n 'consortium',\n 'disease',\n 'modified_on',\n 'modified_by',\n 'created_on',\n 'tissue',\n 'num_samples',\n 'created_by',\n]\n\nexport const USER_FACET_NAMES = [\n 'modified_by',\n 'created_by',\n 'ModifiedBy',\n 'CreatedBy',\n]\n\nexport const FACET_PLURAL_DISPLAY_NAMES: Record<string, string> = {\n node_type: 'Entity Types',\n consortium: 'Consortiums',\n disease: 'Diseases',\n tissue: 'Tissues',\n num_samples: 'Num Samples',\n modified_by: 'Last Modified By',\n created_by: 'Created By',\n}\n\n// Helper functions\n/**\n * Get the label for the \"All\" option in a facet, e.g. \"All Entity Types\" for the 'node_type' facet\n */\nexport function getAllFacetLabel(facetName: string): string {\n const pluralName =\n FACET_PLURAL_DISPLAY_NAMES[facetName] || formatFacetName(facetName)\n return `All ${pluralName}`\n}\n\n/**\n * Determines if a facet value should be displayed in the UI.\n * Hides 'link' entity types and colon-prefixed values\n */\nexport function shouldShowFacetValue(\n facetName: string,\n value: string,\n): boolean {\n if (!value || value.trim() === '') {\n return false\n }\n\n const isHiddenEntityType =\n (facetName === 'node_type' || facetName === 'EntityType') &&\n value === 'link'\n\n const isInternalPrefixedValue = value.includes(':')\n\n return !isHiddenEntityType && !isInternalPrefixedValue\n}\n\n/**\n * Check if a facet is a user facet (e.g., 'modified_by' or 'created_by')\n * Accepts either snake_case or PascalCase facet names.\n */\nexport const isUserFacet = (name: string): boolean => {\n // Normalize by removing underscores and converting to lowercase\n const normalizedFacetName = name.toLowerCase().replace(/_/g, '')\n\n return USER_FACET_NAMES.some(\n facet => facet.toLowerCase().replace(/_/g, '') === normalizedFacetName,\n )\n}\n\n/**\n * Format facet name: capitalize first letter, replace underscores with spaces\n */\nexport function formatFacetName(name: string): string {\n return name.replace(/_/g, ' ').replace(/\\b\\w/g, char => char.toUpperCase())\n}\n\n/**\n * Get user-friendly display name for a facet\n */\nexport function getFacetDisplayName(facetName: string): string {\n return FACET_DISPLAY_NAMES[facetName] || formatFacetName(facetName)\n}\n\n/**\n * Check if a facet should be rendered (some facets like 'link' are hidden)\n */\nexport function shouldRenderFacet(facet: Facet): boolean {\n // Don't render facets with no constraints (values to click on)\n if (!facet.constraints || facet.constraints.length === 0) {\n return false\n }\n return true\n}\n\n/**\n * Get timestamp from URL/query and determine which time range preset it matches\n *\n * @param timestamp - The stored timestamp (in seconds) from the URL/query\n * @returns The ID of the matching time range preset ('PAST_HOUR', 'PAST_DAY', etc.)\n */\nexport function getSelectedTimeRangeId(timestamp: string): string {\n const storedTimestamp = parseInt(timestamp)\n\n if (!storedTimestamp) {\n return 'ANY_TIME'\n }\n\n const diffInSeconds = dayjs().unix() - storedTimestamp\n\n if (diffInSeconds <= 0) {\n return 'ANY_TIME'\n }\n\n // Filter out 'ANY_TIME' since it doesn't have a numeric range\n const presets = timeRanges.filter(\n (range): range is { id: string; label: string; range: number } =>\n range.id !== 'ANY_TIME',\n )\n\n // Find the closest preset by comparing the absolute difference.\n // Ex: If diffInSeconds is 3605, it is 5 seconds away from PAST_HOUR (3600)\n // but 82,795 seconds away from PAST_DAY (86400) so we would match to PAST_HOUR.\n const closest = presets.reduce((best, preset) =>\n Math.abs(diffInSeconds - preset.range) <\n Math.abs(diffInSeconds - best.range)\n ? preset\n : best,\n )\n\n return closest.id\n}\n\n/**\n * Formats a timestamp for display in the applied facets chip.\n *\n * @param timestamp - The stored timestamp (in seconds)\n * @returns A friendly display string\n */\nexport function formatTimeRangeDisplayValue(timestamp: string): string {\n const storedTimestamp = parseInt(timestamp)\n\n if (isNaN(storedTimestamp)) {\n return timestamp\n }\n\n if (storedTimestamp === 0) {\n return 'any time'\n }\n\n // Try to match to a preset\n const rangeId = getSelectedTimeRangeId(timestamp)\n const matchedRange = timeRanges.find(r => r.id === rangeId)\n\n if (matchedRange && matchedRange.id !== 'ANY_TIME') {\n return matchedRange.label\n }\n\n // Fallback to formatted date if no preset matches\n try {\n const valueInMilliseconds = storedTimestamp * 1000\n return new Date(valueInMilliseconds).toLocaleDateString()\n } catch {\n return timestamp\n }\n}\n"],"mappings":";;AAIA,IAAa,IAAyB,IAGhC,IAAc,MACd,IAAa,IAAc,IAC3B,IAAc,IAAa,GAC3B,IAAe,IAAa,IAC5B,IAAc,IAAa,KAIpB,IAAa;CACxB;EAAE,IAAI;EAAY,OAAO;EAAY,OAAO;EAAM;CAClD;EAAE,IAAI;EAAa,OAAO;EAAa,OAAO;EAAa;CAC3D;EAAE,IAAI;EAAY,OAAO;EAAiB,OAAO;EAAY;CAC7D;EAAE,IAAI;EAAa,OAAO;EAAa,OAAO;EAAa;CAC3D;EAAE,IAAI;EAAc,OAAO;EAAc,OAAO;EAAc;CAC9D;EAAE,IAAI;EAAa,OAAO;EAAa,OAAO;EAAa;CAC5D,EAGY,IAA8C;CACzD,WAAW;CACX,aAAa;CACd,EAGY,IAAsB;CACjC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,EAEY,IAAmB;CAC9B;CACA;CACA;CACA;CACD,EAEY,IAAqD;CAChE,WAAW;CACX,YAAY;CACZ,SAAS;CACT,QAAQ;CACR,aAAa;CACb,aAAa;CACb,YAAY;CACb;AAMD,SAAgB,EAAiB,GAA2B;AAG1D,QAAO,OADL,EAA2B,MAAc,EAAgB,EAAU;;AAQvE,SAAgB,EACd,GACA,GACS;AACT,KAAI,CAAC,KAAS,EAAM,MAAM,KAAK,GAC7B,QAAO;CAGT,IAAM,KACH,MAAc,eAAe,MAAc,iBAC5C,MAAU,QAEN,IAA0B,EAAM,SAAS,IAAI;AAEnD,QAAO,CAAC,KAAsB,CAAC;;AAOjC,IAAa,KAAe,MAA0B;CAEpD,IAAM,IAAsB,EAAK,aAAa,CAAC,QAAQ,MAAM,GAAG;AAEhE,QAAO,EAAiB,MACtB,MAAS,EAAM,aAAa,CAAC,QAAQ,MAAM,GAAG,KAAK,EACpD;;AAMH,SAAgB,EAAgB,GAAsB;AACpD,QAAO,EAAK,QAAQ,MAAM,IAAI,CAAC,QAAQ,UAAS,MAAQ,EAAK,aAAa,CAAC;;AAM7E,SAAgB,EAAoB,GAA2B;AAC7D,QAAO,EAAoB,MAAc,EAAgB,EAAU;;AAMrE,SAAgB,EAAkB,GAAuB;AAKvD,QAHA,EAAI,CAAC,EAAM,eAAe,EAAM,YAAY,WAAW;;AAYzD,SAAgB,EAAuB,GAA2B;CAChE,IAAM,IAAkB,SAAS,EAAU;AAE3C,KAAI,CAAC,EACH,QAAO;CAGT,IAAM,IAAgB,GAAO,CAAC,MAAM,GAAG;AAsBvC,QApBI,KAAiB,IACZ,aAIO,EAAW,QACxB,MACC,EAAM,OAAO,WAChB,CAKuB,QAAQ,GAAM,MACpC,KAAK,IAAI,IAAgB,EAAO,MAAM,GACtC,KAAK,IAAI,IAAgB,EAAK,MAAM,GAChC,IACA,EACL,CAEc;;AASjB,SAAgB,EAA4B,GAA2B;CACrE,IAAM,IAAkB,SAAS,EAAU;AAE3C,KAAI,MAAM,EAAgB,CACxB,QAAO;AAGT,KAAI,MAAoB,EACtB,QAAO;CAIT,IAAM,IAAU,EAAuB,EAAU,EAC3C,IAAe,EAAW,MAAK,MAAK,EAAE,OAAO,EAAQ;AAE3D,KAAI,KAAgB,EAAa,OAAO,WACtC,QAAO,EAAa;AAItB,KAAI;EACF,IAAM,IAAsB,IAAkB;AAC9C,SAAO,IAAI,KAAK,EAAoB,CAAC,oBAAoB;SACnD;AACN,SAAO"}
1
+ {"version":3,"file":"SearchFacetPanelUtils.js","names":[],"sources":["../../../../src/components/SynapseSearchPageResults/SearchFacetPanel/SearchFacetPanelUtils.ts"],"sourcesContent":["import { Facet } from '@sage-bionetworks/synapse-types'\nimport dayjs from 'dayjs'\n\n// Constants\nexport const MAX_FACET_VALUES_SHOWN = 10\n\nconst MINUTE_IN_SEC = 60\nconst HOUR_IN_SEC = MINUTE_IN_SEC * 60\nconst DAY_IN_SEC = HOUR_IN_SEC * 24\nconst WEEK_IN_SEC = DAY_IN_SEC * 7\nconst MONTH_IN_SEC = DAY_IN_SEC * 30\nconst YEAR_IN_SEC = DAY_IN_SEC * 365\n\n// 'range' is the approximate duration in seconds used to match a stored URL timestamp back to a preset.\n// null (ANY_TIME) means no date filter is applied.\nexport const timeRanges = [\n { id: 'ANY_TIME', label: 'Any Time', range: null },\n { id: 'PAST_HOUR', label: 'Past Hour', range: HOUR_IN_SEC },\n { id: 'PAST_DAY', label: 'Past 24 Hours', range: DAY_IN_SEC },\n { id: 'PAST_WEEK', label: 'Past Week', range: WEEK_IN_SEC },\n { id: 'PAST_MONTH', label: 'Past Month', range: MONTH_IN_SEC },\n { id: 'PAST_YEAR', label: 'Past Year', range: YEAR_IN_SEC },\n]\n\n// User-friendly display names\nexport const FACET_DISPLAY_NAMES: Record<string, string> = {\n node_type: 'Entity Type',\n modified_by: 'Last Modified By',\n}\n\n// Facet display order\nexport const FACET_DISPLAY_ORDER = [\n 'node_type',\n 'consortium',\n 'disease',\n 'modified_on',\n 'modified_by',\n 'created_on',\n 'tissue',\n 'num_samples',\n 'created_by',\n]\n\nexport const USER_FACET_NAMES = [\n 'modified_by',\n 'created_by',\n 'ModifiedBy',\n 'CreatedBy',\n]\n\nexport const FACET_PLURAL_DISPLAY_NAMES: Record<string, string> = {\n node_type: 'Entity Types',\n consortium: 'Consortiums',\n disease: 'Diseases',\n tissue: 'Tissues',\n num_samples: 'Num Samples',\n modified_by: 'Last Modified By',\n created_by: 'Created By',\n}\n\n// Helper functions\n/**\n * Get the label for the \"All\" option in a facet, e.g. \"All Entity Types\" for the 'node_type' facet\n */\nexport function getAllFacetLabel(facetName: string): string {\n const pluralName =\n FACET_PLURAL_DISPLAY_NAMES[facetName] || formatFacetName(facetName)\n return `All ${pluralName}`\n}\n\n/**\n * Determines if a facet value should be displayed in the UI.\n * Hides 'link' entity types and colon-prefixed values\n */\nexport function shouldShowFacetValue(\n facetName: string,\n value: string,\n): boolean {\n if (!value || value.trim() === '') {\n return false\n }\n\n const isHiddenEntityType =\n (facetName === 'node_type' || facetName === 'EntityType') &&\n value === 'link'\n\n const isInternalPrefixedValue = value.includes(':')\n\n return !isHiddenEntityType && !isInternalPrefixedValue\n}\n\n/**\n * Check if a facet is a user facet (e.g., 'modified_by' or 'created_by')\n * Accepts either snake_case or PascalCase facet names.\n */\nexport const isUserFacet = (name: string): boolean => {\n // Normalize by removing underscores and converting to lowercase\n const normalizedFacetName = name.toLowerCase().replace(/_/g, '')\n\n return USER_FACET_NAMES.some(\n facet => facet.toLowerCase().replace(/_/g, '') === normalizedFacetName,\n )\n}\n\n/**\n * Format facet name: capitalize first letter, replace underscores with spaces\n */\nexport function formatFacetName(name: string): string {\n return name.replace(/_/g, ' ').replace(/\\b\\w/g, char => char.toUpperCase())\n}\n\n/**\n * Get user-friendly display name for a facet\n */\nexport function getFacetDisplayName(facetName: string): string {\n return FACET_DISPLAY_NAMES[facetName] || formatFacetName(facetName)\n}\n\n/**\n * Check if a facet should be rendered (some facets like 'link' are hidden)\n */\nexport function shouldRenderFacet(facet: Facet): boolean {\n // Don't render facets with no constraints (values to click on)\n if (!facet.constraints || facet.constraints.length === 0) {\n return false\n }\n return true\n}\n\n/**\n * Get timestamp from URL/query and determine which time range preset it matches\n *\n * @param timestamp - The stored timestamp (in seconds) from the URL/query\n * @returns The ID of the matching time range preset ('PAST_HOUR', 'PAST_DAY', etc.)\n */\nexport function getSelectedTimeRangeId(timestamp: string): string {\n const storedTimestamp = parseInt(timestamp)\n\n if (!storedTimestamp) {\n return 'ANY_TIME'\n }\n\n const diffInSeconds = dayjs().unix() - storedTimestamp\n\n if (diffInSeconds <= 0) {\n return 'ANY_TIME'\n }\n\n // Filter out 'ANY_TIME' since it doesn't have a numeric range\n const presets = timeRanges.filter(\n (range): range is { id: string; label: string; range: number } =>\n range.id !== 'ANY_TIME',\n )\n\n // Find the closest preset by comparing the absolute difference.\n // Ex: If diffInSeconds is 3605, it is 5 seconds away from PAST_HOUR (3600)\n // but 82,795 seconds away from PAST_DAY (86400) so we would match to PAST_HOUR.\n const closest = presets.reduce((best, preset) =>\n Math.abs(diffInSeconds - preset.range) <\n Math.abs(diffInSeconds - best.range)\n ? preset\n : best,\n )\n\n return closest.id\n}\n\n/**\n * Formats a timestamp for display in the applied facets chip.\n *\n * @param timestamp - The stored timestamp (in seconds)\n * @returns A friendly display string\n */\nexport function formatTimeRangeDisplayValue(timestamp: string): string {\n const storedTimestamp = parseInt(timestamp)\n\n if (isNaN(storedTimestamp)) {\n return timestamp\n }\n\n if (storedTimestamp === 0) {\n return 'any time'\n }\n\n // Try to match to a preset\n const rangeId = getSelectedTimeRangeId(timestamp)\n const matchedRange = timeRanges.find(r => r.id === rangeId)\n\n if (matchedRange && matchedRange.id !== 'ANY_TIME') {\n return matchedRange.label\n }\n\n // Fallback to formatted date if no preset matches\n try {\n const valueInMilliseconds = storedTimestamp * 1000\n return new Date(valueInMilliseconds).toLocaleDateString()\n } catch {\n return timestamp\n }\n}\n"],"mappings":";;AAIA,IAAa,IAAyB,IAGhC,IAAc,MACd,IAAa,IAAc,IAC3B,IAAc,IAAa,GAC3B,IAAe,IAAa,IAC5B,IAAc,IAAa,KAIpB,IAAa;CACxB;EAAE,IAAI;EAAY,OAAO;EAAY,OAAO;EAAM;CAClD;EAAE,IAAI;EAAa,OAAO;EAAa,OAAO;EAAa;CAC3D;EAAE,IAAI;EAAY,OAAO;EAAiB,OAAO;EAAY;CAC7D;EAAE,IAAI;EAAa,OAAO;EAAa,OAAO;EAAa;CAC3D;EAAE,IAAI;EAAc,OAAO;EAAc,OAAO;EAAc;CAC9D;EAAE,IAAI;EAAa,OAAO;EAAa,OAAO;EAAa;CAC5D,EAGY,IAA8C;CACzD,WAAW;CACX,aAAa;CACd,EAGY,IAAsB;CACjC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,EAEY,IAAmB;CAC9B;CACA;CACA;CACA;CACD,EAEY,IAAqD;CAChE,WAAW;CACX,YAAY;CACZ,SAAS;CACT,QAAQ;CACR,aAAa;CACb,aAAa;CACb,YAAY;CACb;AAMD,SAAgB,EAAiB,GAA2B;AAG1D,QAAO,OADL,EAA2B,MAAc,EAAgB,EAAU;;AAQvE,SAAgB,EACd,GACA,GACS;AACT,KAAI,CAAC,KAAS,EAAM,MAAM,KAAK,GAC7B,QAAO;CAGT,IAAM,KACH,MAAc,eAAe,MAAc,iBAC5C,MAAU,QAEN,IAA0B,EAAM,SAAS,IAAI;AAEnD,QAAO,CAAC,KAAsB,CAAC;;AAOjC,IAAa,KAAe,MAA0B;CAEpD,IAAM,IAAsB,EAAK,aAAa,CAAC,QAAQ,MAAM,GAAG;AAEhE,QAAO,EAAiB,MACtB,MAAS,EAAM,aAAa,CAAC,QAAQ,MAAM,GAAG,KAAK,EACpD;;AAMH,SAAgB,EAAgB,GAAsB;AACpD,QAAO,EAAK,QAAQ,MAAM,IAAI,CAAC,QAAQ,UAAS,MAAQ,EAAK,aAAa,CAAC;;AAM7E,SAAgB,EAAoB,GAA2B;AAC7D,QAAO,EAAoB,MAAc,EAAgB,EAAU;;AAMrE,SAAgB,EAAkB,GAAuB;AAKvD,QAHA,EAAI,CAAC,EAAM,eAAe,EAAM,YAAY,WAAW;;AAYzD,SAAgB,EAAuB,GAA2B;CAChE,IAAM,IAAkB,SAAS,EAAU;AAE3C,KAAI,CAAC,EACH,QAAO;CAGT,IAAM,IAAgB,GAAO,CAAC,MAAM,GAAG;AAsBvC,QApBI,KAAiB,IACZ,aAIO,EAAW,QACxB,MACC,EAAM,OAAO,WAMD,CAAQ,QAAQ,GAAM,MACpC,KAAK,IAAI,IAAgB,EAAO,MAAM,GACtC,KAAK,IAAI,IAAgB,EAAK,MAAM,GAChC,IACA,EAGC,CAAQ;;AASjB,SAAgB,EAA4B,GAA2B;CACrE,IAAM,IAAkB,SAAS,EAAU;AAE3C,KAAI,MAAM,EAAgB,CACxB,QAAO;AAGT,KAAI,MAAoB,EACtB,QAAO;CAIT,IAAM,IAAU,EAAuB,EAAU,EAC3C,IAAe,EAAW,MAAK,MAAK,EAAE,OAAO,EAAQ;AAE3D,KAAI,KAAgB,EAAa,OAAO,WACtC,QAAO,EAAa;AAItB,KAAI;EACF,IAAM,IAAsB,IAAkB;AAC9C,SAAO,IAAI,KAAK,EAAoB,CAAC,oBAAoB;SACnD;AACN,SAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"SynapseSearchPageResults.js","names":[],"sources":["../../../src/components/SynapseSearchPageResults/SynapseSearchPageResults.tsx"],"sourcesContent":["import {\n Box,\n TextField,\n InputAdornment,\n Button,\n Typography,\n IconButton,\n Collapse,\n Badge,\n Skeleton,\n Link,\n} from '@mui/material'\nimport SynapseSearchResultsCard from './SynapseSearchResultsCard'\nimport SearchIcon from '@mui/icons-material/Search'\nimport FilterAltOutlinedIcon from '@mui/icons-material/FilterAltOutlined'\nimport React, {\n useState,\n useEffect,\n useMemo,\n useCallback,\n Suspense,\n} from 'react'\nimport { useSearchInfinite } from '@/synapse-queries/search/useSearch'\nimport {\n SearchQuery,\n KeyRange,\n Hit,\n Facet,\n} from '@sage-bionetworks/synapse-types'\nimport { useDocumentMetadata } from '@/utils/context/DocumentMetadataContext'\nimport { ArrowForward } from '@mui/icons-material'\nimport styles from './SynapseSearchPageResults.module.scss'\nimport { useSuggestion } from '@/synapse-queries/search/useSuggestion'\nimport { Suggestion } from '@sage-bionetworks/synapse-client'\nimport SearchPagePortalBanners from './SearchPagePortalBanners'\nimport { SYNAPSE_ENTITY_ID_REGEX } from '@/utils/functions/RegularExpressions'\nimport { DEFAULT_SEARCH_QUERY } from '@/utils/searchDefaults'\nimport {\n SearchFacetPanel,\n AppliedFacetsChips,\n} from './SearchFacetPanel/SearchFacetPanel'\nimport { shouldShowFacetValue } from './SearchFacetPanel/SearchFacetPanelUtils'\nimport { SkeletonInlineBlock } from '../Skeleton'\nimport { useSynapseContext } from '@/utils'\n\n/**\n * Add a literal facet filter to the query\n */\nfunction addFacetToQuery(\n query: SearchQuery,\n facetName: string,\n facetValue: string,\n): SearchQuery {\n const booleanQuery = query.booleanQuery || []\n\n const isFilterAlreadyApplied = booleanQuery.some(\n kv => kv.key === facetName && kv.value === facetValue,\n )\n\n if (isFilterAlreadyApplied) {\n return query\n }\n\n return {\n ...DEFAULT_SEARCH_QUERY,\n ...query,\n booleanQuery: [\n ...booleanQuery,\n { key: facetName, value: facetValue, not: false },\n ],\n start: 0, // Reset to first page\n }\n}\n\n/**\n * Remove a literal facet filter from the query\n */\nfunction removeFacetFromQuery(\n query: SearchQuery,\n facetName: string,\n facetValue: string,\n): SearchQuery {\n const booleanQuery = query.booleanQuery || []\n\n return {\n ...DEFAULT_SEARCH_QUERY,\n ...query,\n booleanQuery: booleanQuery.filter(\n kv => !(kv.key === facetName && kv.value === facetValue),\n ),\n start: 0,\n }\n}\n\n/**\n * Set a range facet (ex, for modified on, created on)\n */\nfunction setRangeFacetInQuery(\n query: SearchQuery,\n facetName: string,\n minValue: string,\n): SearchQuery {\n const rangeQuery = query.rangeQuery || []\n\n // Remove any existing range for this facet\n const filteredRangeQuery = rangeQuery.filter(kr => kr.key !== facetName)\n\n const maxValue = String(Math.floor(Date.now() / 1000)) // Now in seconds\n\n return {\n ...DEFAULT_SEARCH_QUERY,\n ...query,\n rangeQuery: [\n ...filteredRangeQuery,\n { key: facetName, min: minValue, max: maxValue },\n ],\n start: 0,\n }\n}\n\n/**\n * Remove a range facet from the query\n */\nfunction removeRangeFacetFromQuery(\n query: SearchQuery,\n facetName: string,\n): SearchQuery {\n const rangeQuery = query.rangeQuery || []\n\n return {\n ...DEFAULT_SEARCH_QUERY,\n ...query,\n rangeQuery: rangeQuery.filter(kr => kr.key !== facetName),\n start: 0,\n }\n}\n\n/**\n * Check if a range facet is currently applied\n */\nfunction isRangeFacetApplied(query: SearchQuery, facetName: string): boolean {\n const rangeQuery = query.rangeQuery || []\n return rangeQuery.some(kr => kr.key === facetName)\n}\n\n/**\n * Get the applied range facet value for a given facet name\n */\nfunction getAppliedRangeFacet(\n query: SearchQuery,\n facetName: string,\n): KeyRange | undefined {\n const rangeQuery = query.rangeQuery || []\n return rangeQuery.find(kr => kr.key === facetName)\n}\n\nexport type SynapseSearchPageResultsProps = {\n query?: SearchQuery\n setQuery?: (newQuery: SearchQuery) => void\n}\n\nexport function SynapseSearchPageResults(props: SynapseSearchPageResultsProps) {\n const MIN_SUGGESTION_SCORE = 0.75\n const { query, setQuery } = props\n const { peopleSearchPageUrl } = useSynapseContext()\n const [expanded, setExpanded] = useState(false)\n\n // Set page title (replaces jsniUtils.setPageTitle(DisplayConstants.LABEL_SEARCH) from Java)\n useDocumentMetadata({ title: `Search: ${query?.queryTerm?.join(' ')}` })\n\n // Capture local state to prevent search from executing on every keystroke\n // Join query terms so that textfield input looks correct\n const [searchInputValue, setSearchInputValue] = useState(\n query?.queryTerm?.join(' ') || '',\n )\n\n // Sync input value when query prop changes\n // Join query terms so that textfield input looks correct\n useEffect(() => {\n setSearchInputValue(query?.queryTerm?.join(' ') || '')\n }, [query])\n\n // Execute search\n const {\n data,\n isLoading,\n error,\n fetchNextPage,\n hasNextPage,\n isFetchingNextPage,\n } = useSearchInfinite(\n query\n ? {\n ...DEFAULT_SEARCH_QUERY,\n ...query,\n size: 50,\n returnFields: ['path'],\n }\n : { queryTerm: [], size: 50, returnFields: ['path'] },\n {\n enabled: !!query?.queryTerm?.[0],\n },\n )\n\n // Update local input state\n const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n setSearchInputValue(event.target.value)\n }\n\n // Update query only when user explicitly searches\n // Split query terms to form array\n const handleSearch = () => {\n if (setQuery) {\n const newQuery = {\n ...DEFAULT_SEARCH_QUERY,\n ...query,\n queryTerm: searchInputValue\n ? searchInputValue\n .split(' ')\n .map(term => term.trim())\n .filter(Boolean)\n : [],\n start: 0,\n }\n setQuery(newQuery)\n }\n }\n\n // Fetch spelling suggestions for the search terms\n const { data: suggestionData } = useSuggestion(\n { searchTerm: query?.queryTerm },\n\n {\n enabled: !!query?.queryTerm?.[0],\n },\n )\n\n const suggestion = useMemo(() => {\n const suggestionValues = suggestionData?.suggestions\n const terms = query?.queryTerm || []\n\n if (!suggestionValues) return null\n\n // Map original terms to their best suggestions if available\n const suggestionMap = new Map<string, string>()\n let hasSuggestion = false\n\n for (const suggestionList of suggestionValues) {\n const originalTerm = suggestionList.key\n const suggestions = Array.from(suggestionList.values ?? [])\n\n // Among suggestions above the score threshold, pick the highest-frequency term.\n const bestSuggestion = suggestions.reduce<Suggestion | null>(\n (best, current) => {\n if (\n current.score === undefined ||\n current.score < MIN_SUGGESTION_SCORE\n ) {\n return best\n }\n if (!best || (current.frequency ?? 0) > (best.frequency ?? 0)) {\n return current\n }\n return best\n },\n null,\n )\n\n // If a valid suggestion is found and it's different from the original term, add it to the map\n if (bestSuggestion?.term && bestSuggestion.term !== originalTerm) {\n suggestionMap.set(originalTerm!, bestSuggestion.term)\n hasSuggestion = true\n }\n }\n\n if (!hasSuggestion) return null\n\n // Build the corrected search string by replacing misspelled terms\n // Use toLowerCase() because the suggestion API returns keys in lowercase\n const correctedTerms = terms.map(\n term => suggestionMap.get(term.toLowerCase()) || term,\n )\n\n return correctedTerms.join(' ')\n }, [suggestionData, query?.queryTerm])\n\n // Extract entity IDs from search results for relevant portal banner display\n const entityIdsForPortalBanners = useMemo(() => {\n if (!data?.pages || data.pages.length === 0) {\n return []\n }\n\n const entityIds = new Set<string>()\n\n const firstPage = data.pages[0]\n\n if (firstPage?.hits) {\n for (const hit of firstPage.hits) {\n // search result is the top-level Project itself\n if (hit.id) {\n entityIds.add(hit.id)\n }\n\n if (hit.path?.path) {\n for (const pathEntity of hit.path.path.slice(1)) {\n if (pathEntity.id) {\n entityIds.add(pathEntity.id)\n }\n }\n }\n }\n }\n\n const finalIds = Array.from(entityIds)\n\n return finalIds\n }, [data])\n\n const handleUseSuggestion = () => {\n if (setQuery && suggestion) {\n const newQuery = {\n ...DEFAULT_SEARCH_QUERY,\n ...query,\n queryTerm: suggestion\n .split(' ')\n .map(term => term.trim())\n .filter(Boolean),\n start: 0,\n }\n setQuery(newQuery)\n }\n }\n\n const noResults = data?.pages?.[0]?.hits?.length === 0\n const isSynId = SYNAPSE_ENTITY_ID_REGEX.test(query?.queryTerm?.[0] || '')\n\n // cached facets in local state to prevent them from being cleared when the query changes and new search results are loading\n const [facets, setFacets] = useState<Facet[]>([])\n\n useEffect(() => {\n const newFacets = data?.pages?.[0]?.facets\n if (newFacets) {\n setFacets(newFacets)\n }\n }, [data])\n\n const handleAddFacet = useCallback(\n (facetName: string, facetValue: string) => {\n if (setQuery && query) {\n setQuery(addFacetToQuery(query, facetName, facetValue))\n }\n },\n [query, setQuery],\n )\n\n const handleRemoveFacet = useCallback(\n (facetName: string, facetValue: string) => {\n if (setQuery && query) {\n setQuery(removeFacetFromQuery(query, facetName, facetValue))\n }\n },\n [query, setQuery],\n )\n\n const handleSetRangeFacet = useCallback(\n (facetName: string, minValue: string) => {\n if (setQuery && query) {\n setQuery(setRangeFacetInQuery(query, facetName, minValue))\n }\n },\n [query, setQuery],\n )\n\n const handleRemoveRangeFacet = useCallback(\n (facetName: string) => {\n if (setQuery && query) {\n setQuery(removeRangeFacetFromQuery(query, facetName))\n }\n },\n [query, setQuery],\n )\n\n const isRangeFacetAppliedCallback = useCallback(\n (name: string) => (query ? isRangeFacetApplied(query, name) : false),\n [query],\n )\n\n const getAppliedRangeFacetCallback = useCallback(\n (name: string) => (query ? getAppliedRangeFacet(query, name) : undefined),\n [query],\n )\n\n const appliedFacetsCount =\n (query?.booleanQuery?.filter(kv => shouldShowFacetValue(kv.key, kv.value))\n .length || 0) + (query?.rangeQuery?.length || 0)\n\n return (\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'column',\n width: '100%',\n p: '30px',\n gap: '20px',\n }}\n >\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'column',\n height: 'auto',\n gap: '16px',\n }}\n >\n {peopleSearchPageUrl && (\n <Typography variant=\"smallText1\">\n Searching for a user profile? Try our{' '}\n <Link href={peopleSearchPageUrl}>People Search.</Link>\n </Typography>\n )}\n <Box className={styles.searchContainer}>\n <TextField\n placeholder=\"Search…\"\n sx={{ flex: 1 }}\n value={searchInputValue}\n onChange={handleInputChange}\n onKeyDown={e => {\n if (e.key === 'Enter') {\n handleSearch()\n }\n }}\n slotProps={{\n input: {\n sx: {\n borderRadius: '96px',\n boxShadow: '0px 1px 4px var(--synapse-gray-500)',\n backgroundColor: 'var(--synapse-white)',\n },\n startAdornment: (\n <InputAdornment position=\"start\">\n <SearchIcon sx={{ color: 'secondary.600' }} />\n </InputAdornment>\n ),\n },\n }}\n />\n <Button\n onClick={() => setExpanded(true)}\n variant=\"outlined\"\n startIcon={<FilterAltOutlinedIcon />}\n aria-expanded={expanded}\n aria-controls=\"filter-search-results-panel\"\n sx={{\n color: theme => theme.palette.primary.dark,\n }}\n className={styles.filterButton}\n >\n <Typography\n sx={{\n fontWeight: 700,\n lineHeight: '16px',\n display: 'flex',\n gap: '8px',\n }}\n >\n <span id=\"filter-results-button-label\">\n Filter Search Results\n </span>\n {appliedFacetsCount > 0 && (\n <Badge\n badgeContent={appliedFacetsCount}\n color=\"primary\"\n sx={{\n '& .MuiBadge-badge': {\n position: 'static',\n transform: 'none',\n height: '18px',\n minWidth: '18px',\n },\n }}\n />\n )}\n </Typography>\n </Button>\n </Box>\n <Box>\n {facets.length > 0 && (\n <Collapse\n in={expanded}\n id=\"filter-search-results-panel\"\n aria-labelledby=\"filter-results-button-label\"\n >\n <Box\n sx={{\n border: '1px solid',\n borderColor: 'var(--synapse-gray-100)',\n backgroundColor: 'var(--synapse-white)',\n padding: '25px',\n boxShadow: '0 4px 16px 0 rgba(0, 0, 0, 0.04)',\n pointerEvents: isLoading ? 'none' : 'auto',\n opacity: isLoading ? 0.5 : 1,\n }}\n >\n {query && setQuery && (\n <SearchFacetPanel\n expanded={expanded}\n onCollapse={() => setExpanded(false)}\n disabled={isLoading}\n query={query}\n setQuery={setQuery}\n facets={facets}\n onAddFacet={handleAddFacet}\n onRemoveFacet={handleRemoveFacet}\n onSetRangeFacet={handleSetRangeFacet}\n onRemoveRangeFacet={handleRemoveRangeFacet}\n isRangeFacetApplied={isRangeFacetAppliedCallback}\n getAppliedRangeFacet={getAppliedRangeFacetCallback}\n />\n )}\n </Box>\n </Collapse>\n )}\n </Box>\n </Box>\n <>\n {data && !isSynId && suggestion && (\n <div className={styles.didYouMeanContainer}>\n <div className={styles.didYouMeanCurrentlyShowing}>\n {!noResults && (\n <>\n Currently showing results for{' '}\n <b>{query?.queryTerm?.join(' ')}</b>.\n </>\n )}\n </div>\n <div className={styles.didYouMeanSuggestion}>\n <SearchIcon\n sx={{ color: 'grey.600' }}\n className={styles.searchIcon}\n />\n <Typography variant=\"body1\" className={styles.didYouMeanText}>\n Search for <b className={styles.suggestionText}>{suggestion}</b>{' '}\n instead?\n </Typography>\n <IconButton\n className={styles.didYouMeanArrowContainer}\n onClick={handleUseSuggestion}\n aria-label={`Search for ${suggestion} instead`}\n sx={{\n borderColor: 'primary.main',\n svg: { color: 'primary.main' },\n }}\n >\n <ArrowForward />\n </IconButton>\n </div>\n </div>\n )}\n {noResults && (\n <div className={styles.didYouMeanCurrentlyShowing}>\n No results found for <b>{query?.queryTerm?.join(' ')}</b>.\n </div>\n )}\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'flex-end',\n gap: '20px',\n }}\n >\n {isLoading &&\n Array.from({ length: 3 }, () => (\n <Skeleton variant=\"rectangular\" width={'100%'} height={'250px'} />\n ))}\n {error && <div>Error: {error.message}</div>}\n <Suspense\n fallback={<SkeletonInlineBlock width={'100%'} height={'150px'} />}\n >\n <SearchPagePortalBanners entityIds={entityIdsForPortalBanners} />\n </Suspense>\n {query && (\n <Box sx={{ alignSelf: 'flex-start' }}>\n <AppliedFacetsChips\n query={query}\n onRemoveFacet={handleRemoveFacet}\n onRemoveRangeFacet={handleRemoveRangeFacet}\n />\n </Box>\n )}\n {data &&\n data.pages &&\n data.pages.map((page, pageIndex) =>\n page.hits.map((hit: Hit) => {\n const projectPath = hit.path?.path?.[1]\n return (\n <SynapseSearchResultsCard\n searchTerms={query?.queryTerm ?? []}\n key={hit.id + '-' + pageIndex}\n entityId={hit.id}\n name={hit.name}\n entityType={hit.node_type}\n modifiedOn={hit.modified_on}\n description={hit.description}\n locatedIn={projectPath}\n />\n )\n }),\n )}\n {hasNextPage && (\n <Button\n onClick={() => {\n void fetchNextPage()\n }}\n loading={isFetchingNextPage}\n variant=\"contained\"\n sx={{ mt: 2 }}\n >\n {isFetchingNextPage ? 'Loading more...' : 'Load More'}\n </Button>\n )}\n </Box>\n </>\n </Box>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"SynapseSearchPageResults.js","names":[],"sources":["../../../src/components/SynapseSearchPageResults/SynapseSearchPageResults.tsx"],"sourcesContent":["import {\n Box,\n TextField,\n InputAdornment,\n Button,\n Typography,\n IconButton,\n Collapse,\n Badge,\n Skeleton,\n Link,\n} from '@mui/material'\nimport SynapseSearchResultsCard from './SynapseSearchResultsCard'\nimport SearchIcon from '@mui/icons-material/Search'\nimport FilterAltOutlinedIcon from '@mui/icons-material/FilterAltOutlined'\nimport React, {\n useState,\n useEffect,\n useMemo,\n useCallback,\n Suspense,\n} from 'react'\nimport { useSearchInfinite } from '@/synapse-queries/search/useSearch'\nimport {\n SearchQuery,\n KeyRange,\n Hit,\n Facet,\n} from '@sage-bionetworks/synapse-types'\nimport { useDocumentMetadata } from '@/utils/context/DocumentMetadataContext'\nimport { ArrowForward } from '@mui/icons-material'\nimport styles from './SynapseSearchPageResults.module.scss'\nimport { useSuggestion } from '@/synapse-queries/search/useSuggestion'\nimport { Suggestion } from '@sage-bionetworks/synapse-client'\nimport SearchPagePortalBanners from './SearchPagePortalBanners'\nimport { SYNAPSE_ENTITY_ID_REGEX } from '@/utils/functions/RegularExpressions'\nimport { DEFAULT_SEARCH_QUERY } from '@/utils/searchDefaults'\nimport {\n SearchFacetPanel,\n AppliedFacetsChips,\n} from './SearchFacetPanel/SearchFacetPanel'\nimport { shouldShowFacetValue } from './SearchFacetPanel/SearchFacetPanelUtils'\nimport { SkeletonInlineBlock } from '../Skeleton'\nimport { useSynapseContext } from '@/utils'\n\n/**\n * Add a literal facet filter to the query\n */\nfunction addFacetToQuery(\n query: SearchQuery,\n facetName: string,\n facetValue: string,\n): SearchQuery {\n const booleanQuery = query.booleanQuery || []\n\n const isFilterAlreadyApplied = booleanQuery.some(\n kv => kv.key === facetName && kv.value === facetValue,\n )\n\n if (isFilterAlreadyApplied) {\n return query\n }\n\n return {\n ...DEFAULT_SEARCH_QUERY,\n ...query,\n booleanQuery: [\n ...booleanQuery,\n { key: facetName, value: facetValue, not: false },\n ],\n start: 0, // Reset to first page\n }\n}\n\n/**\n * Remove a literal facet filter from the query\n */\nfunction removeFacetFromQuery(\n query: SearchQuery,\n facetName: string,\n facetValue: string,\n): SearchQuery {\n const booleanQuery = query.booleanQuery || []\n\n return {\n ...DEFAULT_SEARCH_QUERY,\n ...query,\n booleanQuery: booleanQuery.filter(\n kv => !(kv.key === facetName && kv.value === facetValue),\n ),\n start: 0,\n }\n}\n\n/**\n * Set a range facet (ex, for modified on, created on)\n */\nfunction setRangeFacetInQuery(\n query: SearchQuery,\n facetName: string,\n minValue: string,\n): SearchQuery {\n const rangeQuery = query.rangeQuery || []\n\n // Remove any existing range for this facet\n const filteredRangeQuery = rangeQuery.filter(kr => kr.key !== facetName)\n\n const maxValue = String(Math.floor(Date.now() / 1000)) // Now in seconds\n\n return {\n ...DEFAULT_SEARCH_QUERY,\n ...query,\n rangeQuery: [\n ...filteredRangeQuery,\n { key: facetName, min: minValue, max: maxValue },\n ],\n start: 0,\n }\n}\n\n/**\n * Remove a range facet from the query\n */\nfunction removeRangeFacetFromQuery(\n query: SearchQuery,\n facetName: string,\n): SearchQuery {\n const rangeQuery = query.rangeQuery || []\n\n return {\n ...DEFAULT_SEARCH_QUERY,\n ...query,\n rangeQuery: rangeQuery.filter(kr => kr.key !== facetName),\n start: 0,\n }\n}\n\n/**\n * Check if a range facet is currently applied\n */\nfunction isRangeFacetApplied(query: SearchQuery, facetName: string): boolean {\n const rangeQuery = query.rangeQuery || []\n return rangeQuery.some(kr => kr.key === facetName)\n}\n\n/**\n * Get the applied range facet value for a given facet name\n */\nfunction getAppliedRangeFacet(\n query: SearchQuery,\n facetName: string,\n): KeyRange | undefined {\n const rangeQuery = query.rangeQuery || []\n return rangeQuery.find(kr => kr.key === facetName)\n}\n\nexport type SynapseSearchPageResultsProps = {\n query?: SearchQuery\n setQuery?: (newQuery: SearchQuery) => void\n}\n\nexport function SynapseSearchPageResults(props: SynapseSearchPageResultsProps) {\n const MIN_SUGGESTION_SCORE = 0.75\n const { query, setQuery } = props\n const { peopleSearchPageUrl } = useSynapseContext()\n const [expanded, setExpanded] = useState(false)\n\n // Set page title (replaces jsniUtils.setPageTitle(DisplayConstants.LABEL_SEARCH) from Java)\n useDocumentMetadata({ title: `Search: ${query?.queryTerm?.join(' ')}` })\n\n // Capture local state to prevent search from executing on every keystroke\n // Join query terms so that textfield input looks correct\n const [searchInputValue, setSearchInputValue] = useState(\n query?.queryTerm?.join(' ') || '',\n )\n\n // Sync input value when query prop changes\n // Join query terms so that textfield input looks correct\n useEffect(() => {\n setSearchInputValue(query?.queryTerm?.join(' ') || '')\n }, [query])\n\n // Execute search\n const {\n data,\n isLoading,\n error,\n fetchNextPage,\n hasNextPage,\n isFetchingNextPage,\n } = useSearchInfinite(\n query\n ? {\n ...DEFAULT_SEARCH_QUERY,\n ...query,\n size: 50,\n returnFields: ['path'],\n }\n : { queryTerm: [], size: 50, returnFields: ['path'] },\n {\n enabled: !!query?.queryTerm?.[0],\n },\n )\n\n // Update local input state\n const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n setSearchInputValue(event.target.value)\n }\n\n // Update query only when user explicitly searches\n // Split query terms to form array\n const handleSearch = () => {\n if (setQuery) {\n const newQuery = {\n ...DEFAULT_SEARCH_QUERY,\n ...query,\n queryTerm: searchInputValue\n ? searchInputValue\n .split(' ')\n .map(term => term.trim())\n .filter(Boolean)\n : [],\n start: 0,\n }\n setQuery(newQuery)\n }\n }\n\n // Fetch spelling suggestions for the search terms\n const { data: suggestionData } = useSuggestion(\n { searchTerm: query?.queryTerm },\n\n {\n enabled: !!query?.queryTerm?.[0],\n },\n )\n\n const suggestion = useMemo(() => {\n const suggestionValues = suggestionData?.suggestions\n const terms = query?.queryTerm || []\n\n if (!suggestionValues) return null\n\n // Map original terms to their best suggestions if available\n const suggestionMap = new Map<string, string>()\n let hasSuggestion = false\n\n for (const suggestionList of suggestionValues) {\n const originalTerm = suggestionList.key\n const suggestions = Array.from(suggestionList.values ?? [])\n\n // Among suggestions above the score threshold, pick the highest-frequency term.\n const bestSuggestion = suggestions.reduce<Suggestion | null>(\n (best, current) => {\n if (\n current.score === undefined ||\n current.score < MIN_SUGGESTION_SCORE\n ) {\n return best\n }\n if (!best || (current.frequency ?? 0) > (best.frequency ?? 0)) {\n return current\n }\n return best\n },\n null,\n )\n\n // If a valid suggestion is found and it's different from the original term, add it to the map\n if (bestSuggestion?.term && bestSuggestion.term !== originalTerm) {\n suggestionMap.set(originalTerm!, bestSuggestion.term)\n hasSuggestion = true\n }\n }\n\n if (!hasSuggestion) return null\n\n // Build the corrected search string by replacing misspelled terms\n // Use toLowerCase() because the suggestion API returns keys in lowercase\n const correctedTerms = terms.map(\n term => suggestionMap.get(term.toLowerCase()) || term,\n )\n\n return correctedTerms.join(' ')\n }, [suggestionData, query?.queryTerm])\n\n // Extract entity IDs from search results for relevant portal banner display\n const entityIdsForPortalBanners = useMemo(() => {\n if (!data?.pages || data.pages.length === 0) {\n return []\n }\n\n const entityIds = new Set<string>()\n\n const firstPage = data.pages[0]\n\n if (firstPage?.hits) {\n for (const hit of firstPage.hits) {\n // search result is the top-level Project itself\n if (hit.id) {\n entityIds.add(hit.id)\n }\n\n if (hit.path?.path) {\n for (const pathEntity of hit.path.path.slice(1)) {\n if (pathEntity.id) {\n entityIds.add(pathEntity.id)\n }\n }\n }\n }\n }\n\n const finalIds = Array.from(entityIds)\n\n return finalIds\n }, [data])\n\n const handleUseSuggestion = () => {\n if (setQuery && suggestion) {\n const newQuery = {\n ...DEFAULT_SEARCH_QUERY,\n ...query,\n queryTerm: suggestion\n .split(' ')\n .map(term => term.trim())\n .filter(Boolean),\n start: 0,\n }\n setQuery(newQuery)\n }\n }\n\n const noResults = data?.pages?.[0]?.hits?.length === 0\n const isSynId = SYNAPSE_ENTITY_ID_REGEX.test(query?.queryTerm?.[0] || '')\n\n // cached facets in local state to prevent them from being cleared when the query changes and new search results are loading\n const [facets, setFacets] = useState<Facet[]>([])\n\n useEffect(() => {\n const newFacets = data?.pages?.[0]?.facets\n if (newFacets) {\n setFacets(newFacets)\n }\n }, [data])\n\n const handleAddFacet = useCallback(\n (facetName: string, facetValue: string) => {\n if (setQuery && query) {\n setQuery(addFacetToQuery(query, facetName, facetValue))\n }\n },\n [query, setQuery],\n )\n\n const handleRemoveFacet = useCallback(\n (facetName: string, facetValue: string) => {\n if (setQuery && query) {\n setQuery(removeFacetFromQuery(query, facetName, facetValue))\n }\n },\n [query, setQuery],\n )\n\n const handleSetRangeFacet = useCallback(\n (facetName: string, minValue: string) => {\n if (setQuery && query) {\n setQuery(setRangeFacetInQuery(query, facetName, minValue))\n }\n },\n [query, setQuery],\n )\n\n const handleRemoveRangeFacet = useCallback(\n (facetName: string) => {\n if (setQuery && query) {\n setQuery(removeRangeFacetFromQuery(query, facetName))\n }\n },\n [query, setQuery],\n )\n\n const isRangeFacetAppliedCallback = useCallback(\n (name: string) => (query ? isRangeFacetApplied(query, name) : false),\n [query],\n )\n\n const getAppliedRangeFacetCallback = useCallback(\n (name: string) => (query ? getAppliedRangeFacet(query, name) : undefined),\n [query],\n )\n\n const appliedFacetsCount =\n (query?.booleanQuery?.filter(kv => shouldShowFacetValue(kv.key, kv.value))\n .length || 0) + (query?.rangeQuery?.length || 0)\n\n return (\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'column',\n width: '100%',\n p: '30px',\n gap: '20px',\n }}\n >\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'column',\n height: 'auto',\n gap: '16px',\n }}\n >\n {peopleSearchPageUrl && (\n <Typography variant=\"smallText1\">\n Searching for a user profile? Try our{' '}\n <Link href={peopleSearchPageUrl}>People Search.</Link>\n </Typography>\n )}\n <Box className={styles.searchContainer}>\n <TextField\n placeholder=\"Search…\"\n sx={{ flex: 1 }}\n value={searchInputValue}\n onChange={handleInputChange}\n onKeyDown={e => {\n if (e.key === 'Enter') {\n handleSearch()\n }\n }}\n slotProps={{\n input: {\n sx: {\n borderRadius: '96px',\n boxShadow: '0px 1px 4px var(--synapse-gray-500)',\n backgroundColor: 'var(--synapse-white)',\n },\n startAdornment: (\n <InputAdornment position=\"start\">\n <SearchIcon sx={{ color: 'secondary.600' }} />\n </InputAdornment>\n ),\n },\n }}\n />\n <Button\n onClick={() => setExpanded(true)}\n variant=\"outlined\"\n startIcon={<FilterAltOutlinedIcon />}\n aria-expanded={expanded}\n aria-controls=\"filter-search-results-panel\"\n sx={{\n color: theme => theme.palette.primary.dark,\n }}\n className={styles.filterButton}\n >\n <Typography\n sx={{\n fontWeight: 700,\n lineHeight: '16px',\n display: 'flex',\n gap: '8px',\n }}\n >\n <span id=\"filter-results-button-label\">\n Filter Search Results\n </span>\n {appliedFacetsCount > 0 && (\n <Badge\n badgeContent={appliedFacetsCount}\n color=\"primary\"\n sx={{\n '& .MuiBadge-badge': {\n position: 'static',\n transform: 'none',\n height: '18px',\n minWidth: '18px',\n },\n }}\n />\n )}\n </Typography>\n </Button>\n </Box>\n <Box>\n {facets.length > 0 && (\n <Collapse\n in={expanded}\n id=\"filter-search-results-panel\"\n aria-labelledby=\"filter-results-button-label\"\n >\n <Box\n sx={{\n border: '1px solid',\n borderColor: 'var(--synapse-gray-100)',\n backgroundColor: 'var(--synapse-white)',\n padding: '25px',\n boxShadow: '0 4px 16px 0 rgba(0, 0, 0, 0.04)',\n pointerEvents: isLoading ? 'none' : 'auto',\n opacity: isLoading ? 0.5 : 1,\n }}\n >\n {query && setQuery && (\n <SearchFacetPanel\n expanded={expanded}\n onCollapse={() => setExpanded(false)}\n disabled={isLoading}\n query={query}\n setQuery={setQuery}\n facets={facets}\n onAddFacet={handleAddFacet}\n onRemoveFacet={handleRemoveFacet}\n onSetRangeFacet={handleSetRangeFacet}\n onRemoveRangeFacet={handleRemoveRangeFacet}\n isRangeFacetApplied={isRangeFacetAppliedCallback}\n getAppliedRangeFacet={getAppliedRangeFacetCallback}\n />\n )}\n </Box>\n </Collapse>\n )}\n </Box>\n </Box>\n <>\n {data && !isSynId && suggestion && (\n <div className={styles.didYouMeanContainer}>\n <div className={styles.didYouMeanCurrentlyShowing}>\n {!noResults && (\n <>\n Currently showing results for{' '}\n <b>{query?.queryTerm?.join(' ')}</b>.\n </>\n )}\n </div>\n <div className={styles.didYouMeanSuggestion}>\n <SearchIcon\n sx={{ color: 'grey.600' }}\n className={styles.searchIcon}\n />\n <Typography variant=\"body1\" className={styles.didYouMeanText}>\n Search for <b className={styles.suggestionText}>{suggestion}</b>{' '}\n instead?\n </Typography>\n <IconButton\n className={styles.didYouMeanArrowContainer}\n onClick={handleUseSuggestion}\n aria-label={`Search for ${suggestion} instead`}\n sx={{\n borderColor: 'primary.main',\n svg: { color: 'primary.main' },\n }}\n >\n <ArrowForward />\n </IconButton>\n </div>\n </div>\n )}\n {noResults && (\n <div className={styles.didYouMeanCurrentlyShowing}>\n No results found for <b>{query?.queryTerm?.join(' ')}</b>.\n </div>\n )}\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'flex-end',\n gap: '20px',\n }}\n >\n {isLoading &&\n Array.from({ length: 3 }, () => (\n <Skeleton variant=\"rectangular\" width={'100%'} height={'250px'} />\n ))}\n {error && <div>Error: {error.message}</div>}\n <Suspense\n fallback={<SkeletonInlineBlock width={'100%'} height={'150px'} />}\n >\n <SearchPagePortalBanners entityIds={entityIdsForPortalBanners} />\n </Suspense>\n {query && (\n <Box sx={{ alignSelf: 'flex-start' }}>\n <AppliedFacetsChips\n query={query}\n onRemoveFacet={handleRemoveFacet}\n onRemoveRangeFacet={handleRemoveRangeFacet}\n />\n </Box>\n )}\n {data &&\n data.pages &&\n data.pages.map((page, pageIndex) =>\n page.hits.map((hit: Hit) => {\n const projectPath = hit.path?.path?.[1]\n return (\n <SynapseSearchResultsCard\n searchTerms={query?.queryTerm ?? []}\n key={hit.id + '-' + pageIndex}\n entityId={hit.id}\n name={hit.name}\n entityType={hit.node_type}\n modifiedOn={hit.modified_on}\n description={hit.description}\n locatedIn={projectPath}\n />\n )\n }),\n )}\n {hasNextPage && (\n <Button\n onClick={() => {\n void fetchNextPage()\n }}\n loading={isFetchingNextPage}\n variant=\"contained\"\n sx={{ mt: 2 }}\n >\n {isFetchingNextPage ? 'Loading more...' : 'Load More'}\n </Button>\n )}\n </Box>\n </>\n </Box>\n )\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"EntityIDColumnCopyIcon.js","names":[],"sources":["../../../src/components/SynapseTable/EntityIDColumnCopyIcon.tsx"],"sourcesContent":["import React from 'react'\nimport { getFullQueryTableResults } from '@/synapse-client/SynapseClient'\nimport { SynapseConstants } from '@/utils'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport { parseEntityIdAndVersionFromSqlStatement } from '@/utils/functions/SqlFunctions'\nimport { QueryResultBundle, Row } from '@sage-bionetworks/synapse-types'\nimport { useEffect, useMemo, useState } from 'react'\nimport {\n InteractiveCopyIdsIcon,\n InteractiveCopyIdsIconProps,\n} from '../InteractiveCopyIdsIcon'\nimport { SynapseSpinner } from '../LoadingScreen/LoadingScreen'\nimport { useQueryContext } from '../QueryContext/QueryContext'\nimport { displayToast } from '../ToastMessage/ToastMessage'\nimport { copyStringToClipboard } from '@/utils/functions/StringUtils'\n\ntype EntityIDColumnCopyIconProps = Omit<InteractiveCopyIdsIconProps, 'onCopy'>\n\nconst EntityIDColumnCopyIcon = (\n props: EntityIDColumnCopyIconProps,\n): React.ReactNode => {\n const synapseContext = useSynapseContext()\n const { getCurrentQueryRequest } = useQueryContext()\n const queryRequestClone = useMemo(\n () => getCurrentQueryRequest(),\n [getCurrentQueryRequest],\n )\n const [isLoading, setIsLoading] = useState(false)\n const [idData, setIdData] = useState<QueryResultBundle>()\n const [abortController, setAbortController] = useState<AbortController>()\n\n useEffect(() => {\n if (!abortController) {\n setAbortController(new AbortController())\n }\n return () => {\n // clean up\n if (abortController) {\n abortController.abort()\n }\n }\n }, [abortController])\n /**\n * handle copy IDs to clipboard\n */\n const handleCopyIdsToClipboard = () => {\n setIsLoading(true)\n\n // ask for all pages of data\n const { sql: oldSql } = queryRequestClone.query\n const { entityId, versionNumber } =\n parseEntityIdAndVersionFromSqlStatement(oldSql)\n const versionNumberString = versionNumber ? `.${versionNumber}` : ''\n queryRequestClone.partMask = SynapseConstants.BUNDLE_MASK_QUERY_RESULTS\n const entityIdString = `${entityId}${versionNumberString}`\n const indexOfEntityId = oldSql.indexOf(entityIdString)\n queryRequestClone.query.sql = `select id from ${entityIdString}${oldSql.substring(\n indexOfEntityId + entityIdString.length,\n )}`\n getFullQueryTableResults(\n queryRequestClone,\n synapseContext.accessToken,\n abortController?.signal,\n )\n .then((data: QueryResultBundle) => {\n setIdData(data)\n })\n .catch((err: any) => {\n console.error(err)\n displayToast('Unable to query for all Synapse IDs to copy', 'danger')\n })\n .finally(() => {\n setIsLoading(false)\n })\n }\n\n useEffect(() => {\n if (idData) {\n const { rows } = idData.queryResult!.queryResults\n const synIDs = rows\n .map((row: Row) => {\n return `${row.values[0]}`\n })\n .join('\\n')\n copyStringToClipboard(synIDs).then(() => {\n displayToast('Successfully copied to clipboard')\n setIdData(undefined)\n })\n }\n }, [idData])\n\n return isLoading ? (\n <SynapseSpinner size={25} />\n ) : (\n <InteractiveCopyIdsIcon\n {...props}\n onCopy={() => {\n handleCopyIdsToClipboard()\n }}\n />\n )\n}\n\nexport default EntityIDColumnCopyIcon\n"],"mappings":";;;;;;;;;;;;;AAkBA,IAAM,KACJ,MACoB;CACpB,IAAM,IAAiB,GAAmB,EACpC,EAAE,8BAA2B,GAAiB,EAC9C,IAAoB,QAClB,GAAwB,EAC9B,CAAC,EAAuB,CACzB,EACK,CAAC,GAAW,KAAgB,EAAS,GAAM,EAC3C,CAAC,GAAQ,KAAa,GAA6B,EACnD,CAAC,GAAiB,KAAsB,GAA2B;AAEzE,UACO,KACH,EAAmB,IAAI,iBAAiB,CAAC,QAE9B;AAEX,EAAI,KACF,EAAgB,OAAO;KAG1B,CAAC,EAAgB,CAAC;CAIrB,IAAM,UAAiC;AACrC,IAAa,GAAK;EAGlB,IAAM,EAAE,KAAK,MAAW,EAAkB,OACpC,EAAE,aAAU,qBAChB,EAAwC,EAAO,EAC3C,IAAsB,IAAgB,IAAI,MAAkB;AAClE,IAAkB,WAAW;EAC7B,IAAM,IAAiB,GAAG,IAAW,KAC/B,IAAkB,EAAO,QAAQ,EAAe;AAItD,EAHA,EAAkB,MAAM,MAAM,kBAAkB,IAAiB,EAAO,UACtE,IAAkB,EAAe,OAClC,IACD,EACE,GACA,EAAe,aACf,GAAiB,OAClB,CACE,MAAM,MAA4B;AACjC,KAAU,EAAK;IACf,CACD,OAAO,MAAa;AAEnB,GADA,QAAQ,MAAM,EAAI,EAClB,EAAa,+CAA+C,SAAS;IACrE,CACD,cAAc;AACb,KAAa,GAAM;IACnB;;AAkBN,QAfA,QAAgB;AACd,MAAI,GAAQ;GACV,IAAM,EAAE,YAAS,EAAO,YAAa;AAMrC,KALe,EACZ,KAAK,MACG,GAAG,EAAI,OAAO,KACrB,CACD,KAAK,KAAK,CACgB,CAAC,WAAW;AAEvC,IADA,EAAa,mCAAmC,EAChD,EAAU,KAAA,EAAU;KACpB;;IAEH,CAAC,EAAO,CAAC,EAEL,IACL,kBAAC,GAAD,EAAgB,MAAM,IAAM,CAAA,GAE5B,kBAAC,GAAD;EACE,GAAI;EACJ,cAAc;AACZ,MAA0B;;EAE5B,CAAA"}
1
+ {"version":3,"file":"EntityIDColumnCopyIcon.js","names":[],"sources":["../../../src/components/SynapseTable/EntityIDColumnCopyIcon.tsx"],"sourcesContent":["import React from 'react'\nimport { getFullQueryTableResults } from '@/synapse-client/SynapseClient'\nimport { SynapseConstants } from '@/utils'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport { parseEntityIdAndVersionFromSqlStatement } from '@/utils/functions/SqlFunctions'\nimport { QueryResultBundle, Row } from '@sage-bionetworks/synapse-types'\nimport { useEffect, useMemo, useState } from 'react'\nimport {\n InteractiveCopyIdsIcon,\n InteractiveCopyIdsIconProps,\n} from '../InteractiveCopyIdsIcon'\nimport { SynapseSpinner } from '../LoadingScreen/LoadingScreen'\nimport { useQueryContext } from '../QueryContext/QueryContext'\nimport { displayToast } from '../ToastMessage/ToastMessage'\nimport { copyStringToClipboard } from '@/utils/functions/StringUtils'\n\ntype EntityIDColumnCopyIconProps = Omit<InteractiveCopyIdsIconProps, 'onCopy'>\n\nconst EntityIDColumnCopyIcon = (\n props: EntityIDColumnCopyIconProps,\n): React.ReactNode => {\n const synapseContext = useSynapseContext()\n const { getCurrentQueryRequest } = useQueryContext()\n const queryRequestClone = useMemo(\n () => getCurrentQueryRequest(),\n [getCurrentQueryRequest],\n )\n const [isLoading, setIsLoading] = useState(false)\n const [idData, setIdData] = useState<QueryResultBundle>()\n const [abortController, setAbortController] = useState<AbortController>()\n\n useEffect(() => {\n if (!abortController) {\n setAbortController(new AbortController())\n }\n return () => {\n // clean up\n if (abortController) {\n abortController.abort()\n }\n }\n }, [abortController])\n /**\n * handle copy IDs to clipboard\n */\n const handleCopyIdsToClipboard = () => {\n setIsLoading(true)\n\n // ask for all pages of data\n const { sql: oldSql } = queryRequestClone.query\n const { entityId, versionNumber } =\n parseEntityIdAndVersionFromSqlStatement(oldSql)\n const versionNumberString = versionNumber ? `.${versionNumber}` : ''\n queryRequestClone.partMask = SynapseConstants.BUNDLE_MASK_QUERY_RESULTS\n const entityIdString = `${entityId}${versionNumberString}`\n const indexOfEntityId = oldSql.indexOf(entityIdString)\n queryRequestClone.query.sql = `select id from ${entityIdString}${oldSql.substring(\n indexOfEntityId + entityIdString.length,\n )}`\n getFullQueryTableResults(\n queryRequestClone,\n synapseContext.accessToken,\n abortController?.signal,\n )\n .then((data: QueryResultBundle) => {\n setIdData(data)\n })\n .catch((err: any) => {\n console.error(err)\n displayToast('Unable to query for all Synapse IDs to copy', 'danger')\n })\n .finally(() => {\n setIsLoading(false)\n })\n }\n\n useEffect(() => {\n if (idData) {\n const { rows } = idData.queryResult!.queryResults\n const synIDs = rows\n .map((row: Row) => {\n return `${row.values[0]}`\n })\n .join('\\n')\n copyStringToClipboard(synIDs).then(() => {\n displayToast('Successfully copied to clipboard')\n setIdData(undefined)\n })\n }\n }, [idData])\n\n return isLoading ? (\n <SynapseSpinner size={25} />\n ) : (\n <InteractiveCopyIdsIcon\n {...props}\n onCopy={() => {\n handleCopyIdsToClipboard()\n }}\n />\n )\n}\n\nexport default EntityIDColumnCopyIcon\n"],"mappings":";;;;;;;;;;;;;AAkBA,IAAM,KACJ,MACoB;CACpB,IAAM,IAAiB,GAAmB,EACpC,EAAE,8BAA2B,GAAiB,EAC9C,IAAoB,QAClB,GAAwB,EAC9B,CAAC,EAAuB,CACzB,EACK,CAAC,GAAW,KAAgB,EAAS,GAAM,EAC3C,CAAC,GAAQ,KAAa,GAA6B,EACnD,CAAC,GAAiB,KAAsB,GAA2B;AAEzE,UACO,KACH,EAAmB,IAAI,iBAAiB,CAAC,QAE9B;AAEX,EAAI,KACF,EAAgB,OAAO;KAG1B,CAAC,EAAgB,CAAC;CAIrB,IAAM,UAAiC;AACrC,IAAa,GAAK;EAGlB,IAAM,EAAE,KAAK,MAAW,EAAkB,OACpC,EAAE,aAAU,qBAChB,EAAwC,EAAO,EAC3C,IAAsB,IAAgB,IAAI,MAAkB;AAClE,IAAkB,WAAW;EAC7B,IAAM,IAAiB,GAAG,IAAW,KAC/B,IAAkB,EAAO,QAAQ,EAAe;AAItD,EAHA,EAAkB,MAAM,MAAM,kBAAkB,IAAiB,EAAO,UACtE,IAAkB,EAAe,OAClC,IACD,EACE,GACA,EAAe,aACf,GAAiB,OAClB,CACE,MAAM,MAA4B;AACjC,KAAU,EAAK;IACf,CACD,OAAO,MAAa;AAEnB,GADA,QAAQ,MAAM,EAAI,EAClB,EAAa,+CAA+C,SAAS;IACrE,CACD,cAAc;AACb,KAAa,GAAM;IACnB;;AAkBN,QAfA,QAAgB;AACd,MAAI,GAAQ;GACV,IAAM,EAAE,YAAS,EAAO,YAAa;AAMrC,KALe,EACZ,KAAK,MACG,GAAG,EAAI,OAAO,KACrB,CACD,KAAK,KACc,CAAO,CAAC,WAAW;AAEvC,IADA,EAAa,mCAAmC,EAChD,EAAU,KAAA,EAAU;KACpB;;IAEH,CAAC,EAAO,CAAC,EAEL,IACL,kBAAC,GAAD,EAAgB,MAAM,IAAM,CAAA,GAE5B,kBAAC,GAAD;EACE,GAAI;EACJ,cAAc;AACZ,MAA0B;;EAE5B,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"NoContentPlaceholderType.js","names":[],"sources":["../../../src/components/SynapseTable/NoContentPlaceholderType.ts"],"sourcesContent":["/**\n * When displaying that there are no results, there are two scenarios:\n * 1. Interactive - the user can modify the query and may have chosen a query with no results\n * - If the user has not modified the query, show a message that the table is empty\n * - If the user has modified the query, show a message that there are no results and to try a different input\n * 2. Static - the user cannot modify the query. Show a message that there is no content available.\n * 3. Hidden - No content is shown if the user does not have access to the results\n */\nexport enum NoContentPlaceholderType {\n INTERACTIVE = 'INTERACTIVE',\n STATIC = 'STATIC',\n HIDDEN = 'HIDDEN',\n}\n"],"mappings":";AAQA,IAAY,IAAL,yBAAA,GAAA;QACL,EAAA,cAAA,eACA,EAAA,SAAA,UACA,EAAA,SAAA;KACD"}
1
+ {"version":3,"file":"NoContentPlaceholderType.js","names":[],"sources":["../../../src/components/SynapseTable/NoContentPlaceholderType.ts"],"sourcesContent":["/**\n * When displaying that there are no results, there are two scenarios:\n * 1. Interactive - the user can modify the query and may have chosen a query with no results\n * - If the user has not modified the query, show a message that the table is empty\n * - If the user has modified the query, show a message that there are no results and to try a different input\n * 2. Static - the user cannot modify the query. Show a message that there is no content available.\n * 3. Hidden - No content is shown if the user does not have access to the results\n */\nexport enum NoContentPlaceholderType {\n INTERACTIVE = 'INTERACTIVE',\n STATIC = 'STATIC',\n HIDDEN = 'HIDDEN',\n}\n"],"mappings":";AAQA,IAAY,IAAL,yBAAA,GAAA;QACL,EAAA,cAAc,eACd,EAAA,SAAS,UACT,EAAA,SAAS;KACV"}
@@ -1 +1 @@
1
- {"version":3,"file":"RowSelectionControls.js","names":[],"sources":["../../../../src/components/SynapseTable/RowSelection/RowSelectionControls.tsx"],"sourcesContent":["import AddToDownloadListConfirmationAlert from '@/components/download_list/AddToDownloadListConfirmationAlert/AddToDownloadListConfirmationAlert'\nimport { useGetAddToDownloadListRequestForCurrentQuery } from '@/components/QueryWrapper/useGetAddToDownloadListRequestForCurrentQuery'\nimport { useGetEntity } from '@/synapse-queries'\nimport { canTableQueryBeAddedToDownloadList } from '@/utils/functions/queryUtils'\nimport { GetAppTwoTone } from '@mui/icons-material'\nimport { Box, Button } from '@mui/material'\nimport { Table } from '@sage-bionetworks/synapse-types'\nimport { useAtom } from 'jotai'\nimport { useState } from 'react'\nimport { toast } from 'react-hot-toast'\nimport { useSynapseContext } from '@/utils'\nimport { useQueryContext } from '../../QueryContext'\nimport { useQueryVisualizationContext } from '../../QueryVisualizationWrapper'\nimport { selectedRowsAtom } from '../../QueryWrapper/TableRowSelectionState'\nimport { useGetQueryMetadata } from '../../QueryWrapper/useGetQueryMetadata'\nimport {\n getFileColumnModelId,\n SEND_TO_ANALYSIS_PLATFORM_SIGN_IN_MESSAGE,\n} from '../SynapseTableUtils'\nimport { CustomControlButton } from '../CustomControls/CustomControlButton'\nimport { CustomControl } from '../TopLevelControls/TopLevelControls'\nimport { RowSelectionUI } from './RowSelectionUI'\nimport { SignInRequiredModal } from '@/components/SignInRequiredModal/SignInRequiredModal'\n\nconst SEND_TO_ANALYSIS_PLATFORM_BUTTON_ID =\n 'SendToAnalysisPlatformRowSelectionControlButton'\n\nexport type RowSelectionControlsProps = {\n customControls?: CustomControl[]\n remount?: () => void\n}\n\n/**\n * This component is responsible for rendering the RowSelectionUI and the custom controls. Must be wrapped in a\n * QueryContext and a QueryVisualizationContext.\n * @param props\n * @constructor\n */\nexport function RowSelectionControls(props: RowSelectionControlsProps) {\n const { customControls = [], remount } = props\n const { isAuthenticated } = useSynapseContext()\n const [showLoginModal, setShowLoginModal] = useState(false)\n const { entityId, versionNumber, getCurrentQueryRequest } = useQueryContext()\n const { data: entity } = useGetEntity<Table>(entityId, versionNumber)\n const { data: queryMetadata } = useGetQueryMetadata()\n const [selectedRows, setSelectedRows] = useAtom(selectedRowsAtom)\n\n const addToDownloadListRequest =\n useGetAddToDownloadListRequestForCurrentQuery()\n\n const {\n setIsShowingExportToAnalysisPlatformModal,\n enabledExternalAnalysisPlatforms,\n } = useQueryVisualizationContext()\n\n const showExportToAnalysisPlatformButton =\n enabledExternalAnalysisPlatforms.length > 0\n\n const refresh = () => {\n // clear selection\n setSelectedRows([])\n if (remount) {\n remount()\n }\n }\n const fileColumnId = getFileColumnModelId(queryMetadata?.columnModels)\n const showAddToDownloadCart = canTableQueryBeAddedToDownloadList(\n entity,\n fileColumnId,\n )\n\n return (\n <RowSelectionUI\n show={selectedRows.length > 0}\n selectedRowCount={selectedRows.length}\n onClearSelection={() => setSelectedRows([])}\n customControls={\n <>\n {customControls.map(customControl => {\n return (\n <CustomControlButton\n key={customControl.buttonText}\n variant=\"contained\"\n callbackData={{\n tableId: entityId!,\n queryMetadata: queryMetadata,\n selectedRows,\n refresh,\n request: getCurrentQueryRequest(),\n }}\n control={customControl}\n startIcon={customControl.icon}\n />\n )\n })}\n {/* TODO: Generic button */}\n {showExportToAnalysisPlatformButton && (\n <Button\n variant=\"outlined\"\n onClick={() => {\n if (isAuthenticated) {\n setIsShowingExportToAnalysisPlatformModal(true)\n } else {\n setShowLoginModal(true)\n }\n }}\n id={SEND_TO_ANALYSIS_PLATFORM_BUTTON_ID}\n >\n Send to Analysis Platform\n </Button>\n )}\n {showLoginModal && (\n <SignInRequiredModal\n onHide={() => setShowLoginModal(false)}\n content={SEND_TO_ANALYSIS_PLATFORM_SIGN_IN_MESSAGE}\n />\n )}\n {showAddToDownloadCart && (\n <Button\n variant=\"contained\"\n onClick={() => {\n const toastId = toast.custom(\n <Box\n sx={{\n width: '100%',\n }}\n >\n <AddToDownloadListConfirmationAlert\n addToDownloadListRequest={addToDownloadListRequest}\n onClose={() => {\n toast.dismiss(toastId)\n }}\n />\n </Box>,\n {\n duration: Infinity,\n },\n )\n }}\n startIcon={<GetAppTwoTone />}\n >\n Add to Download List\n </Button>\n )}\n </>\n }\n />\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAwBA,IAAM,IACJ;AAaF,SAAgB,EAAqB,GAAkC;CACrE,IAAM,EAAE,oBAAiB,EAAE,EAAE,eAAY,GACnC,EAAE,uBAAoB,GAAmB,EACzC,CAAC,GAAgB,KAAqB,EAAS,GAAM,EACrD,EAAE,aAAU,kBAAe,8BAA2B,GAAiB,EACvE,EAAE,MAAM,MAAW,EAAoB,GAAU,EAAc,EAC/D,EAAE,MAAM,MAAkB,GAAqB,EAC/C,CAAC,GAAc,KAAmB,EAAQ,EAAiB,EAE3D,IACJ,GAA+C,EAE3C,EACJ,8CACA,wCACE,GAA8B,EAE5B,IACJ,EAAiC,SAAS,GAEtC,UAAgB;AAGpB,EADA,EAAgB,EAAE,CAAC,EACf,KACF,GAAS;IAIP,IAAwB,EAC5B,GAFmB,EAAqB,GAAe,aAAa,CAIrE;AAED,QACE,kBAAC,GAAD;EACE,MAAM,EAAa,SAAS;EAC5B,kBAAkB,EAAa;EAC/B,wBAAwB,EAAgB,EAAE,CAAC;EAC3C,gBACE,kBAAA,GAAA,EAAA,UAAA;GACG,EAAe,KAAI,MAEhB,kBAAC,GAAD;IAEE,SAAQ;IACR,cAAc;KACZ,SAAS;KACM;KACf;KACA;KACA,SAAS,GAAwB;KAClC;IACD,SAAS;IACT,WAAW,EAAc;IACzB,EAXK,EAAc,WAWnB,CAEJ;GAED,KACC,kBAAC,GAAD;IACE,SAAQ;IACR,eAAe;AACb,KAAI,IACF,EAA0C,GAAK,GAE/C,EAAkB,GAAK;;IAG3B,IAAI;cACL;IAEQ,CAAA;GAEV,KACC,kBAAC,GAAD;IACE,cAAc,EAAkB,GAAM;IACtC,SAAA;IACA,CAAA;GAEH,KACC,kBAAC,GAAD;IACE,SAAQ;IACR,eAAe;KACb,IAAM,IAAU,EAAM,OACpB,kBAAC,GAAD;MACE,IAAI,EACF,OAAO,QACR;gBAED,kBAAC,GAAD;OAC4B;OAC1B,eAAe;AACb,UAAM,QAAQ,EAAQ;;OAExB,CAAA;MACE,CAAA,EACN,EACE,UAAU,UACX,CACF;;IAEH,WAAW,kBAAC,GAAD,EAAiB,CAAA;cAC7B;IAEQ,CAAA;GAEV,EAAA,CAAA;EAEL,CAAA"}
1
+ {"version":3,"file":"RowSelectionControls.js","names":[],"sources":["../../../../src/components/SynapseTable/RowSelection/RowSelectionControls.tsx"],"sourcesContent":["import AddToDownloadListConfirmationAlert from '@/components/download_list/AddToDownloadListConfirmationAlert/AddToDownloadListConfirmationAlert'\nimport { useGetAddToDownloadListRequestForCurrentQuery } from '@/components/QueryWrapper/useGetAddToDownloadListRequestForCurrentQuery'\nimport { useGetEntity } from '@/synapse-queries'\nimport { canTableQueryBeAddedToDownloadList } from '@/utils/functions/queryUtils'\nimport { GetAppTwoTone } from '@mui/icons-material'\nimport { Box, Button } from '@mui/material'\nimport { Table } from '@sage-bionetworks/synapse-types'\nimport { useAtom } from 'jotai'\nimport { useState } from 'react'\nimport { toast } from 'react-hot-toast'\nimport { useSynapseContext } from '@/utils'\nimport { useQueryContext } from '../../QueryContext'\nimport { useQueryVisualizationContext } from '../../QueryVisualizationWrapper'\nimport { selectedRowsAtom } from '../../QueryWrapper/TableRowSelectionState'\nimport { useGetQueryMetadata } from '../../QueryWrapper/useGetQueryMetadata'\nimport {\n getFileColumnModelId,\n SEND_TO_ANALYSIS_PLATFORM_SIGN_IN_MESSAGE,\n} from '../SynapseTableUtils'\nimport { CustomControlButton } from '../CustomControls/CustomControlButton'\nimport { CustomControl } from '../TopLevelControls/TopLevelControls'\nimport { RowSelectionUI } from './RowSelectionUI'\nimport { SignInRequiredModal } from '@/components/SignInRequiredModal/SignInRequiredModal'\n\nconst SEND_TO_ANALYSIS_PLATFORM_BUTTON_ID =\n 'SendToAnalysisPlatformRowSelectionControlButton'\n\nexport type RowSelectionControlsProps = {\n customControls?: CustomControl[]\n remount?: () => void\n}\n\n/**\n * This component is responsible for rendering the RowSelectionUI and the custom controls. Must be wrapped in a\n * QueryContext and a QueryVisualizationContext.\n * @param props\n * @constructor\n */\nexport function RowSelectionControls(props: RowSelectionControlsProps) {\n const { customControls = [], remount } = props\n const { isAuthenticated } = useSynapseContext()\n const [showLoginModal, setShowLoginModal] = useState(false)\n const { entityId, versionNumber, getCurrentQueryRequest } = useQueryContext()\n const { data: entity } = useGetEntity<Table>(entityId, versionNumber)\n const { data: queryMetadata } = useGetQueryMetadata()\n const [selectedRows, setSelectedRows] = useAtom(selectedRowsAtom)\n\n const addToDownloadListRequest =\n useGetAddToDownloadListRequestForCurrentQuery()\n\n const {\n setIsShowingExportToAnalysisPlatformModal,\n enabledExternalAnalysisPlatforms,\n } = useQueryVisualizationContext()\n\n const showExportToAnalysisPlatformButton =\n enabledExternalAnalysisPlatforms.length > 0\n\n const refresh = () => {\n // clear selection\n setSelectedRows([])\n if (remount) {\n remount()\n }\n }\n const fileColumnId = getFileColumnModelId(queryMetadata?.columnModels)\n const showAddToDownloadCart = canTableQueryBeAddedToDownloadList(\n entity,\n fileColumnId,\n )\n\n return (\n <RowSelectionUI\n show={selectedRows.length > 0}\n selectedRowCount={selectedRows.length}\n onClearSelection={() => setSelectedRows([])}\n customControls={\n <>\n {customControls.map(customControl => {\n return (\n <CustomControlButton\n key={customControl.buttonText}\n variant=\"contained\"\n callbackData={{\n tableId: entityId!,\n queryMetadata: queryMetadata,\n selectedRows,\n refresh,\n request: getCurrentQueryRequest(),\n }}\n control={customControl}\n startIcon={customControl.icon}\n />\n )\n })}\n {/* TODO: Generic button */}\n {showExportToAnalysisPlatformButton && (\n <Button\n variant=\"outlined\"\n onClick={() => {\n if (isAuthenticated) {\n setIsShowingExportToAnalysisPlatformModal(true)\n } else {\n setShowLoginModal(true)\n }\n }}\n id={SEND_TO_ANALYSIS_PLATFORM_BUTTON_ID}\n >\n Send to Analysis Platform\n </Button>\n )}\n {showLoginModal && (\n <SignInRequiredModal\n onHide={() => setShowLoginModal(false)}\n content={SEND_TO_ANALYSIS_PLATFORM_SIGN_IN_MESSAGE}\n />\n )}\n {showAddToDownloadCart && (\n <Button\n variant=\"contained\"\n onClick={() => {\n const toastId = toast.custom(\n <Box\n sx={{\n width: '100%',\n }}\n >\n <AddToDownloadListConfirmationAlert\n addToDownloadListRequest={addToDownloadListRequest}\n onClose={() => {\n toast.dismiss(toastId)\n }}\n />\n </Box>,\n {\n duration: Infinity,\n },\n )\n }}\n startIcon={<GetAppTwoTone />}\n >\n Add to Download List\n </Button>\n )}\n </>\n }\n />\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAwBA,IAAM,IACJ;AAaF,SAAgB,EAAqB,GAAkC;CACrE,IAAM,EAAE,oBAAiB,EAAE,EAAE,eAAY,GACnC,EAAE,uBAAoB,GAAmB,EACzC,CAAC,GAAgB,KAAqB,EAAS,GAAM,EACrD,EAAE,aAAU,kBAAe,8BAA2B,GAAiB,EACvE,EAAE,MAAM,MAAW,EAAoB,GAAU,EAAc,EAC/D,EAAE,MAAM,MAAkB,GAAqB,EAC/C,CAAC,GAAc,KAAmB,EAAQ,EAAiB,EAE3D,IACJ,GAA+C,EAE3C,EACJ,8CACA,wCACE,GAA8B,EAE5B,IACJ,EAAiC,SAAS,GAEtC,UAAgB;AAGpB,EADA,EAAgB,EAAE,CAAC,EACf,KACF,GAAS;IAIP,IAAwB,EAC5B,GAFmB,EAAqB,GAAe,aAGvD,CACD;AAED,QACE,kBAAC,GAAD;EACE,MAAM,EAAa,SAAS;EAC5B,kBAAkB,EAAa;EAC/B,wBAAwB,EAAgB,EAAE,CAAC;EAC3C,gBACE,kBAAA,GAAA,EAAA,UAAA;GACG,EAAe,KAAI,MAEhB,kBAAC,GAAD;IAEE,SAAQ;IACR,cAAc;KACZ,SAAS;KACM;KACf;KACA;KACA,SAAS,GAAwB;KAClC;IACD,SAAS;IACT,WAAW,EAAc;IACzB,EAXK,EAAc,WAWnB,CAEJ;GAED,KACC,kBAAC,GAAD;IACE,SAAQ;IACR,eAAe;AACb,KAAI,IACF,EAA0C,GAAK,GAE/C,EAAkB,GAAK;;IAG3B,IAAI;cACL;IAEQ,CAAA;GAEV,KACC,kBAAC,GAAD;IACE,cAAc,EAAkB,GAAM;IACtC,SAAA;IACA,CAAA;GAEH,KACC,kBAAC,GAAD;IACE,SAAQ;IACR,eAAe;KACb,IAAM,IAAU,EAAM,OACpB,kBAAC,GAAD;MACE,IAAI,EACF,OAAO,QACR;gBAED,kBAAC,GAAD;OAC4B;OAC1B,eAAe;AACb,UAAM,QAAQ,EAAQ;;OAExB,CAAA;MACE,CAAA,EACN,EACE,UAAU,UACX,CACF;;IAEH,WAAW,kBAAC,GAAD,EAAiB,CAAA;cAC7B;IAEQ,CAAA;GAEV,EAAA,CAAA;EAEL,CAAA"}