synapse-react-client 4.0.17 → 4.0.19

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 (297) hide show
  1. package/README.md +5 -3
  2. package/dist/SWC.index.d.ts +2 -0
  3. package/dist/SWC.index.d.ts.map +1 -1
  4. package/dist/SWC.index.js +3 -1
  5. package/dist/SWC.index.js.map +1 -1
  6. package/dist/assets/homepage/BlinkingLiveIcon.d.ts +1 -1
  7. package/dist/components/AccessRequirementAclEditor/AccessRequirementAclEditor.d.ts.map +1 -1
  8. package/dist/components/AccessRequirementAclEditor/AccessRequirementAclEditor.js.map +1 -1
  9. package/dist/components/AccessRequirementList/AccessRequirementList.js.map +1 -1
  10. package/dist/components/AccessRequirementList/RequirementItem/CertificationRequirement.js.map +1 -1
  11. package/dist/components/AccessRequirementList/RequirementItem/SelfSignAccessRequirementItem.js.map +1 -1
  12. package/dist/components/AccessRequirementList/RequirementItem/UnmanagedACTAccessRequirementItem.js.map +1 -1
  13. package/dist/components/AccessRequirementList/RequirementItem/ValidationRequirement.js.map +1 -1
  14. package/dist/components/AccessTokenPage/CreateAccessTokenModal.d.ts.map +1 -1
  15. package/dist/components/AccessTokenPage/CreateAccessTokenModal.js +56 -54
  16. package/dist/components/AccessTokenPage/CreateAccessTokenModal.js.map +1 -1
  17. package/dist/components/Authentication/PasswordField.d.ts +1 -1
  18. package/dist/components/Authentication/PasswordField.d.ts.map +1 -1
  19. package/dist/components/Authentication/PasswordField.js.map +1 -1
  20. package/dist/components/Authentication/TwoFactorEnrollmentForm.d.ts.map +1 -1
  21. package/dist/components/Authentication/TwoFactorEnrollmentForm.js +1 -2
  22. package/dist/components/Authentication/TwoFactorEnrollmentForm.js.map +1 -1
  23. package/dist/components/Authentication/UsernamePasswordForm.d.ts.map +1 -1
  24. package/dist/components/Authentication/UsernamePasswordForm.js +32 -29
  25. package/dist/components/Authentication/UsernamePasswordForm.js.map +1 -1
  26. package/dist/components/CardContainer/CardLink.d.ts +2 -2
  27. package/dist/components/CardContainer/CardLink.d.ts.map +1 -1
  28. package/dist/components/CardDeck/CardDeckCardProps.d.ts.map +1 -1
  29. package/dist/components/ChallengeSubmission/SubmissionDirectoryList.js.map +1 -1
  30. package/dist/components/ChallengeTeamWizard/CreateChallengeTeam.d.ts.map +1 -1
  31. package/dist/components/ChallengeTeamWizard/CreateChallengeTeam.js +106 -103
  32. package/dist/components/ChallengeTeamWizard/CreateChallengeTeam.js.map +1 -1
  33. package/dist/components/ChallengeTeamWizard/MembershipRequestForm.d.ts.map +1 -1
  34. package/dist/components/ChallengeTeamWizard/MembershipRequestForm.js.map +1 -1
  35. package/dist/components/ChallengeTeamWizard/useCreateAndRegisterChallengeTeam.d.ts.map +1 -1
  36. package/dist/components/ChallengeTeamWizard/useCreateAndRegisterChallengeTeam.js.map +1 -1
  37. package/dist/components/CreateProjectModal/CreateProjectModal.d.ts.map +1 -1
  38. package/dist/components/CreateProjectModal/CreateProjectModal.js +4 -4
  39. package/dist/components/CreateProjectModal/CreateProjectModal.js.map +1 -1
  40. package/dist/components/CreateTableViewWizard/TableNameForm.js +6 -6
  41. package/dist/components/CreateTableViewWizard/TableNameForm.js.map +1 -1
  42. package/dist/components/CrispChat/CrispChat.js +4 -4
  43. package/dist/components/CrispChat/CrispChat.js.map +1 -1
  44. package/dist/components/DataExplorer/DataExplorer.css +1 -0
  45. package/dist/components/DataExplorer/DataExplorer.d.ts +13 -0
  46. package/dist/components/DataExplorer/DataExplorer.d.ts.map +1 -0
  47. package/dist/components/DataExplorer/DataExplorer.js +119 -0
  48. package/dist/components/DataExplorer/DataExplorer.js.map +1 -0
  49. package/dist/components/DataExplorer/DataExplorer.module.js +22 -0
  50. package/dist/components/DataExplorer/DataExplorer.module.js.map +1 -0
  51. package/dist/components/DataExplorer/DataExplorer.module.scss +156 -0
  52. package/dist/components/DataGrid/columns/AutocompleteColumn.d.ts.map +1 -1
  53. package/dist/components/DataGrid/columns/AutocompleteColumn.js +106 -102
  54. package/dist/components/DataGrid/columns/AutocompleteColumn.js.map +1 -1
  55. package/dist/components/DataGrid/columns/AutocompleteMultipleEnumColumn.d.ts.map +1 -1
  56. package/dist/components/DataGrid/columns/AutocompleteMultipleEnumColumn.js +97 -89
  57. package/dist/components/DataGrid/columns/AutocompleteMultipleEnumColumn.js.map +1 -1
  58. package/dist/components/DataGrid/columns/useGridAutocompleteState.d.ts +19 -8
  59. package/dist/components/DataGrid/columns/useGridAutocompleteState.d.ts.map +1 -1
  60. package/dist/components/DataGrid/columns/useGridAutocompleteState.js +64 -43
  61. package/dist/components/DataGrid/columns/useGridAutocompleteState.js.map +1 -1
  62. package/dist/components/DataGrid/components/UploadCsvToGridDialog.d.ts.map +1 -1
  63. package/dist/components/DataGrid/components/UploadCsvToGridDialog.js +9 -9
  64. package/dist/components/DataGrid/components/UploadCsvToGridDialog.js.map +1 -1
  65. package/dist/components/DataGrid/hooks/useGetSchemaForGrid.d.ts.map +1 -1
  66. package/dist/components/DataGrid/hooks/useGetSchemaForGrid.js +8 -1
  67. package/dist/components/DataGrid/hooks/useGetSchemaForGrid.js.map +1 -1
  68. package/dist/components/DataGrid/utils/json-rx/JsonRxResponseComplete.js.map +1 -1
  69. package/dist/components/DownloadCart/RequestDownloadCard.js +14 -14
  70. package/dist/components/DownloadCart/RequestDownloadCard.js.map +1 -1
  71. package/dist/components/EntityAclEditor/EntityAclEditor.d.ts.map +1 -1
  72. package/dist/components/EntityAclEditor/EntityAclEditor.js.map +1 -1
  73. package/dist/components/EntityBadgeIcons/EntityBadgeIcons.d.ts.map +1 -1
  74. package/dist/components/EntityBadgeIcons/EntityBadgeIcons.js.map +1 -1
  75. package/dist/components/EntityCitation/EntityCitationUtils.js.map +1 -1
  76. package/dist/components/EntityDownloadConfirmation/EntityDownloadConfirmation.js.map +1 -1
  77. package/dist/components/EntityFinder/EntityFinder.js.map +1 -1
  78. package/dist/components/EntityFinder/EntityIdTextField.d.ts +17 -0
  79. package/dist/components/EntityFinder/EntityIdTextField.d.ts.map +1 -0
  80. package/dist/components/EntityFinder/EntityIdTextField.js +35 -0
  81. package/dist/components/EntityFinder/EntityIdTextField.js.map +1 -0
  82. package/dist/components/Evaluation/round_limits/EvaluationRoundLimitOptions.d.ts.map +1 -1
  83. package/dist/components/Evaluation/round_limits/EvaluationRoundLimitOptions.js +22 -16
  84. package/dist/components/Evaluation/round_limits/EvaluationRoundLimitOptions.js.map +1 -1
  85. package/dist/components/FeaturedDataTabs/FacetPlotsCardGrid.js.map +1 -1
  86. package/dist/components/Forum/ForumThreadEditor.js.map +1 -1
  87. package/dist/components/FullWidthAlert/FullWidthAlert.d.ts.map +1 -1
  88. package/dist/components/FullWidthAlert/FullWidthAlert.js.map +1 -1
  89. package/dist/components/GenericCard/PortalDOI/PortalDOIUtils.d.ts.map +1 -1
  90. package/dist/components/GenericCard/PortalDOI/PortalDOIUtils.js.map +1 -1
  91. package/dist/components/Markdown/widget/MarkdownSynapsePlot.js.map +1 -1
  92. package/dist/components/OAuthClientAclEditor/OAuthClientAclEditor.d.ts.map +1 -1
  93. package/dist/components/OAuthClientAclEditor/OAuthClientAclEditor.js.map +1 -1
  94. package/dist/components/PortalAclEditor/PortalAclEditor.d.ts.map +1 -1
  95. package/dist/components/PortalAclEditor/PortalAclEditor.js.map +1 -1
  96. package/dist/components/PortalHomePageHeader/PortalHomePageHeader.d.ts +1 -1
  97. package/dist/components/PortalHomePageHeader/PortalHomePageHeader.d.ts.map +1 -1
  98. package/dist/components/PortalHomePageHeader/PortalHomePageHeader.js +1 -1
  99. package/dist/components/PortalHomePageHeader/PortalHomePageHeader.js.map +1 -1
  100. package/dist/components/PortalList/CreatePortalModal.d.ts.map +1 -1
  101. package/dist/components/PortalList/CreatePortalModal.js +34 -33
  102. package/dist/components/PortalList/CreatePortalModal.js.map +1 -1
  103. package/dist/components/QueryVisualizationWrapper/QueryVisualizationWrapper.d.ts.map +1 -1
  104. package/dist/components/QueryVisualizationWrapper/QueryVisualizationWrapper.js +67 -65
  105. package/dist/components/QueryVisualizationWrapper/QueryVisualizationWrapper.js.map +1 -1
  106. package/dist/components/QueryWrapperPlotNav/QueryWrapperPlotNav.d.ts +1 -1
  107. package/dist/components/QueryWrapperPlotNav/QueryWrapperPlotNav.d.ts.map +1 -1
  108. package/dist/components/QueryWrapperPlotNav/QueryWrapperPlotNav.js +1 -0
  109. package/dist/components/QueryWrapperPlotNav/QueryWrapperPlotNav.js.map +1 -1
  110. package/dist/components/QueryWrapperPlotNav/RowSetView.d.ts.map +1 -1
  111. package/dist/components/QueryWrapperPlotNav/RowSetView.js.map +1 -1
  112. package/dist/components/Resources/Resources.Desktop.js.map +1 -1
  113. package/dist/components/SearchQueryWrapper/SearchQueryUseQueryOptions.js.map +1 -1
  114. package/dist/components/SearchQueryWrapperPlotNav/SearchQueryWrapperPlotNav.d.ts +1 -1
  115. package/dist/components/SearchQueryWrapperPlotNav/SearchQueryWrapperPlotNav.d.ts.map +1 -1
  116. package/dist/components/SearchQueryWrapperPlotNav/SearchQueryWrapperPlotNav.js +1 -0
  117. package/dist/components/SearchQueryWrapperPlotNav/SearchQueryWrapperPlotNav.js.map +1 -1
  118. package/dist/components/SetAccessRequirementCommonFields/SetAccessRequirementCommonFields.d.ts.map +1 -1
  119. package/dist/components/SetAccessRequirementCommonFields/SetAccessRequirementCommonFields.js.map +1 -1
  120. package/dist/components/SetBasicAccessRequirementFields/SetBasicAccessRequirementFields.d.ts.map +1 -1
  121. package/dist/components/SetBasicAccessRequirementFields/SetBasicAccessRequirementFields.js.map +1 -1
  122. package/dist/components/SetManagedAccessRequirementFields/SetManagedAccessRequirementFields.d.ts.map +1 -1
  123. package/dist/components/SetManagedAccessRequirementFields/SetManagedAccessRequirementFields.js.map +1 -1
  124. package/dist/components/StandaloneQueryWrapper/StandaloneQueryWrapper.d.ts +1 -1
  125. package/dist/components/StandaloneQueryWrapper/StandaloneQueryWrapper.d.ts.map +1 -1
  126. package/dist/components/StandaloneQueryWrapper/StandaloneQueryWrapper.js.map +1 -1
  127. package/dist/components/SynapseChat/SynapseChatInteraction.js.map +1 -1
  128. package/dist/components/SynapsePortalBanners/SynapsePortalBanners.d.ts.map +1 -1
  129. package/dist/components/SynapsePortalBanners/SynapsePortalBanners.js +1 -1
  130. package/dist/components/SynapsePortalBanners/SynapsePortalBanners.js.map +1 -1
  131. package/dist/components/SynapseTable/SearchV2.js.map +1 -1
  132. package/dist/components/SynapseTable/SynapseTable.js.map +1 -1
  133. package/dist/components/SynapseTable/SynapseTableUtils.d.ts.map +1 -1
  134. package/dist/components/SynapseTable/SynapseTableUtils.js.map +1 -1
  135. package/dist/components/SynapseTable/datasets/DatasetItemsEditor.js.map +1 -1
  136. package/dist/components/TableColumnSchemaEditor/ColumnModelForm.js +9 -9
  137. package/dist/components/TableColumnSchemaEditor/ColumnModelForm.js.map +1 -1
  138. package/dist/components/TableColumnSchemaEditor/ColumnModelFormFields/MultiValueField.js +4 -4
  139. package/dist/components/TableColumnSchemaEditor/TableColumnSchemaForm.d.ts.map +1 -1
  140. package/dist/components/TableColumnSchemaEditor/TableColumnSchemaForm.js +25 -25
  141. package/dist/components/TableColumnSchemaEditor/TableColumnSchemaForm.js.map +1 -1
  142. package/dist/components/TanStackTable/TanStackTableUtils.js.map +1 -1
  143. package/dist/components/TextField/TextField.css +1 -1
  144. package/dist/components/TextField/TextField.d.ts +14 -3
  145. package/dist/components/TextField/TextField.d.ts.map +1 -1
  146. package/dist/components/TextField/TextField.js +41 -43
  147. package/dist/components/TextField/TextField.js.map +1 -1
  148. package/dist/components/TextField/TextField.module.js +3 -4
  149. package/dist/components/TextField/TextField.module.js.map +1 -1
  150. package/dist/components/TextField/TextField.module.scss +18 -10
  151. package/dist/components/TimelinePlot/TimelinePlotSpeciesSelector.d.ts.map +1 -1
  152. package/dist/components/TimelinePlot/TimelinePlotSpeciesSelector.js +20 -16
  153. package/dist/components/TimelinePlot/TimelinePlotSpeciesSelector.js.map +1 -1
  154. package/dist/components/UserCardList/UserCardList.d.ts.map +1 -1
  155. package/dist/components/UserCardList/UserCardList.js.map +1 -1
  156. package/dist/components/UserCardList/UserCardListGroups/UserCardListGroups.Desktop.js.map +1 -1
  157. package/dist/components/UserOrTeamBadge/useUserOrTeam.js.map +1 -1
  158. package/dist/components/UserSearchBox/UserSearchBox.d.ts.map +1 -1
  159. package/dist/components/UserSearchBox/UserSearchBox.js.map +1 -1
  160. package/dist/components/WikiMarkdownEditorButton/WikiMarkdownEditorButton.js.map +1 -1
  161. package/dist/components/dataaccess/SubmissionPage/SubmissionPage.js.map +1 -1
  162. package/dist/components/doi/CreateOrUpdateDoiModal.js +13 -13
  163. package/dist/components/doi/CreateOrUpdateDoiModal.js.map +1 -1
  164. package/dist/components/entity/page/title_bar/TitleBarProperties.js +23 -23
  165. package/dist/components/entity/page/title_bar/TitleBarProperties.js.map +1 -1
  166. package/dist/components/entity/page/title_bar/useGetMentions.js.map +1 -1
  167. package/dist/components/index.js +17 -17
  168. package/dist/components/styled/StyledFormControl.d.ts +15 -0
  169. package/dist/components/styled/StyledFormControl.d.ts.map +1 -1
  170. package/dist/components/styled/StyledFormControl.js +1 -0
  171. package/dist/components/styled/StyledFormControl.js.map +1 -1
  172. package/dist/components/styled/index.js +3 -3
  173. package/dist/components/table/CsvPreview/CreateTableFromCsvDialog.d.ts +18 -0
  174. package/dist/components/table/CsvPreview/CreateTableFromCsvDialog.d.ts.map +1 -0
  175. package/dist/components/table/CsvPreview/CreateTableFromCsvDialog.js +116 -0
  176. package/dist/components/table/CsvPreview/CreateTableFromCsvDialog.js.map +1 -0
  177. package/dist/components/table/CsvPreview/CsvPreviewDialog.d.ts +5 -5
  178. package/dist/components/table/CsvPreview/CsvPreviewDialog.d.ts.map +1 -1
  179. package/dist/components/table/CsvPreview/CsvPreviewDialog.js +27 -76
  180. package/dist/components/table/CsvPreview/CsvPreviewDialog.js.map +1 -1
  181. package/dist/components/table/CsvPreview/CsvPreviewWithOptions.d.ts +19 -0
  182. package/dist/components/table/CsvPreview/CsvPreviewWithOptions.d.ts.map +1 -0
  183. package/dist/components/table/CsvPreview/CsvPreviewWithOptions.js +41 -0
  184. package/dist/components/table/CsvPreview/CsvPreviewWithOptions.js.map +1 -0
  185. package/dist/components/table/CsvPreview/CsvUploadPreviewContent.d.ts +12 -0
  186. package/dist/components/table/CsvPreview/CsvUploadPreviewContent.d.ts.map +1 -0
  187. package/dist/components/table/CsvPreview/CsvUploadPreviewContent.js +25 -0
  188. package/dist/components/table/CsvPreview/CsvUploadPreviewContent.js.map +1 -0
  189. package/dist/components/table/CsvPreview/UpdateTableWithCsvDialog.d.ts +18 -0
  190. package/dist/components/table/CsvPreview/UpdateTableWithCsvDialog.d.ts.map +1 -0
  191. package/dist/components/table/CsvPreview/UpdateTableWithCsvDialog.js +55 -0
  192. package/dist/components/table/CsvPreview/UpdateTableWithCsvDialog.js.map +1 -0
  193. package/dist/components/table/CsvPreview/useCreateTableFromCsv.d.ts +19 -0
  194. package/dist/components/table/CsvPreview/useCreateTableFromCsv.d.ts.map +1 -0
  195. package/dist/components/table/CsvPreview/useCreateTableFromCsv.js +35 -0
  196. package/dist/components/table/CsvPreview/useCreateTableFromCsv.js.map +1 -0
  197. package/dist/components/table/CsvPreview/useCsvUploadPreview.d.ts +22 -0
  198. package/dist/components/table/CsvPreview/useCsvUploadPreview.d.ts.map +1 -0
  199. package/dist/components/table/CsvPreview/useCsvUploadPreview.js +32 -0
  200. package/dist/components/table/CsvPreview/useCsvUploadPreview.js.map +1 -0
  201. package/dist/components/table/CsvPreview/useUploadCsvToExistingTable.d.ts +14 -0
  202. package/dist/components/table/CsvPreview/useUploadCsvToExistingTable.d.ts.map +1 -0
  203. package/dist/components/table/CsvPreview/useUploadCsvToExistingTable.js +23 -0
  204. package/dist/components/table/CsvPreview/useUploadCsvToExistingTable.js.map +1 -0
  205. package/dist/components/utils/ConditionalWrapper.d.ts.map +1 -1
  206. package/dist/components/utils/ConditionalWrapper.js.map +1 -1
  207. package/dist/components/widgets/ElementWithTooltip.js.map +1 -1
  208. package/dist/components/widgets/facet-nav/FacetNavPanel.d.ts.map +1 -1
  209. package/dist/components/widgets/facet-nav/FacetNavPanel.js +69 -62
  210. package/dist/components/widgets/facet-nav/FacetNavPanel.js.map +1 -1
  211. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilter.d.ts +1 -0
  212. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilter.d.ts.map +1 -1
  213. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilter.js +27 -26
  214. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilter.js.map +1 -1
  215. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterDropdown.d.ts +1 -0
  216. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterDropdown.d.ts.map +1 -1
  217. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterDropdown.js +2 -1
  218. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterDropdown.js.map +1 -1
  219. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterUI.d.ts +1 -0
  220. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterUI.d.ts.map +1 -1
  221. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterUI.js +44 -43
  222. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterUI.js.map +1 -1
  223. package/dist/features/entity/metadata-task/components/CreateOrUpdateCurationTaskDialog.d.ts +13 -0
  224. package/dist/features/entity/metadata-task/components/CreateOrUpdateCurationTaskDialog.d.ts.map +1 -0
  225. package/dist/features/entity/metadata-task/components/CreateOrUpdateCurationTaskDialog.js +398 -0
  226. package/dist/features/entity/metadata-task/components/CreateOrUpdateCurationTaskDialog.js.map +1 -0
  227. package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.d.ts.map +1 -1
  228. package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.js +49 -19
  229. package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.js.map +1 -1
  230. package/dist/features/entity/metadata-task/components/MetadataTasksPage.d.ts.map +1 -1
  231. package/dist/features/entity/metadata-task/components/MetadataTasksPage.js +49 -25
  232. package/dist/features/entity/metadata-task/components/MetadataTasksPage.js.map +1 -1
  233. package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask.d.ts +0 -1
  234. package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask.d.ts.map +1 -1
  235. package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask.js +20 -22
  236. package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask.js.map +1 -1
  237. package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.d.ts.map +1 -1
  238. package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.js +25 -27
  239. package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.js.map +1 -1
  240. package/dist/features/entity/metadata-task/utils/constants.d.ts +29 -0
  241. package/dist/features/entity/metadata-task/utils/constants.d.ts.map +1 -1
  242. package/dist/features/entity/metadata-task/utils/constants.js +2 -2
  243. package/dist/features/entity/metadata-task/utils/constants.js.map +1 -1
  244. package/dist/index.js +17 -17
  245. package/dist/mockServiceWorker.js +6 -8
  246. package/dist/mocks/curation/mockCurationTask.d.ts +2 -2
  247. package/dist/mocks/curation/mockCurationTask.d.ts.map +1 -1
  248. package/dist/mocks/curation/mockCurationTask.js +9 -5
  249. package/dist/mocks/curation/mockCurationTask.js.map +1 -1
  250. package/dist/mocks/msw/handlers/featureFlagHandlers.d.ts +1 -1
  251. package/dist/mocks/msw/handlers/featureFlagHandlers.d.ts.map +1 -1
  252. package/dist/mocks/msw/handlers/featureFlagHandlers.js +1 -1
  253. package/dist/mocks/msw/handlers/featureFlagHandlers.js.map +1 -1
  254. package/dist/style/components/_cards.scss +0 -3
  255. package/dist/style/components/_data-grid-extra.scss +2 -2
  256. package/dist/style/components/_login.scss +6 -2
  257. package/dist/style/main.css +1 -1
  258. package/dist/synapse-client/SynapseClient.d.ts +2 -1
  259. package/dist/synapse-client/SynapseClient.d.ts.map +1 -1
  260. package/dist/synapse-client/SynapseClient.js.map +1 -1
  261. package/dist/synapse-queries/QueryFilterUtils.js.map +1 -1
  262. package/dist/synapse-queries/curation/task/useCurationTask.d.ts +1 -0
  263. package/dist/synapse-queries/curation/task/useCurationTask.d.ts.map +1 -1
  264. package/dist/synapse-queries/curation/task/useCurationTask.js +16 -6
  265. package/dist/synapse-queries/curation/task/useCurationTask.js.map +1 -1
  266. package/dist/synapse-queries/dataaccess/useAccessRequirements.d.ts.map +1 -1
  267. package/dist/synapse-queries/dataaccess/useAccessRequirements.js.map +1 -1
  268. package/dist/synapse-queries/entity/useGetQueryResultBundle.js.map +1 -1
  269. package/dist/synapse-queries/featureflags/useGetFeatureFlag.d.ts +1 -1
  270. package/dist/synapse-queries/featureflags/useGetFeatureFlag.d.ts.map +1 -1
  271. package/dist/synapse-queries/featureflags/useGetFeatureFlag.js.map +1 -1
  272. package/dist/synapse-queries/file/useFiles.d.ts.map +1 -1
  273. package/dist/synapse-queries/file/useFiles.js.map +1 -1
  274. package/dist/synapse-queries/termsOfService/useTermsOfService.d.ts.map +1 -1
  275. package/dist/synapse-queries/termsOfService/useTermsOfService.js.map +1 -1
  276. package/dist/synapse-queries/user/useGetUserChallenges.d.ts.map +1 -1
  277. package/dist/synapse-queries/user/useGetUserChallenges.js.map +1 -1
  278. package/dist/testutils/ReactQueryMockUtils.js.map +1 -1
  279. package/dist/theme/palette/Palettes.d.ts +2 -2
  280. package/dist/theme/palette/Palettes.d.ts.map +1 -1
  281. package/dist/theme/palette/Palettes.js +2 -2
  282. package/dist/theme/palette/Palettes.js.map +1 -1
  283. package/dist/tsconfig.build.tsbuildinfo +1 -1
  284. package/dist/types/ThemeTypes.d.ts +5 -6
  285. package/dist/utils/AppUtils/session/SynapseSessionManager.d.ts.map +1 -1
  286. package/dist/utils/AppUtils/session/SynapseSessionManager.js.map +1 -1
  287. package/dist/utils/featureflag/FeatureFlags.d.ts +13 -0
  288. package/dist/utils/featureflag/FeatureFlags.d.ts.map +1 -0
  289. package/dist/utils/featureflag/FeatureFlags.js +8 -0
  290. package/dist/utils/featureflag/FeatureFlags.js.map +1 -0
  291. package/dist/utils/functions/SanitizeHtmlUtils.js.map +1 -1
  292. package/dist/utils/functions/queryUtils.js.map +1 -1
  293. package/dist/utils/hooks/useGetInfoFromIds.d.ts.map +1 -1
  294. package/dist/utils/hooks/useGetInfoFromIds.js.map +1 -1
  295. package/dist/utils/slots/SlotUtils.d.ts.map +1 -1
  296. package/dist/utils/slots/SlotUtils.js.map +1 -1
  297. package/package.json +5 -6
