synapse-react-client 4.0.36 → 4.0.37

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 (316) hide show
  1. package/dist/SWC.index.js +1 -1
  2. package/dist/aridhia-queries/index.js +11 -11
  3. package/dist/aridhia-queries/useAridhiaQuery.d.ts +1 -0
  4. package/dist/aridhia-queries/useAridhiaQuery.d.ts.map +1 -1
  5. package/dist/aridhia-queries/useAridhiaQuery.js +24 -17
  6. package/dist/aridhia-queries/useAridhiaQuery.js.map +1 -1
  7. package/dist/assets/icons/emailWithNotification.js +15 -15
  8. package/dist/assets/icons/emailWithNotification.js.map +1 -1
  9. package/dist/assets/icons/emailWithNotification.svg +13 -13
  10. package/dist/components/AccessRequirementList/AccessRequirementList.d.ts.map +1 -1
  11. package/dist/components/AccessRequirementList/AccessRequirementList.js +124 -117
  12. package/dist/components/AccessRequirementList/AccessRequirementList.js.map +1 -1
  13. package/dist/components/AccessRequirementList/ManagedACTAccessRequirementRequestFlow/DataAccessRequestAccessorsFilesForm/DataAccessRequestAccessorsFilesForm.d.ts.map +1 -1
  14. package/dist/components/AccessRequirementList/ManagedACTAccessRequirementRequestFlow/DataAccessRequestAccessorsFilesForm/DataAccessRequestAccessorsFilesForm.js +1 -1
  15. package/dist/components/AccessRequirementList/ManagedACTAccessRequirementRequestFlow/DataAccessRequestAccessorsFilesForm/DataAccessRequestAccessorsFilesForm.js.map +1 -1
  16. package/dist/components/AccessRequirementList/ManagedACTAccessRequirementRequestFlow/EDucPreviewStep/EDucPreviewStep.d.ts.map +1 -1
  17. package/dist/components/AccessRequirementList/ManagedACTAccessRequirementRequestFlow/EDucPreviewStep/EDucPreviewStep.js +1 -1
  18. package/dist/components/AccessRequirementList/ManagedACTAccessRequirementRequestFlow/EDucPreviewStep/EDucPreviewStep.js.map +1 -1
  19. package/dist/components/AccessRequirementList/ManagedACTAccessRequirementRequestFlow/ManualUploadDucStep/ManualUploadDucStep.d.ts.map +1 -1
  20. package/dist/components/AccessRequirementList/ManagedACTAccessRequirementRequestFlow/ManualUploadDucStep/ManualUploadDucStep.js +33 -32
  21. package/dist/components/AccessRequirementList/ManagedACTAccessRequirementRequestFlow/ManualUploadDucStep/ManualUploadDucStep.js.map +1 -1
  22. package/dist/components/Aridhia/AridhiaAccessStatus.d.ts.map +1 -1
  23. package/dist/components/Aridhia/AridhiaAccessStatus.js +39 -18
  24. package/dist/components/Aridhia/AridhiaAccessStatus.js.map +1 -1
  25. package/dist/components/Aridhia/DarWizard/AridhiaDarWizard.d.ts +32 -0
  26. package/dist/components/Aridhia/DarWizard/AridhiaDarWizard.d.ts.map +1 -0
  27. package/dist/components/Aridhia/DarWizard/AridhiaDarWizard.js +285 -0
  28. package/dist/components/Aridhia/DarWizard/AridhiaDarWizard.js.map +1 -0
  29. package/dist/components/Aridhia/DarWizard/DarAboutStep.d.ts +4 -0
  30. package/dist/components/Aridhia/DarWizard/DarAboutStep.d.ts.map +1 -0
  31. package/dist/components/Aridhia/DarWizard/DarAboutStep.js +17 -0
  32. package/dist/components/Aridhia/DarWizard/DarAboutStep.js.map +1 -0
  33. package/dist/components/Aridhia/DarWizard/DarCompleteStep.d.ts +27 -0
  34. package/dist/components/Aridhia/DarWizard/DarCompleteStep.d.ts.map +1 -0
  35. package/dist/components/Aridhia/DarWizard/DarCompleteStep.js +96 -0
  36. package/dist/components/Aridhia/DarWizard/DarCompleteStep.js.map +1 -0
  37. package/dist/components/Aridhia/DarWizard/DarDestinationStep.d.ts +28 -0
  38. package/dist/components/Aridhia/DarWizard/DarDestinationStep.d.ts.map +1 -0
  39. package/dist/components/Aridhia/DarWizard/DarDestinationStep.js +128 -0
  40. package/dist/components/Aridhia/DarWizard/DarDestinationStep.js.map +1 -0
  41. package/dist/components/Aridhia/DarWizard/DarProjectStep.d.ts +4 -0
  42. package/dist/components/Aridhia/DarWizard/DarProjectStep.d.ts.map +1 -0
  43. package/dist/components/Aridhia/DarWizard/DarProjectStep.js +17 -0
  44. package/dist/components/Aridhia/DarWizard/DarProjectStep.js.map +1 -0
  45. package/dist/components/Aridhia/DarWizard/DarSectionForm.d.ts +13 -0
  46. package/dist/components/Aridhia/DarWizard/DarSectionForm.d.ts.map +1 -0
  47. package/dist/components/Aridhia/DarWizard/DarSectionForm.js +23 -0
  48. package/dist/components/Aridhia/DarWizard/DarSectionForm.js.map +1 -0
  49. package/dist/components/Aridhia/DarWizard/DarSubmittedPanel.d.ts +11 -0
  50. package/dist/components/Aridhia/DarWizard/DarSubmittedPanel.d.ts.map +1 -0
  51. package/dist/components/Aridhia/DarWizard/DarSubmittedPanel.js +47 -0
  52. package/dist/components/Aridhia/DarWizard/DarSubmittedPanel.js.map +1 -0
  53. package/dist/components/Aridhia/DarWizard/DarWorkspaceStep.d.ts +16 -0
  54. package/dist/components/Aridhia/DarWizard/DarWorkspaceStep.d.ts.map +1 -0
  55. package/dist/components/Aridhia/DarWizard/DarWorkspaceStep.js +33 -0
  56. package/dist/components/Aridhia/DarWizard/DarWorkspaceStep.js.map +1 -0
  57. package/dist/components/Aridhia/DarWizard/useDarDraft.d.ts +32 -0
  58. package/dist/components/Aridhia/DarWizard/useDarDraft.d.ts.map +1 -0
  59. package/dist/components/Aridhia/DarWizard/useDarDraft.js +44 -0
  60. package/dist/components/Aridhia/DarWizard/useDarDraft.js.map +1 -0
  61. package/dist/components/Aridhia/FairLabelField.d.ts +8 -0
  62. package/dist/components/Aridhia/FairLabelField.d.ts.map +1 -0
  63. package/dist/components/Aridhia/FairLabelField.js +13 -0
  64. package/dist/components/Aridhia/FairLabelField.js.map +1 -0
  65. package/dist/components/Aridhia/fairFormToRjsf.d.ts +36 -0
  66. package/dist/components/Aridhia/fairFormToRjsf.d.ts.map +1 -0
  67. package/dist/components/Aridhia/fairFormToRjsf.js +137 -0
  68. package/dist/components/Aridhia/fairFormToRjsf.js.map +1 -0
  69. package/dist/components/CannedRejectionDialog/CannedRejectionDialog.d.ts.map +1 -1
  70. package/dist/components/CannedRejectionDialog/CannedRejectionDialog.js +2 -2
  71. package/dist/components/CannedRejectionDialog/CannedRejectionDialog.js.map +1 -1
  72. package/dist/components/CardContainer/CardContainer.d.ts.map +1 -1
  73. package/dist/components/CardContainer/CardContainer.js +1 -1
  74. package/dist/components/CardContainer/CardContainer.js.map +1 -1
  75. package/dist/components/ChallengeSubmission/ChallengeSubmission.d.ts.map +1 -1
  76. package/dist/components/ChallengeSubmission/ChallengeSubmission.js +2 -2
  77. package/dist/components/ChallengeSubmission/ChallengeSubmission.js.map +1 -1
  78. package/dist/components/ChallengeTeamWizard/ChallengeTeamWizard.d.ts.map +1 -1
  79. package/dist/components/ChallengeTeamWizard/ChallengeTeamWizard.js +3 -3
  80. package/dist/components/ChallengeTeamWizard/ChallengeTeamWizard.js.map +1 -1
  81. package/dist/components/ChallengeTeamWizard/CreateChallengeTeam.js +1 -1
  82. package/dist/components/ChallengeTeamWizard/CreateChallengeTeam.js.map +1 -1
  83. package/dist/components/CreateTableViewWizard/CreateTableViewWizard.js +2 -2
  84. package/dist/components/CreateTableViewWizard/CreateTableViewWizard.js.map +1 -1
  85. package/dist/components/DataGrid/SynapseGrid.d.ts.map +1 -1
  86. package/dist/components/DataGrid/SynapseGrid.js +121 -117
  87. package/dist/components/DataGrid/SynapseGrid.js.map +1 -1
  88. package/dist/components/DataGrid/columns/DateTimeColumn.d.ts +21 -1
  89. package/dist/components/DataGrid/columns/DateTimeColumn.d.ts.map +1 -1
  90. package/dist/components/DataGrid/columns/DateTimeColumn.js +73 -29
  91. package/dist/components/DataGrid/columns/DateTimeColumn.js.map +1 -1
  92. package/dist/components/DataGrid/columns/NumberColumn.d.ts +31 -0
  93. package/dist/components/DataGrid/columns/NumberColumn.d.ts.map +1 -0
  94. package/dist/components/DataGrid/columns/NumberColumn.js +27 -0
  95. package/dist/components/DataGrid/columns/NumberColumn.js.map +1 -0
  96. package/dist/components/DataGrid/components/ReorderColumnsButton.d.ts +1 -0
  97. package/dist/components/DataGrid/components/ReorderColumnsButton.d.ts.map +1 -1
  98. package/dist/components/DataGrid/components/ReorderColumnsButton.js +17 -16
  99. package/dist/components/DataGrid/components/ReorderColumnsButton.js.map +1 -1
  100. package/dist/components/DataGrid/components/ReorderColumnsDialog.d.ts +2 -0
  101. package/dist/components/DataGrid/components/ReorderColumnsDialog.d.ts.map +1 -1
  102. package/dist/components/DataGrid/components/ReorderColumnsDialog.js +104 -65
  103. package/dist/components/DataGrid/components/ReorderColumnsDialog.js.map +1 -1
  104. package/dist/components/DataGrid/useDataGridWebsocket.js +1 -1
  105. package/dist/components/DataGrid/useDataGridWebsocket.js.map +1 -1
  106. package/dist/components/DataGrid/utils/columnFactory.d.ts.map +1 -1
  107. package/dist/components/DataGrid/utils/columnFactory.js +55 -51
  108. package/dist/components/DataGrid/utils/columnFactory.js.map +1 -1
  109. package/dist/components/DataGrid/utils/computeDefaultColumnOrder.d.ts.map +1 -1
  110. package/dist/components/DataGrid/utils/computeDefaultColumnOrder.js +9 -8
  111. package/dist/components/DataGrid/utils/computeDefaultColumnOrder.js.map +1 -1
  112. package/dist/components/DatasetHosting/DatasetDownloadButton.d.ts +10 -5
  113. package/dist/components/DatasetHosting/DatasetDownloadButton.d.ts.map +1 -1
  114. package/dist/components/DatasetHosting/DatasetDownloadButton.js +66 -74
  115. package/dist/components/DatasetHosting/DatasetDownloadButton.js.map +1 -1
  116. package/dist/components/DatasetHosting/DatasetHosting.d.ts +6 -0
  117. package/dist/components/DatasetHosting/DatasetHosting.d.ts.map +1 -1
  118. package/dist/components/DatasetHosting/DatasetHosting.js +6 -0
  119. package/dist/components/DatasetHosting/DatasetHosting.js.map +1 -1
  120. package/dist/components/DatasetHosting/DatasetHostingAdornment.d.ts +15 -0
  121. package/dist/components/DatasetHosting/DatasetHostingAdornment.d.ts.map +1 -0
  122. package/dist/components/DatasetHosting/DatasetHostingAdornment.js +23 -0
  123. package/dist/components/DatasetHosting/DatasetHostingAdornment.js.map +1 -0
  124. package/dist/components/DatasetHosting/index.d.ts +2 -0
  125. package/dist/components/DatasetHosting/index.d.ts.map +1 -1
  126. package/dist/components/DatasetHosting/index.js +2 -1
  127. package/dist/components/DownloadCart/DownloadCartPage.d.ts.map +1 -1
  128. package/dist/components/DownloadCart/DownloadCartPage.js +1 -1
  129. package/dist/components/DownloadCart/DownloadCartPage.js.map +1 -1
  130. package/dist/components/DropdownSelect/DropdownSelect.d.ts.map +1 -1
  131. package/dist/components/DropdownSelect/DropdownSelect.js +1 -1
  132. package/dist/components/DropdownSelect/DropdownSelect.js.map +1 -1
  133. package/dist/components/EntityFinder/tree/EntityTree.d.ts.map +1 -1
  134. package/dist/components/EntityFinder/tree/EntityTree.js +1 -1
  135. package/dist/components/EntityFinder/tree/EntityTree.js.map +1 -1
  136. package/dist/components/EntityFinder/tree/VirtualizedTree.js +1 -1
  137. package/dist/components/EntityFinder/tree/VirtualizedTree.js.map +1 -1
  138. package/dist/components/FeaturedDataTabs/FacetPlotsCard.js +1 -1
  139. package/dist/components/FeaturedDataTabs/FacetPlotsCard.js.map +1 -1
  140. package/dist/components/GenericCard/TableRowGenericCard.d.ts.map +1 -1
  141. package/dist/components/GenericCard/TableRowGenericCard.js +176 -170
  142. package/dist/components/GenericCard/TableRowGenericCard.js.map +1 -1
  143. package/dist/components/JsonSchemaForm/CustomFormContext.d.ts +9 -0
  144. package/dist/components/JsonSchemaForm/CustomFormContext.d.ts.map +1 -1
  145. package/dist/components/JsonSchemaForm/JsonSchemaForm.d.ts.map +1 -1
  146. package/dist/components/JsonSchemaForm/JsonSchemaForm.js +2 -1
  147. package/dist/components/JsonSchemaForm/JsonSchemaForm.js.map +1 -1
  148. package/dist/components/JsonSchemaForm/templates/ArrayFieldTemplate.d.ts.map +1 -1
  149. package/dist/components/JsonSchemaForm/templates/ArrayFieldTemplate.js +1 -1
  150. package/dist/components/JsonSchemaForm/templates/ArrayFieldTemplate.js.map +1 -1
  151. package/dist/components/JsonSchemaForm/templates/FieldTemplate.d.ts.map +1 -1
  152. package/dist/components/JsonSchemaForm/templates/FieldTemplate.js +6 -6
  153. package/dist/components/JsonSchemaForm/templates/FieldTemplate.js.map +1 -1
  154. package/dist/components/JsonSchemaForm/widgets/DateWidget.d.ts +9 -0
  155. package/dist/components/JsonSchemaForm/widgets/DateWidget.d.ts.map +1 -0
  156. package/dist/components/JsonSchemaForm/widgets/DateWidget.js +23 -0
  157. package/dist/components/JsonSchemaForm/widgets/DateWidget.js.map +1 -0
  158. package/dist/components/MailchimpSubscribeSection/MailchimpSubscribeSection.css +1 -1
  159. package/dist/components/MailchimpSubscribeSection/MailchimpSubscribeSection.d.ts +3 -2
  160. package/dist/components/MailchimpSubscribeSection/MailchimpSubscribeSection.d.ts.map +1 -1
  161. package/dist/components/MailchimpSubscribeSection/MailchimpSubscribeSection.js +10 -12
  162. package/dist/components/MailchimpSubscribeSection/MailchimpSubscribeSection.js.map +1 -1
  163. package/dist/components/MailchimpSubscribeSection/MailchimpSubscribeSection.module.js +8 -7
  164. package/dist/components/MailchimpSubscribeSection/MailchimpSubscribeSection.module.js.map +1 -1
  165. package/dist/components/MailchimpSubscribeSection/MailchimpSubscribeSection.module.scss +12 -2
  166. package/dist/components/Markdown/MarkdownEditor.js +1 -1
  167. package/dist/components/Markdown/MarkdownEditor.js.map +1 -1
  168. package/dist/components/ProvenanceGraph/ProvenanceGraph.d.ts.map +1 -1
  169. package/dist/components/ProvenanceGraph/ProvenanceGraph.js +46 -46
  170. package/dist/components/ProvenanceGraph/ProvenanceGraph.js.map +1 -1
  171. package/dist/components/QueryBuilder/queryBuilderTranslation.js +1 -1
  172. package/dist/components/QueryBuilder/queryBuilderTranslation.js.map +1 -1
  173. package/dist/components/QueryWrapperPlotNav/LastUpdatedOn.js +1 -1
  174. package/dist/components/QueryWrapperPlotNav/LastUpdatedOn.js.map +1 -1
  175. package/dist/components/QueryWrapperPlotNav/QueryWrapperPlotNav.d.ts +1 -1
  176. package/dist/components/QueryWrapperPlotNav/QueryWrapperPlotNav.d.ts.map +1 -1
  177. package/dist/components/QueryWrapperPlotNav/QueryWrapperPlotNav.js +27 -25
  178. package/dist/components/QueryWrapperPlotNav/QueryWrapperPlotNav.js.map +1 -1
  179. package/dist/components/SchemaDrivenAnnotationEditor/AnnotationEditorUtils.d.ts +0 -9
  180. package/dist/components/SchemaDrivenAnnotationEditor/AnnotationEditorUtils.d.ts.map +1 -1
  181. package/dist/components/SchemaDrivenAnnotationEditor/AnnotationEditorUtils.js +23 -31
  182. package/dist/components/SchemaDrivenAnnotationEditor/AnnotationEditorUtils.js.map +1 -1
  183. package/dist/components/SchemaDrivenAnnotationEditor/SchemaDrivenAnnotationEditor.d.ts.map +1 -1
  184. package/dist/components/SchemaDrivenAnnotationEditor/SchemaDrivenAnnotationEditor.js +5 -4
  185. package/dist/components/SchemaDrivenAnnotationEditor/SchemaDrivenAnnotationEditor.js.map +1 -1
  186. package/dist/components/SchemaDrivenAnnotationEditor/field/SynapseAnnotationsRJSFObjectField.d.ts.map +1 -1
  187. package/dist/components/SchemaDrivenAnnotationEditor/field/SynapseAnnotationsRJSFObjectField.js +6 -5
  188. package/dist/components/SchemaDrivenAnnotationEditor/field/SynapseAnnotationsRJSFObjectField.js.map +1 -1
  189. package/dist/components/SearchQueryWrapper/SearchQueryUseQueryOptions.d.ts +2 -0
  190. package/dist/components/SearchQueryWrapper/SearchQueryUseQueryOptions.d.ts.map +1 -1
  191. package/dist/components/SearchQueryWrapper/SearchQueryUseQueryOptions.js +18 -13
  192. package/dist/components/SearchQueryWrapper/SearchQueryUseQueryOptions.js.map +1 -1
  193. package/dist/components/StatisticsPlot.d.ts.map +1 -1
  194. package/dist/components/StatisticsPlot.js +1 -1
  195. package/dist/components/StatisticsPlot.js.map +1 -1
  196. package/dist/components/SynapseForm/SynapseFormWrapper.js +1 -1
  197. package/dist/components/SynapseForm/SynapseFormWrapper.js.map +1 -1
  198. package/dist/components/SynapseHomepageV2/HotdropsAndNews.css +1 -1
  199. package/dist/components/SynapseHomepageV2/HotdropsAndNews.module.js +9 -9
  200. package/dist/components/SynapseHomepageV2/HotdropsAndNews.module.js.map +1 -1
  201. package/dist/components/SynapseHomepageV2/HotdropsAndNews.module.scss +14 -0
  202. package/dist/components/SynapseHomepageV2/SynapseHomepageChatSearch.js +1 -1
  203. package/dist/components/SynapseHomepageV2/SynapseHomepageChatSearch.js.map +1 -1
  204. package/dist/components/SynapseSearchPageResults/SynapseSearchPage.js +1 -1
  205. package/dist/components/SynapseSearchPageResults/SynapseSearchPage.js.map +1 -1
  206. package/dist/components/SynapseTable/SynapseTableRenderers.d.ts.map +1 -1
  207. package/dist/components/SynapseTable/SynapseTableRenderers.js +1 -1
  208. package/dist/components/SynapseTable/SynapseTableRenderers.js.map +1 -1
  209. package/dist/components/SynapseTable/TopLevelControls/TopLevelControls.d.ts +4 -0
  210. package/dist/components/SynapseTable/TopLevelControls/TopLevelControls.d.ts.map +1 -1
  211. package/dist/components/SynapseTable/TopLevelControls/TopLevelControls.js +71 -69
  212. package/dist/components/SynapseTable/TopLevelControls/TopLevelControls.js.map +1 -1
  213. package/dist/components/SynapseTable/table-top/DownloadOptions.d.ts +4 -0
  214. package/dist/components/SynapseTable/table-top/DownloadOptions.d.ts.map +1 -1
  215. package/dist/components/SynapseTable/table-top/DownloadOptions.js +14 -13
  216. package/dist/components/SynapseTable/table-top/DownloadOptions.js.map +1 -1
  217. package/dist/components/SynapseTable/usePrefetchTableData.js +1 -1
  218. package/dist/components/SynapseTable/usePrefetchTableData.js.map +1 -1
  219. package/dist/components/TableColumnSchemaEditor/TableColumnSchemaFormReducer.js +4 -4
  220. package/dist/components/TableColumnSchemaEditor/TableColumnSchemaFormReducer.js.map +1 -1
  221. package/dist/components/TanStackTable/TableCellRenderer.d.ts.map +1 -1
  222. package/dist/components/TanStackTable/TableCellRenderer.js +1 -1
  223. package/dist/components/TanStackTable/TableCellRenderer.js.map +1 -1
  224. package/dist/components/TermsAndConditions/TermsAndConditions.js +1 -1
  225. package/dist/components/TermsAndConditions/TermsAndConditions.js.map +1 -1
  226. package/dist/components/Webhook/CreateWebhookModal.d.ts.map +1 -1
  227. package/dist/components/Webhook/CreateWebhookModal.js +1 -1
  228. package/dist/components/Webhook/CreateWebhookModal.js.map +1 -1
  229. package/dist/components/dataaccess/UserAccessRequestHistory/InFlightEDucSignaturesTable.d.ts.map +1 -1
  230. package/dist/components/dataaccess/UserAccessRequestHistory/InFlightEDucSignaturesTable.js +172 -63
  231. package/dist/components/dataaccess/UserAccessRequestHistory/InFlightEDucSignaturesTable.js.map +1 -1
  232. package/dist/components/dataaccess/UserAccessRequestHistory/RouteConstants.d.ts +3 -0
  233. package/dist/components/dataaccess/UserAccessRequestHistory/RouteConstants.d.ts.map +1 -1
  234. package/dist/components/dataaccess/UserAccessRequestHistory/RouteConstants.js +2 -2
  235. package/dist/components/dataaccess/UserAccessRequestHistory/RouteConstants.js.map +1 -1
  236. package/dist/components/dataaccess/UserAccessRequestHistory/UserAccessRequestHistoryPage.d.ts.map +1 -1
  237. package/dist/components/dataaccess/UserAccessRequestHistory/UserAccessRequestHistoryPage.js +10 -8
  238. package/dist/components/dataaccess/UserAccessRequestHistory/UserAccessRequestHistoryPage.js.map +1 -1
  239. package/dist/components/dataaccess/UserAccessRequestHistory/UserAccessRequestHistoryPlace.d.ts.map +1 -1
  240. package/dist/components/dataaccess/UserAccessRequestHistory/UserAccessRequestHistoryPlace.js +74 -43
  241. package/dist/components/dataaccess/UserAccessRequestHistory/UserAccessRequestHistoryPlace.js.map +1 -1
  242. package/dist/components/dataaccess/UserAccessRequestHistory/UserAccessRequestHistoryTable.d.ts.map +1 -1
  243. package/dist/components/dataaccess/UserAccessRequestHistory/UserAccessRequestHistoryTable.js +2 -2
  244. package/dist/components/dataaccess/UserAccessRequestHistory/UserAccessRequestHistoryTable.js.map +1 -1
  245. package/dist/components/doi/CreateOrUpdateDoiModal.js +5 -5
  246. package/dist/components/doi/CreateOrUpdateDoiModal.js.map +1 -1
  247. package/dist/components/entity/metadata/EntityModal.js +1 -1
  248. package/dist/components/entity/metadata/EntityModal.js.map +1 -1
  249. package/dist/components/entity/page/action_menu/EntityActionMenu.js +2 -2
  250. package/dist/components/entity/page/action_menu/EntityActionMenu.js.map +1 -1
  251. package/dist/components/index.js +113 -112
  252. package/dist/components/menu/DropdownMenu.d.ts.map +1 -1
  253. package/dist/components/menu/DropdownMenu.js +1 -1
  254. package/dist/components/menu/DropdownMenu.js.map +1 -1
  255. package/dist/components/row_renderers/Dataset.js +1 -1
  256. package/dist/components/row_renderers/Dataset.js.map +1 -1
  257. package/dist/components/styled/LeftRightPanel.d.ts +8 -0
  258. package/dist/components/styled/LeftRightPanel.d.ts.map +1 -1
  259. package/dist/components/styled/LeftRightPanel.js +10 -1
  260. package/dist/components/styled/LeftRightPanel.js.map +1 -1
  261. package/dist/components/widgets/facet-nav/FacetNavPanel.js +1 -1
  262. package/dist/components/widgets/facet-nav/FacetNavPanel.js.map +1 -1
  263. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilter.d.ts.map +1 -1
  264. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilter.js +1 -1
  265. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilter.js.map +1 -1
  266. package/dist/components/widgets/query-filter/FacetFilterControls.js +1 -1
  267. package/dist/components/widgets/query-filter/FacetFilterControls.js.map +1 -1
  268. package/dist/features/entity/metadata-task/components/CreateOrUpdateCurationTaskDialog.d.ts.map +1 -1
  269. package/dist/features/entity/metadata-task/components/CreateOrUpdateCurationTaskDialog.js +1 -1
  270. package/dist/features/entity/metadata-task/components/CreateOrUpdateCurationTaskDialog.js.map +1 -1
  271. package/dist/index.js +174 -173
  272. package/dist/index.js.map +1 -1
  273. package/dist/mocks/msw/handlers/aridhiaHandlers.d.ts +73 -0
  274. package/dist/mocks/msw/handlers/aridhiaHandlers.d.ts.map +1 -0
  275. package/dist/mocks/msw/handlers/aridhiaHandlers.js +119 -0
  276. package/dist/mocks/msw/handlers/aridhiaHandlers.js.map +1 -0
  277. package/dist/mocks/msw/handlers/dataAccessRequestHandlers.js +1 -1
  278. package/dist/mocks/msw/handlers/dataAccessRequestHandlers.js.map +1 -1
  279. package/dist/mocks/msw/handlers/entityHandlers.d.ts.map +1 -1
  280. package/dist/mocks/msw/handlers/entityHandlers.js +4 -4
  281. package/dist/mocks/msw/handlers/entityHandlers.js.map +1 -1
  282. package/dist/mocks/msw/handlers/userProfileHandlers.js +2 -2
  283. package/dist/mocks/msw/handlers/userProfileHandlers.js.map +1 -1
  284. package/dist/mocks/msw/handlers.d.ts.map +1 -1
  285. package/dist/mocks/msw/handlers.js +72 -69
  286. package/dist/mocks/msw/handlers.js.map +1 -1
  287. package/dist/style/components/_terms-and-conditions.scss +25 -3
  288. package/dist/style/main.css +1 -1
  289. package/dist/testutils/RjsfFormTestUtils.js +12 -0
  290. package/dist/testutils/RjsfFormTestUtils.js.map +1 -0
  291. package/dist/tsconfig.build.tsbuildinfo +1 -1
  292. package/dist/utils/featureflag/FeatureFlags.d.ts +1 -0
  293. package/dist/utils/featureflag/FeatureFlags.d.ts.map +1 -1
  294. package/dist/utils/featureflag/FeatureFlags.js +1 -1
  295. package/dist/utils/featureflag/FeatureFlags.js.map +1 -1
  296. package/dist/utils/functions/QueryFilterUtils.js +1 -1
  297. package/dist/utils/functions/QueryFilterUtils.js.map +1 -1
  298. package/dist/utils/functions/SqlFunctions.js +1 -1
  299. package/dist/utils/functions/SqlFunctions.js.map +1 -1
  300. package/dist/utils/functions/queryUtils.js +1 -1
  301. package/dist/utils/functions/queryUtils.js.map +1 -1
  302. package/dist/utils/hooks/useDetectSSOCode.d.ts.map +1 -1
  303. package/dist/utils/hooks/useDetectSSOCode.js +1 -1
  304. package/dist/utils/hooks/useDetectSSOCode.js.map +1 -1
  305. package/dist/utils/hooks/useImmutableTableQuery/useImmutableTableQuery.js +1 -1
  306. package/dist/utils/hooks/useImmutableTableQuery/useImmutableTableQuery.js.map +1 -1
  307. package/dist/utils/jsonschema/SchemaAnnotationUtils.js +1 -1
  308. package/dist/utils/jsonschema/SchemaAnnotationUtils.js.map +1 -1
  309. package/dist/utils/jsonschema/collectTopLevelProperties.d.ts +22 -0
  310. package/dist/utils/jsonschema/collectTopLevelProperties.d.ts.map +1 -0
  311. package/dist/utils/jsonschema/collectTopLevelProperties.js +31 -0
  312. package/dist/utils/jsonschema/collectTopLevelProperties.js.map +1 -0
  313. package/dist/utils/jsonschema/getSchemaPropertyInfo.d.ts.map +1 -1
  314. package/dist/utils/jsonschema/getSchemaPropertyInfo.js +1 -1
  315. package/dist/utils/jsonschema/getSchemaPropertyInfo.js.map +1 -1
  316. package/package.json +4 -4
