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":"EntityHeaderTable.js","names":[],"sources":["../../../src/components/EntityHeaderTable/EntityHeaderTable.tsx"],"sourcesContent":["import React from 'react'\nimport AddAd from '@/assets/icons/AddAd'\nimport { StyledTableContainer } from '@/components/styled/StyledTableContainer'\nimport { useGetEntityHeaders } from '@/synapse-queries/entity/useGetEntityHeaders'\nimport {\n entityTypeToFriendlyName,\n getEntityTypeFromHeader,\n normalizeSynPrefix,\n} from '@/utils/functions/EntityTypeUtils'\nimport { SYNAPSE_ENTITY_ID_REGEX } from '@/utils/functions/RegularExpressions'\nimport { AddCircleTwoTone } from '@mui/icons-material'\nimport {\n Alert,\n AlertTitle,\n Box,\n Button,\n IconButton,\n InputLabel,\n TextField,\n Tooltip,\n Typography,\n} from '@mui/material'\nimport { EntityHeader, ReferenceList } from '@sage-bionetworks/synapse-types'\nimport {\n ColumnDef,\n ColumnFiltersState,\n flexRender,\n getCoreRowModel,\n getFacetedMinMaxValues,\n getFacetedRowModel,\n getFacetedUniqueValues,\n getFilteredRowModel,\n getSortedRowModel,\n useReactTable,\n} from '@tanstack/react-table'\nimport { noop, upperFirst } from 'lodash-es'\nimport papaparseLib from 'papaparse'\n// papaparse is CJS-only; pull named values from the default export.\nconst { parse } = papaparseLib\nimport pluralize from 'pluralize'\nimport { Fragment, useCallback, useEffect, useMemo, useState } from 'react'\nimport {\n EntityFinderModal,\n EntityFinderModalProps,\n} from '../EntityFinder/EntityFinderModal'\nimport { FinderScope } from '../EntityFinder/tree/EntityTree'\nimport { VersionSelectionType } from '../EntityFinder/VersionSelectionType'\nimport IconSvg from '../IconSvg'\nimport { SkeletonTable } from '../Skeleton'\nimport {\n CheckBoxCell,\n CheckBoxHeader,\n EntityHeaderIDCell,\n EntityHeaderNameCell,\n EntityHeaderTypeCell,\n} from './EntityHeaderTableCellRenderers'\nimport { Filter } from './Filter'\nimport { useEntityHeaderTableState } from './useEntityHeaderTableState'\n\nconst DEFAULT_FINDER_CONFIG: EntityFinderModalProps['configuration'] = {\n selectMultiple: true,\n versionSelection: VersionSelectionType.DISALLOWED,\n initialScope: FinderScope.ALL_PROJECTS,\n initialContainer: 'root',\n}\n\nexport type EntityHeaderTableProps = {\n references: ReferenceList\n isEditable: boolean\n disabled?: boolean\n onUpdate?: (updatedRefs: ReferenceList) => void // when the references are updated, EntityHeaderTable will call this function with the updated list\n removeSelectedRowsButtonText?: string\n onUpdateEntityIDsTextbox?: (value: string) => void // when the entity IDs text box is updated, this is called\n /* The word used to describe the items in the table. Default 'entity' */\n objectNameCopy?: string\n // If true, the text field where IDs are pasted is hidden, and confirming the entity finder will immediately call `onUpdate`\n hideTextFieldToPasteValue?: boolean\n entityFinderConfiguration?: EntityFinderModalProps['configuration']\n}\n\nconst UNMANAGEABLE_SUBJECT_COUNT = 10\n\n// extend EntityHeader to create dummy EntityHeader rows for those that the current user cannot view\nexport type EntityHeaderOrDummy = EntityHeader & { isDummy?: boolean }\n\n/**\n * Renders a sortable/filterable table for a set of entity references. If editable, onUpdate will be called back\n * on any entity added/removed.\n */\nexport const EntityHeaderTable = (\n props: EntityHeaderTableProps,\n): React.ReactNode => {\n const {\n references,\n isEditable,\n disabled,\n onUpdate = noop,\n removeSelectedRowsButtonText = 'Remove Selected Rows',\n onUpdateEntityIDsTextbox,\n objectNameCopy = 'entity',\n hideTextFieldToPasteValue = false,\n entityFinderConfiguration = DEFAULT_FINDER_CONFIG,\n } = props\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n const [showEntityFinder, setShowEntityFinder] = useState<boolean>(false)\n\n const {\n rowSelection,\n setRowSelection,\n refsInState,\n setRefsInState,\n newEntityIDs,\n setNewEntityIDs,\n parseErrors,\n setParseErrors,\n } = useEntityHeaderTableState(references, onUpdateEntityIDsTextbox, onUpdate)\n\n const setInvalidEntityIDError = useCallback(\n (invalidEntityIDs: string[]) => {\n setParseErrors([`Invalid Synapse ID(s): ${invalidEntityIDs.join(',')}`])\n },\n [setParseErrors],\n )\n\n const addRefsFromEntityIDs = useCallback(\n (entityIDs: string[]) => {\n const newReferences: ReferenceList = entityIDs.map(id => {\n return {\n targetId: id.trim(),\n }\n })\n setRefsInState([...refsInState, ...newReferences])\n },\n [refsInState, setRefsInState],\n )\n\n const addPastedValuesToArray = useCallback(() => {\n if (newEntityIDs) {\n if (newEntityIDs.includes(',')) {\n parse<string[]>(newEntityIDs, {\n complete: result => {\n if (result.errors.length > 0) {\n const newParseErrors = result.errors.map(\n parseError => parseError.message,\n )\n setParseErrors(newParseErrors)\n } else {\n const newParsedEntityIDs = result.data[0]\n const invalidEntityIDs = newParsedEntityIDs.filter(\n id => !id.trim().match(SYNAPSE_ENTITY_ID_REGEX),\n )\n if (invalidEntityIDs.length > 0) {\n setInvalidEntityIDError(invalidEntityIDs)\n } else {\n addRefsFromEntityIDs(newParsedEntityIDs)\n }\n }\n },\n })\n } else {\n // single item\n if (!newEntityIDs.trim().match(SYNAPSE_ENTITY_ID_REGEX)) {\n setInvalidEntityIDError([newEntityIDs])\n } else {\n addRefsFromEntityIDs([newEntityIDs])\n }\n }\n } else {\n setParseErrors([])\n setNewEntityIDs('')\n }\n }, [\n addRefsFromEntityIDs,\n newEntityIDs,\n setInvalidEntityIDError,\n setNewEntityIDs,\n setParseErrors,\n ])\n\n const pluralObjectName = upperFirst(pluralize(objectNameCopy))\n\n const selectColumns: ColumnDef<EntityHeaderOrDummy, any>[] = useMemo(\n () => [\n {\n id: 'select',\n header: CheckBoxHeader,\n cell: CheckBoxCell,\n },\n ],\n [],\n )\n\n const entityHeaderColumns: ColumnDef<EntityHeaderOrDummy, any>[] = useMemo(\n () => [\n {\n accessorFn: (row: EntityHeaderOrDummy) => row.name,\n id: 'name',\n cell: EntityHeaderNameCell,\n header: 'Name',\n },\n {\n accessorFn: (row: EntityHeaderOrDummy) => row.id,\n id: 'id',\n cell: EntityHeaderIDCell,\n header: 'SynID',\n },\n {\n accessorFn: (row: EntityHeaderOrDummy) =>\n row.isDummy\n ? '-'\n : entityTypeToFriendlyName(getEntityTypeFromHeader(row)),\n id: 'type',\n header: 'Type',\n cell: EntityHeaderTypeCell,\n filterFn: 'includesString',\n },\n ],\n [],\n )\n\n const columns = useMemo<ColumnDef<EntityHeaderOrDummy, any>[]>(\n () =>\n isEditable\n ? selectColumns.concat(entityHeaderColumns)\n : entityHeaderColumns,\n [entityHeaderColumns, isEditable, selectColumns],\n )\n const selectionCount = Object.keys(rowSelection).length\n const {\n data: results,\n isSuccess,\n isLoading,\n } = useGetEntityHeaders(refsInState, {\n throwOnError: true,\n })\n\n const data = useMemo(() => {\n //create dummy entries for values that were not returned by the getEntityHeaders call!\n const newData = results ? results?.results : []\n const newDataEntityIds = new Set()\n newData.forEach(entityHeader =>\n newDataEntityIds.add(normalizeSynPrefix(entityHeader.id)),\n )\n const missingRefs = refsInState.filter(\n ref => !newDataEntityIds.has(normalizeSynPrefix(ref.targetId)),\n )\n const dummyEntityHeaders: EntityHeaderOrDummy[] = missingRefs.map(ref => {\n return {\n id: ref.targetId,\n name: ref.targetId,\n benefactorId: -1,\n type: 'org.sagebionetworks.repo.model.Project',\n createdOn: '',\n modifiedOn: '',\n createdBy: '',\n modifiedBy: '',\n isLatestVersion: true,\n isDummy: true,\n }\n })\n return newData.concat(dummyEntityHeaders)\n }, [refsInState, results])\n const table = useReactTable({\n data,\n columns,\n state: {\n rowSelection,\n columnFilters,\n },\n enableRowSelection: isEditable,\n onRowSelectionChange: setRowSelection,\n onColumnFiltersChange: setColumnFilters,\n getCoreRowModel: getCoreRowModel(),\n getFilteredRowModel: getFilteredRowModel(),\n getSortedRowModel: getSortedRowModel(),\n getFacetedRowModel: getFacetedRowModel(),\n getFacetedUniqueValues: getFacetedUniqueValues(),\n getFacetedMinMaxValues: getFacetedMinMaxValues(),\n // debugTable: true,\n // debugHeaders: true,\n // debugColumns: false,\n columnResizeMode: 'onChange',\n })\n\n const onRemove = useCallback(() => {\n // rowSelection looks like {3: true. 5: true} where the key is the row index.\n // Create a new ReferenceList based on the entityHeaders in the current table.\n const updatedData = data.filter(\n (_value, index) => !(rowSelection[index] === true),\n )\n const newRowRefs: ReferenceList = updatedData.map(entityHeader => {\n return {\n targetId: entityHeader.id,\n }\n })\n setRefsInState(newRowRefs)\n }, [data, rowSelection, setRefsInState])\n\n const isSelection = selectionCount > 0\n const totalRowCount = data.length\n const filteredRowCount = table.getPrePaginationRowModel().rows.length\n const showFilterControls = totalRowCount > UNMANAGEABLE_SUBJECT_COUNT\n\n /**\n * Reset the column filters when the filter controls are hidden.\n * This handles the following edge case:\n * 1. List contains 100 items of type \"A\" and 1 of type \"B\"\n * 2. User filters to show just \"A\" items\n * 3. User removes all \"A\" items\n * 4. Only the single \"B\" item remains, but the filter is still present on type \"A\".\n * The filter controls are hidden, so the user cannot see the \"B\" item.\n *\n * This effect will clear the filters when the filter controls are hidden, preventing this scenario.\n */\n useEffect(\n function resetFiltersWhenFilterControlsAreHidden() {\n if (!showFilterControls) {\n table.setColumnFilters([])\n }\n },\n [table, showFilterControls],\n )\n\n if (isLoading) {\n return (\n <SkeletonTable numCols={3} numRows={Math.min(10, refsInState.length)} />\n )\n } else if (!isSuccess) {\n return <></>\n }\n return (\n <div>\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'space-between',\n p: '12px 10px 10px 5px',\n }}\n >\n {showFilterControls && (\n <Typography variant=\"body1\" sx={{ marginBottom: '10px' }}>\n {totalRowCount} {pluralObjectName}{' '}\n {filteredRowCount < totalRowCount\n ? `(${filteredRowCount} visible)`\n : ''}\n {isSelection && <span>{` (${selectionCount} selected)`}</span>}\n </Typography>\n )}\n {isEditable && refsInState.length > 0 && (\n <Button\n variant=\"contained\"\n disabled={!isSelection || disabled}\n onClick={onRemove}\n >\n {removeSelectedRowsButtonText}\n </Button>\n )}\n </Box>\n <Box\n sx={{\n display: 'flex',\n pb: 2,\n }}\n >\n {table.getHeaderGroups().map(headerGroup =>\n headerGroup.headers.map(header => {\n return header.isPlaceholder ? null : (\n <Fragment key={header.column.id}>\n {header.column.getCanFilter() && showFilterControls ? (\n <Box sx={{ flexGrow: 1 }}>\n <Filter column={header.column} table={table} />\n </Box>\n ) : null}\n </Fragment>\n )\n }),\n )}\n </Box>\n {totalRowCount > 0 && (\n <StyledTableContainer\n sx={{\n th: {\n zIndex: 100,\n maxHeight: '250px',\n },\n }}\n >\n <table style={{ borderCollapse: 'collapse', width: '100%' }}>\n <thead>\n {table.getHeaderGroups().map(headerGroup => (\n <tr key={headerGroup.id}>\n {headerGroup.headers.map(header => {\n let columnSize: string = '5%'\n switch (header.id) {\n case 'name':\n columnSize = '50%'\n break\n case 'id':\n columnSize = '22%'\n break\n case 'type':\n columnSize = '22%'\n break\n default:\n break\n }\n return (\n <th\n key={header.id}\n colSpan={header.colSpan}\n style={{\n width: columnSize,\n position: 'sticky',\n top: '0px',\n }}\n >\n {header.isPlaceholder ? null : (\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n }}\n >\n {flexRender(\n header.column.columnDef.header,\n header.getContext(),\n )}\n <Box\n sx={{\n mx: 'auto',\n }}\n />\n {header.column.getCanSort() && (\n <IconButton\n onClick={header.column.getToggleSortingHandler()}\n size={'small'}\n sx={{\n marginLeft: 'auto',\n marginRight: '16px',\n }}\n >\n <IconSvg\n icon={\n header.column.getIsSorted() === 'asc'\n ? 'sortUp'\n : 'sortDown'\n }\n wrap={false}\n fontSize={'inherit'}\n sx={{\n color: header.column.getIsSorted()\n ? 'primary.main'\n : 'grey.700',\n backgroundColor: 'none',\n }}\n />\n </IconButton>\n )}\n </Box>\n )}\n {header.column.getCanResize() && (\n <div\n className={`resizer ${\n header.column.getIsResizing() ? 'isResizing' : ''\n }`}\n onMouseDown={header.getResizeHandler()}\n onTouchStart={header.getResizeHandler()}\n />\n )}\n </th>\n )\n })}\n </tr>\n ))}\n </thead>\n <tbody>\n {table.getRowModel().rows.map(row => {\n return (\n <tr key={row.id} style={{ height: '30px' }}>\n {row.getVisibleCells().map(cell => {\n return (\n <td\n key={cell.id}\n style={{\n width: cell.column.getSize(),\n }}\n >\n {flexRender(\n cell.column.columnDef.cell,\n cell.getContext(),\n )}\n </td>\n )\n })}\n </tr>\n )\n })}\n </tbody>\n </table>\n </StyledTableContainer>\n )}\n <EntityFinderModal\n configuration={entityFinderConfiguration}\n promptCopy={`Select ${pluralObjectName} to add to the Synapse ID list`}\n show={showEntityFinder}\n title={`Select ${pluralObjectName}`}\n confirmButtonCopy={`Add ${pluralObjectName}`}\n onConfirm={items => {\n if (hideTextFieldToPasteValue) {\n const newRefs = [...refsInState, ...items]\n setRefsInState(newRefs)\n onUpdate(newRefs)\n } else {\n const newEntityIDsArray = items.map(ref => ref.targetId)\n const newEntityIDsString =\n newEntityIDs.trim().length > 0\n ? newEntityIDs.concat(',')\n : newEntityIDs\n const newValue = newEntityIDsString.concat(\n newEntityIDsArray.join(','),\n )\n setNewEntityIDs(newValue)\n }\n setShowEntityFinder(false)\n }}\n onCancel={() => setShowEntityFinder(false)}\n />\n {isEditable && (\n <Box sx={{ marginTop: '10px' }}>\n {hideTextFieldToPasteValue && (\n <Button\n variant=\"outlined\"\n onClick={() => {\n setShowEntityFinder(true)\n }}\n startIcon={<AddAd />}\n disabled={disabled}\n >\n Add {pluralObjectName}\n </Button>\n )}\n {!hideTextFieldToPasteValue && (\n <>\n <InputLabel htmlFor=\"synIDs\">Add Synapse IDs</InputLabel>\n <Box\n sx={{ display: 'grid', gridTemplateColumns: 'auto 50px 150px' }}\n >\n <TextField\n id=\"synIDs\"\n name=\"synIDs\"\n fullWidth\n onChange={e => {\n setNewEntityIDs(e.target.value)\n }}\n value={newEntityIDs}\n placeholder=\"Enter a list of Synapse IDs (i.e. 'syn123, syn456')\"\n disabled={disabled}\n />\n <Box sx={{ padding: '5px 0px 0px 5px' }}>\n {/* Entity finder button. On select, append the selected entity ID to the newSynIDs list */}\n <Tooltip title=\"Add a Synapse ID to the list via the Entity Finder\">\n <IconButton\n disabled={disabled}\n onClick={() => {\n setShowEntityFinder(true)\n }}\n >\n <AddAd />\n </IconButton>\n </Tooltip>\n </Box>\n <Button\n variant=\"outlined\"\n onClick={addPastedValuesToArray}\n disabled={\n isLoading || newEntityIDs.trim().length == 0 || disabled\n }\n startIcon={<AddCircleTwoTone />}\n >\n Add {pluralObjectName}\n </Button>\n </Box>\n </>\n )}\n {parseErrors && parseErrors.length > 0 && (\n <Alert severity={'error'} sx={{ my: 2 }}>\n <AlertTitle>Parsing errors encountered:</AlertTitle>\n <ul>\n {parseErrors.map((error, index) => {\n return (\n <Typography\n component={parseErrors.length > 1 ? 'li' : 'span'}\n key={index}\n variant={'smallText1'}\n sx={{\n lineHeight: 1.5,\n }}\n >\n {error}\n </Typography>\n )\n })}\n </ul>\n </Alert>\n )}\n </Box>\n )}\n </div>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"EntityHeaderTable.js","names":[],"sources":["../../../src/components/EntityHeaderTable/EntityHeaderTable.tsx"],"sourcesContent":["import React from 'react'\nimport AddAd from '@/assets/icons/AddAd'\nimport { StyledTableContainer } from '@/components/styled/StyledTableContainer'\nimport { useGetEntityHeaders } from '@/synapse-queries/entity/useGetEntityHeaders'\nimport {\n entityTypeToFriendlyName,\n getEntityTypeFromHeader,\n normalizeSynPrefix,\n} from '@/utils/functions/EntityTypeUtils'\nimport { SYNAPSE_ENTITY_ID_REGEX } from '@/utils/functions/RegularExpressions'\nimport { AddCircleTwoTone } from '@mui/icons-material'\nimport {\n Alert,\n AlertTitle,\n Box,\n Button,\n IconButton,\n InputLabel,\n TextField,\n Tooltip,\n Typography,\n} from '@mui/material'\nimport { EntityHeader, ReferenceList } from '@sage-bionetworks/synapse-types'\nimport {\n ColumnDef,\n ColumnFiltersState,\n flexRender,\n getCoreRowModel,\n getFacetedMinMaxValues,\n getFacetedRowModel,\n getFacetedUniqueValues,\n getFilteredRowModel,\n getSortedRowModel,\n useReactTable,\n} from '@tanstack/react-table'\nimport { noop, upperFirst } from 'lodash-es'\nimport papaparseLib from 'papaparse'\n// papaparse is CJS-only; pull named values from the default export.\nconst { parse } = papaparseLib\nimport pluralize from 'pluralize'\nimport { Fragment, useCallback, useEffect, useMemo, useState } from 'react'\nimport {\n EntityFinderModal,\n EntityFinderModalProps,\n} from '../EntityFinder/EntityFinderModal'\nimport { FinderScope } from '../EntityFinder/tree/EntityTree'\nimport { VersionSelectionType } from '../EntityFinder/VersionSelectionType'\nimport IconSvg from '../IconSvg'\nimport { SkeletonTable } from '../Skeleton'\nimport {\n CheckBoxCell,\n CheckBoxHeader,\n EntityHeaderIDCell,\n EntityHeaderNameCell,\n EntityHeaderTypeCell,\n} from './EntityHeaderTableCellRenderers'\nimport { Filter } from './Filter'\nimport { useEntityHeaderTableState } from './useEntityHeaderTableState'\n\nconst DEFAULT_FINDER_CONFIG: EntityFinderModalProps['configuration'] = {\n selectMultiple: true,\n versionSelection: VersionSelectionType.DISALLOWED,\n initialScope: FinderScope.ALL_PROJECTS,\n initialContainer: 'root',\n}\n\nexport type EntityHeaderTableProps = {\n references: ReferenceList\n isEditable: boolean\n disabled?: boolean\n onUpdate?: (updatedRefs: ReferenceList) => void // when the references are updated, EntityHeaderTable will call this function with the updated list\n removeSelectedRowsButtonText?: string\n onUpdateEntityIDsTextbox?: (value: string) => void // when the entity IDs text box is updated, this is called\n /* The word used to describe the items in the table. Default 'entity' */\n objectNameCopy?: string\n // If true, the text field where IDs are pasted is hidden, and confirming the entity finder will immediately call `onUpdate`\n hideTextFieldToPasteValue?: boolean\n entityFinderConfiguration?: EntityFinderModalProps['configuration']\n}\n\nconst UNMANAGEABLE_SUBJECT_COUNT = 10\n\n// extend EntityHeader to create dummy EntityHeader rows for those that the current user cannot view\nexport type EntityHeaderOrDummy = EntityHeader & { isDummy?: boolean }\n\n/**\n * Renders a sortable/filterable table for a set of entity references. If editable, onUpdate will be called back\n * on any entity added/removed.\n */\nexport const EntityHeaderTable = (\n props: EntityHeaderTableProps,\n): React.ReactNode => {\n const {\n references,\n isEditable,\n disabled,\n onUpdate = noop,\n removeSelectedRowsButtonText = 'Remove Selected Rows',\n onUpdateEntityIDsTextbox,\n objectNameCopy = 'entity',\n hideTextFieldToPasteValue = false,\n entityFinderConfiguration = DEFAULT_FINDER_CONFIG,\n } = props\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n const [showEntityFinder, setShowEntityFinder] = useState<boolean>(false)\n\n const {\n rowSelection,\n setRowSelection,\n refsInState,\n setRefsInState,\n newEntityIDs,\n setNewEntityIDs,\n parseErrors,\n setParseErrors,\n } = useEntityHeaderTableState(references, onUpdateEntityIDsTextbox, onUpdate)\n\n const setInvalidEntityIDError = useCallback(\n (invalidEntityIDs: string[]) => {\n setParseErrors([`Invalid Synapse ID(s): ${invalidEntityIDs.join(',')}`])\n },\n [setParseErrors],\n )\n\n const addRefsFromEntityIDs = useCallback(\n (entityIDs: string[]) => {\n const newReferences: ReferenceList = entityIDs.map(id => {\n return {\n targetId: id.trim(),\n }\n })\n setRefsInState([...refsInState, ...newReferences])\n },\n [refsInState, setRefsInState],\n )\n\n const addPastedValuesToArray = useCallback(() => {\n if (newEntityIDs) {\n if (newEntityIDs.includes(',')) {\n parse<string[]>(newEntityIDs, {\n complete: result => {\n if (result.errors.length > 0) {\n const newParseErrors = result.errors.map(\n parseError => parseError.message,\n )\n setParseErrors(newParseErrors)\n } else {\n const newParsedEntityIDs = result.data[0]\n const invalidEntityIDs = newParsedEntityIDs.filter(\n id => !id.trim().match(SYNAPSE_ENTITY_ID_REGEX),\n )\n if (invalidEntityIDs.length > 0) {\n setInvalidEntityIDError(invalidEntityIDs)\n } else {\n addRefsFromEntityIDs(newParsedEntityIDs)\n }\n }\n },\n })\n } else {\n // single item\n if (!newEntityIDs.trim().match(SYNAPSE_ENTITY_ID_REGEX)) {\n setInvalidEntityIDError([newEntityIDs])\n } else {\n addRefsFromEntityIDs([newEntityIDs])\n }\n }\n } else {\n setParseErrors([])\n setNewEntityIDs('')\n }\n }, [\n addRefsFromEntityIDs,\n newEntityIDs,\n setInvalidEntityIDError,\n setNewEntityIDs,\n setParseErrors,\n ])\n\n const pluralObjectName = upperFirst(pluralize(objectNameCopy))\n\n const selectColumns: ColumnDef<EntityHeaderOrDummy, any>[] = useMemo(\n () => [\n {\n id: 'select',\n header: CheckBoxHeader,\n cell: CheckBoxCell,\n },\n ],\n [],\n )\n\n const entityHeaderColumns: ColumnDef<EntityHeaderOrDummy, any>[] = useMemo(\n () => [\n {\n accessorFn: (row: EntityHeaderOrDummy) => row.name,\n id: 'name',\n cell: EntityHeaderNameCell,\n header: 'Name',\n },\n {\n accessorFn: (row: EntityHeaderOrDummy) => row.id,\n id: 'id',\n cell: EntityHeaderIDCell,\n header: 'SynID',\n },\n {\n accessorFn: (row: EntityHeaderOrDummy) =>\n row.isDummy\n ? '-'\n : entityTypeToFriendlyName(getEntityTypeFromHeader(row)),\n id: 'type',\n header: 'Type',\n cell: EntityHeaderTypeCell,\n filterFn: 'includesString',\n },\n ],\n [],\n )\n\n const columns = useMemo<ColumnDef<EntityHeaderOrDummy, any>[]>(\n () =>\n isEditable\n ? selectColumns.concat(entityHeaderColumns)\n : entityHeaderColumns,\n [entityHeaderColumns, isEditable, selectColumns],\n )\n const selectionCount = Object.keys(rowSelection).length\n const {\n data: results,\n isSuccess,\n isLoading,\n } = useGetEntityHeaders(refsInState, {\n throwOnError: true,\n })\n\n const data = useMemo(() => {\n //create dummy entries for values that were not returned by the getEntityHeaders call!\n const newData = results ? results?.results : []\n const newDataEntityIds = new Set()\n newData.forEach(entityHeader =>\n newDataEntityIds.add(normalizeSynPrefix(entityHeader.id)),\n )\n const missingRefs = refsInState.filter(\n ref => !newDataEntityIds.has(normalizeSynPrefix(ref.targetId)),\n )\n const dummyEntityHeaders: EntityHeaderOrDummy[] = missingRefs.map(ref => {\n return {\n id: ref.targetId,\n name: ref.targetId,\n benefactorId: -1,\n type: 'org.sagebionetworks.repo.model.Project',\n createdOn: '',\n modifiedOn: '',\n createdBy: '',\n modifiedBy: '',\n isLatestVersion: true,\n isDummy: true,\n }\n })\n return newData.concat(dummyEntityHeaders)\n }, [refsInState, results])\n const table = useReactTable({\n data,\n columns,\n state: {\n rowSelection,\n columnFilters,\n },\n enableRowSelection: isEditable,\n onRowSelectionChange: setRowSelection,\n onColumnFiltersChange: setColumnFilters,\n getCoreRowModel: getCoreRowModel(),\n getFilteredRowModel: getFilteredRowModel(),\n getSortedRowModel: getSortedRowModel(),\n getFacetedRowModel: getFacetedRowModel(),\n getFacetedUniqueValues: getFacetedUniqueValues(),\n getFacetedMinMaxValues: getFacetedMinMaxValues(),\n // debugTable: true,\n // debugHeaders: true,\n // debugColumns: false,\n columnResizeMode: 'onChange',\n })\n\n const onRemove = useCallback(() => {\n // rowSelection looks like {3: true. 5: true} where the key is the row index.\n // Create a new ReferenceList based on the entityHeaders in the current table.\n const updatedData = data.filter(\n (_value, index) => !(rowSelection[index] === true),\n )\n const newRowRefs: ReferenceList = updatedData.map(entityHeader => {\n return {\n targetId: entityHeader.id,\n }\n })\n setRefsInState(newRowRefs)\n }, [data, rowSelection, setRefsInState])\n\n const isSelection = selectionCount > 0\n const totalRowCount = data.length\n const filteredRowCount = table.getPrePaginationRowModel().rows.length\n const showFilterControls = totalRowCount > UNMANAGEABLE_SUBJECT_COUNT\n\n /**\n * Reset the column filters when the filter controls are hidden.\n * This handles the following edge case:\n * 1. List contains 100 items of type \"A\" and 1 of type \"B\"\n * 2. User filters to show just \"A\" items\n * 3. User removes all \"A\" items\n * 4. Only the single \"B\" item remains, but the filter is still present on type \"A\".\n * The filter controls are hidden, so the user cannot see the \"B\" item.\n *\n * This effect will clear the filters when the filter controls are hidden, preventing this scenario.\n */\n useEffect(\n function resetFiltersWhenFilterControlsAreHidden() {\n if (!showFilterControls) {\n table.setColumnFilters([])\n }\n },\n [table, showFilterControls],\n )\n\n if (isLoading) {\n return (\n <SkeletonTable numCols={3} numRows={Math.min(10, refsInState.length)} />\n )\n } else if (!isSuccess) {\n return <></>\n }\n return (\n <div>\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'space-between',\n p: '12px 10px 10px 5px',\n }}\n >\n {showFilterControls && (\n <Typography variant=\"body1\" sx={{ marginBottom: '10px' }}>\n {totalRowCount} {pluralObjectName}{' '}\n {filteredRowCount < totalRowCount\n ? `(${filteredRowCount} visible)`\n : ''}\n {isSelection && <span>{` (${selectionCount} selected)`}</span>}\n </Typography>\n )}\n {isEditable && refsInState.length > 0 && (\n <Button\n variant=\"contained\"\n disabled={!isSelection || disabled}\n onClick={onRemove}\n >\n {removeSelectedRowsButtonText}\n </Button>\n )}\n </Box>\n <Box\n sx={{\n display: 'flex',\n pb: 2,\n }}\n >\n {table.getHeaderGroups().map(headerGroup =>\n headerGroup.headers.map(header => {\n return header.isPlaceholder ? null : (\n <Fragment key={header.column.id}>\n {header.column.getCanFilter() && showFilterControls ? (\n <Box sx={{ flexGrow: 1 }}>\n <Filter column={header.column} table={table} />\n </Box>\n ) : null}\n </Fragment>\n )\n }),\n )}\n </Box>\n {totalRowCount > 0 && (\n <StyledTableContainer\n sx={{\n th: {\n zIndex: 100,\n maxHeight: '250px',\n },\n }}\n >\n <table style={{ borderCollapse: 'collapse', width: '100%' }}>\n <thead>\n {table.getHeaderGroups().map(headerGroup => (\n <tr key={headerGroup.id}>\n {headerGroup.headers.map(header => {\n let columnSize: string = '5%'\n switch (header.id) {\n case 'name':\n columnSize = '50%'\n break\n case 'id':\n columnSize = '22%'\n break\n case 'type':\n columnSize = '22%'\n break\n default:\n break\n }\n return (\n <th\n key={header.id}\n colSpan={header.colSpan}\n style={{\n width: columnSize,\n position: 'sticky',\n top: '0px',\n }}\n >\n {header.isPlaceholder ? null : (\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n }}\n >\n {flexRender(\n header.column.columnDef.header,\n header.getContext(),\n )}\n <Box\n sx={{\n mx: 'auto',\n }}\n />\n {header.column.getCanSort() && (\n <IconButton\n onClick={header.column.getToggleSortingHandler()}\n size={'small'}\n sx={{\n marginLeft: 'auto',\n marginRight: '16px',\n }}\n >\n <IconSvg\n icon={\n header.column.getIsSorted() === 'asc'\n ? 'sortUp'\n : 'sortDown'\n }\n wrap={false}\n fontSize={'inherit'}\n sx={{\n color: header.column.getIsSorted()\n ? 'primary.main'\n : 'grey.700',\n backgroundColor: 'none',\n }}\n />\n </IconButton>\n )}\n </Box>\n )}\n {header.column.getCanResize() && (\n <div\n className={`resizer ${\n header.column.getIsResizing() ? 'isResizing' : ''\n }`}\n onMouseDown={header.getResizeHandler()}\n onTouchStart={header.getResizeHandler()}\n />\n )}\n </th>\n )\n })}\n </tr>\n ))}\n </thead>\n <tbody>\n {table.getRowModel().rows.map(row => {\n return (\n <tr key={row.id} style={{ height: '30px' }}>\n {row.getVisibleCells().map(cell => {\n return (\n <td\n key={cell.id}\n style={{\n width: cell.column.getSize(),\n }}\n >\n {flexRender(\n cell.column.columnDef.cell,\n cell.getContext(),\n )}\n </td>\n )\n })}\n </tr>\n )\n })}\n </tbody>\n </table>\n </StyledTableContainer>\n )}\n <EntityFinderModal\n configuration={entityFinderConfiguration}\n promptCopy={`Select ${pluralObjectName} to add to the Synapse ID list`}\n show={showEntityFinder}\n title={`Select ${pluralObjectName}`}\n confirmButtonCopy={`Add ${pluralObjectName}`}\n onConfirm={items => {\n if (hideTextFieldToPasteValue) {\n const newRefs = [...refsInState, ...items]\n setRefsInState(newRefs)\n onUpdate(newRefs)\n } else {\n const newEntityIDsArray = items.map(ref => ref.targetId)\n const newEntityIDsString =\n newEntityIDs.trim().length > 0\n ? newEntityIDs.concat(',')\n : newEntityIDs\n const newValue = newEntityIDsString.concat(\n newEntityIDsArray.join(','),\n )\n setNewEntityIDs(newValue)\n }\n setShowEntityFinder(false)\n }}\n onCancel={() => setShowEntityFinder(false)}\n />\n {isEditable && (\n <Box sx={{ marginTop: '10px' }}>\n {hideTextFieldToPasteValue && (\n <Button\n variant=\"outlined\"\n onClick={() => {\n setShowEntityFinder(true)\n }}\n startIcon={<AddAd />}\n disabled={disabled}\n >\n Add {pluralObjectName}\n </Button>\n )}\n {!hideTextFieldToPasteValue && (\n <>\n <InputLabel htmlFor=\"synIDs\">Add Synapse IDs</InputLabel>\n <Box\n sx={{ display: 'grid', gridTemplateColumns: 'auto 50px 150px' }}\n >\n <TextField\n id=\"synIDs\"\n name=\"synIDs\"\n fullWidth\n onChange={e => {\n setNewEntityIDs(e.target.value)\n }}\n value={newEntityIDs}\n placeholder=\"Enter a list of Synapse IDs (i.e. 'syn123, syn456')\"\n disabled={disabled}\n />\n <Box sx={{ padding: '5px 0px 0px 5px' }}>\n {/* Entity finder button. On select, append the selected entity ID to the newSynIDs list */}\n <Tooltip title=\"Add a Synapse ID to the list via the Entity Finder\">\n <IconButton\n disabled={disabled}\n onClick={() => {\n setShowEntityFinder(true)\n }}\n >\n <AddAd />\n </IconButton>\n </Tooltip>\n </Box>\n <Button\n variant=\"outlined\"\n onClick={addPastedValuesToArray}\n disabled={\n isLoading || newEntityIDs.trim().length == 0 || disabled\n }\n startIcon={<AddCircleTwoTone />}\n >\n Add {pluralObjectName}\n </Button>\n </Box>\n </>\n )}\n {parseErrors && parseErrors.length > 0 && (\n <Alert severity={'error'} sx={{ my: 2 }}>\n <AlertTitle>Parsing errors encountered:</AlertTitle>\n <ul>\n {parseErrors.map((error, index) => {\n return (\n <Typography\n component={parseErrors.length > 1 ? 'li' : 'span'}\n key={index}\n variant={'smallText1'}\n sx={{\n lineHeight: 1.5,\n }}\n >\n {error}\n </Typography>\n )\n })}\n </ul>\n </Alert>\n )}\n </Box>\n )}\n </div>\n )\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Filter.js","names":[],"sources":["../../../src/components/EntityHeaderTable/Filter.tsx"],"sourcesContent":["import { useMemo } from 'react'\nimport { Column, Table } from '@tanstack/react-table'\nimport { DebouncedInput } from './DebouncedInput'\n\nexport function Filter({\n column,\n table,\n}: {\n column: Column<any, unknown>\n table: Table<any>\n}) {\n const firstValue = table\n .getPreFilteredRowModel()\n .flatRows[0]?.getValue(column.id)\n\n const columnFilterValue = (column.getFilterValue() as string) ?? ''\n\n const sortedUniqueValues: string[] = useMemo(\n () =>\n typeof firstValue === 'number'\n ? []\n : Array.from(column.getFacetedUniqueValues().keys()).sort(),\n [column.getFacetedUniqueValues()],\n )\n return (\n <DebouncedInput\n type=\"text\"\n options={sortedUniqueValues}\n initialValue={columnFilterValue}\n onChange={value => column.setFilterValue(value)}\n label={`Filter by ${column.columnDef.header} (${\n column.getFacetedUniqueValues().size\n })`}\n />\n )\n}\n"],"mappings":";;;;AAIA,SAAgB,EAAO,EACrB,WACA,YAIC;CACD,IAAM,IAAa,EAChB,wBAAwB,CACxB,SAAS,IAAI,SAAS,EAAO,GAAG,EAE7B,IAAqB,EAAO,gBAAgB,IAAe;AASjE,QACE,kBAAC,GAAD;EACE,MAAK;EACL,SAViC,QAEjC,OAAO,KAAe,WAClB,EAAE,GACF,MAAM,KAAK,EAAO,wBAAwB,CAAC,MAAM,CAAC,CAAC,MAAM,EAC/D,CAAC,EAAO,wBAAwB,CAAC,CAClC;EAKG,cAAc;EACd,WAAU,MAAS,EAAO,eAAe,EAAM;EAC/C,OAAO,aAAa,EAAO,UAAU,OAAO,IAC1C,EAAO,wBAAwB,CAAC,KACjC;EACD,CAAA"}
1
+ {"version":3,"file":"Filter.js","names":[],"sources":["../../../src/components/EntityHeaderTable/Filter.tsx"],"sourcesContent":["import { useMemo } from 'react'\nimport { Column, Table } from '@tanstack/react-table'\nimport { DebouncedInput } from './DebouncedInput'\n\nexport function Filter({\n column,\n table,\n}: {\n column: Column<any, unknown>\n table: Table<any>\n}) {\n const firstValue = table\n .getPreFilteredRowModel()\n .flatRows[0]?.getValue(column.id)\n\n const columnFilterValue = (column.getFilterValue() as string) ?? ''\n\n const sortedUniqueValues: string[] = useMemo(\n () =>\n typeof firstValue === 'number'\n ? []\n : Array.from(column.getFacetedUniqueValues().keys()).sort(),\n [column.getFacetedUniqueValues()],\n )\n return (\n <DebouncedInput\n type=\"text\"\n options={sortedUniqueValues}\n initialValue={columnFilterValue}\n onChange={value => column.setFilterValue(value)}\n label={`Filter by ${column.columnDef.header} (${\n column.getFacetedUniqueValues().size\n })`}\n />\n )\n}\n"],"mappings":";;;;AAIA,SAAgB,EAAO,EACrB,WACA,YAIC;CACD,IAAM,IAAa,EAChB,wBAAwB,CACxB,SAAS,IAAI,SAAS,EAAO,GAAG,EAE7B,IAAqB,EAAO,gBAAgB,IAAe;AASjE,QACE,kBAAC,GAAD;EACE,MAAK;EACL,SAViC,QAEjC,OAAO,KAAe,WAClB,EAAE,GACF,MAAM,KAAK,EAAO,wBAAwB,CAAC,MAAM,CAAC,CAAC,MAAM,EAC/D,CAAC,EAAO,wBAAwB,CAAC,CAKtB;EACT,cAAc;EACd,WAAU,MAAS,EAAO,eAAe,EAAM;EAC/C,OAAO,aAAa,EAAO,UAAU,OAAO,IAC1C,EAAO,wBAAwB,CAAC,KACjC;EACD,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"useEntityHeaderTableState.js","names":[],"sources":["../../../src/components/EntityHeaderTable/useEntityHeaderTableState.ts"],"sourcesContent":["import { useState, useCallback, useEffect } from 'react'\nimport { RowSelectionState } from '@tanstack/react-table'\nimport { cloneDeep } from 'lodash-es'\nimport { ReferenceList } from '@sage-bionetworks/synapse-types'\n\nexport function useEntityHeaderTableState(\n references: ReferenceList,\n onUpdateEntityIDsTextbox?: (value: string) => void,\n onUpdate?: (updatedRefs: ReferenceList) => void,\n) {\n const [rowSelection, setRowSelection] = useState<RowSelectionState>({})\n const [refsInState, _setRefsInState] = useState<ReferenceList>(\n cloneDeep(references),\n )\n const [newEntityIDs, _setNewEntityIDs] = useState<string>('')\n const [parseErrors, setParseErrors] = useState<string[]>([])\n\n /* Reset state if the `references` argument changes */\n useEffect(() => {\n _setRefsInState(cloneDeep(references))\n }, [references])\n\n const setNewEntityIDs = useCallback(\n (newValue: string) => {\n _setNewEntityIDs(newValue)\n if (onUpdateEntityIDsTextbox) {\n onUpdateEntityIDsTextbox(newValue)\n }\n },\n [onUpdateEntityIDsTextbox],\n )\n\n const setRefsInState = useCallback(\n (refs: ReferenceList) => {\n setRowSelection({})\n _setRefsInState(refs)\n if (onUpdate) {\n onUpdate(refs)\n }\n setParseErrors([])\n setNewEntityIDs('')\n },\n [onUpdate, setNewEntityIDs],\n )\n\n return {\n rowSelection,\n setRowSelection,\n refsInState,\n setRefsInState,\n newEntityIDs,\n setNewEntityIDs,\n parseErrors,\n setParseErrors,\n }\n}\n"],"mappings":";;;AAKA,SAAgB,EACd,GACA,GACA,GACA;CACA,IAAM,CAAC,GAAc,KAAmB,EAA4B,EAAE,CAAC,EACjE,CAAC,GAAa,KAAmB,EACrC,EAAU,EAAW,CACtB,EACK,CAAC,GAAc,KAAoB,EAAiB,GAAG,EACvD,CAAC,GAAa,KAAkB,EAAmB,EAAE,CAAC;AAG5D,SAAgB;AACd,IAAgB,EAAU,EAAW,CAAC;IACrC,CAAC,EAAW,CAAC;CAEhB,IAAM,IAAkB,GACrB,MAAqB;AAEpB,EADA,EAAiB,EAAS,EACtB,KACF,EAAyB,EAAS;IAGtC,CAAC,EAAyB,CAC3B;AAeD,QAAO;EACL;EACA;EACA;EACA,gBAjBqB,GACpB,MAAwB;AAOvB,GANA,EAAgB,EAAE,CAAC,EACnB,EAAgB,EAAK,EACjB,KACF,EAAS,EAAK,EAEhB,EAAe,EAAE,CAAC,EAClB,EAAgB,GAAG;KAErB,CAAC,GAAU,EAAgB,CAC5B;EAOC;EACA;EACA;EACA;EACD"}
1
+ {"version":3,"file":"useEntityHeaderTableState.js","names":[],"sources":["../../../src/components/EntityHeaderTable/useEntityHeaderTableState.ts"],"sourcesContent":["import { useState, useCallback, useEffect } from 'react'\nimport { RowSelectionState } from '@tanstack/react-table'\nimport { cloneDeep } from 'lodash-es'\nimport { ReferenceList } from '@sage-bionetworks/synapse-types'\n\nexport function useEntityHeaderTableState(\n references: ReferenceList,\n onUpdateEntityIDsTextbox?: (value: string) => void,\n onUpdate?: (updatedRefs: ReferenceList) => void,\n) {\n const [rowSelection, setRowSelection] = useState<RowSelectionState>({})\n const [refsInState, _setRefsInState] = useState<ReferenceList>(\n cloneDeep(references),\n )\n const [newEntityIDs, _setNewEntityIDs] = useState<string>('')\n const [parseErrors, setParseErrors] = useState<string[]>([])\n\n /* Reset state if the `references` argument changes */\n useEffect(() => {\n _setRefsInState(cloneDeep(references))\n }, [references])\n\n const setNewEntityIDs = useCallback(\n (newValue: string) => {\n _setNewEntityIDs(newValue)\n if (onUpdateEntityIDsTextbox) {\n onUpdateEntityIDsTextbox(newValue)\n }\n },\n [onUpdateEntityIDsTextbox],\n )\n\n const setRefsInState = useCallback(\n (refs: ReferenceList) => {\n setRowSelection({})\n _setRefsInState(refs)\n if (onUpdate) {\n onUpdate(refs)\n }\n setParseErrors([])\n setNewEntityIDs('')\n },\n [onUpdate, setNewEntityIDs],\n )\n\n return {\n rowSelection,\n setRowSelection,\n refsInState,\n setRefsInState,\n newEntityIDs,\n setNewEntityIDs,\n parseErrors,\n setParseErrors,\n }\n}\n"],"mappings":";;;AAKA,SAAgB,EACd,GACA,GACA,GACA;CACA,IAAM,CAAC,GAAc,KAAmB,EAA4B,EAAE,CAAC,EACjE,CAAC,GAAa,KAAmB,EACrC,EAAU,EAAW,CACtB,EACK,CAAC,GAAc,KAAoB,EAAiB,GAAG,EACvD,CAAC,GAAa,KAAkB,EAAmB,EAAE,CAAC;AAG5D,SAAgB;AACd,IAAgB,EAAU,EAAW,CAAC;IACrC,CAAC,EAAW,CAAC;CAEhB,IAAM,IAAkB,GACrB,MAAqB;AAEpB,EADA,EAAiB,EAAS,EACtB,KACF,EAAyB,EAAS;IAGtC,CAAC,EAAyB,CAC3B;AAeD,QAAO;EACL;EACA;EACA;EACA,gBAjBqB,GACpB,MAAwB;AAOvB,GANA,EAAgB,EAAE,CAAC,EACnB,EAAgB,EAAK,EACjB,KACF,EAAS,EAAK,EAEhB,EAAe,EAAE,CAAC,EAClB,EAAgB,GAAG;KAErB,CAAC,GAAU,EAAgB,CAO3B;EACA;EACA;EACA;EACA;EACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"EntitySubjectsSelector.js","names":[],"sources":["../../../src/components/EntitySubjectsSelector/EntitySubjectsSelector.tsx"],"sourcesContent":["import { Box, Typography } from '@mui/material'\nimport {\n Reference,\n ReferenceList,\n RestrictableObjectDescriptor,\n RestrictableObjectType,\n} from '@sage-bionetworks/synapse-types'\nimport { isEqual, uniqWith } from 'lodash-es'\nimport { useMemo } from 'react'\nimport EntityHeaderTable, { EntityHeaderTableProps } from '../EntityHeaderTable'\n\nexport const REMOVE_BUTTON_TEXT = 'Mark for Removal from AR'\nexport const NO_ENTITIES_SELECTED = 'No entities selected.'\n\nexport type EntitySubjectsSelectorProps = {\n // will be filtered to only entity subjects\n subjects: RestrictableObjectDescriptor[]\n onUpdate?: (subjects: RestrictableObjectDescriptor[]) => void\n onUpdateEntityIDsTextbox: EntityHeaderTableProps['onUpdateEntityIDsTextbox']\n}\n\nfunction EntitySubjectsSelector(props: EntitySubjectsSelectorProps) {\n const { subjects, onUpdate, onUpdateEntityIDsTextbox } = props\n\n const references = useMemo(() => {\n return subjects\n .filter(subject => {\n return subject.type === RestrictableObjectType.ENTITY\n })\n .map(subject => {\n const ref: Reference = {\n targetId: subject.id,\n }\n return ref\n })\n }, [subjects])\n\n const handleChange = (updatedReferences: ReferenceList) => {\n if (onUpdate) {\n const dedupedReferences = uniqWith(updatedReferences, isEqual)\n const updatedSubjects = dedupedReferences.map(reference => {\n const subject: RestrictableObjectDescriptor = {\n id: reference.targetId,\n type: RestrictableObjectType.ENTITY,\n }\n return subject\n })\n onUpdate(updatedSubjects)\n }\n }\n\n return (\n <Box\n sx={{\n mb: 2,\n }}\n >\n {references.length === 0 && (\n <Typography\n variant=\"body1Italic\"\n sx={{\n mb: -4,\n }}\n >\n {NO_ENTITIES_SELECTED}\n </Typography>\n )}\n <EntityHeaderTable\n references={references}\n isEditable={Boolean(onUpdate)}\n onUpdate={newReferences => {\n handleChange(newReferences)\n }}\n removeSelectedRowsButtonText={REMOVE_BUTTON_TEXT}\n onUpdateEntityIDsTextbox={onUpdateEntityIDsTextbox}\n />\n </Box>\n )\n}\n\nexport default EntitySubjectsSelector\n"],"mappings":";;;;;;;AAWA,IAAa,IAAqB,4BACrB,IAAuB;AASpC,SAAS,EAAuB,GAAoC;CAClE,IAAM,EAAE,aAAU,aAAU,gCAA6B,GAEnD,IAAa,QACV,EACJ,QAAO,MACC,EAAQ,SAAS,EAAuB,OAC/C,CACD,KAAI,OACoB,EACrB,UAAU,EAAQ,IACnB,EAED,EACH,CAAC,EAAS,CAAC,EAER,KAAgB,MAAqC;AACzD,EAAI,KASF,EAR0B,EAAS,GAAmB,EAAQ,CACpB,KAAI,OACE;GAC5C,IAAI,EAAU;GACd,MAAM,EAAuB;GAC9B,EAED,CACuB;;AAI7B,QACE,kBAAC,GAAD;EACE,IAAI,EACF,IAAI,GACL;YAHH,CAKG,EAAW,WAAW,KACrB,kBAAC,GAAD;GACE,SAAQ;GACR,IAAI,EACF,IAAI,IACL;;GAGU,CAAA,EAEf,kBAAC,GAAD;GACc;GACZ,YAAY,EAAQ;GACpB,WAAU,MAAiB;AACzB,MAAa,EAAc;;GAE7B,8BAA8B;GACJ;GAC1B,CAAA,CACE"}
1
+ {"version":3,"file":"EntitySubjectsSelector.js","names":[],"sources":["../../../src/components/EntitySubjectsSelector/EntitySubjectsSelector.tsx"],"sourcesContent":["import { Box, Typography } from '@mui/material'\nimport {\n Reference,\n ReferenceList,\n RestrictableObjectDescriptor,\n RestrictableObjectType,\n} from '@sage-bionetworks/synapse-types'\nimport { isEqual, uniqWith } from 'lodash-es'\nimport { useMemo } from 'react'\nimport EntityHeaderTable, { EntityHeaderTableProps } from '../EntityHeaderTable'\n\nexport const REMOVE_BUTTON_TEXT = 'Mark for Removal from AR'\nexport const NO_ENTITIES_SELECTED = 'No entities selected.'\n\nexport type EntitySubjectsSelectorProps = {\n // will be filtered to only entity subjects\n subjects: RestrictableObjectDescriptor[]\n onUpdate?: (subjects: RestrictableObjectDescriptor[]) => void\n onUpdateEntityIDsTextbox: EntityHeaderTableProps['onUpdateEntityIDsTextbox']\n}\n\nfunction EntitySubjectsSelector(props: EntitySubjectsSelectorProps) {\n const { subjects, onUpdate, onUpdateEntityIDsTextbox } = props\n\n const references = useMemo(() => {\n return subjects\n .filter(subject => {\n return subject.type === RestrictableObjectType.ENTITY\n })\n .map(subject => {\n const ref: Reference = {\n targetId: subject.id,\n }\n return ref\n })\n }, [subjects])\n\n const handleChange = (updatedReferences: ReferenceList) => {\n if (onUpdate) {\n const dedupedReferences = uniqWith(updatedReferences, isEqual)\n const updatedSubjects = dedupedReferences.map(reference => {\n const subject: RestrictableObjectDescriptor = {\n id: reference.targetId,\n type: RestrictableObjectType.ENTITY,\n }\n return subject\n })\n onUpdate(updatedSubjects)\n }\n }\n\n return (\n <Box\n sx={{\n mb: 2,\n }}\n >\n {references.length === 0 && (\n <Typography\n variant=\"body1Italic\"\n sx={{\n mb: -4,\n }}\n >\n {NO_ENTITIES_SELECTED}\n </Typography>\n )}\n <EntityHeaderTable\n references={references}\n isEditable={Boolean(onUpdate)}\n onUpdate={newReferences => {\n handleChange(newReferences)\n }}\n removeSelectedRowsButtonText={REMOVE_BUTTON_TEXT}\n onUpdateEntityIDsTextbox={onUpdateEntityIDsTextbox}\n />\n </Box>\n )\n}\n\nexport default EntitySubjectsSelector\n"],"mappings":";;;;;;;AAWA,IAAa,IAAqB,4BACrB,IAAuB;AASpC,SAAS,EAAuB,GAAoC;CAClE,IAAM,EAAE,aAAU,aAAU,gCAA6B,GAEnD,IAAa,QACV,EACJ,QAAO,MACC,EAAQ,SAAS,EAAuB,OAC/C,CACD,KAAI,OAII,EAFL,UAAU,EAAQ,IAEb,EACP,EACH,CAAC,EAAS,CAAC,EAER,KAAgB,MAAqC;AACzD,EAAI,KASF,EAR0B,EAAS,GAAmB,EAC9B,CAAkB,KAAI,OAKrC;GAHL,IAAI,EAAU;GACd,MAAM,EAAuB;GAExB,EAEA,CAAgB;;AAI7B,QACE,kBAAC,GAAD;EACE,IAAI,EACF,IAAI,GACL;YAHH,CAKG,EAAW,WAAW,KACrB,kBAAC,GAAD;GACE,SAAQ;GACR,IAAI,EACF,IAAI,IACL;;GAGU,CAAA,EAEf,kBAAC,GAAD;GACc;GACZ,YAAY,EAAQ;GACpB,WAAU,MAAiB;AACzB,MAAa,EAAc;;GAE7B,8BAA8B;GACJ;GAC1B,CAAA,CACE"}
@@ -1 +1 @@
1
- {"version":3,"file":"IdColumnHeader.js","names":[],"sources":["../../../../src/components/EntityTreeTable/components/IdColumnHeader.tsx"],"sourcesContent":["import React, { useMemo } from 'react'\nimport { HeaderContext } from '@tanstack/react-table'\nimport { EntityBundleRow } from '../EntityTreeTable'\nimport ColumnHeader from '../../TanStackTable/ColumnHeader'\nimport { CopyToClipboardIcon } from '../../CopyToClipboardIcon'\n\nexport const IdColumnHeader: React.FC<\n HeaderContext<EntityBundleRow, unknown>\n> = props => {\n const { table } = props\n\n // Get all visible rows and extract their entity IDs\n const visibleIds = useMemo(() => {\n const visibleRows = table.getRowModel().rows\n return visibleRows\n .filter(row => !row.original.isLoadMore && row.original.entityId) // Exclude \"Load More\" rows and rows without entityId\n .map(row => row.original.entityId)\n .join('\\n')\n }, [table.getRowModel().rows])\n\n const copyButton = <CopyToClipboardIcon value={visibleIds} sizePx={16} />\n\n return <ColumnHeader {...props} title=\"ID\" additionalButtons={copyButton} />\n}\n"],"mappings":";;;;;AAMA,IAAa,KAET,MAAS;CACX,IAAM,EAAE,aAAU,GAWZ,IAAa,kBAAC,GAAD;EAAqB,OARrB,QACG,EAAM,aAAa,CAAC,KAErC,QAAO,MAAO,CAAC,EAAI,SAAS,cAAc,EAAI,SAAS,SAAS,CAChE,KAAI,MAAO,EAAI,SAAS,SAAS,CACjC,KAAK,KAAK,EACZ,CAAC,EAAM,aAAa,CAAC,KAAK,CAAC;EAE6B,QAAQ;EAAM,CAAA;AAEzE,QAAO,kBAAC,GAAD;EAAc,GAAI;EAAO,OAAM;EAAK,mBAAmB;EAAc,CAAA"}
1
+ {"version":3,"file":"IdColumnHeader.js","names":[],"sources":["../../../../src/components/EntityTreeTable/components/IdColumnHeader.tsx"],"sourcesContent":["import React, { useMemo } from 'react'\nimport { HeaderContext } from '@tanstack/react-table'\nimport { EntityBundleRow } from '../EntityTreeTable'\nimport ColumnHeader from '../../TanStackTable/ColumnHeader'\nimport { CopyToClipboardIcon } from '../../CopyToClipboardIcon'\n\nexport const IdColumnHeader: React.FC<\n HeaderContext<EntityBundleRow, unknown>\n> = props => {\n const { table } = props\n\n // Get all visible rows and extract their entity IDs\n const visibleIds = useMemo(() => {\n const visibleRows = table.getRowModel().rows\n return visibleRows\n .filter(row => !row.original.isLoadMore && row.original.entityId) // Exclude \"Load More\" rows and rows without entityId\n .map(row => row.original.entityId)\n .join('\\n')\n }, [table.getRowModel().rows])\n\n const copyButton = <CopyToClipboardIcon value={visibleIds} sizePx={16} />\n\n return <ColumnHeader {...props} title=\"ID\" additionalButtons={copyButton} />\n}\n"],"mappings":";;;;;AAMA,IAAa,KAET,MAAS;CACX,IAAM,EAAE,aAAU,GAWZ,IAAa,kBAAC,GAAD;EAAqB,OARrB,QACG,EAAM,aAAa,CAAC,KAErC,QAAO,MAAO,CAAC,EAAI,SAAS,cAAc,EAAI,SAAS,SAAS,CAChE,KAAI,MAAO,EAAI,SAAS,SAAS,CACjC,KAAK,KAAK,EACZ,CAAC,EAAM,aAAa,CAAC,KAAK,CAEkB;EAAY,QAAQ;EAAM,CAAA;AAEzE,QAAO,kBAAC,GAAD;EAAc,GAAI;EAAO,OAAM;EAAK,mBAAmB;EAAc,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"useEntityTreeState.js","names":[],"sources":["../../../../src/components/EntityTreeTable/hooks/useEntityTreeState.ts"],"sourcesContent":["import { useState, useCallback, useEffect, useMemo } from 'react'\nimport { SortingState } from '@tanstack/react-table'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { matchQuery } from '@tanstack/query-core'\nimport {\n EntityChildrenRequest,\n EntityHeader,\n SortBy,\n Direction,\n} from '@sage-bionetworks/synapse-types'\nimport { EntityType } from '@sage-bionetworks/synapse-client'\nimport { useGetEntityHeader } from '@/synapse-queries'\nimport { useGetEntityChildren } from '@/synapse-queries/entity/useGetEntityChildren'\nimport { convertToEntityType } from '@/utils/functions/EntityTypeUtils'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\n\nexport type TreeNode = {\n entityHeader: EntityHeader\n parentId?: string\n depth: number\n isLeaf: boolean\n children?: TreeNode[]\n}\n\nconst includeTypes: EntityType[] = [\n EntityType.folder,\n EntityType.file,\n EntityType.link,\n EntityType.recordset,\n]\n\n/**\n * Hook that manages all tree state and data initialization.\n */\nexport const useEntityTreeState = (\n rootId: string,\n expandRootByDefault: boolean,\n showRootNode: boolean,\n) => {\n // Core state\n const [expanded, setExpanded] = useState<Record<string, boolean>>({})\n const [tree, setTree] = useState<Record<string, TreeNode>>({})\n const [loadingIds, setLoadingIds] = useState<Set<string>>(new Set())\n const [loadedChildren, setLoadedChildren] = useState<Set<string>>(new Set())\n const [nextPageTokens, setNextPageTokens] = useState<\n Record<string, string | undefined>\n >({})\n const [loadingPageTokens, setLoadingPageTokens] = useState<\n Record<string, string | undefined>\n >({})\n const [sorting, setSorting] = useState<SortingState>([])\n const queryClient = useQueryClient()\n const { keyFactory } = useSynapseContext()\n const rootEntityQueryKey = useMemo(\n () => keyFactory.getEntityQueryKey(rootId),\n [keyFactory, rootId],\n )\n\n // Derive sorting parameters from state\n const { sortBy, sortDirection } = useMemo(() => {\n if (!sorting.length) return {}\n\n const firstSort = sorting[0]\n let sortBy: SortBy | undefined\n\n switch (firstSort.id) {\n case 'name':\n sortBy = SortBy.NAME\n break\n case 'createdOn':\n sortBy = SortBy.CREATED_ON\n break\n case 'modifiedOn':\n sortBy = SortBy.MODIFIED_ON\n break\n default:\n return {}\n }\n\n return {\n sortBy,\n sortDirection: firstSort.desc ? Direction.DESC : Direction.ASC,\n }\n }, [sorting])\n\n const rootChildrenRequest: EntityChildrenRequest = useMemo(() => {\n const baseRequest: EntityChildrenRequest = {\n parentId: rootId,\n includeTypes,\n sortBy,\n sortDirection,\n }\n\n return baseRequest\n }, [rootId, sortBy, sortDirection])\n\n const rootChildrenQueryKey = useMemo(\n () => keyFactory.getEntityChildrenQueryKey(rootChildrenRequest, false),\n [keyFactory, rootChildrenRequest],\n )\n\n // Reset tree data when sorting changes\n const resetTreeData = useCallback(() => {\n void queryClient.removeQueries({\n queryKey: rootChildrenQueryKey,\n exact: true,\n })\n\n setTree({})\n setLoadedChildren(new Set())\n setExpanded({})\n setNextPageTokens({})\n setLoadingPageTokens({})\n setLoadingIds(new Set())\n }, [queryClient, rootChildrenQueryKey])\n\n // Get root entity header\n const { data: rootHeader } = useGetEntityHeader(rootId)\n // Get root children - only fetch when we have header and haven't loaded children yet\n const shouldFetchChildren = !!rootHeader && !loadedChildren.has(rootId)\n const { data: rootChildren } = useGetEntityChildren(rootChildrenRequest, {\n enabled: shouldFetchChildren,\n })\n\n // Effect to reset data when sorting changes\n useEffect(() => {\n resetTreeData()\n }, [resetTreeData, sorting])\n\n useEffect(() => {\n const unsubscribe = queryClient.getQueryCache().subscribe(event => {\n if (event?.type === 'updated' && event.action?.type === 'invalidate') {\n // Check if any entity in the tree was invalidated\n const entityIds = Object.keys(tree)\n for (const entityId of entityIds) {\n const entityQueryKey = keyFactory.getEntityQueryKey(entityId)\n if (\n matchQuery({ queryKey: entityQueryKey, exact: false }, event.query)\n ) {\n resetTreeData()\n return\n }\n }\n }\n })\n\n return () => {\n unsubscribe()\n }\n }, [queryClient, rootEntityQueryKey, resetTreeData, tree, keyFactory])\n\n // Effect to initialize root node and its children\n useEffect(() => {\n if (rootHeader && rootChildren && !tree[rootId]) {\n // Build the children nodes from the response\n const children: TreeNode[] = rootChildren.page.map(\n (eh: EntityHeader) => ({\n entityHeader: eh,\n parentId: rootId,\n depth: showRootNode ? 1 : 0,\n isLeaf: !(\n convertToEntityType(eh.type) === EntityType.project ||\n convertToEntityType(eh.type) === EntityType.folder\n ),\n }),\n )\n\n // Create child entries for the tree\n const childEntries = Object.fromEntries(\n children.map(child => [child.entityHeader.id, child]),\n )\n\n // Set up the complete tree state in one go\n setTree({\n [rootId]: {\n entityHeader: rootHeader,\n depth: showRootNode ? 0 : -1,\n isLeaf: false,\n children,\n },\n ...childEntries,\n })\n\n // Set up pagination token\n const rootNext = rootChildren.nextPageToken\n setNextPageTokens({ [rootId]: rootNext })\n\n // Mark as loaded if there's no next page token\n if (!rootNext) {\n setLoadedChildren(new Set([rootId]))\n }\n\n // Expand root node by default if the flag is set\n if (expandRootByDefault) {\n setExpanded(prev => ({ ...prev, [rootId]: true }))\n }\n }\n }, [\n rootHeader,\n rootChildren,\n rootId,\n expandRootByDefault,\n showRootNode,\n tree,\n ])\n\n return {\n // State\n expanded,\n setExpanded,\n tree,\n setTree,\n loadingIds,\n setLoadingIds,\n loadedChildren,\n setLoadedChildren,\n nextPageTokens,\n setNextPageTokens,\n loadingPageTokens,\n setLoadingPageTokens,\n sorting,\n setSorting,\n\n // Derived values\n sortBy,\n sortDirection,\n\n // Data\n rootHeader,\n rootChildren,\n\n // Actions\n resetTreeData,\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"useEntityTreeState.js","names":[],"sources":["../../../../src/components/EntityTreeTable/hooks/useEntityTreeState.ts"],"sourcesContent":["import { useState, useCallback, useEffect, useMemo } from 'react'\nimport { SortingState } from '@tanstack/react-table'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { matchQuery } from '@tanstack/query-core'\nimport {\n EntityChildrenRequest,\n EntityHeader,\n SortBy,\n Direction,\n} from '@sage-bionetworks/synapse-types'\nimport { EntityType } from '@sage-bionetworks/synapse-client'\nimport { useGetEntityHeader } from '@/synapse-queries'\nimport { useGetEntityChildren } from '@/synapse-queries/entity/useGetEntityChildren'\nimport { convertToEntityType } from '@/utils/functions/EntityTypeUtils'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\n\nexport type TreeNode = {\n entityHeader: EntityHeader\n parentId?: string\n depth: number\n isLeaf: boolean\n children?: TreeNode[]\n}\n\nconst includeTypes: EntityType[] = [\n EntityType.folder,\n EntityType.file,\n EntityType.link,\n EntityType.recordset,\n]\n\n/**\n * Hook that manages all tree state and data initialization.\n */\nexport const useEntityTreeState = (\n rootId: string,\n expandRootByDefault: boolean,\n showRootNode: boolean,\n) => {\n // Core state\n const [expanded, setExpanded] = useState<Record<string, boolean>>({})\n const [tree, setTree] = useState<Record<string, TreeNode>>({})\n const [loadingIds, setLoadingIds] = useState<Set<string>>(new Set())\n const [loadedChildren, setLoadedChildren] = useState<Set<string>>(new Set())\n const [nextPageTokens, setNextPageTokens] = useState<\n Record<string, string | undefined>\n >({})\n const [loadingPageTokens, setLoadingPageTokens] = useState<\n Record<string, string | undefined>\n >({})\n const [sorting, setSorting] = useState<SortingState>([])\n const queryClient = useQueryClient()\n const { keyFactory } = useSynapseContext()\n const rootEntityQueryKey = useMemo(\n () => keyFactory.getEntityQueryKey(rootId),\n [keyFactory, rootId],\n )\n\n // Derive sorting parameters from state\n const { sortBy, sortDirection } = useMemo(() => {\n if (!sorting.length) return {}\n\n const firstSort = sorting[0]\n let sortBy: SortBy | undefined\n\n switch (firstSort.id) {\n case 'name':\n sortBy = SortBy.NAME\n break\n case 'createdOn':\n sortBy = SortBy.CREATED_ON\n break\n case 'modifiedOn':\n sortBy = SortBy.MODIFIED_ON\n break\n default:\n return {}\n }\n\n return {\n sortBy,\n sortDirection: firstSort.desc ? Direction.DESC : Direction.ASC,\n }\n }, [sorting])\n\n const rootChildrenRequest: EntityChildrenRequest = useMemo(() => {\n const baseRequest: EntityChildrenRequest = {\n parentId: rootId,\n includeTypes,\n sortBy,\n sortDirection,\n }\n\n return baseRequest\n }, [rootId, sortBy, sortDirection])\n\n const rootChildrenQueryKey = useMemo(\n () => keyFactory.getEntityChildrenQueryKey(rootChildrenRequest, false),\n [keyFactory, rootChildrenRequest],\n )\n\n // Reset tree data when sorting changes\n const resetTreeData = useCallback(() => {\n void queryClient.removeQueries({\n queryKey: rootChildrenQueryKey,\n exact: true,\n })\n\n setTree({})\n setLoadedChildren(new Set())\n setExpanded({})\n setNextPageTokens({})\n setLoadingPageTokens({})\n setLoadingIds(new Set())\n }, [queryClient, rootChildrenQueryKey])\n\n // Get root entity header\n const { data: rootHeader } = useGetEntityHeader(rootId)\n // Get root children - only fetch when we have header and haven't loaded children yet\n const shouldFetchChildren = !!rootHeader && !loadedChildren.has(rootId)\n const { data: rootChildren } = useGetEntityChildren(rootChildrenRequest, {\n enabled: shouldFetchChildren,\n })\n\n // Effect to reset data when sorting changes\n useEffect(() => {\n resetTreeData()\n }, [resetTreeData, sorting])\n\n useEffect(() => {\n const unsubscribe = queryClient.getQueryCache().subscribe(event => {\n if (event?.type === 'updated' && event.action?.type === 'invalidate') {\n // Check if any entity in the tree was invalidated\n const entityIds = Object.keys(tree)\n for (const entityId of entityIds) {\n const entityQueryKey = keyFactory.getEntityQueryKey(entityId)\n if (\n matchQuery({ queryKey: entityQueryKey, exact: false }, event.query)\n ) {\n resetTreeData()\n return\n }\n }\n }\n })\n\n return () => {\n unsubscribe()\n }\n }, [queryClient, rootEntityQueryKey, resetTreeData, tree, keyFactory])\n\n // Effect to initialize root node and its children\n useEffect(() => {\n if (rootHeader && rootChildren && !tree[rootId]) {\n // Build the children nodes from the response\n const children: TreeNode[] = rootChildren.page.map(\n (eh: EntityHeader) => ({\n entityHeader: eh,\n parentId: rootId,\n depth: showRootNode ? 1 : 0,\n isLeaf: !(\n convertToEntityType(eh.type) === EntityType.project ||\n convertToEntityType(eh.type) === EntityType.folder\n ),\n }),\n )\n\n // Create child entries for the tree\n const childEntries = Object.fromEntries(\n children.map(child => [child.entityHeader.id, child]),\n )\n\n // Set up the complete tree state in one go\n setTree({\n [rootId]: {\n entityHeader: rootHeader,\n depth: showRootNode ? 0 : -1,\n isLeaf: false,\n children,\n },\n ...childEntries,\n })\n\n // Set up pagination token\n const rootNext = rootChildren.nextPageToken\n setNextPageTokens({ [rootId]: rootNext })\n\n // Mark as loaded if there's no next page token\n if (!rootNext) {\n setLoadedChildren(new Set([rootId]))\n }\n\n // Expand root node by default if the flag is set\n if (expandRootByDefault) {\n setExpanded(prev => ({ ...prev, [rootId]: true }))\n }\n }\n }, [\n rootHeader,\n rootChildren,\n rootId,\n expandRootByDefault,\n showRootNode,\n tree,\n ])\n\n return {\n // State\n expanded,\n setExpanded,\n tree,\n setTree,\n loadingIds,\n setLoadingIds,\n loadedChildren,\n setLoadedChildren,\n nextPageTokens,\n setNextPageTokens,\n loadingPageTokens,\n setLoadingPageTokens,\n sorting,\n setSorting,\n\n // Derived values\n sortBy,\n sortDirection,\n\n // Data\n rootHeader,\n rootChildren,\n\n // Actions\n resetTreeData,\n }\n}\n"],"mappings":";;;;;;;;;;;AAwBA,IAAM,IAA6B;CACjC,EAAW;CACX,EAAW;CACX,EAAW;CACX,EAAW;CACZ,EAKY,KACX,GACA,GACA,MACG;CAEH,IAAM,CAAC,GAAU,KAAe,EAAkC,EAAE,CAAC,EAC/D,CAAC,GAAM,KAAW,EAAmC,EAAE,CAAC,EACxD,CAAC,GAAY,KAAiB,kBAAsB,IAAI,KAAK,CAAC,EAC9D,CAAC,GAAgB,KAAqB,kBAAsB,IAAI,KAAK,CAAC,EACtE,CAAC,GAAgB,KAAqB,EAE1C,EAAE,CAAC,EACC,CAAC,GAAmB,KAAwB,EAEhD,EAAE,CAAC,EACC,CAAC,GAAS,KAAc,EAAuB,EAAE,CAAC,EAClD,IAAc,GAAgB,EAC9B,EAAE,kBAAe,GAAmB,EACpC,IAAqB,QACnB,EAAW,kBAAkB,EAAO,EAC1C,CAAC,GAAY,EAAO,CACrB,EAGK,EAAE,WAAQ,qBAAkB,QAAc;AAC9C,MAAI,CAAC,EAAQ,OAAQ,QAAO,EAAE;EAE9B,IAAM,IAAY,EAAQ,IACtB;AAEJ,UAAQ,EAAU,IAAlB;GACE,KAAK;AACH,QAAS,EAAO;AAChB;GACF,KAAK;AACH,QAAS,EAAO;AAChB;GACF,KAAK;AACH,QAAS,EAAO;AAChB;GACF,QACE,QAAO,EAAE;;AAGb,SAAO;GACL;GACA,eAAe,EAAU,OAAO,EAAU,OAAO,EAAU;GAC5D;IACA,CAAC,EAAQ,CAAC,EAEP,IAA6C,SAQ1C;EANL,UAAU;EACV;EACA;EACA;EAGK,GACN;EAAC;EAAQ;EAAQ;EAAc,CAAC,EAE7B,IAAuB,QACrB,EAAW,0BAA0B,GAAqB,GAAM,EACtE,CAAC,GAAY,EAAoB,CAClC,EAGK,IAAgB,QAAkB;AAWtC,EAVK,EAAY,cAAc;GAC7B,UAAU;GACV,OAAO;GACR,CAAC,EAEF,EAAQ,EAAE,CAAC,EACX,kBAAkB,IAAI,KAAK,CAAC,EAC5B,EAAY,EAAE,CAAC,EACf,EAAkB,EAAE,CAAC,EACrB,EAAqB,EAAE,CAAC,EACxB,kBAAc,IAAI,KAAK,CAAC;IACvB,CAAC,GAAa,EAAqB,CAAC,EAGjC,EAAE,MAAM,MAAe,EAAmB,EAAO,EAGjD,EAAE,MAAM,MAAiB,EAAqB,GAAqB,EACvE,SAF0B,CAAC,CAAC,KAAc,CAAC,EAAe,IAAI,EAAO,EAGtE,CAAC;AAoFF,QAjFA,QAAgB;AACd,KAAe;IACd,CAAC,GAAe,EAAQ,CAAC,EAE5B,QAAgB;EACd,IAAM,IAAc,EAAY,eAAe,CAAC,WAAU,MAAS;AACjE,OAAI,GAAO,SAAS,aAAa,EAAM,QAAQ,SAAS,cAAc;IAEpE,IAAM,IAAY,OAAO,KAAK,EAAK;AACnC,SAAK,IAAM,KAAY,EAErB,KACE,EAAW;KAAE,UAFQ,EAAW,kBAAkB,EAE3B;KAAgB,OAAO;KAAO,EAAE,EAAM,MAAM,EACnE;AACA,QAAe;AACf;;;IAIN;AAEF,eAAa;AACX,MAAa;;IAEd;EAAC;EAAa;EAAoB;EAAe;EAAM;EAAW,CAAC,EAGtE,QAAgB;AACd,MAAI,KAAc,KAAgB,CAAC,EAAK,IAAS;GAE/C,IAAM,IAAuB,EAAa,KAAK,KAC5C,OAAsB;IACrB,cAAc;IACd,UAAU;IACV,OAAO;IACP,QAAQ,EACN,EAAoB,EAAG,KAAK,KAAK,EAAW,WAC5C,EAAoB,EAAG,KAAK,KAAK,EAAW;IAE/C,EACF,EAGK,IAAe,OAAO,YAC1B,EAAS,KAAI,MAAS,CAAC,EAAM,aAAa,IAAI,EAAM,CAAC,CACtD;AAGD,KAAQ;KACL,IAAS;KACR,cAAc;KACd,OAAO,IAAe,IAAI;KAC1B,QAAQ;KACR;KACD;IACD,GAAG;IACJ,CAAC;GAGF,IAAM,IAAW,EAAa;AAS9B,GARA,EAAkB,GAAG,IAAS,GAAU,CAAC,EAGpC,KACH,EAAkB,IAAI,IAAI,CAAC,EAAO,CAAC,CAAC,EAIlC,KACF,GAAY,OAAS;IAAE,GAAG;KAAO,IAAS;IAAM,EAAE;;IAGrD;EACD;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,EAEK;EAEL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EAGA;EACA;EAGA;EACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"useTableColumns.js","names":[],"sources":["../../../../src/components/EntityTreeTable/hooks/useTableColumns.ts"],"sourcesContent":["import { useMemo } from 'react'\nimport { ColumnDef } from '@tanstack/react-table'\nimport { useTheme, useMediaQuery } from '@mui/material'\nimport { EntityBundleRow } from '../EntityTreeTable'\nimport { NameCell } from '../components/EntityNameCell'\nimport { IdCell } from '../components/IdCell'\nimport { IdColumnHeader } from '../components/IdColumnHeader'\nimport { ModifiedOnCell } from '../../EntityFinder/details/view/table/ModifiedOnCell'\nimport { ModifiedByCell } from '../../EntityFinder/details/view/table/ModifiedByCell'\nimport { CreatedOnCell } from '../../EntityFinder/details/view/table/CreatedOnCell'\nimport { FileEntitySizeCell } from '../../EntityFinder/details/view/table/FileEntitySizeCell'\nimport { FileEntityMD5Cell } from '../../EntityFinder/details/view/table/FileEntityMD5Cell'\nimport { AddFileToDownloadListCell } from '../../EntityFinder/details/view/table/AddToDownloadListCell'\nimport {\n NameColumnHeader,\n CreatedOnColumnHeader,\n ModifiedOnColumnHeader,\n} from '../components/ColumnHeaders'\nimport { EntityBadgeIconsCell } from '../components/EntityBadgeIconsCell'\n\nexport const useTableColumns = (enableSorting: boolean) => {\n // Responsive design hooks\n const theme = useTheme()\n const isXtraLarge = useMediaQuery(theme.breakpoints.up('xl'))\n const isMediumAndUp = useMediaQuery(theme.breakpoints.up('md'))\n\n // Table columns\n const columns = useMemo<ColumnDef<EntityBundleRow>[]>(() => {\n const baseColumns: ColumnDef<EntityBundleRow>[] = [\n {\n accessorKey: 'entityHeader.name',\n id: 'name',\n header: NameColumnHeader,\n cell: NameCell,\n enableSorting: enableSorting,\n size: 450, // Default width for Name column\n },\n ]\n if (isMediumAndUp) {\n baseColumns.push({\n id: 'badges',\n header: '',\n cell: EntityBadgeIconsCell,\n enableSorting: false,\n size: 120, // Default width for Badges column\n })\n baseColumns.push({\n id: 'id',\n header: IdColumnHeader,\n cell: IdCell,\n enableSorting: false,\n })\n }\n if (isXtraLarge) {\n baseColumns.push({\n accessorKey: 'entityHeader.createdOn',\n id: 'createdOn',\n header: CreatedOnColumnHeader,\n cell: CreatedOnCell,\n enableSorting: enableSorting,\n })\n }\n\n if (isMediumAndUp) {\n baseColumns.push({\n accessorKey: 'entityHeader.modifiedOn',\n id: 'modifiedOn',\n header: ModifiedOnColumnHeader,\n cell: ModifiedOnCell,\n enableSorting: enableSorting,\n })\n }\n\n if (isXtraLarge) {\n baseColumns.push({\n id: 'modifiedBy',\n header: 'Modified By',\n cell: ModifiedByCell,\n enableSorting: false,\n })\n }\n\n if (isMediumAndUp) {\n baseColumns.push({\n id: 'size',\n header: 'Size',\n cell: FileEntitySizeCell,\n enableSorting: false,\n })\n }\n if (isXtraLarge) {\n baseColumns.push({\n id: 'md5',\n header: 'MD5',\n cell: FileEntityMD5Cell,\n enableSorting: false,\n })\n }\n\n baseColumns.push({\n id: 'download',\n header: 'Download',\n cell: AddFileToDownloadListCell,\n enableSorting: false,\n size: 90,\n })\n\n return baseColumns\n }, [enableSorting, isXtraLarge, isMediumAndUp])\n\n return columns\n}\n"],"mappings":";;;;;;;;;;;;;;AAoBA,IAAa,KAAmB,MAA2B;CAEzD,IAAM,IAAQ,GAAU,EAClB,IAAc,EAAc,EAAM,YAAY,GAAG,KAAK,CAAC,EACvD,IAAgB,EAAc,EAAM,YAAY,GAAG,KAAK,CAAC;AAsF/D,QAnFgB,QAA4C;EAC1D,IAAM,IAA4C,CAChD;GACE,aAAa;GACb,IAAI;GACJ,QAAQ;GACR,MAAM;GACS;GACf,MAAM;GACP,CACF;AAsED,SArEI,MACF,EAAY,KAAK;GACf,IAAI;GACJ,QAAQ;GACR,MAAM;GACN,eAAe;GACf,MAAM;GACP,CAAC,EACF,EAAY,KAAK;GACf,IAAI;GACJ,QAAQ;GACR,MAAM;GACN,eAAe;GAChB,CAAC,GAEA,KACF,EAAY,KAAK;GACf,aAAa;GACb,IAAI;GACJ,QAAQ;GACR,MAAM;GACS;GAChB,CAAC,EAGA,KACF,EAAY,KAAK;GACf,aAAa;GACb,IAAI;GACJ,QAAQ;GACR,MAAM;GACS;GAChB,CAAC,EAGA,KACF,EAAY,KAAK;GACf,IAAI;GACJ,QAAQ;GACR,MAAM;GACN,eAAe;GAChB,CAAC,EAGA,KACF,EAAY,KAAK;GACf,IAAI;GACJ,QAAQ;GACR,MAAM;GACN,eAAe;GAChB,CAAC,EAEA,KACF,EAAY,KAAK;GACf,IAAI;GACJ,QAAQ;GACR,MAAM;GACN,eAAe;GAChB,CAAC,EAGJ,EAAY,KAAK;GACf,IAAI;GACJ,QAAQ;GACR,MAAM;GACN,eAAe;GACf,MAAM;GACP,CAAC,EAEK;IACN;EAAC;EAAe;EAAa;EAAc,CAAC"}
1
+ {"version":3,"file":"useTableColumns.js","names":[],"sources":["../../../../src/components/EntityTreeTable/hooks/useTableColumns.ts"],"sourcesContent":["import { useMemo } from 'react'\nimport { ColumnDef } from '@tanstack/react-table'\nimport { useTheme, useMediaQuery } from '@mui/material'\nimport { EntityBundleRow } from '../EntityTreeTable'\nimport { NameCell } from '../components/EntityNameCell'\nimport { IdCell } from '../components/IdCell'\nimport { IdColumnHeader } from '../components/IdColumnHeader'\nimport { ModifiedOnCell } from '../../EntityFinder/details/view/table/ModifiedOnCell'\nimport { ModifiedByCell } from '../../EntityFinder/details/view/table/ModifiedByCell'\nimport { CreatedOnCell } from '../../EntityFinder/details/view/table/CreatedOnCell'\nimport { FileEntitySizeCell } from '../../EntityFinder/details/view/table/FileEntitySizeCell'\nimport { FileEntityMD5Cell } from '../../EntityFinder/details/view/table/FileEntityMD5Cell'\nimport { AddFileToDownloadListCell } from '../../EntityFinder/details/view/table/AddToDownloadListCell'\nimport {\n NameColumnHeader,\n CreatedOnColumnHeader,\n ModifiedOnColumnHeader,\n} from '../components/ColumnHeaders'\nimport { EntityBadgeIconsCell } from '../components/EntityBadgeIconsCell'\n\nexport const useTableColumns = (enableSorting: boolean) => {\n // Responsive design hooks\n const theme = useTheme()\n const isXtraLarge = useMediaQuery(theme.breakpoints.up('xl'))\n const isMediumAndUp = useMediaQuery(theme.breakpoints.up('md'))\n\n // Table columns\n const columns = useMemo<ColumnDef<EntityBundleRow>[]>(() => {\n const baseColumns: ColumnDef<EntityBundleRow>[] = [\n {\n accessorKey: 'entityHeader.name',\n id: 'name',\n header: NameColumnHeader,\n cell: NameCell,\n enableSorting: enableSorting,\n size: 450, // Default width for Name column\n },\n ]\n if (isMediumAndUp) {\n baseColumns.push({\n id: 'badges',\n header: '',\n cell: EntityBadgeIconsCell,\n enableSorting: false,\n size: 120, // Default width for Badges column\n })\n baseColumns.push({\n id: 'id',\n header: IdColumnHeader,\n cell: IdCell,\n enableSorting: false,\n })\n }\n if (isXtraLarge) {\n baseColumns.push({\n accessorKey: 'entityHeader.createdOn',\n id: 'createdOn',\n header: CreatedOnColumnHeader,\n cell: CreatedOnCell,\n enableSorting: enableSorting,\n })\n }\n\n if (isMediumAndUp) {\n baseColumns.push({\n accessorKey: 'entityHeader.modifiedOn',\n id: 'modifiedOn',\n header: ModifiedOnColumnHeader,\n cell: ModifiedOnCell,\n enableSorting: enableSorting,\n })\n }\n\n if (isXtraLarge) {\n baseColumns.push({\n id: 'modifiedBy',\n header: 'Modified By',\n cell: ModifiedByCell,\n enableSorting: false,\n })\n }\n\n if (isMediumAndUp) {\n baseColumns.push({\n id: 'size',\n header: 'Size',\n cell: FileEntitySizeCell,\n enableSorting: false,\n })\n }\n if (isXtraLarge) {\n baseColumns.push({\n id: 'md5',\n header: 'MD5',\n cell: FileEntityMD5Cell,\n enableSorting: false,\n })\n }\n\n baseColumns.push({\n id: 'download',\n header: 'Download',\n cell: AddFileToDownloadListCell,\n enableSorting: false,\n size: 90,\n })\n\n return baseColumns\n }, [enableSorting, isXtraLarge, isMediumAndUp])\n\n return columns\n}\n"],"mappings":";;;;;;;;;;;;;;AAoBA,IAAa,KAAmB,MAA2B;CAEzD,IAAM,IAAQ,GAAU,EAClB,IAAc,EAAc,EAAM,YAAY,GAAG,KAAK,CAAC,EACvD,IAAgB,EAAc,EAAM,YAAY,GAAG,KAAK,CAAC;AAsF/D,QAnFgB,QAA4C;EAC1D,IAAM,IAA4C,CAChD;GACE,aAAa;GACb,IAAI;GACJ,QAAQ;GACR,MAAM;GACS;GACf,MAAM;GACP,CACF;AAsED,SArEI,MACF,EAAY,KAAK;GACf,IAAI;GACJ,QAAQ;GACR,MAAM;GACN,eAAe;GACf,MAAM;GACP,CAAC,EACF,EAAY,KAAK;GACf,IAAI;GACJ,QAAQ;GACR,MAAM;GACN,eAAe;GAChB,CAAC,GAEA,KACF,EAAY,KAAK;GACf,aAAa;GACb,IAAI;GACJ,QAAQ;GACR,MAAM;GACS;GAChB,CAAC,EAGA,KACF,EAAY,KAAK;GACf,aAAa;GACb,IAAI;GACJ,QAAQ;GACR,MAAM;GACS;GAChB,CAAC,EAGA,KACF,EAAY,KAAK;GACf,IAAI;GACJ,QAAQ;GACR,MAAM;GACN,eAAe;GAChB,CAAC,EAGA,KACF,EAAY,KAAK;GACf,IAAI;GACJ,QAAQ;GACR,MAAM;GACN,eAAe;GAChB,CAAC,EAEA,KACF,EAAY,KAAK;GACf,IAAI;GACJ,QAAQ;GACR,MAAM;GACN,eAAe;GAChB,CAAC,EAGJ,EAAY,KAAK;GACf,IAAI;GACJ,QAAQ;GACR,MAAM;GACN,eAAe;GACf,MAAM;GACP,CAAC,EAEK;IACN;EAAC;EAAe;EAAa;EAAc,CAEvC"}
@@ -1 +1 @@
1
- {"version":3,"file":"useTableData.js","names":[],"sources":["../../../../src/components/EntityTreeTable/hooks/useTableData.ts"],"sourcesContent":["import { useMemo } from 'react'\nimport { EntityBundleRow } from '../EntityTreeTable'\nimport { TreeNode } from './useEntityTreeState'\n\nexport const useTableData = (\n tree: Record<string, TreeNode>,\n rootId: string,\n showRootNode: boolean,\n expanded: Record<string, boolean>,\n nextPageTokens: Record<string, string | undefined>,\n flattenTree: (nodeId: string, visited?: Set<string>) => EntityBundleRow[],\n) => {\n const rows: EntityBundleRow[] = useMemo(() => {\n const rootNode = tree[rootId]\n if (!rootNode) return []\n\n if (showRootNode) {\n return flattenTree(rootId, new Set<string>())\n } else {\n // If root node is not shown, start with its children\n const rows: EntityBundleRow[] = []\n if (expanded[rootId] && rootNode.children) {\n rootNode.children.forEach(child => {\n const childRows = flattenTree(\n child.entityHeader.id,\n new Set<string>(),\n )\n rows.push(...childRows)\n })\n // If there is a next page token for the root, add a synthetic 'Load more' row\n const nextToken = nextPageTokens[rootId]\n if (nextToken) {\n rows.push({\n entityId: '', // Empty placeholder for load more rows\n entityHeader: rootNode.entityHeader,\n depth: 0,\n isLeaf: true,\n parentId: rootId,\n versionNumber: rootNode.entityHeader.versionNumber,\n isLoadMore: true,\n pageToken: nextToken,\n })\n }\n }\n return rows\n }\n }, [tree, rootId, flattenTree, showRootNode, expanded, nextPageTokens])\n\n return rows\n}\n"],"mappings":";;AAIA,IAAa,KACX,GACA,GACA,GACA,GACA,GACA,MAEgC,QAAc;CAC5C,IAAM,IAAW,EAAK;AACtB,KAAI,CAAC,EAAU,QAAO,EAAE;AAExB,KAAI,EACF,QAAO,EAAY,mBAAQ,IAAI,KAAa,CAAC;CACxC;EAEL,IAAM,IAA0B,EAAE;AAClC,MAAI,EAAS,MAAW,EAAS,UAAU;AACzC,KAAS,SAAS,SAAQ,MAAS;IACjC,IAAM,IAAY,EAChB,EAAM,aAAa,oBACnB,IAAI,KAAa,CAClB;AACD,MAAK,KAAK,GAAG,EAAU;KACvB;GAEF,IAAM,IAAY,EAAe;AACjC,GAAI,KACF,EAAK,KAAK;IACR,UAAU;IACV,cAAc,EAAS;IACvB,OAAO;IACP,QAAQ;IACR,UAAU;IACV,eAAe,EAAS,aAAa;IACrC,YAAY;IACZ,WAAW;IACZ,CAAC;;AAGN,SAAO;;GAER;CAAC;CAAM;CAAQ;CAAa;CAAc;CAAU;CAAe,CAAC"}
1
+ {"version":3,"file":"useTableData.js","names":[],"sources":["../../../../src/components/EntityTreeTable/hooks/useTableData.ts"],"sourcesContent":["import { useMemo } from 'react'\nimport { EntityBundleRow } from '../EntityTreeTable'\nimport { TreeNode } from './useEntityTreeState'\n\nexport const useTableData = (\n tree: Record<string, TreeNode>,\n rootId: string,\n showRootNode: boolean,\n expanded: Record<string, boolean>,\n nextPageTokens: Record<string, string | undefined>,\n flattenTree: (nodeId: string, visited?: Set<string>) => EntityBundleRow[],\n) => {\n const rows: EntityBundleRow[] = useMemo(() => {\n const rootNode = tree[rootId]\n if (!rootNode) return []\n\n if (showRootNode) {\n return flattenTree(rootId, new Set<string>())\n } else {\n // If root node is not shown, start with its children\n const rows: EntityBundleRow[] = []\n if (expanded[rootId] && rootNode.children) {\n rootNode.children.forEach(child => {\n const childRows = flattenTree(\n child.entityHeader.id,\n new Set<string>(),\n )\n rows.push(...childRows)\n })\n // If there is a next page token for the root, add a synthetic 'Load more' row\n const nextToken = nextPageTokens[rootId]\n if (nextToken) {\n rows.push({\n entityId: '', // Empty placeholder for load more rows\n entityHeader: rootNode.entityHeader,\n depth: 0,\n isLeaf: true,\n parentId: rootId,\n versionNumber: rootNode.entityHeader.versionNumber,\n isLoadMore: true,\n pageToken: nextToken,\n })\n }\n }\n return rows\n }\n }, [tree, rootId, flattenTree, showRootNode, expanded, nextPageTokens])\n\n return rows\n}\n"],"mappings":";;AAIA,IAAa,KACX,GACA,GACA,GACA,GACA,GACA,MAEgC,QAAc;CAC5C,IAAM,IAAW,EAAK;AACtB,KAAI,CAAC,EAAU,QAAO,EAAE;AAExB,KAAI,EACF,QAAO,EAAY,mBAAQ,IAAI,KAAa,CAAC;CACxC;EAEL,IAAM,IAA0B,EAAE;AAClC,MAAI,EAAS,MAAW,EAAS,UAAU;AACzC,KAAS,SAAS,SAAQ,MAAS;IACjC,IAAM,IAAY,EAChB,EAAM,aAAa,oBACnB,IAAI,KAAa,CAClB;AACD,MAAK,KAAK,GAAG,EAAU;KACvB;GAEF,IAAM,IAAY,EAAe;AACjC,GAAI,KACF,EAAK,KAAK;IACR,UAAU;IACV,cAAc,EAAS;IACvB,OAAO;IACP,QAAQ;IACR,UAAU;IACV,eAAe,EAAS,aAAa;IACrC,YAAY;IACZ,WAAW;IACZ,CAAC;;AAGN,SAAO;;GAER;CAAC;CAAM;CAAQ;CAAa;CAAc;CAAU;CAAe,CAE/D"}
@@ -1 +1 @@
1
- {"version":3,"file":"useTreeOperationsWithDirectFetch.js","names":[],"sources":["../../../../src/components/EntityTreeTable/hooks/useTreeOperationsWithDirectFetch.ts"],"sourcesContent":["import { useCallback } from 'react'\nimport { EntityBundleRow } from '../EntityTreeTable'\nimport { TreeNode } from './useEntityTreeState'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport SynapseClient from '@/synapse-client'\nimport { EntityType } from '@sage-bionetworks/synapse-client'\nimport {\n EntityHeader,\n SortBy,\n Direction,\n} from '@sage-bionetworks/synapse-types'\nimport {\n convertToEntityType,\n isContainerType,\n} from '@/utils/functions/EntityTypeUtils'\nimport { omit } from 'lodash-es'\n\nconst includeTypes: EntityType[] = [\n EntityType.folder,\n EntityType.file,\n EntityType.link,\n EntityType.recordset,\n]\n\nexport const useTreeOperationsWithDirectFetch = (\n expanded: Record<string, boolean>,\n setExpanded: (value: React.SetStateAction<Record<string, boolean>>) => void,\n tree: Record<string, TreeNode>,\n setTree: (value: React.SetStateAction<Record<string, TreeNode>>) => void,\n loadedChildren: Set<string>,\n setLoadedChildren: (value: React.SetStateAction<Set<string>>) => void,\n loadingIds: Set<string>,\n setLoadingIds: (value: React.SetStateAction<Set<string>>) => void,\n setNextPageTokens: (\n value: React.SetStateAction<Record<string, string | undefined>>,\n ) => void,\n setLoadingPageTokens: (\n value: React.SetStateAction<Record<string, string | undefined>>,\n ) => void,\n loadingPageTokens: Record<string, string | undefined>,\n nextPageTokens: Record<string, string | undefined>,\n sortBy?: SortBy,\n sortDirection?: Direction,\n) => {\n const queryClient = useQueryClient()\n const { accessToken, keyFactory } = useSynapseContext()\n\n // Helper function to convert EntityHeaders to TreeNodes\n const createTreeNodes = useCallback(\n (\n entityHeaders: EntityHeader[],\n parentId: string,\n parentDepth: number,\n ): TreeNode[] => {\n return entityHeaders.map((eh: EntityHeader) => ({\n entityHeader: eh,\n parentId,\n depth: parentDepth + 1,\n isLeaf: !isContainerType(convertToEntityType(eh.type)),\n }))\n },\n [],\n )\n\n // Helper function to clean up loading state on error\n const cleanupLoadingState = useCallback(\n (entityId: string, pageToken?: string) => {\n setLoadingIds(prev => {\n const next = new Set(prev)\n next.delete(entityId)\n return next\n })\n\n if (pageToken !== undefined) {\n setLoadingPageTokens(prev => {\n return omit(prev, [entityId])\n })\n }\n },\n [setLoadingIds, setLoadingPageTokens],\n )\n\n // Helper function to fetch entity children\n const fetchEntityChildren = useCallback(\n async (entityId: string, pageToken?: string) => {\n const entityChildrenRequest = {\n parentId: entityId,\n includeTypes,\n ...(pageToken && { nextPageToken: pageToken }),\n sortBy,\n sortDirection,\n }\n\n return await queryClient.fetchQuery({\n queryKey: keyFactory.getEntityChildrenQueryKey(\n entityChildrenRequest,\n false,\n ),\n queryFn: () =>\n SynapseClient.getEntityChildren(entityChildrenRequest, accessToken),\n })\n },\n [queryClient, keyFactory, accessToken, sortBy, sortDirection],\n )\n\n // Callback to handle when children are loaded - moved before handleToggleExpanded to fix dependency order\n const handleChildrenLoaded = useCallback(\n (entityId: string, children: TreeNode[], nextPageToken?: string) => {\n setTree(prev => {\n const node = prev[entityId]\n if (node) {\n // Set correct depth for child nodes\n const childNodesWithDepth = children.map(child => ({\n ...child,\n depth: node.depth + 1,\n }))\n\n const mergedChildren = [\n ...(node.children || []),\n ...childNodesWithDepth,\n ]\n\n // Merge children into the tree mapping while preserving existing\n // subtree entries for those children (so expanding deeper nodes\n // isn't lost when siblings are added).\n const mergedChildEntries = Object.fromEntries(\n mergedChildren.map(child => {\n const existing = prev[child.entityHeader.id]\n const merged = {\n ...existing,\n ...child,\n depth: child.depth,\n parentId: child.parentId,\n isLeaf: child.isLeaf,\n }\n\n return [child.entityHeader.id, merged]\n }),\n )\n\n return {\n ...prev,\n [entityId]: {\n ...node,\n children: mergedChildren,\n },\n ...mergedChildEntries,\n }\n }\n return prev\n })\n\n // store nextPageToken for this parent (if any)\n setNextPageTokens(prev => ({ ...prev, [entityId]: nextPageToken }))\n // clear the loading page token entry for this parent since the\n // requested page has completed (this prevents any remaining loading state)\n setLoadingPageTokens(prev => {\n return omit(prev, [entityId])\n })\n\n setLoadingIds(prev => {\n const next = new Set(prev)\n next.delete(entityId)\n return next\n })\n\n // mark as loaded only if there is no next page token (i.e., fully loaded)\n if (!nextPageToken) {\n setLoadedChildren(prev => new Set(prev).add(entityId))\n }\n },\n [\n loadingPageTokens,\n setTree,\n setNextPageTokens,\n setLoadingPageTokens,\n setLoadingIds,\n setLoadedChildren,\n ],\n )\n\n // Handler for expanding nodes - handles fetching children\n const handleToggleExpanded = useCallback(\n async (entityId: string) => {\n const isCurrentlyExpanded = expanded[entityId]\n\n setExpanded(prev => ({\n ...prev,\n [entityId]: !prev[entityId],\n }))\n\n // If expanding and children haven't been loaded yet, fetch them directly\n if (\n !isCurrentlyExpanded &&\n !loadedChildren.has(entityId) &&\n !loadingIds.has(entityId)\n ) {\n const node = tree[entityId]\n if (node && !node.isLeaf) {\n setLoadingIds(prev => new Set(prev).add(entityId))\n\n try {\n const children = await fetchEntityChildren(entityId)\n const childNodes = createTreeNodes(\n children.page,\n entityId,\n node.depth,\n )\n handleChildrenLoaded(entityId, childNodes, children.nextPageToken)\n } catch (error) {\n console.error(\n 'Failed to fetch children for entity:',\n entityId,\n error,\n )\n cleanupLoadingState(entityId)\n }\n }\n }\n },\n [\n expanded,\n loadedChildren,\n tree,\n setExpanded,\n setLoadingIds,\n fetchEntityChildren,\n createTreeNodes,\n handleChildrenLoaded,\n cleanupLoadingState,\n ],\n )\n\n const loadMoreChildren = useCallback(\n async (entityId: string, pageToken?: string) => {\n // set which page token is being requested for this parent and mark loading\n setLoadingPageTokens(prev => ({ ...prev, [entityId]: pageToken }))\n setLoadingIds(prev => new Set(prev).add(entityId))\n\n try {\n const children = await fetchEntityChildren(entityId, pageToken)\n const node = tree[entityId]\n const childNodes = createTreeNodes(\n children.page,\n entityId,\n node ? node.depth : -1,\n )\n handleChildrenLoaded(entityId, childNodes, children.nextPageToken)\n } catch (error) {\n console.error(\n 'Failed to load more children for entity:',\n entityId,\n error,\n )\n cleanupLoadingState(entityId, pageToken)\n }\n },\n [\n setLoadingPageTokens,\n setLoadingIds,\n fetchEntityChildren,\n createTreeNodes,\n tree,\n handleChildrenLoaded,\n cleanupLoadingState,\n ],\n )\n\n // Flatten tree for table rows. Track visited node ids to avoid cycles and\n // duplicate rows when the same entity appears multiple times in the\n // traversal (links, cycles, or bad/multiple parent relationships).\n const flattenTree = useCallback(\n (nodeId: string, visited = new Set<string>()): EntityBundleRow[] => {\n // Prevent revisiting the same node and producing duplicate rows\n if (visited.has(nodeId)) return []\n visited.add(nodeId)\n\n const node = tree[nodeId]\n if (!node) return []\n\n const rows: EntityBundleRow[] = [\n {\n entityId: node.entityHeader.id,\n entityHeader: node.entityHeader,\n depth: node.depth,\n isLeaf: node.isLeaf,\n parentId: node.parentId,\n versionNumber: node.entityHeader.versionNumber,\n },\n ]\n\n if (expanded[node.entityHeader.id] && node.children) {\n node.children.forEach(child => {\n rows.push(...flattenTree(child.entityHeader.id, visited))\n })\n // If there is a next page token for this node, add a synthetic 'Load more' row\n const nextToken = nextPageTokens[node.entityHeader.id]\n\n if (nextToken) {\n rows.push({\n entityId: '', // Empty placeholder for load more rows\n entityHeader: node.entityHeader,\n depth: node.depth + 1,\n isLeaf: true,\n parentId: node.entityHeader.id,\n versionNumber: node.entityHeader.versionNumber,\n isLoadMore: true,\n pageToken: nextToken,\n })\n }\n }\n return rows\n },\n [expanded, tree, nextPageTokens],\n )\n\n return {\n handleToggleExpanded,\n handleChildrenLoaded,\n loadMoreChildren,\n flattenTree,\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"useTreeOperationsWithDirectFetch.js","names":[],"sources":["../../../../src/components/EntityTreeTable/hooks/useTreeOperationsWithDirectFetch.ts"],"sourcesContent":["import { useCallback } from 'react'\nimport { EntityBundleRow } from '../EntityTreeTable'\nimport { TreeNode } from './useEntityTreeState'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport SynapseClient from '@/synapse-client'\nimport { EntityType } from '@sage-bionetworks/synapse-client'\nimport {\n EntityHeader,\n SortBy,\n Direction,\n} from '@sage-bionetworks/synapse-types'\nimport {\n convertToEntityType,\n isContainerType,\n} from '@/utils/functions/EntityTypeUtils'\nimport { omit } from 'lodash-es'\n\nconst includeTypes: EntityType[] = [\n EntityType.folder,\n EntityType.file,\n EntityType.link,\n EntityType.recordset,\n]\n\nexport const useTreeOperationsWithDirectFetch = (\n expanded: Record<string, boolean>,\n setExpanded: (value: React.SetStateAction<Record<string, boolean>>) => void,\n tree: Record<string, TreeNode>,\n setTree: (value: React.SetStateAction<Record<string, TreeNode>>) => void,\n loadedChildren: Set<string>,\n setLoadedChildren: (value: React.SetStateAction<Set<string>>) => void,\n loadingIds: Set<string>,\n setLoadingIds: (value: React.SetStateAction<Set<string>>) => void,\n setNextPageTokens: (\n value: React.SetStateAction<Record<string, string | undefined>>,\n ) => void,\n setLoadingPageTokens: (\n value: React.SetStateAction<Record<string, string | undefined>>,\n ) => void,\n loadingPageTokens: Record<string, string | undefined>,\n nextPageTokens: Record<string, string | undefined>,\n sortBy?: SortBy,\n sortDirection?: Direction,\n) => {\n const queryClient = useQueryClient()\n const { accessToken, keyFactory } = useSynapseContext()\n\n // Helper function to convert EntityHeaders to TreeNodes\n const createTreeNodes = useCallback(\n (\n entityHeaders: EntityHeader[],\n parentId: string,\n parentDepth: number,\n ): TreeNode[] => {\n return entityHeaders.map((eh: EntityHeader) => ({\n entityHeader: eh,\n parentId,\n depth: parentDepth + 1,\n isLeaf: !isContainerType(convertToEntityType(eh.type)),\n }))\n },\n [],\n )\n\n // Helper function to clean up loading state on error\n const cleanupLoadingState = useCallback(\n (entityId: string, pageToken?: string) => {\n setLoadingIds(prev => {\n const next = new Set(prev)\n next.delete(entityId)\n return next\n })\n\n if (pageToken !== undefined) {\n setLoadingPageTokens(prev => {\n return omit(prev, [entityId])\n })\n }\n },\n [setLoadingIds, setLoadingPageTokens],\n )\n\n // Helper function to fetch entity children\n const fetchEntityChildren = useCallback(\n async (entityId: string, pageToken?: string) => {\n const entityChildrenRequest = {\n parentId: entityId,\n includeTypes,\n ...(pageToken && { nextPageToken: pageToken }),\n sortBy,\n sortDirection,\n }\n\n return await queryClient.fetchQuery({\n queryKey: keyFactory.getEntityChildrenQueryKey(\n entityChildrenRequest,\n false,\n ),\n queryFn: () =>\n SynapseClient.getEntityChildren(entityChildrenRequest, accessToken),\n })\n },\n [queryClient, keyFactory, accessToken, sortBy, sortDirection],\n )\n\n // Callback to handle when children are loaded - moved before handleToggleExpanded to fix dependency order\n const handleChildrenLoaded = useCallback(\n (entityId: string, children: TreeNode[], nextPageToken?: string) => {\n setTree(prev => {\n const node = prev[entityId]\n if (node) {\n // Set correct depth for child nodes\n const childNodesWithDepth = children.map(child => ({\n ...child,\n depth: node.depth + 1,\n }))\n\n const mergedChildren = [\n ...(node.children || []),\n ...childNodesWithDepth,\n ]\n\n // Merge children into the tree mapping while preserving existing\n // subtree entries for those children (so expanding deeper nodes\n // isn't lost when siblings are added).\n const mergedChildEntries = Object.fromEntries(\n mergedChildren.map(child => {\n const existing = prev[child.entityHeader.id]\n const merged = {\n ...existing,\n ...child,\n depth: child.depth,\n parentId: child.parentId,\n isLeaf: child.isLeaf,\n }\n\n return [child.entityHeader.id, merged]\n }),\n )\n\n return {\n ...prev,\n [entityId]: {\n ...node,\n children: mergedChildren,\n },\n ...mergedChildEntries,\n }\n }\n return prev\n })\n\n // store nextPageToken for this parent (if any)\n setNextPageTokens(prev => ({ ...prev, [entityId]: nextPageToken }))\n // clear the loading page token entry for this parent since the\n // requested page has completed (this prevents any remaining loading state)\n setLoadingPageTokens(prev => {\n return omit(prev, [entityId])\n })\n\n setLoadingIds(prev => {\n const next = new Set(prev)\n next.delete(entityId)\n return next\n })\n\n // mark as loaded only if there is no next page token (i.e., fully loaded)\n if (!nextPageToken) {\n setLoadedChildren(prev => new Set(prev).add(entityId))\n }\n },\n [\n loadingPageTokens,\n setTree,\n setNextPageTokens,\n setLoadingPageTokens,\n setLoadingIds,\n setLoadedChildren,\n ],\n )\n\n // Handler for expanding nodes - handles fetching children\n const handleToggleExpanded = useCallback(\n async (entityId: string) => {\n const isCurrentlyExpanded = expanded[entityId]\n\n setExpanded(prev => ({\n ...prev,\n [entityId]: !prev[entityId],\n }))\n\n // If expanding and children haven't been loaded yet, fetch them directly\n if (\n !isCurrentlyExpanded &&\n !loadedChildren.has(entityId) &&\n !loadingIds.has(entityId)\n ) {\n const node = tree[entityId]\n if (node && !node.isLeaf) {\n setLoadingIds(prev => new Set(prev).add(entityId))\n\n try {\n const children = await fetchEntityChildren(entityId)\n const childNodes = createTreeNodes(\n children.page,\n entityId,\n node.depth,\n )\n handleChildrenLoaded(entityId, childNodes, children.nextPageToken)\n } catch (error) {\n console.error(\n 'Failed to fetch children for entity:',\n entityId,\n error,\n )\n cleanupLoadingState(entityId)\n }\n }\n }\n },\n [\n expanded,\n loadedChildren,\n tree,\n setExpanded,\n setLoadingIds,\n fetchEntityChildren,\n createTreeNodes,\n handleChildrenLoaded,\n cleanupLoadingState,\n ],\n )\n\n const loadMoreChildren = useCallback(\n async (entityId: string, pageToken?: string) => {\n // set which page token is being requested for this parent and mark loading\n setLoadingPageTokens(prev => ({ ...prev, [entityId]: pageToken }))\n setLoadingIds(prev => new Set(prev).add(entityId))\n\n try {\n const children = await fetchEntityChildren(entityId, pageToken)\n const node = tree[entityId]\n const childNodes = createTreeNodes(\n children.page,\n entityId,\n node ? node.depth : -1,\n )\n handleChildrenLoaded(entityId, childNodes, children.nextPageToken)\n } catch (error) {\n console.error(\n 'Failed to load more children for entity:',\n entityId,\n error,\n )\n cleanupLoadingState(entityId, pageToken)\n }\n },\n [\n setLoadingPageTokens,\n setLoadingIds,\n fetchEntityChildren,\n createTreeNodes,\n tree,\n handleChildrenLoaded,\n cleanupLoadingState,\n ],\n )\n\n // Flatten tree for table rows. Track visited node ids to avoid cycles and\n // duplicate rows when the same entity appears multiple times in the\n // traversal (links, cycles, or bad/multiple parent relationships).\n const flattenTree = useCallback(\n (nodeId: string, visited = new Set<string>()): EntityBundleRow[] => {\n // Prevent revisiting the same node and producing duplicate rows\n if (visited.has(nodeId)) return []\n visited.add(nodeId)\n\n const node = tree[nodeId]\n if (!node) return []\n\n const rows: EntityBundleRow[] = [\n {\n entityId: node.entityHeader.id,\n entityHeader: node.entityHeader,\n depth: node.depth,\n isLeaf: node.isLeaf,\n parentId: node.parentId,\n versionNumber: node.entityHeader.versionNumber,\n },\n ]\n\n if (expanded[node.entityHeader.id] && node.children) {\n node.children.forEach(child => {\n rows.push(...flattenTree(child.entityHeader.id, visited))\n })\n // If there is a next page token for this node, add a synthetic 'Load more' row\n const nextToken = nextPageTokens[node.entityHeader.id]\n\n if (nextToken) {\n rows.push({\n entityId: '', // Empty placeholder for load more rows\n entityHeader: node.entityHeader,\n depth: node.depth + 1,\n isLeaf: true,\n parentId: node.entityHeader.id,\n versionNumber: node.entityHeader.versionNumber,\n isLoadMore: true,\n pageToken: nextToken,\n })\n }\n }\n return rows\n },\n [expanded, tree, nextPageTokens],\n )\n\n return {\n handleToggleExpanded,\n handleChildrenLoaded,\n loadMoreChildren,\n flattenTree,\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"EntityUpload.js","names":[],"sources":["../../../src/components/EntityUpload/EntityUpload.tsx"],"sourcesContent":["import MultiFileUploadProgress from '@/components/file/upload/MultiFileUploadProgress'\nimport UploadFilePanel from '@/components/file/upload/UploadFilePanel'\nimport { SYNAPSE_STORAGE_LOCATION_ID } from '@/synapse-client/index'\nimport { useGetDefaultUploadDestination, useGetEntity } from '@/synapse-queries'\nimport { getUploadDestinationString } from '@/utils/functions/FileHandleUtils'\nimport {\n EntityUploaderState,\n useUploadFileEntities,\n} from '@/utils/hooks/useUploadFileEntity/useUploadFileEntities'\nimport { Typography } from '@mui/material'\nimport { noop } from 'lodash-es'\nimport {\n ForwardedRef,\n forwardRef,\n useEffect,\n useImperativeHandle,\n useState,\n} from 'react'\nimport FullWidthAlert from '../FullWidthAlert/FullWidthAlert'\nimport { displayToast } from '../ToastMessage/ToastMessage'\nimport { EntityUploadPromptDialog } from './EntityUploadPromptDialog'\nimport { ExternalObjectStoreCredentialsForm } from './ExternalObjectStoreCredentialsForm'\nimport { ProjectStorageLimitAlert } from './ProjectStorageLimitAlert'\n\nexport type EntityUploadProps = {\n /** The ID of the entity to upload to. If this is a container, file(s) will be added as children. If this is a\n * FileEntity, then a file may be uploaded as a new version */\n entityId: string\n /** Callback that is invoked when the state of the uploader changes */\n onStateChange?: (state: EntityUploaderState) => void\n /** Callback that is invoked when component is ready to upload */\n onUploadReady?: () => void\n}\n\nexport type EntityUploadHandle = {\n /** Programmatically add files to the upload (e.g. on drag & drop) */\n handleUploads: (fileList: ArrayLike<File>) => void\n}\n\nexport const EntityUpload = forwardRef(function EntityUpload(\n props: EntityUploadProps,\n ref: ForwardedRef<EntityUploadHandle>,\n) {\n const { entityId, onStateChange = noop, onUploadReady = noop } = props\n\n const { data: entity, isLoading: isLoadingEntity } = useGetEntity(entityId)\n\n const isFileEntity =\n entity?.concreteType === 'org.sagebionetworks.repo.model.FileEntity'\n\n const { data: uploadDestination, isLoading: isLoadingUploadDestination } =\n useGetDefaultUploadDestination(entityId)\n const isLoading = isLoadingEntity || isLoadingUploadDestination\n\n const [accessKey, setAccessKey] = useState('')\n const [secretKey, setSecretKey] = useState('')\n\n const [didUploadsExceedStorageLimit, setDidUploadsExceedStorageLimit] =\n useState(false)\n\n const {\n initiateUpload,\n state,\n uploadProgress,\n activePrompts,\n isPrecheckingUpload,\n isUploadReady,\n } = useUploadFileEntities(entityId, accessKey, secretKey, () =>\n setDidUploadsExceedStorageLimit(true),\n )\n\n useEffect(() => {\n onStateChange(state)\n }, [state, onStateChange])\n\n useEffect(() => {\n if (isUploadReady) {\n onUploadReady()\n }\n }, [isUploadReady, onUploadReady])\n\n function uploadFileList(fileList: ArrayLike<File>) {\n if (uploadDestination?.projectStorageLocationUsage?.isOverLimit) {\n displayToast(\n 'Cannot upload files because the storage limit has been exceeded.',\n 'danger',\n )\n return\n }\n const args = Array.from(fileList).map(file => {\n if (isFileEntity) {\n return { file, existingEntityId: entityId }\n }\n return {\n file,\n rootContainerId: entityId,\n }\n })\n initiateUpload(args)\n }\n\n useImperativeHandle(ref, () => ({\n handleUploads: uploadFileList,\n }))\n\n const showLoading = isPrecheckingUpload || isLoading\n const loadingText = isPrecheckingUpload\n ? 'Preparing files for upload...'\n : 'Loading...'\n\n return (\n <div>\n <EntityUploadPromptDialog activePrompts={activePrompts} />\n {uploadDestination?.projectStorageLocationUsage && (\n <ProjectStorageLimitAlert\n usage={uploadDestination.projectStorageLocationUsage}\n didUploadsExceedLimit={didUploadsExceedStorageLimit}\n />\n )}\n <ExternalObjectStoreCredentialsForm\n uploadDestination={uploadDestination}\n accessKey={accessKey}\n setAccessKey={setAccessKey}\n secretKey={secretKey}\n setSecretKey={setSecretKey}\n />\n <UploadFilePanel\n onUploadFileList={uploadFileList}\n allowMultipleFiles={!isFileEntity}\n isLoading={showLoading}\n loadingText={loadingText}\n disabled={uploadDestination?.projectStorageLocationUsage?.isOverLimit}\n message={\n <>\n <Typography variant={'smallText1'}>\n All uploaded files will be stored in\n {uploadDestination?.storageLocationId ===\n SYNAPSE_STORAGE_LOCATION_ID && ' Synapse storage'}\n {uploadDestination &&\n uploadDestination?.storageLocationId !==\n SYNAPSE_STORAGE_LOCATION_ID && (\n <>\n :<br />\n {getUploadDestinationString(uploadDestination)}\n </>\n )}\n </Typography>\n {uploadDestination && uploadDestination.banner && (\n <FullWidthAlert\n sx={{\n textAlign: 'left',\n }}\n isGlobal={false}\n title={'Storage Location Message'}\n description={uploadDestination.banner}\n variant={'info'}\n />\n )}\n </>\n }\n />\n <MultiFileUploadProgress\n uploaderState={state}\n uploadProgress={uploadProgress}\n />\n </div>\n )\n})\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAuCA,IAAa,IAAe,EAAW,SACrC,GACA,GACA;CACA,IAAM,EAAE,aAAU,mBAAgB,GAAM,mBAAgB,MAAS,GAE3D,EAAE,MAAM,GAAQ,WAAW,MAAoB,EAAa,EAAS,EAErE,IACJ,GAAQ,iBAAiB,6CAErB,EAAE,MAAM,GAAmB,WAAW,MAC1C,EAA+B,EAAS,EACpC,IAAY,KAAmB,GAE/B,CAAC,GAAW,KAAgB,EAAS,GAAG,EACxC,CAAC,GAAW,KAAgB,EAAS,GAAG,EAExC,CAAC,GAA8B,KACnC,EAAS,GAAM,EAEX,EACJ,mBACA,UACA,mBACA,kBACA,wBACA,qBACE,EAAsB,GAAU,GAAW,SAC7C,EAAgC,GAAK,CACtC;AAMD,CAJA,QAAgB;AACd,IAAc,EAAM;IACnB,CAAC,GAAO,EAAc,CAAC,EAE1B,QAAgB;AACd,EAAI,KACF,GAAe;IAEhB,CAAC,GAAe,EAAc,CAAC;CAElC,SAAS,EAAe,GAA2B;AACjD,MAAI,GAAmB,6BAA6B,aAAa;AAC/D,KACE,oEACA,SACD;AACD;;AAWF,IATa,MAAM,KAAK,EAAS,CAAC,KAAI,MAChC,IACK;GAAE;GAAM,kBAAkB;GAAU,GAEtC;GACL;GACA,iBAAiB;GAClB,CACD,CACkB;;AAGtB,GAAoB,UAAY,EAC9B,eAAe,GAChB,EAAE;CAEH,IAAM,IAAc,KAAuB,GACrC,IAAc,IAChB,kCACA;AAEJ,QACE,kBAAC,OAAD,EAAA,UAAA;EACE,kBAAC,GAAD,EAAyC,kBAAiB,CAAA;EACzD,GAAmB,+BAClB,kBAAC,GAAD;GACE,OAAO,EAAkB;GACzB,uBAAuB;GACvB,CAAA;EAEJ,kBAAC,GAAD;GACqB;GACR;GACG;GACH;GACG;GACd,CAAA;EACF,kBAAC,GAAD;GACE,kBAAkB;GAClB,oBAAoB,CAAC;GACrB,WAAW;GACE;GACb,UAAU,GAAmB,6BAA6B;GAC1D,SACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;IAAY,SAAS;cAArB;KAAmC;KAEhC,GAAmB,sBAAA,KACa;KAChC,KACC,GAAmB,sBAAA,KAEjB,kBAAA,GAAA,EAAA,UAAA;MAAE;MACC,kBAAC,MAAD,EAAM,CAAA;MACN,EAA2B,EAAkB;MAC7C,EAAA,CAAA;KAEI;OACZ,KAAqB,EAAkB,UACtC,kBAAC,GAAD;IACE,IAAI,EACF,WAAW,QACZ;IACD,UAAU;IACV,OAAO;IACP,aAAa,EAAkB;IAC/B,SAAS;IACT,CAAA,CAEH,EAAA,CAAA;GAEL,CAAA;EACF,kBAAC,GAAD;GACE,eAAe;GACC;GAChB,CAAA;EACE,EAAA,CAAA;EAER"}
1
+ {"version":3,"file":"EntityUpload.js","names":[],"sources":["../../../src/components/EntityUpload/EntityUpload.tsx"],"sourcesContent":["import MultiFileUploadProgress from '@/components/file/upload/MultiFileUploadProgress'\nimport UploadFilePanel from '@/components/file/upload/UploadFilePanel'\nimport { SYNAPSE_STORAGE_LOCATION_ID } from '@/synapse-client/index'\nimport { useGetDefaultUploadDestination, useGetEntity } from '@/synapse-queries'\nimport { getUploadDestinationString } from '@/utils/functions/FileHandleUtils'\nimport {\n EntityUploaderState,\n useUploadFileEntities,\n} from '@/utils/hooks/useUploadFileEntity/useUploadFileEntities'\nimport { Typography } from '@mui/material'\nimport { noop } from 'lodash-es'\nimport {\n ForwardedRef,\n forwardRef,\n useEffect,\n useImperativeHandle,\n useState,\n} from 'react'\nimport FullWidthAlert from '../FullWidthAlert/FullWidthAlert'\nimport { displayToast } from '../ToastMessage/ToastMessage'\nimport { EntityUploadPromptDialog } from './EntityUploadPromptDialog'\nimport { ExternalObjectStoreCredentialsForm } from './ExternalObjectStoreCredentialsForm'\nimport { ProjectStorageLimitAlert } from './ProjectStorageLimitAlert'\n\nexport type EntityUploadProps = {\n /** The ID of the entity to upload to. If this is a container, file(s) will be added as children. If this is a\n * FileEntity, then a file may be uploaded as a new version */\n entityId: string\n /** Callback that is invoked when the state of the uploader changes */\n onStateChange?: (state: EntityUploaderState) => void\n /** Callback that is invoked when component is ready to upload */\n onUploadReady?: () => void\n}\n\nexport type EntityUploadHandle = {\n /** Programmatically add files to the upload (e.g. on drag & drop) */\n handleUploads: (fileList: ArrayLike<File>) => void\n}\n\nexport const EntityUpload = forwardRef(function EntityUpload(\n props: EntityUploadProps,\n ref: ForwardedRef<EntityUploadHandle>,\n) {\n const { entityId, onStateChange = noop, onUploadReady = noop } = props\n\n const { data: entity, isLoading: isLoadingEntity } = useGetEntity(entityId)\n\n const isFileEntity =\n entity?.concreteType === 'org.sagebionetworks.repo.model.FileEntity'\n\n const { data: uploadDestination, isLoading: isLoadingUploadDestination } =\n useGetDefaultUploadDestination(entityId)\n const isLoading = isLoadingEntity || isLoadingUploadDestination\n\n const [accessKey, setAccessKey] = useState('')\n const [secretKey, setSecretKey] = useState('')\n\n const [didUploadsExceedStorageLimit, setDidUploadsExceedStorageLimit] =\n useState(false)\n\n const {\n initiateUpload,\n state,\n uploadProgress,\n activePrompts,\n isPrecheckingUpload,\n isUploadReady,\n } = useUploadFileEntities(entityId, accessKey, secretKey, () =>\n setDidUploadsExceedStorageLimit(true),\n )\n\n useEffect(() => {\n onStateChange(state)\n }, [state, onStateChange])\n\n useEffect(() => {\n if (isUploadReady) {\n onUploadReady()\n }\n }, [isUploadReady, onUploadReady])\n\n function uploadFileList(fileList: ArrayLike<File>) {\n if (uploadDestination?.projectStorageLocationUsage?.isOverLimit) {\n displayToast(\n 'Cannot upload files because the storage limit has been exceeded.',\n 'danger',\n )\n return\n }\n const args = Array.from(fileList).map(file => {\n if (isFileEntity) {\n return { file, existingEntityId: entityId }\n }\n return {\n file,\n rootContainerId: entityId,\n }\n })\n initiateUpload(args)\n }\n\n useImperativeHandle(ref, () => ({\n handleUploads: uploadFileList,\n }))\n\n const showLoading = isPrecheckingUpload || isLoading\n const loadingText = isPrecheckingUpload\n ? 'Preparing files for upload...'\n : 'Loading...'\n\n return (\n <div>\n <EntityUploadPromptDialog activePrompts={activePrompts} />\n {uploadDestination?.projectStorageLocationUsage && (\n <ProjectStorageLimitAlert\n usage={uploadDestination.projectStorageLocationUsage}\n didUploadsExceedLimit={didUploadsExceedStorageLimit}\n />\n )}\n <ExternalObjectStoreCredentialsForm\n uploadDestination={uploadDestination}\n accessKey={accessKey}\n setAccessKey={setAccessKey}\n secretKey={secretKey}\n setSecretKey={setSecretKey}\n />\n <UploadFilePanel\n onUploadFileList={uploadFileList}\n allowMultipleFiles={!isFileEntity}\n isLoading={showLoading}\n loadingText={loadingText}\n disabled={uploadDestination?.projectStorageLocationUsage?.isOverLimit}\n message={\n <>\n <Typography variant={'smallText1'}>\n All uploaded files will be stored in\n {uploadDestination?.storageLocationId ===\n SYNAPSE_STORAGE_LOCATION_ID && ' Synapse storage'}\n {uploadDestination &&\n uploadDestination?.storageLocationId !==\n SYNAPSE_STORAGE_LOCATION_ID && (\n <>\n :<br />\n {getUploadDestinationString(uploadDestination)}\n </>\n )}\n </Typography>\n {uploadDestination && uploadDestination.banner && (\n <FullWidthAlert\n sx={{\n textAlign: 'left',\n }}\n isGlobal={false}\n title={'Storage Location Message'}\n description={uploadDestination.banner}\n variant={'info'}\n />\n )}\n </>\n }\n />\n <MultiFileUploadProgress\n uploaderState={state}\n uploadProgress={uploadProgress}\n />\n </div>\n )\n})\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAuCA,IAAa,IAAe,EAAW,SACrC,GACA,GACA;CACA,IAAM,EAAE,aAAU,mBAAgB,GAAM,mBAAgB,MAAS,GAE3D,EAAE,MAAM,GAAQ,WAAW,MAAoB,EAAa,EAAS,EAErE,IACJ,GAAQ,iBAAiB,6CAErB,EAAE,MAAM,GAAmB,WAAW,MAC1C,EAA+B,EAAS,EACpC,IAAY,KAAmB,GAE/B,CAAC,GAAW,KAAgB,EAAS,GAAG,EACxC,CAAC,GAAW,KAAgB,EAAS,GAAG,EAExC,CAAC,GAA8B,KACnC,EAAS,GAAM,EAEX,EACJ,mBACA,UACA,mBACA,kBACA,wBACA,qBACE,EAAsB,GAAU,GAAW,SAC7C,EAAgC,GAAK,CACtC;AAMD,CAJA,QAAgB;AACd,IAAc,EAAM;IACnB,CAAC,GAAO,EAAc,CAAC,EAE1B,QAAgB;AACd,EAAI,KACF,GAAe;IAEhB,CAAC,GAAe,EAAc,CAAC;CAElC,SAAS,EAAe,GAA2B;AACjD,MAAI,GAAmB,6BAA6B,aAAa;AAC/D,KACE,oEACA,SACD;AACD;;AAWF,IATa,MAAM,KAAK,EAAS,CAAC,KAAI,MAChC,IACK;GAAE;GAAM,kBAAkB;GAAU,GAEtC;GACL;GACA,iBAAiB;GAClB,CAEY,CAAK;;AAGtB,GAAoB,UAAY,EAC9B,eAAe,GAChB,EAAE;CAEH,IAAM,IAAc,KAAuB,GACrC,IAAc,IAChB,kCACA;AAEJ,QACE,kBAAC,OAAD,EAAA,UAAA;EACE,kBAAC,GAAD,EAAyC,kBAAiB,CAAA;EACzD,GAAmB,+BAClB,kBAAC,GAAD;GACE,OAAO,EAAkB;GACzB,uBAAuB;GACvB,CAAA;EAEJ,kBAAC,GAAD;GACqB;GACR;GACG;GACH;GACG;GACd,CAAA;EACF,kBAAC,GAAD;GACE,kBAAkB;GAClB,oBAAoB,CAAC;GACrB,WAAW;GACE;GACb,UAAU,GAAmB,6BAA6B;GAC1D,SACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;IAAY,SAAS;cAArB;KAAmC;KAEhC,GAAmB,sBAAA,KACa;KAChC,KACC,GAAmB,sBAAA,KAEjB,kBAAA,GAAA,EAAA,UAAA;MAAE;MACC,kBAAC,MAAD,EAAM,CAAA;MACN,EAA2B,EAAkB;MAC7C,EAAA,CAAA;KAEI;OACZ,KAAqB,EAAkB,UACtC,kBAAC,GAAD;IACE,IAAI,EACF,WAAW,QACZ;IACD,UAAU;IACV,OAAO;IACP,aAAa,EAAkB;IAC/B,SAAS;IACT,CAAA,CAEH,EAAA,CAAA;GAEL,CAAA;EACF,kBAAC,GAAD;GACE,eAAe;GACC;GAChB,CAAA;EACE,EAAA,CAAA;EAER"}
@@ -1 +1 @@
1
- {"version":3,"file":"ExperimentalMode.js","names":[],"sources":["../../../src/components/ExperimentalMode/ExperimentalMode.tsx"],"sourcesContent":["import { isInSynapseExperimentalMode } from '@/synapse-client/SynapseClient'\nimport { EXPERIMENTAL_MODE_COOKIE } from '@/utils/SynapseConstants'\nimport { InfoOutlined } from '@mui/icons-material'\nimport { Box, IconButton, Tooltip, Typography, useTheme } from '@mui/material'\nimport { useEffect, useState } from 'react'\nimport Switch from 'react-switch'\nimport UniversalCookies from 'universal-cookie'\n\nconst EXPERIMENTAL_MODE_SWITCH_ID = 'experimental-mode'\nconst experimentalModeText =\n 'This mode gives you early access to features that are still in development. Please note that we do not guarantee an absence of errors, and that the data created using these features may be lost during product upgrade.'\n\nexport type ExperimentalModeProps = {\n onExperimentalModeToggle?: (newValue: boolean) => void\n}\nfunction ExperimentalMode({ onExperimentalModeToggle }: ExperimentalModeProps) {\n const [isExperimentalModeOn, setIsExperimentalModeOn] =\n useState<boolean>(false)\n let mounted = true\n const theme = useTheme()\n useEffect(() => {\n if (mounted) {\n if (isInSynapseExperimentalMode()) {\n setIsExperimentalModeOn(true)\n }\n }\n return () => {\n mounted = false\n }\n }, [])\n\n const getExperimentalModeCookieOptions = () => {\n const hostname = window.location.hostname.toLowerCase()\n return {\n path: '/',\n domain: hostname.endsWith('.synapse.org') ? 'synapse.org' : undefined,\n }\n }\n\n const createExperimentalModeCookie = () => {\n const cookies = new UniversalCookies()\n cookies.set(\n EXPERIMENTAL_MODE_COOKIE,\n 'true',\n getExperimentalModeCookieOptions(),\n )\n setIsExperimentalModeOn(true)\n if (onExperimentalModeToggle) {\n onExperimentalModeToggle(true)\n }\n }\n\n const deleteExperimentalModeCookie = () => {\n const cookies = new UniversalCookies()\n cookies.remove(EXPERIMENTAL_MODE_COOKIE, getExperimentalModeCookieOptions())\n setIsExperimentalModeOn(false)\n if (onExperimentalModeToggle) {\n onExperimentalModeToggle(false)\n }\n }\n\n return (\n <Box sx={{ display: 'flex', alignItems: 'center' }}>\n <Typography\n component={'label'}\n variant=\"body1\"\n htmlFor={EXPERIMENTAL_MODE_SWITCH_ID}\n >\n Experimental Mode\n </Typography>\n <Tooltip title={experimentalModeText} arrow placement=\"top\">\n <IconButton\n aria-label=\"info\"\n color=\"inherit\"\n sx={{ '&:hover': { backgroundColor: 'transparent' } }}\n >\n <InfoOutlined sx={{ verticalAlign: 'middle' }} />\n </IconButton>\n </Tooltip>\n <Switch\n id={EXPERIMENTAL_MODE_SWITCH_ID}\n width={35}\n height={20}\n onColor={theme.palette.secondary.main}\n checkedIcon={false}\n uncheckedIcon={false}\n checked={isExperimentalModeOn}\n onChange={\n isExperimentalModeOn\n ? deleteExperimentalModeCookie\n : createExperimentalModeCookie\n }\n />\n </Box>\n )\n}\n\nexport default ExperimentalMode\n"],"mappings":";;;;;;;;;AAQA,IAAM,IAA8B,qBAC9B,IACJ;AAKF,SAAS,EAAiB,EAAE,+BAAmD;CAC7E,IAAM,CAAC,GAAsB,KAC3B,EAAkB,GAAM,EACtB,IAAU,IACR,IAAQ,GAAU;AACxB,UACM,KACE,GAA6B,IAC/B,EAAwB,GAAK,QAGpB;AACX,MAAU;KAEX,EAAE,CAAC;CAEN,IAAM,WAEG;EACL,MAAM;EACN,QAHe,OAAO,SAAS,SAAS,aAAa,CAGpC,SAAS,eAAe,GAAG,gBAAgB,KAAA;EAC7D;AAyBH,QACE,kBAAC,GAAD;EAAK,IAAI;GAAE,SAAS;GAAQ,YAAY;GAAU;YAAlD;GACE,kBAAC,GAAD;IACE,WAAW;IACX,SAAQ;IACR,SAAS;cACV;IAEY,CAAA;GACb,kBAAC,GAAD;IAAS,OAAO;IAAsB,OAAA;IAAM,WAAU;cACpD,kBAAC,GAAD;KACE,cAAW;KACX,OAAM;KACN,IAAI,EAAE,WAAW,EAAE,iBAAiB,eAAe,EAAE;eAErD,kBAAC,GAAD,EAAc,IAAI,EAAE,eAAe,UAAU,EAAI,CAAA;KACtC,CAAA;IACL,CAAA;GACV,kBAAC,GAAD;IACE,IAAI;IACJ,OAAO;IACP,QAAQ;IACR,SAAS,EAAM,QAAQ,UAAU;IACjC,aAAa;IACb,eAAe;IACf,SAAS;IACT,UACE,UApCmC;AAIzC,KAHgB,IAAI,GAAkB,CAC9B,OAAO,GAA0B,GAAkC,CAAC,EAC5E,EAAwB,GAAM,EAC1B,KACF,EAAyB,GAAM;cAlBQ;AAQzC,KAPgB,IAAI,GAAkB,CAC9B,IACN,GACA,QACA,GAAkC,CACnC,EACD,EAAwB,GAAK,EACzB,KACF,EAAyB,GAAK;;IA4C5B,CAAA;GACE"}
1
+ {"version":3,"file":"ExperimentalMode.js","names":[],"sources":["../../../src/components/ExperimentalMode/ExperimentalMode.tsx"],"sourcesContent":["import { isInSynapseExperimentalMode } from '@/synapse-client/SynapseClient'\nimport { EXPERIMENTAL_MODE_COOKIE } from '@/utils/SynapseConstants'\nimport { InfoOutlined } from '@mui/icons-material'\nimport { Box, IconButton, Tooltip, Typography, useTheme } from '@mui/material'\nimport { useEffect, useState } from 'react'\nimport Switch from 'react-switch'\nimport UniversalCookies from 'universal-cookie'\n\nconst EXPERIMENTAL_MODE_SWITCH_ID = 'experimental-mode'\nconst experimentalModeText =\n 'This mode gives you early access to features that are still in development. Please note that we do not guarantee an absence of errors, and that the data created using these features may be lost during product upgrade.'\n\nexport type ExperimentalModeProps = {\n onExperimentalModeToggle?: (newValue: boolean) => void\n}\nfunction ExperimentalMode({ onExperimentalModeToggle }: ExperimentalModeProps) {\n const [isExperimentalModeOn, setIsExperimentalModeOn] =\n useState<boolean>(false)\n let mounted = true\n const theme = useTheme()\n useEffect(() => {\n if (mounted) {\n if (isInSynapseExperimentalMode()) {\n setIsExperimentalModeOn(true)\n }\n }\n return () => {\n mounted = false\n }\n }, [])\n\n const getExperimentalModeCookieOptions = () => {\n const hostname = window.location.hostname.toLowerCase()\n return {\n path: '/',\n domain: hostname.endsWith('.synapse.org') ? 'synapse.org' : undefined,\n }\n }\n\n const createExperimentalModeCookie = () => {\n const cookies = new UniversalCookies()\n cookies.set(\n EXPERIMENTAL_MODE_COOKIE,\n 'true',\n getExperimentalModeCookieOptions(),\n )\n setIsExperimentalModeOn(true)\n if (onExperimentalModeToggle) {\n onExperimentalModeToggle(true)\n }\n }\n\n const deleteExperimentalModeCookie = () => {\n const cookies = new UniversalCookies()\n cookies.remove(EXPERIMENTAL_MODE_COOKIE, getExperimentalModeCookieOptions())\n setIsExperimentalModeOn(false)\n if (onExperimentalModeToggle) {\n onExperimentalModeToggle(false)\n }\n }\n\n return (\n <Box sx={{ display: 'flex', alignItems: 'center' }}>\n <Typography\n component={'label'}\n variant=\"body1\"\n htmlFor={EXPERIMENTAL_MODE_SWITCH_ID}\n >\n Experimental Mode\n </Typography>\n <Tooltip title={experimentalModeText} arrow placement=\"top\">\n <IconButton\n aria-label=\"info\"\n color=\"inherit\"\n sx={{ '&:hover': { backgroundColor: 'transparent' } }}\n >\n <InfoOutlined sx={{ verticalAlign: 'middle' }} />\n </IconButton>\n </Tooltip>\n <Switch\n id={EXPERIMENTAL_MODE_SWITCH_ID}\n width={35}\n height={20}\n onColor={theme.palette.secondary.main}\n checkedIcon={false}\n uncheckedIcon={false}\n checked={isExperimentalModeOn}\n onChange={\n isExperimentalModeOn\n ? deleteExperimentalModeCookie\n : createExperimentalModeCookie\n }\n />\n </Box>\n )\n}\n\nexport default ExperimentalMode\n"],"mappings":";;;;;;;;;AAQA,IAAM,IAA8B,qBAC9B,IACJ;AAKF,SAAS,EAAiB,EAAE,+BAAmD;CAC7E,IAAM,CAAC,GAAsB,KAC3B,EAAkB,GAAM,EACtB,IAAU,IACR,IAAQ,GAAU;AACxB,UACM,KACE,GAA6B,IAC/B,EAAwB,GAAK,QAGpB;AACX,MAAU;KAEX,EAAE,CAAC;CAEN,IAAM,WAEG;EACL,MAAM;EACN,QAHe,OAAO,SAAS,SAAS,aAGhC,CAAS,SAAS,eAAe,GAAG,gBAAgB,KAAA;EAC7D;AAyBH,QACE,kBAAC,GAAD;EAAK,IAAI;GAAE,SAAS;GAAQ,YAAY;GAAU;YAAlD;GACE,kBAAC,GAAD;IACE,WAAW;IACX,SAAQ;IACR,SAAS;cACV;IAEY,CAAA;GACb,kBAAC,GAAD;IAAS,OAAO;IAAsB,OAAA;IAAM,WAAU;cACpD,kBAAC,GAAD;KACE,cAAW;KACX,OAAM;KACN,IAAI,EAAE,WAAW,EAAE,iBAAiB,eAAe,EAAE;eAErD,kBAAC,GAAD,EAAc,IAAI,EAAE,eAAe,UAAU,EAAI,CAAA;KACtC,CAAA;IACL,CAAA;GACV,kBAAC,GAAD;IACE,IAAI;IACJ,OAAO;IACP,QAAQ;IACR,SAAS,EAAM,QAAQ,UAAU;IACjC,aAAa;IACb,eAAe;IACf,SAAS;IACT,UACE,UApCmC;AAIzC,KAFA,IADoB,GACpB,CAAQ,OAAO,GAA0B,GAAkC,CAAC,EAC5E,EAAwB,GAAM,EAC1B,KACF,EAAyB,GAAM;cAlBQ;AAQzC,KANA,IADoB,GACpB,CAAQ,IACN,GACA,QACA,GAAkC,CACnC,EACD,EAAwB,GAAK,EACzB,KACF,EAAyB,GAAK;;IA4C5B,CAAA;GACE"}
@@ -1 +1 @@
1
- {"version":3,"file":"ExternalFileHandleLink.js","names":[],"sources":["../../../src/components/ExternalFileHandleLink/ExternalFileHandleLink.tsx"],"sourcesContent":["import React from 'react'\nimport SynapseClient from '@/synapse-client'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport { isExternalFileHandle, isFileEntity } from '@/utils/types/IsType'\nimport { OpenInNewTwoTone } from '@mui/icons-material'\nimport {\n BatchFileRequest,\n ExternalFileHandle,\n FileEntity,\n FileHandleAssociateType,\n} from '@sage-bionetworks/synapse-types'\nimport { useEffect, useState } from 'react'\n\nexport type ExternalFileHandleLinkProps = {\n synId: string\n className?: string\n}\n\nexport const ExternalFileHandleLink = (\n props: ExternalFileHandleLinkProps,\n): React.ReactNode => {\n const { accessToken } = useSynapseContext()\n const { synId, className } = props\n const [data, setData] = useState<\n | { fileEntity: FileEntity; externalFileHandle: ExternalFileHandle }\n | undefined\n >(undefined)\n useEffect(() => {\n const getEntity = async () => {\n try {\n const fileEntity = await SynapseClient.getEntity<FileEntity>(\n accessToken,\n synId,\n )\n if (!isFileEntity(fileEntity)) {\n throw new Error(`File Entity expected but found ${fileEntity}`)\n }\n const batchFileRequest: BatchFileRequest = {\n requestedFiles: [\n {\n associateObjectId: synId,\n associateObjectType: FileHandleAssociateType.FileEntity,\n fileHandleId: fileEntity.dataFileHandleId,\n },\n ],\n includeFileHandles: true,\n includePreSignedURLs: false,\n includePreviewPreSignedURLs: false,\n }\n const file = await SynapseClient.getFiles(batchFileRequest, accessToken)\n const externalFileHandle = file.requestedFiles[0].fileHandle\n if (externalFileHandle && isExternalFileHandle(externalFileHandle)) {\n setData({\n externalFileHandle,\n fileEntity,\n })\n } else {\n throw new Error(\n `Not an external file handle: ${externalFileHandle?.id}`,\n )\n }\n } catch (e) {\n console.error('Error on getting external file handle = ', e)\n }\n }\n getEntity()\n }, [synId, accessToken])\n\n const externalFileHandle = data?.externalFileHandle\n const fileEntity = data?.fileEntity\n\n return externalFileHandle ? (\n <a\n href={externalFileHandle.externalURL}\n className={className}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n <span>\n {fileEntity?.name}\n <OpenInNewTwoTone style={{ marginLeft: 5 }} />\n </span>\n </a>\n ) : (\n <></>\n )\n}\n"],"mappings":";;;;;;;;AAkBA,IAAa,KACX,MACoB;CACpB,IAAM,EAAE,mBAAgB,GAAmB,EACrC,EAAE,UAAO,iBAAc,GACvB,CAAC,GAAM,KAAW,EAGtB,KAAA,EAAU;AACZ,SAAgB;AAsCd,GArCkB,YAAY;AAC5B,OAAI;IACF,IAAM,IAAa,MAAM,EAAc,UACrC,GACA,EACD;AACD,QAAI,CAAC,EAAa,EAAW,CAC3B,OAAU,MAAM,kCAAkC,IAAa;IAEjE,IAAM,IAAqC;KACzC,gBAAgB,CACd;MACE,mBAAmB;MACnB,qBAAqB,EAAwB;MAC7C,cAAc,EAAW;MAC1B,CACF;KACD,oBAAoB;KACpB,sBAAsB;KACtB,6BAA6B;KAC9B,EAEK,KADO,MAAM,EAAc,SAAS,GAAkB,EAAY,EACxC,eAAe,GAAG;AAClD,QAAI,KAAsB,EAAqB,EAAmB,CAChE,GAAQ;KACN;KACA;KACD,CAAC;QAEF,OAAU,MACR,gCAAgC,GAAoB,KACrD;YAEI,GAAG;AACV,YAAQ,MAAM,4CAA4C,EAAE;;MAGrD;IACV,CAAC,GAAO,EAAY,CAAC;CAExB,IAAM,IAAqB,GAAM,oBAC3B,IAAa,GAAM;AAEzB,QAAO,IACL,kBAAC,KAAD;EACE,MAAM,EAAmB;EACd;EACX,QAAO;EACP,KAAI;YAEJ,kBAAC,QAAD,EAAA,UAAA,CACG,GAAY,MACb,kBAAC,GAAD,EAAkB,OAAO,EAAE,YAAY,GAAG,EAAI,CAAA,CACzC,EAAA,CAAA;EACL,CAAA,GAEJ,kBAAA,GAAA,EAAK,CAAA"}
1
+ {"version":3,"file":"ExternalFileHandleLink.js","names":[],"sources":["../../../src/components/ExternalFileHandleLink/ExternalFileHandleLink.tsx"],"sourcesContent":["import React from 'react'\nimport SynapseClient from '@/synapse-client'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport { isExternalFileHandle, isFileEntity } from '@/utils/types/IsType'\nimport { OpenInNewTwoTone } from '@mui/icons-material'\nimport {\n BatchFileRequest,\n ExternalFileHandle,\n FileEntity,\n FileHandleAssociateType,\n} from '@sage-bionetworks/synapse-types'\nimport { useEffect, useState } from 'react'\n\nexport type ExternalFileHandleLinkProps = {\n synId: string\n className?: string\n}\n\nexport const ExternalFileHandleLink = (\n props: ExternalFileHandleLinkProps,\n): React.ReactNode => {\n const { accessToken } = useSynapseContext()\n const { synId, className } = props\n const [data, setData] = useState<\n | { fileEntity: FileEntity; externalFileHandle: ExternalFileHandle }\n | undefined\n >(undefined)\n useEffect(() => {\n const getEntity = async () => {\n try {\n const fileEntity = await SynapseClient.getEntity<FileEntity>(\n accessToken,\n synId,\n )\n if (!isFileEntity(fileEntity)) {\n throw new Error(`File Entity expected but found ${fileEntity}`)\n }\n const batchFileRequest: BatchFileRequest = {\n requestedFiles: [\n {\n associateObjectId: synId,\n associateObjectType: FileHandleAssociateType.FileEntity,\n fileHandleId: fileEntity.dataFileHandleId,\n },\n ],\n includeFileHandles: true,\n includePreSignedURLs: false,\n includePreviewPreSignedURLs: false,\n }\n const file = await SynapseClient.getFiles(batchFileRequest, accessToken)\n const externalFileHandle = file.requestedFiles[0].fileHandle\n if (externalFileHandle && isExternalFileHandle(externalFileHandle)) {\n setData({\n externalFileHandle,\n fileEntity,\n })\n } else {\n throw new Error(\n `Not an external file handle: ${externalFileHandle?.id}`,\n )\n }\n } catch (e) {\n console.error('Error on getting external file handle = ', e)\n }\n }\n getEntity()\n }, [synId, accessToken])\n\n const externalFileHandle = data?.externalFileHandle\n const fileEntity = data?.fileEntity\n\n return externalFileHandle ? (\n <a\n href={externalFileHandle.externalURL}\n className={className}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n <span>\n {fileEntity?.name}\n <OpenInNewTwoTone style={{ marginLeft: 5 }} />\n </span>\n </a>\n ) : (\n <></>\n )\n}\n"],"mappings":";;;;;;;;AAkBA,IAAa,KACX,MACoB;CACpB,IAAM,EAAE,mBAAgB,GAAmB,EACrC,EAAE,UAAO,iBAAc,GACvB,CAAC,GAAM,KAAW,EAGtB,KAAA,EAAU;AACZ,SAAgB;AAsCd,eArC8B;AAC5B,OAAI;IACF,IAAM,IAAa,MAAM,EAAc,UACrC,GACA,EACD;AACD,QAAI,CAAC,EAAa,EAAW,CAC3B,OAAU,MAAM,kCAAkC,IAAa;IAEjE,IAAM,IAAqC;KACzC,gBAAgB,CACd;MACE,mBAAmB;MACnB,qBAAqB,EAAwB;MAC7C,cAAc,EAAW;MAC1B,CACF;KACD,oBAAoB;KACpB,sBAAsB;KACtB,6BAA6B;KAC9B,EAEK,KAAqB,MADR,EAAc,SAAS,GAAkB,EAAY,EACxC,eAAe,GAAG;AAClD,QAAI,KAAsB,EAAqB,EAAmB,CAChE,GAAQ;KACN;KACA;KACD,CAAC;QAEF,OAAU,MACR,gCAAgC,GAAoB,KACrD;YAEI,GAAG;AACV,YAAQ,MAAM,4CAA4C,EAAE;;MAGrD;IACV,CAAC,GAAO,EAAY,CAAC;CAExB,IAAM,IAAqB,GAAM,oBAC3B,IAAa,GAAM;AAEzB,QAAO,IACL,kBAAC,KAAD;EACE,MAAM,EAAmB;EACd;EACX,QAAO;EACP,KAAI;YAEJ,kBAAC,QAAD,EAAA,UAAA,CACG,GAAY,MACb,kBAAC,GAAD,EAAkB,OAAO,EAAE,YAAY,GAAG,EAAI,CAAA,CACzC,EAAA,CAAA;EACL,CAAA,GAEJ,kBAAA,GAAA,EAAK,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"FacetPlotsCard.js","names":[],"sources":["../../../src/components/FeaturedDataTabs/FacetPlotsCard.tsx"],"sourcesContent":["import { useSynapseContext } from '@/utils/context/SynapseContext'\nimport {\n Box,\n Button,\n Divider,\n Paper,\n Skeleton,\n Typography,\n} from '@mui/material'\nimport {\n ColumnTypeEnum,\n FacetColumnResult,\n FacetColumnResultValueCount,\n FacetColumnResultValues,\n} from '@sage-bionetworks/synapse-types'\nimport { useSuspenseQuery } from '@tanstack/react-query'\nimport { times } from 'lodash-es'\nimport Plotly from 'plotly.js-basic-dist'\nimport { Fragment, Suspense, useMemo } from 'react'\nimport Plot from '../Plot/Plot'\nimport { useQueryVisualizationContext } from '../QueryVisualizationWrapper'\nimport { useSuspenseGetQueryMetadata } from '../QueryWrapper/useGetQueryMetadata'\nimport { ShowMore } from '../row_renderers/utils'\nimport { SkeletonParagraph, SkeletonTable } from '../Skeleton'\nimport {\n extractPlotDataArray,\n getPlotStyle,\n PlotType,\n} from '../widgets/facet-nav/FacetNavPanel'\nimport { FacetPlotLegendTable } from '../widgets/facet-nav/FacetPlotLegendTable'\nimport { getFacets } from '../widgets/facet-nav/useFacetPlots'\nimport {\n FACET_PLOTS_CARD_CLASSNAME,\n FACET_PLOTS_CARD_PLOT_CONTAINER_CLASSNAME,\n FACET_PLOTS_CARD_TITLE_CONTAINER_CLASSNAME,\n FacetPlotsCardPlotContainer,\n FacetPlotsCardTitleContainer,\n} from './FacetPlotsCardGrid'\nimport { useMeasure } from '@react-hookz/web'\n\nexport type FacetPlotsCardProps = {\n title?: string\n description?: string\n facetsToPlot?: string[]\n detailsPagePath?: string\n plotType?: PlotType\n}\n\nconst layout: Partial<Plotly.Layout> = {\n showlegend: false,\n annotations: [],\n margin: { l: 0, r: 0, b: 0, t: 0, pad: 0 },\n yaxis: {\n visible: false,\n showgrid: false,\n },\n xaxis: {\n visible: false,\n showgrid: false,\n },\n}\n\nfunction LoadingCard(props: { numPlots: number }) {\n const { numPlots } = props\n return (\n <Paper className={FACET_PLOTS_CARD_CLASSNAME}>\n <FacetPlotsCardTitleContainer\n className={FACET_PLOTS_CARD_TITLE_CONTAINER_CLASSNAME}\n >\n <Skeleton width={'60%'} height={'24px'} />\n\n <SkeletonParagraph numRows={5} />\n\n <Skeleton width={'40%'}>\n <Button variant={'contained'}>Explore</Button>\n </Skeleton>\n </FacetPlotsCardTitleContainer>\n {times(numPlots).map(index => (\n <FacetPlotsCardPlotContainer\n key={index}\n className={FACET_PLOTS_CARD_PLOT_CONTAINER_CLASSNAME}\n sx={{\n py: 3,\n gridRow: `plot${index}`,\n }}\n >\n <Skeleton width={'100%'} height={'300px'} />\n <SkeletonTable numRows={4} numCols={2} />\n </FacetPlotsCardPlotContainer>\n ))}\n </Paper>\n )\n}\n\nfunction FacetPlotsCard(props: FacetPlotsCardProps) {\n const {\n title,\n description,\n facetsToPlot,\n detailsPagePath,\n plotType = 'PIE',\n } = props\n const { accessToken } = useSynapseContext()\n const { data: queryMetadata } = useSuspenseGetQueryMetadata()\n const { getColumnDisplayName } = useQueryVisualizationContext()\n const [plotContainerMeasurements, plotContainerRef] = useMeasure()\n\n const facetDataArray = useMemo(() => {\n if (!facetsToPlot) {\n return []\n }\n\n return getFacets(queryMetadata, facetsToPlot)\n }, [facetsToPlot, queryMetadata])\n\n const currentLayout: Partial<Plotly.Layout> = useMemo(() => {\n return {\n ...layout,\n barmode: plotType === 'STACKED_HORIZONTAL_BAR' ? 'stack' : undefined,\n }\n }, [plotType])\n const maxPlotHeight = plotType === 'STACKED_HORIZONTAL_BAR' ? 50 : 150\n const { data: facetPlotDataArray } = useSuspenseQuery({\n queryKey: ['facetPlotDataArray', facetsToPlot, facetDataArray],\n queryFn: async () => {\n if (!facetsToPlot) {\n return []\n }\n\n const getColumnType = (\n facetToPlot: FacetColumnResult,\n ): ColumnTypeEnum | undefined =>\n queryMetadata.columnModels!.find(\n columnModel => columnModel.name === facetToPlot.columnName,\n )?.columnType as ColumnTypeEnum\n\n return Promise.all(\n facetDataArray.map(async (item, index) => {\n const plotData = await extractPlotDataArray(\n item as FacetColumnResultValues,\n getColumnType(item),\n index + 1, //individual plot rgbIndex\n plotType,\n accessToken,\n )\n return plotData\n }),\n )\n },\n })\n\n const selectedFacetValue = useMemo(() => {\n if (!facetsToPlot) {\n return ''\n }\n\n // If we are showing a facet selection based card, then set the selectedFacetValue. For example, facet column \"study\" with value \"ROSMAP\"\n const selectedFacet: FacetColumnResultValueCount | undefined = queryMetadata\n ?.facets!.map(item => {\n const facetValues: FacetColumnResultValueCount[] = (\n item as FacetColumnResultValues\n ).facetValues\n if (facetValues) {\n const filteredFacetValues: FacetColumnResultValueCount[] =\n facetValues.filter(facetValue => {\n return facetValue.isSelected\n })\n return filteredFacetValues.length > 0\n ? filteredFacetValues[0]\n : undefined\n } else {\n return undefined\n }\n })\n .filter(x => x !== undefined)[0]\n\n if (selectedFacet && selectedFacet.value) {\n return selectedFacet?.value\n }\n return ''\n }, [facetsToPlot, queryMetadata?.facets])\n\n const isShowingMultiplePlots = facetPlotDataArray.length > 1\n const cardTitle =\n title ??\n (isShowingMultiplePlots\n ? selectedFacetValue\n : getColumnDisplayName(facetDataArray[0].columnName))\n return (\n <Paper className={FACET_PLOTS_CARD_CLASSNAME} sx={{ overflow: 'hidden' }}>\n <FacetPlotsCardTitleContainer\n className={FACET_PLOTS_CARD_TITLE_CONTAINER_CLASSNAME}\n >\n <Typography variant={'headline1'}>{cardTitle}</Typography>\n {description && (\n <Typography variant={'body1'} sx={{ color: 'grey.700', my: 2 }}>\n <ShowMore summary={description} maxCharacterCount={200} />\n </Typography>\n )}\n\n {detailsPagePath && selectedFacetValue && (\n <Box sx={{ my: 2 }}>\n <Button\n variant={'contained'}\n href={detailsPagePath}\n color={'secondary'}\n sx={theme => ({\n [theme.breakpoints.down('sm')]: { width: '100%' },\n })}\n >\n Explore {selectedFacetValue}\n </Button>\n </Box>\n )}\n </FacetPlotsCardTitleContainer>\n\n {/* create a plot for every facet to be plotted */}\n {facetPlotDataArray.map((plotData, index) => {\n return (\n <Fragment key={index}>\n <FacetPlotsCardPlotContainer\n className={FACET_PLOTS_CARD_PLOT_CONTAINER_CLASSNAME}\n sx={{\n pt: index === 0 ? 5 : 0,\n gridRow: `plot${index}`,\n }}\n key={index}\n >\n {index != 0 && <Divider sx={{ mt: 2, mb: 4 }} />}\n <Box sx={{ minHeight: '130px' }}>\n <Box\n ref={plotContainerRef}\n sx={{\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n }}\n >\n <Plot\n key={`${facetsToPlot![index]}-${\n plotContainerMeasurements?.width\n }`}\n layout={currentLayout}\n data={plotData?.data ?? []}\n style={getPlotStyle(\n plotContainerMeasurements?.width,\n plotType,\n maxPlotHeight,\n )}\n config={{ displayModeBar: false }}\n />\n </Box>\n <Box sx={{ mt: 4, width: '100%' }}>\n <FacetPlotLegendTable\n facetName={getColumnDisplayName(\n facetDataArray[index].columnName,\n )}\n labels={plotData?.labels}\n colors={plotData?.colors}\n isExpanded={false}\n linkToFullQuery={detailsPagePath}\n />\n </Box>\n </Box>\n </FacetPlotsCardPlotContainer>\n </Fragment>\n )\n })}\n </Paper>\n )\n}\n\nexport default function FacetPlotsCardWithSuspense(props: FacetPlotsCardProps) {\n return (\n <Suspense\n fallback={<LoadingCard numPlots={(props.facetsToPlot ?? []).length} />}\n >\n <FacetPlotsCard {...props} />\n </Suspense>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"FacetPlotsCard.js","names":[],"sources":["../../../src/components/FeaturedDataTabs/FacetPlotsCard.tsx"],"sourcesContent":["import { useSynapseContext } from '@/utils/context/SynapseContext'\nimport {\n Box,\n Button,\n Divider,\n Paper,\n Skeleton,\n Typography,\n} from '@mui/material'\nimport {\n ColumnTypeEnum,\n FacetColumnResult,\n FacetColumnResultValueCount,\n FacetColumnResultValues,\n} from '@sage-bionetworks/synapse-types'\nimport { useSuspenseQuery } from '@tanstack/react-query'\nimport { times } from 'lodash-es'\nimport Plotly from 'plotly.js-basic-dist'\nimport { Fragment, Suspense, useMemo } from 'react'\nimport Plot from '../Plot/Plot'\nimport { useQueryVisualizationContext } from '../QueryVisualizationWrapper'\nimport { useSuspenseGetQueryMetadata } from '../QueryWrapper/useGetQueryMetadata'\nimport { ShowMore } from '../row_renderers/utils'\nimport { SkeletonParagraph, SkeletonTable } from '../Skeleton'\nimport {\n extractPlotDataArray,\n getPlotStyle,\n PlotType,\n} from '../widgets/facet-nav/FacetNavPanel'\nimport { FacetPlotLegendTable } from '../widgets/facet-nav/FacetPlotLegendTable'\nimport { getFacets } from '../widgets/facet-nav/useFacetPlots'\nimport {\n FACET_PLOTS_CARD_CLASSNAME,\n FACET_PLOTS_CARD_PLOT_CONTAINER_CLASSNAME,\n FACET_PLOTS_CARD_TITLE_CONTAINER_CLASSNAME,\n FacetPlotsCardPlotContainer,\n FacetPlotsCardTitleContainer,\n} from './FacetPlotsCardGrid'\nimport { useMeasure } from '@react-hookz/web'\n\nexport type FacetPlotsCardProps = {\n title?: string\n description?: string\n facetsToPlot?: string[]\n detailsPagePath?: string\n plotType?: PlotType\n}\n\nconst layout: Partial<Plotly.Layout> = {\n showlegend: false,\n annotations: [],\n margin: { l: 0, r: 0, b: 0, t: 0, pad: 0 },\n yaxis: {\n visible: false,\n showgrid: false,\n },\n xaxis: {\n visible: false,\n showgrid: false,\n },\n}\n\nfunction LoadingCard(props: { numPlots: number }) {\n const { numPlots } = props\n return (\n <Paper className={FACET_PLOTS_CARD_CLASSNAME}>\n <FacetPlotsCardTitleContainer\n className={FACET_PLOTS_CARD_TITLE_CONTAINER_CLASSNAME}\n >\n <Skeleton width={'60%'} height={'24px'} />\n\n <SkeletonParagraph numRows={5} />\n\n <Skeleton width={'40%'}>\n <Button variant={'contained'}>Explore</Button>\n </Skeleton>\n </FacetPlotsCardTitleContainer>\n {times(numPlots).map(index => (\n <FacetPlotsCardPlotContainer\n key={index}\n className={FACET_PLOTS_CARD_PLOT_CONTAINER_CLASSNAME}\n sx={{\n py: 3,\n gridRow: `plot${index}`,\n }}\n >\n <Skeleton width={'100%'} height={'300px'} />\n <SkeletonTable numRows={4} numCols={2} />\n </FacetPlotsCardPlotContainer>\n ))}\n </Paper>\n )\n}\n\nfunction FacetPlotsCard(props: FacetPlotsCardProps) {\n const {\n title,\n description,\n facetsToPlot,\n detailsPagePath,\n plotType = 'PIE',\n } = props\n const { accessToken } = useSynapseContext()\n const { data: queryMetadata } = useSuspenseGetQueryMetadata()\n const { getColumnDisplayName } = useQueryVisualizationContext()\n const [plotContainerMeasurements, plotContainerRef] = useMeasure()\n\n const facetDataArray = useMemo(() => {\n if (!facetsToPlot) {\n return []\n }\n\n return getFacets(queryMetadata, facetsToPlot)\n }, [facetsToPlot, queryMetadata])\n\n const currentLayout: Partial<Plotly.Layout> = useMemo(() => {\n return {\n ...layout,\n barmode: plotType === 'STACKED_HORIZONTAL_BAR' ? 'stack' : undefined,\n }\n }, [plotType])\n const maxPlotHeight = plotType === 'STACKED_HORIZONTAL_BAR' ? 50 : 150\n const { data: facetPlotDataArray } = useSuspenseQuery({\n queryKey: ['facetPlotDataArray', facetsToPlot, facetDataArray],\n queryFn: async () => {\n if (!facetsToPlot) {\n return []\n }\n\n const getColumnType = (\n facetToPlot: FacetColumnResult,\n ): ColumnTypeEnum | undefined =>\n queryMetadata.columnModels!.find(\n columnModel => columnModel.name === facetToPlot.columnName,\n )?.columnType as ColumnTypeEnum\n\n return Promise.all(\n facetDataArray.map(async (item, index) => {\n const plotData = await extractPlotDataArray(\n item as FacetColumnResultValues,\n getColumnType(item),\n index + 1, //individual plot rgbIndex\n plotType,\n accessToken,\n )\n return plotData\n }),\n )\n },\n })\n\n const selectedFacetValue = useMemo(() => {\n if (!facetsToPlot) {\n return ''\n }\n\n // If we are showing a facet selection based card, then set the selectedFacetValue. For example, facet column \"study\" with value \"ROSMAP\"\n const selectedFacet: FacetColumnResultValueCount | undefined = queryMetadata\n ?.facets!.map(item => {\n const facetValues: FacetColumnResultValueCount[] = (\n item as FacetColumnResultValues\n ).facetValues\n if (facetValues) {\n const filteredFacetValues: FacetColumnResultValueCount[] =\n facetValues.filter(facetValue => {\n return facetValue.isSelected\n })\n return filteredFacetValues.length > 0\n ? filteredFacetValues[0]\n : undefined\n } else {\n return undefined\n }\n })\n .filter(x => x !== undefined)[0]\n\n if (selectedFacet && selectedFacet.value) {\n return selectedFacet?.value\n }\n return ''\n }, [facetsToPlot, queryMetadata?.facets])\n\n const isShowingMultiplePlots = facetPlotDataArray.length > 1\n const cardTitle =\n title ??\n (isShowingMultiplePlots\n ? selectedFacetValue\n : getColumnDisplayName(facetDataArray[0].columnName))\n return (\n <Paper className={FACET_PLOTS_CARD_CLASSNAME} sx={{ overflow: 'hidden' }}>\n <FacetPlotsCardTitleContainer\n className={FACET_PLOTS_CARD_TITLE_CONTAINER_CLASSNAME}\n >\n <Typography variant={'headline1'}>{cardTitle}</Typography>\n {description && (\n <Typography variant={'body1'} sx={{ color: 'grey.700', my: 2 }}>\n <ShowMore summary={description} maxCharacterCount={200} />\n </Typography>\n )}\n\n {detailsPagePath && selectedFacetValue && (\n <Box sx={{ my: 2 }}>\n <Button\n variant={'contained'}\n href={detailsPagePath}\n color={'secondary'}\n sx={theme => ({\n [theme.breakpoints.down('sm')]: { width: '100%' },\n })}\n >\n Explore {selectedFacetValue}\n </Button>\n </Box>\n )}\n </FacetPlotsCardTitleContainer>\n\n {/* create a plot for every facet to be plotted */}\n {facetPlotDataArray.map((plotData, index) => {\n return (\n <Fragment key={index}>\n <FacetPlotsCardPlotContainer\n className={FACET_PLOTS_CARD_PLOT_CONTAINER_CLASSNAME}\n sx={{\n pt: index === 0 ? 5 : 0,\n gridRow: `plot${index}`,\n }}\n key={index}\n >\n {index != 0 && <Divider sx={{ mt: 2, mb: 4 }} />}\n <Box sx={{ minHeight: '130px' }}>\n <Box\n ref={plotContainerRef}\n sx={{\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n }}\n >\n <Plot\n key={`${facetsToPlot![index]}-${\n plotContainerMeasurements?.width\n }`}\n layout={currentLayout}\n data={plotData?.data ?? []}\n style={getPlotStyle(\n plotContainerMeasurements?.width,\n plotType,\n maxPlotHeight,\n )}\n config={{ displayModeBar: false }}\n />\n </Box>\n <Box sx={{ mt: 4, width: '100%' }}>\n <FacetPlotLegendTable\n facetName={getColumnDisplayName(\n facetDataArray[index].columnName,\n )}\n labels={plotData?.labels}\n colors={plotData?.colors}\n isExpanded={false}\n linkToFullQuery={detailsPagePath}\n />\n </Box>\n </Box>\n </FacetPlotsCardPlotContainer>\n </Fragment>\n )\n })}\n </Paper>\n )\n}\n\nexport default function FacetPlotsCardWithSuspense(props: FacetPlotsCardProps) {\n return (\n <Suspense\n fallback={<LoadingCard numPlots={(props.facetsToPlot ?? []).length} />}\n >\n <FacetPlotsCard {...props} />\n </Suspense>\n )\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"QueryPerFacetPlotsCard.js","names":[],"sources":["../../../src/components/FeaturedDataTabs/QueryPerFacetPlotsCard.tsx"],"sourcesContent":["import { SynapseConstants } from '@/utils'\nimport { parseEntityIdFromSqlStatement } from '@/utils/functions'\nimport { DEFAULT_PAGE_SIZE } from '@/utils/SynapseConstants'\nimport { QueryBundleRequest } from '@sage-bionetworks/synapse-types'\nimport {\n QueryVisualizationContextType,\n QueryVisualizationWrapper,\n} from '../QueryVisualizationWrapper'\nimport { QueryWrapper } from '../QueryWrapper'\nimport { QueryWrapperErrorBoundary } from '../QueryWrapperErrorBoundary'\nimport FacetPlotsCard, { FacetPlotsCardProps } from './FacetPlotsCard'\n\nexport type QueryPerFacetPlotsCardProps = {\n title?: string\n description?: string\n rgbIndex?: number\n facetsToPlot?: string[]\n selectFacetColumnName: string\n selectFacetColumnValue: string\n sql?: string\n detailsPagePath: string\n} & Pick<QueryVisualizationContextType, 'unitDescription'> &\n Pick<FacetPlotsCardProps, 'plotType'>\n\nfunction getQueryRequest(\n sql: string,\n selectFacetColumnName: string,\n selectFacetColumnValue: string,\n): QueryBundleRequest {\n const entityId = parseEntityIdFromSqlStatement(sql)\n return {\n entityId,\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n partMask:\n SynapseConstants.BUNDLE_MASK_QUERY_COLUMN_MODELS |\n SynapseConstants.BUNDLE_MASK_QUERY_FACETS,\n query: {\n sql,\n offset: 0,\n limit: DEFAULT_PAGE_SIZE,\n selectedFacets: [\n {\n columnName: selectFacetColumnName,\n facetValues: [selectFacetColumnValue],\n concreteType:\n 'org.sagebionetworks.repo.model.table.FacetColumnValuesRequest',\n },\n ],\n },\n }\n}\nfunction QueryPerFacetPlotsCard(props: QueryPerFacetPlotsCardProps) {\n const {\n title,\n description,\n sql,\n facetsToPlot,\n rgbIndex,\n selectFacetColumnName,\n selectFacetColumnValue,\n detailsPagePath,\n plotType,\n ...rest\n } = props\n const initQueryRequest: QueryBundleRequest = getQueryRequest(\n sql!,\n selectFacetColumnName,\n selectFacetColumnValue,\n )\n\n /**\n * Fully re-render the uncontrolled QueryWrapper component when the initial query changes. This eliminates a class of\n * bugs where our 'derived' state (the current query), which should be reset, is out of sync with props.\n *\n * See https://legacy.reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#recommendation-fully-uncontrolled-component-with-a-key\n */\n const queryWrapperKey = JSON.stringify(initQueryRequest)\n return (\n <QueryWrapper\n {...rest}\n initQueryRequest={initQueryRequest}\n key={queryWrapperKey}\n >\n <QueryVisualizationWrapper rgbIndex={rgbIndex} {...rest}>\n <QueryWrapperErrorBoundary>\n <FacetPlotsCard\n title={title}\n description={description}\n facetsToPlot={facetsToPlot}\n detailsPagePath={detailsPagePath}\n plotType={plotType}\n />\n </QueryWrapperErrorBoundary>\n </QueryVisualizationWrapper>\n </QueryWrapper>\n )\n}\n\nexport default QueryPerFacetPlotsCard\n"],"mappings":";;;;;;;;;;;;;AAwBA,SAAS,EACP,GACA,GACA,GACoB;AAEpB,QAAO;EACL,UAFe,EAA8B,EAAI;EAGjD,cAAc;EACd,UACE;EAEF,OAAO;GACL;GACA,QAAQ;GACR,OAAA;GACA,gBAAgB,CACd;IACE,YAAY;IACZ,aAAa,CAAC,EAAuB;IACrC,cACE;IACH,CACF;GACF;EACF;;AAEH,SAAS,EAAuB,GAAoC;CAClE,IAAM,EACJ,UACA,gBACA,QACA,iBACA,aACA,0BACA,2BACA,oBACA,aACA,GAAG,MACD,GACE,IAAuC,EAC3C,GACA,GACA,EACD,EAQK,IAAkB,KAAK,UAAU,EAAiB;AACxD,QACE,kBAAC,GAAD;EACE,GAAI;EACc;EAClB,KAAK;EAaQ,EAXb,kBAAC,GAAD;EAAqC;EAAU,GAAI;YACjD,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;GACS;GACM;GACC;GACG;GACP;GACV,CAAA,EACwB,CAAA;EACF,CAAA,CACf"}
1
+ {"version":3,"file":"QueryPerFacetPlotsCard.js","names":[],"sources":["../../../src/components/FeaturedDataTabs/QueryPerFacetPlotsCard.tsx"],"sourcesContent":["import { SynapseConstants } from '@/utils'\nimport { parseEntityIdFromSqlStatement } from '@/utils/functions'\nimport { DEFAULT_PAGE_SIZE } from '@/utils/SynapseConstants'\nimport { QueryBundleRequest } from '@sage-bionetworks/synapse-types'\nimport {\n QueryVisualizationContextType,\n QueryVisualizationWrapper,\n} from '../QueryVisualizationWrapper'\nimport { QueryWrapper } from '../QueryWrapper'\nimport { QueryWrapperErrorBoundary } from '../QueryWrapperErrorBoundary'\nimport FacetPlotsCard, { FacetPlotsCardProps } from './FacetPlotsCard'\n\nexport type QueryPerFacetPlotsCardProps = {\n title?: string\n description?: string\n rgbIndex?: number\n facetsToPlot?: string[]\n selectFacetColumnName: string\n selectFacetColumnValue: string\n sql?: string\n detailsPagePath: string\n} & Pick<QueryVisualizationContextType, 'unitDescription'> &\n Pick<FacetPlotsCardProps, 'plotType'>\n\nfunction getQueryRequest(\n sql: string,\n selectFacetColumnName: string,\n selectFacetColumnValue: string,\n): QueryBundleRequest {\n const entityId = parseEntityIdFromSqlStatement(sql)\n return {\n entityId,\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n partMask:\n SynapseConstants.BUNDLE_MASK_QUERY_COLUMN_MODELS |\n SynapseConstants.BUNDLE_MASK_QUERY_FACETS,\n query: {\n sql,\n offset: 0,\n limit: DEFAULT_PAGE_SIZE,\n selectedFacets: [\n {\n columnName: selectFacetColumnName,\n facetValues: [selectFacetColumnValue],\n concreteType:\n 'org.sagebionetworks.repo.model.table.FacetColumnValuesRequest',\n },\n ],\n },\n }\n}\nfunction QueryPerFacetPlotsCard(props: QueryPerFacetPlotsCardProps) {\n const {\n title,\n description,\n sql,\n facetsToPlot,\n rgbIndex,\n selectFacetColumnName,\n selectFacetColumnValue,\n detailsPagePath,\n plotType,\n ...rest\n } = props\n const initQueryRequest: QueryBundleRequest = getQueryRequest(\n sql!,\n selectFacetColumnName,\n selectFacetColumnValue,\n )\n\n /**\n * Fully re-render the uncontrolled QueryWrapper component when the initial query changes. This eliminates a class of\n * bugs where our 'derived' state (the current query), which should be reset, is out of sync with props.\n *\n * See https://legacy.reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#recommendation-fully-uncontrolled-component-with-a-key\n */\n const queryWrapperKey = JSON.stringify(initQueryRequest)\n return (\n <QueryWrapper\n {...rest}\n initQueryRequest={initQueryRequest}\n key={queryWrapperKey}\n >\n <QueryVisualizationWrapper rgbIndex={rgbIndex} {...rest}>\n <QueryWrapperErrorBoundary>\n <FacetPlotsCard\n title={title}\n description={description}\n facetsToPlot={facetsToPlot}\n detailsPagePath={detailsPagePath}\n plotType={plotType}\n />\n </QueryWrapperErrorBoundary>\n </QueryVisualizationWrapper>\n </QueryWrapper>\n )\n}\n\nexport default QueryPerFacetPlotsCard\n"],"mappings":";;;;;;;;;;;;;AAwBA,SAAS,EACP,GACA,GACA,GACoB;AAEpB,QAAO;EACL,UAFe,EAA8B,EAE7C;EACA,cAAc;EACd,UACE;EAEF,OAAO;GACL;GACA,QAAQ;GACR,OAAA;GACA,gBAAgB,CACd;IACE,YAAY;IACZ,aAAa,CAAC,EAAuB;IACrC,cACE;IACH,CACF;GACF;EACF;;AAEH,SAAS,EAAuB,GAAoC;CAClE,IAAM,EACJ,UACA,gBACA,QACA,iBACA,aACA,0BACA,2BACA,oBACA,aACA,GAAG,MACD,GACE,IAAuC,EAC3C,GACA,GACA,EACD,EAQK,IAAkB,KAAK,UAAU,EAAiB;AACxD,QACE,kBAAC,GAAD;EACE,GAAI;EACc;EAClB,KAAK;EAaQ,EAXb,kBAAC,GAAD;EAAqC;EAAU,GAAI;YACjD,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;GACS;GACM;GACC;GACG;GACP;GACV,CAAA,EACwB,CAAA;EACF,CAAA,CACf"}
@@ -1 +1 @@
1
- {"version":3,"file":"SingleQueryFacetPlotsCards.js","names":[],"sources":["../../../src/components/FeaturedDataTabs/SingleQueryFacetPlotsCards.tsx"],"sourcesContent":["import { SynapseConstants } from '@/utils'\nimport { parseEntityIdFromSqlStatement } from '@/utils/functions'\nimport { QueryBundleRequest } from '@sage-bionetworks/synapse-types'\nimport { chunk } from 'lodash-es'\nimport {\n QueryVisualizationContextType,\n QueryVisualizationWrapper,\n} from '../QueryVisualizationWrapper'\nimport { QueryWrapper } from '../QueryWrapper'\nimport { QueryWrapperErrorBoundary } from '../QueryWrapperErrorBoundary'\nimport FacetPlotsCard, { FacetPlotsCardProps } from './FacetPlotsCard'\nimport { FacetPlotsCardGridContainer } from './FacetPlotsCardGrid'\nimport { CARDS_PER_ROW } from './FeaturedDataTabsUtils'\n\nexport type SingleQueryFacetPlotsCardsProps = {\n rgbIndex?: number\n facetsToPlot?: string[]\n columnAliases?: Record<string, string>\n sql?: string\n} & Pick<QueryVisualizationContextType, 'unitDescription'> &\n Pick<FacetPlotsCardProps, 'plotType'>\n\nfunction getQueryRequest(sql: string): QueryBundleRequest {\n const entityId = parseEntityIdFromSqlStatement(sql)\n return {\n entityId,\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n partMask:\n SynapseConstants.BUNDLE_MASK_QUERY_COLUMN_MODELS |\n SynapseConstants.BUNDLE_MASK_QUERY_FACETS,\n query: {\n sql,\n offset: 0,\n limit: 1,\n },\n }\n}\n\nfunction SingleQueryFacetPlotsCards(props: SingleQueryFacetPlotsCardsProps) {\n const {\n sql,\n facetsToPlot,\n rgbIndex,\n columnAliases,\n unitDescription,\n plotType,\n } = props\n const initQueryRequest: QueryBundleRequest = getQueryRequest(sql!)\n\n /**\n * Fully re-render the uncontrolled QueryWrapper component when the initial query changes. This eliminates a class of\n * bugs where our 'derived' state (the current query), which should be reset, is out of sync with props.\n *\n * See https://legacy.reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#recommendation-fully-uncontrolled-component-with-a-key\n */\n const queryWrapperKey = JSON.stringify(initQueryRequest)\n\n return (\n <QueryWrapper initQueryRequest={initQueryRequest} key={queryWrapperKey}>\n <QueryVisualizationWrapper\n rgbIndex={rgbIndex}\n columnAliases={columnAliases}\n unitDescription={unitDescription}\n >\n <QueryWrapperErrorBoundary>\n {chunk(facetsToPlot, CARDS_PER_ROW).map((facets, rowIndex) => {\n return (\n <FacetPlotsCardGridContainer\n key={rowIndex}\n className={`FeaturedDataPlots__queryPerCard`}\n sx={{\n my: 4,\n }}\n >\n {facets?.map(facetName => {\n return (\n <FacetPlotsCard\n key={facetName}\n facetsToPlot={[facetName]}\n plotType={plotType}\n />\n )\n })}\n </FacetPlotsCardGridContainer>\n )\n })}\n </QueryWrapperErrorBoundary>\n </QueryVisualizationWrapper>\n </QueryWrapper>\n )\n}\n\nexport default SingleQueryFacetPlotsCards\n"],"mappings":";;;;;;;;;;;;;;;AAsBA,SAAS,EAAgB,GAAiC;AAExD,QAAO;EACL,UAFe,EAA8B,EAAI;EAGjD,cAAc;EACd,UACE;EAEF,OAAO;GACL;GACA,QAAQ;GACR,OAAO;GACR;EACF;;AAGH,SAAS,EAA2B,GAAwC;CAC1E,IAAM,EACJ,QACA,iBACA,aACA,kBACA,oBACA,gBACE,GACE,IAAuC,EAAgB,EAAK,EAQ5D,IAAkB,KAAK,UAAU,EAAiB;AAExD,QACE,kBAAC,GAAD;EAAgC;YAC9B,kBAAC,GAAD;GACY;GACK;GACE;aAEjB,kBAAC,GAAD,EAAA,UACG,EAAM,GAAA,EAA4B,CAAC,KAAK,GAAQ,MAE7C,kBAAC,GAAD;IAEE,WAAW;IACX,IAAI,EACF,IAAI,GACL;cAEA,GAAQ,KAAI,MAET,kBAAC,GAAD;KAEE,cAAc,CAAC,EAAU;KACf;KACV,EAHK,EAGL,CAEJ;IAC0B,EAfvB,EAeuB,CAEhC,EACwB,CAAA;GACF,CAAA;EACf,EA9BwC,EA8BxC"}
1
+ {"version":3,"file":"SingleQueryFacetPlotsCards.js","names":[],"sources":["../../../src/components/FeaturedDataTabs/SingleQueryFacetPlotsCards.tsx"],"sourcesContent":["import { SynapseConstants } from '@/utils'\nimport { parseEntityIdFromSqlStatement } from '@/utils/functions'\nimport { QueryBundleRequest } from '@sage-bionetworks/synapse-types'\nimport { chunk } from 'lodash-es'\nimport {\n QueryVisualizationContextType,\n QueryVisualizationWrapper,\n} from '../QueryVisualizationWrapper'\nimport { QueryWrapper } from '../QueryWrapper'\nimport { QueryWrapperErrorBoundary } from '../QueryWrapperErrorBoundary'\nimport FacetPlotsCard, { FacetPlotsCardProps } from './FacetPlotsCard'\nimport { FacetPlotsCardGridContainer } from './FacetPlotsCardGrid'\nimport { CARDS_PER_ROW } from './FeaturedDataTabsUtils'\n\nexport type SingleQueryFacetPlotsCardsProps = {\n rgbIndex?: number\n facetsToPlot?: string[]\n columnAliases?: Record<string, string>\n sql?: string\n} & Pick<QueryVisualizationContextType, 'unitDescription'> &\n Pick<FacetPlotsCardProps, 'plotType'>\n\nfunction getQueryRequest(sql: string): QueryBundleRequest {\n const entityId = parseEntityIdFromSqlStatement(sql)\n return {\n entityId,\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n partMask:\n SynapseConstants.BUNDLE_MASK_QUERY_COLUMN_MODELS |\n SynapseConstants.BUNDLE_MASK_QUERY_FACETS,\n query: {\n sql,\n offset: 0,\n limit: 1,\n },\n }\n}\n\nfunction SingleQueryFacetPlotsCards(props: SingleQueryFacetPlotsCardsProps) {\n const {\n sql,\n facetsToPlot,\n rgbIndex,\n columnAliases,\n unitDescription,\n plotType,\n } = props\n const initQueryRequest: QueryBundleRequest = getQueryRequest(sql!)\n\n /**\n * Fully re-render the uncontrolled QueryWrapper component when the initial query changes. This eliminates a class of\n * bugs where our 'derived' state (the current query), which should be reset, is out of sync with props.\n *\n * See https://legacy.reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#recommendation-fully-uncontrolled-component-with-a-key\n */\n const queryWrapperKey = JSON.stringify(initQueryRequest)\n\n return (\n <QueryWrapper initQueryRequest={initQueryRequest} key={queryWrapperKey}>\n <QueryVisualizationWrapper\n rgbIndex={rgbIndex}\n columnAliases={columnAliases}\n unitDescription={unitDescription}\n >\n <QueryWrapperErrorBoundary>\n {chunk(facetsToPlot, CARDS_PER_ROW).map((facets, rowIndex) => {\n return (\n <FacetPlotsCardGridContainer\n key={rowIndex}\n className={`FeaturedDataPlots__queryPerCard`}\n sx={{\n my: 4,\n }}\n >\n {facets?.map(facetName => {\n return (\n <FacetPlotsCard\n key={facetName}\n facetsToPlot={[facetName]}\n plotType={plotType}\n />\n )\n })}\n </FacetPlotsCardGridContainer>\n )\n })}\n </QueryWrapperErrorBoundary>\n </QueryVisualizationWrapper>\n </QueryWrapper>\n )\n}\n\nexport default SingleQueryFacetPlotsCards\n"],"mappings":";;;;;;;;;;;;;;;AAsBA,SAAS,EAAgB,GAAiC;AAExD,QAAO;EACL,UAFe,EAA8B,EAE7C;EACA,cAAc;EACd,UACE;EAEF,OAAO;GACL;GACA,QAAQ;GACR,OAAO;GACR;EACF;;AAGH,SAAS,EAA2B,GAAwC;CAC1E,IAAM,EACJ,QACA,iBACA,aACA,kBACA,oBACA,gBACE,GACE,IAAuC,EAAgB,EAAK,EAQ5D,IAAkB,KAAK,UAAU,EAAiB;AAExD,QACE,kBAAC,GAAD;EAAgC;YAC9B,kBAAC,GAAD;GACY;GACK;GACE;aAEjB,kBAAC,GAAD,EAAA,UACG,EAAM,GAAA,EAA4B,CAAC,KAAK,GAAQ,MAE7C,kBAAC,GAAD;IAEE,WAAW;IACX,IAAI,EACF,IAAI,GACL;cAEA,GAAQ,KAAI,MAET,kBAAC,GAAD;KAEE,cAAc,CAAC,EAAU;KACf;KACV,EAHK,EAGL,CAEJ;IAC0B,EAfvB,EAeuB,CAEhC,EACwB,CAAA;GACF,CAAA;EACf,EA9BwC,EA8BxC"}