@@ -1 +1 @@
1
- {"version":3,"file":"SearchQueryUseQueryOptions.js","names":[],"sources":["../../../src/components/SearchQueryWrapper/SearchQueryUseQueryOptions.ts"],"sourcesContent":["import * as SynapseClient from '@/synapse-client/SynapseClient'\nimport { tableQueryUseQueryDefaults } from '@/synapse-queries'\nimport { useGetEntityBundle } from '@/synapse-queries/entity/useEntityBundle'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport {\n AsynchronousJobStatus,\n ColumnModel,\n FACET_COLUMN_RANGE_REQUEST_CONCRETE_TYPE_VALUE,\n FacetColumnRangeRequest,\n FacetColumnResultRange,\n FACET_COLUMN_VALUES_REQUEST_CONCRETE_TYPE_VALUE,\n FacetColumnValuesRequest,\n QueryBundleRequest,\n QueryResultBundle,\n RowSet,\n SortItem,\n TEXT_MATCHES_QUERY_FILTER_CONCRETE_TYPE_VALUE,\n TextMatchesQueryFilter,\n} from '@sage-bionetworks/synapse-types'\nimport type {\n FacetRequest,\n KeyValues,\n SearchIndexQuery,\n SearchKeyRange,\n SearchQueryResults,\n SearchSearchQuery,\n SearchSortField,\n SynapseClientError,\n} from '@sage-bionetworks/synapse-client'\nimport {\n FacetRequestSortDirectionEnum as FacetRequestSortDirectionEnumValues,\n FacetRequestSortFieldEnum as FacetRequestSortFieldEnumValues,\n} from '@sage-bionetworks/synapse-client'\nimport {\n InfiniteData,\n QueryKey,\n UseInfiniteQueryOptions,\n UseSuspenseQueryOptions,\n} from '@tanstack/react-query'\nimport { omit } from 'lodash-es'\nimport dayjs from 'dayjs'\nimport { useCallback, useMemo } from 'react'\nimport { KeyFactory } from '@/synapse-queries/KeyFactory'\n\n/**\n * TanStack Query options for the SearchQueryServicesApi, mirroring TableQueryUseQueryOptions\n * but parameterised over SearchIndexQuery rather than QueryBundleRequest. This eliminates\n * `as unknown as` casts inside the implementation. A single cast to TableQueryUseQueryOptions\n * is still required at the boundary where SearchQueryWrapper assigns these into QueryContextType.\n */\nexport type SearchTableQueryUseQueryOptions = {\n rowDataQueryOptions: UseSuspenseQueryOptions<\n AsynchronousJobStatus<SearchIndexQuery, QueryResultBundle>,\n SynapseClientError,\n RowSet | undefined\n >\n rowDataInfiniteQueryOptions: UseInfiniteQueryOptions<\n AsynchronousJobStatus<SearchIndexQuery, QueryResultBundle>,\n SynapseClientError,\n InfiniteData<AsynchronousJobStatus<SearchIndexQuery, QueryResultBundle>>,\n QueryKey,\n string | number | undefined\n >\n queryMetadataQueryOptions: UseSuspenseQueryOptions<\n AsynchronousJobStatus<SearchIndexQuery, QueryResultBundle>,\n SynapseClientError,\n Omit<QueryResultBundle, 'queryResult'>\n >\n}\n\n/**\n * Converts a QueryBundleRequest (used internally for state management) into a SearchIndexQuery\n * that can be sent to the SearchQueryServicesApi.\n *\n * Mapping:\n * - columnModels (facetType defined) → facetRequests (columns to aggregate as facets, with optional sort config)\n * - query.selectedFacets (enumeration) → termsFilters (IN-clause filters)\n * - query.selectedFacets (range) → rangeFilters (range filters)\n * - query.sort → sort (SortItem { column, direction } → SearchSortField { columnName, direction })\n * - query.limit → limit\n * - query.offset → offset\n * - partMask → dropped (SearchIndexQuery has no bitmask concept)\n */\nexport function toSearchIndexQuery(\n queryBundleRequest: QueryBundleRequest,\n searchIndexId: string,\n columnModels?: ColumnModel[],\n): SearchIndexQuery {\n // Build facetRequests from ColumnModels that have a facetType of 'enumeration'.\n // Range columns are excluded: the Search API's FacetRequest only supports terms aggregations\n // and cannot produce the min/max stats needed for FacetColumnResultRange.\n const facetRequests: FacetRequest[] | undefined = columnModels\n ?.filter(cm => cm.facetType === 'enumeration')\n .map(cm => {\n const facetReq: FacetRequest = { columnName: cm.name, maxValueCount: 100 }\n if (cm.facetSortConfig) {\n // Map FacetColumnSortProperty ('FREQUENCY'|'VALUE') → FacetRequestSortFieldEnum ('COUNT'|'KEY')\n if (cm.facetSortConfig.property != null) {\n facetReq.sortField =\n cm.facetSortConfig.property === 'VALUE'\n ? FacetRequestSortFieldEnumValues.KEY\n : FacetRequestSortFieldEnumValues.COUNT\n }\n if (cm.facetSortConfig.direction != null) {\n facetReq.sortDirection =\n cm.facetSortConfig.direction === 'ASC'\n ? FacetRequestSortDirectionEnumValues.ASC\n : FacetRequestSortDirectionEnumValues.DESC\n }\n }\n return facetReq\n })\n\n // Build termsFilters from enumeration selectedFacets\n const termsFilters: KeyValues[] | undefined =\n queryBundleRequest.query.selectedFacets\n ?.filter(\n (f): f is FacetColumnValuesRequest =>\n f.concreteType === FACET_COLUMN_VALUES_REQUEST_CONCRETE_TYPE_VALUE,\n )\n .map(f => ({ key: f.columnName, values: f.facetValues }))\n\n // Build rangeFilters from range selectedFacets.\n // DATE columns: the Range UI component emits formatted dates (\"YYYY-MM-DD\") but the\n // Search API (OpenSearch) expects unix millisecond timestamps. Convert here.\n const rangeFilters: SearchKeyRange[] | undefined =\n queryBundleRequest.query.selectedFacets\n ?.filter(\n (f): f is FacetColumnRangeRequest =>\n f.concreteType === FACET_COLUMN_RANGE_REQUEST_CONCRETE_TYPE_VALUE,\n )\n .map(f => {\n const columnType = columnModels?.find(\n cm => cm.name === f.columnName,\n )?.columnType\n const toApiValue = (v: string | undefined): string | undefined => {\n if (!v || columnType !== 'DATE') return v\n // Convert \"YYYY-MM-DD\" → unix ms; leave already-numeric values untouched\n if (/^\\d{4}-\\d{2}-\\d{2}$/.test(v)) {\n return String(dayjs(v).valueOf())\n }\n return v\n }\n return {\n key: f.columnName,\n min: toApiValue(f.min),\n max: toApiValue(f.max),\n }\n })\n\n // Extract queryText by concatenating all TextMatchesQueryFilter searchExpression values\n const textMatchesExpressions = queryBundleRequest.query.additionalFilters\n ?.filter(\n (f): f is TextMatchesQueryFilter =>\n f.concreteType === TEXT_MATCHES_QUERY_FILTER_CONCRETE_TYPE_VALUE,\n )\n .map(f => f.searchExpression)\n .filter((expr): expr is string => expr != null && expr.length > 0)\n const queryText =\n textMatchesExpressions && textMatchesExpressions.length > 0\n ? textMatchesExpressions.join(' ')\n : undefined\n\n // Map SortItem[] (column + direction) → SearchSortField[] (columnName + direction),\n // filtering out entries with no direction (which mean \"remove sort\").\n const sort: SearchSortField[] | undefined = queryBundleRequest.query.sort\n ?.filter(\n (s): s is SortItem & { direction: 'ASC' | 'DESC' } =>\n s.direction === 'ASC' || s.direction === 'DESC',\n )\n .map(s => ({ columnName: s.column, direction: s.direction }))\n\n const searchQuery: SearchSearchQuery = {\n facetRequests: facetRequests?.length ? facetRequests : undefined,\n termsFilters: termsFilters?.length ? termsFilters : undefined,\n rangeFilters: rangeFilters?.length ? rangeFilters : undefined,\n queryText,\n queryType: 'MULTI_MATCH',\n fuzziness: 'AUTO',\n sort: sort?.length ? sort : undefined,\n limit: queryBundleRequest.query.limit,\n offset: queryBundleRequest.query.offset,\n }\n\n return {\n concreteType:\n 'org.sagebionetworks.repo.model.search.table.SearchIndexQuery' as const,\n searchIndexId,\n searchQuery,\n }\n}\n\n/**\n * Converts a SearchQueryResults (the actual API response) into a QueryResultBundle\n * so that existing subcomponents (FacetFilterControls, RowSetView, etc.) work unchanged.\n *\n * Mapping:\n * - totalHits → queryCount\n * - hits → queryResult.queryResults (rows derived from hit.rowId/rowVersion/fields)\n * - facets → facets (same FacetColumnResult type)\n */\nexport function searchQueryResultsToQueryResultBundle(\n results: SearchQueryResults | undefined,\n query: SearchIndexQuery,\n columnModels?: ColumnModel[],\n): QueryResultBundle {\n if (!results) {\n return {\n concreteType: 'org.sagebionetworks.repo.model.table.QueryResultBundle',\n }\n }\n\n // Derive column names from the server-returned selectColumns. Both the row data\n // query and the metadata query request SELECT_COLUMNS, so this is always present.\n const fieldNames: string[] =\n results.selectColumns\n ?.map(col => col.name)\n .filter((n): n is string => !!n) ?? []\n\n const headers = fieldNames.map(name => ({\n name,\n columnType:\n columnModels?.find(cm => cm.name === name)?.columnType ??\n ('STRING' as const),\n }))\n\n const rows = (results.hits ?? []).map(hit => ({\n rowId: hit.rowId,\n versionNumber: hit.rowVersion,\n values: fieldNames.map(name => {\n return hit.fields?.find(f => f.name === name)?.value ?? null\n }),\n }))\n\n const queryResult =\n headers.length > 0 || rows.length > 0\n ? {\n concreteType:\n 'org.sagebionetworks.repo.model.table.QueryResult' as const,\n queryResults: {\n concreteType:\n 'org.sagebionetworks.repo.model.table.RowSet' as const,\n tableId: query.searchIndexId ?? '',\n etag: '',\n headers,\n rows,\n },\n }\n : undefined\n\n const rawFacets = results.facets as QueryResultBundle['facets']\n\n // Synthesize FacetColumnResultRange for range-type DATE/DOUBLE/INTEGER columns. The Search API's\n // FacetRequest only produces terms aggregations and cannot return min/max stats, so these\n // entries will never appear in results.facets. columnMin/columnMax are empty strings\n // (unavailable from the server); selectedMin/selectedMax are derived from the query's\n // rangeFilters so any applied range filter is still reflected in the UI.\n // Note: for INTEGER columns the RangeSlider requires real bounds, so the UI falls back to a\n // plain Range number input when columnMin/columnMax are absent.\n const syntheticRangeFacets: FacetColumnResultRange[] = (columnModels ?? [])\n .filter(\n cm =>\n cm.facetType === 'range' &&\n (cm.columnType === 'DATE' ||\n cm.columnType === 'DOUBLE' ||\n cm.columnType === 'INTEGER') &&\n !(rawFacets ?? []).some(f => f.columnName === cm.name),\n )\n .map(cm => {\n const rangeFilter = query.searchQuery?.rangeFilters?.find(\n rf => rf.key === cm.name,\n )\n // rangeFilters carry unix ms for DATE columns (converted in toSearchIndexQuery).\n // Convert back to \"YYYY-MM-DD\" so the Range UI component can display them.\n const toDisplayValue = (v: string | undefined): string | undefined => {\n if (!v || cm.columnType !== 'DATE') return v\n if (/^\\d+$/.test(v)) {\n return dayjs(parseInt(v)).format('YYYY-MM-DD')\n }\n return v\n }\n return {\n concreteType:\n 'org.sagebionetworks.repo.model.table.FacetColumnResultRange' as const,\n facetType: 'range' as const,\n columnName: cm.name,\n columnMin: '',\n columnMax: '',\n selectedMin: toDisplayValue(rangeFilter?.min),\n selectedMax: toDisplayValue(rangeFilter?.max),\n }\n })\n\n const allFacets: NonNullable<QueryResultBundle['facets']> = [\n ...(rawFacets ?? []),\n ...syntheticRangeFacets,\n ]\n\n // Reorder all facets to match the columnModels order so downstream components\n // (e.g. FacetFilterControls) render facets in the expected column order.\n const orderedFacets: QueryResultBundle['facets'] = columnModels\n ? [\n ...allFacets\n .filter(f => columnModels.some(cm => cm.name === f.columnName))\n .sort(\n (a, b) =>\n columnModels.findIndex(cm => cm.name === a.columnName) -\n columnModels.findIndex(cm => cm.name === b.columnName),\n ),\n ...allFacets.filter(\n f => !columnModels.some(cm => cm.name === f.columnName),\n ),\n ]\n : allFacets\n\n return {\n concreteType: 'org.sagebionetworks.repo.model.table.QueryResultBundle',\n queryCount: results.totalHits,\n selectColumns: headers,\n queryResult,\n facets: orderedFacets,\n }\n}\n\nexport function getSearchQueryUseQueryOptions(\n queryBundleRequest: QueryBundleRequest,\n keyFactory: KeyFactory,\n accessToken: string | undefined,\n searchIndexId: string,\n columnModels?: ColumnModel[],\n): SearchTableQueryUseQueryOptions {\n const baseQuery: SearchIndexQuery = toSearchIndexQuery(\n queryBundleRequest,\n searchIndexId,\n columnModels,\n )\n const rowDataQuery: SearchIndexQuery = {\n ...baseQuery,\n searchQuery: {\n ...baseQuery.searchQuery,\n // Omit facetRequests from the row data query: facet aggregations are only needed\n // in the metadata query (which requests FACETS). Removing facetRequests here keeps\n // the row data query key stable while column models are loading, preventing an\n // unnecessary re-fetch (and a brief loading flash) when column models first arrive.\n facetRequests: undefined,\n },\n // Request SELECT_COLUMNS so headers are available for row rendering.\n // HITS is returned by default even when responseParts is specified.\n responseParts: new Set(['HITS', 'SELECT_COLUMNS'] as const),\n }\n const metadataQuery: SearchIndexQuery = {\n ...baseQuery,\n // Request all opt-in parts needed for the metadata response:\n // TOTAL_HITS → queryCount (drives tab count / spinner resolution)\n // SELECT_COLUMNS → column headers for the table\n // FACETS → facet aggregations for FacetFilterControls / plots\n responseParts: new Set(['TOTAL_HITS', 'SELECT_COLUMNS', 'FACETS'] as const),\n }\n\n // Convert responseParts Set → sorted array for query key building.\n // JSON.stringify(new Set([...])) === '{}', so two queries whose only difference is\n // their responseParts would hash to the same key and share a cache entry.\n // Using a sorted array gives each query a distinct, stable key.\n const toKeyShape = (query: SearchIndexQuery) => ({\n ...query,\n responseParts: query.responseParts\n ? [...query.responseParts].sort()\n : undefined,\n })\n\n // Fetches from the SearchQueryServicesApi and converts the SearchQueryResults responseBody\n // into QueryResultBundle shape. This allows all downstream shared components\n // (UseRowSet, QueryVisualizationWrapper, etc.) to access data.responseBody.*\n // using the same patterns as regular table queries (queryResult.queryResults, selectColumns, etc.).\n const fetchAndConvert = async (query: SearchIndexQuery) => {\n const asyncStatus = await SynapseClient.getSearchQueryAsyncJobResults(\n query,\n accessToken,\n )\n return {\n ...asyncStatus,\n responseBody: searchQueryResultsToQueryResultBundle(\n asyncStatus.responseBody,\n query,\n columnModels,\n ),\n }\n }\n\n // `as unknown as` is necessary because SearchIndexQuery.responseParts is a Set but\n // toKeyShape converts it to a sorted string[] for stable cache key serialisation.\n const rowDataQueryOptions: SearchTableQueryUseQueryOptions['rowDataQueryOptions'] =\n {\n ...tableQueryUseQueryDefaults,\n queryKey: keyFactory.getSearchQueryResultWithAsyncStatusQueryKey(\n toKeyShape(rowDataQuery) as unknown as SearchIndexQuery,\n false,\n ),\n queryFn: () => fetchAndConvert(rowDataQuery),\n select: (\n data: AsynchronousJobStatus<SearchIndexQuery, QueryResultBundle>,\n ): RowSet | undefined => data.responseBody?.queryResult?.queryResults,\n }\n\n const rowDataInfiniteQueryOptions: SearchTableQueryUseQueryOptions['rowDataInfiniteQueryOptions'] =\n {\n ...tableQueryUseQueryDefaults,\n queryKey: keyFactory.getSearchQueryResultWithAsyncStatusQueryKey(\n toKeyShape(rowDataQuery) as unknown as SearchIndexQuery,\n true,\n ),\n initialPageParam: 0 as number | string | undefined,\n getNextPageParam: (\n lastPage: AsynchronousJobStatus<SearchIndexQuery, QueryResultBundle>,\n allPages: AsynchronousJobStatus<SearchIndexQuery, QueryResultBundle>[],\n ): number | string | undefined => {\n const totalRows = lastPage.responseBody?.queryCount\n const fetchedRows = allPages.reduce(\n (acc, page) =>\n acc +\n (page.responseBody?.queryResult?.queryResults.rows?.length ?? 0),\n 0,\n )\n if (totalRows != null && fetchedRows >= totalRows) {\n return undefined\n }\n return fetchedRows\n },\n queryFn: (context: { pageParam?: number | string }) => {\n const offset =\n typeof context.pageParam === 'string'\n ? parseInt(context.pageParam)\n : context.pageParam ?? 0\n const requestForPage: SearchIndexQuery = {\n ...rowDataQuery,\n searchQuery: {\n ...rowDataQuery.searchQuery,\n offset,\n },\n }\n return fetchAndConvert(requestForPage)\n },\n select: (\n data: InfiniteData<\n AsynchronousJobStatus<SearchIndexQuery, QueryResultBundle>\n >,\n ) => data,\n }\n\n const queryMetadataQueryOptions: SearchTableQueryUseQueryOptions['queryMetadataQueryOptions'] =\n {\n ...tableQueryUseQueryDefaults,\n queryKey: keyFactory.getSearchQueryResultWithAsyncStatusQueryKey(\n toKeyShape(metadataQuery) as unknown as SearchIndexQuery,\n false,\n ),\n queryFn: () => fetchAndConvert(metadataQuery),\n select: (\n data: AsynchronousJobStatus<SearchIndexQuery, QueryResultBundle>,\n ): Omit<QueryResultBundle, 'queryResult'> => {\n const result = omit(data.responseBody ?? {}, 'queryResult') as Omit<\n QueryResultBundle,\n 'queryResult'\n >\n return columnModels ? { ...result, columnModels } : result\n },\n }\n\n return {\n rowDataQueryOptions,\n rowDataInfiniteQueryOptions,\n queryMetadataQueryOptions,\n }\n}\n\n/**\n * Returns a stable callback that fetches autocomplete suggestions for a search input\n * using the synchronous `POST /search/autocomplete` endpoint.\n *\n * The query is built from the current `searchIndexId` and `autocompleteFieldName`:\n * - `searchQuery.queryText` is set to the user-entered search text\n * - `searchQuery.queryFields` is set to `[autocompleteFieldName]` so the server\n * only returns values for that single field\n *\n * When `autocompleteFieldName` is undefined, the returned callback immediately returns `[]`.\n */\nexport function useGetSuggestionsForSearchIndex(\n searchIndexId: string,\n autocompleteFieldName: string | undefined,\n): (searchText: string) => Promise<string[]> {\n const { synapseClient } = useSynapseContext()\n\n return useCallback(\n async (searchText: string): Promise<string[]> => {\n if (!autocompleteFieldName) return []\n const trimmed = searchText.trim()\n if (!trimmed) return []\n const results =\n await synapseClient.searchManagementServicesClient.postRepoV1SearchAutocomplete(\n {\n searchIndexQuery: {\n concreteType:\n 'org.sagebionetworks.repo.model.search.table.SearchIndexQuery' as const,\n searchIndexId,\n searchQuery: {\n queryText: trimmed,\n queryFields: [autocompleteFieldName],\n returnFields: [autocompleteFieldName],\n },\n },\n },\n )\n const suggestions: string[] = []\n for (const hit of results.hits ?? []) {\n for (const field of hit.fields ?? []) {\n if (field.value) {\n suggestions.push(field.value)\n }\n }\n }\n return suggestions\n },\n [synapseClient, searchIndexId, autocompleteFieldName],\n )\n}\n\n/**\n * Returns TanStack Query options that call the SearchQueryServicesApi (instead of the\n * standard Table Query API) but return data in the same QueryResultBundle format, allowing\n * all existing subcomponents (FacetFilterControls, RowSetView, etc.) to work unchanged.\n */\nexport function useSearchQueryUseQueryOptions(\n queryBundleRequest: QueryBundleRequest,\n searchIndexId: string,\n synapseId?: string,\n): SearchTableQueryUseQueryOptions {\n const { keyFactory, accessToken } = useSynapseContext()\n\n const { data: entityBundle } = useGetEntityBundle(synapseId, undefined, {\n includeTableBundle: true,\n })\n const columnModels = entityBundle?.tableBundle?.columnModels\n\n return useMemo(\n () =>\n getSearchQueryUseQueryOptions(\n queryBundleRequest,\n keyFactory,\n accessToken,\n searchIndexId,\n columnModels,\n ),\n [keyFactory, accessToken, queryBundleRequest, searchIndexId, columnModels],\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"SearchQueryUseQueryOptions.js","names":[],"sources":["../../../src/components/SearchQueryWrapper/SearchQueryUseQueryOptions.ts"],"sourcesContent":["import * as SynapseClient from '@/synapse-client/SynapseClient'\nimport { tableQueryUseQueryDefaults } from '@/synapse-queries'\nimport { useGetEntityBundle } from '@/synapse-queries/entity/useEntityBundle'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport {\n AsynchronousJobStatus,\n ColumnModel,\n FACET_COLUMN_RANGE_REQUEST_CONCRETE_TYPE_VALUE,\n FacetColumnRangeRequest,\n FacetColumnResultRange,\n FACET_COLUMN_VALUES_REQUEST_CONCRETE_TYPE_VALUE,\n FacetColumnValuesRequest,\n QueryBundleRequest,\n QueryResultBundle,\n RowSet,\n SortItem,\n TEXT_MATCHES_QUERY_FILTER_CONCRETE_TYPE_VALUE,\n TextMatchesQueryFilter,\n} from '@sage-bionetworks/synapse-types'\nimport type {\n FacetRequest,\n KeyValues,\n SearchIndexQuery,\n SearchKeyRange,\n SearchQueryResults,\n SearchSearchQuery,\n SearchSortField,\n SynapseClientError,\n} from '@sage-bionetworks/synapse-client'\nimport {\n FacetRequestSortDirectionEnum as FacetRequestSortDirectionEnumValues,\n FacetRequestSortFieldEnum as FacetRequestSortFieldEnumValues,\n} from '@sage-bionetworks/synapse-client'\nimport {\n InfiniteData,\n QueryKey,\n UseInfiniteQueryOptions,\n UseSuspenseQueryOptions,\n} from '@tanstack/react-query'\nimport { omit } from 'lodash-es'\nimport dayjs from 'dayjs'\nimport { useCallback, useMemo } from 'react'\nimport { KeyFactory } from '@/synapse-queries/KeyFactory'\n\n/**\n * TanStack Query options for the SearchQueryServicesApi, mirroring TableQueryUseQueryOptions\n * but parameterised over SearchIndexQuery rather than QueryBundleRequest. This eliminates\n * `as unknown as` casts inside the implementation. A single cast to TableQueryUseQueryOptions\n * is still required at the boundary where SearchQueryWrapper assigns these into QueryContextType.\n */\nexport type SearchTableQueryUseQueryOptions = {\n rowDataQueryOptions: UseSuspenseQueryOptions<\n AsynchronousJobStatus<SearchIndexQuery, QueryResultBundle>,\n SynapseClientError,\n RowSet | undefined\n >\n rowDataInfiniteQueryOptions: UseInfiniteQueryOptions<\n AsynchronousJobStatus<SearchIndexQuery, QueryResultBundle>,\n SynapseClientError,\n InfiniteData<AsynchronousJobStatus<SearchIndexQuery, QueryResultBundle>>,\n QueryKey,\n string | number | undefined\n >\n queryMetadataQueryOptions: UseSuspenseQueryOptions<\n AsynchronousJobStatus<SearchIndexQuery, QueryResultBundle>,\n SynapseClientError,\n Omit<QueryResultBundle, 'queryResult'>\n >\n}\n\n/**\n * Converts a QueryBundleRequest (used internally for state management) into a SearchIndexQuery\n * that can be sent to the SearchQueryServicesApi.\n *\n * Mapping:\n * - columnModels (facetType defined) → facetRequests (columns to aggregate as facets, with optional sort config)\n * - query.selectedFacets (enumeration) → termsFilters (IN-clause filters)\n * - query.selectedFacets (range) → rangeFilters (range filters)\n * - query.sort → sort (SortItem { column, direction } → SearchSortField { columnName, direction })\n * - query.limit → limit\n * - query.offset → offset\n * - partMask → dropped (SearchIndexQuery has no bitmask concept)\n */\nexport function toSearchIndexQuery(\n queryBundleRequest: QueryBundleRequest,\n searchIndexId: string,\n columnModels?: ColumnModel[],\n): SearchIndexQuery {\n // Build facetRequests from ColumnModels that have a facetType of 'enumeration'.\n // Range columns are excluded: the Search API's FacetRequest only supports terms aggregations\n // and cannot produce the min/max stats needed for FacetColumnResultRange.\n const facetRequests: FacetRequest[] | undefined = columnModels\n ?.filter(cm => cm.facetType === 'enumeration')\n .map(cm => {\n const facetReq: FacetRequest = { columnName: cm.name, maxValueCount: 100 }\n if (cm.facetSortConfig) {\n // Map FacetColumnSortProperty ('FREQUENCY'|'VALUE') → FacetRequestSortFieldEnum ('COUNT'|'KEY')\n if (cm.facetSortConfig.property != null) {\n facetReq.sortField =\n cm.facetSortConfig.property === 'VALUE'\n ? FacetRequestSortFieldEnumValues.KEY\n : FacetRequestSortFieldEnumValues.COUNT\n }\n if (cm.facetSortConfig.direction != null) {\n facetReq.sortDirection =\n cm.facetSortConfig.direction === 'ASC'\n ? FacetRequestSortDirectionEnumValues.ASC\n : FacetRequestSortDirectionEnumValues.DESC\n }\n }\n return facetReq\n })\n\n // Build termsFilters from enumeration selectedFacets\n const termsFilters: KeyValues[] | undefined =\n queryBundleRequest.query.selectedFacets\n ?.filter(\n (f): f is FacetColumnValuesRequest =>\n f.concreteType === FACET_COLUMN_VALUES_REQUEST_CONCRETE_TYPE_VALUE,\n )\n .map(f => ({ key: f.columnName, values: f.facetValues }))\n\n // Build rangeFilters from range selectedFacets.\n // DATE columns: the Range UI component emits formatted dates (\"YYYY-MM-DD\") but the\n // Search API (OpenSearch) expects unix millisecond timestamps. Convert here.\n const rangeFilters: SearchKeyRange[] | undefined =\n queryBundleRequest.query.selectedFacets\n ?.filter(\n (f): f is FacetColumnRangeRequest =>\n f.concreteType === FACET_COLUMN_RANGE_REQUEST_CONCRETE_TYPE_VALUE,\n )\n .map(f => {\n const columnType = columnModels?.find(\n cm => cm.name === f.columnName,\n )?.columnType\n const toApiValue = (v: string | undefined): string | undefined => {\n if (!v || columnType !== 'DATE') return v\n // Convert \"YYYY-MM-DD\" → unix ms; leave already-numeric values untouched\n if (/^\\d{4}-\\d{2}-\\d{2}$/.test(v)) {\n return String(dayjs(v).valueOf())\n }\n return v\n }\n return {\n key: f.columnName,\n min: toApiValue(f.min),\n max: toApiValue(f.max),\n }\n })\n\n // Extract queryText by concatenating all TextMatchesQueryFilter searchExpression values\n const textMatchesExpressions = queryBundleRequest.query.additionalFilters\n ?.filter(\n (f): f is TextMatchesQueryFilter =>\n f.concreteType === TEXT_MATCHES_QUERY_FILTER_CONCRETE_TYPE_VALUE,\n )\n .map(f => f.searchExpression)\n .filter((expr): expr is string => expr != null && expr.length > 0)\n const queryText =\n textMatchesExpressions && textMatchesExpressions.length > 0\n ? textMatchesExpressions.join(' ')\n : undefined\n\n // Map SortItem[] (column + direction) → SearchSortField[] (columnName + direction),\n // filtering out entries with no direction (which mean \"remove sort\").\n const sort: SearchSortField[] | undefined = queryBundleRequest.query.sort\n ?.filter(\n (s): s is SortItem & { direction: 'ASC' | 'DESC' } =>\n s.direction === 'ASC' || s.direction === 'DESC',\n )\n .map(s => ({ columnName: s.column, direction: s.direction }))\n\n const searchQuery: SearchSearchQuery = {\n facetRequests: facetRequests?.length ? facetRequests : undefined,\n termsFilters: termsFilters?.length ? termsFilters : undefined,\n rangeFilters: rangeFilters?.length ? rangeFilters : undefined,\n queryText,\n queryType: 'MULTI_MATCH',\n fuzziness: 'AUTO',\n sort: sort?.length ? sort : undefined,\n limit: queryBundleRequest.query.limit,\n offset: queryBundleRequest.query.offset,\n }\n\n return {\n concreteType:\n 'org.sagebionetworks.repo.model.search.table.SearchIndexQuery' as const,\n searchIndexId,\n searchQuery,\n }\n}\n\n/**\n * Converts a SearchQueryResults (the actual API response) into a QueryResultBundle\n * so that existing subcomponents (FacetFilterControls, RowSetView, etc.) work unchanged.\n *\n * Mapping:\n * - totalHits → queryCount\n * - hits → queryResult.queryResults (rows derived from hit.rowId/rowVersion/fields)\n * - facets → facets (same FacetColumnResult type)\n */\nexport function searchQueryResultsToQueryResultBundle(\n results: SearchQueryResults | undefined,\n query: SearchIndexQuery,\n columnModels?: ColumnModel[],\n): QueryResultBundle {\n if (!results) {\n return {\n concreteType: 'org.sagebionetworks.repo.model.table.QueryResultBundle',\n }\n }\n\n // Derive column names from the server-returned selectColumns. Both the row data\n // query and the metadata query request SELECT_COLUMNS, so this is always present.\n const fieldNames: string[] =\n results.selectColumns\n ?.map(col => col.name)\n .filter((n): n is string => !!n) ?? []\n\n const headers = fieldNames.map(name => ({\n name,\n columnType:\n columnModels?.find(cm => cm.name === name)?.columnType ??\n ('STRING' as const),\n }))\n\n const rows = (results.hits ?? []).map(hit => ({\n rowId: hit.rowId,\n versionNumber: hit.rowVersion,\n values: fieldNames.map(name => {\n return hit.fields?.find(f => f.name === name)?.value ?? null\n }),\n }))\n\n const queryResult =\n headers.length > 0 || rows.length > 0\n ? {\n concreteType:\n 'org.sagebionetworks.repo.model.table.QueryResult' as const,\n queryResults: {\n concreteType:\n 'org.sagebionetworks.repo.model.table.RowSet' as const,\n tableId: query.searchIndexId ?? '',\n etag: '',\n headers,\n rows,\n },\n }\n : undefined\n\n const rawFacets = results.facets as QueryResultBundle['facets']\n\n // Synthesize FacetColumnResultRange for range-type DATE/DOUBLE/INTEGER columns. The Search API's\n // FacetRequest only produces terms aggregations and cannot return min/max stats, so these\n // entries will never appear in results.facets. columnMin/columnMax are empty strings\n // (unavailable from the server); selectedMin/selectedMax are derived from the query's\n // rangeFilters so any applied range filter is still reflected in the UI.\n // Note: for INTEGER columns the RangeSlider requires real bounds, so the UI falls back to a\n // plain Range number input when columnMin/columnMax are absent.\n const syntheticRangeFacets: FacetColumnResultRange[] = (columnModels ?? [])\n .filter(\n cm =>\n cm.facetType === 'range' &&\n (cm.columnType === 'DATE' ||\n cm.columnType === 'DOUBLE' ||\n cm.columnType === 'INTEGER') &&\n !(rawFacets ?? []).some(f => f.columnName === cm.name),\n )\n .map(cm => {\n const rangeFilter = query.searchQuery?.rangeFilters?.find(\n rf => rf.key === cm.name,\n )\n // rangeFilters carry unix ms for DATE columns (converted in toSearchIndexQuery).\n // Convert back to \"YYYY-MM-DD\" so the Range UI component can display them.\n const toDisplayValue = (v: string | undefined): string | undefined => {\n if (!v || cm.columnType !== 'DATE') return v\n if (/^\\d+$/.test(v)) {\n return dayjs(parseInt(v)).format('YYYY-MM-DD')\n }\n return v\n }\n return {\n concreteType:\n 'org.sagebionetworks.repo.model.table.FacetColumnResultRange' as const,\n facetType: 'range' as const,\n columnName: cm.name,\n columnMin: '',\n columnMax: '',\n selectedMin: toDisplayValue(rangeFilter?.min),\n selectedMax: toDisplayValue(rangeFilter?.max),\n }\n })\n\n const allFacets: NonNullable<QueryResultBundle['facets']> = [\n ...(rawFacets ?? []),\n ...syntheticRangeFacets,\n ]\n\n // Reorder all facets to match the columnModels order so downstream components\n // (e.g. FacetFilterControls) render facets in the expected column order.\n const orderedFacets: QueryResultBundle['facets'] = columnModels\n ? [\n ...allFacets\n .filter(f => columnModels.some(cm => cm.name === f.columnName))\n .sort(\n (a, b) =>\n columnModels.findIndex(cm => cm.name === a.columnName) -\n columnModels.findIndex(cm => cm.name === b.columnName),\n ),\n ...allFacets.filter(\n f => !columnModels.some(cm => cm.name === f.columnName),\n ),\n ]\n : allFacets\n\n return {\n concreteType: 'org.sagebionetworks.repo.model.table.QueryResultBundle',\n queryCount: results.totalHits,\n selectColumns: headers,\n queryResult,\n facets: orderedFacets,\n }\n}\n\nexport function getSearchQueryUseQueryOptions(\n queryBundleRequest: QueryBundleRequest,\n keyFactory: KeyFactory,\n accessToken: string | undefined,\n searchIndexId: string,\n columnModels?: ColumnModel[],\n): SearchTableQueryUseQueryOptions {\n const baseQuery: SearchIndexQuery = toSearchIndexQuery(\n queryBundleRequest,\n searchIndexId,\n columnModels,\n )\n const rowDataQuery: SearchIndexQuery = {\n ...baseQuery,\n searchQuery: {\n ...baseQuery.searchQuery,\n // Omit facetRequests from the row data query: facet aggregations are only needed\n // in the metadata query (which requests FACETS). Removing facetRequests here keeps\n // the row data query key stable while column models are loading, preventing an\n // unnecessary re-fetch (and a brief loading flash) when column models first arrive.\n facetRequests: undefined,\n },\n // Request SELECT_COLUMNS so headers are available for row rendering.\n // HITS is returned by default even when responseParts is specified.\n responseParts: new Set(['HITS', 'SELECT_COLUMNS'] as const),\n }\n const metadataQuery: SearchIndexQuery = {\n ...baseQuery,\n // Request all opt-in parts needed for the metadata response:\n // TOTAL_HITS → queryCount (drives tab count / spinner resolution)\n // SELECT_COLUMNS → column headers for the table\n // FACETS → facet aggregations for FacetFilterControls / plots\n responseParts: new Set(['TOTAL_HITS', 'SELECT_COLUMNS', 'FACETS'] as const),\n }\n\n // Convert responseParts Set → sorted array for query key building.\n // JSON.stringify(new Set([...])) === '{}', so two queries whose only difference is\n // their responseParts would hash to the same key and share a cache entry.\n // Using a sorted array gives each query a distinct, stable key.\n const toKeyShape = (query: SearchIndexQuery) => ({\n ...query,\n responseParts: query.responseParts\n ? [...query.responseParts].sort()\n : undefined,\n })\n\n // Fetches from the SearchQueryServicesApi and converts the SearchQueryResults responseBody\n // into QueryResultBundle shape. This allows all downstream shared components\n // (UseRowSet, QueryVisualizationWrapper, etc.) to access data.responseBody.*\n // using the same patterns as regular table queries (queryResult.queryResults, selectColumns, etc.).\n const fetchAndConvert = async (query: SearchIndexQuery) => {\n const asyncStatus = await SynapseClient.getSearchQueryAsyncJobResults(\n query,\n accessToken,\n )\n return {\n ...asyncStatus,\n responseBody: searchQueryResultsToQueryResultBundle(\n asyncStatus.responseBody,\n query,\n columnModels,\n ),\n }\n }\n\n // `as unknown as` is necessary because SearchIndexQuery.responseParts is a Set but\n // toKeyShape converts it to a sorted string[] for stable cache key serialisation.\n const rowDataQueryOptions: SearchTableQueryUseQueryOptions['rowDataQueryOptions'] =\n {\n ...tableQueryUseQueryDefaults,\n queryKey: keyFactory.getSearchQueryResultWithAsyncStatusQueryKey(\n toKeyShape(rowDataQuery) as unknown as SearchIndexQuery,\n false,\n ),\n queryFn: () => fetchAndConvert(rowDataQuery),\n select: (\n data: AsynchronousJobStatus<SearchIndexQuery, QueryResultBundle>,\n ): RowSet | undefined => data.responseBody?.queryResult?.queryResults,\n }\n\n const rowDataInfiniteQueryOptions: SearchTableQueryUseQueryOptions['rowDataInfiniteQueryOptions'] =\n {\n ...tableQueryUseQueryDefaults,\n queryKey: keyFactory.getSearchQueryResultWithAsyncStatusQueryKey(\n toKeyShape(rowDataQuery) as unknown as SearchIndexQuery,\n true,\n ),\n initialPageParam: 0 as number | string | undefined,\n getNextPageParam: (\n lastPage: AsynchronousJobStatus<SearchIndexQuery, QueryResultBundle>,\n allPages: AsynchronousJobStatus<SearchIndexQuery, QueryResultBundle>[],\n ): number | string | undefined => {\n const totalRows = lastPage.responseBody?.queryCount\n const fetchedRows = allPages.reduce(\n (acc, page) =>\n acc +\n (page.responseBody?.queryResult?.queryResults.rows?.length ?? 0),\n 0,\n )\n if (totalRows != null && fetchedRows >= totalRows) {\n return undefined\n }\n return fetchedRows\n },\n queryFn: (context: { pageParam?: number | string }) => {\n const offset =\n typeof context.pageParam === 'string'\n ? parseInt(context.pageParam)\n : (context.pageParam ?? 0)\n const requestForPage: SearchIndexQuery = {\n ...rowDataQuery,\n searchQuery: {\n ...rowDataQuery.searchQuery,\n offset,\n },\n }\n return fetchAndConvert(requestForPage)\n },\n select: (\n data: InfiniteData<\n AsynchronousJobStatus<SearchIndexQuery, QueryResultBundle>\n >,\n ) => data,\n }\n\n const queryMetadataQueryOptions: SearchTableQueryUseQueryOptions['queryMetadataQueryOptions'] =\n {\n ...tableQueryUseQueryDefaults,\n queryKey: keyFactory.getSearchQueryResultWithAsyncStatusQueryKey(\n toKeyShape(metadataQuery) as unknown as SearchIndexQuery,\n false,\n ),\n queryFn: () => fetchAndConvert(metadataQuery),\n select: (\n data: AsynchronousJobStatus<SearchIndexQuery, QueryResultBundle>,\n ): Omit<QueryResultBundle, 'queryResult'> => {\n const result = omit(data.responseBody ?? {}, 'queryResult') as Omit<\n QueryResultBundle,\n 'queryResult'\n >\n return columnModels ? { ...result, columnModels } : result\n },\n }\n\n return {\n rowDataQueryOptions,\n rowDataInfiniteQueryOptions,\n queryMetadataQueryOptions,\n }\n}\n\n/**\n * Returns a stable callback that fetches autocomplete suggestions for a search input\n * using the synchronous `POST /search/autocomplete` endpoint.\n *\n * The query is built from the current `searchIndexId` and `autocompleteFieldName`:\n * - `searchQuery.queryText` is set to the user-entered search text\n * - `searchQuery.queryFields` is set to `[autocompleteFieldName]` so the server\n * only returns values for that single field\n *\n * When `autocompleteFieldName` is undefined, the returned callback immediately returns `[]`.\n */\nexport function useGetSuggestionsForSearchIndex(\n searchIndexId: string,\n autocompleteFieldName: string | undefined,\n): (searchText: string) => Promise<string[]> {\n const { synapseClient } = useSynapseContext()\n\n return useCallback(\n async (searchText: string): Promise<string[]> => {\n if (!autocompleteFieldName) return []\n const trimmed = searchText.trim()\n if (!trimmed) return []\n const results =\n await synapseClient.searchManagementServicesClient.postRepoV1SearchAutocomplete(\n {\n searchIndexQuery: {\n concreteType:\n 'org.sagebionetworks.repo.model.search.table.SearchIndexQuery' as const,\n searchIndexId,\n searchQuery: {\n queryText: trimmed,\n queryFields: [autocompleteFieldName],\n returnFields: [autocompleteFieldName],\n },\n },\n },\n )\n const suggestions: string[] = []\n for (const hit of results.hits ?? []) {\n for (const field of hit.fields ?? []) {\n if (field.value) {\n suggestions.push(field.value)\n }\n }\n }\n return suggestions\n },\n [synapseClient, searchIndexId, autocompleteFieldName],\n )\n}\n\n/**\n * Returns TanStack Query options that call the SearchQueryServicesApi (instead of the\n * standard Table Query API) but return data in the same QueryResultBundle format, allowing\n * all existing subcomponents (FacetFilterControls, RowSetView, etc.) to work unchanged.\n */\nexport function useSearchQueryUseQueryOptions(\n queryBundleRequest: QueryBundleRequest,\n searchIndexId: string,\n synapseId?: string,\n): SearchTableQueryUseQueryOptions {\n const { keyFactory, accessToken } = useSynapseContext()\n\n const { data: entityBundle } = useGetEntityBundle(synapseId, undefined, {\n includeTableBundle: true,\n })\n const columnModels = entityBundle?.tableBundle?.columnModels\n\n return useMemo(\n () =>\n getSearchQueryUseQueryOptions(\n queryBundleRequest,\n keyFactory,\n accessToken,\n searchIndexId,\n columnModels,\n ),\n [keyFactory, accessToken, queryBundleRequest, searchIndexId, columnModels],\n )\n}\n"],"mappings":"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"}
@@ -24,7 +24,7 @@ type SearchQueryWrapperPlotNavOwnProps = {
24
24
  initialLimit?: number;
25
25
  hideTopLevelControls?: boolean;
26
26
  };
27
- export type SearchQueryWrapperPlotNavProps = SearchQueryWrapperPlotNavOwnProps & PlotsContainerProps & Pick<QueryVisualizationWrapperProps, 'defaultShowPlots' | 'visibleColumnCount' | 'columnAliases' | 'rgbIndex' | 'showLastUpdatedOn' | 'noContentPlaceholderType' | 'unitDescription' | 'helpConfiguration' | 'hideCopyToClipboard' | 'hideVisualizationsControl' | 'lockTextMatchesQueryFilterPill' | 'hideSearchBarControl' | 'defaultShowSearchBar'> & Pick<TopLevelControlsProps, 'name' | 'hideQueryCount'> & {
27
+ export type SearchQueryWrapperPlotNavProps = SearchQueryWrapperPlotNavOwnProps & PlotsContainerProps & Pick<QueryVisualizationWrapperProps, 'defaultShowPlots' | 'visibleColumnCount' | 'hiddenColumns' | 'columnAliases' | 'rgbIndex' | 'showLastUpdatedOn' | 'noContentPlaceholderType' | 'unitDescription' | 'helpConfiguration' | 'hideCopyToClipboard' | 'hideVisualizationsControl' | 'lockTextMatchesQueryFilterPill' | 'hideSearchBarControl' | 'defaultShowSearchBar'> & Pick<TopLevelControlsProps, 'name' | 'hideQueryCount'> & {
28
28
  /** Optional initial query parameters. Only selectedFacets, additionalFilters, limit, and offset are used. */
29
29
  initQueryRequest?: SearchQueryWrapperProps['initQueryRequest'];
30
30
  /** Called when the query result bundle changes (e.g. to report result counts to a parent). */
@@ -1 +1 @@
1
- {"version":3,"file":"SearchQueryWrapperPlotNav.d.ts","sourceRoot":"","sources":["../../../src/components/SearchQueryWrapperPlotNav/SearchQueryWrapperPlotNav.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAA;AACtE,OAAO,EAEL,8BAA8B,EAC/B,MAAM,8BAA8B,CAAA;AAErC,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAA;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,mDAAmD,CAAA;AACzF,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAA;AACzE,OAAO,EAAE,wBAAwB,EAAE,MAAM,6CAA6C,CAAA;AACtF,OAAO,EAEL,uBAAuB,EACxB,MAAM,0CAA0C,CAAA;AAIjD,KAAK,iCAAiC,GAAG;IACvC,iDAAiD;IACjD,aAAa,EAAE,MAAM,CAAA;IACrB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,2HAA2H;IAC3H,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,kBAAkB,CAAC,EAAE,yBAAyB,CAAA;IAC9C,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IACrC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,eAAe,CAAC,EAAE,wBAAwB,CAAC,iBAAiB,CAAC,CAAA;IAC7D,4BAA4B,CAAC,EAAE,wBAAwB,CAAC,8BAA8B,CAAC,CAAA;IACvF,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAI/B,CAAA;AAED,MAAM,MAAM,8BAA8B,GAAG,iCAAiC,GAC5E,mBAAmB,GACnB,IAAI,CACF,8BAA8B,EAC5B,kBAAkB,GAClB,oBAAoB,GACpB,eAAe,GACf,UAAU,GACV,mBAAmB,GACnB,0BAA0B,GAC1B,iBAAiB,GACjB,mBAAmB,GACnB,qBAAqB,GACrB,2BAA2B,GAC3B,gCAAgC,GAChC,sBAAsB,GACtB,sBAAsB,CACzB,GACD,IAAI,CAAC,qBAAqB,EAAE,MAAM,GAAG,gBAAgB,CAAC,GAAG;IACvD,6GAA6G;IAC7G,gBAAgB,CAAC,EAAE,uBAAuB,CAAC,kBAAkB,CAAC,CAAA;IAC9D,8FAA8F;IAC9F,yBAAyB,CAAC,EAAE,uBAAuB,CAAC,2BAA2B,CAAC,CAAA;IAChF,+EAA+E;IAC/E,cAAc,CAAC,EAAE,uBAAuB,CAAC,gBAAgB,CAAC,CAAA;CAC3D,CAAA;AAEH;;;;;;;;;GASG;AACH,wBAAgB,gCAAgC,CAAC,MAAM,EAAE;IACvD,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,GAAG,CAAC,EAAE,OAAO,CAAA;CACd,GAAG,MAAM,IAAI,8BAA8B,CAE3C;AAED;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAC/C,KAAK,EAAE,8BAA8B,2CAoGtC"}
1
+ {"version":3,"file":"SearchQueryWrapperPlotNav.d.ts","sourceRoot":"","sources":["../../../src/components/SearchQueryWrapperPlotNav/SearchQueryWrapperPlotNav.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAA;AACtE,OAAO,EAEL,8BAA8B,EAC/B,MAAM,8BAA8B,CAAA;AAErC,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAA;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,mDAAmD,CAAA;AACzF,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAA;AACzE,OAAO,EAAE,wBAAwB,EAAE,MAAM,6CAA6C,CAAA;AACtF,OAAO,EAEL,uBAAuB,EACxB,MAAM,0CAA0C,CAAA;AAIjD,KAAK,iCAAiC,GAAG;IACvC,iDAAiD;IACjD,aAAa,EAAE,MAAM,CAAA;IACrB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,2HAA2H;IAC3H,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,kBAAkB,CAAC,EAAE,yBAAyB,CAAA;IAC9C,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IACrC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,eAAe,CAAC,EAAE,wBAAwB,CAAC,iBAAiB,CAAC,CAAA;IAC7D,4BAA4B,CAAC,EAAE,wBAAwB,CAAC,8BAA8B,CAAC,CAAA;IACvF,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAI/B,CAAA;AAED,MAAM,MAAM,8BAA8B,GAAG,iCAAiC,GAC5E,mBAAmB,GACnB,IAAI,CACF,8BAA8B,EAC5B,kBAAkB,GAClB,oBAAoB,GACpB,eAAe,GACf,eAAe,GACf,UAAU,GACV,mBAAmB,GACnB,0BAA0B,GAC1B,iBAAiB,GACjB,mBAAmB,GACnB,qBAAqB,GACrB,2BAA2B,GAC3B,gCAAgC,GAChC,sBAAsB,GACtB,sBAAsB,CACzB,GACD,IAAI,CAAC,qBAAqB,EAAE,MAAM,GAAG,gBAAgB,CAAC,GAAG;IACvD,6GAA6G;IAC7G,gBAAgB,CAAC,EAAE,uBAAuB,CAAC,kBAAkB,CAAC,CAAA;IAC9D,8FAA8F;IAC9F,yBAAyB,CAAC,EAAE,uBAAuB,CAAC,2BAA2B,CAAC,CAAA;IAChF,+EAA+E;IAC/E,cAAc,CAAC,EAAE,uBAAuB,CAAC,gBAAgB,CAAC,CAAA;CAC3D,CAAA;AAEH;;;;;;;;;GASG;AACH,wBAAgB,gCAAgC,CAAC,MAAM,EAAE;IACvD,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,GAAG,CAAC,EAAE,OAAO,CAAA;CACd,GAAG,MAAM,IAAI,8BAA8B,CAE3C;AAED;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAC/C,KAAK,EAAE,8BAA8B,2CAqGtC"}
@@ -37,6 +37,7 @@ function d(u) {
37
37
  columnAliases: u.columnAliases,
38
38
  helpConfiguration: m,
39
39
  visibleColumnCount: u.visibleColumnCount,
40
+ hiddenColumns: u.hiddenColumns,
40
41
  defaultShowPlots: u.defaultShowPlots,
41
42
  hideCopyToClipboard: u.hideCopyToClipboard,
42
43
  hideSearchBarControl: u.hideSearchBarControl ?? !1,
@@ -1 +1 @@
1
- {"version":3,"file":"SearchQueryWrapperPlotNav.js","names":[],"sources":["../../../src/components/SearchQueryWrapperPlotNav/SearchQueryWrapperPlotNav.tsx"],"sourcesContent":["import { NoContentPlaceholderType } from '@/components/SynapseTable/NoContentPlaceholderType'\nimport { DEFAULT_PAGE_SIZE } from '@/utils/SynapseConstants'\nimport { Suspense, useRef } from 'react'\nimport { useDeepCompareMemoize } from 'use-deep-compare-effect'\nimport { CardConfiguration } from '../CardContainer/CardConfiguration'\nimport {\n QueryVisualizationWrapper,\n QueryVisualizationWrapperProps,\n} from '../QueryVisualizationWrapper'\nimport QueryWrapperLoadingScreen from '../QueryWrapper/QueryWrapperLoadingScreen'\nimport { SynapseTableConfiguration } from '../SynapseTable'\nimport { TopLevelControlsProps } from '../SynapseTable/TopLevelControls/TopLevelControls'\nimport { PlotsContainerProps } from '../widgets/facet-nav/PlotsContainer'\nimport { FacetFilterControlsProps } from '../widgets/query-filter/FacetFilterControls'\nimport {\n SearchQueryWrapper,\n SearchQueryWrapperProps,\n} from '../SearchQueryWrapper/SearchQueryWrapper'\nimport { QueryWrapperPlotNavContents } from '../QueryWrapperPlotNav/QueryWrapperPlotNav'\nimport { useGetSuggestionsForSearchIndex } from '../SearchQueryWrapper/SearchQueryUseQueryOptions'\n\ntype SearchQueryWrapperPlotNavOwnProps = {\n /** The ID of the SearchIndex entity to query. */\n searchIndexId: string\n /**\n * The name of the field to use for autocomplete suggestions.\n * When provided, the search bar will show a dropdown of suggestions as the user types,\n * populated by querying the search index with this field restricted via POST /search/autocomplete.\n */\n autocompleteFieldName?: string\n /** Whether the displayed results should be paginated or infinite. Default for cards is true, default for table is false */\n isInfinite?: boolean\n tableConfiguration?: SynapseTableConfiguration\n cardConfiguration?: CardConfiguration\n facetsToPlot?: string[]\n availableFacets?: FacetFilterControlsProps['availableFacets']\n initialExpandedFacetControls?: FacetFilterControlsProps['initialExpandedFacetControls']\n initialLimit?: number\n hideTopLevelControls?: boolean\n // Note: hideDownload, hideSqlEditorControl are intentionally\n // excluded — they are hardcoded to true because these controls are not applicable to the\n // SearchQueryServicesApi (no file download, no SQL editing).\n}\n\nexport type SearchQueryWrapperPlotNavProps = SearchQueryWrapperPlotNavOwnProps &\n PlotsContainerProps &\n Pick<\n QueryVisualizationWrapperProps,\n | 'defaultShowPlots'\n | 'visibleColumnCount'\n | 'columnAliases'\n | 'rgbIndex'\n | 'showLastUpdatedOn'\n | 'noContentPlaceholderType'\n | 'unitDescription'\n | 'helpConfiguration'\n | 'hideCopyToClipboard'\n | 'hideVisualizationsControl'\n | 'lockTextMatchesQueryFilterPill'\n | 'hideSearchBarControl'\n | 'defaultShowSearchBar'\n > &\n Pick<TopLevelControlsProps, 'name' | 'hideQueryCount'> & {\n /** Optional initial query parameters. Only selectedFacets, additionalFilters, limit, and offset are used. */\n initQueryRequest?: SearchQueryWrapperProps['initQueryRequest']\n /** Called when the query result bundle changes (e.g. to report result counts to a parent). */\n onQueryResultBundleChange?: SearchQueryWrapperProps['onQueryResultBundleChange']\n /** Whether the URL should update when the query is modified (deep linking). */\n shouldDeepLink?: SearchQueryWrapperProps['shouldDeepLink']\n }\n\n/**\n * Type guard that identifies a SearchQueryWrapperPlotNavProps from the union\n * `QueryWrapperPlotNavProps | SearchQueryWrapperPlotNavProps`.\n *\n * Two conditions are checked to be robust against future API changes:\n * 1. The config has `searchIndexId` (present only on SearchQueryWrapperPlotNavProps).\n * 2. The config does NOT have `sql` (always present on QueryWrapperPlotNavProps via\n * QueryOrDeprecatedSearchParams), so that if QueryWrapperPlotNavProps ever gains a\n * `searchIndexId` field the guard remains correct.\n */\nexport function isSearchQueryWrapperPlotNavProps(config: {\n searchIndexId?: unknown\n sql?: unknown\n}): config is SearchQueryWrapperPlotNavProps {\n return 'searchIndexId' in config && !('sql' in config)\n}\n\n/**\n * A component similar to QueryWrapperPlotNav that sources its data from the SearchQueryServicesApi\n * rather than the standard Synapse Table Services. Facets, table/card rendering, and plots are\n * all reused from the existing component library.\n */\nexport default function SearchQueryWrapperPlotNav(\n props: SearchQueryWrapperPlotNavProps,\n) {\n const {\n tableConfiguration,\n isInfinite = !tableConfiguration,\n unitDescription,\n helpConfiguration,\n initQueryRequest: initQueryRequestFromProps,\n onQueryResultBundleChange,\n searchIndexId,\n autocompleteFieldName,\n shouldDeepLink,\n } = props\n\n const getSuggestions = useGetSuggestionsForSearchIndex(\n searchIndexId,\n autocompleteFieldName,\n )\n\n const initQueryRequest: SearchQueryWrapperProps['initQueryRequest'] =\n useDeepCompareMemoize({\n partMask: initQueryRequestFromProps?.partMask ?? 0,\n query: {\n selectedFacets: initQueryRequestFromProps?.query?.selectedFacets,\n additionalFilters: initQueryRequestFromProps?.query?.additionalFilters,\n limit: initQueryRequestFromProps?.query?.limit ?? DEFAULT_PAGE_SIZE,\n offset: initQueryRequestFromProps?.query?.offset ?? 0,\n },\n })\n\n // Remount SearchQueryWrapper when initQueryRequest content changes.\n // useDeepCompareMemoize returns the same reference when content is equal, so reference\n // comparison is sufficient here. A counter is used rather than JSON.stringify to avoid\n // serializing the object on every render.\n const mountKeyRef = useRef(0)\n const prevInitQueryRef = useRef(initQueryRequest)\n if (prevInitQueryRef.current !== initQueryRequest) {\n mountKeyRef.current += 1\n prevInitQueryRef.current = initQueryRequest\n }\n\n return (\n <SearchQueryWrapper\n key={mountKeyRef.current}\n searchIndexId={searchIndexId}\n initQueryRequest={initQueryRequest}\n isInfinite={isInfinite}\n onQueryResultBundleChange={onQueryResultBundleChange}\n shouldDeepLink={shouldDeepLink}\n >\n <Suspense fallback={<QueryWrapperLoadingScreen />}>\n <QueryVisualizationWrapper\n unitDescription={unitDescription}\n rgbIndex={props.rgbIndex}\n columnAliases={props.columnAliases}\n helpConfiguration={helpConfiguration}\n visibleColumnCount={props.visibleColumnCount}\n defaultShowPlots={props.defaultShowPlots}\n hideCopyToClipboard={props.hideCopyToClipboard}\n hideSearchBarControl={props.hideSearchBarControl ?? false}\n lockTextMatchesQueryFilterPill={props.lockTextMatchesQueryFilterPill}\n defaultShowSearchBar={props.defaultShowSearchBar ?? true}\n showLastUpdatedOn={props.showLastUpdatedOn}\n noContentPlaceholderType={\n props.noContentPlaceholderType ??\n NoContentPlaceholderType.INTERACTIVE\n }\n >\n <QueryWrapperPlotNavContents\n tableConfiguration={tableConfiguration}\n name={props.name}\n cardConfiguration={props.cardConfiguration}\n facetsToPlot={props.facetsToPlot}\n availableFacets={props.availableFacets}\n initialExpandedFacetControls={props.initialExpandedFacetControls}\n hideDownload={true}\n hideQueryCount={props.hideQueryCount ?? false}\n hideSqlEditorControl={true}\n hideVisualizationsControl={props.hideVisualizationsControl}\n initialLimit={props.initialLimit}\n initialPlotTypeByFacetColumnName={\n props.initialPlotTypeByFacetColumnName\n }\n hideTopLevelControls={props.hideTopLevelControls}\n isFullTextSearchEnabled={true}\n searchConfiguration={{\n ftsConfig: {\n textMatchesMode: 'NATURAL_LANGUAGE',\n minSearchQueryLength: 1,\n replaceExistingFilter: true,\n getSuggestions: autocompleteFieldName\n ? getSuggestions\n : undefined,\n },\n }}\n />\n </QueryVisualizationWrapper>\n </Suspense>\n </SearchQueryWrapper>\n )\n}\n"],"mappings":";;;;;;;;;;;;AAiFA,SAAgB,EAAiC,GAGJ;AAC3C,QAAO,mBAAmB,KAAU,EAAE,SAAS;;AAQjD,SAAwB,EACtB,GACA;CACA,IAAM,EACJ,uBACA,gBAAa,CAAC,GACd,oBACA,sBACA,kBAAkB,GAClB,8BACA,kBACA,0BACA,sBACE,GAEE,IAAiB,EACrB,GACA,EACD,EAEK,IACJ,EAAsB;EACpB,UAAU,GAA2B,YAAY;EACjD,OAAO;GACL,gBAAgB,GAA2B,OAAO;GAClD,mBAAmB,GAA2B,OAAO;GACrD,OAAO,GAA2B,OAAO,SAAA;GACzC,QAAQ,GAA2B,OAAO,UAAU;GACrD;EACF,CAAC,EAME,IAAc,EAAO,EAAE,EACvB,IAAmB,EAAO,EAAiB;AAMjD,QALI,EAAiB,YAAY,MAC/B,EAAY,WAAW,GACvB,EAAiB,UAAU,IAI3B,kBAAC,GAAD;EAEiB;EACG;EACN;EACe;EACX;YAEhB,kBAAC,GAAD;GAAU,UAAU,kBAAC,GAAD,EAA6B,CAAA;aAC/C,kBAAC,GAAD;IACmB;IACjB,UAAU,EAAM;IAChB,eAAe,EAAM;IACF;IACnB,oBAAoB,EAAM;IAC1B,kBAAkB,EAAM;IACxB,qBAAqB,EAAM;IAC3B,sBAAsB,EAAM,wBAAwB;IACpD,gCAAgC,EAAM;IACtC,sBAAsB,EAAM,wBAAwB;IACpD,mBAAmB,EAAM;IACzB,0BACE,EAAM,4BACN,EAAyB;cAG3B,kBAAC,GAAD;KACsB;KACpB,MAAM,EAAM;KACZ,mBAAmB,EAAM;KACzB,cAAc,EAAM;KACpB,iBAAiB,EAAM;KACvB,8BAA8B,EAAM;KACpC,cAAc;KACd,gBAAgB,EAAM,kBAAkB;KACxC,sBAAsB;KACtB,2BAA2B,EAAM;KACjC,cAAc,EAAM;KACpB,kCACE,EAAM;KAER,sBAAsB,EAAM;KAC5B,yBAAyB;KACzB,qBAAqB,EACnB,WAAW;MACT,iBAAiB;MACjB,sBAAsB;MACtB,uBAAuB;MACvB,gBAAgB,IACZ,IACA,KAAA;MACL,EACF;KACD,CAAA;IACwB,CAAA;GACnB,CAAA;EACQ,EAvDd,EAAY,QAuDE"}
1
+ {"version":3,"file":"SearchQueryWrapperPlotNav.js","names":[],"sources":["../../../src/components/SearchQueryWrapperPlotNav/SearchQueryWrapperPlotNav.tsx"],"sourcesContent":["import { NoContentPlaceholderType } from '@/components/SynapseTable/NoContentPlaceholderType'\nimport { DEFAULT_PAGE_SIZE } from '@/utils/SynapseConstants'\nimport { Suspense, useRef } from 'react'\nimport { useDeepCompareMemoize } from 'use-deep-compare-effect'\nimport { CardConfiguration } from '../CardContainer/CardConfiguration'\nimport {\n QueryVisualizationWrapper,\n QueryVisualizationWrapperProps,\n} from '../QueryVisualizationWrapper'\nimport QueryWrapperLoadingScreen from '../QueryWrapper/QueryWrapperLoadingScreen'\nimport { SynapseTableConfiguration } from '../SynapseTable'\nimport { TopLevelControlsProps } from '../SynapseTable/TopLevelControls/TopLevelControls'\nimport { PlotsContainerProps } from '../widgets/facet-nav/PlotsContainer'\nimport { FacetFilterControlsProps } from '../widgets/query-filter/FacetFilterControls'\nimport {\n SearchQueryWrapper,\n SearchQueryWrapperProps,\n} from '../SearchQueryWrapper/SearchQueryWrapper'\nimport { QueryWrapperPlotNavContents } from '../QueryWrapperPlotNav/QueryWrapperPlotNav'\nimport { useGetSuggestionsForSearchIndex } from '../SearchQueryWrapper/SearchQueryUseQueryOptions'\n\ntype SearchQueryWrapperPlotNavOwnProps = {\n /** The ID of the SearchIndex entity to query. */\n searchIndexId: string\n /**\n * The name of the field to use for autocomplete suggestions.\n * When provided, the search bar will show a dropdown of suggestions as the user types,\n * populated by querying the search index with this field restricted via POST /search/autocomplete.\n */\n autocompleteFieldName?: string\n /** Whether the displayed results should be paginated or infinite. Default for cards is true, default for table is false */\n isInfinite?: boolean\n tableConfiguration?: SynapseTableConfiguration\n cardConfiguration?: CardConfiguration\n facetsToPlot?: string[]\n availableFacets?: FacetFilterControlsProps['availableFacets']\n initialExpandedFacetControls?: FacetFilterControlsProps['initialExpandedFacetControls']\n initialLimit?: number\n hideTopLevelControls?: boolean\n // Note: hideDownload, hideSqlEditorControl are intentionally\n // excluded — they are hardcoded to true because these controls are not applicable to the\n // SearchQueryServicesApi (no file download, no SQL editing).\n}\n\nexport type SearchQueryWrapperPlotNavProps = SearchQueryWrapperPlotNavOwnProps &\n PlotsContainerProps &\n Pick<\n QueryVisualizationWrapperProps,\n | 'defaultShowPlots'\n | 'visibleColumnCount'\n | 'hiddenColumns'\n | 'columnAliases'\n | 'rgbIndex'\n | 'showLastUpdatedOn'\n | 'noContentPlaceholderType'\n | 'unitDescription'\n | 'helpConfiguration'\n | 'hideCopyToClipboard'\n | 'hideVisualizationsControl'\n | 'lockTextMatchesQueryFilterPill'\n | 'hideSearchBarControl'\n | 'defaultShowSearchBar'\n > &\n Pick<TopLevelControlsProps, 'name' | 'hideQueryCount'> & {\n /** Optional initial query parameters. Only selectedFacets, additionalFilters, limit, and offset are used. */\n initQueryRequest?: SearchQueryWrapperProps['initQueryRequest']\n /** Called when the query result bundle changes (e.g. to report result counts to a parent). */\n onQueryResultBundleChange?: SearchQueryWrapperProps['onQueryResultBundleChange']\n /** Whether the URL should update when the query is modified (deep linking). */\n shouldDeepLink?: SearchQueryWrapperProps['shouldDeepLink']\n }\n\n/**\n * Type guard that identifies a SearchQueryWrapperPlotNavProps from the union\n * `QueryWrapperPlotNavProps | SearchQueryWrapperPlotNavProps`.\n *\n * Two conditions are checked to be robust against future API changes:\n * 1. The config has `searchIndexId` (present only on SearchQueryWrapperPlotNavProps).\n * 2. The config does NOT have `sql` (always present on QueryWrapperPlotNavProps via\n * QueryOrDeprecatedSearchParams), so that if QueryWrapperPlotNavProps ever gains a\n * `searchIndexId` field the guard remains correct.\n */\nexport function isSearchQueryWrapperPlotNavProps(config: {\n searchIndexId?: unknown\n sql?: unknown\n}): config is SearchQueryWrapperPlotNavProps {\n return 'searchIndexId' in config && !('sql' in config)\n}\n\n/**\n * A component similar to QueryWrapperPlotNav that sources its data from the SearchQueryServicesApi\n * rather than the standard Synapse Table Services. Facets, table/card rendering, and plots are\n * all reused from the existing component library.\n */\nexport default function SearchQueryWrapperPlotNav(\n props: SearchQueryWrapperPlotNavProps,\n) {\n const {\n tableConfiguration,\n isInfinite = !tableConfiguration,\n unitDescription,\n helpConfiguration,\n initQueryRequest: initQueryRequestFromProps,\n onQueryResultBundleChange,\n searchIndexId,\n autocompleteFieldName,\n shouldDeepLink,\n } = props\n\n const getSuggestions = useGetSuggestionsForSearchIndex(\n searchIndexId,\n autocompleteFieldName,\n )\n\n const initQueryRequest: SearchQueryWrapperProps['initQueryRequest'] =\n useDeepCompareMemoize({\n partMask: initQueryRequestFromProps?.partMask ?? 0,\n query: {\n selectedFacets: initQueryRequestFromProps?.query?.selectedFacets,\n additionalFilters: initQueryRequestFromProps?.query?.additionalFilters,\n limit: initQueryRequestFromProps?.query?.limit ?? DEFAULT_PAGE_SIZE,\n offset: initQueryRequestFromProps?.query?.offset ?? 0,\n },\n })\n\n // Remount SearchQueryWrapper when initQueryRequest content changes.\n // useDeepCompareMemoize returns the same reference when content is equal, so reference\n // comparison is sufficient here. A counter is used rather than JSON.stringify to avoid\n // serializing the object on every render.\n const mountKeyRef = useRef(0)\n const prevInitQueryRef = useRef(initQueryRequest)\n if (prevInitQueryRef.current !== initQueryRequest) {\n mountKeyRef.current += 1\n prevInitQueryRef.current = initQueryRequest\n }\n\n return (\n <SearchQueryWrapper\n key={mountKeyRef.current}\n searchIndexId={searchIndexId}\n initQueryRequest={initQueryRequest}\n isInfinite={isInfinite}\n onQueryResultBundleChange={onQueryResultBundleChange}\n shouldDeepLink={shouldDeepLink}\n >\n <Suspense fallback={<QueryWrapperLoadingScreen />}>\n <QueryVisualizationWrapper\n unitDescription={unitDescription}\n rgbIndex={props.rgbIndex}\n columnAliases={props.columnAliases}\n helpConfiguration={helpConfiguration}\n visibleColumnCount={props.visibleColumnCount}\n hiddenColumns={props.hiddenColumns}\n defaultShowPlots={props.defaultShowPlots}\n hideCopyToClipboard={props.hideCopyToClipboard}\n hideSearchBarControl={props.hideSearchBarControl ?? false}\n lockTextMatchesQueryFilterPill={props.lockTextMatchesQueryFilterPill}\n defaultShowSearchBar={props.defaultShowSearchBar ?? true}\n showLastUpdatedOn={props.showLastUpdatedOn}\n noContentPlaceholderType={\n props.noContentPlaceholderType ??\n NoContentPlaceholderType.INTERACTIVE\n }\n >\n <QueryWrapperPlotNavContents\n tableConfiguration={tableConfiguration}\n name={props.name}\n cardConfiguration={props.cardConfiguration}\n facetsToPlot={props.facetsToPlot}\n availableFacets={props.availableFacets}\n initialExpandedFacetControls={props.initialExpandedFacetControls}\n hideDownload={true}\n hideQueryCount={props.hideQueryCount ?? false}\n hideSqlEditorControl={true}\n hideVisualizationsControl={props.hideVisualizationsControl}\n initialLimit={props.initialLimit}\n initialPlotTypeByFacetColumnName={\n props.initialPlotTypeByFacetColumnName\n }\n hideTopLevelControls={props.hideTopLevelControls}\n isFullTextSearchEnabled={true}\n searchConfiguration={{\n ftsConfig: {\n textMatchesMode: 'NATURAL_LANGUAGE',\n minSearchQueryLength: 1,\n replaceExistingFilter: true,\n getSuggestions: autocompleteFieldName\n ? getSuggestions\n : undefined,\n },\n }}\n />\n </QueryVisualizationWrapper>\n </Suspense>\n </SearchQueryWrapper>\n )\n}\n"],"mappings":";;;;;;;;;;;;AAkFA,SAAgB,EAAiC,GAGJ;AAC3C,QAAO,mBAAmB,KAAU,EAAE,SAAS;;AAQjD,SAAwB,EACtB,GACA;CACA,IAAM,EACJ,uBACA,gBAAa,CAAC,GACd,oBACA,sBACA,kBAAkB,GAClB,8BACA,kBACA,0BACA,sBACE,GAEE,IAAiB,EACrB,GACA,EACD,EAEK,IACJ,EAAsB;EACpB,UAAU,GAA2B,YAAY;EACjD,OAAO;GACL,gBAAgB,GAA2B,OAAO;GAClD,mBAAmB,GAA2B,OAAO;GACrD,OAAO,GAA2B,OAAO,SAAA;GACzC,QAAQ,GAA2B,OAAO,UAAU;GACrD;EACF,CAAC,EAME,IAAc,EAAO,EAAE,EACvB,IAAmB,EAAO,EAAiB;AAMjD,QALI,EAAiB,YAAY,MAC/B,EAAY,WAAW,GACvB,EAAiB,UAAU,IAI3B,kBAAC,GAAD;EAEiB;EACG;EACN;EACe;EACX;YAEhB,kBAAC,GAAD;GAAU,UAAU,kBAAC,GAAD,EAA6B,CAAA;aAC/C,kBAAC,GAAD;IACmB;IACjB,UAAU,EAAM;IAChB,eAAe,EAAM;IACF;IACnB,oBAAoB,EAAM;IAC1B,eAAe,EAAM;IACrB,kBAAkB,EAAM;IACxB,qBAAqB,EAAM;IAC3B,sBAAsB,EAAM,wBAAwB;IACpD,gCAAgC,EAAM;IACtC,sBAAsB,EAAM,wBAAwB;IACpD,mBAAmB,EAAM;IACzB,0BACE,EAAM,4BACN,EAAyB;cAG3B,kBAAC,GAAD;KACsB;KACpB,MAAM,EAAM;KACZ,mBAAmB,EAAM;KACzB,cAAc,EAAM;KACpB,iBAAiB,EAAM;KACvB,8BAA8B,EAAM;KACpC,cAAc;KACd,gBAAgB,EAAM,kBAAkB;KACxC,sBAAsB;KACtB,2BAA2B,EAAM;KACjC,cAAc,EAAM;KACpB,kCACE,EAAM;KAER,sBAAsB,EAAM;KAC5B,yBAAyB;KACzB,qBAAqB,EACnB,WAAW;MACT,iBAAiB;MACjB,sBAAsB;MACtB,uBAAuB;MACvB,gBAAgB,IACZ,IACA,KAAA;MACL,EACF;KACD,CAAA;IACwB,CAAA;GACnB,CAAA;EACQ,EAxDd,EAAY,QAwDE"}
@@ -1 +1 @@
1
- {"version":3,"file":"SetAccessRequirementCommonFields.d.ts","sourceRoot":"","sources":["../../../src/components/SetAccessRequirementCommonFields/SetAccessRequirementCommonFields.tsx"],"names":[],"mappings":"AAqBA,OAAO,EACL,gCAAgC,EAIhC,4BAA4B,EAC5B,sBAAsB,EAEvB,MAAM,iCAAiC,CAAA;AAcxC,eAAO,MAAM,gCAAgC,2FAC6C,CAAA;AAC1F,eAAO,MAAM,8BAA8B,GACzC,cAAc,sBAAsB,WASrC,CAAA;AAsBD,MAAM,MAAM,sCAAsC,GAAG;IAEnD,IAAI,EAAE,MAAM,IAAI,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,qCAAqC,GAAG;IAElD,OAAO,CAAC,EAAE,4BAA4B,CAAA;IAEtC,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAE5B,MAAM,EAAE,CACN,mBAAmB,EAAE,MAAM,EAC3B,4BAA4B,EAAE,gCAAgC,KAC3D,IAAI,CAAA;IAET,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,CAAA;AAED,eAAO,MAAM,gCAAgC,0JAqS5C,CAAA"}
1
+ {"version":3,"file":"SetAccessRequirementCommonFields.d.ts","sourceRoot":"","sources":["../../../src/components/SetAccessRequirementCommonFields/SetAccessRequirementCommonFields.tsx"],"names":[],"mappings":"AAqBA,OAAO,EACL,gCAAgC,EAIhC,4BAA4B,EAC5B,sBAAsB,EAEvB,MAAM,iCAAiC,CAAA;AAcxC,eAAO,MAAM,gCAAgC,2FAC6C,CAAA;AAC1F,eAAO,MAAM,8BAA8B,GACzC,cAAc,sBAAsB,WASrC,CAAA;AAsBD,MAAM,MAAM,sCAAsC,GAAG;IAEnD,IAAI,EAAE,MAAM,IAAI,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,qCAAqC,GAAG;IAElD,OAAO,CAAC,EAAE,4BAA4B,CAAA;IAEtC,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAE5B,MAAM,EAAE,CACN,mBAAmB,EAAE,MAAM,EAC3B,4BAA4B,EAAE,gCAAgC,KAC3D,IAAI,CAAA;IAET,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,CAAA;AAED,eAAO,MAAM,gCAAgC,0JAiS5C,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"SetAccessRequirementCommonFields.js","names":[],"sources":["../../../src/components/SetAccessRequirementCommonFields/SetAccessRequirementCommonFields.tsx"],"sourcesContent":["import {\n useCreateAccessRequirement,\n useGetAccessRequirements,\n useUpdateAccessRequirement,\n} from '@/synapse-queries'\nimport { spreadSx } from '@/theme/spreadSx'\nimport { HelpOutlineTwoTone } from '@mui/icons-material'\nimport {\n Alert,\n Checkbox,\n FormControlLabel,\n Radio,\n RadioGroup,\n Skeleton,\n Stack,\n TextField,\n Tooltip,\n Typography,\n TypographyProps,\n} from '@mui/material'\nimport { SynapseClientError } from '@sage-bionetworks/synapse-client/util/SynapseClientError'\nimport {\n ACCESS_REQUIREMENT_CONCRETE_TYPE,\n ACCESS_TYPE,\n AccessRequirement,\n MANAGED_ACT_ACCESS_REQUIREMENT_CONCRETE_TYPE_VALUE,\n RestrictableObjectDescriptor,\n RestrictableObjectType,\n SELF_SIGN_ACCESS_REQUIREMENT_CONCRETE_TYPE_VALUE,\n} from '@sage-bionetworks/synapse-types'\nimport pluralize from 'pluralize'\nimport {\n ForwardedRef,\n forwardRef,\n useEffect,\n useImperativeHandle,\n useMemo,\n useState,\n} from 'react'\nimport EntitySubjectsSelector from '../EntitySubjectsSelector'\nimport { SynapseErrorBoundary } from '../error'\nimport TeamSubjectsSelector from '../TeamSubjectsSelector'\n\nexport const EMPTY_SUBJECT_LIST_ERROR_MESSAGE =\n 'Please select at least one resource for this Access Requirement to be associated with.'\nexport const UNSAVED_SUBJECTS_ERROR_MESSAGE = (\n subjectsType: RestrictableObjectType,\n) => {\n const idsText =\n subjectsType === RestrictableObjectType.ENTITY ? 'Synapse' : 'Team'\n const typeText =\n subjectsType[0].toUpperCase() + subjectsType.slice(1).toLowerCase()\n return `${idsText} IDs were specified but not added to the subjects list. Please either clear out the Add ${idsText} IDs textbox or click the Add ${pluralize(\n typeText,\n )} button.`\n}\nconst NAME_HELP_TEXT =\n \"Enter access requirement name. This will also be used when sending notifications for expiring or revoked approval. For example, 'The approval for the name access requirement was revoked...'\"\n\nconst headerProps: Partial<TypographyProps> = {\n variant: 'body1',\n fontWeight: 700,\n}\n\nfunction getAccessType(subjectType: RestrictableObjectType) {\n switch (subjectType) {\n case RestrictableObjectType.ENTITY:\n return ACCESS_TYPE.DOWNLOAD\n case RestrictableObjectType.TEAM:\n return ACCESS_TYPE.PARTICIPATE\n default:\n throw new Error(\n `RestrictableObjectType ${subjectType} does not have an access type specified.`,\n )\n }\n}\n\nexport type SetAccessRequirementCommonFieldsHandle = {\n /* Allow the parent component to trigger saving the AR, so this may be embedded in an arbitrary modal. */\n save: () => void\n}\n\nexport type SetAccessRequirementCommonFieldsProps = {\n /* Provided when creating a new AR */\n subject?: RestrictableObjectDescriptor\n /* Provided when editing an existing AR */\n accessRequirementId?: string\n /* Called when AR has been saved successfully */\n onSave: (\n accessRequirementId: string,\n accessRequirementConreteType: ACCESS_REQUIREMENT_CONCRETE_TYPE,\n ) => void\n /* Called when error saving AR */\n onError: () => void\n}\n\nexport const SetAccessRequirementCommonFields = forwardRef(\n function SetAccessRequirementCommonFields(\n props: SetAccessRequirementCommonFieldsProps,\n ref: ForwardedRef<SetAccessRequirementCommonFieldsHandle>,\n ) {\n const { subject, accessRequirementId, onSave, onError } = props\n\n const isEditing = !subject\n\n const [subjects, setSubjects] = useState<RestrictableObjectDescriptor[]>(\n subject ? [subject] : [],\n )\n const [hasPendingSubjects, setHasPendingSubjects] = useState<boolean>(false)\n const [subjectsError, setSubjectsError] = useState<string | null>(null)\n const [name, setName] = useState<string>('')\n const [subjectsDefinedByAnnotations, setSubjectsDefinedByAnnotations] =\n useState<boolean>(false)\n const [arType, setArType] = useState<ACCESS_REQUIREMENT_CONCRETE_TYPE>(\n subject?.type === RestrictableObjectType.TEAM\n ? SELF_SIGN_ACCESS_REQUIREMENT_CONCRETE_TYPE_VALUE\n : MANAGED_ACT_ACCESS_REQUIREMENT_CONCRETE_TYPE_VALUE,\n )\n const [clientError, setClientError] = useState<string | null>(null)\n\n const onMutationSuccess = (ar: AccessRequirement) => {\n setClientError(null)\n onSave(ar.id.toString(), ar.concreteType)\n }\n\n const onMutationError = (error: SynapseClientError) => {\n setClientError(error.reason)\n onError()\n }\n\n const { mutate: createAccessRequirement } = useCreateAccessRequirement({\n onSuccess: newAr => onMutationSuccess(newAr),\n onError: error => onMutationError(error),\n })\n\n const { mutate: updateAccessRequirement } = useUpdateAccessRequirement({\n onSuccess: updatedAr => onMutationSuccess(updatedAr),\n onError: error => onMutationError(error),\n })\n\n const {\n data: accessRequirement,\n isLoading: isLoadingAr,\n error: getArError,\n } = useGetAccessRequirements(accessRequirementId!, {\n enabled: Boolean(accessRequirementId),\n })\n\n useEffect(() => {\n if (accessRequirement) {\n setArType(accessRequirement.concreteType)\n setName(accessRequirement.name)\n setSubjects(accessRequirement.subjectIds)\n setSubjectsDefinedByAnnotations(\n accessRequirement.subjectsDefinedByAnnotations,\n )\n }\n }, [accessRequirement])\n\n const subjectsType = useMemo(() => {\n if (subject) {\n return subject.type\n }\n if (accessRequirement) {\n const initialSubjects = accessRequirement.subjectIds\n if (initialSubjects.length > 0) {\n return initialSubjects[0].type\n }\n }\n if (subjectsDefinedByAnnotations) {\n return RestrictableObjectType.ENTITY\n }\n return null\n }, [subject, accessRequirement, subjectsDefinedByAnnotations])\n\n const selectorContent = useMemo(() => {\n if (!subjectsType) return <></>\n\n function onUpdate(subjects: RestrictableObjectDescriptor[]) {\n setSubjectsError(null)\n setSubjects(subjects)\n }\n\n function onUpdateIdsTextbox(value: string) {\n setSubjectsError(null)\n setHasPendingSubjects(value.trim() !== '')\n }\n\n if (subjectsDefinedByAnnotations) {\n return <></>\n }\n switch (subjectsType) {\n case RestrictableObjectType.TEAM:\n return (\n <TeamSubjectsSelector\n subjects={subjects}\n onUpdate={subjects => onUpdate(subjects)}\n onUpdateTeamIDsTextbox={value => onUpdateIdsTextbox(value)}\n />\n )\n case RestrictableObjectType.ENTITY:\n return (\n <EntitySubjectsSelector\n subjects={subjects}\n onUpdate={subjects => onUpdate(subjects)}\n onUpdateEntityIDsTextbox={value => onUpdateIdsTextbox(value)}\n />\n )\n default:\n console.error(\n `RestrictableObjectType ${subjectsType} does not have a selector implemented.`,\n )\n return <></>\n }\n }, [subjectsType, subjects, subjectsDefinedByAnnotations])\n\n useImperativeHandle(\n ref,\n () => {\n return {\n save() {\n const isStillLoading =\n (isEditing && !accessRequirement) || !subjectsType\n const hasSubjectsError =\n !subjectsDefinedByAnnotations &&\n (hasPendingSubjects || subjects.length === 0)\n if (isStillLoading || hasSubjectsError) {\n if (hasSubjectsError && !isStillLoading) {\n if (hasPendingSubjects) {\n setSubjectsError(UNSAVED_SUBJECTS_ERROR_MESSAGE(subjectsType))\n } else if (subjects.length === 0) {\n setSubjectsError(EMPTY_SUBJECT_LIST_ERROR_MESSAGE)\n }\n }\n\n onError()\n return\n }\n\n const newAccessType = getAccessType(subjectsType)\n if (!isEditing) {\n const newAr: Partial<AccessRequirement> = {\n concreteType: arType,\n subjectIds: subjects,\n name: name,\n accessType: newAccessType,\n subjectsDefinedByAnnotations: subjectsDefinedByAnnotations,\n }\n createAccessRequirement(newAr)\n }\n\n if (isEditing && accessRequirement) {\n updateAccessRequirement({\n ...accessRequirement,\n subjectIds: subjects,\n name: name,\n accessType: newAccessType,\n subjectsDefinedByAnnotations: subjectsDefinedByAnnotations,\n })\n }\n },\n }\n },\n [\n hasPendingSubjects,\n subjectsType,\n subjects,\n name,\n arType,\n accessRequirement,\n isEditing,\n onError,\n createAccessRequirement,\n updateAccessRequirement,\n subjectsDefinedByAnnotations,\n ],\n )\n\n if (isLoadingAr || !subjectsType) {\n return (\n <>\n <Skeleton width={100} height={30} />\n <Skeleton width={125} height={30} />\n <Skeleton width=\"100%\">\n <TextField />\n </Skeleton>\n <Skeleton width={100} height={30} />\n <Skeleton width=\"100%\">\n <TextField />\n </Skeleton>\n </>\n )\n }\n\n if (getArError) {\n return <Alert severity=\"error\">{getArError.reason}</Alert>\n }\n\n return (\n <>\n <Typography {...headerProps}>Resources</Typography>\n {subjectsType !== RestrictableObjectType.TEAM && (\n <FormControlLabel\n control={<Checkbox />}\n label=\"Associated entities should be defined by annotations (DUO)\"\n checked={subjectsDefinedByAnnotations}\n onChange={() => {\n setSubjectsError(null)\n // if we are switching from DUO to manually defining the subjects (and the AR has been retrieved), then\n // reset to the AR subject IDs or the original subject ID. Otherwise, clear out the subjects.\n let newSubjectIds: RestrictableObjectDescriptor[] = []\n if (subjectsDefinedByAnnotations) {\n if (accessRequirement) {\n newSubjectIds = accessRequirement.subjectIds\n } else if (subject) {\n newSubjectIds = [subject]\n }\n }\n setSubjects(newSubjectIds)\n setSubjectsDefinedByAnnotations(!subjectsDefinedByAnnotations)\n }}\n />\n )}\n <SynapseErrorBoundary>{selectorContent}</SynapseErrorBoundary>\n {subjectsError && <Alert severity=\"error\">{subjectsError}</Alert>}\n <Stack\n direction=\"row\"\n sx={{\n gap: 1,\n alignItems: 'center',\n mb: 1,\n mt: 2,\n }}\n >\n <Typography component=\"label\" htmlFor=\"arName\" {...headerProps}>\n Name\n </Typography>\n <Tooltip title={NAME_HELP_TEXT} placement=\"right\">\n <HelpOutlineTwoTone sx={{ color: 'grey.600' }} />\n </Tooltip>\n </Stack>\n <TextField\n id=\"arName\"\n name=\"arName\"\n value={name}\n placeholder=\"Access requirement name\"\n fullWidth\n onChange={event => setName(event.target.value)}\n />\n {!isEditing && subjectsType !== RestrictableObjectType.TEAM && (\n <>\n <Typography\n {...headerProps}\n sx={spreadSx(\n {\n mt: 2,\n },\n headerProps.sx,\n )}\n >\n Access requirement type\n </Typography>\n <RadioGroup\n value={arType}\n onChange={(_event, value) =>\n setArType(value as ACCESS_REQUIREMENT_CONCRETE_TYPE)\n }\n >\n <FormControlLabel\n value={MANAGED_ACT_ACCESS_REQUIREMENT_CONCRETE_TYPE_VALUE}\n control={<Radio />}\n label=\"Controlled - requests are in Synapse\"\n />\n <FormControlLabel\n value={SELF_SIGN_ACCESS_REQUIREMENT_CONCRETE_TYPE_VALUE}\n control={<Radio />}\n label=\"Click wrap\"\n />\n </RadioGroup>\n </>\n )}\n {clientError && (\n <Alert severity=\"error\" sx={{ marginTop: 2 }}>\n {clientError}\n </Alert>\n )}\n </>\n )\n },\n)\n"],"mappings":"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"}
1
+ {"version":3,"file":"SetAccessRequirementCommonFields.js","names":[],"sources":["../../../src/components/SetAccessRequirementCommonFields/SetAccessRequirementCommonFields.tsx"],"sourcesContent":["import {\n useCreateAccessRequirement,\n useGetAccessRequirements,\n useUpdateAccessRequirement,\n} from '@/synapse-queries'\nimport { spreadSx } from '@/theme/spreadSx'\nimport { HelpOutlineTwoTone } from '@mui/icons-material'\nimport {\n Alert,\n Checkbox,\n FormControlLabel,\n Radio,\n RadioGroup,\n Skeleton,\n Stack,\n TextField,\n Tooltip,\n Typography,\n TypographyProps,\n} from '@mui/material'\nimport { SynapseClientError } from '@sage-bionetworks/synapse-client/util/SynapseClientError'\nimport {\n ACCESS_REQUIREMENT_CONCRETE_TYPE,\n ACCESS_TYPE,\n AccessRequirement,\n MANAGED_ACT_ACCESS_REQUIREMENT_CONCRETE_TYPE_VALUE,\n RestrictableObjectDescriptor,\n RestrictableObjectType,\n SELF_SIGN_ACCESS_REQUIREMENT_CONCRETE_TYPE_VALUE,\n} from '@sage-bionetworks/synapse-types'\nimport pluralize from 'pluralize'\nimport {\n ForwardedRef,\n forwardRef,\n useEffect,\n useImperativeHandle,\n useMemo,\n useState,\n} from 'react'\nimport EntitySubjectsSelector from '../EntitySubjectsSelector'\nimport { SynapseErrorBoundary } from '../error'\nimport TeamSubjectsSelector from '../TeamSubjectsSelector'\n\nexport const EMPTY_SUBJECT_LIST_ERROR_MESSAGE =\n 'Please select at least one resource for this Access Requirement to be associated with.'\nexport const UNSAVED_SUBJECTS_ERROR_MESSAGE = (\n subjectsType: RestrictableObjectType,\n) => {\n const idsText =\n subjectsType === RestrictableObjectType.ENTITY ? 'Synapse' : 'Team'\n const typeText =\n subjectsType[0].toUpperCase() + subjectsType.slice(1).toLowerCase()\n return `${idsText} IDs were specified but not added to the subjects list. Please either clear out the Add ${idsText} IDs textbox or click the Add ${pluralize(\n typeText,\n )} button.`\n}\nconst NAME_HELP_TEXT =\n \"Enter access requirement name. This will also be used when sending notifications for expiring or revoked approval. For example, 'The approval for the name access requirement was revoked...'\"\n\nconst headerProps: Partial<TypographyProps> = {\n variant: 'body1',\n fontWeight: 700,\n}\n\nfunction getAccessType(subjectType: RestrictableObjectType) {\n switch (subjectType) {\n case RestrictableObjectType.ENTITY:\n return ACCESS_TYPE.DOWNLOAD\n case RestrictableObjectType.TEAM:\n return ACCESS_TYPE.PARTICIPATE\n default:\n throw new Error(\n `RestrictableObjectType ${subjectType} does not have an access type specified.`,\n )\n }\n}\n\nexport type SetAccessRequirementCommonFieldsHandle = {\n /* Allow the parent component to trigger saving the AR, so this may be embedded in an arbitrary modal. */\n save: () => void\n}\n\nexport type SetAccessRequirementCommonFieldsProps = {\n /* Provided when creating a new AR */\n subject?: RestrictableObjectDescriptor\n /* Provided when editing an existing AR */\n accessRequirementId?: string\n /* Called when AR has been saved successfully */\n onSave: (\n accessRequirementId: string,\n accessRequirementConreteType: ACCESS_REQUIREMENT_CONCRETE_TYPE,\n ) => void\n /* Called when error saving AR */\n onError: () => void\n}\n\nexport const SetAccessRequirementCommonFields = forwardRef(\n function SetAccessRequirementCommonFields(\n props: SetAccessRequirementCommonFieldsProps,\n ref: ForwardedRef<SetAccessRequirementCommonFieldsHandle>,\n ) {\n const { subject, accessRequirementId, onSave, onError } = props\n\n const isEditing = !subject\n\n const [subjects, setSubjects] = useState<RestrictableObjectDescriptor[]>(\n subject ? [subject] : [],\n )\n const [hasPendingSubjects, setHasPendingSubjects] = useState<boolean>(false)\n const [subjectsError, setSubjectsError] = useState<string | null>(null)\n const [name, setName] = useState<string>('')\n const [subjectsDefinedByAnnotations, setSubjectsDefinedByAnnotations] =\n useState<boolean>(false)\n const [arType, setArType] = useState<ACCESS_REQUIREMENT_CONCRETE_TYPE>(\n subject?.type === RestrictableObjectType.TEAM\n ? SELF_SIGN_ACCESS_REQUIREMENT_CONCRETE_TYPE_VALUE\n : MANAGED_ACT_ACCESS_REQUIREMENT_CONCRETE_TYPE_VALUE,\n )\n const [clientError, setClientError] = useState<string | null>(null)\n\n const onMutationSuccess = (ar: AccessRequirement) => {\n setClientError(null)\n onSave(ar.id.toString(), ar.concreteType)\n }\n\n const onMutationError = (error: SynapseClientError) => {\n setClientError(error.reason)\n onError()\n }\n\n const { mutate: createAccessRequirement } = useCreateAccessRequirement({\n onSuccess: newAr => onMutationSuccess(newAr),\n onError: error => onMutationError(error),\n })\n\n const { mutate: updateAccessRequirement } = useUpdateAccessRequirement({\n onSuccess: updatedAr => onMutationSuccess(updatedAr),\n onError: error => onMutationError(error),\n })\n\n const {\n data: accessRequirement,\n isLoading: isLoadingAr,\n error: getArError,\n } = useGetAccessRequirements(accessRequirementId!, {\n enabled: Boolean(accessRequirementId),\n })\n\n useEffect(() => {\n if (accessRequirement) {\n setArType(accessRequirement.concreteType)\n setName(accessRequirement.name)\n setSubjects(accessRequirement.subjectIds)\n setSubjectsDefinedByAnnotations(\n accessRequirement.subjectsDefinedByAnnotations,\n )\n }\n }, [accessRequirement])\n\n const subjectsType = useMemo(() => {\n if (subject) {\n return subject.type\n }\n if (accessRequirement) {\n const initialSubjects = accessRequirement.subjectIds\n if (initialSubjects.length > 0) {\n return initialSubjects[0].type\n }\n }\n if (subjectsDefinedByAnnotations) {\n return RestrictableObjectType.ENTITY\n }\n return null\n }, [subject, accessRequirement, subjectsDefinedByAnnotations])\n\n const selectorContent = useMemo(() => {\n if (!subjectsType) return <></>\n\n function onUpdate(subjects: RestrictableObjectDescriptor[]) {\n setSubjectsError(null)\n setSubjects(subjects)\n }\n\n function onUpdateIdsTextbox(value: string) {\n setSubjectsError(null)\n setHasPendingSubjects(value.trim() !== '')\n }\n\n if (subjectsDefinedByAnnotations) {\n return <></>\n }\n switch (subjectsType) {\n case RestrictableObjectType.TEAM:\n return (\n <TeamSubjectsSelector\n subjects={subjects}\n onUpdate={subjects => onUpdate(subjects)}\n onUpdateTeamIDsTextbox={value => onUpdateIdsTextbox(value)}\n />\n )\n case RestrictableObjectType.ENTITY:\n return (\n <EntitySubjectsSelector\n subjects={subjects}\n onUpdate={subjects => onUpdate(subjects)}\n onUpdateEntityIDsTextbox={value => onUpdateIdsTextbox(value)}\n />\n )\n default:\n console.error(\n `RestrictableObjectType ${subjectsType} does not have a selector implemented.`,\n )\n return <></>\n }\n }, [subjectsType, subjects, subjectsDefinedByAnnotations])\n\n useImperativeHandle(ref, () => {\n return {\n save() {\n const isStillLoading =\n (isEditing && !accessRequirement) || !subjectsType\n const hasSubjectsError =\n !subjectsDefinedByAnnotations &&\n (hasPendingSubjects || subjects.length === 0)\n if (isStillLoading || hasSubjectsError) {\n if (hasSubjectsError && !isStillLoading) {\n if (hasPendingSubjects) {\n setSubjectsError(UNSAVED_SUBJECTS_ERROR_MESSAGE(subjectsType))\n } else if (subjects.length === 0) {\n setSubjectsError(EMPTY_SUBJECT_LIST_ERROR_MESSAGE)\n }\n }\n\n onError()\n return\n }\n\n const newAccessType = getAccessType(subjectsType)\n if (!isEditing) {\n const newAr: Partial<AccessRequirement> = {\n concreteType: arType,\n subjectIds: subjects,\n name: name,\n accessType: newAccessType,\n subjectsDefinedByAnnotations: subjectsDefinedByAnnotations,\n }\n createAccessRequirement(newAr)\n }\n\n if (isEditing && accessRequirement) {\n updateAccessRequirement({\n ...accessRequirement,\n subjectIds: subjects,\n name: name,\n accessType: newAccessType,\n subjectsDefinedByAnnotations: subjectsDefinedByAnnotations,\n })\n }\n },\n }\n }, [\n hasPendingSubjects,\n subjectsType,\n subjects,\n name,\n arType,\n accessRequirement,\n isEditing,\n onError,\n createAccessRequirement,\n updateAccessRequirement,\n subjectsDefinedByAnnotations,\n ])\n\n if (isLoadingAr || !subjectsType) {\n return (\n <>\n <Skeleton width={100} height={30} />\n <Skeleton width={125} height={30} />\n <Skeleton width=\"100%\">\n <TextField />\n </Skeleton>\n <Skeleton width={100} height={30} />\n <Skeleton width=\"100%\">\n <TextField />\n </Skeleton>\n </>\n )\n }\n\n if (getArError) {\n return <Alert severity=\"error\">{getArError.reason}</Alert>\n }\n\n return (\n <>\n <Typography {...headerProps}>Resources</Typography>\n {subjectsType !== RestrictableObjectType.TEAM && (\n <FormControlLabel\n control={<Checkbox />}\n label=\"Associated entities should be defined by annotations (DUO)\"\n checked={subjectsDefinedByAnnotations}\n onChange={() => {\n setSubjectsError(null)\n // if we are switching from DUO to manually defining the subjects (and the AR has been retrieved), then\n // reset to the AR subject IDs or the original subject ID. Otherwise, clear out the subjects.\n let newSubjectIds: RestrictableObjectDescriptor[] = []\n if (subjectsDefinedByAnnotations) {\n if (accessRequirement) {\n newSubjectIds = accessRequirement.subjectIds\n } else if (subject) {\n newSubjectIds = [subject]\n }\n }\n setSubjects(newSubjectIds)\n setSubjectsDefinedByAnnotations(!subjectsDefinedByAnnotations)\n }}\n />\n )}\n <SynapseErrorBoundary>{selectorContent}</SynapseErrorBoundary>\n {subjectsError && <Alert severity=\"error\">{subjectsError}</Alert>}\n <Stack\n direction=\"row\"\n sx={{\n gap: 1,\n alignItems: 'center',\n mb: 1,\n mt: 2,\n }}\n >\n <Typography component=\"label\" htmlFor=\"arName\" {...headerProps}>\n Name\n </Typography>\n <Tooltip title={NAME_HELP_TEXT} placement=\"right\">\n <HelpOutlineTwoTone sx={{ color: 'grey.600' }} />\n </Tooltip>\n </Stack>\n <TextField\n id=\"arName\"\n name=\"arName\"\n value={name}\n placeholder=\"Access requirement name\"\n fullWidth\n onChange={event => setName(event.target.value)}\n />\n {!isEditing && subjectsType !== RestrictableObjectType.TEAM && (\n <>\n <Typography\n {...headerProps}\n sx={spreadSx(\n {\n mt: 2,\n },\n headerProps.sx,\n )}\n >\n Access requirement type\n </Typography>\n <RadioGroup\n value={arType}\n onChange={(_event, value) =>\n setArType(value as ACCESS_REQUIREMENT_CONCRETE_TYPE)\n }\n >\n <FormControlLabel\n value={MANAGED_ACT_ACCESS_REQUIREMENT_CONCRETE_TYPE_VALUE}\n control={<Radio />}\n label=\"Controlled - requests are in Synapse\"\n />\n <FormControlLabel\n value={SELF_SIGN_ACCESS_REQUIREMENT_CONCRETE_TYPE_VALUE}\n control={<Radio />}\n label=\"Click wrap\"\n />\n </RadioGroup>\n </>\n )}\n {clientError && (\n <Alert severity=\"error\" sx={{ marginTop: 2 }}>\n {clientError}\n </Alert>\n )}\n </>\n )\n },\n)\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"SetBasicAccessRequirementFields.d.ts","sourceRoot":"","sources":["../../../src/components/SetBasicAccessRequirementFields/SetBasicAccessRequirementFields.tsx"],"names":[],"mappings":"AAKA,OAAO,EACL,iBAAiB,EACjB,2BAA2B,EAC5B,MAAM,iCAAiC,CAAA;AAcxC,MAAM,MAAM,sBAAsB,GAAG,OAAO,CAC1C,iBAAiB,EACjB,2BAA2B,CAC5B,CAAA;AAED,MAAM,MAAM,qCAAqC,GAAG;IAElD,IAAI,EAAE,MAAM,IAAI,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,oCAAoC,GAAG;IACjD,mBAAmB,EAAE,MAAM,CAAA;IAE3B,MAAM,EAAE,MAAM,IAAI,CAAA;IAElB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,2BAA2B,CAAC,EAAE,OAAO,CAAA;CACtC,CAAA;AAED,eAAO,MAAM,+BAA+B,wJA4F3C,CAAA"}
1
+ {"version":3,"file":"SetBasicAccessRequirementFields.d.ts","sourceRoot":"","sources":["../../../src/components/SetBasicAccessRequirementFields/SetBasicAccessRequirementFields.tsx"],"names":[],"mappings":"AAKA,OAAO,EACL,iBAAiB,EACjB,2BAA2B,EAC5B,MAAM,iCAAiC,CAAA;AAcxC,MAAM,MAAM,sBAAsB,GAAG,OAAO,CAC1C,iBAAiB,EACjB,2BAA2B,CAC5B,CAAA;AAED,MAAM,MAAM,qCAAqC,GAAG;IAElD,IAAI,EAAE,MAAM,IAAI,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,oCAAoC,GAAG;IACjD,mBAAmB,EAAE,MAAM,CAAA;IAE3B,MAAM,EAAE,MAAM,IAAI,CAAA;IAElB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,2BAA2B,CAAC,EAAE,OAAO,CAAA;CACtC,CAAA;AAED,eAAO,MAAM,+BAA+B,wJAwF3C,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"SetBasicAccessRequirementFields.js","names":[],"sources":["../../../src/components/SetBasicAccessRequirementFields/SetBasicAccessRequirementFields.tsx"],"sourcesContent":["import {\n useGetAccessRequirements,\n useUpdateAccessRequirement,\n} from '@/synapse-queries'\nimport { Alert } from '@mui/material'\nimport {\n AccessRequirement,\n ManagedACTAccessRequirement,\n} from '@sage-bionetworks/synapse-types'\nimport {\n ForwardedRef,\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useState,\n} from 'react'\nimport { SynapseSpinner } from '../LoadingScreen/LoadingScreen'\nimport { AccessorRequirements } from './AccessorRequirements'\nimport { AccessRequirementTextInstructions } from './AccessRequirementTextInstructions'\nimport { AccessRequirementWikiInstructions } from './AccessRequirementWikiInstructions'\n\nexport type BasicAccessRequirement = Exclude<\n AccessRequirement,\n ManagedACTAccessRequirement\n>\n\nexport type SetBasicAccessRequirementFieldsHandle = {\n /* Allow the parent component to trigger saving the AR, so this may be embedded in an arbitrary modal. */\n save: () => void\n}\n\nexport type SetBasicAccessRequirementFieldsProps = {\n accessRequirementId: string\n /* Called when AR has been saved successfully */\n onSave: () => void\n /* Called when error saving AR */\n onError: () => void\n allowDeleteTextInstructions?: boolean\n}\n\nexport const SetBasicAccessRequirementFields = forwardRef(\n function SetBasicAccessRequirementFields(\n props: SetBasicAccessRequirementFieldsProps,\n ref: ForwardedRef<SetBasicAccessRequirementFieldsHandle>,\n ) {\n const {\n accessRequirementId,\n onSave,\n onError,\n allowDeleteTextInstructions = false,\n } = props\n const [updatedAr, setUpdatedAr] = useState<BasicAccessRequirement | null>(\n null,\n )\n\n const { data: accessRequirement, error: getArError } =\n useGetAccessRequirements<BasicAccessRequirement>(accessRequirementId, {\n staleTime: Infinity,\n })\n useEffect(() => {\n if (accessRequirement) {\n setUpdatedAr(accessRequirement)\n }\n }, [accessRequirement])\n\n const { mutateAsync: updateAccessRequirement, error: updateArError } =\n useUpdateAccessRequirement<BasicAccessRequirement>()\n\n const onUpdateAccessRequirement = useCallback(\n async (\n updatedAr: BasicAccessRequirement,\n isDeletingTextInstructions: boolean,\n ) => {\n try {\n await updateAccessRequirement(updatedAr)\n setUpdatedAr(updatedAr)\n if (!isDeletingTextInstructions) {\n onSave()\n }\n } catch {\n if (!isDeletingTextInstructions) {\n onError()\n }\n }\n },\n [onSave, onError, updateAccessRequirement],\n )\n\n useImperativeHandle(\n ref,\n () => {\n return {\n save() {\n if (updatedAr) onUpdateAccessRequirement(updatedAr, false)\n },\n }\n },\n [updatedAr, onUpdateAccessRequirement],\n )\n\n if (!updatedAr) {\n if (getArError) {\n return <Alert severity=\"error\">{getArError.reason}</Alert>\n } else {\n return <SynapseSpinner />\n }\n }\n\n return (\n <>\n <AccessRequirementTextInstructions\n accessRequirement={updatedAr}\n allowDelete={allowDeleteTextInstructions}\n onConfirmDelete={updatedAr => {\n onUpdateAccessRequirement(updatedAr as BasicAccessRequirement, true)\n }}\n />\n <AccessRequirementWikiInstructions accessRequirement={updatedAr} />\n <AccessorRequirements\n accessRequirement={updatedAr}\n onChange={updatedAr =>\n setUpdatedAr(updatedAr as BasicAccessRequirement)\n }\n />\n {updateArError && (\n <Alert severity=\"error\" sx={{ marginTop: 2 }}>\n {updateArError.reason}\n </Alert>\n )}\n </>\n )\n },\n)\n"],"mappings":";;;;;;;;;;AAyCA,IAAa,IAAkC,EAC7C,SACE,GACA,GACA;CACA,IAAM,EACJ,wBACA,WACA,YACA,iCAA8B,OAC5B,GACE,CAAC,GAAW,KAAgB,EAChC,KACD,EAEK,EAAE,MAAM,GAAmB,OAAO,MACtC,EAAiD,GAAqB,EACpE,WAAW,UACZ,CAAC;AACJ,SAAgB;AACd,EAAI,KACF,EAAa,EAAkB;IAEhC,CAAC,EAAkB,CAAC;CAEvB,IAAM,EAAE,aAAa,GAAyB,OAAO,MACnD,GAAoD,EAEhD,IAA4B,EAChC,OACE,GACA,MACG;AACH,MAAI;AAGF,GAFA,MAAM,EAAwB,EAAU,EACxC,EAAa,EAAU,EAClB,KACH,GAAQ;UAEJ;AACN,GAAK,KACH,GAAS;;IAIf;EAAC;EAAQ;EAAS;EAAwB,CAC3C;AAsBD,QApBA,EACE,UAES,EACL,OAAO;AACL,EAAI,KAAW,EAA0B,GAAW,GAAM;IAE7D,GAEH,CAAC,GAAW,EAA0B,CACvC,EAEI,IASH,kBAAA,GAAA,EAAA,UAAA;EACE,kBAAC,GAAD;GACE,mBAAmB;GACnB,aAAa;GACb,kBAAiB,MAAa;AAC5B,MAA0B,GAAqC,GAAK;;GAEtE,CAAA;EACF,kBAAC,GAAD,EAAmC,mBAAmB,GAAa,CAAA;EACnE,kBAAC,GAAD;GACE,mBAAmB;GACnB,WAAU,MACR,EAAa,EAAoC;GAEnD,CAAA;EACD,KACC,kBAAC,GAAD;GAAO,UAAS;GAAQ,IAAI,EAAE,WAAW,GAAG;aACzC,EAAc;GACT,CAAA;EAET,EAAA,CAAA,GA5BC,IACK,kBAAC,GAAD;EAAO,UAAS;YAAS,EAAW;EAAe,CAAA,GAEnD,kBAAC,GAAD,EAAkB,CAAA;EA4BhC"}
1
+ {"version":3,"file":"SetBasicAccessRequirementFields.js","names":[],"sources":["../../../src/components/SetBasicAccessRequirementFields/SetBasicAccessRequirementFields.tsx"],"sourcesContent":["import {\n useGetAccessRequirements,\n useUpdateAccessRequirement,\n} from '@/synapse-queries'\nimport { Alert } from '@mui/material'\nimport {\n AccessRequirement,\n ManagedACTAccessRequirement,\n} from '@sage-bionetworks/synapse-types'\nimport {\n ForwardedRef,\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useState,\n} from 'react'\nimport { SynapseSpinner } from '../LoadingScreen/LoadingScreen'\nimport { AccessorRequirements } from './AccessorRequirements'\nimport { AccessRequirementTextInstructions } from './AccessRequirementTextInstructions'\nimport { AccessRequirementWikiInstructions } from './AccessRequirementWikiInstructions'\n\nexport type BasicAccessRequirement = Exclude<\n AccessRequirement,\n ManagedACTAccessRequirement\n>\n\nexport type SetBasicAccessRequirementFieldsHandle = {\n /* Allow the parent component to trigger saving the AR, so this may be embedded in an arbitrary modal. */\n save: () => void\n}\n\nexport type SetBasicAccessRequirementFieldsProps = {\n accessRequirementId: string\n /* Called when AR has been saved successfully */\n onSave: () => void\n /* Called when error saving AR */\n onError: () => void\n allowDeleteTextInstructions?: boolean\n}\n\nexport const SetBasicAccessRequirementFields = forwardRef(\n function SetBasicAccessRequirementFields(\n props: SetBasicAccessRequirementFieldsProps,\n ref: ForwardedRef<SetBasicAccessRequirementFieldsHandle>,\n ) {\n const {\n accessRequirementId,\n onSave,\n onError,\n allowDeleteTextInstructions = false,\n } = props\n const [updatedAr, setUpdatedAr] = useState<BasicAccessRequirement | null>(\n null,\n )\n\n const { data: accessRequirement, error: getArError } =\n useGetAccessRequirements<BasicAccessRequirement>(accessRequirementId, {\n staleTime: Infinity,\n })\n useEffect(() => {\n if (accessRequirement) {\n setUpdatedAr(accessRequirement)\n }\n }, [accessRequirement])\n\n const { mutateAsync: updateAccessRequirement, error: updateArError } =\n useUpdateAccessRequirement<BasicAccessRequirement>()\n\n const onUpdateAccessRequirement = useCallback(\n async (\n updatedAr: BasicAccessRequirement,\n isDeletingTextInstructions: boolean,\n ) => {\n try {\n await updateAccessRequirement(updatedAr)\n setUpdatedAr(updatedAr)\n if (!isDeletingTextInstructions) {\n onSave()\n }\n } catch {\n if (!isDeletingTextInstructions) {\n onError()\n }\n }\n },\n [onSave, onError, updateAccessRequirement],\n )\n\n useImperativeHandle(ref, () => {\n return {\n save() {\n if (updatedAr) onUpdateAccessRequirement(updatedAr, false)\n },\n }\n }, [updatedAr, onUpdateAccessRequirement])\n\n if (!updatedAr) {\n if (getArError) {\n return <Alert severity=\"error\">{getArError.reason}</Alert>\n } else {\n return <SynapseSpinner />\n }\n }\n\n return (\n <>\n <AccessRequirementTextInstructions\n accessRequirement={updatedAr}\n allowDelete={allowDeleteTextInstructions}\n onConfirmDelete={updatedAr => {\n onUpdateAccessRequirement(updatedAr as BasicAccessRequirement, true)\n }}\n />\n <AccessRequirementWikiInstructions accessRequirement={updatedAr} />\n <AccessorRequirements\n accessRequirement={updatedAr}\n onChange={updatedAr =>\n setUpdatedAr(updatedAr as BasicAccessRequirement)\n }\n />\n {updateArError && (\n <Alert severity=\"error\" sx={{ marginTop: 2 }}>\n {updateArError.reason}\n </Alert>\n )}\n </>\n )\n },\n)\n"],"mappings":";;;;;;;;;;AAyCA,IAAa,IAAkC,EAC7C,SACE,GACA,GACA;CACA,IAAM,EACJ,wBACA,WACA,YACA,iCAA8B,OAC5B,GACE,CAAC,GAAW,KAAgB,EAChC,KACD,EAEK,EAAE,MAAM,GAAmB,OAAO,MACtC,EAAiD,GAAqB,EACpE,WAAW,UACZ,CAAC;AACJ,SAAgB;AACd,EAAI,KACF,EAAa,EAAkB;IAEhC,CAAC,EAAkB,CAAC;CAEvB,IAAM,EAAE,aAAa,GAAyB,OAAO,MACnD,GAAoD,EAEhD,IAA4B,EAChC,OACE,GACA,MACG;AACH,MAAI;AAGF,GAFA,MAAM,EAAwB,EAAU,EACxC,EAAa,EAAU,EAClB,KACH,GAAQ;UAEJ;AACN,GAAK,KACH,GAAS;;IAIf;EAAC;EAAQ;EAAS;EAAwB,CAC3C;AAkBD,QAhBA,EAAoB,UACX,EACL,OAAO;AACL,EAAI,KAAW,EAA0B,GAAW,GAAM;IAE7D,GACA,CAAC,GAAW,EAA0B,CAAC,EAErC,IASH,kBAAA,GAAA,EAAA,UAAA;EACE,kBAAC,GAAD;GACE,mBAAmB;GACnB,aAAa;GACb,kBAAiB,MAAa;AAC5B,MAA0B,GAAqC,GAAK;;GAEtE,CAAA;EACF,kBAAC,GAAD,EAAmC,mBAAmB,GAAa,CAAA;EACnE,kBAAC,GAAD;GACE,mBAAmB;GACnB,WAAU,MACR,EAAa,EAAoC;GAEnD,CAAA;EACD,KACC,kBAAC,GAAD;GAAO,UAAS;GAAQ,IAAI,EAAE,WAAW,GAAG;aACzC,EAAc;GACT,CAAA;EAET,EAAA,CAAA,GA5BC,IACK,kBAAC,GAAD;EAAO,UAAS;YAAS,EAAW;EAAe,CAAA,GAEnD,kBAAC,GAAD,EAAkB,CAAA;EA4BhC"}
@@ -1 +1 @@
1
- {"version":3,"file":"SetManagedAccessRequirementFields.d.ts","sourceRoot":"","sources":["../../../src/components/SetManagedAccessRequirementFields/SetManagedAccessRequirementFields.tsx"],"names":[],"mappings":"AAqCA,eAAO,MAAM,yBAAyB,oDACa,CAAA;AAEnD,eAAO,MAAM,sCAAsC,GACjD,sBAAsB,MAAM,oBAa7B,CAAA;AAED,MAAM,MAAM,uCAAuC,GAAG;IAEpD,IAAI,EAAE,MAAM,IAAI,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,sCAAsC,GAAG;IACnD,mBAAmB,EAAE,MAAM,CAAA;IAE3B,MAAM,EAAE,MAAM,IAAI,CAAA;IAElB,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,CAAA;AAED,eAAO,MAAM,iCAAiC,4JA2Q7C,CAAA"}
1
+ {"version":3,"file":"SetManagedAccessRequirementFields.d.ts","sourceRoot":"","sources":["../../../src/components/SetManagedAccessRequirementFields/SetManagedAccessRequirementFields.tsx"],"names":[],"mappings":"AAqCA,eAAO,MAAM,yBAAyB,oDACa,CAAA;AAEnD,eAAO,MAAM,sCAAsC,GACjD,sBAAsB,MAAM,oBAa7B,CAAA;AAED,MAAM,MAAM,uCAAuC,GAAG;IAEpD,IAAI,EAAE,MAAM,IAAI,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,sCAAsC,GAAG;IACnD,mBAAmB,EAAE,MAAM,CAAA;IAE3B,MAAM,EAAE,MAAM,IAAI,CAAA;IAElB,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,CAAA;AAED,eAAO,MAAM,iCAAiC,4JAuQ7C,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"SetManagedAccessRequirementFields.js","names":[],"sources":["../../../src/components/SetManagedAccessRequirementFields/SetManagedAccessRequirementFields.tsx"],"sourcesContent":["import {\n useGetAccessRequirements,\n useUpdateAccessRequirement,\n} from '@/synapse-queries'\nimport { DAY_IN_MS } from '@/utils/SynapseConstants'\nimport {\n Alert,\n Box,\n Checkbox,\n FormControlLabel,\n TextField,\n Typography,\n} from '@mui/material'\nimport { SynapseClientError } from '@sage-bionetworks/synapse-client/util/SynapseClientError'\nimport {\n FileHandleAssociateType,\n FileHandleAssociation,\n FileUploadComplete,\n ManagedACTAccessRequirement,\n UploadCallbackResp,\n} from '@sage-bionetworks/synapse-types'\nimport {\n ForwardedRef,\n forwardRef,\n useEffect,\n useImperativeHandle,\n useMemo,\n useState,\n} from 'react'\nimport { UploadDocumentField } from '../AccessRequirementList/ManagedACTAccessRequirementRequestFlow/UploadDocumentField'\nimport { SynapseErrorBoundary } from '../error/ErrorBanner'\nimport { SynapseSpinner } from '../LoadingScreen/LoadingScreen'\nimport {\n AccessorRequirements,\n AccessRequirementWikiInstructions,\n} from '../SetBasicAccessRequirementFields'\n\nexport const DUC_TEMPLATE_UPLOAD_ERROR =\n 'There was an error uploading the DUC template. '\n\nexport const getValidExpirationPeriodOrErrorMessage = (\n expirationPeriodDays: string,\n) => {\n if (expirationPeriodDays === '') return 0\n\n const msgPrefix = 'Please enter a valid expiration period (in days): '\n if (/^[-]?\\d+$/.test(expirationPeriodDays)) {\n const num = Number(expirationPeriodDays)\n if (num < 0) {\n return `${msgPrefix}If expiration period is set, then it must be greater than 0.`\n }\n return num * DAY_IN_MS\n }\n return `${msgPrefix}For input string: \"${expirationPeriodDays}\"`\n}\n\nexport type SetManagedAccessRequirementFieldsHandle = {\n /* Allow the parent component to trigger saving the AR, so this may be embedded in an arbitrary modal. */\n save: () => void\n}\n\nexport type SetManagedAccessRequirementFieldsProps = {\n accessRequirementId: string\n /* Called when AR has been saved successfully */\n onSave: () => void\n /* Called when error saving AR */\n onError: () => void\n}\n\nexport const SetManagedAccessRequirementFields = forwardRef(\n function SetManagedAccessRequirementFields(\n props: SetManagedAccessRequirementFieldsProps,\n ref: ForwardedRef<SetManagedAccessRequirementFieldsHandle>,\n ) {\n const { accessRequirementId, onSave, onError } = props\n\n const { data: accessRequirement, error: getArError } =\n useGetAccessRequirements<ManagedACTAccessRequirement>(\n accessRequirementId,\n { staleTime: Infinity },\n )\n useEffect(() => {\n if (accessRequirement) {\n setUpdatedAr(accessRequirement)\n setExpirationPeriodDays(\n (accessRequirement.expirationPeriod / DAY_IN_MS).toString(),\n )\n }\n }, [accessRequirement])\n\n const [uploadDucTemplateError, setUploadDucTemplateError] = useState<\n string | null\n >(null)\n const [expirationPeriodError, setExpirationPeriodError] = useState<\n string | null\n >(null)\n\n const [updatedAr, setUpdatedAr] =\n useState<ManagedACTAccessRequirement | null>(null)\n const [expirationPeriodDays, setExpirationPeriodDays] = useState<string>('')\n\n const ducTemplateFileHandleAssociation = useMemo(() => {\n if (updatedAr?.ducTemplateFileHandleId) {\n const ducTemplateFileHandleAssociation: FileHandleAssociation = {\n fileHandleId: updatedAr.ducTemplateFileHandleId,\n associateObjectType:\n FileHandleAssociateType.AccessRequirementAttachment,\n associateObjectId: updatedAr.id.toString(),\n }\n return ducTemplateFileHandleAssociation\n }\n return undefined\n }, [updatedAr?.ducTemplateFileHandleId, updatedAr?.id])\n\n const uploadDucTemplateCallback = (data: UploadCallbackResp) => {\n if (data.resp && data.success && updatedAr) {\n setUploadDucTemplateError(null)\n // Files are uploaded and synced with the server immediately\n const uploadResponse: FileUploadComplete = data.resp\n setUpdatedAr({\n ...updatedAr,\n ducTemplateFileHandleId: uploadResponse.fileHandleId,\n })\n } else if (!data.success && data.error) {\n setUploadDucTemplateError(\n `${DUC_TEMPLATE_UPLOAD_ERROR} ${\n (data.error as SynapseClientError).reason\n }`,\n )\n }\n }\n\n const {\n mutate: updateAccessRequirement,\n isPending: isUpdatingAccessRequirement,\n error: updateArError,\n } = useUpdateAccessRequirement<ManagedACTAccessRequirement>({\n onSuccess: () => onSave(),\n onError: () => onError(),\n })\n\n useImperativeHandle(\n ref,\n () => {\n return {\n save() {\n if (updatedAr) {\n const expirationPeriodOrErrorMessage =\n getValidExpirationPeriodOrErrorMessage(expirationPeriodDays)\n if (typeof expirationPeriodOrErrorMessage === 'string') {\n setExpirationPeriodError(expirationPeriodOrErrorMessage)\n onError()\n } else {\n updateAccessRequirement({\n ...updatedAr,\n expirationPeriod: expirationPeriodOrErrorMessage,\n })\n }\n }\n },\n }\n },\n [expirationPeriodDays, updatedAr, updateAccessRequirement, onError],\n )\n\n if (!updatedAr) {\n if (getArError) {\n return <Alert severity=\"error\">{getArError.reason}</Alert>\n } else {\n return <SynapseSpinner />\n }\n }\n\n return (\n <>\n <AccessRequirementWikiInstructions accessRequirement={updatedAr} />\n <Box>\n <Typography\n sx={{\n bgcolor: '#f5f5f5',\n borderBottom: '1px solid #ddd',\n color: '#333',\n px: 2,\n py: 1,\n }}\n >\n Data Access Request Parameters\n </Typography>\n <Box\n sx={{\n mt: 2,\n mb: 4,\n }}\n >\n <AccessorRequirements\n accessRequirement={updatedAr}\n onChange={updatedAr =>\n setUpdatedAr(updatedAr as ManagedACTAccessRequirement)\n }\n />\n <Box\n sx={{\n mb: 2,\n }}\n >\n <Typography\n variant=\"body1\"\n sx={{\n fontWeight: 700,\n }}\n >\n DUC\n </Typography>\n <FormControlLabel\n control={<Checkbox />}\n label=\"DUC is required.\"\n checked={updatedAr.isDUCRequired}\n onChange={(_event, checked: boolean) =>\n setUpdatedAr({\n ...updatedAr,\n isDUCRequired: checked,\n })\n }\n />\n <SynapseErrorBoundary>\n <UploadDocumentField\n id=\"duc\"\n isLoading={isUpdatingAccessRequirement}\n uploadCallback={resp => uploadDucTemplateCallback(resp)}\n documentName=\"Template DUC\"\n fileHandleAssociations={\n ducTemplateFileHandleAssociation\n ? [ducTemplateFileHandleAssociation]\n : undefined\n }\n isMultiFileUpload={false}\n uploadBtnVariant=\"contained\"\n />\n {uploadDucTemplateError && (\n <Alert severity=\"error\" sx={{ marginTop: 2 }}>\n {uploadDucTemplateError}\n </Alert>\n )}\n </SynapseErrorBoundary>\n <FormControlLabel\n label=\"IRB approval is required.\"\n checked={updatedAr.isIRBApprovalRequired}\n control={<Checkbox />}\n onChange={(_event, checked: boolean) =>\n setUpdatedAr({\n ...updatedAr,\n isIRBApprovalRequired: checked,\n })\n }\n sx={{ ml: 0 }}\n />\n <FormControlLabel\n control={<Checkbox />}\n label=\"Other documents are required.\"\n checked={updatedAr.areOtherAttachmentsRequired}\n onChange={(_event, checked: boolean) =>\n setUpdatedAr({\n ...updatedAr,\n areOtherAttachmentsRequired: checked,\n })\n }\n />\n <TextField\n id=\"expirationPeriod\"\n name=\"expirationPeriod\"\n label=\"Expiration period (days)\"\n value={expirationPeriodDays}\n error={Boolean(expirationPeriodError)}\n helperText={expirationPeriodError}\n sx={{ mt: 1 }}\n fullWidth\n onChange={event => {\n setExpirationPeriodError(null)\n setExpirationPeriodDays(event.target.value)\n }}\n onBlur={() => {\n const expirationPeriodOrErrorMessage =\n getValidExpirationPeriodOrErrorMessage(expirationPeriodDays)\n if (typeof expirationPeriodOrErrorMessage === 'string') {\n setExpirationPeriodError(expirationPeriodOrErrorMessage)\n }\n }}\n />\n <Box\n sx={{\n mt: 1,\n }}\n >\n <FormControlLabel\n control={<Checkbox />}\n label=\"Intended Data Use statement is required.\"\n checked={updatedAr.isIDURequired}\n onChange={(_event, checked: boolean) => {\n if (checked) {\n setUpdatedAr({\n ...updatedAr,\n isIDURequired: true,\n })\n } else {\n setUpdatedAr({\n ...updatedAr,\n isIDURequired: false,\n isIDUPublic: false,\n })\n }\n }}\n />\n <FormControlLabel\n control={<Checkbox />}\n label=\"Intended Data Use statements will be publicly available.\"\n checked={updatedAr.isIDUPublic}\n disabled={!updatedAr.isIDURequired}\n onChange={(_event, checked: boolean) =>\n setUpdatedAr({\n ...updatedAr,\n isIDUPublic: checked,\n })\n }\n />\n </Box>\n </Box>\n </Box>\n </Box>\n {updateArError && (\n <Alert severity=\"error\" sx={{ marginTop: 2 }}>\n {updateArError.reason}\n </Alert>\n )}\n </>\n )\n },\n)\n"],"mappings":"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"}
1
+ {"version":3,"file":"SetManagedAccessRequirementFields.js","names":[],"sources":["../../../src/components/SetManagedAccessRequirementFields/SetManagedAccessRequirementFields.tsx"],"sourcesContent":["import {\n useGetAccessRequirements,\n useUpdateAccessRequirement,\n} from '@/synapse-queries'\nimport { DAY_IN_MS } from '@/utils/SynapseConstants'\nimport {\n Alert,\n Box,\n Checkbox,\n FormControlLabel,\n TextField,\n Typography,\n} from '@mui/material'\nimport { SynapseClientError } from '@sage-bionetworks/synapse-client/util/SynapseClientError'\nimport {\n FileHandleAssociateType,\n FileHandleAssociation,\n FileUploadComplete,\n ManagedACTAccessRequirement,\n UploadCallbackResp,\n} from '@sage-bionetworks/synapse-types'\nimport {\n ForwardedRef,\n forwardRef,\n useEffect,\n useImperativeHandle,\n useMemo,\n useState,\n} from 'react'\nimport { UploadDocumentField } from '../AccessRequirementList/ManagedACTAccessRequirementRequestFlow/UploadDocumentField'\nimport { SynapseErrorBoundary } from '../error/ErrorBanner'\nimport { SynapseSpinner } from '../LoadingScreen/LoadingScreen'\nimport {\n AccessorRequirements,\n AccessRequirementWikiInstructions,\n} from '../SetBasicAccessRequirementFields'\n\nexport const DUC_TEMPLATE_UPLOAD_ERROR =\n 'There was an error uploading the DUC template. '\n\nexport const getValidExpirationPeriodOrErrorMessage = (\n expirationPeriodDays: string,\n) => {\n if (expirationPeriodDays === '') return 0\n\n const msgPrefix = 'Please enter a valid expiration period (in days): '\n if (/^[-]?\\d+$/.test(expirationPeriodDays)) {\n const num = Number(expirationPeriodDays)\n if (num < 0) {\n return `${msgPrefix}If expiration period is set, then it must be greater than 0.`\n }\n return num * DAY_IN_MS\n }\n return `${msgPrefix}For input string: \"${expirationPeriodDays}\"`\n}\n\nexport type SetManagedAccessRequirementFieldsHandle = {\n /* Allow the parent component to trigger saving the AR, so this may be embedded in an arbitrary modal. */\n save: () => void\n}\n\nexport type SetManagedAccessRequirementFieldsProps = {\n accessRequirementId: string\n /* Called when AR has been saved successfully */\n onSave: () => void\n /* Called when error saving AR */\n onError: () => void\n}\n\nexport const SetManagedAccessRequirementFields = forwardRef(\n function SetManagedAccessRequirementFields(\n props: SetManagedAccessRequirementFieldsProps,\n ref: ForwardedRef<SetManagedAccessRequirementFieldsHandle>,\n ) {\n const { accessRequirementId, onSave, onError } = props\n\n const { data: accessRequirement, error: getArError } =\n useGetAccessRequirements<ManagedACTAccessRequirement>(\n accessRequirementId,\n { staleTime: Infinity },\n )\n useEffect(() => {\n if (accessRequirement) {\n setUpdatedAr(accessRequirement)\n setExpirationPeriodDays(\n (accessRequirement.expirationPeriod / DAY_IN_MS).toString(),\n )\n }\n }, [accessRequirement])\n\n const [uploadDucTemplateError, setUploadDucTemplateError] = useState<\n string | null\n >(null)\n const [expirationPeriodError, setExpirationPeriodError] = useState<\n string | null\n >(null)\n\n const [updatedAr, setUpdatedAr] =\n useState<ManagedACTAccessRequirement | null>(null)\n const [expirationPeriodDays, setExpirationPeriodDays] = useState<string>('')\n\n const ducTemplateFileHandleAssociation = useMemo(() => {\n if (updatedAr?.ducTemplateFileHandleId) {\n const ducTemplateFileHandleAssociation: FileHandleAssociation = {\n fileHandleId: updatedAr.ducTemplateFileHandleId,\n associateObjectType:\n FileHandleAssociateType.AccessRequirementAttachment,\n associateObjectId: updatedAr.id.toString(),\n }\n return ducTemplateFileHandleAssociation\n }\n return undefined\n }, [updatedAr?.ducTemplateFileHandleId, updatedAr?.id])\n\n const uploadDucTemplateCallback = (data: UploadCallbackResp) => {\n if (data.resp && data.success && updatedAr) {\n setUploadDucTemplateError(null)\n // Files are uploaded and synced with the server immediately\n const uploadResponse: FileUploadComplete = data.resp\n setUpdatedAr({\n ...updatedAr,\n ducTemplateFileHandleId: uploadResponse.fileHandleId,\n })\n } else if (!data.success && data.error) {\n setUploadDucTemplateError(\n `${DUC_TEMPLATE_UPLOAD_ERROR} ${\n (data.error as SynapseClientError).reason\n }`,\n )\n }\n }\n\n const {\n mutate: updateAccessRequirement,\n isPending: isUpdatingAccessRequirement,\n error: updateArError,\n } = useUpdateAccessRequirement<ManagedACTAccessRequirement>({\n onSuccess: () => onSave(),\n onError: () => onError(),\n })\n\n useImperativeHandle(ref, () => {\n return {\n save() {\n if (updatedAr) {\n const expirationPeriodOrErrorMessage =\n getValidExpirationPeriodOrErrorMessage(expirationPeriodDays)\n if (typeof expirationPeriodOrErrorMessage === 'string') {\n setExpirationPeriodError(expirationPeriodOrErrorMessage)\n onError()\n } else {\n updateAccessRequirement({\n ...updatedAr,\n expirationPeriod: expirationPeriodOrErrorMessage,\n })\n }\n }\n },\n }\n }, [expirationPeriodDays, updatedAr, updateAccessRequirement, onError])\n\n if (!updatedAr) {\n if (getArError) {\n return <Alert severity=\"error\">{getArError.reason}</Alert>\n } else {\n return <SynapseSpinner />\n }\n }\n\n return (\n <>\n <AccessRequirementWikiInstructions accessRequirement={updatedAr} />\n <Box>\n <Typography\n sx={{\n bgcolor: '#f5f5f5',\n borderBottom: '1px solid #ddd',\n color: '#333',\n px: 2,\n py: 1,\n }}\n >\n Data Access Request Parameters\n </Typography>\n <Box\n sx={{\n mt: 2,\n mb: 4,\n }}\n >\n <AccessorRequirements\n accessRequirement={updatedAr}\n onChange={updatedAr =>\n setUpdatedAr(updatedAr as ManagedACTAccessRequirement)\n }\n />\n <Box\n sx={{\n mb: 2,\n }}\n >\n <Typography\n variant=\"body1\"\n sx={{\n fontWeight: 700,\n }}\n >\n DUC\n </Typography>\n <FormControlLabel\n control={<Checkbox />}\n label=\"DUC is required.\"\n checked={updatedAr.isDUCRequired}\n onChange={(_event, checked: boolean) =>\n setUpdatedAr({\n ...updatedAr,\n isDUCRequired: checked,\n })\n }\n />\n <SynapseErrorBoundary>\n <UploadDocumentField\n id=\"duc\"\n isLoading={isUpdatingAccessRequirement}\n uploadCallback={resp => uploadDucTemplateCallback(resp)}\n documentName=\"Template DUC\"\n fileHandleAssociations={\n ducTemplateFileHandleAssociation\n ? [ducTemplateFileHandleAssociation]\n : undefined\n }\n isMultiFileUpload={false}\n uploadBtnVariant=\"contained\"\n />\n {uploadDucTemplateError && (\n <Alert severity=\"error\" sx={{ marginTop: 2 }}>\n {uploadDucTemplateError}\n </Alert>\n )}\n </SynapseErrorBoundary>\n <FormControlLabel\n label=\"IRB approval is required.\"\n checked={updatedAr.isIRBApprovalRequired}\n control={<Checkbox />}\n onChange={(_event, checked: boolean) =>\n setUpdatedAr({\n ...updatedAr,\n isIRBApprovalRequired: checked,\n })\n }\n sx={{ ml: 0 }}\n />\n <FormControlLabel\n control={<Checkbox />}\n label=\"Other documents are required.\"\n checked={updatedAr.areOtherAttachmentsRequired}\n onChange={(_event, checked: boolean) =>\n setUpdatedAr({\n ...updatedAr,\n areOtherAttachmentsRequired: checked,\n })\n }\n />\n <TextField\n id=\"expirationPeriod\"\n name=\"expirationPeriod\"\n label=\"Expiration period (days)\"\n value={expirationPeriodDays}\n error={Boolean(expirationPeriodError)}\n helperText={expirationPeriodError}\n sx={{ mt: 1 }}\n fullWidth\n onChange={event => {\n setExpirationPeriodError(null)\n setExpirationPeriodDays(event.target.value)\n }}\n onBlur={() => {\n const expirationPeriodOrErrorMessage =\n getValidExpirationPeriodOrErrorMessage(expirationPeriodDays)\n if (typeof expirationPeriodOrErrorMessage === 'string') {\n setExpirationPeriodError(expirationPeriodOrErrorMessage)\n }\n }}\n />\n <Box\n sx={{\n mt: 1,\n }}\n >\n <FormControlLabel\n control={<Checkbox />}\n label=\"Intended Data Use statement is required.\"\n checked={updatedAr.isIDURequired}\n onChange={(_event, checked: boolean) => {\n if (checked) {\n setUpdatedAr({\n ...updatedAr,\n isIDURequired: true,\n })\n } else {\n setUpdatedAr({\n ...updatedAr,\n isIDURequired: false,\n isIDUPublic: false,\n })\n }\n }}\n />\n <FormControlLabel\n control={<Checkbox />}\n label=\"Intended Data Use statements will be publicly available.\"\n checked={updatedAr.isIDUPublic}\n disabled={!updatedAr.isIDURequired}\n onChange={(_event, checked: boolean) =>\n setUpdatedAr({\n ...updatedAr,\n isIDUPublic: checked,\n })\n }\n />\n </Box>\n </Box>\n </Box>\n </Box>\n {updateArError && (\n <Alert severity=\"error\" sx={{ marginTop: 2 }}>\n {updateArError.reason}\n </Alert>\n )}\n </>\n )\n },\n)\n"],"mappings":"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"}
@@ -10,7 +10,7 @@ type StandaloneQueryWrapperOwnProps = {
10
10
  showTopLevelControls?: boolean;
11
11
  searchConfiguration?: Omit<SearchV2Props, 'queryContext' | 'queryVisualizationContext'>;
12
12
  customControls?: CustomControl[];
13
- } & Omit<TopLevelControlsProps, 'customControls'> & Pick<QueryVisualizationWrapperProps, 'rgbIndex' | 'unitDescription' | 'columnAliases' | 'noContentPlaceholderType' | 'showLastUpdatedOn' | 'visibleColumnCount' | 'additionalFiltersSessionStorageKey'> & Pick<QueryWrapperProps, 'fileIdColumnName' | 'fileNameColumnName' | 'fileVersionColumnName' | 'onQueryResultBundleChange' | 'shouldDeepLink'> & Pick<QueryWrapperPlotNavProps, 'cardConfiguration' | 'tableConfiguration'>;
13
+ } & Omit<TopLevelControlsProps, 'customControls'> & Pick<QueryVisualizationWrapperProps, 'rgbIndex' | 'unitDescription' | 'columnAliases' | 'noContentPlaceholderType' | 'showLastUpdatedOn' | 'visibleColumnCount' | 'hiddenColumns' | 'additionalFiltersSessionStorageKey'> & Pick<QueryWrapperProps, 'fileIdColumnName' | 'fileNameColumnName' | 'fileVersionColumnName' | 'onQueryResultBundleChange' | 'shouldDeepLink'> & Pick<QueryWrapperPlotNavProps, 'cardConfiguration' | 'tableConfiguration'>;
14
14
  export type StandaloneQueryWrapperProps = QueryOrDeprecatedSearchParams & SynapseTableConfiguration & StandaloneQueryWrapperOwnProps;
15
15
  export declare const generateInitQueryRequest: (query: Query) => QueryBundleRequest;
16
16
  export declare function getQueryFromProps(props: StandaloneQueryWrapperProps): Query;
@@ -1 +1 @@
1
- {"version":3,"file":"StandaloneQueryWrapper.d.ts","sourceRoot":"","sources":["../../../src/components/StandaloneQueryWrapper/StandaloneQueryWrapper.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAA;AASlG,OAAO,EAAE,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AAI3E,OAAO,EAGL,8BAA8B,EAC/B,MAAM,8BAA8B,CAAA;AACrC,OAAO,EAAgB,iBAAiB,EAAE,MAAM,8BAA8B,CAAA;AAC9E,OAAO,EAAE,wBAAwB,EAAE,MAAM,4CAA4C,CAAA;AAGrF,OAAiB,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAElE,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAA;AACxE,OAAyB,EACvB,qBAAqB,EACrB,aAAa,EACd,MAAM,mDAAmD,CAAA;AAI1D,KAAK,8BAA8B,GAAG;IACpC,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,mBAAmB,CAAC,EAAE,IAAI,CACxB,aAAa,EACb,cAAc,GAAG,2BAA2B,CAC7C,CAAA;IACD,cAAc,CAAC,EAAE,aAAa,EAAE,CAAA;CACjC,GAAG,IAAI,CAAC,qBAAqB,EAAE,gBAAgB,CAAC,GAC/C,IAAI,CACF,8BAA8B,EAC5B,UAAU,GACV,iBAAiB,GACjB,eAAe,GACf,0BAA0B,GAC1B,mBAAmB,GACnB,oBAAoB,GACpB,oCAAoC,CACvC,GACD,IAAI,CACF,iBAAiB,EACf,kBAAkB,GAClB,oBAAoB,GACpB,uBAAuB,GACvB,2BAA2B,GAC3B,gBAAgB,CACnB,GACD,IAAI,CAAC,wBAAwB,EAAE,mBAAmB,GAAG,oBAAoB,CAAC,CAAA;AAE5E,MAAM,MAAM,2BAA2B,GAAG,6BAA6B,GACrE,yBAAyB,GACzB,8BAA8B,CAAA;AAEhC,eAAO,MAAM,wBAAwB,GAAI,OAAO,KAAK,KAAG,kBAiBvD,CAAA;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,2BAA2B,SAiBnE;AAED;;;GAGG;AACH,iBAAS,sBAAsB,CAAC,KAAK,EAAE,2BAA2B,2CAiIjE;AAED,eAAe,sBAAsB,CAAA"}
1
+ {"version":3,"file":"StandaloneQueryWrapper.d.ts","sourceRoot":"","sources":["../../../src/components/StandaloneQueryWrapper/StandaloneQueryWrapper.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAA;AASlG,OAAO,EAAE,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AAI3E,OAAO,EAGL,8BAA8B,EAC/B,MAAM,8BAA8B,CAAA;AACrC,OAAO,EAAgB,iBAAiB,EAAE,MAAM,8BAA8B,CAAA;AAC9E,OAAO,EAAE,wBAAwB,EAAE,MAAM,4CAA4C,CAAA;AAGrF,OAAiB,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAElE,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAA;AACxE,OAAyB,EACvB,qBAAqB,EACrB,aAAa,EACd,MAAM,mDAAmD,CAAA;AAI1D,KAAK,8BAA8B,GAAG;IACpC,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,mBAAmB,CAAC,EAAE,IAAI,CACxB,aAAa,EACb,cAAc,GAAG,2BAA2B,CAC7C,CAAA;IACD,cAAc,CAAC,EAAE,aAAa,EAAE,CAAA;CACjC,GAAG,IAAI,CAAC,qBAAqB,EAAE,gBAAgB,CAAC,GAC/C,IAAI,CACF,8BAA8B,EAC5B,UAAU,GACV,iBAAiB,GACjB,eAAe,GACf,0BAA0B,GAC1B,mBAAmB,GACnB,oBAAoB,GACpB,eAAe,GACf,oCAAoC,CACvC,GACD,IAAI,CACF,iBAAiB,EACf,kBAAkB,GAClB,oBAAoB,GACpB,uBAAuB,GACvB,2BAA2B,GAC3B,gBAAgB,CACnB,GACD,IAAI,CAAC,wBAAwB,EAAE,mBAAmB,GAAG,oBAAoB,CAAC,CAAA;AAE5E,MAAM,MAAM,2BAA2B,GAAG,6BAA6B,GACrE,yBAAyB,GACzB,8BAA8B,CAAA;AAEhC,eAAO,MAAM,wBAAwB,GAAI,OAAO,KAAK,KAAG,kBAiBvD,CAAA;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,2BAA2B,SAiBnE;AAED;;;GAGG;AACH,iBAAS,sBAAsB,CAAC,KAAK,EAAE,2BAA2B,2CAiIjE;AAED,eAAe,sBAAsB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"StandaloneQueryWrapper.js","names":[],"sources":["../../../src/components/StandaloneQueryWrapper/StandaloneQueryWrapper.tsx"],"sourcesContent":["import { QueryOrDeprecatedSearchParams } from '@/components/CardContainerLogic/CardContainerLogic'\nimport { useGetEntity } from '@/synapse-queries/entity/useEntity'\nimport { SynapseConstants } from '@/utils'\nimport { isTable } from '@/utils/functions/EntityTypeUtils'\nimport {\n getAdditionalFilters,\n parseEntityIdFromSqlStatement,\n} from '@/utils/functions/SqlFunctions'\nimport { DEFAULT_PAGE_SIZE } from '@/utils/SynapseConstants'\nimport { Query, QueryBundleRequest } from '@sage-bionetworks/synapse-types'\nimport { useState } from 'react'\nimport FullTextSearch from '../FullTextSearch/FullTextSearch'\nimport { QueryContextConsumer } from '../QueryContext/QueryContext'\nimport {\n QueryVisualizationContextConsumer,\n QueryVisualizationWrapper,\n QueryVisualizationWrapperProps,\n} from '../QueryVisualizationWrapper'\nimport { QueryWrapper, QueryWrapperProps } from '../QueryWrapper/QueryWrapper'\nimport { QueryWrapperPlotNavProps } from '../QueryWrapperPlotNav/QueryWrapperPlotNav'\nimport { RowSetView } from '../QueryWrapperPlotNav/RowSetView'\nimport { NoContentPlaceholderType } from '../SynapseTable/NoContentPlaceholderType'\nimport SearchV2, { SearchV2Props } from '../SynapseTable/SearchV2'\nimport SqlEditor from '../SynapseTable/SqlEditor'\nimport { SynapseTableConfiguration } from '../SynapseTable/SynapseTable'\nimport TopLevelControls, {\n TopLevelControlsProps,\n CustomControl,\n} from '../SynapseTable/TopLevelControls/TopLevelControls'\nimport { CustomControls } from '../SynapseTable/CustomControls/CustomControls'\nimport TotalQueryResults from '../TotalQueryResults'\n\ntype StandaloneQueryWrapperOwnProps = {\n showTopLevelControls?: boolean\n searchConfiguration?: Omit<\n SearchV2Props,\n 'queryContext' | 'queryVisualizationContext'\n >\n customControls?: CustomControl[]\n} & Omit<TopLevelControlsProps, 'customControls'> &\n Pick<\n QueryVisualizationWrapperProps,\n | 'rgbIndex'\n | 'unitDescription'\n | 'columnAliases'\n | 'noContentPlaceholderType'\n | 'showLastUpdatedOn'\n | 'visibleColumnCount'\n | 'additionalFiltersSessionStorageKey'\n > &\n Pick<\n QueryWrapperProps,\n | 'fileIdColumnName'\n | 'fileNameColumnName'\n | 'fileVersionColumnName'\n | 'onQueryResultBundleChange'\n | 'shouldDeepLink'\n > &\n Pick<QueryWrapperPlotNavProps, 'cardConfiguration' | 'tableConfiguration'>\n\nexport type StandaloneQueryWrapperProps = QueryOrDeprecatedSearchParams &\n SynapseTableConfiguration &\n StandaloneQueryWrapperOwnProps\n\nexport const generateInitQueryRequest = (query: Query): QueryBundleRequest => {\n return {\n partMask:\n SynapseConstants.BUNDLE_MASK_QUERY_FACETS |\n SynapseConstants.BUNDLE_MASK_QUERY_COUNT |\n SynapseConstants.BUNDLE_MASK_QUERY_SELECT_COLUMNS |\n SynapseConstants.BUNDLE_MASK_QUERY_COLUMN_MODELS |\n SynapseConstants.BUNDLE_MASK_QUERY_RESULTS |\n SynapseConstants.BUNDLE_MASK_LAST_UPDATED_ON,\n entityId: parseEntityIdFromSqlStatement(query.sql),\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n query: {\n limit: DEFAULT_PAGE_SIZE,\n offset: 0,\n ...query,\n },\n }\n}\n\nexport function getQueryFromProps(props: StandaloneQueryWrapperProps) {\n if (props.query) {\n // use props.query if set\n return props.query\n } else {\n // use the deprecated sql, searchParams, and sqlOperator\n const additionalFilters = getAdditionalFilters(\n props.searchParams,\n props.sqlOperator,\n props.additionalFiltersSessionStorageKey,\n )\n return {\n sql: props.sql!,\n additionalFilters,\n offset: 0,\n }\n }\n}\n\n/**\n * This component was initially implemented on the portal side. It renders a SynapseTable if a title is provided.\n * If showTopLevelControls is set to true, then the SynapseTable will also include the TopLevelControls (search, export table, column selection).\n */\nfunction StandaloneQueryWrapper(props: StandaloneQueryWrapperProps) {\n /** @deprecated property inherited from SynapseTableProps */\n const { hideDownload } = props\n const {\n showAccessColumn,\n sql: deprecatedSql,\n hideAddToDownloadListColumn = hideDownload,\n hideQueryCount,\n name,\n showTopLevelControls = false,\n searchConfiguration,\n unitDescription = 'Results',\n rgbIndex,\n showLastUpdatedOn,\n noContentPlaceholderType = showTopLevelControls\n ? NoContentPlaceholderType.INTERACTIVE\n : NoContentPlaceholderType.STATIC,\n cardConfiguration,\n tableConfiguration,\n shouldDeepLink,\n customControls,\n ...rest\n } = props\n const [componentKey, setComponentKey] = useState(1)\n const remount = () => {\n setComponentKey(componentKey + 1)\n }\n\n const sql = props.query?.sql ?? deprecatedSql ?? ''\n const query: Query = getQueryFromProps(props)\n const derivedQueryRequestFromSearchParams = generateInitQueryRequest(query)\n const entityId = parseEntityIdFromSqlStatement(sql)\n const { data: entity } = useGetEntity(entityId)\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 =\n JSON.stringify(derivedQueryRequestFromSearchParams) + componentKey\n return (\n <QueryWrapper\n {...rest}\n initQueryRequest={derivedQueryRequestFromSearchParams}\n shouldDeepLink={shouldDeepLink}\n key={queryWrapperKey}\n >\n <QueryVisualizationWrapper\n rgbIndex={rgbIndex}\n unitDescription={unitDescription}\n showLastUpdatedOn={showLastUpdatedOn}\n noContentPlaceholderType={noContentPlaceholderType}\n {...rest}\n >\n <QueryContextConsumer>\n {queryContext => {\n if (queryContext === undefined) {\n throw new Error(\n 'No queryContext found when calling QueryContextConsumer',\n )\n }\n return (\n <QueryVisualizationContextConsumer>\n {queryVisualizationContext => {\n if (queryVisualizationContext === undefined) {\n throw new Error(\n 'No queryVisualizationContext found when calling QueryVisualizationContextConsumer',\n )\n }\n\n return (\n <>\n {showTopLevelControls && (\n <TopLevelControls\n showColumnSelection={true}\n name={name}\n hideDownload={hideAddToDownloadListColumn}\n hideQueryCount={hideQueryCount}\n hideFacetFilterControl={true}\n hideVisualizationsControl={true}\n remount={remount}\n customControls={customControls}\n />\n )}\n {entity && isTable(entity) && entity.isSearchEnabled ? (\n <FullTextSearch\n ftsConfig={searchConfiguration?.ftsConfig}\n />\n ) : (\n <SearchV2\n {...searchConfiguration}\n queryContext={queryContext}\n queryVisualizationContext={queryVisualizationContext}\n />\n )}\n <SqlEditor />\n {showTopLevelControls && (\n <TotalQueryResults frontText={''} />\n )}\n <CustomControls\n customControls={props.customControls}\n remount={remount}\n />\n\n <RowSetView\n tableConfiguration={\n cardConfiguration\n ? undefined\n : {\n ...tableConfiguration, // if exist, use tableConfiguration property\n showAccessColumn: showAccessColumn,\n hideAddToDownloadListColumn,\n ...rest,\n }\n }\n cardConfiguration={cardConfiguration} // if exist, use the cardConfiguration property\n />\n </>\n )\n }}\n </QueryVisualizationContextConsumer>\n )\n }}\n </QueryContextConsumer>\n </QueryVisualizationWrapper>\n </QueryWrapper>\n )\n}\n\nexport default StandaloneQueryWrapper\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAgEA,IAAa,KAA4B,OAChC;CACL,UACE;CAMF,UAAU,EAA8B,EAAM,IAAI;CAClD,cAAc;CACd,OAAO;EACL,OAAA;EACA,QAAQ;EACR,GAAG;EACJ;CACF;AAGH,SAAgB,EAAkB,GAAoC;AACpE,KAAI,EAAM,MAER,QAAO,EAAM;CACR;EAEL,IAAM,IAAoB,EACxB,EAAM,cACN,EAAM,aACN,EAAM,mCACP;AACD,SAAO;GACL,KAAK,EAAM;GACX;GACA,QAAQ;GACT;;;AAQL,SAAS,EAAuB,GAAoC;CAElE,IAAM,EAAE,oBAAiB,GACnB,EACJ,qBACA,KAAK,GACL,iCAA8B,GAC9B,mBACA,SACA,0BAAuB,IACvB,wBACA,qBAAkB,WAClB,aACA,sBACA,8BAA2B,IACvB,EAAyB,cACzB,EAAyB,QAC7B,sBACA,uBACA,mBACA,mBACA,GAAG,MACD,GACE,CAAC,GAAc,KAAmB,EAAS,EAAE,EAC7C,UAAgB;AACpB,IAAgB,IAAe,EAAE;IAG7B,IAAM,EAAM,OAAO,OAAO,KAAiB,IAE3C,IAAsC,EADvB,EAAkB,EAC8B,CAAM,EAErE,EAAE,MAAM,MAAW,EADR,EAA8B,EACT,CAAS,EAQzC,IACJ,KAAK,UAAU,EAAoC,GAAG;AACxD,QACE,kBAAC,GAAD;EACE,GAAI;EACJ,kBAAkB;EACF;EAChB,KAAK;EAgFQ,EA9Eb,kBAAC,GAAD;EACY;EACO;EACE;EACO;EAC1B,GAAI;YAEJ,kBAAC,GAAD,EAAA,WACG,MAAgB;AACf,OAAI,MAAiB,KAAA,EACnB,OAAU,MACR,0DACD;AAEH,UACE,kBAAC,GAAD,EAAA,WACG,MAA6B;AAC5B,QAAI,MAA8B,KAAA,EAChC,OAAU,MACR,oFACD;AAGH,WACE,kBAAA,GAAA,EAAA,UAAA;KACG,KACC,kBAAC,GAAD;MACE,qBAAqB;MACf;MACN,cAAc;MACE;MAChB,wBAAwB;MACxB,2BAA2B;MAClB;MACO;MAChB,CAAA;KAEH,KAAU,EAAQ,EAAO,IAAI,EAAO,kBACnC,kBAAC,GAAD,EACE,WAAW,GAAqB,WAChC,CAAA,GAEF,kBAAC,GAAD;MACE,GAAI;MACU;MACa;MAC3B,CAAA;KAEJ,kBAAC,GAAD,EAAa,CAAA;KACZ,KACC,kBAAC,GAAD,EAAmB,WAAW,IAAM,CAAA;KAEtC,kBAAC,GAAD;MACE,gBAAgB,EAAM;MACb;MACT,CAAA;KAEF,kBAAC,GAAD;MACE,oBACE,IACI,KAAA,IACA;OACE,GAAG;OACe;OAClB;OACA,GAAG;OACJ;MAEY;MACnB,CAAA;KACD,EAAA,CAAA;MAG2B,CAAA;KAGnB,CAAA;EACG,CAAA,CACf"}
1
+ {"version":3,"file":"StandaloneQueryWrapper.js","names":[],"sources":["../../../src/components/StandaloneQueryWrapper/StandaloneQueryWrapper.tsx"],"sourcesContent":["import { QueryOrDeprecatedSearchParams } from '@/components/CardContainerLogic/CardContainerLogic'\nimport { useGetEntity } from '@/synapse-queries/entity/useEntity'\nimport { SynapseConstants } from '@/utils'\nimport { isTable } from '@/utils/functions/EntityTypeUtils'\nimport {\n getAdditionalFilters,\n parseEntityIdFromSqlStatement,\n} from '@/utils/functions/SqlFunctions'\nimport { DEFAULT_PAGE_SIZE } from '@/utils/SynapseConstants'\nimport { Query, QueryBundleRequest } from '@sage-bionetworks/synapse-types'\nimport { useState } from 'react'\nimport FullTextSearch from '../FullTextSearch/FullTextSearch'\nimport { QueryContextConsumer } from '../QueryContext/QueryContext'\nimport {\n QueryVisualizationContextConsumer,\n QueryVisualizationWrapper,\n QueryVisualizationWrapperProps,\n} from '../QueryVisualizationWrapper'\nimport { QueryWrapper, QueryWrapperProps } from '../QueryWrapper/QueryWrapper'\nimport { QueryWrapperPlotNavProps } from '../QueryWrapperPlotNav/QueryWrapperPlotNav'\nimport { RowSetView } from '../QueryWrapperPlotNav/RowSetView'\nimport { NoContentPlaceholderType } from '../SynapseTable/NoContentPlaceholderType'\nimport SearchV2, { SearchV2Props } from '../SynapseTable/SearchV2'\nimport SqlEditor from '../SynapseTable/SqlEditor'\nimport { SynapseTableConfiguration } from '../SynapseTable/SynapseTable'\nimport TopLevelControls, {\n TopLevelControlsProps,\n CustomControl,\n} from '../SynapseTable/TopLevelControls/TopLevelControls'\nimport { CustomControls } from '../SynapseTable/CustomControls/CustomControls'\nimport TotalQueryResults from '../TotalQueryResults'\n\ntype StandaloneQueryWrapperOwnProps = {\n showTopLevelControls?: boolean\n searchConfiguration?: Omit<\n SearchV2Props,\n 'queryContext' | 'queryVisualizationContext'\n >\n customControls?: CustomControl[]\n} & Omit<TopLevelControlsProps, 'customControls'> &\n Pick<\n QueryVisualizationWrapperProps,\n | 'rgbIndex'\n | 'unitDescription'\n | 'columnAliases'\n | 'noContentPlaceholderType'\n | 'showLastUpdatedOn'\n | 'visibleColumnCount'\n | 'hiddenColumns'\n | 'additionalFiltersSessionStorageKey'\n > &\n Pick<\n QueryWrapperProps,\n | 'fileIdColumnName'\n | 'fileNameColumnName'\n | 'fileVersionColumnName'\n | 'onQueryResultBundleChange'\n | 'shouldDeepLink'\n > &\n Pick<QueryWrapperPlotNavProps, 'cardConfiguration' | 'tableConfiguration'>\n\nexport type StandaloneQueryWrapperProps = QueryOrDeprecatedSearchParams &\n SynapseTableConfiguration &\n StandaloneQueryWrapperOwnProps\n\nexport const generateInitQueryRequest = (query: Query): QueryBundleRequest => {\n return {\n partMask:\n SynapseConstants.BUNDLE_MASK_QUERY_FACETS |\n SynapseConstants.BUNDLE_MASK_QUERY_COUNT |\n SynapseConstants.BUNDLE_MASK_QUERY_SELECT_COLUMNS |\n SynapseConstants.BUNDLE_MASK_QUERY_COLUMN_MODELS |\n SynapseConstants.BUNDLE_MASK_QUERY_RESULTS |\n SynapseConstants.BUNDLE_MASK_LAST_UPDATED_ON,\n entityId: parseEntityIdFromSqlStatement(query.sql),\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n query: {\n limit: DEFAULT_PAGE_SIZE,\n offset: 0,\n ...query,\n },\n }\n}\n\nexport function getQueryFromProps(props: StandaloneQueryWrapperProps) {\n if (props.query) {\n // use props.query if set\n return props.query\n } else {\n // use the deprecated sql, searchParams, and sqlOperator\n const additionalFilters = getAdditionalFilters(\n props.searchParams,\n props.sqlOperator,\n props.additionalFiltersSessionStorageKey,\n )\n return {\n sql: props.sql!,\n additionalFilters,\n offset: 0,\n }\n }\n}\n\n/**\n * This component was initially implemented on the portal side. It renders a SynapseTable if a title is provided.\n * If showTopLevelControls is set to true, then the SynapseTable will also include the TopLevelControls (search, export table, column selection).\n */\nfunction StandaloneQueryWrapper(props: StandaloneQueryWrapperProps) {\n /** @deprecated property inherited from SynapseTableProps */\n const { hideDownload } = props\n const {\n showAccessColumn,\n sql: deprecatedSql,\n hideAddToDownloadListColumn = hideDownload,\n hideQueryCount,\n name,\n showTopLevelControls = false,\n searchConfiguration,\n unitDescription = 'Results',\n rgbIndex,\n showLastUpdatedOn,\n noContentPlaceholderType = showTopLevelControls\n ? NoContentPlaceholderType.INTERACTIVE\n : NoContentPlaceholderType.STATIC,\n cardConfiguration,\n tableConfiguration,\n shouldDeepLink,\n customControls,\n ...rest\n } = props\n const [componentKey, setComponentKey] = useState(1)\n const remount = () => {\n setComponentKey(componentKey + 1)\n }\n\n const sql = props.query?.sql ?? deprecatedSql ?? ''\n const query: Query = getQueryFromProps(props)\n const derivedQueryRequestFromSearchParams = generateInitQueryRequest(query)\n const entityId = parseEntityIdFromSqlStatement(sql)\n const { data: entity } = useGetEntity(entityId)\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 =\n JSON.stringify(derivedQueryRequestFromSearchParams) + componentKey\n return (\n <QueryWrapper\n {...rest}\n initQueryRequest={derivedQueryRequestFromSearchParams}\n shouldDeepLink={shouldDeepLink}\n key={queryWrapperKey}\n >\n <QueryVisualizationWrapper\n rgbIndex={rgbIndex}\n unitDescription={unitDescription}\n showLastUpdatedOn={showLastUpdatedOn}\n noContentPlaceholderType={noContentPlaceholderType}\n {...rest}\n >\n <QueryContextConsumer>\n {queryContext => {\n if (queryContext === undefined) {\n throw new Error(\n 'No queryContext found when calling QueryContextConsumer',\n )\n }\n return (\n <QueryVisualizationContextConsumer>\n {queryVisualizationContext => {\n if (queryVisualizationContext === undefined) {\n throw new Error(\n 'No queryVisualizationContext found when calling QueryVisualizationContextConsumer',\n )\n }\n\n return (\n <>\n {showTopLevelControls && (\n <TopLevelControls\n showColumnSelection={true}\n name={name}\n hideDownload={hideAddToDownloadListColumn}\n hideQueryCount={hideQueryCount}\n hideFacetFilterControl={true}\n hideVisualizationsControl={true}\n remount={remount}\n customControls={customControls}\n />\n )}\n {entity && isTable(entity) && entity.isSearchEnabled ? (\n <FullTextSearch\n ftsConfig={searchConfiguration?.ftsConfig}\n />\n ) : (\n <SearchV2\n {...searchConfiguration}\n queryContext={queryContext}\n queryVisualizationContext={queryVisualizationContext}\n />\n )}\n <SqlEditor />\n {showTopLevelControls && (\n <TotalQueryResults frontText={''} />\n )}\n <CustomControls\n customControls={props.customControls}\n remount={remount}\n />\n\n <RowSetView\n tableConfiguration={\n cardConfiguration\n ? undefined\n : {\n ...tableConfiguration, // if exist, use tableConfiguration property\n showAccessColumn: showAccessColumn,\n hideAddToDownloadListColumn,\n ...rest,\n }\n }\n cardConfiguration={cardConfiguration} // if exist, use the cardConfiguration property\n />\n </>\n )\n }}\n </QueryVisualizationContextConsumer>\n )\n }}\n </QueryContextConsumer>\n </QueryVisualizationWrapper>\n </QueryWrapper>\n )\n}\n\nexport default StandaloneQueryWrapper\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAiEA,IAAa,KAA4B,OAChC;CACL,UACE;CAMF,UAAU,EAA8B,EAAM,IAAI;CAClD,cAAc;CACd,OAAO;EACL,OAAA;EACA,QAAQ;EACR,GAAG;EACJ;CACF;AAGH,SAAgB,EAAkB,GAAoC;AACpE,KAAI,EAAM,MAER,QAAO,EAAM;CACR;EAEL,IAAM,IAAoB,EACxB,EAAM,cACN,EAAM,aACN,EAAM,mCACP;AACD,SAAO;GACL,KAAK,EAAM;GACX;GACA,QAAQ;GACT;;;AAQL,SAAS,EAAuB,GAAoC;CAElE,IAAM,EAAE,oBAAiB,GACnB,EACJ,qBACA,KAAK,GACL,iCAA8B,GAC9B,mBACA,SACA,0BAAuB,IACvB,wBACA,qBAAkB,WAClB,aACA,sBACA,8BAA2B,IACvB,EAAyB,cACzB,EAAyB,QAC7B,sBACA,uBACA,mBACA,mBACA,GAAG,MACD,GACE,CAAC,GAAc,KAAmB,EAAS,EAAE,EAC7C,UAAgB;AACpB,IAAgB,IAAe,EAAE;IAG7B,IAAM,EAAM,OAAO,OAAO,KAAiB,IAE3C,IAAsC,EADvB,EAAkB,EAC8B,CAAM,EAErE,EAAE,MAAM,MAAW,EADR,EAA8B,EACT,CAAS,EAQzC,IACJ,KAAK,UAAU,EAAoC,GAAG;AACxD,QACE,kBAAC,GAAD;EACE,GAAI;EACJ,kBAAkB;EACF;EAChB,KAAK;EAgFQ,EA9Eb,kBAAC,GAAD;EACY;EACO;EACE;EACO;EAC1B,GAAI;YAEJ,kBAAC,GAAD,EAAA,WACG,MAAgB;AACf,OAAI,MAAiB,KAAA,EACnB,OAAU,MACR,0DACD;AAEH,UACE,kBAAC,GAAD,EAAA,WACG,MAA6B;AAC5B,QAAI,MAA8B,KAAA,EAChC,OAAU,MACR,oFACD;AAGH,WACE,kBAAA,GAAA,EAAA,UAAA;KACG,KACC,kBAAC,GAAD;MACE,qBAAqB;MACf;MACN,cAAc;MACE;MAChB,wBAAwB;MACxB,2BAA2B;MAClB;MACO;MAChB,CAAA;KAEH,KAAU,EAAQ,EAAO,IAAI,EAAO,kBACnC,kBAAC,GAAD,EACE,WAAW,GAAqB,WAChC,CAAA,GAEF,kBAAC,GAAD;MACE,GAAI;MACU;MACa;MAC3B,CAAA;KAEJ,kBAAC,GAAD,EAAa,CAAA;KACZ,KACC,kBAAC,GAAD,EAAmB,WAAW,IAAM,CAAA;KAEtC,kBAAC,GAAD;MACE,gBAAgB,EAAM;MACb;MACT,CAAA;KAEF,kBAAC,GAAD;MACE,oBACE,IACI,KAAA,IACA;OACE,GAAG;OACe;OAClB;OACA,GAAG;OACJ;MAEY;MACnB,CAAA;KACD,EAAA,CAAA;MAG2B,CAAA;KAGnB,CAAA;EACG,CAAA,CACf"}
@@ -1 +1 @@
1
- {"version":3,"file":"SynapseChatInteraction.js","names":[],"sources":["../../../src/components/SynapseChat/SynapseChatInteraction.tsx"],"sourcesContent":["import { SynapseSpinner } from '@/components/LoadingScreen/LoadingScreen'\nimport extractMessageFromTraceEvent, {\n TraceMessage,\n} from '@/components/SynapseChat/extractMessageFromTraceEvent'\nimport {\n KeyboardArrowDown,\n KeyboardArrowRight,\n SmartToyTwoTone,\n} from '@mui/icons-material'\nimport {\n Alert,\n Box,\n Button,\n Chip,\n Collapse,\n ListItem,\n ListItemText,\n Stack,\n Tooltip,\n useTheme,\n} from '@mui/material'\nimport { Color } from '@mui/material/styles'\nimport { TraceEvent } from '@sage-bionetworks/synapse-types'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport MarkdownSynapse from '../Markdown/MarkdownSynapse'\n\nexport type SynapseChatInteractionProps = {\n userMessage: string\n chatResponseText?: string\n chatResponseTrace?: TraceEvent[]\n scrollIntoView?: boolean\n chatErrorReason?: string\n onSendChat?: (message: string) => void\n}\n\n// Show tool calls in the trace. Useful for development. We may want to show them to users in the future.\nconst SHOW_TOOL_USE = false\n\nfunction getMarkdownForTraceMessage(traceMessage: TraceMessage): string {\n if ('reasoningText' in traceMessage) {\n return traceMessage.reasoningText\n }\n if (SHOW_TOOL_USE && 'toolName' in traceMessage) {\n return `**Tool Used:** \\`${\n traceMessage.toolName\n }\\`\\n\\n**Tool Input:**\\n\\`\\`\\`json\\n${JSON.stringify(\n traceMessage.toolInput,\n null,\n 2,\n )}\\n\\`\\`\\`\\n`\n }\n return ''\n}\n\nexport function SynapseChatInteraction({\n userMessage,\n chatResponseText,\n chatErrorReason,\n chatResponseTrace,\n scrollIntoView = false,\n onSendChat,\n}: SynapseChatInteractionProps) {\n const theme = useTheme()\n const ref = useRef<HTMLLIElement | null>(null)\n const [showTrace, setShowTrace] = useState(false)\n\n useEffect(() => {\n // on mount, scroll into view if instructed\n if (scrollIntoView) {\n if (ref.current) {\n ref.current.scrollIntoView({ behavior: 'smooth' })\n }\n }\n }, [ref, scrollIntoView])\n\n const isLoading = !chatResponseText && !chatErrorReason\n\n const traceMessages = useMemo(\n () =>\n (chatResponseTrace ?? [])\n .flatMap(traceEvent => extractMessageFromTraceEvent(traceEvent))\n ?.filter(trace => !!trace),\n [chatResponseTrace],\n )\n\n const hasTraceInfo = traceMessages.length > 0\n\n const lastReasoningMessage = useMemo(\n () => traceMessages.filter(trace => 'reasoningText' in trace).at(-1),\n [traceMessages],\n )\n\n const traceButtonLoadingText =\n lastReasoningMessage == null\n ? 'Thinking...'\n : lastReasoningMessage.reasoningText\n\n const traceButtonText = isLoading\n ? traceButtonLoadingText\n : `${showTrace ? 'Hide' : 'Show'} Trace`\n\n const { textContent, guidePrompts } = useMemo(() => {\n try {\n const parser = new DOMParser()\n const doc = parser.parseFromString(chatResponseText ?? '', 'text/html')\n\n // Remove tool_name and actions elements (AI XML tags not for display)\n doc\n .querySelectorAll('tool_name, actions')\n .forEach(element => element.remove())\n\n // Extract guideprompts before removing them\n const extractedGuidePrompts = Array.from(\n doc.querySelectorAll('guideprompt'),\n )\n .map(el => el.textContent?.trim())\n .filter((t): t is string => !!t)\n\n // Remove guideprompt elements\n doc.querySelectorAll('guideprompt').forEach(element => element.remove())\n\n // Extract text from <chat> element if present, otherwise use full body text\n const chatElement = doc.querySelector('chat')\n return {\n textContent: chatElement\n ? chatElement.textContent ?? ''\n : doc.body.textContent ?? '',\n guidePrompts: extractedGuidePrompts,\n }\n } catch (e) {\n console.error(e)\n return { textContent: chatResponseText ?? '', guidePrompts: [] }\n }\n }, [chatResponseText])\n\n return (\n <>\n <ListItem\n ref={ref}\n sx={{\n alignSelf: 'flex-end',\n backgroundColor: (theme.palette.secondary as unknown as Color)[100],\n borderRadius: '24px',\n maxWidth: '70%',\n display: 'block',\n mb: '5px',\n p: '8px 12px',\n wordWrap: 'break-word',\n width: 'auto',\n }}\n >\n <ListItemText primary={userMessage} />\n </ListItem>\n <ListItem\n sx={{\n display: 'grid',\n gridTemplateColumns: '50px auto',\n columnGap: '0px',\n justifyItems: 'center',\n alignItems: 'start',\n p: '0px',\n }}\n >\n <Box\n sx={{\n p: '3px',\n mt: '10px',\n height: '31px',\n borderRadius: '50%',\n borderStyle: 'solid',\n borderWidth: '1px',\n borderColor: 'grey.300',\n }}\n >\n <SmartToyTwoTone sx={{ color: 'secondary.main' }} />\n </Box>\n <Box\n sx={{\n borderRadius: '10px',\n padding: '10px',\n maxWidth: '100%',\n overflow: 'auto',\n }}\n >\n <Box\n component={'aside'}\n sx={{\n '.markdown': {\n fontStyle: 'italic',\n borderLeft: `4px solid ${theme.palette.grey[300]}`,\n marginLeft: '4px',\n paddingLeft: '8px',\n mt: 1,\n mb: 2,\n },\n }}\n >\n <Button\n variant={'outlined'}\n size={'small'}\n startIcon={\n isLoading ? (\n <SynapseSpinner size={14} />\n ) : showTrace ? (\n <KeyboardArrowDown sx={{ width: '14px' }} />\n ) : (\n <KeyboardArrowRight sx={{ width: '14px' }} />\n )\n }\n disabled={!hasTraceInfo}\n onClick={() => {\n setShowTrace(v => !v)\n }}\n sx={{\n height: '20px',\n fontSize: '12px',\n fontWeight: 600,\n mb: 1,\n border: 'none !important',\n color: 'grey.700',\n justifyContent: 'flex-start',\n whiteSpace: 'nowrap',\n maxWidth: '325px',\n textTransform: 'none',\n pl: 0,\n '.MuiButton-startIcon': { mr: 0.5 },\n }}\n >\n <Box sx={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>\n {traceButtonText}\n </Box>\n </Button>\n {chatResponseTrace && (\n <Collapse in={showTrace}>\n <MarkdownSynapse\n markdown={traceMessages\n .map(getMarkdownForTraceMessage)\n .filter(md => md.trim().length > 0)\n .join('<br/><br/>')}\n />\n </Collapse>\n )}\n </Box>\n {textContent && <MarkdownSynapse markdown={textContent} />}\n {onSendChat && guidePrompts.length > 0 && (\n <Stack direction=\"row\" flexWrap=\"wrap\" gap={1} mt={1}>\n {guidePrompts.map(prompt => (\n <Tooltip key={prompt} title={prompt}>\n <Chip\n label={prompt}\n variant=\"outlined\"\n color=\"primary\"\n clickable\n onClick={() => onSendChat(prompt)}\n sx={{ maxWidth: 200 }}\n />\n </Tooltip>\n ))}\n </Stack>\n )}\n </Box>\n </ListItem>\n {chatErrorReason && (\n <Alert severity={'error'} sx={{ my: 2 }}>\n {chatErrorReason}\n </Alert>\n )}\n </>\n )\n}\n\nexport default SynapseChatInteraction\n"],"mappings":"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"}
1
+ {"version":3,"file":"SynapseChatInteraction.js","names":[],"sources":["../../../src/components/SynapseChat/SynapseChatInteraction.tsx"],"sourcesContent":["import { SynapseSpinner } from '@/components/LoadingScreen/LoadingScreen'\nimport extractMessageFromTraceEvent, {\n TraceMessage,\n} from '@/components/SynapseChat/extractMessageFromTraceEvent'\nimport {\n KeyboardArrowDown,\n KeyboardArrowRight,\n SmartToyTwoTone,\n} from '@mui/icons-material'\nimport {\n Alert,\n Box,\n Button,\n Chip,\n Collapse,\n ListItem,\n ListItemText,\n Stack,\n Tooltip,\n useTheme,\n} from '@mui/material'\nimport { Color } from '@mui/material/styles'\nimport { TraceEvent } from '@sage-bionetworks/synapse-types'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport MarkdownSynapse from '../Markdown/MarkdownSynapse'\n\nexport type SynapseChatInteractionProps = {\n userMessage: string\n chatResponseText?: string\n chatResponseTrace?: TraceEvent[]\n scrollIntoView?: boolean\n chatErrorReason?: string\n onSendChat?: (message: string) => void\n}\n\n// Show tool calls in the trace. Useful for development. We may want to show them to users in the future.\nconst SHOW_TOOL_USE = false\n\nfunction getMarkdownForTraceMessage(traceMessage: TraceMessage): string {\n if ('reasoningText' in traceMessage) {\n return traceMessage.reasoningText\n }\n if (SHOW_TOOL_USE && 'toolName' in traceMessage) {\n return `**Tool Used:** \\`${\n traceMessage.toolName\n }\\`\\n\\n**Tool Input:**\\n\\`\\`\\`json\\n${JSON.stringify(\n traceMessage.toolInput,\n null,\n 2,\n )}\\n\\`\\`\\`\\n`\n }\n return ''\n}\n\nexport function SynapseChatInteraction({\n userMessage,\n chatResponseText,\n chatErrorReason,\n chatResponseTrace,\n scrollIntoView = false,\n onSendChat,\n}: SynapseChatInteractionProps) {\n const theme = useTheme()\n const ref = useRef<HTMLLIElement | null>(null)\n const [showTrace, setShowTrace] = useState(false)\n\n useEffect(() => {\n // on mount, scroll into view if instructed\n if (scrollIntoView) {\n if (ref.current) {\n ref.current.scrollIntoView({ behavior: 'smooth' })\n }\n }\n }, [ref, scrollIntoView])\n\n const isLoading = !chatResponseText && !chatErrorReason\n\n const traceMessages = useMemo(\n () =>\n (chatResponseTrace ?? [])\n .flatMap(traceEvent => extractMessageFromTraceEvent(traceEvent))\n ?.filter(trace => !!trace),\n [chatResponseTrace],\n )\n\n const hasTraceInfo = traceMessages.length > 0\n\n const lastReasoningMessage = useMemo(\n () => traceMessages.filter(trace => 'reasoningText' in trace).at(-1),\n [traceMessages],\n )\n\n const traceButtonLoadingText =\n lastReasoningMessage == null\n ? 'Thinking...'\n : lastReasoningMessage.reasoningText\n\n const traceButtonText = isLoading\n ? traceButtonLoadingText\n : `${showTrace ? 'Hide' : 'Show'} Trace`\n\n const { textContent, guidePrompts } = useMemo(() => {\n try {\n const parser = new DOMParser()\n const doc = parser.parseFromString(chatResponseText ?? '', 'text/html')\n\n // Remove tool_name and actions elements (AI XML tags not for display)\n doc\n .querySelectorAll('tool_name, actions')\n .forEach(element => element.remove())\n\n // Extract guideprompts before removing them\n const extractedGuidePrompts = Array.from(\n doc.querySelectorAll('guideprompt'),\n )\n .map(el => el.textContent?.trim())\n .filter((t): t is string => !!t)\n\n // Remove guideprompt elements\n doc.querySelectorAll('guideprompt').forEach(element => element.remove())\n\n // Extract text from <chat> element if present, otherwise use full body text\n const chatElement = doc.querySelector('chat')\n return {\n textContent: chatElement\n ? (chatElement.textContent ?? '')\n : (doc.body.textContent ?? ''),\n guidePrompts: extractedGuidePrompts,\n }\n } catch (e) {\n console.error(e)\n return { textContent: chatResponseText ?? '', guidePrompts: [] }\n }\n }, [chatResponseText])\n\n return (\n <>\n <ListItem\n ref={ref}\n sx={{\n alignSelf: 'flex-end',\n backgroundColor: (theme.palette.secondary as unknown as Color)[100],\n borderRadius: '24px',\n maxWidth: '70%',\n display: 'block',\n mb: '5px',\n p: '8px 12px',\n wordWrap: 'break-word',\n width: 'auto',\n }}\n >\n <ListItemText primary={userMessage} />\n </ListItem>\n <ListItem\n sx={{\n display: 'grid',\n gridTemplateColumns: '50px auto',\n columnGap: '0px',\n justifyItems: 'center',\n alignItems: 'start',\n p: '0px',\n }}\n >\n <Box\n sx={{\n p: '3px',\n mt: '10px',\n height: '31px',\n borderRadius: '50%',\n borderStyle: 'solid',\n borderWidth: '1px',\n borderColor: 'grey.300',\n }}\n >\n <SmartToyTwoTone sx={{ color: 'secondary.main' }} />\n </Box>\n <Box\n sx={{\n borderRadius: '10px',\n padding: '10px',\n maxWidth: '100%',\n overflow: 'auto',\n }}\n >\n <Box\n component={'aside'}\n sx={{\n '.markdown': {\n fontStyle: 'italic',\n borderLeft: `4px solid ${theme.palette.grey[300]}`,\n marginLeft: '4px',\n paddingLeft: '8px',\n mt: 1,\n mb: 2,\n },\n }}\n >\n <Button\n variant={'outlined'}\n size={'small'}\n startIcon={\n isLoading ? (\n <SynapseSpinner size={14} />\n ) : showTrace ? (\n <KeyboardArrowDown sx={{ width: '14px' }} />\n ) : (\n <KeyboardArrowRight sx={{ width: '14px' }} />\n )\n }\n disabled={!hasTraceInfo}\n onClick={() => {\n setShowTrace(v => !v)\n }}\n sx={{\n height: '20px',\n fontSize: '12px',\n fontWeight: 600,\n mb: 1,\n border: 'none !important',\n color: 'grey.700',\n justifyContent: 'flex-start',\n whiteSpace: 'nowrap',\n maxWidth: '325px',\n textTransform: 'none',\n pl: 0,\n '.MuiButton-startIcon': { mr: 0.5 },\n }}\n >\n <Box sx={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>\n {traceButtonText}\n </Box>\n </Button>\n {chatResponseTrace && (\n <Collapse in={showTrace}>\n <MarkdownSynapse\n markdown={traceMessages\n .map(getMarkdownForTraceMessage)\n .filter(md => md.trim().length > 0)\n .join('<br/><br/>')}\n />\n </Collapse>\n )}\n </Box>\n {textContent && <MarkdownSynapse markdown={textContent} />}\n {onSendChat && guidePrompts.length > 0 && (\n <Stack direction=\"row\" flexWrap=\"wrap\" gap={1} mt={1}>\n {guidePrompts.map(prompt => (\n <Tooltip key={prompt} title={prompt}>\n <Chip\n label={prompt}\n variant=\"outlined\"\n color=\"primary\"\n clickable\n onClick={() => onSendChat(prompt)}\n sx={{ maxWidth: 200 }}\n />\n </Tooltip>\n ))}\n </Stack>\n )}\n </Box>\n </ListItem>\n {chatErrorReason && (\n <Alert severity={'error'} sx={{ my: 2 }}>\n {chatErrorReason}\n </Alert>\n )}\n </>\n )\n}\n\nexport default SynapseChatInteraction\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"SynapsePortalBanners.d.ts","sourceRoot":"","sources":["../../../src/components/SynapsePortalBanners/SynapsePortalBanners.tsx"],"names":[],"mappings":"AAaA,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,EAAE,MAAM,CAAA;IAChB,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,sBAAsB,CAAC,EAAE,MAAM,CAAA;CAChC,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAAC,EAC3C,QAAQ,EACR,mBAAmC,EACnC,sBAAsC,GACvC,EAAE,yBAAyB,2CAkJ3B"}
1
+ {"version":3,"file":"SynapsePortalBanners.d.ts","sourceRoot":"","sources":["../../../src/components/SynapsePortalBanners/SynapsePortalBanners.tsx"],"names":[],"mappings":"AAaA,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,EAAE,MAAM,CAAA;IAChB,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,sBAAsB,CAAC,EAAE,MAAM,CAAA;CAChC,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAAC,EAC3C,QAAQ,EACR,mBAAmC,EACnC,sBAAsC,GACvC,EAAE,yBAAyB,2CAqJ3B"}