@@ -8,6 +8,7 @@ export declare enum FeatureFlagEnum {
8
8
  CURIE_CHAT_WIDGET = "CURIE_CHAT_WIDGET",
9
9
  CURATION_TASK_PAGE_SHOW_NEW_TASK_BUTTON = "CURATION_TASK_PAGE_SHOW_NEW_TASK_BUTTON",
10
10
  ELITE_PORTAL_MODELS = "ELITE_PORTAL_MODELS",
11
+ AMPALS_RDCA_DAP_FORM_ENABLED = "AMPALS_RDCA_DAP_FORM_ENABLED",
11
12
  TEST_ONLY = "TEST_ONLY"
12
13
  }
13
14
  //# sourceMappingURL=FeatureFlags.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"FeatureFlags.d.ts","sourceRoot":"","sources":["../../../src/utils/featureflag/FeatureFlags.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,eAAe,EAAE,OAAO,CAAC,CAAA;AAE3D,oBAAY,eAAe;IAEzB,oBAAoB,yBAAyB;IAG7C,gBAAgB,qBAAqB;IAGrC,WAAW,gBAAgB;IAG3B,UAAU,eAAe;IAGzB,WAAW,gBAAgB;IAG3B,iBAAiB,sBAAsB;IAGvC,uCAAuC,4CAA4C;IAGnF,mBAAmB,wBAAwB;IAG3C,SAAS,cAAc;CACxB"}
1
+ {"version":3,"file":"FeatureFlags.d.ts","sourceRoot":"","sources":["../../../src/utils/featureflag/FeatureFlags.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,eAAe,EAAE,OAAO,CAAC,CAAA;AAE3D,oBAAY,eAAe;IAEzB,oBAAoB,yBAAyB;IAG7C,gBAAgB,qBAAqB;IAGrC,WAAW,gBAAgB;IAG3B,UAAU,eAAe;IAGzB,WAAW,gBAAgB;IAG3B,iBAAiB,sBAAsB;IAGvC,uCAAuC,4CAA4C;IAGnF,mBAAmB,wBAAwB;IAG3C,4BAA4B,iCAAiC;IAG7D,SAAS,cAAc;CACxB"}
@@ -1,6 +1,6 @@
1
1
  //#region src/utils/featureflag/FeatureFlags.ts
2
2
  var e = /* @__PURE__ */ function(e) {
3
- return e.PORTAL_SEARCH_HEADER = "PORTAL_SEARCH_HEADER", e.HOMEPAGE_CHATBOT = "HOMEPAGE_CHATBOT", e.WEBHOOKS_UI = "WEBHOOKS_UI", e.CRISP_CHAT = "CRISP_CHAT", e.PORTAL_CHAT = "PORTAL_CHAT", e.CURIE_CHAT_WIDGET = "CURIE_CHAT_WIDGET", e.CURATION_TASK_PAGE_SHOW_NEW_TASK_BUTTON = "CURATION_TASK_PAGE_SHOW_NEW_TASK_BUTTON", e.ELITE_PORTAL_MODELS = "ELITE_PORTAL_MODELS", e.TEST_ONLY = "TEST_ONLY", e;
3
+ return e.PORTAL_SEARCH_HEADER = "PORTAL_SEARCH_HEADER", e.HOMEPAGE_CHATBOT = "HOMEPAGE_CHATBOT", e.WEBHOOKS_UI = "WEBHOOKS_UI", e.CRISP_CHAT = "CRISP_CHAT", e.PORTAL_CHAT = "PORTAL_CHAT", e.CURIE_CHAT_WIDGET = "CURIE_CHAT_WIDGET", e.CURATION_TASK_PAGE_SHOW_NEW_TASK_BUTTON = "CURATION_TASK_PAGE_SHOW_NEW_TASK_BUTTON", e.ELITE_PORTAL_MODELS = "ELITE_PORTAL_MODELS", e.AMPALS_RDCA_DAP_FORM_ENABLED = "AMPALS_RDCA_DAP_FORM_ENABLED", e.TEST_ONLY = "TEST_ONLY", e;
4
4
  }({});
5
5
  //#endregion
6
6
  export { e as FeatureFlagEnum };
@@ -1 +1 @@
1
- {"version":3,"file":"FeatureFlags.js","names":[],"sources":["../../../src/utils/featureflag/FeatureFlags.ts"],"sourcesContent":["export type FeatureFlags = Record<FeatureFlagEnum, boolean>\n\nexport enum FeatureFlagEnum {\n // If enabled, show the new header component that uses the HeaderSearchBox component\n PORTAL_SEARCH_HEADER = 'PORTAL_SEARCH_HEADER',\n\n // If enabled, show the chatbot entrypoint from the new Synapse Homepage\n HOMEPAGE_CHATBOT = 'HOMEPAGE_CHATBOT',\n\n // If enabled, account settings will link to a page to manage webhooks\n WEBHOOKS_UI = 'WEBHOOKS_UI',\n\n // If enabled, load the Crisp chat widget\n CRISP_CHAT = 'CRISP_CHAT',\n\n // If enabled, show the SynapseChat dialog in portals\n PORTAL_CHAT = 'PORTAL_CHAT',\n\n // If enabled, show the Curie launcher widget in portals\n CURIE_CHAT_WIDGET = 'CURIE_CHAT_WIDGET',\n\n // If enabled, shows a \"New Task\" button on the metadata tasks page\n CURATION_TASK_PAGE_SHOW_NEW_TASK_BUTTON = 'CURATION_TASK_PAGE_SHOW_NEW_TASK_BUTTON',\n\n // If enabled, show the Models section in the ELITE portal (nav item, Explore tab, and Search tab)\n ELITE_PORTAL_MODELS = 'ELITE_PORTAL_MODELS',\n\n // Reserved for unit tests. Not configured in Stack Builder; do not use in production code.\n TEST_ONLY = 'TEST_ONLY',\n}\n"],"mappings":";AAEA,IAAY,IAAL,yBAAA,GAAA;QAEL,EAAA,uBAAA,wBAGA,EAAA,mBAAA,oBAGA,EAAA,cAAA,eAGA,EAAA,aAAA,cAGA,EAAA,cAAA,eAGA,EAAA,oBAAA,qBAGA,EAAA,0CAAA,2CAGA,EAAA,sBAAA,uBAGA,EAAA,YAAA;AACF,EAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"FeatureFlags.js","names":[],"sources":["../../../src/utils/featureflag/FeatureFlags.ts"],"sourcesContent":["export type FeatureFlags = Record<FeatureFlagEnum, boolean>\n\nexport enum FeatureFlagEnum {\n // If enabled, show the new header component that uses the HeaderSearchBox component\n PORTAL_SEARCH_HEADER = 'PORTAL_SEARCH_HEADER',\n\n // If enabled, show the chatbot entrypoint from the new Synapse Homepage\n HOMEPAGE_CHATBOT = 'HOMEPAGE_CHATBOT',\n\n // If enabled, account settings will link to a page to manage webhooks\n WEBHOOKS_UI = 'WEBHOOKS_UI',\n\n // If enabled, load the Crisp chat widget\n CRISP_CHAT = 'CRISP_CHAT',\n\n // If enabled, show the SynapseChat dialog in portals\n PORTAL_CHAT = 'PORTAL_CHAT',\n\n // If enabled, show the Curie launcher widget in portals\n CURIE_CHAT_WIDGET = 'CURIE_CHAT_WIDGET',\n\n // If enabled, shows a \"New Task\" button on the metadata tasks page\n CURATION_TASK_PAGE_SHOW_NEW_TASK_BUTTON = 'CURATION_TASK_PAGE_SHOW_NEW_TASK_BUTTON',\n\n // If enabled, show the Models section in the ELITE portal (nav item, Explore tab, and Search tab)\n ELITE_PORTAL_MODELS = 'ELITE_PORTAL_MODELS',\n\n // If enabled, opens the RDCA-DAP data access request form when requesting access to an Aridhia dataset\n AMPALS_RDCA_DAP_FORM_ENABLED = 'AMPALS_RDCA_DAP_FORM_ENABLED',\n\n // Reserved for unit tests. Not configured in Stack Builder; do not use in production code.\n TEST_ONLY = 'TEST_ONLY',\n}\n"],"mappings":";AAEA,IAAY,IAAL,yBAAA,GAAA;QAEL,EAAA,uBAAA,wBAGA,EAAA,mBAAA,oBAGA,EAAA,cAAA,eAGA,EAAA,aAAA,cAGA,EAAA,cAAA,eAGA,EAAA,oBAAA,qBAGA,EAAA,0CAAA,2CAGA,EAAA,sBAAA,uBAGA,EAAA,+BAAA,gCAGA,EAAA,YAAA;AACF,EAAA,CAAA,CAAA"}
@@ -1,7 +1,7 @@
1
1
  import { ColumnSingleValueFilterOperator as e } from "@sage-bionetworks/synapse-types";
2
2
  //#region src/utils/functions/QueryFilterUtils.ts
3
3
  function t(t, n, r) {
4
- if (!t || t.length !== 1) throw Error("rowSelectionPrimaryKey must be defined and have length 1");
4
+ if (t?.length !== 1) throw Error("rowSelectionPrimaryKey must be defined and have length 1");
5
5
  let i = r.findIndex((e) => e.name === t[0]);
6
6
  return {
7
7
  concreteType: "org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter",
@@ -1 +1 @@
1
- {"version":3,"file":"QueryFilterUtils.js","names":[],"sources":["../../../src/utils/functions/QueryFilterUtils.ts"],"sourcesContent":["import {\n ColumnSingleValueFilterOperator,\n ColumnSingleValueQueryFilter,\n QueryFilter,\n Row,\n SelectColumn,\n} from '@sage-bionetworks/synapse-types'\n\n/**\n * Given a list of selected rows, return a QueryFilter that will only return those rows\n * @param primaryKeyColumnNames\n * @param selectedRows\n * @param selectColumns\n */\nexport function getPrimaryKeyINFilter(\n primaryKeyColumnNames: string[],\n selectedRows: Row[],\n selectColumns: SelectColumn[],\n): QueryFilter {\n if (!primaryKeyColumnNames || primaryKeyColumnNames.length !== 1) {\n // If the key is undefined, then the user should have never been able to apply a filter\n // TODO: Handling a composite key would be tricky since the QueryFilter API currently only allows you to specify one column\n throw new Error('rowSelectionPrimaryKey must be defined and have length 1')\n }\n // Apply a filter that should only return the selected rows\n const primaryKeyColumnIndex = selectColumns.findIndex(\n sc => sc.name === primaryKeyColumnNames[0],\n )\n const filter: ColumnSingleValueQueryFilter = {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n columnName: primaryKeyColumnNames[0],\n operator: ColumnSingleValueFilterOperator.IN,\n values: selectedRows.map(row => row.values[primaryKeyColumnIndex]!),\n }\n return filter\n}\n"],"mappings":";;AAcA,SAAgB,EACd,GACA,GACA,GACa;CACb,IAAI,CAAC,KAAyB,EAAsB,WAAW,GAG7D,MAAU,MAAM,0DAA0D;CAG5E,IAAM,IAAwB,EAAc,WAC1C,MAAM,EAAG,SAAS,EAAsB,EAC1C;CAQA,OAAO;EANL,cACE;EACF,YAAY,EAAsB;EAClC,UAAU,EAAgC;EAC1C,QAAQ,EAAa,KAAI,MAAO,EAAI,OAAO,EAAuB;CAE7D;AACT"}
1
+ {"version":3,"file":"QueryFilterUtils.js","names":[],"sources":["../../../src/utils/functions/QueryFilterUtils.ts"],"sourcesContent":["import {\n ColumnSingleValueFilterOperator,\n ColumnSingleValueQueryFilter,\n QueryFilter,\n Row,\n SelectColumn,\n} from '@sage-bionetworks/synapse-types'\n\n/**\n * Given a list of selected rows, return a QueryFilter that will only return those rows\n * @param primaryKeyColumnNames\n * @param selectedRows\n * @param selectColumns\n */\nexport function getPrimaryKeyINFilter(\n primaryKeyColumnNames: string[],\n selectedRows: Row[],\n selectColumns: SelectColumn[],\n): QueryFilter {\n if (primaryKeyColumnNames?.length !== 1) {\n // If the key is undefined, then the user should have never been able to apply a filter\n // TODO: Handling a composite key would be tricky since the QueryFilter API currently only allows you to specify one column\n throw new Error('rowSelectionPrimaryKey must be defined and have length 1')\n }\n // Apply a filter that should only return the selected rows\n const primaryKeyColumnIndex = selectColumns.findIndex(\n sc => sc.name === primaryKeyColumnNames[0],\n )\n const filter: ColumnSingleValueQueryFilter = {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n columnName: primaryKeyColumnNames[0],\n operator: ColumnSingleValueFilterOperator.IN,\n values: selectedRows.map(row => row.values[primaryKeyColumnIndex]!),\n }\n return filter\n}\n"],"mappings":";;AAcA,SAAgB,EACd,GACA,GACA,GACa;CACb,IAAI,GAAuB,WAAW,GAGpC,MAAU,MAAM,0DAA0D;CAG5E,IAAM,IAAwB,EAAc,WAC1C,MAAM,EAAG,SAAS,EAAsB,EAC1C;CAQA,OAAO;EANL,cACE;EACF,YAAY,EAAsB;EAClC,UAAU,EAAgC;EAC1C,QAAQ,EAAa,KAAI,MAAO,EAAI,OAAO,EAAuB;CAE7D;AACT"}
@@ -70,7 +70,7 @@ var s = (e, t) => `__${t ?? ""}_${e}`, c = "SEARCH_TERM", l = "SEARCH_ROLE", u =
70
70
  return l.length === 0 ? void 0 : l;
71
71
  }, p = (e) => {
72
72
  let t = e.match(/(from)\s+(syn)\d+/gi);
73
- return t && t[0] ? t[0].substr(5).trim() : "";
73
+ return t?.[0] ? t[0].substr(5).trim() : "";
74
74
  }, m = (e) => {
75
75
  let t = /from\s+(syn\d+)(?:\.(\d+))?/i.exec(e);
76
76
  return t ? {
@@ -1 +1 @@
1
- {"version":3,"file":"SqlFunctions.js","names":[],"sources":["../../../src/utils/functions/SqlFunctions.ts"],"sourcesContent":["import {\n ColumnModel,\n ColumnMultiValueFunction,\n ColumnMultiValueFunctionQueryFilter,\n ColumnSingleValueFilterOperator,\n ColumnSingleValueQueryFilter,\n QueryFilter,\n Row,\n SelectColumn,\n TextMatchesQueryFilter,\n} from '@sage-bionetworks/synapse-types'\nimport { SYNAPSE_ENTITY_ID_REGEX } from './RegularExpressions'\nimport { splitAndTrim } from './StringUtils'\n\nexport type SQLOperator =\n | ColumnSingleValueFilterOperator\n | ColumnMultiValueFunction\n\nconst WITHOUT_SYN_PREFIX = 3\nexport const QUERY_FILTERS_SESSION_STORAGE_KEY = (key: string) =>\n `${key}-temp-QueryFilter-array`\n\nexport function removePrefixIfSynId(value: string) {\n if (value.match(SYNAPSE_ENTITY_ID_REGEX)) {\n return value.substring(WITHOUT_SYN_PREFIX)\n }\n return value\n}\nexport const getIgnoredQueryFilterSearchParamKey = (\n key: string,\n namespace?: string,\n) => {\n return `__${namespace ?? ''}_${key}`\n}\n\n// Special search parameter key that will automatically apply a FTS search term to a Query Wrapper if present\nexport const SEARCH_TERM = 'SEARCH_TERM'\nexport const SEARCH_ROLE = 'SEARCH_ROLE'\n\n/** @deprecated Use SEARCH_TERM instead */\nexport const FTS_SEARCH_TERM = 'FTS_SEARCH_TERM'\n/** @deprecated Use SEARCH_ROLE instead */\nexport const FTS_SEARCH_ROLE = 'FTS_SEARCH_ROLE'\n\n/**\n * Look in sessionStorage for a set of QueryFilters to apply. In addition, given the search params,\n * generate a set of QueryFilters to narrow the query to view just related data.\n * May return null if a QueryFilter should not be added.\n * @param sql\n * @param searchParams\n * @param operator\n * @returns\n */\nexport const getAdditionalFilters = (\n searchParams?: Record<string, string>,\n operator: SQLOperator = ColumnSingleValueFilterOperator.LIKE,\n sessionStorageKey?: string,\n): QueryFilter[] | undefined => {\n const hasSessionStorage = typeof sessionStorage !== 'undefined'\n const sessionStorageQueryFiltersString =\n hasSessionStorage && sessionStorageKey\n ? sessionStorage.getItem(\n QUERY_FILTERS_SESSION_STORAGE_KEY(sessionStorageKey),\n )\n : undefined\n let additionalFilters: QueryFilter[] = []\n if (sessionStorageQueryFiltersString) {\n additionalFilters = JSON.parse(\n sessionStorageQueryFiltersString,\n ) as QueryFilter[]\n }\n if (searchParams) {\n const isQueryWrapperKey = (key: string) =>\n key.startsWith('qw') || key.startsWith('__')\n additionalFilters = additionalFilters.concat(\n Object.keys(searchParams || {})\n .filter(\n key =>\n !isQueryWrapperKey(key) &&\n searchParams[key] != undefined &&\n searchParams[key].trim() != '',\n )\n .map(key => {\n if (key == SEARCH_TERM || key == FTS_SEARCH_TERM) {\n const filter: TextMatchesQueryFilter = {\n concreteType:\n 'org.sagebionetworks.repo.model.table.TextMatchesQueryFilter',\n searchExpression: searchParams[key],\n }\n return filter\n }\n switch (operator) {\n case ColumnSingleValueFilterOperator.EQUAL:\n case ColumnSingleValueFilterOperator.NOT_EQUAL:\n case ColumnSingleValueFilterOperator.GREATER_THAN:\n case ColumnSingleValueFilterOperator.LESS_THAN:\n case ColumnSingleValueFilterOperator.GREATER_THAN_OR_EQUAL:\n case ColumnSingleValueFilterOperator.LESS_THAN_OR_EQUAL: {\n const filter: ColumnSingleValueQueryFilter = {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n columnName: key,\n operator: operator,\n values: [searchParams[key]],\n }\n return filter\n }\n case ColumnSingleValueFilterOperator.IN:\n case ColumnSingleValueFilterOperator.BETWEEN: {\n const filter: ColumnSingleValueQueryFilter = {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n columnName: key,\n operator: operator,\n values: splitAndTrim(searchParams[key]),\n }\n return filter\n }\n case ColumnSingleValueFilterOperator.IS_NULL:\n case ColumnSingleValueFilterOperator.IS_NOT_NULL: {\n const filter: ColumnSingleValueQueryFilter = {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n columnName: key,\n operator: operator,\n values: [],\n }\n return filter\n }\n case ColumnMultiValueFunction.HAS: {\n const filter: ColumnMultiValueFunctionQueryFilter = {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnMultiValueFunctionQueryFilter',\n columnName: key,\n function: operator,\n _function: operator,\n values: splitAndTrim(searchParams[key]),\n }\n return filter\n }\n case ColumnSingleValueFilterOperator.LIKE: {\n // If we use a LIKE statement with a synId the backend will look for a string with the first three\n // characters being 'syn', however, it stores synIds without 'syn', so the query will fail\n // The backend usually parses 'syn' out, but not with the LIKE clause since its expecting a regex, so we\n // parse this out. This will cause a bug if something matches the synId regex but is in free text.\n const filter: ColumnSingleValueQueryFilter = {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n columnName: key,\n operator: operator,\n // Add wildcards around the value\n values: [`%${removePrefixIfSynId(searchParams[key])}%`],\n }\n return filter\n }\n case ColumnMultiValueFunction.HAS_LIKE: {\n const filter: ColumnMultiValueFunctionQueryFilter = {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnMultiValueFunctionQueryFilter',\n columnName: key,\n function: operator,\n _function: operator,\n values: searchParams[key].split(',').map(param => {\n // Remove synId prefix for the same reasons as in the LIKE case\n return `%${removePrefixIfSynId(param)}%`\n }),\n }\n return filter\n }\n default:\n // Compile-time exhaustiveness guard; the log fires only if a new\n // operator is added to the union without a case here.\n operator satisfies never\n console.warn(\n `getAdditionalFilters: unrecognized SQL operator, skipping filter for key \"${key}\"`,\n { operator },\n )\n return undefined\n }\n })\n .filter(\n (\n f,\n ): f is\n | TextMatchesQueryFilter\n | ColumnSingleValueQueryFilter\n | ColumnMultiValueFunctionQueryFilter => f !== undefined,\n ),\n )\n }\n\n return additionalFilters.length === 0 ? undefined : additionalFilters\n}\n\n//parses synapse entity id from a sql query string\n//look for a pattern of 'from[some number of spaces]syn[somenumbers]` case insensitive\nexport const parseEntityIdFromSqlStatement = (sql: string): string => {\n const matches = sql.match(/(from)\\s+(syn)\\d+/gi)\n return matches && matches[0] ? matches[0].substr(5).trim() : ''\n}\n\nexport const parseEntityIdAndVersionFromSqlStatement = (\n sql: string,\n): { entityId?: string; versionNumber?: number } => {\n const regex = /from\\s+(syn\\d+)(?:\\.(\\d+))?/i\n const matches = regex.exec(sql)\n if (!matches) {\n return { entityId: undefined, versionNumber: undefined }\n }\n return {\n entityId: matches[1],\n versionNumber: matches[2] ? parseInt(matches[2]) : undefined,\n }\n}\n\nexport const resultToJson = (\n headerColumns: SelectColumn[],\n rowColumns: Row[],\n) => {\n const rows = rowColumns.map(row => row.values)\n const headers = headerColumns.map(column => column.name)\n return rows.map(row => {\n const obj: Record<string, string | null> = {}\n row.forEach((text, cellIndex) => {\n obj[headers[cellIndex]] = text\n })\n return obj\n })\n}\n\n/**\n * Finds the index of the given column name in the selectColumns or columnModels.\n *\n * @returns a non-negative integer if the column is found, or undefined if the column is not found\n * @param columnName\n * @param selectColumns\n * @param columnModels\n */\nexport const getColumnIndex = (\n columnName?: string,\n selectColumns?: SelectColumn[],\n columnModels?: ColumnModel[],\n): number | undefined => {\n if (!columnName) {\n return undefined\n }\n\n const lowerCaseColumnName = columnName.toLowerCase()\n\n if (selectColumns) {\n const findIndexResult = selectColumns.findIndex(\n el => el.name?.toLowerCase() === lowerCaseColumnName,\n )\n if (findIndexResult != -1) {\n return findIndexResult\n }\n }\n\n if (columnModels) {\n const findIndexResult = columnModels.findIndex(\n el => el.name?.toLowerCase() === lowerCaseColumnName,\n )\n if (findIndexResult !== -1) {\n return findIndexResult\n }\n }\n\n return undefined\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"SqlFunctions.js","names":[],"sources":["../../../src/utils/functions/SqlFunctions.ts"],"sourcesContent":["import {\n ColumnModel,\n ColumnMultiValueFunction,\n ColumnMultiValueFunctionQueryFilter,\n ColumnSingleValueFilterOperator,\n ColumnSingleValueQueryFilter,\n QueryFilter,\n Row,\n SelectColumn,\n TextMatchesQueryFilter,\n} from '@sage-bionetworks/synapse-types'\nimport { SYNAPSE_ENTITY_ID_REGEX } from './RegularExpressions'\nimport { splitAndTrim } from './StringUtils'\n\nexport type SQLOperator =\n | ColumnSingleValueFilterOperator\n | ColumnMultiValueFunction\n\nconst WITHOUT_SYN_PREFIX = 3\nexport const QUERY_FILTERS_SESSION_STORAGE_KEY = (key: string) =>\n `${key}-temp-QueryFilter-array`\n\nexport function removePrefixIfSynId(value: string) {\n if (value.match(SYNAPSE_ENTITY_ID_REGEX)) {\n return value.substring(WITHOUT_SYN_PREFIX)\n }\n return value\n}\nexport const getIgnoredQueryFilterSearchParamKey = (\n key: string,\n namespace?: string,\n) => {\n return `__${namespace ?? ''}_${key}`\n}\n\n// Special search parameter key that will automatically apply a FTS search term to a Query Wrapper if present\nexport const SEARCH_TERM = 'SEARCH_TERM'\nexport const SEARCH_ROLE = 'SEARCH_ROLE'\n\n/** @deprecated Use SEARCH_TERM instead */\nexport const FTS_SEARCH_TERM = 'FTS_SEARCH_TERM'\n/** @deprecated Use SEARCH_ROLE instead */\nexport const FTS_SEARCH_ROLE = 'FTS_SEARCH_ROLE'\n\n/**\n * Look in sessionStorage for a set of QueryFilters to apply. In addition, given the search params,\n * generate a set of QueryFilters to narrow the query to view just related data.\n * May return null if a QueryFilter should not be added.\n * @param sql\n * @param searchParams\n * @param operator\n * @returns\n */\nexport const getAdditionalFilters = (\n searchParams?: Record<string, string>,\n operator: SQLOperator = ColumnSingleValueFilterOperator.LIKE,\n sessionStorageKey?: string,\n): QueryFilter[] | undefined => {\n const hasSessionStorage = typeof sessionStorage !== 'undefined'\n const sessionStorageQueryFiltersString =\n hasSessionStorage && sessionStorageKey\n ? sessionStorage.getItem(\n QUERY_FILTERS_SESSION_STORAGE_KEY(sessionStorageKey),\n )\n : undefined\n let additionalFilters: QueryFilter[] = []\n if (sessionStorageQueryFiltersString) {\n additionalFilters = JSON.parse(\n sessionStorageQueryFiltersString,\n ) as QueryFilter[]\n }\n if (searchParams) {\n const isQueryWrapperKey = (key: string) =>\n key.startsWith('qw') || key.startsWith('__')\n additionalFilters = additionalFilters.concat(\n Object.keys(searchParams || {})\n .filter(\n key =>\n !isQueryWrapperKey(key) &&\n searchParams[key] != undefined &&\n searchParams[key].trim() != '',\n )\n .map(key => {\n if (key == SEARCH_TERM || key == FTS_SEARCH_TERM) {\n const filter: TextMatchesQueryFilter = {\n concreteType:\n 'org.sagebionetworks.repo.model.table.TextMatchesQueryFilter',\n searchExpression: searchParams[key],\n }\n return filter\n }\n switch (operator) {\n case ColumnSingleValueFilterOperator.EQUAL:\n case ColumnSingleValueFilterOperator.NOT_EQUAL:\n case ColumnSingleValueFilterOperator.GREATER_THAN:\n case ColumnSingleValueFilterOperator.LESS_THAN:\n case ColumnSingleValueFilterOperator.GREATER_THAN_OR_EQUAL:\n case ColumnSingleValueFilterOperator.LESS_THAN_OR_EQUAL: {\n const filter: ColumnSingleValueQueryFilter = {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n columnName: key,\n operator: operator,\n values: [searchParams[key]],\n }\n return filter\n }\n case ColumnSingleValueFilterOperator.IN:\n case ColumnSingleValueFilterOperator.BETWEEN: {\n const filter: ColumnSingleValueQueryFilter = {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n columnName: key,\n operator: operator,\n values: splitAndTrim(searchParams[key]),\n }\n return filter\n }\n case ColumnSingleValueFilterOperator.IS_NULL:\n case ColumnSingleValueFilterOperator.IS_NOT_NULL: {\n const filter: ColumnSingleValueQueryFilter = {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n columnName: key,\n operator: operator,\n values: [],\n }\n return filter\n }\n case ColumnMultiValueFunction.HAS: {\n const filter: ColumnMultiValueFunctionQueryFilter = {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnMultiValueFunctionQueryFilter',\n columnName: key,\n function: operator,\n _function: operator,\n values: splitAndTrim(searchParams[key]),\n }\n return filter\n }\n case ColumnSingleValueFilterOperator.LIKE: {\n // If we use a LIKE statement with a synId the backend will look for a string with the first three\n // characters being 'syn', however, it stores synIds without 'syn', so the query will fail\n // The backend usually parses 'syn' out, but not with the LIKE clause since its expecting a regex, so we\n // parse this out. This will cause a bug if something matches the synId regex but is in free text.\n const filter: ColumnSingleValueQueryFilter = {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n columnName: key,\n operator: operator,\n // Add wildcards around the value\n values: [`%${removePrefixIfSynId(searchParams[key])}%`],\n }\n return filter\n }\n case ColumnMultiValueFunction.HAS_LIKE: {\n const filter: ColumnMultiValueFunctionQueryFilter = {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnMultiValueFunctionQueryFilter',\n columnName: key,\n function: operator,\n _function: operator,\n values: searchParams[key].split(',').map(param => {\n // Remove synId prefix for the same reasons as in the LIKE case\n return `%${removePrefixIfSynId(param)}%`\n }),\n }\n return filter\n }\n default:\n // Compile-time exhaustiveness guard; the log fires only if a new\n // operator is added to the union without a case here.\n operator satisfies never\n console.warn(\n `getAdditionalFilters: unrecognized SQL operator, skipping filter for key \"${key}\"`,\n { operator },\n )\n return undefined\n }\n })\n .filter(\n (\n f,\n ): f is\n | TextMatchesQueryFilter\n | ColumnSingleValueQueryFilter\n | ColumnMultiValueFunctionQueryFilter => f !== undefined,\n ),\n )\n }\n\n return additionalFilters.length === 0 ? undefined : additionalFilters\n}\n\n//parses synapse entity id from a sql query string\n//look for a pattern of 'from[some number of spaces]syn[somenumbers]` case insensitive\nexport const parseEntityIdFromSqlStatement = (sql: string): string => {\n const matches = sql.match(/(from)\\s+(syn)\\d+/gi)\n return matches?.[0] ? matches[0].substr(5).trim() : ''\n}\n\nexport const parseEntityIdAndVersionFromSqlStatement = (\n sql: string,\n): { entityId?: string; versionNumber?: number } => {\n const regex = /from\\s+(syn\\d+)(?:\\.(\\d+))?/i\n const matches = regex.exec(sql)\n if (!matches) {\n return { entityId: undefined, versionNumber: undefined }\n }\n return {\n entityId: matches[1],\n versionNumber: matches[2] ? parseInt(matches[2]) : undefined,\n }\n}\n\nexport const resultToJson = (\n headerColumns: SelectColumn[],\n rowColumns: Row[],\n) => {\n const rows = rowColumns.map(row => row.values)\n const headers = headerColumns.map(column => column.name)\n return rows.map(row => {\n const obj: Record<string, string | null> = {}\n row.forEach((text, cellIndex) => {\n obj[headers[cellIndex]] = text\n })\n return obj\n })\n}\n\n/**\n * Finds the index of the given column name in the selectColumns or columnModels.\n *\n * @returns a non-negative integer if the column is found, or undefined if the column is not found\n * @param columnName\n * @param selectColumns\n * @param columnModels\n */\nexport const getColumnIndex = (\n columnName?: string,\n selectColumns?: SelectColumn[],\n columnModels?: ColumnModel[],\n): number | undefined => {\n if (!columnName) {\n return undefined\n }\n\n const lowerCaseColumnName = columnName.toLowerCase()\n\n if (selectColumns) {\n const findIndexResult = selectColumns.findIndex(\n el => el.name?.toLowerCase() === lowerCaseColumnName,\n )\n if (findIndexResult != -1) {\n return findIndexResult\n }\n }\n\n if (columnModels) {\n const findIndexResult = columnModels.findIndex(\n el => el.name?.toLowerCase() === lowerCaseColumnName,\n )\n if (findIndexResult !== -1) {\n return findIndexResult\n }\n }\n\n return undefined\n}\n"],"mappings":"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"}
@@ -38,7 +38,7 @@ function x(e) {
38
38
  }
39
39
  function S(e, t) {
40
40
  let n = t.find((t) => t.name === e.columnName);
41
- return e.jsonPath && n && n.jsonSubColumns && (n = n.jsonSubColumns.find((t) => t.jsonPath === e.jsonPath)), n;
41
+ return e.jsonPath && n?.jsonSubColumns && (n = n.jsonSubColumns.find((t) => t.jsonPath === e.jsonPath)), n;
42
42
  }
43
43
  function C(e, t) {
44
44
  return t?.find((t) => w(e, t));
@@ -1 +1 @@
1
- {"version":3,"file":"queryUtils.js","names":[],"sources":["../../../src/utils/functions/queryUtils.ts"],"sourcesContent":["import {\n isColumnMultiValueFunctionQueryFilter,\n isColumnSingleValueQueryFilter,\n LockedColumn,\n UniqueFacetIdentifier,\n} from '@/utils/types'\nimport {\n ColumnModel,\n ColumnTypeEnum,\n FacetColumnRequest,\n FacetColumnResult,\n JsonSubColumnModel,\n Query,\n QueryBundleRequest,\n QueryResultBundle,\n SelectColumn,\n Table,\n} from '@sage-bionetworks/synapse-types'\nimport { cloneDeep, isEqual, isEqualWith, isMatch, isNil } from 'lodash-es'\nimport * as SynapseConstants from '../SynapseConstants'\nimport { BUNDLE_MASK_QUERY_RESULTS } from '../SynapseConstants'\nimport {\n hasFilesInView,\n isDataset,\n isDatasetCollection,\n isEntityView,\n isFileView,\n} from './EntityTypeUtils'\n\n/**\n * Retrieve the index of a column using the column name\n * @param name the column name\n * @param result the QueryResultBundle containing the columns\n * @returns The index of the column, or -1 if the column doesn't exist in the result\n */\nexport const getFieldIndex = (name?: string, result?: QueryResultBundle) => {\n if (name == undefined) {\n return -1\n }\n return (\n result?.selectColumns?.findIndex(el => {\n return el.name === name\n }) ?? -1\n )\n}\n\n/**\n * Retrieve the index of a column using the header column name found inthe query results.\n * Ignores case.\n * @param name the column name\n * @param result the QueryResultBundle containing the columns\n * @returns The index of the column, or -1 if the column doesn't exist in the result\n */\nexport const getHeaderIndex = (\n name: string,\n result: QueryResultBundle | undefined,\n) => {\n const nameLowercase = name.toLowerCase()\n return (\n result?.queryResult?.queryResults.headers.findIndex(el => {\n return el.name.toLowerCase() === nameLowercase\n }) ?? -1\n )\n}\n\n/**\n * Returns the indices of the selectColumns with the specified type\n * @param columnType\n * @param selectColumns\n */\nexport function getTypeIndices(\n columnType: ColumnTypeEnum,\n selectColumns: SelectColumn[] = [],\n): number[] {\n return selectColumns.reduce((prev: number[], curr, index) => {\n if (curr.columnType === columnType) {\n return [...prev, index]\n }\n return prev\n }, [])\n}\n\nexport const hasFacetedSelectColumn = (\n facets?: FacetColumnResult[],\n selectColumns?: SelectColumn[],\n): boolean => {\n /**\n * Facets are available iff\n * * there is at least one facet AND\n * * each facet has a corresponding columnModel in the selectColumns AND\n * * each facets has a valid value other than the null/not set value\n */\n if (facets == null || selectColumns == null) {\n return false\n }\n\n if (facets.length === 0 || selectColumns.length === 0) {\n return false\n }\n\n const facetsWithValuesAndColumnModels = facets.filter(facet => {\n return (\n !isSingleNotSetValue(facet) &&\n selectColumns.find(model => model.name === facet.columnName)\n )\n })\n\n return facetsWithValuesAndColumnModels.length > 0\n}\n\nexport const isSingleNotSetValue = (facet: FacetColumnResult): boolean => {\n return (\n facet.facetType === 'enumeration' &&\n facet.facetValues.length == 1 &&\n facet.facetValues[0].value == SynapseConstants.VALUE_NOT_SET\n )\n}\n\n// TODO Instead of removing the facet from the data, the facet renderers should just be aware of what to hide\nexport function removeLockedColumnFromFacetData(\n data?: QueryResultBundle,\n lockedColumn?: LockedColumn,\n): QueryResultBundle | undefined {\n const lockedColumnName = lockedColumn?.columnName\n if (lockedColumnName && data) {\n // for details page, return data without the \"locked\" facet\n const dataCopy: QueryResultBundle = cloneDeep(data)\n const facets = dataCopy.facets?.filter(\n item => item.columnName.toLowerCase() !== lockedColumnName.toLowerCase(),\n )\n dataCopy.facets = facets\n return dataCopy\n } else {\n // for other pages, just return the data\n return data\n }\n}\n\n/**\n * Returns true iff the query has filters applied that can be reset.\n * This includes facet filters and additional filters that are not applied to a locked column.\n */\nexport function hasResettableFilters(\n query: Query,\n lockedColumn?: LockedColumn,\n): boolean {\n const hasFacetFilters =\n Array.isArray(query.selectedFacets) &&\n query.selectedFacets.filter(\n facet =>\n facet.columnName.toLowerCase() !==\n lockedColumn?.columnName?.toLowerCase(),\n ).length > 0\n const hasAdditionalFilters =\n Array.isArray(query.additionalFilters) &&\n query.additionalFilters.filter(queryFilter =>\n isColumnSingleValueQueryFilter(queryFilter) ||\n isColumnMultiValueFunctionQueryFilter(queryFilter)\n ? queryFilter.columnName.toLowerCase() !==\n lockedColumn?.columnName?.toLowerCase()\n : true,\n ).length > 0\n\n return hasFacetFilters || hasAdditionalFilters\n}\n\n/**\n * Returns true iff a table query can be added to the download list.\n * @param entity\n * @param entityColumnId\n */\nexport function canTableQueryBeAddedToDownloadList<T extends Table = Table>(\n entity?: T,\n entityColumnId?: string,\n) {\n const viewCannotIncludeFiles =\n // EntityViews without the file bit mask cannot contain files\n (entity && isEntityView(entity) && !hasFilesInView(entity)) ||\n // DatasetCollections cannot contain files\n (entity && isDatasetCollection(entity))\n\n if (viewCannotIncludeFiles) {\n return false\n }\n\n return Boolean(\n entityColumnId ||\n (entity &&\n ((isEntityView(entity) && isFileView(entity)) || isDataset(entity))),\n )\n}\n\n/**\n * Returns true if the queries necessarily return the same result set, i.e. if they have identical parameters other than\n * limit, offset, sort.\n *\n * Note that this does not query the actual tables, so this only captures the semantic equivalence of the queries.\n */\nexport function queryRequestsHaveSameTotalResults(\n request1: Query,\n request2: Query,\n) {\n const clone1 = cloneDeep(request1)\n delete clone1.limit\n delete clone1.offset\n delete clone1.sort\n const clone2 = cloneDeep(request2)\n delete clone2.limit\n delete clone2.offset\n delete clone2.sort\n return isEqualWith(clone1, clone2, (value1, value2) => {\n if (isNil(value1) && isNil(value2)) {\n // Consider all nil (e.g. undefined/null) values equal\n return true\n }\n return isEqual(value1, value2)\n })\n}\n\n/**\n * Remove null/empty values from the query parameters where an undefined value is equivalent.\n *\n * This will ensure a query object is as simple as possible for URL search parameters and also increases the\n * likelihood of a cache hit.\n * @param q\n */\nexport function removeEmptyQueryParams(q: Query) {\n const query = cloneDeep(q)\n\n if (query.limit == null) {\n delete query.limit\n }\n if (query.offset == null || query.offset == 0) {\n delete query.offset\n }\n\n if (query.sort == null || query.sort.length == 0) {\n delete query.sort\n }\n\n if (query.selectedFacets == null || query.selectedFacets.length == 0) {\n delete query.selectedFacets\n }\n\n if (query.additionalFilters == null || query.additionalFilters.length == 0) {\n delete query.additionalFilters\n }\n\n return query\n}\n\n/**\n * Given a FacetColumnResult and a set of ColumnModels, return the ColumnModel that\n * matches the FacetColumnResult.\n * @param facet\n * @param columnModels\n */\nexport function getCorrespondingColumnForFacet(\n facet: FacetColumnResult,\n columnModels: ColumnModel[],\n): ColumnModel | JsonSubColumnModel | undefined {\n let columnModel: ColumnModel | JsonSubColumnModel | undefined =\n columnModels.find(model => model.name === facet.columnName)\n if (facet.jsonPath && columnModel && columnModel.jsonSubColumns) {\n columnModel = columnModel.jsonSubColumns.find(\n cm => cm.jsonPath === facet.jsonPath,\n )\n }\n return columnModel\n}\n\n/**\n * Given a set of FacetColumnRequests, return the FacetColumnRequest that matches the given UniqueFacetIdentifier.\n * @param facetDefinition\n * @param selectedFacets\n */\nexport function getCorrespondingSelectedFacet(\n facetDefinition: UniqueFacetIdentifier,\n selectedFacets?: FacetColumnRequest[],\n): FacetColumnRequest | undefined {\n return selectedFacets?.find(selectedFacet =>\n facetObjectMatchesDefinition(facetDefinition, selectedFacet),\n )\n}\n\nexport function facetObjectMatchesDefinition(\n facetDefinition:\n | UniqueFacetIdentifier\n | FacetColumnRequest\n | FacetColumnResult,\n facetObject: UniqueFacetIdentifier | FacetColumnRequest | FacetColumnResult,\n) {\n return isMatch(\n {\n columnName: facetDefinition.columnName,\n jsonPath: facetDefinition.jsonPath,\n },\n { columnName: facetObject.columnName, jsonPath: facetObject.jsonPath },\n )\n}\n\nexport function partitionQueryBundleRequestIntoRowsAndMetadata(\n queryBundleRequest: QueryBundleRequest,\n): {\n rowDataRequest: QueryBundleRequest\n queryMetadataRequest: QueryBundleRequest\n} {\n const rowDataRequest: QueryBundleRequest = {\n ...queryBundleRequest,\n // Get just the rows (if they were originally requested)\n partMask: queryBundleRequest.partMask & BUNDLE_MASK_QUERY_RESULTS,\n }\n\n const queryMetadataRequest: QueryBundleRequest = {\n ...queryBundleRequest,\n query: {\n ...queryBundleRequest.query,\n // Remove query fields that don't affect the results.\n offset: undefined,\n limit: undefined,\n sort: undefined,\n },\n // Bitwise remove the query result flag from the mask\n partMask: queryBundleRequest.partMask & ~BUNDLE_MASK_QUERY_RESULTS,\n }\n\n return {\n rowDataRequest,\n queryMetadataRequest,\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"queryUtils.js","names":[],"sources":["../../../src/utils/functions/queryUtils.ts"],"sourcesContent":["import {\n isColumnMultiValueFunctionQueryFilter,\n isColumnSingleValueQueryFilter,\n LockedColumn,\n UniqueFacetIdentifier,\n} from '@/utils/types'\nimport {\n ColumnModel,\n ColumnTypeEnum,\n FacetColumnRequest,\n FacetColumnResult,\n JsonSubColumnModel,\n Query,\n QueryBundleRequest,\n QueryResultBundle,\n SelectColumn,\n Table,\n} from '@sage-bionetworks/synapse-types'\nimport { cloneDeep, isEqual, isEqualWith, isMatch, isNil } from 'lodash-es'\nimport * as SynapseConstants from '../SynapseConstants'\nimport { BUNDLE_MASK_QUERY_RESULTS } from '../SynapseConstants'\nimport {\n hasFilesInView,\n isDataset,\n isDatasetCollection,\n isEntityView,\n isFileView,\n} from './EntityTypeUtils'\n\n/**\n * Retrieve the index of a column using the column name\n * @param name the column name\n * @param result the QueryResultBundle containing the columns\n * @returns The index of the column, or -1 if the column doesn't exist in the result\n */\nexport const getFieldIndex = (name?: string, result?: QueryResultBundle) => {\n if (name == undefined) {\n return -1\n }\n return (\n result?.selectColumns?.findIndex(el => {\n return el.name === name\n }) ?? -1\n )\n}\n\n/**\n * Retrieve the index of a column using the header column name found inthe query results.\n * Ignores case.\n * @param name the column name\n * @param result the QueryResultBundle containing the columns\n * @returns The index of the column, or -1 if the column doesn't exist in the result\n */\nexport const getHeaderIndex = (\n name: string,\n result: QueryResultBundle | undefined,\n) => {\n const nameLowercase = name.toLowerCase()\n return (\n result?.queryResult?.queryResults.headers.findIndex(el => {\n return el.name.toLowerCase() === nameLowercase\n }) ?? -1\n )\n}\n\n/**\n * Returns the indices of the selectColumns with the specified type\n * @param columnType\n * @param selectColumns\n */\nexport function getTypeIndices(\n columnType: ColumnTypeEnum,\n selectColumns: SelectColumn[] = [],\n): number[] {\n return selectColumns.reduce((prev: number[], curr, index) => {\n if (curr.columnType === columnType) {\n return [...prev, index]\n }\n return prev\n }, [])\n}\n\nexport const hasFacetedSelectColumn = (\n facets?: FacetColumnResult[],\n selectColumns?: SelectColumn[],\n): boolean => {\n /**\n * Facets are available iff\n * * there is at least one facet AND\n * * each facet has a corresponding columnModel in the selectColumns AND\n * * each facets has a valid value other than the null/not set value\n */\n if (facets == null || selectColumns == null) {\n return false\n }\n\n if (facets.length === 0 || selectColumns.length === 0) {\n return false\n }\n\n const facetsWithValuesAndColumnModels = facets.filter(facet => {\n return (\n !isSingleNotSetValue(facet) &&\n selectColumns.find(model => model.name === facet.columnName)\n )\n })\n\n return facetsWithValuesAndColumnModels.length > 0\n}\n\nexport const isSingleNotSetValue = (facet: FacetColumnResult): boolean => {\n return (\n facet.facetType === 'enumeration' &&\n facet.facetValues.length == 1 &&\n facet.facetValues[0].value == SynapseConstants.VALUE_NOT_SET\n )\n}\n\n// TODO Instead of removing the facet from the data, the facet renderers should just be aware of what to hide\nexport function removeLockedColumnFromFacetData(\n data?: QueryResultBundle,\n lockedColumn?: LockedColumn,\n): QueryResultBundle | undefined {\n const lockedColumnName = lockedColumn?.columnName\n if (lockedColumnName && data) {\n // for details page, return data without the \"locked\" facet\n const dataCopy: QueryResultBundle = cloneDeep(data)\n const facets = dataCopy.facets?.filter(\n item => item.columnName.toLowerCase() !== lockedColumnName.toLowerCase(),\n )\n dataCopy.facets = facets\n return dataCopy\n } else {\n // for other pages, just return the data\n return data\n }\n}\n\n/**\n * Returns true iff the query has filters applied that can be reset.\n * This includes facet filters and additional filters that are not applied to a locked column.\n */\nexport function hasResettableFilters(\n query: Query,\n lockedColumn?: LockedColumn,\n): boolean {\n const hasFacetFilters =\n Array.isArray(query.selectedFacets) &&\n query.selectedFacets.filter(\n facet =>\n facet.columnName.toLowerCase() !==\n lockedColumn?.columnName?.toLowerCase(),\n ).length > 0\n const hasAdditionalFilters =\n Array.isArray(query.additionalFilters) &&\n query.additionalFilters.filter(queryFilter =>\n isColumnSingleValueQueryFilter(queryFilter) ||\n isColumnMultiValueFunctionQueryFilter(queryFilter)\n ? queryFilter.columnName.toLowerCase() !==\n lockedColumn?.columnName?.toLowerCase()\n : true,\n ).length > 0\n\n return hasFacetFilters || hasAdditionalFilters\n}\n\n/**\n * Returns true iff a table query can be added to the download list.\n * @param entity\n * @param entityColumnId\n */\nexport function canTableQueryBeAddedToDownloadList<T extends Table = Table>(\n entity?: T,\n entityColumnId?: string,\n) {\n const viewCannotIncludeFiles =\n // EntityViews without the file bit mask cannot contain files\n (entity && isEntityView(entity) && !hasFilesInView(entity)) ||\n // DatasetCollections cannot contain files\n (entity && isDatasetCollection(entity))\n\n if (viewCannotIncludeFiles) {\n return false\n }\n\n return Boolean(\n entityColumnId ||\n (entity &&\n ((isEntityView(entity) && isFileView(entity)) || isDataset(entity))),\n )\n}\n\n/**\n * Returns true if the queries necessarily return the same result set, i.e. if they have identical parameters other than\n * limit, offset, sort.\n *\n * Note that this does not query the actual tables, so this only captures the semantic equivalence of the queries.\n */\nexport function queryRequestsHaveSameTotalResults(\n request1: Query,\n request2: Query,\n) {\n const clone1 = cloneDeep(request1)\n delete clone1.limit\n delete clone1.offset\n delete clone1.sort\n const clone2 = cloneDeep(request2)\n delete clone2.limit\n delete clone2.offset\n delete clone2.sort\n return isEqualWith(clone1, clone2, (value1, value2) => {\n if (isNil(value1) && isNil(value2)) {\n // Consider all nil (e.g. undefined/null) values equal\n return true\n }\n return isEqual(value1, value2)\n })\n}\n\n/**\n * Remove null/empty values from the query parameters where an undefined value is equivalent.\n *\n * This will ensure a query object is as simple as possible for URL search parameters and also increases the\n * likelihood of a cache hit.\n * @param q\n */\nexport function removeEmptyQueryParams(q: Query) {\n const query = cloneDeep(q)\n\n if (query.limit == null) {\n delete query.limit\n }\n if (query.offset == null || query.offset == 0) {\n delete query.offset\n }\n\n if (query.sort == null || query.sort.length == 0) {\n delete query.sort\n }\n\n if (query.selectedFacets == null || query.selectedFacets.length == 0) {\n delete query.selectedFacets\n }\n\n if (query.additionalFilters == null || query.additionalFilters.length == 0) {\n delete query.additionalFilters\n }\n\n return query\n}\n\n/**\n * Given a FacetColumnResult and a set of ColumnModels, return the ColumnModel that\n * matches the FacetColumnResult.\n * @param facet\n * @param columnModels\n */\nexport function getCorrespondingColumnForFacet(\n facet: FacetColumnResult,\n columnModels: ColumnModel[],\n): ColumnModel | JsonSubColumnModel | undefined {\n let columnModel: ColumnModel | JsonSubColumnModel | undefined =\n columnModels.find(model => model.name === facet.columnName)\n if (facet.jsonPath && columnModel?.jsonSubColumns) {\n columnModel = columnModel.jsonSubColumns.find(\n cm => cm.jsonPath === facet.jsonPath,\n )\n }\n return columnModel\n}\n\n/**\n * Given a set of FacetColumnRequests, return the FacetColumnRequest that matches the given UniqueFacetIdentifier.\n * @param facetDefinition\n * @param selectedFacets\n */\nexport function getCorrespondingSelectedFacet(\n facetDefinition: UniqueFacetIdentifier,\n selectedFacets?: FacetColumnRequest[],\n): FacetColumnRequest | undefined {\n return selectedFacets?.find(selectedFacet =>\n facetObjectMatchesDefinition(facetDefinition, selectedFacet),\n )\n}\n\nexport function facetObjectMatchesDefinition(\n facetDefinition:\n | UniqueFacetIdentifier\n | FacetColumnRequest\n | FacetColumnResult,\n facetObject: UniqueFacetIdentifier | FacetColumnRequest | FacetColumnResult,\n) {\n return isMatch(\n {\n columnName: facetDefinition.columnName,\n jsonPath: facetDefinition.jsonPath,\n },\n { columnName: facetObject.columnName, jsonPath: facetObject.jsonPath },\n )\n}\n\nexport function partitionQueryBundleRequestIntoRowsAndMetadata(\n queryBundleRequest: QueryBundleRequest,\n): {\n rowDataRequest: QueryBundleRequest\n queryMetadataRequest: QueryBundleRequest\n} {\n const rowDataRequest: QueryBundleRequest = {\n ...queryBundleRequest,\n // Get just the rows (if they were originally requested)\n partMask: queryBundleRequest.partMask & BUNDLE_MASK_QUERY_RESULTS,\n }\n\n const queryMetadataRequest: QueryBundleRequest = {\n ...queryBundleRequest,\n query: {\n ...queryBundleRequest.query,\n // Remove query fields that don't affect the results.\n offset: undefined,\n limit: undefined,\n sort: undefined,\n },\n // Bitwise remove the query result flag from the mask\n partMask: queryBundleRequest.partMask & ~BUNDLE_MASK_QUERY_RESULTS,\n }\n\n return {\n rowDataRequest,\n queryMetadataRequest,\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"useDetectSSOCode.d.ts","sourceRoot":"","sources":["../../../src/utils/hooks/useDetectSSOCode.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,0BAA0B,EAAE,MAAM,8EAA8E,CAAA;AAyBzH,MAAM,MAAM,0BAA0B,GAAG;IAEvC,SAAS,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAA;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAA;IAChC,uBAAuB,CAAC,EAAE,CAAC,IAAI,EAAE,0BAA0B,KAAK,IAAI,CAAA;IACpE,gCAAgC,CAAC,EAAE,CACjC,IAAI,EAAE,0BAA0B,EAChC,sBAAsB,EAAE,MAAM,KAC3B,IAAI,CAAA;IACT,qBAAqB,EAAE,OAAO,CAAA;IAC9B,eAAe,EAAE,OAAO,CAAA;CACzB,CAAA;AAQD,MAAM,CAAC,OAAO,UAAU,gBAAgB,CACtC,IAAI,GAAE,uBAGL,GACA,0BAA0B,CA2N5B"}
1
+ {"version":3,"file":"useDetectSSOCode.d.ts","sourceRoot":"","sources":["../../../src/utils/hooks/useDetectSSOCode.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,0BAA0B,EAAE,MAAM,8EAA8E,CAAA;AAyBzH,MAAM,MAAM,0BAA0B,GAAG;IAEvC,SAAS,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAA;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAA;IAChC,uBAAuB,CAAC,EAAE,CAAC,IAAI,EAAE,0BAA0B,KAAK,IAAI,CAAA;IACpE,gCAAgC,CAAC,EAAE,CACjC,IAAI,EAAE,0BAA0B,EAChC,sBAAsB,EAAE,MAAM,KAC3B,IAAI,CAAA;IACT,qBAAqB,EAAE,OAAO,CAAA;IAC9B,eAAe,EAAE,OAAO,CAAA;CACzB,CAAA;AAQD,MAAM,CAAC,OAAO,UAAU,gBAAgB,CACtC,IAAI,GAAE,uBAGL,GACA,0BAA0B,CA0N5B"}
@@ -54,7 +54,7 @@ function h(h = {
54
54
  }).finally(() => j(!1));
55
55
  else if (t.GOOGLE == D || t.ORCID == D || t.ARCUS == D || t.SAGE_BIONETWORKS == D || t.NIH_RESEARCHER_AUTH_SERVICE == D) {
56
56
  let e = (e) => {
57
- e && ("accessToken" in e ? c(e.accessToken).then(_) : (b && b(e), k && k.twoFaResetToken && x && x(e, k.twoFaResetToken)));
57
+ e && ("accessToken" in e ? c(e.accessToken).then(_) : (b && b(e), k?.twoFaResetToken && x && x(e, k.twoFaResetToken)));
58
58
  }, r = (e) => {
59
59
  if (e.status === 404) {
60
60
  if (t.NIH_RESEARCHER_AUTH_SERVICE == D) {
@@ -1 +1 @@
1
- {"version":3,"file":"useDetectSSOCode.js","names":[],"sources":["../../../src/utils/hooks/useDetectSSOCode.ts"],"sourcesContent":["import {\n bindOAuthProviderToAccount,\n getRootURL,\n oAuthIdentityRequest,\n oAuthRegisterAccountStep2,\n oAuthSessionRequest,\n setAccessTokenCookie,\n} from '@/synapse-client'\nimport { OAuth2State } from '@/utils/types'\nimport { OAuthValidationRequestProviderEnum } from '@sage-bionetworks/synapse-client'\nimport { TwoFactorAuthErrorResponse } from '@sage-bionetworks/synapse-client/generated/models/TwoFactorAuthErrorResponse'\nimport { SynapseClientError } from '@sage-bionetworks/synapse-client/util/SynapseClientError'\nimport { LoginResponse } from '@sage-bionetworks/synapse-types'\nimport { useEffect, useMemo, useState } from 'react'\nimport { BackendDestinationEnum } from '../functions'\nimport { CSRF_TOKEN_STORAGE_KEY, OAUTH2_PROVIDERS } from '../SynapseConstants'\nimport { useOneSageURL } from './useOneSageURL'\n\nfunction safeLocalStorageGetItem(key: string): string | null {\n try {\n return localStorage.getItem(key)\n } catch (err) {\n console.warn(`Unable to read from localStorage: ${key}`, err)\n return null\n }\n}\n\nfunction safeLocalStorageRemoveItem(key: string): void {\n try {\n localStorage.removeItem(key)\n } catch (err) {\n console.warn(`Unable to remove from localStorage: ${key}`, err)\n }\n}\n\nexport type UseDetectSSOCodeReturnType = {\n /* true iff SSO login has occurred and the completion of the OAuth flow in Synapse is pending */\n isLoading: boolean\n}\n\nexport type UseDetectSSOCodeOptions = {\n onSignInComplete?: () => void\n registerAccountUrl?: string\n onError?: (err: unknown) => void\n onTwoFactorAuthRequired?: (resp: TwoFactorAuthErrorResponse) => void\n onTwoFactorAuthResetTokenPresent?: (\n resp: TwoFactorAuthErrorResponse,\n encodedTwoFaResetToken: string,\n ) => void\n isInitializingSession: boolean\n isAuthenticated: boolean\n}\n\n/*\n * During SSO login, the authorization provider (Google, ORCiD, ArcusBio Okta, ...) will send the user back to the portal with an authorization code,\n * which can be exchanged for a Synapse user session. This function should be called whenever the root App is initialized\n * (to look for this code parameter and complete the round-trip). If state is included, then we assume that this is being\n * used for account creation, where we pass the username through the process.\n */\nexport default function useDetectSSOCode(\n opts: UseDetectSSOCodeOptions = {\n isInitializingSession: true,\n isAuthenticated: false,\n },\n): UseDetectSSOCodeReturnType {\n const defaultRegisterAccountURL = useOneSageURL('/register1')\n\n const {\n onSignInComplete,\n registerAccountUrl = defaultRegisterAccountURL.toString(),\n onError,\n onTwoFactorAuthRequired,\n onTwoFactorAuthResetTokenPresent,\n isInitializingSession,\n isAuthenticated,\n } = opts\n const redirectURL = getRootURL()\n // 'code' handling (from SSO) should be preformed on the root page, and then redirect to original route.\n // Use 'http://localhost/' as a placeholder during SSR (no browser URL available).\n // Since there is no 'code' or 'provider' in this placeholder URL, the rest of the hook is a no-op.\n const fullUrl: URL = new URL(\n typeof window !== 'undefined' ? window.location.href : 'http://localhost/',\n )\n // in test environment the searchParams isn't defined\n const { searchParams } = fullUrl\n const code = searchParams?.get('code')\n const provider = searchParams?.get('provider')\n\n // If the URL contains a client_id and redirect_uri, then we are acting as an identity provider for an external OAuth client\n const isHandlingSynapseOAuthSignIn = Boolean(\n searchParams?.get('client_id') && searchParams?.get('redirect_uri'),\n )\n\n // If the Synapse user signed in with an external IdP, we may have passed data in the 'state' param\n // Parse it (if appropriate)\n const state: OAuth2State | null = useMemo(() => {\n // If we are acting as an OIDC identity provider, then we should not parse the state param -- it was sent to us, and we should return it untouched\n if (!isHandlingSynapseOAuthSignIn) {\n const encodedState = searchParams?.get('state')\n try {\n return encodedState\n ? (JSON.parse(decodeURIComponent(encodedState)) as OAuth2State)\n : null\n } catch (e) {\n console.error(\n 'Error parsing state param:\\n',\n e,\n '\\nEncoded value:\\n',\n encodedState,\n )\n }\n }\n return null\n }, [isHandlingSynapseOAuthSignIn, searchParams])\n\n const [isLoading, setIsLoading] = useState(!!(code && provider))\n\n useEffect(() => {\n if (!isInitializingSession) {\n if (code && provider) {\n if (!isHandlingSynapseOAuthSignIn) {\n const storedCsrfToken = safeLocalStorageGetItem(\n CSRF_TOKEN_STORAGE_KEY,\n )\n\n const expectedCsrfToken = state?.csrfToken ?? null\n const tokensMatch =\n typeof expectedCsrfToken === 'string' &&\n typeof storedCsrfToken === 'string' &&\n expectedCsrfToken === storedCsrfToken\n\n if (!tokensMatch) {\n safeLocalStorageRemoveItem(CSRF_TOKEN_STORAGE_KEY)\n console.error(\n 'Invalid or missing OAuth CSRF token detected. Aborting OAuth flow.',\n )\n if (onError) {\n onError('Invalid OAuth state. Please try signing in again.')\n }\n setIsLoading(false)\n return\n }\n\n safeLocalStorageRemoveItem(CSRF_TOKEN_STORAGE_KEY)\n }\n\n const redirectUrl = `${redirectURL}?provider=${provider}`\n\n //If user is already logged in, and the provider is ORCID, then try to bind this OAuth provider to the account.\n if (OAUTH2_PROVIDERS.ORCID == provider && isAuthenticated) {\n // now bind this to the user account\n const onFailure = (err: SynapseClientError) => {\n console.error('Error binding ORCiD to account: ', err)\n if (onError) {\n onError(err.reason)\n }\n }\n bindOAuthProviderToAccount(\n provider,\n code,\n redirectUrl,\n BackendDestinationEnum.REPO_ENDPOINT,\n )\n .then(onSignInComplete)\n .catch(onFailure)\n .finally(() => setIsLoading(false))\n } else if (\n OAUTH2_PROVIDERS.NIH_RESEARCHER_AUTH_SERVICE == provider &&\n isAuthenticated\n ) {\n // RAS does not provide an alias, so bind via the identity endpoint\n const onFailure = (err: SynapseClientError) => {\n console.error('Error binding NIH RAS identity to account: ', err)\n if (onError) {\n onError(err.reason)\n }\n }\n oAuthIdentityRequest(\n provider as OAuthValidationRequestProviderEnum,\n String(code),\n redirectUrl,\n )\n .then(onSignInComplete)\n .catch(onFailure)\n .finally(() => setIsLoading(false))\n } else if (\n OAUTH2_PROVIDERS.GOOGLE == provider ||\n OAUTH2_PROVIDERS.ORCID == provider ||\n OAUTH2_PROVIDERS.ARCUS == provider ||\n OAUTH2_PROVIDERS.SAGE_BIONETWORKS == provider ||\n OAUTH2_PROVIDERS.NIH_RESEARCHER_AUTH_SERVICE == provider\n ) {\n const onSuccess = (\n response: LoginResponse | TwoFactorAuthErrorResponse | null,\n ) => {\n if (response) {\n if ('accessToken' in response) {\n setAccessTokenCookie(response.accessToken).then(\n onSignInComplete,\n )\n } else {\n // The app will redirect or open a modal to handle a standard 2FA sign in\n if (onTwoFactorAuthRequired) {\n onTwoFactorAuthRequired(response)\n }\n if (\n // The user logged in with OAuth while attempting to disable 2FA using an emailed signed token\n state &&\n state.twoFaResetToken &&\n onTwoFactorAuthResetTokenPresent\n ) {\n // Let the app handle redirecting to the 2FA reset page\n onTwoFactorAuthResetTokenPresent(\n response,\n state.twoFaResetToken,\n )\n }\n }\n }\n }\n const onFailure = (err: SynapseClientError) => {\n if (err.status === 404) {\n if (OAUTH2_PROVIDERS.NIH_RESEARCHER_AUTH_SERVICE == provider) {\n // RAS cannot create a Synapse account (no alias). Surface an\n // explicit error instead of redirecting to registration.\n console.error(\n 'No Synapse account is linked to this NIH RAS identity: ',\n err,\n )\n if (onError) {\n onError(\n 'No Synapse account is linked to this NIH RAS identity. Sign in to Synapse and link your NIH RAS identity from your account settings.',\n )\n }\n return\n }\n // Synapse account not found, send to registration page\n window.location.replace(registerAccountUrl)\n }\n console.error('Error with account login: ', err)\n if (onError) {\n onError(err.reason)\n }\n }\n\n if (\n (OAUTH2_PROVIDERS.GOOGLE == provider ||\n OAUTH2_PROVIDERS.ARCUS == provider ||\n OAUTH2_PROVIDERS.SAGE_BIONETWORKS == provider) &&\n state?.registrationUsername\n ) {\n oAuthRegisterAccountStep2(\n state.registrationUsername,\n provider,\n code,\n redirectUrl,\n BackendDestinationEnum.REPO_ENDPOINT,\n )\n .then(onSuccess)\n .catch(onFailure)\n .finally(() => setIsLoading(false))\n } else {\n oAuthSessionRequest(\n provider,\n code,\n redirectUrl,\n BackendDestinationEnum.REPO_ENDPOINT,\n )\n .then(onSuccess)\n .catch(onFailure)\n .finally(() => setIsLoading(false))\n }\n } else {\n console.warn('Unknown SSO Provider: ', provider)\n setIsLoading(false)\n }\n }\n }\n // Intentionally only monitoring initialization of the session -- only running on mount after the session detection has completed since this uses URL params that come from a redirect\n // oxlint-disable-next-line react-hooks/exhaustive-deps\n }, [isInitializingSession])\n\n return { isLoading }\n}\n"],"mappings":";;;;;;;;AAkBA,SAAS,EAAwB,GAA4B;CAC3D,IAAI;EACF,OAAO,aAAa,QAAQ,CAAG;CACjC,SAAS,GAAK;EAEZ,OADA,QAAQ,KAAK,qCAAqC,KAAO,CAAG,GACrD;CACT;AACF;AAEA,SAAS,EAA2B,GAAmB;CACrD,IAAI;EACF,aAAa,WAAW,CAAG;CAC7B,SAAS,GAAK;EACZ,QAAQ,KAAK,uCAAuC,KAAO,CAAG;CAChE;AACF;AA0BA,SAAwB,EACtB,IAAgC;CAC9B,uBAAuB;CACvB,iBAAiB;AACnB,GAC4B;CAC5B,IAAM,IAA4B,EAAc,YAAY,GAEtD,EACJ,qBACA,wBAAqB,EAA0B,SAAS,GACxD,YACA,4BACA,qCACA,0BACA,uBACE,GACE,IAAc,EAAW,GAQzB,EAAE,oBAAiB,IAJA,IACvB,OAAO,SAAW,MAAc,OAAO,SAAS,OAAO,mBAGhC,GACnB,IAAO,GAAc,IAAI,MAAM,GAC/B,IAAW,GAAc,IAAI,UAAU,GAGvC,IAA+B,GACnC,GAAc,IAAI,WAAW,KAAK,GAAc,IAAI,cAAc,IAK9D,IAA4B,QAAc;EAE9C,IAAI,CAAC,GAA8B;GACjC,IAAM,IAAe,GAAc,IAAI,OAAO;GAC9C,IAAI;IACF,OAAO,IACF,KAAK,MAAM,mBAAmB,CAAY,CAAC,IAC5C;GACN,SAAS,GAAG;IACV,QAAQ,MACN,gCACA,GACA,sBACA,CACF;GACF;EACF;EACA,OAAO;CACT,GAAG,CAAC,GAA8B,CAAY,CAAC,GAEzC,CAAC,GAAW,KAAgB,EAAS,CAAC,EAAE,KAAQ,EAAS;CAuK/D,OArKA,QAAgB;EACd,IAAI,CAAC,KACC,KAAQ,GAAU;GACpB,IAAI,CAAC,GAA8B;IACjC,IAAM,IAAkB,EACtB,CACF,GAEM,IAAoB,GAAO,aAAa;IAM9C,IAAI,EAJF,OAAO,KAAsB,YAC7B,OAAO,KAAoB,YAC3B,MAAsB,IAEN;KAQhB,AAPA,EAA2B,CAAsB,GACjD,QAAQ,MACN,oEACF,GACI,KACF,EAAQ,mDAAmD,GAE7D,EAAa,EAAK;KAClB;IACF;IAEA,EAA2B,CAAsB;GACnD;GAEA,IAAM,IAAc,GAAG,EAAY,YAAY;GAG/C,IAAI,EAAiB,SAAS,KAAY,GAQxC,EACE,GACA,GACA,GACA,EAAuB,aACzB,EACG,KAAK,CAAgB,EACrB,OAbgB,MAA4B;IAE7C,AADA,QAAQ,MAAM,oCAAoC,CAAG,GACjD,KACF,EAAQ,EAAI,MAAM;GAEtB,CAQkB,EACf,cAAc,EAAa,EAAK,CAAC;QAC/B,IACL,EAAiB,+BAA+B,KAChD,GASA,EACE,GACA,OAAO,CAAI,GACX,CACF,EACG,KAAK,CAAgB,EACrB,OAZgB,MAA4B;IAE7C,AADA,QAAQ,MAAM,+CAA+C,CAAG,GAC5D,KACF,EAAQ,EAAI,MAAM;GAEtB,CAOkB,EACf,cAAc,EAAa,EAAK,CAAC;QAC/B,IACL,EAAiB,UAAU,KAC3B,EAAiB,SAAS,KAC1B,EAAiB,SAAS,KAC1B,EAAiB,oBAAoB,KACrC,EAAiB,+BAA+B,GAChD;IACA,IAAM,KACJ,MACG;KACH,AAAI,MACE,iBAAiB,IACnB,EAAqB,EAAS,WAAW,EAAE,KACzC,CACF,KAGI,KACF,EAAwB,CAAQ,GAIhC,KACA,EAAM,mBACN,KAGA,EACE,GACA,EAAM,eACR;IAIR,GACM,KAAa,MAA4B;KAC7C,IAAI,EAAI,WAAW,KAAK;MACtB,IAAI,EAAiB,+BAA+B,GAAU;OAO5D,AAJA,QAAQ,MACN,2DACA,CACF,GACI,KACF,EACE,sIACF;OAEF;MACF;MAEA,OAAO,SAAS,QAAQ,CAAkB;KAC5C;KAEA,AADA,QAAQ,MAAM,8BAA8B,CAAG,GAC3C,KACF,EAAQ,EAAI,MAAM;IAEtB;IAEA,CACG,EAAiB,UAAU,KAC1B,EAAiB,SAAS,KAC1B,EAAiB,oBAAoB,MACvC,GAAO,uBAEP,EACE,EAAM,sBACN,GACA,GACA,GACA,EAAuB,aACzB,EACG,KAAK,CAAS,EACd,MAAM,CAAS,EACf,cAAc,EAAa,EAAK,CAAC,IAEpC,EACE,GACA,GACA,GACA,EAAuB,aACzB,EACG,KAAK,CAAS,EACd,MAAM,CAAS,EACf,cAAc,EAAa,EAAK,CAAC;GAExC,OAEE,AADA,QAAQ,KAAK,0BAA0B,CAAQ,GAC/C,EAAa,EAAK;EAEtB;CAIJ,GAAG,CAAC,CAAqB,CAAC,GAEnB,EAAE,aAAU;AACrB"}
1
+ {"version":3,"file":"useDetectSSOCode.js","names":[],"sources":["../../../src/utils/hooks/useDetectSSOCode.ts"],"sourcesContent":["import {\n bindOAuthProviderToAccount,\n getRootURL,\n oAuthIdentityRequest,\n oAuthRegisterAccountStep2,\n oAuthSessionRequest,\n setAccessTokenCookie,\n} from '@/synapse-client'\nimport { OAuth2State } from '@/utils/types'\nimport { OAuthValidationRequestProviderEnum } from '@sage-bionetworks/synapse-client'\nimport { TwoFactorAuthErrorResponse } from '@sage-bionetworks/synapse-client/generated/models/TwoFactorAuthErrorResponse'\nimport { SynapseClientError } from '@sage-bionetworks/synapse-client/util/SynapseClientError'\nimport { LoginResponse } from '@sage-bionetworks/synapse-types'\nimport { useEffect, useMemo, useState } from 'react'\nimport { BackendDestinationEnum } from '../functions'\nimport { CSRF_TOKEN_STORAGE_KEY, OAUTH2_PROVIDERS } from '../SynapseConstants'\nimport { useOneSageURL } from './useOneSageURL'\n\nfunction safeLocalStorageGetItem(key: string): string | null {\n try {\n return localStorage.getItem(key)\n } catch (err) {\n console.warn(`Unable to read from localStorage: ${key}`, err)\n return null\n }\n}\n\nfunction safeLocalStorageRemoveItem(key: string): void {\n try {\n localStorage.removeItem(key)\n } catch (err) {\n console.warn(`Unable to remove from localStorage: ${key}`, err)\n }\n}\n\nexport type UseDetectSSOCodeReturnType = {\n /* true iff SSO login has occurred and the completion of the OAuth flow in Synapse is pending */\n isLoading: boolean\n}\n\nexport type UseDetectSSOCodeOptions = {\n onSignInComplete?: () => void\n registerAccountUrl?: string\n onError?: (err: unknown) => void\n onTwoFactorAuthRequired?: (resp: TwoFactorAuthErrorResponse) => void\n onTwoFactorAuthResetTokenPresent?: (\n resp: TwoFactorAuthErrorResponse,\n encodedTwoFaResetToken: string,\n ) => void\n isInitializingSession: boolean\n isAuthenticated: boolean\n}\n\n/*\n * During SSO login, the authorization provider (Google, ORCiD, ArcusBio Okta, ...) will send the user back to the portal with an authorization code,\n * which can be exchanged for a Synapse user session. This function should be called whenever the root App is initialized\n * (to look for this code parameter and complete the round-trip). If state is included, then we assume that this is being\n * used for account creation, where we pass the username through the process.\n */\nexport default function useDetectSSOCode(\n opts: UseDetectSSOCodeOptions = {\n isInitializingSession: true,\n isAuthenticated: false,\n },\n): UseDetectSSOCodeReturnType {\n const defaultRegisterAccountURL = useOneSageURL('/register1')\n\n const {\n onSignInComplete,\n registerAccountUrl = defaultRegisterAccountURL.toString(),\n onError,\n onTwoFactorAuthRequired,\n onTwoFactorAuthResetTokenPresent,\n isInitializingSession,\n isAuthenticated,\n } = opts\n const redirectURL = getRootURL()\n // 'code' handling (from SSO) should be preformed on the root page, and then redirect to original route.\n // Use 'http://localhost/' as a placeholder during SSR (no browser URL available).\n // Since there is no 'code' or 'provider' in this placeholder URL, the rest of the hook is a no-op.\n const fullUrl: URL = new URL(\n typeof window !== 'undefined' ? window.location.href : 'http://localhost/',\n )\n // in test environment the searchParams isn't defined\n const { searchParams } = fullUrl\n const code = searchParams?.get('code')\n const provider = searchParams?.get('provider')\n\n // If the URL contains a client_id and redirect_uri, then we are acting as an identity provider for an external OAuth client\n const isHandlingSynapseOAuthSignIn = Boolean(\n searchParams?.get('client_id') && searchParams?.get('redirect_uri'),\n )\n\n // If the Synapse user signed in with an external IdP, we may have passed data in the 'state' param\n // Parse it (if appropriate)\n const state: OAuth2State | null = useMemo(() => {\n // If we are acting as an OIDC identity provider, then we should not parse the state param -- it was sent to us, and we should return it untouched\n if (!isHandlingSynapseOAuthSignIn) {\n const encodedState = searchParams?.get('state')\n try {\n return encodedState\n ? (JSON.parse(decodeURIComponent(encodedState)) as OAuth2State)\n : null\n } catch (e) {\n console.error(\n 'Error parsing state param:\\n',\n e,\n '\\nEncoded value:\\n',\n encodedState,\n )\n }\n }\n return null\n }, [isHandlingSynapseOAuthSignIn, searchParams])\n\n const [isLoading, setIsLoading] = useState(!!(code && provider))\n\n useEffect(() => {\n if (!isInitializingSession) {\n if (code && provider) {\n if (!isHandlingSynapseOAuthSignIn) {\n const storedCsrfToken = safeLocalStorageGetItem(\n CSRF_TOKEN_STORAGE_KEY,\n )\n\n const expectedCsrfToken = state?.csrfToken ?? null\n const tokensMatch =\n typeof expectedCsrfToken === 'string' &&\n typeof storedCsrfToken === 'string' &&\n expectedCsrfToken === storedCsrfToken\n\n if (!tokensMatch) {\n safeLocalStorageRemoveItem(CSRF_TOKEN_STORAGE_KEY)\n console.error(\n 'Invalid or missing OAuth CSRF token detected. Aborting OAuth flow.',\n )\n if (onError) {\n onError('Invalid OAuth state. Please try signing in again.')\n }\n setIsLoading(false)\n return\n }\n\n safeLocalStorageRemoveItem(CSRF_TOKEN_STORAGE_KEY)\n }\n\n const redirectUrl = `${redirectURL}?provider=${provider}`\n\n //If user is already logged in, and the provider is ORCID, then try to bind this OAuth provider to the account.\n if (OAUTH2_PROVIDERS.ORCID == provider && isAuthenticated) {\n // now bind this to the user account\n const onFailure = (err: SynapseClientError) => {\n console.error('Error binding ORCiD to account: ', err)\n if (onError) {\n onError(err.reason)\n }\n }\n bindOAuthProviderToAccount(\n provider,\n code,\n redirectUrl,\n BackendDestinationEnum.REPO_ENDPOINT,\n )\n .then(onSignInComplete)\n .catch(onFailure)\n .finally(() => setIsLoading(false))\n } else if (\n OAUTH2_PROVIDERS.NIH_RESEARCHER_AUTH_SERVICE == provider &&\n isAuthenticated\n ) {\n // RAS does not provide an alias, so bind via the identity endpoint\n const onFailure = (err: SynapseClientError) => {\n console.error('Error binding NIH RAS identity to account: ', err)\n if (onError) {\n onError(err.reason)\n }\n }\n oAuthIdentityRequest(\n provider as OAuthValidationRequestProviderEnum,\n String(code),\n redirectUrl,\n )\n .then(onSignInComplete)\n .catch(onFailure)\n .finally(() => setIsLoading(false))\n } else if (\n OAUTH2_PROVIDERS.GOOGLE == provider ||\n OAUTH2_PROVIDERS.ORCID == provider ||\n OAUTH2_PROVIDERS.ARCUS == provider ||\n OAUTH2_PROVIDERS.SAGE_BIONETWORKS == provider ||\n OAUTH2_PROVIDERS.NIH_RESEARCHER_AUTH_SERVICE == provider\n ) {\n const onSuccess = (\n response: LoginResponse | TwoFactorAuthErrorResponse | null,\n ) => {\n if (response) {\n if ('accessToken' in response) {\n setAccessTokenCookie(response.accessToken).then(\n onSignInComplete,\n )\n } else {\n // The app will redirect or open a modal to handle a standard 2FA sign in\n if (onTwoFactorAuthRequired) {\n onTwoFactorAuthRequired(response)\n }\n if (\n // The user logged in with OAuth while attempting to disable 2FA using an emailed signed token\n state?.twoFaResetToken &&\n onTwoFactorAuthResetTokenPresent\n ) {\n // Let the app handle redirecting to the 2FA reset page\n onTwoFactorAuthResetTokenPresent(\n response,\n state.twoFaResetToken,\n )\n }\n }\n }\n }\n const onFailure = (err: SynapseClientError) => {\n if (err.status === 404) {\n if (OAUTH2_PROVIDERS.NIH_RESEARCHER_AUTH_SERVICE == provider) {\n // RAS cannot create a Synapse account (no alias). Surface an\n // explicit error instead of redirecting to registration.\n console.error(\n 'No Synapse account is linked to this NIH RAS identity: ',\n err,\n )\n if (onError) {\n onError(\n 'No Synapse account is linked to this NIH RAS identity. Sign in to Synapse and link your NIH RAS identity from your account settings.',\n )\n }\n return\n }\n // Synapse account not found, send to registration page\n window.location.replace(registerAccountUrl)\n }\n console.error('Error with account login: ', err)\n if (onError) {\n onError(err.reason)\n }\n }\n\n if (\n (OAUTH2_PROVIDERS.GOOGLE == provider ||\n OAUTH2_PROVIDERS.ARCUS == provider ||\n OAUTH2_PROVIDERS.SAGE_BIONETWORKS == provider) &&\n state?.registrationUsername\n ) {\n oAuthRegisterAccountStep2(\n state.registrationUsername,\n provider,\n code,\n redirectUrl,\n BackendDestinationEnum.REPO_ENDPOINT,\n )\n .then(onSuccess)\n .catch(onFailure)\n .finally(() => setIsLoading(false))\n } else {\n oAuthSessionRequest(\n provider,\n code,\n redirectUrl,\n BackendDestinationEnum.REPO_ENDPOINT,\n )\n .then(onSuccess)\n .catch(onFailure)\n .finally(() => setIsLoading(false))\n }\n } else {\n console.warn('Unknown SSO Provider: ', provider)\n setIsLoading(false)\n }\n }\n }\n // Intentionally only monitoring initialization of the session -- only running on mount after the session detection has completed since this uses URL params that come from a redirect\n // oxlint-disable-next-line react-hooks/exhaustive-deps\n }, [isInitializingSession])\n\n return { isLoading }\n}\n"],"mappings":";;;;;;;;AAkBA,SAAS,EAAwB,GAA4B;CAC3D,IAAI;EACF,OAAO,aAAa,QAAQ,CAAG;CACjC,SAAS,GAAK;EAEZ,OADA,QAAQ,KAAK,qCAAqC,KAAO,CAAG,GACrD;CACT;AACF;AAEA,SAAS,EAA2B,GAAmB;CACrD,IAAI;EACF,aAAa,WAAW,CAAG;CAC7B,SAAS,GAAK;EACZ,QAAQ,KAAK,uCAAuC,KAAO,CAAG;CAChE;AACF;AA0BA,SAAwB,EACtB,IAAgC;CAC9B,uBAAuB;CACvB,iBAAiB;AACnB,GAC4B;CAC5B,IAAM,IAA4B,EAAc,YAAY,GAEtD,EACJ,qBACA,wBAAqB,EAA0B,SAAS,GACxD,YACA,4BACA,qCACA,0BACA,uBACE,GACE,IAAc,EAAW,GAQzB,EAAE,oBAAiB,IAJA,IACvB,OAAO,SAAW,MAAc,OAAO,SAAS,OAAO,mBAGhC,GACnB,IAAO,GAAc,IAAI,MAAM,GAC/B,IAAW,GAAc,IAAI,UAAU,GAGvC,IAA+B,GACnC,GAAc,IAAI,WAAW,KAAK,GAAc,IAAI,cAAc,IAK9D,IAA4B,QAAc;EAE9C,IAAI,CAAC,GAA8B;GACjC,IAAM,IAAe,GAAc,IAAI,OAAO;GAC9C,IAAI;IACF,OAAO,IACF,KAAK,MAAM,mBAAmB,CAAY,CAAC,IAC5C;GACN,SAAS,GAAG;IACV,QAAQ,MACN,gCACA,GACA,sBACA,CACF;GACF;EACF;EACA,OAAO;CACT,GAAG,CAAC,GAA8B,CAAY,CAAC,GAEzC,CAAC,GAAW,KAAgB,EAAS,CAAC,EAAE,KAAQ,EAAS;CAsK/D,OApKA,QAAgB;EACd,IAAI,CAAC,KACC,KAAQ,GAAU;GACpB,IAAI,CAAC,GAA8B;IACjC,IAAM,IAAkB,EACtB,CACF,GAEM,IAAoB,GAAO,aAAa;IAM9C,IAAI,EAJF,OAAO,KAAsB,YAC7B,OAAO,KAAoB,YAC3B,MAAsB,IAEN;KAQhB,AAPA,EAA2B,CAAsB,GACjD,QAAQ,MACN,oEACF,GACI,KACF,EAAQ,mDAAmD,GAE7D,EAAa,EAAK;KAClB;IACF;IAEA,EAA2B,CAAsB;GACnD;GAEA,IAAM,IAAc,GAAG,EAAY,YAAY;GAG/C,IAAI,EAAiB,SAAS,KAAY,GAQxC,EACE,GACA,GACA,GACA,EAAuB,aACzB,EACG,KAAK,CAAgB,EACrB,OAbgB,MAA4B;IAE7C,AADA,QAAQ,MAAM,oCAAoC,CAAG,GACjD,KACF,EAAQ,EAAI,MAAM;GAEtB,CAQkB,EACf,cAAc,EAAa,EAAK,CAAC;QAC/B,IACL,EAAiB,+BAA+B,KAChD,GASA,EACE,GACA,OAAO,CAAI,GACX,CACF,EACG,KAAK,CAAgB,EACrB,OAZgB,MAA4B;IAE7C,AADA,QAAQ,MAAM,+CAA+C,CAAG,GAC5D,KACF,EAAQ,EAAI,MAAM;GAEtB,CAOkB,EACf,cAAc,EAAa,EAAK,CAAC;QAC/B,IACL,EAAiB,UAAU,KAC3B,EAAiB,SAAS,KAC1B,EAAiB,SAAS,KAC1B,EAAiB,oBAAoB,KACrC,EAAiB,+BAA+B,GAChD;IACA,IAAM,KACJ,MACG;KACH,AAAI,MACE,iBAAiB,IACnB,EAAqB,EAAS,WAAW,EAAE,KACzC,CACF,KAGI,KACF,EAAwB,CAAQ,GAIhC,GAAO,mBACP,KAGA,EACE,GACA,EAAM,eACR;IAIR,GACM,KAAa,MAA4B;KAC7C,IAAI,EAAI,WAAW,KAAK;MACtB,IAAI,EAAiB,+BAA+B,GAAU;OAO5D,AAJA,QAAQ,MACN,2DACA,CACF,GACI,KACF,EACE,sIACF;OAEF;MACF;MAEA,OAAO,SAAS,QAAQ,CAAkB;KAC5C;KAEA,AADA,QAAQ,MAAM,8BAA8B,CAAG,GAC3C,KACF,EAAQ,EAAI,MAAM;IAEtB;IAEA,CACG,EAAiB,UAAU,KAC1B,EAAiB,SAAS,KAC1B,EAAiB,oBAAoB,MACvC,GAAO,uBAEP,EACE,EAAM,sBACN,GACA,GACA,GACA,EAAuB,aACzB,EACG,KAAK,CAAS,EACd,MAAM,CAAS,EACf,cAAc,EAAa,EAAK,CAAC,IAEpC,EACE,GACA,GACA,GACA,EAAuB,aACzB,EACG,KAAK,CAAS,EACd,MAAM,CAAS,EACf,cAAc,EAAa,EAAK,CAAC;GAExC,OAEE,AADA,QAAQ,KAAK,0BAA0B,CAAQ,GAC/C,EAAa,EAAK;EAEtB;CAIJ,GAAG,CAAC,CAAqB,CAAC,GAEnB,EAAE,aAAU;AACrB"}
@@ -11,7 +11,7 @@ var d = 750;
11
11
  function f(e, t, i, a, s) {
12
12
  o(() => {
13
13
  e && n(t, a.query).then((e) => {
14
- e && e.query && i((t) => ({
14
+ e?.query && i((t) => ({
15
15
  ...t,
16
16
  ...e,
17
17
  query: {
@@ -1 +1 @@
1
- {"version":3,"file":"useImmutableTableQuery.js","names":[],"sources":["../../../../src/utils/hooks/useImmutableTableQuery/useImmutableTableQuery.ts"],"sourcesContent":["import { UniqueFacetIdentifier } from '@/utils/types/UniqueFacetIdentifier'\nimport {\n QueryBundleRequest,\n QueryFilter,\n} from '@sage-bionetworks/synapse-types'\nimport { cloneDeep, isEqual } from 'lodash-es'\nimport * as React from 'react'\nimport { useCallback, useEffect, useMemo } from 'react'\nimport { ReadonlyDeep } from 'type-fest'\nimport useDeepCompareEffect from 'use-deep-compare-effect'\nimport * as DeepLinkingUtils from '../../functions/deepLinkingUtils'\nimport { removeEmptyQueryParams } from '../../functions/queryUtils'\nimport { parseEntityIdAndVersionFromSqlStatement } from '../../functions/SqlFunctions'\nimport { DEFAULT_PAGE_SIZE } from '../../SynapseConstants'\nimport {\n QueryChangeCommitOptions,\n useTableQueryReducer,\n} from './useTableQueryReducer'\n\nexport type ImmutableTableQueryResult = {\n /** The ID of the table parsed from the SQL query */\n entityId?: string\n /** The version number of the table parsed from the SQL query */\n versionNumber?: number\n /** The current query request, which is passed on to the server for results */\n currentQueryRequest: ReadonlyDeep<QueryBundleRequest>\n /** The next (uncommitted) query request. This will become the current query request when commitChanges is called, or the configured debounced timer elapses. */\n nextQueryRequest: ReadonlyDeep<QueryBundleRequest>\n /** Resets the debounce timer to delay committing changes in `nextQueryRequest` */\n resetDebounceTimer: () => void\n /** Update the currentQueryRequest to be the nextQueryRequest */\n commitChanges: () => void\n getInitQueryRequest: () => QueryBundleRequest\n getCurrentQueryRequest: () => QueryBundleRequest\n setQuery: (\n queryRequest: React.SetStateAction<QueryBundleRequest>,\n commitOptions?: QueryChangeCommitOptions,\n ) => void\n pageSize: number\n /** The current page of results. The first page is `1` */\n currentPage: number\n setPageSize: (pageSize: number) => void\n /** pageNumber is 1-indexed */\n goToPage: (pageNumber: number) => void\n /** Resets the query to the initial state, clearing all user-specified filters */\n resetQuery: () => void\n addValueToSelectedFacet: (\n facet: UniqueFacetIdentifier,\n value: string,\n commitOptions?: QueryChangeCommitOptions,\n ) => void\n /** Removes a particular selected facet from the query */\n removeSelectedFacet: (\n facet: UniqueFacetIdentifier | UniqueFacetIdentifier[],\n ) => void\n /** Removes a particular value from a selected facet. If the value is the last value in the FacetColumnRequest, the selected facet will be removed. */\n removeValueFromSelectedFacet: (\n facet: UniqueFacetIdentifier,\n value: string,\n commitOptions?: QueryChangeCommitOptions,\n ) => void\n setRangeFacetValue: (\n facet: UniqueFacetIdentifier,\n min?: string,\n max?: string,\n commitOptions?: QueryChangeCommitOptions,\n ) => void\n /** Removes a particular QueryFilter from the query */\n removeQueryFilter: (filter: QueryFilter) => void\n /** Removes a particular value from a QueryFilter. If the value is the last value in the filter, the filter will be removed. */\n removeValueFromQueryFilter: (filter: QueryFilter, value: string) => void\n /** If `requireConfirmationOnChange` is true, this will become true when a function that triggers a query change is invoked. */\n isConfirmingChange: boolean\n /** If `isConfirmingChange` is true, invoke this function to complete the query change */\n onConfirmChange: () => void\n /** If `isConfirmingChange` is true, invoke this function to cancel the query change */\n onCancelChange: () => void\n\n /**\n * TODO: This hook could handle all potential query transformations, such as\n * - addFacetFilter, removeFacetFilter, clearFacetFilters\n * - addAdditionalFilter, remove..., clear...\n *\n * This could be preferable to allowing any QueryContext subscriber to arbitrarily update the query with `setQuery`\n * because we could uniformly handle all complex stateful logic in this hook\n */\n}\n\nexport type UseImmutableTableQueryOptions = {\n /** The initial table query request object */\n initQueryRequest: QueryBundleRequest\n /** Whether the URL should update when the query is modified. */\n shouldDeepLink?: boolean\n /** Unique index for the component on the page so URL updates do not conflict between table query components */\n componentIndex?: number\n /** Callback invoked when the query is modified */\n onQueryChange?: (newQueryJson: string) => void\n /** Whether to require explicit user confirmation before changing the query. */\n requireConfirmationOnChange?: boolean\n}\n\n// When changing the query with the debounce option, the amount of time to wait for additional debounced changes before updating the query\nexport const DEBOUNCE_DELAY_MS = 750\n\n/**\n * Utility to synchronize the URL with the current query request. Synchronization only occurs if `shouldDeepLink` is true.\n * @param shouldDeepLink whether the query should be synchronized with the URL\n * @param componentIndex the index of the component to synchronize with the URL - essential if multiple components to synchronize are on the page\n * @param setQuery - callback used to update the current query\n * @param initQueryRequest - the initial query request passed via props\n * @param currentQueryRequest - the query request that is currently used\n */\nfunction useSynchronizeQueryWithUrl(\n shouldDeepLink: boolean,\n componentIndex: number,\n setQuery: (\n queryRequest: React.SetStateAction<QueryBundleRequest>,\n commitOptions?: QueryChangeCommitOptions,\n ) => void,\n initQueryRequest: QueryBundleRequest,\n currentQueryRequest: QueryBundleRequest,\n) {\n /**\n * Inspect the URL on mount to see if we have a particular query request that we must show.\n */\n useEffect(() => {\n // Only run this effect if deep linking is enabled\n if (shouldDeepLink) {\n DeepLinkingUtils.getQueryRequestFromLink(\n componentIndex,\n initQueryRequest.query,\n ).then(queryRequestFromLink => {\n if (queryRequestFromLink && queryRequestFromLink.query) {\n setQuery(prevState => ({\n ...prevState,\n ...queryRequestFromLink,\n query: {\n ...prevState.query,\n ...queryRequestFromLink.query,\n },\n }))\n }\n })\n }\n // should only run on mount, or if the component index changes\n // oxlint-disable-next-line react-hooks/exhaustive-deps\n }, [componentIndex])\n\n // If `shouldDeepLink` is true, synchronize the URL\n useEffect(() => {\n if (shouldDeepLink) {\n if (isEqual(initQueryRequest, currentQueryRequest)) {\n void DeepLinkingUtils.updateUrlWithNewSearchParam(\n 'qw',\n componentIndex,\n null,\n null,\n ).catch(error => {\n console.error('Failed to update URL with search param:', error)\n })\n } else {\n void DeepLinkingUtils.updateUrlWithNewSearchParam(\n 'qw',\n componentIndex,\n currentQueryRequest.query,\n initQueryRequest.query,\n ).catch(error => {\n console.error('Failed to update URL with search param:', error)\n })\n }\n }\n // Clean up the URL param when this component unmounts or deep linking is disabled\n return () => {\n if (shouldDeepLink) {\n DeepLinkingUtils.updateUrlWithNewSearchParam(\n 'qw',\n componentIndex,\n null,\n initQueryRequest.query,\n )\n }\n }\n }, [componentIndex, currentQueryRequest, initQueryRequest, shouldDeepLink])\n}\n\n/**\n * Custom hook that maintains and manages the state of a Synapse Table query.\n * @param options\n * @returns\n */\nexport default function useImmutableTableQuery(\n options: UseImmutableTableQueryOptions,\n): ImmutableTableQueryResult {\n const {\n initQueryRequest: initQueryRequestFromProps,\n componentIndex = 0,\n shouldDeepLink = false,\n onQueryChange,\n requireConfirmationOnChange = false,\n } = options\n\n const initQueryRequest = useMemo(() => {\n const request = cloneDeep(initQueryRequestFromProps)\n request.query = removeEmptyQueryParams(request.query)\n return request\n }, [initQueryRequestFromProps])\n\n const {\n currentQueryRequest,\n nextQueryRequest,\n isConfirmingChange,\n dispatch,\n } = useTableQueryReducer(\n initQueryRequest,\n requireConfirmationOnChange,\n onQueryChange,\n )\n\n const onConfirmChange = useCallback(() => {\n dispatch({ type: 'confirmChanges' })\n }, [dispatch])\n\n /**\n * Pass down a deep clone (so no side effects on the child's part) of the\n * current query request\n *\n * @returns\n * @memberof QueryWrapper\n */\n const getCurrentQueryRequest = useCallback(() => {\n return cloneDeep(currentQueryRequest)\n }, [currentQueryRequest])\n\n /**\n * Pass down a deep clone (so no side effects on the child's part) of the\n * first query request made\n *\n * @returns\n * @memberof QueryWrapper\n */\n const getInitQueryRequest = useCallback((): QueryBundleRequest => {\n return cloneDeep(initQueryRequest)\n }, [initQueryRequest])\n\n /**\n * Execute the given query request, updating all the data in the QueryContext to match the new query\n * @param {*} queryRequest Query request as specified by\n * https://rest-docs.synapse.org/rest/org/sagebionetworks/repo/model/table/Query.html\n */\n const setQuery: ImmutableTableQueryResult['setQuery'] = useCallback(\n (\n queryRequest: React.SetStateAction<QueryBundleRequest>,\n commitOptions?: QueryChangeCommitOptions,\n ): void => {\n dispatch({\n type: 'setQuery',\n queryOrUpdater: queryRequest,\n commitOptions,\n })\n },\n [dispatch],\n )\n\n useSynchronizeQueryWithUrl(\n shouldDeepLink,\n componentIndex,\n setQuery,\n initQueryRequest,\n currentQueryRequest,\n )\n\n const onCancelChange = useCallback(() => {\n dispatch({ type: 'cancelChanges' })\n }, [dispatch])\n\n const { entityId, versionNumber } = useMemo(\n () =>\n parseEntityIdAndVersionFromSqlStatement(currentQueryRequest.query.sql),\n [currentQueryRequest.query.sql],\n )\n\n const pageSize = currentQueryRequest.query.limit ?? DEFAULT_PAGE_SIZE\n const currentPage = Math.ceil(\n ((currentQueryRequest.query.offset ?? 0) + Number(pageSize)) / pageSize,\n )\n\n const setPageSize = useCallback(\n (pageSize: number) => {\n dispatch({ type: 'setPageSize', pageSize })\n },\n [dispatch],\n )\n\n const goToPage = useCallback(\n (pageNumber: number) => {\n dispatch({ type: 'goToPage', pageNumber })\n },\n [dispatch],\n )\n\n const resetQuery = useCallback(() => {\n dispatch({\n type: 'resetQuery',\n })\n }, [dispatch])\n\n /* If the initial query changes, then reset the query to match the new prop */\n useDeepCompareEffect(() => {\n if (currentQueryRequest != initQueryRequest) {\n resetQuery()\n }\n }, [initQueryRequest])\n\n const addValueToSelectedFacet = useCallback(\n (\n facet: UniqueFacetIdentifier,\n value: string,\n commitOptions?: QueryChangeCommitOptions,\n ) => {\n dispatch({\n type: 'addValueToSelectedFacet',\n facet: facet,\n value: value,\n commitOptions: commitOptions,\n })\n },\n [dispatch],\n )\n\n const setRangeFacetValue = useCallback(\n (\n facet: UniqueFacetIdentifier,\n min?: string,\n max?: string,\n commitOptions?: QueryChangeCommitOptions,\n ) => {\n dispatch({\n type: 'setRangeFacetValue',\n facet,\n min,\n max,\n commitOptions,\n })\n },\n [dispatch],\n )\n\n const removeSelectedFacet = useCallback(\n (facetsToRemove: UniqueFacetIdentifier | UniqueFacetIdentifier[]) => {\n dispatch({\n type: 'removeSelectedFacet',\n facetsToRemove: facetsToRemove,\n })\n },\n [dispatch],\n )\n\n const removeValueFromSelectedFacet = useCallback(\n (\n facet: UniqueFacetIdentifier,\n value: string,\n commitOptions?: QueryChangeCommitOptions,\n ) => {\n dispatch({\n type: 'removeValueFromSelectedFacet',\n facet,\n value,\n commitOptions,\n })\n },\n [dispatch],\n )\n\n const removeQueryFilter = useCallback(\n (queryFilter: QueryFilter) => {\n dispatch({\n type: 'removeQueryFilter',\n queryFilter,\n })\n },\n [dispatch],\n )\n\n const removeValueFromQueryFilter = useCallback(\n (queryFilter: QueryFilter, value: string) => {\n dispatch({\n type: 'removeValueFromQueryFilter',\n queryFilter,\n value,\n })\n },\n [dispatch],\n )\n const commitChanges = useCallback(() => {\n dispatch({ type: 'commitChanges' })\n }, [dispatch])\n\n const resetDebounceTimer = useCallback(() => {\n dispatch({ type: 'resetDebounce' })\n }, [dispatch])\n\n return {\n entityId,\n commitChanges,\n resetDebounceTimer,\n currentQueryRequest,\n nextQueryRequest,\n versionNumber,\n getInitQueryRequest,\n getCurrentQueryRequest,\n setQuery,\n pageSize,\n currentPage,\n setPageSize,\n goToPage,\n resetQuery,\n removeSelectedFacet,\n removeValueFromSelectedFacet,\n removeQueryFilter,\n removeValueFromQueryFilter,\n isConfirmingChange,\n onConfirmChange,\n onCancelChange,\n addValueToSelectedFacet,\n setRangeFacetValue,\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"useImmutableTableQuery.js","names":[],"sources":["../../../../src/utils/hooks/useImmutableTableQuery/useImmutableTableQuery.ts"],"sourcesContent":["import { UniqueFacetIdentifier } from '@/utils/types/UniqueFacetIdentifier'\nimport {\n QueryBundleRequest,\n QueryFilter,\n} from '@sage-bionetworks/synapse-types'\nimport { cloneDeep, isEqual } from 'lodash-es'\nimport * as React from 'react'\nimport { useCallback, useEffect, useMemo } from 'react'\nimport { ReadonlyDeep } from 'type-fest'\nimport useDeepCompareEffect from 'use-deep-compare-effect'\nimport * as DeepLinkingUtils from '../../functions/deepLinkingUtils'\nimport { removeEmptyQueryParams } from '../../functions/queryUtils'\nimport { parseEntityIdAndVersionFromSqlStatement } from '../../functions/SqlFunctions'\nimport { DEFAULT_PAGE_SIZE } from '../../SynapseConstants'\nimport {\n QueryChangeCommitOptions,\n useTableQueryReducer,\n} from './useTableQueryReducer'\n\nexport type ImmutableTableQueryResult = {\n /** The ID of the table parsed from the SQL query */\n entityId?: string\n /** The version number of the table parsed from the SQL query */\n versionNumber?: number\n /** The current query request, which is passed on to the server for results */\n currentQueryRequest: ReadonlyDeep<QueryBundleRequest>\n /** The next (uncommitted) query request. This will become the current query request when commitChanges is called, or the configured debounced timer elapses. */\n nextQueryRequest: ReadonlyDeep<QueryBundleRequest>\n /** Resets the debounce timer to delay committing changes in `nextQueryRequest` */\n resetDebounceTimer: () => void\n /** Update the currentQueryRequest to be the nextQueryRequest */\n commitChanges: () => void\n getInitQueryRequest: () => QueryBundleRequest\n getCurrentQueryRequest: () => QueryBundleRequest\n setQuery: (\n queryRequest: React.SetStateAction<QueryBundleRequest>,\n commitOptions?: QueryChangeCommitOptions,\n ) => void\n pageSize: number\n /** The current page of results. The first page is `1` */\n currentPage: number\n setPageSize: (pageSize: number) => void\n /** pageNumber is 1-indexed */\n goToPage: (pageNumber: number) => void\n /** Resets the query to the initial state, clearing all user-specified filters */\n resetQuery: () => void\n addValueToSelectedFacet: (\n facet: UniqueFacetIdentifier,\n value: string,\n commitOptions?: QueryChangeCommitOptions,\n ) => void\n /** Removes a particular selected facet from the query */\n removeSelectedFacet: (\n facet: UniqueFacetIdentifier | UniqueFacetIdentifier[],\n ) => void\n /** Removes a particular value from a selected facet. If the value is the last value in the FacetColumnRequest, the selected facet will be removed. */\n removeValueFromSelectedFacet: (\n facet: UniqueFacetIdentifier,\n value: string,\n commitOptions?: QueryChangeCommitOptions,\n ) => void\n setRangeFacetValue: (\n facet: UniqueFacetIdentifier,\n min?: string,\n max?: string,\n commitOptions?: QueryChangeCommitOptions,\n ) => void\n /** Removes a particular QueryFilter from the query */\n removeQueryFilter: (filter: QueryFilter) => void\n /** Removes a particular value from a QueryFilter. If the value is the last value in the filter, the filter will be removed. */\n removeValueFromQueryFilter: (filter: QueryFilter, value: string) => void\n /** If `requireConfirmationOnChange` is true, this will become true when a function that triggers a query change is invoked. */\n isConfirmingChange: boolean\n /** If `isConfirmingChange` is true, invoke this function to complete the query change */\n onConfirmChange: () => void\n /** If `isConfirmingChange` is true, invoke this function to cancel the query change */\n onCancelChange: () => void\n\n /**\n * TODO: This hook could handle all potential query transformations, such as\n * - addFacetFilter, removeFacetFilter, clearFacetFilters\n * - addAdditionalFilter, remove..., clear...\n *\n * This could be preferable to allowing any QueryContext subscriber to arbitrarily update the query with `setQuery`\n * because we could uniformly handle all complex stateful logic in this hook\n */\n}\n\nexport type UseImmutableTableQueryOptions = {\n /** The initial table query request object */\n initQueryRequest: QueryBundleRequest\n /** Whether the URL should update when the query is modified. */\n shouldDeepLink?: boolean\n /** Unique index for the component on the page so URL updates do not conflict between table query components */\n componentIndex?: number\n /** Callback invoked when the query is modified */\n onQueryChange?: (newQueryJson: string) => void\n /** Whether to require explicit user confirmation before changing the query. */\n requireConfirmationOnChange?: boolean\n}\n\n// When changing the query with the debounce option, the amount of time to wait for additional debounced changes before updating the query\nexport const DEBOUNCE_DELAY_MS = 750\n\n/**\n * Utility to synchronize the URL with the current query request. Synchronization only occurs if `shouldDeepLink` is true.\n * @param shouldDeepLink whether the query should be synchronized with the URL\n * @param componentIndex the index of the component to synchronize with the URL - essential if multiple components to synchronize are on the page\n * @param setQuery - callback used to update the current query\n * @param initQueryRequest - the initial query request passed via props\n * @param currentQueryRequest - the query request that is currently used\n */\nfunction useSynchronizeQueryWithUrl(\n shouldDeepLink: boolean,\n componentIndex: number,\n setQuery: (\n queryRequest: React.SetStateAction<QueryBundleRequest>,\n commitOptions?: QueryChangeCommitOptions,\n ) => void,\n initQueryRequest: QueryBundleRequest,\n currentQueryRequest: QueryBundleRequest,\n) {\n /**\n * Inspect the URL on mount to see if we have a particular query request that we must show.\n */\n useEffect(() => {\n // Only run this effect if deep linking is enabled\n if (shouldDeepLink) {\n DeepLinkingUtils.getQueryRequestFromLink(\n componentIndex,\n initQueryRequest.query,\n ).then(queryRequestFromLink => {\n if (queryRequestFromLink?.query) {\n setQuery(prevState => ({\n ...prevState,\n ...queryRequestFromLink,\n query: {\n ...prevState.query,\n ...queryRequestFromLink.query,\n },\n }))\n }\n })\n }\n // should only run on mount, or if the component index changes\n // oxlint-disable-next-line react-hooks/exhaustive-deps\n }, [componentIndex])\n\n // If `shouldDeepLink` is true, synchronize the URL\n useEffect(() => {\n if (shouldDeepLink) {\n if (isEqual(initQueryRequest, currentQueryRequest)) {\n void DeepLinkingUtils.updateUrlWithNewSearchParam(\n 'qw',\n componentIndex,\n null,\n null,\n ).catch(error => {\n console.error('Failed to update URL with search param:', error)\n })\n } else {\n void DeepLinkingUtils.updateUrlWithNewSearchParam(\n 'qw',\n componentIndex,\n currentQueryRequest.query,\n initQueryRequest.query,\n ).catch(error => {\n console.error('Failed to update URL with search param:', error)\n })\n }\n }\n // Clean up the URL param when this component unmounts or deep linking is disabled\n return () => {\n if (shouldDeepLink) {\n DeepLinkingUtils.updateUrlWithNewSearchParam(\n 'qw',\n componentIndex,\n null,\n initQueryRequest.query,\n )\n }\n }\n }, [componentIndex, currentQueryRequest, initQueryRequest, shouldDeepLink])\n}\n\n/**\n * Custom hook that maintains and manages the state of a Synapse Table query.\n * @param options\n * @returns\n */\nexport default function useImmutableTableQuery(\n options: UseImmutableTableQueryOptions,\n): ImmutableTableQueryResult {\n const {\n initQueryRequest: initQueryRequestFromProps,\n componentIndex = 0,\n shouldDeepLink = false,\n onQueryChange,\n requireConfirmationOnChange = false,\n } = options\n\n const initQueryRequest = useMemo(() => {\n const request = cloneDeep(initQueryRequestFromProps)\n request.query = removeEmptyQueryParams(request.query)\n return request\n }, [initQueryRequestFromProps])\n\n const {\n currentQueryRequest,\n nextQueryRequest,\n isConfirmingChange,\n dispatch,\n } = useTableQueryReducer(\n initQueryRequest,\n requireConfirmationOnChange,\n onQueryChange,\n )\n\n const onConfirmChange = useCallback(() => {\n dispatch({ type: 'confirmChanges' })\n }, [dispatch])\n\n /**\n * Pass down a deep clone (so no side effects on the child's part) of the\n * current query request\n *\n * @returns\n * @memberof QueryWrapper\n */\n const getCurrentQueryRequest = useCallback(() => {\n return cloneDeep(currentQueryRequest)\n }, [currentQueryRequest])\n\n /**\n * Pass down a deep clone (so no side effects on the child's part) of the\n * first query request made\n *\n * @returns\n * @memberof QueryWrapper\n */\n const getInitQueryRequest = useCallback((): QueryBundleRequest => {\n return cloneDeep(initQueryRequest)\n }, [initQueryRequest])\n\n /**\n * Execute the given query request, updating all the data in the QueryContext to match the new query\n * @param {*} queryRequest Query request as specified by\n * https://rest-docs.synapse.org/rest/org/sagebionetworks/repo/model/table/Query.html\n */\n const setQuery: ImmutableTableQueryResult['setQuery'] = useCallback(\n (\n queryRequest: React.SetStateAction<QueryBundleRequest>,\n commitOptions?: QueryChangeCommitOptions,\n ): void => {\n dispatch({\n type: 'setQuery',\n queryOrUpdater: queryRequest,\n commitOptions,\n })\n },\n [dispatch],\n )\n\n useSynchronizeQueryWithUrl(\n shouldDeepLink,\n componentIndex,\n setQuery,\n initQueryRequest,\n currentQueryRequest,\n )\n\n const onCancelChange = useCallback(() => {\n dispatch({ type: 'cancelChanges' })\n }, [dispatch])\n\n const { entityId, versionNumber } = useMemo(\n () =>\n parseEntityIdAndVersionFromSqlStatement(currentQueryRequest.query.sql),\n [currentQueryRequest.query.sql],\n )\n\n const pageSize = currentQueryRequest.query.limit ?? DEFAULT_PAGE_SIZE\n const currentPage = Math.ceil(\n ((currentQueryRequest.query.offset ?? 0) + Number(pageSize)) / pageSize,\n )\n\n const setPageSize = useCallback(\n (pageSize: number) => {\n dispatch({ type: 'setPageSize', pageSize })\n },\n [dispatch],\n )\n\n const goToPage = useCallback(\n (pageNumber: number) => {\n dispatch({ type: 'goToPage', pageNumber })\n },\n [dispatch],\n )\n\n const resetQuery = useCallback(() => {\n dispatch({\n type: 'resetQuery',\n })\n }, [dispatch])\n\n /* If the initial query changes, then reset the query to match the new prop */\n useDeepCompareEffect(() => {\n if (currentQueryRequest != initQueryRequest) {\n resetQuery()\n }\n }, [initQueryRequest])\n\n const addValueToSelectedFacet = useCallback(\n (\n facet: UniqueFacetIdentifier,\n value: string,\n commitOptions?: QueryChangeCommitOptions,\n ) => {\n dispatch({\n type: 'addValueToSelectedFacet',\n facet: facet,\n value: value,\n commitOptions: commitOptions,\n })\n },\n [dispatch],\n )\n\n const setRangeFacetValue = useCallback(\n (\n facet: UniqueFacetIdentifier,\n min?: string,\n max?: string,\n commitOptions?: QueryChangeCommitOptions,\n ) => {\n dispatch({\n type: 'setRangeFacetValue',\n facet,\n min,\n max,\n commitOptions,\n })\n },\n [dispatch],\n )\n\n const removeSelectedFacet = useCallback(\n (facetsToRemove: UniqueFacetIdentifier | UniqueFacetIdentifier[]) => {\n dispatch({\n type: 'removeSelectedFacet',\n facetsToRemove: facetsToRemove,\n })\n },\n [dispatch],\n )\n\n const removeValueFromSelectedFacet = useCallback(\n (\n facet: UniqueFacetIdentifier,\n value: string,\n commitOptions?: QueryChangeCommitOptions,\n ) => {\n dispatch({\n type: 'removeValueFromSelectedFacet',\n facet,\n value,\n commitOptions,\n })\n },\n [dispatch],\n )\n\n const removeQueryFilter = useCallback(\n (queryFilter: QueryFilter) => {\n dispatch({\n type: 'removeQueryFilter',\n queryFilter,\n })\n },\n [dispatch],\n )\n\n const removeValueFromQueryFilter = useCallback(\n (queryFilter: QueryFilter, value: string) => {\n dispatch({\n type: 'removeValueFromQueryFilter',\n queryFilter,\n value,\n })\n },\n [dispatch],\n )\n const commitChanges = useCallback(() => {\n dispatch({ type: 'commitChanges' })\n }, [dispatch])\n\n const resetDebounceTimer = useCallback(() => {\n dispatch({ type: 'resetDebounce' })\n }, [dispatch])\n\n return {\n entityId,\n commitChanges,\n resetDebounceTimer,\n currentQueryRequest,\n nextQueryRequest,\n versionNumber,\n getInitQueryRequest,\n getCurrentQueryRequest,\n setQuery,\n pageSize,\n currentPage,\n setPageSize,\n goToPage,\n resetQuery,\n removeSelectedFacet,\n removeValueFromSelectedFacet,\n removeQueryFilter,\n removeValueFromQueryFilter,\n isConfirmingChange,\n onConfirmChange,\n onCancelChange,\n addValueToSelectedFacet,\n setRangeFacetValue,\n }\n}\n"],"mappings":"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"}
@@ -23,7 +23,7 @@ function l(e, t) {
23
23
  function u(n) {
24
24
  let [a, o] = t(!1);
25
25
  return e(() => {
26
- if (n && n.$id) if (r(n.$id)) o(!0);
26
+ if (n?.$id) if (r(n.$id)) o(!0);
27
27
  else try {
28
28
  i(n), o(!0);
29
29
  } catch (e) {
@@ -1 +1 @@
1
- {"version":3,"file":"SchemaAnnotationUtils.js","names":[],"sources":["../../../src/utils/jsonschema/SchemaAnnotationUtils.ts"],"sourcesContent":["/**\n * Utilities for retrieving annotation fields (e.g. \"title\", \"description\") from JSON Schemas\n */\n\nimport { hasSchema, SchemaObject } from '@hyperjump/json-schema'\nimport { registerSchema } from '@hyperjump/json-schema/draft-07'\nimport * as AnnotatedInstance from '@hyperjump/json-schema/annotated-instance/experimental'\nimport { annotate } from '@hyperjump/json-schema/annotations/experimental'\nimport { JsonNode } from '@hyperjump/json-schema/instance/experimental'\nimport { Json } from '@sage-bionetworks/synapse-client'\nimport { useQuery } from '@tanstack/react-query'\nimport { JSONSchema7 } from 'json-schema'\nimport { useEffect, useState } from 'react'\n\n/**\n * Get the value of a specified annotation for a specified key described in the JsonNode\n * @param key - the property key for which the description should be retrieved.\n * @param instance - a JsonNode resolved by the `annotate` API provided by @hyperjump/json-schema/annotations/experimental\n * @param annotationKey - the value that corresponds to the annotation to retrieve, e.g. \"title\", \"description\"\n */\nexport function getSchemaAnnotationForProperty(\n key: string,\n instance: JsonNode,\n annotationKey: string,\n): string | undefined {\n if (instance) {\n // Get the title of each of the properties in the object\n for (const [\n propertyNameNode,\n propertyInstance,\n ] of AnnotatedInstance.entries(instance)) {\n const propertyName = AnnotatedInstance.value(propertyNameNode)\n if (propertyName === key) {\n const annotationValue = AnnotatedInstance.annotation(\n propertyInstance,\n annotationKey,\n )[0] as string | undefined\n return annotationValue\n }\n }\n }\n\n return undefined\n}\n\n/**\n * Get the \"title\" for a specific key described in the JsonNode\n * @param key - the property key for which the description should be retrieved.\n * @param instance - a JsonNode resolved by the `annotate` API provided by @hyperjump/json-schema/annotations/experimental\n */\nexport function getDisplayedAnnotationTitle(\n key: string,\n instance?: JsonNode | null,\n): string {\n if (instance) {\n const titleFromSchema = getSchemaAnnotationForProperty(\n key,\n instance,\n 'title',\n )\n if (titleFromSchema) {\n return titleFromSchema\n }\n }\n\n return key\n}\n\n/**\n * Get the \"description\" for a specific key described in the JsonNode\n * @param key - the property key for which the description should be retrieved.\n * @param instance - a JsonNode resolved by the `annotate` API provided by @hyperjump/json-schema/annotations/experimental\n */\nexport function getDisplayedAnnotationDescription(\n key: string,\n instance?: JsonNode | null,\n): string | undefined {\n if (instance) {\n return getSchemaAnnotationForProperty(key, instance, 'description')\n }\n\n return undefined\n}\n\n/**\n * Registers a schema with @hyperjump/json-schema.\n * @param schema\n * @return boolean indicating if the schema is registered.\n */\nexport function useRegisterSchema(schema?: JSONSchema7) {\n const [isRegistered, setIsRegistered] = useState(false)\n\n useEffect(() => {\n if (schema && schema.$id) {\n // The schema can be registered\n if (!hasSchema(schema.$id)) {\n try {\n registerSchema(schema as SchemaObject)\n setIsRegistered(true)\n } catch (e) {\n console.error(\n 'Unable to register JSON Schema in @hyperjump/json-schema:',\n e,\n )\n }\n } else {\n // Already registered, update local state.\n setIsRegistered(true)\n }\n }\n // TODO: Unregister the schema to avoid memory bloat\n // This would require syncing with the current state of schemas being used to make sure that we don't unregister a\n // schema being used by multiple hook instances\n }, [schema])\n\n return isRegistered\n}\n\n/**\n * Given a JSON document and a schema that describes it, return a query result that\n * resolves a JsonNode that can be used to retrieve schema annotations. Uses the `annotate` API provided\n * by @hyperjump/json-schema/annotations/experimental\n * @param json - a JSON document\n * @param schema - a JSON Schema that describes the JSON document\n */\nexport function useGetAnnotatedJsonInstance(json?: Json, schema?: JSONSchema7) {\n const schemaIsRegistered = useRegisterSchema(schema)\n\n return useQuery<JsonNode | null>({\n queryKey: ['getAnnotatedInstance', { json, schema, schemaIsRegistered }],\n queryFn: () => {\n if (json && schema && schemaIsRegistered) {\n try {\n return annotate(schema.$id!, json)\n } catch (e) {\n console.error('Could not create annotated schema instance:', e)\n }\n }\n return null\n },\n enabled: Boolean(schema && json),\n })\n}\n"],"mappings":";;;;;;;AAoBA,SAAgB,EACd,GACA,GACA,GACoB;CACpB,IAAI;OAEG,IAAM,CACT,GACA,MACG,EAAkB,QAAQ,CAAQ,GAErC,IADqB,EAAkB,MAAM,CACzC,MAAiB,GAKnB,OAJwB,EAAkB,WACxC,GACA,CACF,EAAE;CAAA;AAOV;AAOA,SAAgB,EACd,GACA,GACQ;CACR,IAAI,GAAU;EACZ,IAAM,IAAkB,EACtB,GACA,GACA,OACF;EACA,IAAI,GACF,OAAO;CAEX;CAEA,OAAO;AACT;AAOA,SAAgB,EACd,GACA,GACoB;CACpB,IAAI,GACF,OAAO,EAA+B,GAAK,GAAU,aAAa;AAItE;AAOA,SAAgB,EAAkB,GAAsB;CACtD,IAAM,CAAC,GAAc,KAAmB,EAAS,EAAK;CAyBtD,OAvBA,QAAgB;EACd,IAAI,KAAU,EAAO,KAEnB,IAAK,EAAU,EAAO,GAAG,GAYvB,EAAgB,EAAI;OAXpB,IAAI;GAEF,AADA,EAAe,CAAsB,GACrC,EAAgB,EAAI;EACtB,SAAS,GAAG;GACV,QAAQ,MACN,6DACA,CACF;EACF;CASN,GAAG,CAAC,CAAM,CAAC,GAEJ;AACT;AASA,SAAgB,EAA4B,GAAa,GAAsB;CAC7E,IAAM,IAAqB,EAAkB,CAAM;CAEnD,OAAO,EAA0B;EAC/B,UAAU,CAAC,wBAAwB;GAAE;GAAM;GAAQ;EAAmB,CAAC;EACvE,eAAe;GACb,IAAI,KAAQ,KAAU,GACpB,IAAI;IACF,OAAO,EAAS,EAAO,KAAM,CAAI;GACnC,SAAS,GAAG;IACV,QAAQ,MAAM,+CAA+C,CAAC;GAChE;GAEF,OAAO;EACT;EACA,SAAS,GAAQ,KAAU;CAC7B,CAAC;AACH"}
1
+ {"version":3,"file":"SchemaAnnotationUtils.js","names":[],"sources":["../../../src/utils/jsonschema/SchemaAnnotationUtils.ts"],"sourcesContent":["/**\n * Utilities for retrieving annotation fields (e.g. \"title\", \"description\") from JSON Schemas\n */\n\nimport { hasSchema, SchemaObject } from '@hyperjump/json-schema'\nimport { registerSchema } from '@hyperjump/json-schema/draft-07'\nimport * as AnnotatedInstance from '@hyperjump/json-schema/annotated-instance/experimental'\nimport { annotate } from '@hyperjump/json-schema/annotations/experimental'\nimport { JsonNode } from '@hyperjump/json-schema/instance/experimental'\nimport { Json } from '@sage-bionetworks/synapse-client'\nimport { useQuery } from '@tanstack/react-query'\nimport { JSONSchema7 } from 'json-schema'\nimport { useEffect, useState } from 'react'\n\n/**\n * Get the value of a specified annotation for a specified key described in the JsonNode\n * @param key - the property key for which the description should be retrieved.\n * @param instance - a JsonNode resolved by the `annotate` API provided by @hyperjump/json-schema/annotations/experimental\n * @param annotationKey - the value that corresponds to the annotation to retrieve, e.g. \"title\", \"description\"\n */\nexport function getSchemaAnnotationForProperty(\n key: string,\n instance: JsonNode,\n annotationKey: string,\n): string | undefined {\n if (instance) {\n // Get the title of each of the properties in the object\n for (const [\n propertyNameNode,\n propertyInstance,\n ] of AnnotatedInstance.entries(instance)) {\n const propertyName = AnnotatedInstance.value(propertyNameNode)\n if (propertyName === key) {\n const annotationValue = AnnotatedInstance.annotation(\n propertyInstance,\n annotationKey,\n )[0] as string | undefined\n return annotationValue\n }\n }\n }\n\n return undefined\n}\n\n/**\n * Get the \"title\" for a specific key described in the JsonNode\n * @param key - the property key for which the description should be retrieved.\n * @param instance - a JsonNode resolved by the `annotate` API provided by @hyperjump/json-schema/annotations/experimental\n */\nexport function getDisplayedAnnotationTitle(\n key: string,\n instance?: JsonNode | null,\n): string {\n if (instance) {\n const titleFromSchema = getSchemaAnnotationForProperty(\n key,\n instance,\n 'title',\n )\n if (titleFromSchema) {\n return titleFromSchema\n }\n }\n\n return key\n}\n\n/**\n * Get the \"description\" for a specific key described in the JsonNode\n * @param key - the property key for which the description should be retrieved.\n * @param instance - a JsonNode resolved by the `annotate` API provided by @hyperjump/json-schema/annotations/experimental\n */\nexport function getDisplayedAnnotationDescription(\n key: string,\n instance?: JsonNode | null,\n): string | undefined {\n if (instance) {\n return getSchemaAnnotationForProperty(key, instance, 'description')\n }\n\n return undefined\n}\n\n/**\n * Registers a schema with @hyperjump/json-schema.\n * @param schema\n * @return boolean indicating if the schema is registered.\n */\nexport function useRegisterSchema(schema?: JSONSchema7) {\n const [isRegistered, setIsRegistered] = useState(false)\n\n useEffect(() => {\n if (schema?.$id) {\n // The schema can be registered\n if (!hasSchema(schema.$id)) {\n try {\n registerSchema(schema as SchemaObject)\n setIsRegistered(true)\n } catch (e) {\n console.error(\n 'Unable to register JSON Schema in @hyperjump/json-schema:',\n e,\n )\n }\n } else {\n // Already registered, update local state.\n setIsRegistered(true)\n }\n }\n // TODO: Unregister the schema to avoid memory bloat\n // This would require syncing with the current state of schemas being used to make sure that we don't unregister a\n // schema being used by multiple hook instances\n }, [schema])\n\n return isRegistered\n}\n\n/**\n * Given a JSON document and a schema that describes it, return a query result that\n * resolves a JsonNode that can be used to retrieve schema annotations. Uses the `annotate` API provided\n * by @hyperjump/json-schema/annotations/experimental\n * @param json - a JSON document\n * @param schema - a JSON Schema that describes the JSON document\n */\nexport function useGetAnnotatedJsonInstance(json?: Json, schema?: JSONSchema7) {\n const schemaIsRegistered = useRegisterSchema(schema)\n\n return useQuery<JsonNode | null>({\n queryKey: ['getAnnotatedInstance', { json, schema, schemaIsRegistered }],\n queryFn: () => {\n if (json && schema && schemaIsRegistered) {\n try {\n return annotate(schema.$id!, json)\n } catch (e) {\n console.error('Could not create annotated schema instance:', e)\n }\n }\n return null\n },\n enabled: Boolean(schema && json),\n })\n}\n"],"mappings":";;;;;;;AAoBA,SAAgB,EACd,GACA,GACA,GACoB;CACpB,IAAI;OAEG,IAAM,CACT,GACA,MACG,EAAkB,QAAQ,CAAQ,GAErC,IADqB,EAAkB,MAAM,CACzC,MAAiB,GAKnB,OAJwB,EAAkB,WACxC,GACA,CACF,EAAE;CAAA;AAOV;AAOA,SAAgB,EACd,GACA,GACQ;CACR,IAAI,GAAU;EACZ,IAAM,IAAkB,EACtB,GACA,GACA,OACF;EACA,IAAI,GACF,OAAO;CAEX;CAEA,OAAO;AACT;AAOA,SAAgB,EACd,GACA,GACoB;CACpB,IAAI,GACF,OAAO,EAA+B,GAAK,GAAU,aAAa;AAItE;AAOA,SAAgB,EAAkB,GAAsB;CACtD,IAAM,CAAC,GAAc,KAAmB,EAAS,EAAK;CAyBtD,OAvBA,QAAgB;EACd,IAAI,GAAQ,KAEV,IAAK,EAAU,EAAO,GAAG,GAYvB,EAAgB,EAAI;OAXpB,IAAI;GAEF,AADA,EAAe,CAAsB,GACrC,EAAgB,EAAI;EACtB,SAAS,GAAG;GACV,QAAQ,MACN,6DACA,CACF;EACF;CASN,GAAG,CAAC,CAAM,CAAC,GAEJ;AACT;AASA,SAAgB,EAA4B,GAAa,GAAsB;CAC7E,IAAM,IAAqB,EAAkB,CAAM;CAEnD,OAAO,EAA0B;EAC/B,UAAU,CAAC,wBAAwB;GAAE;GAAM;GAAQ;EAAmB,CAAC;EACvE,eAAe;GACb,IAAI,KAAQ,KAAU,GACpB,IAAI;IACF,OAAO,EAAS,EAAO,KAAM,CAAI;GACnC,SAAS,GAAG;IACV,QAAQ,MAAM,+CAA+C,CAAC;GAChE;GAEF,OAAO;EACT;EACA,SAAS,GAAQ,KAAU;CAC7B,CAAC;AACH"}
@@ -0,0 +1,22 @@
1
+ import { JSONSchema7, JSONSchema7Definition } from 'json-schema';
2
+ type TopLevelProperties = Record<string, JSONSchema7Definition>;
3
+ /**
4
+ * Collects the names that could appear as a top-level property of an instance validated by the given
5
+ * JSON Schema, keyed by property name. Each value is the `$ref`-resolved schema for that property.
6
+ *
7
+ * The walk follows schema combination keywords (`$ref`, `allOf`, `anyOf`, `oneOf`, `if`, `then`,
8
+ * `else`) so that properties declared in referenced or composed sub-schemas are included. It does
9
+ * NOT descend into a property's own value, `items`, `contains`, `additionalProperties`, or `not`, so
10
+ * the nested properties of an object or the elements of an array are never surfaced as top-level
11
+ * properties.
12
+ *
13
+ * Insertion order is the order in which properties were first encountered, and the first occurrence
14
+ * of a name wins -- so a schema's own properties take precedence over composed/inherited ones.
15
+ *
16
+ * This mirrors the backend's `JsonSchemaProperties.collectTopLevelProperties`, which is what defines
17
+ * a RecordSet's schema columns. Only draft-07 `definitions` references are resolved (not `$defs`),
18
+ * matching that implementation.
19
+ */
20
+ export declare function collectTopLevelProperties(root: JSONSchema7 | undefined): TopLevelProperties;
21
+ export {};
22
+ //# sourceMappingURL=collectTopLevelProperties.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collectTopLevelProperties.d.ts","sourceRoot":"","sources":["../../../src/utils/jsonschema/collectTopLevelProperties.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAKhE,KAAK,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAA;AAmF/D;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,WAAW,GAAG,SAAS,GAC5B,kBAAkB,CAOpB"}
@@ -0,0 +1,31 @@
1
+ //#region src/utils/jsonschema/collectTopLevelProperties.ts
2
+ var e = "#/definitions/";
3
+ function t(t) {
4
+ return t.startsWith(e) ? t.substring(14) : t;
5
+ }
6
+ function n(e, n) {
7
+ let r = n?.[t(e)];
8
+ return typeof r == "object" ? r : void 0;
9
+ }
10
+ function r(e, t) {
11
+ return typeof e != "object" || !e.$ref ? e : n(e.$ref, t) ?? e;
12
+ }
13
+ function i(e, t, a, o) {
14
+ if (typeof e == "object") {
15
+ if (e.$ref) {
16
+ if (a.has(e.$ref)) return;
17
+ a.add(e.$ref), i(n(e.$ref, t), t, a, o);
18
+ return;
19
+ }
20
+ if (e.properties) for (let [n, i] of Object.entries(e.properties)) n in o || (o[n] = r(i, t));
21
+ e.allOf?.forEach((e) => i(e, t, a, o)), e.anyOf?.forEach((e) => i(e, t, a, o)), e.oneOf?.forEach((e) => i(e, t, a, o)), i(e.if, t, a, o), i(e.then, t, a, o), i(e.else, t, a, o);
22
+ }
23
+ }
24
+ function a(e) {
25
+ let t = {};
26
+ return e && i(e, e.definitions, /* @__PURE__ */ new Set(), t), t;
27
+ }
28
+ //#endregion
29
+ export { a as collectTopLevelProperties };
30
+
31
+ //# sourceMappingURL=collectTopLevelProperties.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collectTopLevelProperties.js","names":[],"sources":["../../../src/utils/jsonschema/collectTopLevelProperties.ts"],"sourcesContent":["import { JSONSchema7, JSONSchema7Definition } from 'json-schema'\n\nconst DEFINITIONS_PREFIX = '#/definitions/'\n\ntype Definitions = NonNullable<JSONSchema7['definitions']>\ntype TopLevelProperties = Record<string, JSONSchema7Definition>\n\n/**\n * Given a full `#/definitions/X` reference, return the relative key (`X`) used in the definitions\n * map. A reference that is already a bare key is returned as-is.\n */\nfunction getRelativeRef(ref: string): string {\n return ref.startsWith(DEFINITIONS_PREFIX)\n ? ref.substring(DEFINITIONS_PREFIX.length)\n : ref\n}\n\nfunction resolveRef(\n ref: string,\n definitions: Definitions | undefined,\n): JSONSchema7 | undefined {\n const resolved = definitions?.[getRelativeRef(ref)]\n // A boolean schema (`true`/`false`) carries no properties to collect\n return typeof resolved === 'object' ? resolved : undefined\n}\n\n/**\n * Resolve a property value: if it is a `$ref` it is replaced with the referenced schema. A dangling\n * or unresolvable `$ref` returns the raw node so the property name is preserved with an unknown type.\n */\nfunction resolveProperty(\n property: JSONSchema7Definition,\n definitions: Definitions | undefined,\n): JSONSchema7Definition {\n if (typeof property !== 'object' || !property.$ref) {\n return property\n }\n return resolveRef(property.$ref, definitions) ?? property\n}\n\nfunction collect(\n node: JSONSchema7Definition | undefined,\n definitions: Definitions | undefined,\n visitedRefs: Set<string>,\n result: TopLevelProperties,\n): void {\n if (typeof node !== 'object') {\n return\n }\n\n // Follow a combination $ref to the schema it references. Nothing else on a $ref node contributes.\n if (node.$ref) {\n if (visitedRefs.has(node.$ref)) {\n return\n }\n visitedRefs.add(node.$ref)\n collect(\n resolveRef(node.$ref, definitions),\n definitions,\n visitedRefs,\n result,\n )\n return\n }\n\n if (node.properties) {\n for (const [name, propertySchema] of Object.entries(node.properties)) {\n if (!(name in result)) {\n result[name] = resolveProperty(propertySchema, definitions)\n }\n }\n }\n\n // Recurse through combination keywords in a fixed, deterministic order.\n node.allOf?.forEach(member =>\n collect(member, definitions, visitedRefs, result),\n )\n node.anyOf?.forEach(member =>\n collect(member, definitions, visitedRefs, result),\n )\n node.oneOf?.forEach(member =>\n collect(member, definitions, visitedRefs, result),\n )\n collect(node.if, definitions, visitedRefs, result)\n collect(node.then, definitions, visitedRefs, result)\n collect(node.else, definitions, visitedRefs, result)\n}\n\n/**\n * Collects the names that could appear as a top-level property of an instance validated by the given\n * JSON Schema, keyed by property name. Each value is the `$ref`-resolved schema for that property.\n *\n * The walk follows schema combination keywords (`$ref`, `allOf`, `anyOf`, `oneOf`, `if`, `then`,\n * `else`) so that properties declared in referenced or composed sub-schemas are included. It does\n * NOT descend into a property's own value, `items`, `contains`, `additionalProperties`, or `not`, so\n * the nested properties of an object or the elements of an array are never surfaced as top-level\n * properties.\n *\n * Insertion order is the order in which properties were first encountered, and the first occurrence\n * of a name wins -- so a schema's own properties take precedence over composed/inherited ones.\n *\n * This mirrors the backend's `JsonSchemaProperties.collectTopLevelProperties`, which is what defines\n * a RecordSet's schema columns. Only draft-07 `definitions` references are resolved (not `$defs`),\n * matching that implementation.\n */\nexport function collectTopLevelProperties(\n root: JSONSchema7 | undefined,\n): TopLevelProperties {\n const result: TopLevelProperties = {}\n if (!root) {\n return result\n }\n collect(root, root.definitions, new Set<string>(), result)\n return result\n}\n"],"mappings":";AAEA,IAAM,IAAqB;AAS3B,SAAS,EAAe,GAAqB;CAC3C,OAAO,EAAI,WAAW,CAAkB,IACpC,EAAI,UAAU,EAAyB,IACvC;AACN;AAEA,SAAS,EACP,GACA,GACyB;CACzB,IAAM,IAAW,IAAc,EAAe,CAAG;CAEjD,OAAO,OAAO,KAAa,WAAW,IAAW,KAAA;AACnD;AAMA,SAAS,EACP,GACA,GACuB;CAIvB,OAHI,OAAO,KAAa,YAAY,CAAC,EAAS,OACrC,IAEF,EAAW,EAAS,MAAM,CAAW,KAAK;AACnD;AAEA,SAAS,EACP,GACA,GACA,GACA,GACM;CACF,WAAO,KAAS,UAKpB;MAAI,EAAK,MAAM;GACb,IAAI,EAAY,IAAI,EAAK,IAAI,GAC3B;GAGF,AADA,EAAY,IAAI,EAAK,IAAI,GACzB,EACE,EAAW,EAAK,MAAM,CAAW,GACjC,GACA,GACA,CACF;GACA;EACF;EAEA,IAAI,EAAK,iBACF,IAAM,CAAC,GAAM,MAAmB,OAAO,QAAQ,EAAK,UAAU,GACjE,AAAM,KAAQ,MACZ,EAAO,KAAQ,EAAgB,GAAgB,CAAW;EAiBhE,AAXA,EAAK,OAAO,SAAQ,MAClB,EAAQ,GAAQ,GAAa,GAAa,CAAM,CAClD,GACA,EAAK,OAAO,SAAQ,MAClB,EAAQ,GAAQ,GAAa,GAAa,CAAM,CAClD,GACA,EAAK,OAAO,SAAQ,MAClB,EAAQ,GAAQ,GAAa,GAAa,CAAM,CAClD,GACA,EAAQ,EAAK,IAAI,GAAa,GAAa,CAAM,GACjD,EAAQ,EAAK,MAAM,GAAa,GAAa,CAAM,GACnD,EAAQ,EAAK,MAAM,GAAa,GAAa,CAAM;CAtBnD;AAuBF;AAmBA,SAAgB,EACd,GACoB;CACpB,IAAM,IAA6B,CAAC;CAKpC,OAJK,KAGL,EAAQ,GAAM,EAAK,6BAAa,IAAI,IAAY,GAAG,CAAM,GAFhD;AAIX"}
@@ -1 +1 @@
1
- {"version":3,"file":"getSchemaPropertyInfo.d.ts","sourceRoot":"","sources":["../../../src/utils/jsonschema/getSchemaPropertyInfo.ts"],"names":[],"mappings":"AAAA,OAA4B,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAG5E,OAAO,EAAE,YAAY,EAAmB,MAAM,WAAW,CAAA;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEzC,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,YAAY,GAAG,SAAS,CAAA;IAC9B,UAAU,EAAE,OAAO,CAAA;IACnB,gBAAgB,EAAE,eAAe,EAAE,GAAG,IAAI,CAAA;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,CAAC,YAAY,EAAE,MAAM,GAAG,kBAAkB,CAAA;CAC3C;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,WAAW,GAAG,IAAI,GACzB,mBAAmB,CAyCrB"}
1
+ {"version":3,"file":"getSchemaPropertyInfo.d.ts","sourceRoot":"","sources":["../../../src/utils/jsonschema/getSchemaPropertyInfo.ts"],"names":[],"mappings":"AAAA,OAA4B,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAG5E,OAAO,EAAE,YAAY,EAAmB,MAAM,WAAW,CAAA;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEzC,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,YAAY,GAAG,SAAS,CAAA;IAC9B,UAAU,EAAE,OAAO,CAAA;IACnB,gBAAgB,EAAE,eAAe,EAAE,GAAG,IAAI,CAAA;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,CAAC,YAAY,EAAE,MAAM,GAAG,kBAAkB,CAAA;CAC3C;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,WAAW,GAAG,IAAI,GACzB,mBAAmB,CAqCrB"}
@@ -8,7 +8,7 @@ function i(i) {
8
8
  let a = t(i), o = {};
9
9
  return i.properties && Object.keys(i.properties).forEach((t) => {
10
10
  let s = n(i, t), c = r(s), l = e(s).map((e) => e.value);
11
- l.length === 0 && s && s.items && (l = e(Array.isArray(s.items) ? s.items[0] : s.items).map((e) => e.value)), o[t] = {
11
+ l.length === 0 && s?.items && (l = e(Array.isArray(s.items) ? s.items[0] : s.items).map((e) => e.value)), o[t] = {
12
12
  type: c,
13
13
  isRequired: a.includes(t),
14
14
  enumeratedValues: l.length > 0 ? l : null,
@@ -1 +1 @@
1
- {"version":3,"file":"getSchemaPropertyInfo.js","names":[],"sources":["../../../src/utils/jsonschema/getSchemaPropertyInfo.ts"],"sourcesContent":["import getEnumeratedValues, { EnumeratedValue } from './getEnumeratedValues'\nimport getSchemaForProperty from './getSchemaForProperty'\nimport getRequiredAttributes from './getRequiredAttributes'\nimport { FlatTypeInfo, getFlatTypeInfo } from './getType'\nimport { JSONSchema7 } from 'json-schema'\n\nexport interface SchemaPropertyInfo {\n type: FlatTypeInfo | undefined\n isRequired: boolean\n enumeratedValues: EnumeratedValue[] | null\n description?: string\n}\n\nexport interface SchemaPropertiesMap {\n [propertyName: string]: SchemaPropertyInfo\n}\n\n/**\n * Processes a JSON schema once and returns information for all properties\n * @param schema The JSON schema to process\n * @returns A map of property names to their schema information\n */\nexport function getSchemaPropertiesInfo(\n schema: JSONSchema7 | null,\n): SchemaPropertiesMap {\n if (!schema) {\n return {}\n }\n\n const requiredFields = getRequiredAttributes(schema)\n const propertiesMap: SchemaPropertiesMap = {}\n\n // Process each property in the schema\n if (schema.properties) {\n Object.keys(schema.properties).forEach(propertyName => {\n const propertySchema = getSchemaForProperty(schema, propertyName)\n const type = getFlatTypeInfo(propertySchema)\n let enumeratedValues = getEnumeratedValues(propertySchema).map(\n item => item.value,\n )\n\n // Check for nested enums in array items\n if (\n enumeratedValues.length === 0 &&\n propertySchema &&\n propertySchema.items\n ) {\n const itemsSchema = Array.isArray(propertySchema.items)\n ? propertySchema.items[0]\n : propertySchema.items\n enumeratedValues = getEnumeratedValues(itemsSchema).map(\n item => item.value,\n )\n }\n\n propertiesMap[propertyName] = {\n type,\n isRequired: requiredFields.includes(propertyName),\n enumeratedValues: enumeratedValues.length > 0 ? enumeratedValues : null,\n description: propertySchema?.description,\n }\n })\n }\n\n return propertiesMap\n}\n"],"mappings":";;;;;AAsBA,SAAgB,EACd,GACqB;CACrB,IAAI,CAAC,GACH,OAAO,CAAC;CAGV,IAAM,IAAiB,EAAsB,CAAM,GAC7C,IAAqC,CAAC;CAkC5C,OA/BI,EAAO,cACT,OAAO,KAAK,EAAO,UAAU,EAAE,SAAQ,MAAgB;EACrD,IAAM,IAAiB,EAAqB,GAAQ,CAAY,GAC1D,IAAO,EAAgB,CAAc,GACvC,IAAmB,EAAoB,CAAc,EAAE,KACzD,MAAQ,EAAK,KACf;EAgBA,AAZE,EAAiB,WAAW,KAC5B,KACA,EAAe,UAKf,IAAmB,EAHC,MAAM,QAAQ,EAAe,KAAK,IAClD,EAAe,MAAM,KACrB,EAAe,KAC+B,EAAE,KAClD,MAAQ,EAAK,KACf,IAGF,EAAc,KAAgB;GAC5B;GACA,YAAY,EAAe,SAAS,CAAY;GAChD,kBAAkB,EAAiB,SAAS,IAAI,IAAmB;GACnE,aAAa,GAAgB;EAC/B;CACF,CAAC,GAGI;AACT"}
1
+ {"version":3,"file":"getSchemaPropertyInfo.js","names":[],"sources":["../../../src/utils/jsonschema/getSchemaPropertyInfo.ts"],"sourcesContent":["import getEnumeratedValues, { EnumeratedValue } from './getEnumeratedValues'\nimport getSchemaForProperty from './getSchemaForProperty'\nimport getRequiredAttributes from './getRequiredAttributes'\nimport { FlatTypeInfo, getFlatTypeInfo } from './getType'\nimport { JSONSchema7 } from 'json-schema'\n\nexport interface SchemaPropertyInfo {\n type: FlatTypeInfo | undefined\n isRequired: boolean\n enumeratedValues: EnumeratedValue[] | null\n description?: string\n}\n\nexport interface SchemaPropertiesMap {\n [propertyName: string]: SchemaPropertyInfo\n}\n\n/**\n * Processes a JSON schema once and returns information for all properties\n * @param schema The JSON schema to process\n * @returns A map of property names to their schema information\n */\nexport function getSchemaPropertiesInfo(\n schema: JSONSchema7 | null,\n): SchemaPropertiesMap {\n if (!schema) {\n return {}\n }\n\n const requiredFields = getRequiredAttributes(schema)\n const propertiesMap: SchemaPropertiesMap = {}\n\n // Process each property in the schema\n if (schema.properties) {\n Object.keys(schema.properties).forEach(propertyName => {\n const propertySchema = getSchemaForProperty(schema, propertyName)\n const type = getFlatTypeInfo(propertySchema)\n let enumeratedValues = getEnumeratedValues(propertySchema).map(\n item => item.value,\n )\n\n // Check for nested enums in array items\n if (enumeratedValues.length === 0 && propertySchema?.items) {\n const itemsSchema = Array.isArray(propertySchema.items)\n ? propertySchema.items[0]\n : propertySchema.items\n enumeratedValues = getEnumeratedValues(itemsSchema).map(\n item => item.value,\n )\n }\n\n propertiesMap[propertyName] = {\n type,\n isRequired: requiredFields.includes(propertyName),\n enumeratedValues: enumeratedValues.length > 0 ? enumeratedValues : null,\n description: propertySchema?.description,\n }\n })\n }\n\n return propertiesMap\n}\n"],"mappings":";;;;;AAsBA,SAAgB,EACd,GACqB;CACrB,IAAI,CAAC,GACH,OAAO,CAAC;CAGV,IAAM,IAAiB,EAAsB,CAAM,GAC7C,IAAqC,CAAC;CA8B5C,OA3BI,EAAO,cACT,OAAO,KAAK,EAAO,UAAU,EAAE,SAAQ,MAAgB;EACrD,IAAM,IAAiB,EAAqB,GAAQ,CAAY,GAC1D,IAAO,EAAgB,CAAc,GACvC,IAAmB,EAAoB,CAAc,EAAE,KACzD,MAAQ,EAAK,KACf;EAYA,AATI,EAAiB,WAAW,KAAK,GAAgB,UAInD,IAAmB,EAHC,MAAM,QAAQ,EAAe,KAAK,IAClD,EAAe,MAAM,KACrB,EAAe,KAC+B,EAAE,KAClD,MAAQ,EAAK,KACf,IAGF,EAAc,KAAgB;GAC5B;GACA,YAAY,EAAe,SAAS,CAAY;GAChD,kBAAkB,EAAiB,SAAS,IAAI,IAAmB;GACnE,aAAa,GAAgB;EAC/B;CACF,CAAC,GAGI;AACT"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synapse-react-client",
3
- "version": "4.0.36",
3
+ "version": "4.0.37",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -119,9 +119,9 @@
119
119
  "xss": "^1.0.15",
120
120
  "zod": "^4.4.3",
121
121
  "@sage-bionetworks/synapse-client": "0.0.23",
122
- "@sage-bionetworks/synapse-types": "0.0.9",
123
122
  "@sage-bionetworks/markdown-it-container": "4.0.1",
124
123
  "@sage-bionetworks/react-datasheet-grid": "4.11.5-sage.9",
124
+ "@sage-bionetworks/synapse-types": "0.0.9",
125
125
  "markdown-it-synapse": "2.0.0",
126
126
  "markdown-it-synapse-table": "1.0.8"
127
127
  },
@@ -219,8 +219,8 @@
219
219
  "vitest-when": "^0.10.0",
220
220
  "weak-napi": "^2.0.2",
221
221
  "whatwg-fetch": "^3.6.20",
222
- "vite-config": "0.0.0",
223
- "@sage-bionetworks/aridhia-client": "0.0.1"
222
+ "@sage-bionetworks/aridhia-client": "0.0.1",
223
+ "vite-config": "0.0.0"
224
224
  },
225
225
  "nx": {
226
226
  "targets": {