synapse-react-client 4.0.9 → 4.0.11

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 (613) hide show
  1. package/dist/SWC.index.d.ts +1 -0
  2. package/dist/SWC.index.d.ts.map +1 -1
  3. package/dist/SWC.index.js +2 -1
  4. package/dist/SWC.index.js.map +1 -1
  5. package/dist/aridhia-queries/aridhiaTokenExchange.js.map +1 -1
  6. package/dist/aridhia-queries/useGetAridhiaRequests.js.map +1 -1
  7. package/dist/assets/icons/CloudWarning.d.ts +5 -0
  8. package/dist/assets/icons/CloudWarning.d.ts.map +1 -0
  9. package/dist/assets/icons/CloudWarning.js +47 -0
  10. package/dist/assets/icons/CloudWarning.js.map +1 -0
  11. package/dist/assets/icons/TasksIcon.d.ts.map +1 -1
  12. package/dist/assets/icons/TasksIcon.js +6 -10
  13. package/dist/assets/icons/TasksIcon.js.map +1 -1
  14. package/dist/components/AccessRequirementAclEditor/AccessRequirementAclEditor.d.ts.map +1 -1
  15. package/dist/components/AccessRequirementAclEditor/AccessRequirementAclEditor.js +69 -63
  16. package/dist/components/AccessRequirementAclEditor/AccessRequirementAclEditor.js.map +1 -1
  17. package/dist/components/AccessRequirementList/AccessApprovalCheckMark.js.map +1 -1
  18. package/dist/components/AccessRequirementList/AccessRequirementList.js.map +1 -1
  19. package/dist/components/AccessRequirementList/AccessRequirementListUtils.js.map +1 -1
  20. package/dist/components/AccessRequirementList/ManagedACTAccessRequirementRequestFlow/DataAccessRequestAccessorsEditor.js.map +1 -1
  21. package/dist/components/AccessRequirementList/RequirementItem/SelfSignAccessRequirementItem.js.map +1 -1
  22. package/dist/components/AccessRequirementRelatedProjectsList/AccessRequirementRelatedProjectsList.js.map +1 -1
  23. package/dist/components/AccessTokenPage/AccessTokenCard/AccessTokenCard.js.map +1 -1
  24. package/dist/components/AcknowledgementsPage/StudyAcknowledgements.js.map +1 -1
  25. package/dist/components/AclEditor/PermissionLevelMenu.js.map +1 -1
  26. package/dist/components/AclEditor/ResourceAccessAndUserGroupHeader.js.map +1 -1
  27. package/dist/components/AclEditor/useSortResourceAccessList.js.map +1 -1
  28. package/dist/components/AclEditor/useUpdateAcl.js.map +1 -1
  29. package/dist/components/Aridhia/AridhiaAccessStatus.js.map +1 -1
  30. package/dist/components/Authentication/AuthenticationMethodSelection.d.ts.map +1 -1
  31. package/dist/components/Authentication/AuthenticationMethodSelection.js +38 -37
  32. package/dist/components/Authentication/AuthenticationMethodSelection.js.map +1 -1
  33. package/dist/components/Authentication/Constants.d.ts +1 -0
  34. package/dist/components/Authentication/Constants.d.ts.map +1 -1
  35. package/dist/components/Authentication/Constants.js +2 -2
  36. package/dist/components/Authentication/Constants.js.map +1 -1
  37. package/dist/components/Authentication/LastLoginInfo.js.map +1 -1
  38. package/dist/components/Authentication/RecoveryCodeForm.js.map +1 -1
  39. package/dist/components/Authentication/RecoveryCodeGrid.js.map +1 -1
  40. package/dist/components/Authentication/RegenerateBackupCodesWarning.js.map +1 -1
  41. package/dist/components/Authentication/Reset2FAWarning.js.map +1 -1
  42. package/dist/components/Authentication/StandaloneLoginForm.js +1 -1
  43. package/dist/components/Authentication/TwoFactorBackupCodes.js.map +1 -1
  44. package/dist/components/Authentication/TwoFactorEnrollmentForm.d.ts.map +1 -1
  45. package/dist/components/Authentication/TwoFactorEnrollmentForm.js +2 -1
  46. package/dist/components/Authentication/TwoFactorEnrollmentForm.js.map +1 -1
  47. package/dist/components/BasePortalCard/ColorfulPortalCardWithChips/ColorfulPortalCardWithChips.js.map +1 -1
  48. package/dist/components/CardContainer/CardContainer.js.map +1 -1
  49. package/dist/components/CardDeck/CardDeck.Mobile.js.map +1 -1
  50. package/dist/components/CardDeck/TableQueryCardDeck.js.map +1 -1
  51. package/dist/components/CertificationQuiz/CertificationQuiz.js.map +1 -1
  52. package/dist/components/ChallengeDataDownload/ChallengeDataDownload.js.map +1 -1
  53. package/dist/components/ChallengeSubmission/ChallengeSubmission.js.map +1 -1
  54. package/dist/components/ChallengeSubmission/ChallengeSubmissionStepper.js.map +1 -1
  55. package/dist/components/ChallengeSubmission/EvaluationQueueCurrentRoundInfo.js.map +1 -1
  56. package/dist/components/ChallengeSubmission/EvaluationQueueList.js.map +1 -1
  57. package/dist/components/ChallengeSubmission/SubmissionDirectoryList.d.ts.map +1 -1
  58. package/dist/components/ChallengeSubmission/SubmissionDirectoryList.js +143 -140
  59. package/dist/components/ChallengeSubmission/SubmissionDirectoryList.js.map +1 -1
  60. package/dist/components/ChallengeTeamWizard/ChallengeTeamWizard.js.map +1 -1
  61. package/dist/components/ChallengeTeamWizard/CreateChallengeTeam.js.map +1 -1
  62. package/dist/components/ChangePassword/ChangePassword.js.map +1 -1
  63. package/dist/components/ChangePassword/ChangePasswordWithToken.js.map +1 -1
  64. package/dist/components/ChangePassword/useChangePasswordFormState.js +1 -1
  65. package/dist/components/ChangePassword/useChangePasswordFormState.js.map +1 -1
  66. package/dist/components/CitationPopover/CitationPopoverContent.js.map +1 -1
  67. package/dist/components/ColumnFilter/ColumnFilter.js.map +1 -1
  68. package/dist/components/ComponentCollapse.js.map +1 -1
  69. package/dist/components/CookiesNotification/CookiesNotification.js.map +1 -1
  70. package/dist/components/CreateProjectModal/CreateProjectModal.js.map +1 -1
  71. package/dist/components/CreateTableViewWizard/CreateTableViewWizardUtils.js.map +1 -1
  72. package/dist/components/DataGrid/DataGrid.d.ts +0 -1
  73. package/dist/components/DataGrid/DataGrid.d.ts.map +1 -1
  74. package/dist/components/DataGrid/DataGrid.js +72 -72
  75. package/dist/components/DataGrid/DataGrid.js.map +1 -1
  76. package/dist/components/DataGrid/DataGridWebSocket.d.ts +4 -0
  77. package/dist/components/DataGrid/DataGridWebSocket.d.ts.map +1 -1
  78. package/dist/components/DataGrid/DataGridWebSocket.js +9 -8
  79. package/dist/components/DataGrid/DataGridWebSocket.js.map +1 -1
  80. package/dist/components/DataGrid/SynapseGrid.d.ts.map +1 -1
  81. package/dist/components/DataGrid/SynapseGrid.js +326 -268
  82. package/dist/components/DataGrid/SynapseGrid.js.map +1 -1
  83. package/dist/components/DataGrid/columns/AutocompleteColumn.d.ts +2 -0
  84. package/dist/components/DataGrid/columns/AutocompleteColumn.d.ts.map +1 -1
  85. package/dist/components/DataGrid/columns/AutocompleteColumn.js +124 -67
  86. package/dist/components/DataGrid/columns/AutocompleteColumn.js.map +1 -1
  87. package/dist/components/DataGrid/columns/AutocompleteMultipleEnumColumn.d.ts +2 -1
  88. package/dist/components/DataGrid/columns/AutocompleteMultipleEnumColumn.d.ts.map +1 -1
  89. package/dist/components/DataGrid/columns/AutocompleteMultipleEnumColumn.js +126 -122
  90. package/dist/components/DataGrid/columns/AutocompleteMultipleEnumColumn.js.map +1 -1
  91. package/dist/components/DataGrid/columns/useGridAutocompleteState.d.ts +58 -0
  92. package/dist/components/DataGrid/columns/useGridAutocompleteState.d.ts.map +1 -0
  93. package/dist/components/DataGrid/columns/useGridAutocompleteState.js +52 -0
  94. package/dist/components/DataGrid/columns/useGridAutocompleteState.js.map +1 -0
  95. package/dist/components/DataGrid/components/ValidationAlert.d.ts +5 -2
  96. package/dist/components/DataGrid/components/ValidationAlert.d.ts.map +1 -1
  97. package/dist/components/DataGrid/components/ValidationAlert.js +429 -24
  98. package/dist/components/DataGrid/components/ValidationAlert.js.map +1 -1
  99. package/dist/components/DataGrid/hooks/useColumnResizeHandles.js.map +1 -1
  100. package/dist/components/DataGrid/hooks/useGetSchemaForGrid.js.map +1 -1
  101. package/dist/components/DataGrid/hooks/useGridUndoRedo.js.map +1 -1
  102. package/dist/components/DataGrid/hooks/useStack.js.map +1 -1
  103. package/dist/components/DataGrid/useCRDTModelView.js.map +1 -1
  104. package/dist/components/DataGrid/useDataGridWebsocket.d.ts +7 -0
  105. package/dist/components/DataGrid/useDataGridWebsocket.d.ts.map +1 -1
  106. package/dist/components/DataGrid/useDataGridWebsocket.js +16 -2
  107. package/dist/components/DataGrid/useDataGridWebsocket.js.map +1 -1
  108. package/dist/components/DataGrid/useInitializeGridConnection.js.map +1 -1
  109. package/dist/components/DataGrid/useMergeGridWithRecordSet.js.map +1 -1
  110. package/dist/components/DataGrid/useMergeGridWithSource.js.map +1 -1
  111. package/dist/components/DataGrid/useMergeGridWithTable.js.map +1 -1
  112. package/dist/components/DataGrid/utils/DataGridUtils.js.map +1 -1
  113. package/dist/components/DataGrid/utils/applyModelChange.d.ts +1 -1
  114. package/dist/components/DataGrid/utils/applyModelChange.d.ts.map +1 -1
  115. package/dist/components/DataGrid/utils/applyModelChange.js +27 -24
  116. package/dist/components/DataGrid/utils/applyModelChange.js.map +1 -1
  117. package/dist/components/DataGrid/utils/columnFactory.d.ts +8 -0
  118. package/dist/components/DataGrid/utils/columnFactory.d.ts.map +1 -1
  119. package/dist/components/DataGrid/utils/columnFactory.js +47 -44
  120. package/dist/components/DataGrid/utils/columnFactory.js.map +1 -1
  121. package/dist/components/DataGrid/utils/computeReplicaSelectionModel.js.map +1 -1
  122. package/dist/components/DataGrid/utils/extractColumnValidationMessages.js.map +1 -1
  123. package/dist/components/DataGrid/utils/getCellClassName.d.ts.map +1 -1
  124. package/dist/components/DataGrid/utils/getCellClassName.js +8 -8
  125. package/dist/components/DataGrid/utils/getCellClassName.js.map +1 -1
  126. package/dist/components/DataGrid/utils/getEmptyValue.d.ts +2 -0
  127. package/dist/components/DataGrid/utils/getEmptyValue.d.ts.map +1 -0
  128. package/dist/components/DataGrid/utils/getEmptyValue.js +8 -0
  129. package/dist/components/DataGrid/utils/getEmptyValue.js.map +1 -0
  130. package/dist/components/DataGrid/utils/json-rx/JsonRx.js.map +1 -1
  131. package/dist/components/DataGrid/utils/modelColsToGrid.d.ts.map +1 -1
  132. package/dist/components/DataGrid/utils/modelColsToGrid.js +2 -1
  133. package/dist/components/DataGrid/utils/modelColsToGrid.js.map +1 -1
  134. package/dist/components/DataGrid/utils/modelRowsToGrid.js.map +1 -1
  135. package/dist/components/DataGrid/utils/parseFreeTextUsingJsonSchemaType.js.map +1 -1
  136. package/dist/components/DataGrid/utils/schemaAwarePasteValue.d.ts +32 -0
  137. package/dist/components/DataGrid/utils/schemaAwarePasteValue.d.ts.map +1 -0
  138. package/dist/components/DataGrid/utils/schemaAwarePasteValue.js +22 -0
  139. package/dist/components/DataGrid/utils/schemaAwarePasteValue.js.map +1 -0
  140. package/dist/components/DataGrid/utils/splitPatch.js.map +1 -1
  141. package/dist/components/DateTimePicker/DateTimePicker.js.map +1 -1
  142. package/dist/components/DirectDownload/DirectDownload.js.map +1 -1
  143. package/dist/components/DirectDownloadButton.js.map +1 -1
  144. package/dist/components/DownloadCart/CreatePackageV2.js.map +1 -1
  145. package/dist/components/DownloadCart/DownloadIneligibleForPackagingFilesFromListButton.css +1 -0
  146. package/dist/components/DownloadCart/DownloadIneligibleForPackagingFilesFromListButton.d.ts.map +1 -1
  147. package/dist/components/DownloadCart/DownloadIneligibleForPackagingFilesFromListButton.js +199 -132
  148. package/dist/components/DownloadCart/DownloadIneligibleForPackagingFilesFromListButton.js.map +1 -1
  149. package/dist/components/DownloadCart/DownloadIneligibleForPackagingFilesFromListButton.module.js +22 -0
  150. package/dist/components/DownloadCart/DownloadIneligibleForPackagingFilesFromListButton.module.js.map +1 -0
  151. package/dist/components/DownloadCart/DownloadIneligibleForPackagingFilesFromListButton.module.scss +170 -0
  152. package/dist/components/DownloadCart/DownloadListActionsRequired.js.map +1 -1
  153. package/dist/components/DownloadCart/DownloadListTable.js.map +1 -1
  154. package/dist/components/DownloadCart/fileNameUtils.js.map +1 -1
  155. package/dist/components/DraggableDialog/DraggableDialog.js.map +1 -1
  156. package/dist/components/DynamicForm/DynamicFormModal.js.map +1 -1
  157. package/dist/components/Ecosystem/TableQueryEcosystem.js.map +1 -1
  158. package/dist/components/EntityAclEditor/EntityAclEditor.d.ts.map +1 -1
  159. package/dist/components/EntityAclEditor/EntityAclEditor.js +103 -103
  160. package/dist/components/EntityAclEditor/EntityAclEditor.js.map +1 -1
  161. package/dist/components/EntityAclEditor/useNotifyNewACLUsers.js.map +1 -1
  162. package/dist/components/EntityBadgeIcons/EntityBadgeIcons.js.map +1 -1
  163. package/dist/components/EntityCitation/EntityCitation.js.map +1 -1
  164. package/dist/components/EntityDownloadButton/EntityDownloadButton.d.ts.map +1 -1
  165. package/dist/components/EntityDownloadButton/EntityDownloadButton.js +1 -0
  166. package/dist/components/EntityDownloadButton/EntityDownloadButton.js.map +1 -1
  167. package/dist/components/EntityDownloadConfirmation/EntityDownloadConfirmation.d.ts.map +1 -1
  168. package/dist/components/EntityDownloadConfirmation/EntityDownloadConfirmation.js +36 -30
  169. package/dist/components/EntityDownloadConfirmation/EntityDownloadConfirmation.js.map +1 -1
  170. package/dist/components/EntityFinder/EntityFinder.js.map +1 -1
  171. package/dist/components/EntityFinder/VersionSelectionType.js.map +1 -1
  172. package/dist/components/EntityFinder/details/configurations/EntityChildrenDetails.js.map +1 -1
  173. package/dist/components/EntityFinder/details/configurations/FavoritesDetails.js.map +1 -1
  174. package/dist/components/EntityFinder/details/configurations/ProjectListDetails.js.map +1 -1
  175. package/dist/components/EntityFinder/details/view/DetailsView.js.map +1 -1
  176. package/dist/components/EntityFinder/tree/EntityTree.js.map +1 -1
  177. package/dist/components/EntityFinder/tree/VirtualizedTree.js.map +1 -1
  178. package/dist/components/EntityFinder/useEntitySelection.js.map +1 -1
  179. package/dist/components/EntityForm/EntityForm.js.map +1 -1
  180. package/dist/components/EntityHeaderTable/EntityHeaderTable.js.map +1 -1
  181. package/dist/components/EntityHeaderTable/Filter.js.map +1 -1
  182. package/dist/components/EntityHeaderTable/useEntityHeaderTableState.js.map +1 -1
  183. package/dist/components/EntitySubjectsSelector/EntitySubjectsSelector.js.map +1 -1
  184. package/dist/components/EntityTreeTable/components/IdColumnHeader.js.map +1 -1
  185. package/dist/components/EntityTreeTable/hooks/useEntityTreeState.js.map +1 -1
  186. package/dist/components/EntityTreeTable/hooks/useTableColumns.js.map +1 -1
  187. package/dist/components/EntityTreeTable/hooks/useTableData.js.map +1 -1
  188. package/dist/components/EntityTreeTable/hooks/useTreeOperationsWithDirectFetch.js.map +1 -1
  189. package/dist/components/EntityUpload/EntityUpload.js.map +1 -1
  190. package/dist/components/EntityViewScopeEditor/EntityViewMaskEditor.d.ts.map +1 -1
  191. package/dist/components/EntityViewScopeEditor/EntityViewMaskEditor.js +15 -14
  192. package/dist/components/EntityViewScopeEditor/EntityViewMaskEditor.js.map +1 -1
  193. package/dist/components/ExperimentalMode/ExperimentalMode.js.map +1 -1
  194. package/dist/components/ExternalFileHandleLink/ExternalFileHandleLink.js.map +1 -1
  195. package/dist/components/FeaturedDataTabs/FacetPlotsCard.js.map +1 -1
  196. package/dist/components/FeaturedDataTabs/QueryPerFacetPlotsCard.js.map +1 -1
  197. package/dist/components/FeaturedDataTabs/SingleQueryFacetPlotsCards.js.map +1 -1
  198. package/dist/components/FeaturedResearch/FeaturedResearch.js.map +1 -1
  199. package/dist/components/FeaturedToolsList/FeaturedToolsList.js.map +1 -1
  200. package/dist/components/FilePreview/FileHandleContentRenderer.js.map +1 -1
  201. package/dist/components/FilePreview/HtmlPreview/HtmlPreview.js.map +1 -1
  202. package/dist/components/FilePreview/PreviewRendererType.js.map +1 -1
  203. package/dist/components/Forum/DiscussionReply.d.ts +1 -0
  204. package/dist/components/Forum/DiscussionReply.d.ts.map +1 -1
  205. package/dist/components/Forum/DiscussionReply.js +19 -19
  206. package/dist/components/Forum/DiscussionReply.js.map +1 -1
  207. package/dist/components/Forum/DiscussionSearchResult.js.map +1 -1
  208. package/dist/components/Forum/DiscussionThread.d.ts +1 -0
  209. package/dist/components/Forum/DiscussionThread.d.ts.map +1 -1
  210. package/dist/components/Forum/DiscussionThread.js +73 -72
  211. package/dist/components/Forum/DiscussionThread.js.map +1 -1
  212. package/dist/components/Forum/ForumTable.js.map +1 -1
  213. package/dist/components/Forum/ForumThreadEditor.js.map +1 -1
  214. package/dist/components/FullTextSearch/FullTextSearchUtils.js.map +1 -1
  215. package/dist/components/GenericCard/BioregistryRules.d.ts.map +1 -1
  216. package/dist/components/GenericCard/BioregistryRules.js +7 -3
  217. package/dist/components/GenericCard/BioregistryRules.js.map +1 -1
  218. package/dist/components/GenericCard/GenericCard.d.ts.map +1 -1
  219. package/dist/components/GenericCard/GenericCard.js +12 -7
  220. package/dist/components/GenericCard/GenericCard.js.map +1 -1
  221. package/dist/components/GenericCard/Linkify.js.map +1 -1
  222. package/dist/components/GenericCard/SynapseCardLabel.js.map +1 -1
  223. package/dist/components/GenericCard/TableRowGenericCard.js +105 -105
  224. package/dist/components/GenericCard/TableRowGenericCard.js.map +1 -1
  225. package/dist/components/Goals/Goals.Mobile.js.map +1 -1
  226. package/dist/components/Goals/Goals.js.map +1 -1
  227. package/dist/components/GoalsV2/GoalsV2.Mobile.js.map +1 -1
  228. package/dist/components/GoalsV2/GoalsV2.js.map +1 -1
  229. package/dist/components/GoalsV3/GoalsV3.Mobile.js.map +1 -1
  230. package/dist/components/GoalsV3/GoalsV3.js.map +1 -1
  231. package/dist/components/GoogleMap/SynapseUserMarker.js.map +1 -1
  232. package/dist/components/HasAccess/AccessIcon.js.map +1 -1
  233. package/dist/components/HasAccess/useHasAccess.js.map +1 -1
  234. package/dist/components/HeaderCard/HeaderCardV2.js.map +1 -1
  235. package/dist/components/HeaderCard.d.ts +6 -1
  236. package/dist/components/HeaderCard.d.ts.map +1 -1
  237. package/dist/components/HeaderCard.js +107 -76
  238. package/dist/components/HeaderCard.js.map +1 -1
  239. package/dist/components/HexGrid/HexGrid.js.map +1 -1
  240. package/dist/components/IconList.js.map +1 -1
  241. package/dist/components/IconSvg/IconSvg.d.ts.map +1 -1
  242. package/dist/components/IconSvg/IconSvg.js +2 -1
  243. package/dist/components/IconSvg/IconSvg.js.map +1 -1
  244. package/dist/components/ImageCardGridWithLinks/ImageCardGridWithLinks.js.map +1 -1
  245. package/dist/components/ImageFromSynapseTable.js.map +1 -1
  246. package/dist/components/JSONArrayEditor/useParseCsv.js.map +1 -1
  247. package/dist/components/JsonSchemaForm/templates/ArrayFieldDescriptionTemplate.js.map +1 -1
  248. package/dist/components/JsonSchemaForm/templates/ArrayFieldItemTemplate.js.map +1 -1
  249. package/dist/components/JsonSchemaForm/templates/BaseInputTemplate.js.map +1 -1
  250. package/dist/components/JsonSchemaForm/templates/FieldTemplate.js.map +1 -1
  251. package/dist/components/JsonSchemaForm/templates/RJSFInputLabel.js.map +1 -1
  252. package/dist/components/Markdown/MarkdownGithub.js.map +1 -1
  253. package/dist/components/Markdown/MarkdownSynapse.js.map +1 -1
  254. package/dist/components/Markdown/MarkdownUtils.js.map +1 -1
  255. package/dist/components/Markdown/SynapseWikiContext.js.map +1 -1
  256. package/dist/components/Markdown/UserMentionModal.js.map +1 -1
  257. package/dist/components/Markdown/widget/MarkdownProvenanceGraph.js.map +1 -1
  258. package/dist/components/MissingQueryResultsWarning/MissingQueryResultsWarning.js.map +1 -1
  259. package/dist/components/ModalDownload/ModalDownload.js.map +1 -1
  260. package/dist/components/OAuthClientAclEditor/OAuthClientAclEditor.d.ts.map +1 -1
  261. package/dist/components/OAuthClientAclEditor/OAuthClientAclEditor.js +45 -39
  262. package/dist/components/OAuthClientAclEditor/OAuthClientAclEditor.js.map +1 -1
  263. package/dist/components/OAuthClientManagement/OAuthManagement.js.map +1 -1
  264. package/dist/components/PageProgress/PageProgress.js.map +1 -1
  265. package/dist/components/Plot/DotPlot.js.map +1 -1
  266. package/dist/components/Plot/Plot.js.map +1 -1
  267. package/dist/components/Plot/SynapsePlot.js.map +1 -1
  268. package/dist/components/Plot/ThemesPlot.js.map +1 -1
  269. package/dist/components/Plot/UpsetPlot.js.map +1 -1
  270. package/dist/components/PortalAclEditor/PortalAclEditor.d.ts.map +1 -1
  271. package/dist/components/PortalAclEditor/PortalAclEditor.js +43 -41
  272. package/dist/components/PortalAclEditor/PortalAclEditor.js.map +1 -1
  273. package/dist/components/PortalFeaturedPartners/PortalFeaturedPartners.js.map +1 -1
  274. package/dist/components/PortalList/CreatePortalModal.js.map +1 -1
  275. package/dist/components/ProgrammaticInstructionsModal/ProgrammaticInstructionsModal.js.map +1 -1
  276. package/dist/components/ProgrammaticTableDownload/ProgrammaticTableDownload.js.map +1 -1
  277. package/dist/components/Programs/Programs.Mobile.js.map +1 -1
  278. package/dist/components/Programs/Programs.js.map +1 -1
  279. package/dist/components/ProvenanceGraph/ProvenanceExternalIcon.js.map +1 -1
  280. package/dist/components/ProvenanceGraph/ProvenanceGraph.js.map +1 -1
  281. package/dist/components/ProvenanceGraph/ProvenanceGraphUtils.js.map +1 -1
  282. package/dist/components/ProvenanceGraph/ProvenanceUtils.js.map +1 -1
  283. package/dist/components/QueryCount/QueryCount.js.map +1 -1
  284. package/dist/components/QueryCountButton/QueryCountButton.js.map +1 -1
  285. package/dist/components/QueryVisualizationWrapper/QueryVisualizationWrapper.js.map +1 -1
  286. package/dist/components/QueryWrapper/QueryWrapper.js.map +1 -1
  287. package/dist/components/QueryWrapper/TableQueryUseQueryOptions.js.map +1 -1
  288. package/dist/components/QueryWrapper/TableRowSelectionState.js.map +1 -1
  289. package/dist/components/QueryWrapper/generateEncodedPathAndQueryForSelectedFacetURL.js.map +1 -1
  290. package/dist/components/QueryWrapper/useGetQueryMetadata.js.map +1 -1
  291. package/dist/components/QueryWrapperErrorBoundary.js.map +1 -1
  292. package/dist/components/QueryWrapperPlotNav/QueryWrapperPlotNav.js.map +1 -1
  293. package/dist/components/QueryWrapperPlotNav/UseRowSet.js.map +1 -1
  294. package/dist/components/RecentPublicationsGrid/RecentPublicationsGrid.js.map +1 -1
  295. package/dist/components/ReleaseCard/ReleaseCardUtils.js.map +1 -1
  296. package/dist/components/ResizableContainer/hooks/useResizable.js.map +1 -1
  297. package/dist/components/Resources/Resources.Mobile.js.map +1 -1
  298. package/dist/components/Resources/Resources.js.map +1 -1
  299. package/dist/components/RowDataTable/RowDataTableWithQuery.js.map +1 -1
  300. package/dist/components/SageResourcesPopover/SageResourcesPopover.js.map +1 -1
  301. package/dist/components/SchemaDrivenAnnotationEditor/AnnotationEditorUtils.js.map +1 -1
  302. package/dist/components/SetAccessRequirementCommonFields/SetAccessRequirementCommonFields.js.map +1 -1
  303. package/dist/components/SetManagedAccessRequirementFields/SetManagedAccessRequirementFields.js.map +1 -1
  304. package/dist/components/SmartLink/SmartButton.js.map +1 -1
  305. package/dist/components/SmartLink/SmartLink.js.map +1 -1
  306. package/dist/components/SourceAppImage.js.map +1 -1
  307. package/dist/components/StandaloneQueryWrapper/StandaloneQueryWrapper.js.map +1 -1
  308. package/dist/components/StatisticsPlot.js.map +1 -1
  309. package/dist/components/StorybookComponentWrapper.js.map +1 -1
  310. package/dist/components/SubsectionRowRenderer/SubsectionRowRenderer.js.map +1 -1
  311. package/dist/components/SustainabilityScorecard/SustainabilityScorecard.js.map +1 -1
  312. package/dist/components/SynapseChat/GridAgentChat.js.map +1 -1
  313. package/dist/components/SynapseChat/SynapseChatInteraction.js.map +1 -1
  314. package/dist/components/SynapseChat/SynapseChatMessage.js.map +1 -1
  315. package/dist/components/SynapseChat/extractMessageFromTraceEvent.js.map +1 -1
  316. package/dist/components/SynapseForm/StepsSideNav.js.map +1 -1
  317. package/dist/components/SynapseForm/SummaryTable.js.map +1 -1
  318. package/dist/components/SynapseForm/SynapseForm.js +4 -2
  319. package/dist/components/SynapseForm/SynapseForm.js.map +1 -1
  320. package/dist/components/SynapseForm/SynapseFormWrapper.js.map +1 -1
  321. package/dist/components/SynapseHomepageV2/SynapseByTheNumbersItem.js.map +1 -1
  322. package/dist/components/SynapseHomepageV2/SynapseFeatureItem.js.map +1 -1
  323. package/dist/components/SynapseHomepageV2/SynapseHomepageChatSearch.js.map +1 -1
  324. package/dist/components/SynapseHomepageV2/SynapseHomepageSearch.js.map +1 -1
  325. package/dist/components/SynapseHomepageV2/SynapseInActionItem.js.map +1 -1
  326. package/dist/components/SynapseHomepageV2/SynapsePlans.js.map +1 -1
  327. package/dist/components/SynapseHomepageV2/SynapseTrendingProjects.js.map +1 -1
  328. package/dist/components/SynapseNavDrawer/SynapseNavDrawer.d.ts +8 -7
  329. package/dist/components/SynapseNavDrawer/SynapseNavDrawer.d.ts.map +1 -1
  330. package/dist/components/SynapseNavDrawer/SynapseNavDrawer.js +173 -164
  331. package/dist/components/SynapseNavDrawer/SynapseNavDrawer.js.map +1 -1
  332. package/dist/components/SynapsePortalBanners/SynapsePortalBanners.js.map +1 -1
  333. package/dist/components/SynapseSearchPageResults/SearchFacetPanel/SearchFacetPanel.js.map +1 -1
  334. package/dist/components/SynapseSearchPageResults/SearchFacetPanel/SearchFacetPanelUtils.js.map +1 -1
  335. package/dist/components/SynapseSearchPageResults/SynapseSearchPageResults.js.map +1 -1
  336. package/dist/components/SynapseTable/EntityIDColumnCopyIcon.js.map +1 -1
  337. package/dist/components/SynapseTable/NoContentPlaceholderType.js.map +1 -1
  338. package/dist/components/SynapseTable/RowSelection/RowSelectionControls.js.map +1 -1
  339. package/dist/components/SynapseTable/SynapseTableCell/SynapseTableCell.js.map +1 -1
  340. package/dist/components/SynapseTable/SynapseTableRenderers.js.map +1 -1
  341. package/dist/components/SynapseTable/datasets/DatasetItemsEditor.js.map +1 -1
  342. package/dist/components/SynapseTable/table-top/ColumnSelection.js.map +1 -1
  343. package/dist/components/SynapseTable/table-top/DownloadOptions.js.map +1 -1
  344. package/dist/components/SynapseTable/usePrefetchTableData.js.map +1 -1
  345. package/dist/components/TableColumnSchemaEditor/ColumnModelForm.js.map +1 -1
  346. package/dist/components/TableColumnSchemaEditor/ColumnModelFormFields/DefaultValueField.js.map +1 -1
  347. package/dist/components/TableColumnSchemaEditor/ImportTableColumnsButton.js.map +1 -1
  348. package/dist/components/TableColumnSchemaEditor/TableColumnSchemaEditorUtils.d.ts +1 -1
  349. package/dist/components/TableColumnSchemaEditor/TableColumnSchemaEditorUtils.d.ts.map +1 -1
  350. package/dist/components/TableColumnSchemaEditor/TableColumnSchemaEditorUtils.js.map +1 -1
  351. package/dist/components/TableColumnSchemaEditor/TableColumnSchemaForm.js.map +1 -1
  352. package/dist/components/TableColumnSchemaEditor/TableColumnSchemaFormReducer.js.map +1 -1
  353. package/dist/components/TableColumnSchemaEditor/Validators/ColumnModelValidator.js.map +1 -1
  354. package/dist/components/TableColumnSchemaEditor/Validators/DatetimeSchema.js.map +1 -1
  355. package/dist/components/TanStackTable/ColumnHeader.d.ts +1 -0
  356. package/dist/components/TanStackTable/ColumnHeader.d.ts.map +1 -1
  357. package/dist/components/TanStackTable/ColumnHeader.js +8 -8
  358. package/dist/components/TanStackTable/ColumnHeader.js.map +1 -1
  359. package/dist/components/TanStackTable/ColumnHeaderEnumFilter.js.map +1 -1
  360. package/dist/components/TanStackTable/TableBody.js.map +1 -1
  361. package/dist/components/TeamSubjectsSelector/TeamSubjectsSelector.js.map +1 -1
  362. package/dist/components/TextField/TextField.js.map +1 -1
  363. package/dist/components/TimelinePlot/TimelinePhase.js.map +1 -1
  364. package/dist/components/TimelinePlot/TimelinePlot.js.map +1 -1
  365. package/dist/components/TimelinePlot/TimelinePlotSpeciesSelector.js.map +1 -1
  366. package/dist/components/UserCard/Avatar.js.map +1 -1
  367. package/dist/components/UserCardList/UserCardList.js.map +1 -1
  368. package/dist/components/UserCardList/UserCardListGroups/UserCardListGroups.Mobile.js.map +1 -1
  369. package/dist/components/UserCardList/UserCardListRotate.js.map +1 -1
  370. package/dist/components/UserOrTeamBadge/useUserOrTeam.js.map +1 -1
  371. package/dist/components/UserProfileLinks/UserProjects.js.map +1 -1
  372. package/dist/components/UserSearchBox/UserSearchBox.js.map +1 -1
  373. package/dist/components/Webhook/WebhookDashboard.js.map +1 -1
  374. package/dist/components/WikiMarkdownEditor/WikiMarkdownEditor.js.map +1 -1
  375. package/dist/components/WikiMarkdownEditorButton/WikiMarkdownEditorButton.js.map +1 -1
  376. package/dist/components/dataaccess/AccessApprovalsTable.js.map +1 -1
  377. package/dist/components/dataaccess/AccessRequestSubmissionTable.js.map +1 -1
  378. package/dist/components/dataaccess/SubmissionPage/SubmissionPage.d.ts.map +1 -1
  379. package/dist/components/dataaccess/SubmissionPage/SubmissionPage.js +157 -148
  380. package/dist/components/dataaccess/SubmissionPage/SubmissionPage.js.map +1 -1
  381. package/dist/components/dataaccess/UseAccessRequirementTable.js.map +1 -1
  382. package/dist/components/dataaccess/UserAccessRequestHistory/UserAccessRequestHistoryTable.js.map +1 -1
  383. package/dist/components/doi/CreateOrUpdateDoiModal.d.ts.map +1 -1
  384. package/dist/components/doi/CreateOrUpdateDoiModal.js +20 -19
  385. package/dist/components/doi/CreateOrUpdateDoiModal.js.map +1 -1
  386. package/dist/components/entity/page/CreatedByModifiedBy.js.map +1 -1
  387. package/dist/components/entity/page/action_menu/EntityActionMenu.js.map +1 -1
  388. package/dist/components/entity/page/title_bar/useDataCiteUsage.js.map +1 -1
  389. package/dist/components/entity/page/title_bar/useGetMentions.js.map +1 -1
  390. package/dist/components/error/ErrorPage.js.map +1 -1
  391. package/dist/components/favorites/FavoritesPage.js.map +1 -1
  392. package/dist/components/file/upload/BasicFileHandleUpload.js.map +1 -1
  393. package/dist/components/layout/SWCHeader.d.ts +9 -0
  394. package/dist/components/layout/SWCHeader.d.ts.map +1 -0
  395. package/dist/components/layout/SWCHeader.js +19 -0
  396. package/dist/components/layout/SWCHeader.js.map +1 -0
  397. package/dist/components/layout/SWCPageLayout.d.ts +9 -0
  398. package/dist/components/layout/SWCPageLayout.d.ts.map +1 -0
  399. package/dist/components/layout/SWCPageLayout.js +14 -0
  400. package/dist/components/layout/SWCPageLayout.js.map +1 -0
  401. package/dist/components/menu/ComplexMenu.js.map +1 -1
  402. package/dist/components/row_renderers/utils/ChipContainer.js.map +1 -1
  403. package/dist/components/styled/StyledPopover.js.map +1 -1
  404. package/dist/components/table/CsvPreview/CsvPreview.js +2 -1
  405. package/dist/components/table/CsvPreview/CsvPreview.js.map +1 -1
  406. package/dist/components/table/CsvPreview/CsvPreviewDialog.js.map +1 -1
  407. package/dist/components/trash/TrashCanList.js.map +1 -1
  408. package/dist/components/widgets/FileHandleLink.js.map +1 -1
  409. package/dist/components/widgets/RangeSlider/RangeSlider.js.map +1 -1
  410. package/dist/components/widgets/SynapseVideo.js.map +1 -1
  411. package/dist/components/widgets/facet-nav/FacetNavPanel.js.map +1 -1
  412. package/dist/components/widgets/facet-nav/PlotsContainer.js.map +1 -1
  413. package/dist/components/widgets/facet-nav/SelectionCriteriaPills.js.map +1 -1
  414. package/dist/components/widgets/facet-nav/useFacetPlots.js.map +1 -1
  415. package/dist/components/widgets/query-filter/CombinedRangeFacetFilter.js.map +1 -1
  416. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilter.js.map +1 -1
  417. package/dist/components/widgets/query-filter/FacetFilterControls.js.map +1 -1
  418. package/dist/components/widgets/query-filter/RangeFacetFilter.js.map +1 -1
  419. package/dist/components/widgets/query-filter/RangeFacetFilterUI.js.map +1 -1
  420. package/dist/features/curator/GridPage/components/GridPageTitle.d.ts.map +1 -1
  421. package/dist/features/curator/GridPage/components/GridPageTitle.js +23 -30
  422. package/dist/features/curator/GridPage/components/GridPageTitle.js.map +1 -1
  423. package/dist/features/curator/dashboard/CuratorDashboard.d.ts +2 -0
  424. package/dist/features/curator/dashboard/CuratorDashboard.d.ts.map +1 -0
  425. package/dist/features/curator/dashboard/CuratorDashboard.js +45 -0
  426. package/dist/features/curator/dashboard/CuratorDashboard.js.map +1 -0
  427. package/dist/features/curator/dashboard/components/CurationTaskCard.css +1 -0
  428. package/dist/features/curator/dashboard/components/CurationTaskCard.d.ts +9 -0
  429. package/dist/features/curator/dashboard/components/CurationTaskCard.d.ts.map +1 -0
  430. package/dist/features/curator/dashboard/components/CurationTaskCard.js +106 -0
  431. package/dist/features/curator/dashboard/components/CurationTaskCard.js.map +1 -0
  432. package/dist/features/curator/dashboard/components/CurationTaskCard.module.js +12 -0
  433. package/dist/features/curator/dashboard/components/CurationTaskCard.module.js.map +1 -0
  434. package/dist/features/curator/dashboard/components/CurationTaskCard.module.scss +52 -0
  435. package/dist/features/curator/dashboard/components/NextStepButton.css +1 -0
  436. package/dist/features/curator/dashboard/components/NextStepButton.d.ts +14 -0
  437. package/dist/features/curator/dashboard/components/NextStepButton.d.ts.map +1 -0
  438. package/dist/features/curator/dashboard/components/NextStepButton.js +35 -0
  439. package/dist/features/curator/dashboard/components/NextStepButton.js.map +1 -0
  440. package/dist/features/curator/dashboard/components/NextStepButton.module.js +11 -0
  441. package/dist/features/curator/dashboard/components/NextStepButton.module.js.map +1 -0
  442. package/dist/features/curator/dashboard/components/NextStepButton.module.scss +57 -0
  443. package/dist/features/curator/dashboard/components/UserOrTeamChip.css +1 -1
  444. package/dist/features/curator/dashboard/components/UserOrTeamChip.module.js +1 -1
  445. package/dist/features/curator/dashboard/components/UserOrTeamChip.module.js.map +1 -1
  446. package/dist/features/curator/dashboard/components/UserOrTeamChip.module.scss +5 -5
  447. package/dist/features/curator/dashboard/components/shared.css +1 -0
  448. package/dist/features/curator/dashboard/components/shared.module.js +5 -0
  449. package/dist/features/curator/dashboard/components/shared.module.js.map +1 -0
  450. package/dist/features/curator/dashboard/components/shared.module.scss +8 -0
  451. package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.d.ts +0 -2
  452. package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.d.ts.map +1 -1
  453. package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.js +16 -34
  454. package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.js.map +1 -1
  455. package/dist/features/entity/metadata-task/components/MetadataTasksTableAssigneeCell.d.ts.map +1 -1
  456. package/dist/features/entity/metadata-task/components/MetadataTasksTableAssigneeCell.js +1 -1
  457. package/dist/features/entity/metadata-task/components/MetadataTasksTableAssigneeCell.js.map +1 -1
  458. package/dist/features/entity/metadata-task/hooks/useGetOrCreateGridSessionForSource.js.map +1 -1
  459. package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask.js.map +1 -1
  460. package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask_legacy.js.map +1 -1
  461. package/dist/features/entity/metadata-task/hooks/useMetadataTaskTable.js +1 -1
  462. package/dist/features/entity/metadata-task/hooks/useMetadataTaskTable.js.map +1 -1
  463. package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.d.ts +10 -0
  464. package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.d.ts.map +1 -0
  465. package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.js +37 -0
  466. package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.js.map +1 -0
  467. package/dist/features/entity/metadata-task/utils/constants.d.ts +5 -0
  468. package/dist/features/entity/metadata-task/utils/constants.d.ts.map +1 -0
  469. package/dist/features/entity/metadata-task/utils/constants.js +6 -0
  470. package/dist/features/entity/metadata-task/utils/constants.js.map +1 -0
  471. package/dist/mocks/challenge/mockChallenge.js.map +1 -1
  472. package/dist/mocks/entity/mockDataset.js.map +1 -1
  473. package/dist/mocks/entity/mockDatasetCollection.js.map +1 -1
  474. package/dist/mocks/entity/mockFileEntity.js.map +1 -1
  475. package/dist/mocks/entity/mockFileView.js.map +1 -1
  476. package/dist/mocks/entity/mockGeneratedEntityData.js.map +1 -1
  477. package/dist/mocks/entity/mockProject.js.map +1 -1
  478. package/dist/mocks/entity/mockProjectView.js.map +1 -1
  479. package/dist/mocks/entity/mockRootEntity.js.map +1 -1
  480. package/dist/mocks/entity/mockTableEntity.js.map +1 -1
  481. package/dist/mocks/mockWiki.js.map +1 -1
  482. package/dist/mocks/msw/handlers/asyncJobHandlers.js.map +1 -1
  483. package/dist/mocks/msw/handlers/challengeHandlers.js.map +1 -1
  484. package/dist/mocks/msw/handlers/changePasswordHandlers.js.map +1 -1
  485. package/dist/mocks/msw/handlers/discussionHandlers.js.map +1 -1
  486. package/dist/mocks/msw/handlers/entityHandlers.js.map +1 -1
  487. package/dist/mocks/msw/handlers/fileHandlers.js.map +1 -1
  488. package/dist/mocks/msw/handlers/gridHandlers.js.map +1 -1
  489. package/dist/mocks/msw/handlers/personalAccessTokenHandlers.js.map +1 -1
  490. package/dist/mocks/msw/handlers/subscriptionHandlers.js.map +1 -1
  491. package/dist/mocks/msw/handlers/teamHandlers.js.map +1 -1
  492. package/dist/mocks/msw/handlers/userProfileHandlers.js.map +1 -1
  493. package/dist/mocks/msw/handlers/wikiHandlers.js.map +1 -1
  494. package/dist/mocks/provenance/mockActivity.js.map +1 -1
  495. package/dist/mocks/query/mockReleaseCardsTableQueryResultBundle.js.map +1 -1
  496. package/dist/ror-client/index.js.map +1 -1
  497. package/dist/style/components/_cards.scss +4 -0
  498. package/dist/style/components/_data-grid-extra.css +1 -1
  499. package/dist/style/components/_data-grid-extra.scss +2 -0
  500. package/dist/style/main.css +1 -1
  501. package/dist/synapse-client/HttpClient.js.map +1 -1
  502. package/dist/synapse-client/SynapseClient.js.map +1 -1
  503. package/dist/synapse-queries/KeyFactory.d.ts +1 -0
  504. package/dist/synapse-queries/KeyFactory.d.ts.map +1 -1
  505. package/dist/synapse-queries/KeyFactory.js +3 -0
  506. package/dist/synapse-queries/KeyFactory.js.map +1 -1
  507. package/dist/synapse-queries/QueryMatching.test-utils.js.map +1 -1
  508. package/dist/synapse-queries/auth/useTwoFactorEnrollment.js.map +1 -1
  509. package/dist/synapse-queries/curation/task/useCurationTask.d.ts +1 -1
  510. package/dist/synapse-queries/curation/task/useCurationTask.d.ts.map +1 -1
  511. package/dist/synapse-queries/curation/task/useCurationTask.js +1 -1
  512. package/dist/synapse-queries/curation/task/useCurationTask.js.map +1 -1
  513. package/dist/synapse-queries/dataaccess/useRestrictionInformation.js.map +1 -1
  514. package/dist/synapse-queries/doi/useDOI.js.map +1 -1
  515. package/dist/synapse-queries/download/useDownloadList.js.map +1 -1
  516. package/dist/synapse-queries/entity/useEntity.js.map +1 -1
  517. package/dist/synapse-queries/entity/useEntityBundle.js.map +1 -1
  518. package/dist/synapse-queries/entity/useExportTableQueryToAnalysisPlatform.js.map +1 -1
  519. package/dist/synapse-queries/entity/useExportToTerra.js.map +1 -1
  520. package/dist/synapse-queries/entity/useGetQueryResultBundle.js.map +1 -1
  521. package/dist/synapse-queries/entity/useSchema.js.map +1 -1
  522. package/dist/synapse-queries/file/UploadToS3.js.map +1 -1
  523. package/dist/synapse-queries/file/useDirectUploadToS3.js.map +1 -1
  524. package/dist/synapse-queries/file/useFiles.js.map +1 -1
  525. package/dist/synapse-queries/forum/useReply.js.map +1 -1
  526. package/dist/synapse-queries/forum/useThread.d.ts +1 -0
  527. package/dist/synapse-queries/forum/useThread.d.ts.map +1 -1
  528. package/dist/synapse-queries/forum/useThread.js +19 -12
  529. package/dist/synapse-queries/forum/useThread.js.map +1 -1
  530. package/dist/synapse-queries/grid/useEstablishWebsocketConnection.d.ts +2 -0
  531. package/dist/synapse-queries/grid/useEstablishWebsocketConnection.d.ts.map +1 -1
  532. package/dist/synapse-queries/grid/useEstablishWebsocketConnection.js.map +1 -1
  533. package/dist/synapse-queries/grid/useExportGrid.js.map +1 -1
  534. package/dist/synapse-queries/grid/useGridSession.js.map +1 -1
  535. package/dist/synapse-queries/grid/useImportCsvIntoGrid.js.map +1 -1
  536. package/dist/synapse-queries/subscription/useSubscription.js.map +1 -1
  537. package/dist/synapse-queries/table/useGetCsvPreview.js.map +1 -1
  538. package/dist/synapse-queries/table/useTableUpdateTransaction.js.map +1 -1
  539. package/dist/synapse-queries/team/useTeamMembers.js.map +1 -1
  540. package/dist/synapse-queries/user/useGetUserChallenges.js.map +1 -1
  541. package/dist/synapse-queries/user/useUserBundle.js.map +1 -1
  542. package/dist/synapse-queries/user/useUserGroupHeader.js.map +1 -1
  543. package/dist/testutils/ReactQueryMockUtils.js.map +1 -1
  544. package/dist/theme/ThemeProvider.js.map +1 -1
  545. package/dist/tsconfig.build.tsbuildinfo +1 -1
  546. package/dist/utils/APIConstants.d.ts +1 -0
  547. package/dist/utils/APIConstants.d.ts.map +1 -1
  548. package/dist/utils/APIConstants.js +2 -2
  549. package/dist/utils/APIConstants.js.map +1 -1
  550. package/dist/utils/AppUtils/session/ApplicationSessionManager.d.ts.map +1 -1
  551. package/dist/utils/AppUtils/session/ApplicationSessionManager.js +7 -4
  552. package/dist/utils/AppUtils/session/ApplicationSessionManager.js.map +1 -1
  553. package/dist/utils/AppUtils/session/SynapseSessionManager.js.map +1 -1
  554. package/dist/utils/AppUtils/session/useSessionManager.js.map +1 -1
  555. package/dist/utils/PermissionLevelToAccessType.js.map +1 -1
  556. package/dist/utils/challenge/evaluation/EvaluationUtils.js.map +1 -1
  557. package/dist/utils/context/SynapseContext.js.map +1 -1
  558. package/dist/utils/functions/AccessControlListUtils.d.ts +4 -0
  559. package/dist/utils/functions/AccessControlListUtils.d.ts.map +1 -1
  560. package/dist/utils/functions/AccessControlListUtils.js +12 -1
  561. package/dist/utils/functions/AccessControlListUtils.js.map +1 -1
  562. package/dist/utils/functions/EntityTypeUtils.d.ts.map +1 -1
  563. package/dist/utils/functions/EntityTypeUtils.js +15 -4
  564. package/dist/utils/functions/EntityTypeUtils.js.map +1 -1
  565. package/dist/utils/functions/GridApiUtils.js.map +1 -1
  566. package/dist/utils/functions/QueryFilterUtils.js.map +1 -1
  567. package/dist/utils/functions/RealmUtils.d.ts +4 -0
  568. package/dist/utils/functions/RealmUtils.d.ts.map +1 -1
  569. package/dist/utils/functions/RealmUtils.js +9 -3
  570. package/dist/utils/functions/RealmUtils.js.map +1 -1
  571. package/dist/utils/functions/SanitizeHtmlUtils.js.map +1 -1
  572. package/dist/utils/functions/SanitizeHtmlUtils.test-utils.js.map +1 -1
  573. package/dist/utils/functions/SqlFunctions.js.map +1 -1
  574. package/dist/utils/functions/StringUtils.js.map +1 -1
  575. package/dist/utils/functions/deepLinkingUtils.js.map +1 -1
  576. package/dist/utils/functions/getDataFromFromStorage.js.map +1 -1
  577. package/dist/utils/functions/getEndpoint.js.map +1 -1
  578. package/dist/utils/functions/getUserData.js.map +1 -1
  579. package/dist/utils/functions/queryUtils.js.map +1 -1
  580. package/dist/utils/functions/testDownloadSpeed.js.map +1 -1
  581. package/dist/utils/hooks/useConfirmItems.js.map +1 -1
  582. package/dist/utils/hooks/useCookiePreferences.js.map +1 -1
  583. package/dist/utils/hooks/useCreateShortUrl.js.map +1 -1
  584. package/dist/utils/hooks/useDetectSSOCode.js.map +1 -1
  585. package/dist/utils/hooks/useDirectDownloadHandler.js.map +1 -1
  586. package/dist/utils/hooks/useGetGoalData.js.map +1 -1
  587. package/dist/utils/hooks/useGetInfoFromIds.js.map +1 -1
  588. package/dist/utils/hooks/useImageUrlUtils.js.map +1 -1
  589. package/dist/utils/hooks/useImmutableTableQuery/useImmutableTableQuery.js.map +1 -1
  590. package/dist/utils/hooks/useImmutableTableQuery/useTableQueryReducer.js.map +1 -1
  591. package/dist/utils/hooks/useIsBot.js.map +1 -1
  592. package/dist/utils/hooks/useListState.js.map +1 -1
  593. package/dist/utils/hooks/useLogin.d.ts.map +1 -1
  594. package/dist/utils/hooks/useLogin.js +53 -52
  595. package/dist/utils/hooks/useLogin.js.map +1 -1
  596. package/dist/utils/hooks/useMutuallyExclusiveState.js.map +1 -1
  597. package/dist/utils/hooks/useOverlay.js.map +1 -1
  598. package/dist/utils/hooks/usePreFetchResource.js.map +1 -1
  599. package/dist/utils/hooks/useQuerySearchParam.js.map +1 -1
  600. package/dist/utils/hooks/useScrollFadeTransition.js.map +1 -1
  601. package/dist/utils/hooks/useSet.js.map +1 -1
  602. package/dist/utils/hooks/useSourceAppConfigs.js.map +1 -1
  603. package/dist/utils/hooks/useTableImageUrl.js.map +1 -1
  604. package/dist/utils/hooks/useUploadFileEntity/useCreatePathsAndGetParentId.js.map +1 -1
  605. package/dist/utils/hooks/useUploadFileEntity/useLinkFileEntityToURL.js.map +1 -1
  606. package/dist/utils/hooks/useUploadFileEntity/usePrepareFileEntityUpload.js.map +1 -1
  607. package/dist/utils/hooks/useUploadFileEntity/useTrackFileUploads.js.map +1 -1
  608. package/dist/utils/hooks/useUploadFileEntity/useUploadFileEntities.js.map +1 -1
  609. package/dist/utils/hooks/useUploadFileEntity/useUploadFiles.js.map +1 -1
  610. package/dist/utils/hooks/useUploadFileEntity/willUploadsExceedStorageLimit.js.map +1 -1
  611. package/dist/utils/html/TargetEnum.js.map +1 -1
  612. package/dist/utils/jsonschema/SchemaAnnotationUtils.js.map +1 -1
  613. package/package.json +5 -5
@@ -1 +1 @@
1
- {"version":3,"file":"AnnotationEditorUtils.js","names":[],"sources":["../../../src/components/SchemaDrivenAnnotationEditor/AnnotationEditorUtils.ts"],"sourcesContent":["import { AdditionalPropertiesSchemaField } from '@/components/SchemaDrivenAnnotationEditor/field/AdditionalPropertiesSchemaField'\nimport {\n englishStringTranslator,\n RJSFValidationError,\n TranslatableString,\n} from '@rjsf/utils'\nimport { JSONSchema7 } from 'json-schema'\nimport { JSONPath } from 'jsonpath-plus'\nimport { flatMap, groupBy, isEmpty, isObject } from 'lodash-es'\n\n/**\n * Generates a JSON schema for the form UI based on the provided validation schema and entity schema base properties.\n *\n * To meet the requirements of the desired form to display, we cannot simply show the validation schema. This is because\n * validation schemas may use conditional logic based on default entity properties (e.g. concreteType) to show/hide fields.\n * This method combines the validation schema with the entity schema base properties to create a new schema that will yield\n * the expected form with desired logic.\n * @param validationSchema\n * @param entitySchema\n */\nexport function getJsonSchemaForForm(\n validationSchema: JSONSchema7 = {},\n entitySchema: JSONSchema7 = {},\n): JSONSchema7 {\n const entitySchemaProperties =\n getPossibleTopLevelPropertiesInObjectSchema(entitySchema)\n\n return {\n $schema: 'http://json-schema.org/draft-07/schema#',\n // Spread the validation schema to ensure all other references are included\n // Top level properties like \"$defs\" get lost if we simply put the entire schema in `allOf`\n ...validationSchema,\n // JSON Schemas for Synapse types use \"definitions\", so it should be manually merged.\n definitions: {\n ...entitySchema.definitions,\n ...validationSchema.definitions,\n },\n allOf: [\n ...(validationSchema.allOf || []),\n // Add in the entity properties\n {\n type: 'object',\n properties: entitySchemaProperties,\n },\n ],\n // Always allow adding additional annotations (though it may violate the validationSchema)\n additionalProperties: true,\n }\n}\n\n/**\n * Generates the UiSchema for the annotations editor.\n * @param entitySchemaBaseProperties\n */\nexport function getUiSchemaForForm(\n entitySchemaBaseProperties: JSONSchema7['properties'] = {},\n) {\n // Each 'base' entity field (id, name, concreteType, etc.) should be hidden\n const uiSchemaWithHiddenEntityProperties = Object.keys(\n entitySchemaBaseProperties,\n ).reduce((prev, curr) => ({ ...prev, [curr]: { 'ui:widget': 'hidden' } }), {})\n\n return {\n ...uiSchemaWithHiddenEntityProperties,\n 'ui:globalOptions': {\n copyable: false, // copy button clutters the UI, is not very useful since schemas are flat objects\n duplicateKeySuffixSeparator: '_', // the default duplicateKeySuffixSeparator creates invalid annotation keys\n },\n additionalProperties: {\n 'ui:field': AdditionalPropertiesSchemaField,\n },\n }\n}\n/**\n * Strips null values from arrays in the provided form data. If the array is empty after\n * removing null values, the key is removed from the form data.\n *\n * This allows users to submit forms with empty array fields (SWC-5762)\n */\nexport function dropNullishArrayValues(\n formData: Record<string, unknown>,\n): Record<string, unknown> {\n const newFormData: Record<string, unknown> = {}\n Object.keys(formData).forEach(key => {\n let value = formData[key]\n if (Array.isArray(value)) {\n value = value.filter((item: any) => item != null)\n if (!isEmpty(value)) {\n newFormData[key] = value\n }\n } else {\n newFormData[key] = value\n }\n })\n return newFormData\n}\n\nexport function dropNullValues(\n formData: Record<string, unknown> = {},\n): Record<string, unknown> {\n return Object.keys(formData).reduce(\n (acc: Record<string, unknown>, key: string) => {\n if (formData[key] !== null) {\n acc[key] = formData[key]\n }\n return acc\n },\n {},\n )\n}\n\n/**\n * Inspects the property of the AjvError and modifies it to be comparable to simple key strings, like entity property keys.\n * @param error\n * @returns\n */\nexport function getFriendlyPropertyName(error: RJSFValidationError): string {\n if (error.property?.startsWith('[')) {\n // Additional properties are surrounded by brackets and quotations, so let's remove them\n return error.property.substring(2, error.property.length - 2)\n } else if (error.property?.startsWith('.')) {\n return error.property.substring(1)\n } else {\n return error.property || ''\n }\n}\n\nexport function transformErrors(\n errors: RJSFValidationError[],\n): RJSFValidationError[] {\n // Transform the errors in the following ways:\n // - Simplify the set of errors when failing to select an enumeration defined with an anyOf (SWC-5724)\n // - Show a custom error message when using a property that collides with an internal entity property (SWC-5678)\n\n // Fixing anyOf errors\n // Group the errors by the property that the error applies to\n const grouped = groupBy(errors, error => error.property)\n Object.keys(grouped).map(property => {\n const errorGroup = grouped[property]\n\n // First, see if it is an anyOf error\n const hasAnyOfError = errorGroup.some(\n e => e.message === 'should match some schema in anyOf',\n )\n\n // We determine if it's an anyOf *enum* error if all error messages in the property match one of these three messages:\n const isEnumError =\n hasAnyOfError &&\n errorGroup.every(error => {\n if (error.message === 'should be string') {\n return true\n } else if (error.message === 'should be equal to constant') {\n return true\n } else if (error.message === 'should match some schema in anyOf') {\n return true\n } else {\n return false\n }\n })\n\n // If it's an anyOf enum error, we just modify the first message and drop the rest\n if (isEnumError && errorGroup.length > 0) {\n errorGroup[0].message = 'should be equal to one of the allowed values'\n grouped[property] = [errorGroup[0]]\n }\n })\n\n // Ungroup the errors after potentially modifying them\n errors = flatMap(grouped)\n\n // Return the transformed errors.\n return errors\n}\n\n/**\n * Custom annotations in Synapse are always arrays. This function converts initial data to be an array type.\n * If the initial data is an array, return the data itself.\n * Otherwise, wrap the data in an array.\n */\nexport function convertToArray<T>(value: T): Array<unknown> {\n if (Array.isArray(value)) {\n return value\n } else {\n return [value]\n }\n}\n\n/**\n * Returns true if the default behavior of the form should be to live validate\n * @param existingAnnotations\n * @param validationSchema\n */\nexport function shouldLiveValidate(\n existingAnnotations: Record<string, unknown> | undefined,\n validationSchema: JSONSchema7 | undefined,\n): boolean {\n const hasExistingAnnotations =\n existingAnnotations && Object.keys(existingAnnotations).length > 0\n return Boolean(hasExistingAnnotations && validationSchema)\n}\n\n/**\n * Returns all possible properties in the schema, including those in nested schemas/definitions. Note that this function\n * only works for 'flat objects', i.e. the schema must\n * - define an object AND\n * - the properties of the object cannot be objects\n * which is compatible with how Synapse Annotations are defined.\n * @param resolvedSchema\n */\nexport function getPossibleTopLevelPropertiesInObjectSchema(\n resolvedSchema: JSONSchema7,\n): JSONSchema7['properties'] {\n const allProperties = {}\n const foundPropertiesObjects = JSONPath({\n path: '$..properties',\n json: resolvedSchema,\n })\n for (const propertiesObject of foundPropertiesObjects) {\n Object.assign(allProperties, propertiesObject)\n }\n // Use the schema.properties to override any properties defined in definitions\n if (isObject(resolvedSchema.properties)) {\n Object.assign(allProperties, resolvedSchema.properties)\n }\n return allProperties\n}\n\n/**\n * Get the Synapse entity schema ID for a particular concrete type.\n * @param concreteType\n */\nexport function getSchemaIdForConcreteType(\n concreteType: string,\n): string | null {\n if (!concreteType || !concreteType.startsWith('org.sagebionetworks')) {\n return null\n }\n // e.g. 'org.sagebionetworks.repo.model.FileEntity' -> 'org.sagebionetworks-repo.model.FileEntity'\n return (\n 'org.sagebionetworks-' +\n concreteType.substring('org.sagebionetworks'.length + 1)\n )\n}\n\n/**\n * Custom string translator for react-jsonschema-form.\n * Overrides the translation for \"NewStringDefault\" by returning an empty string.\n * For all other keys, falls back to the default English string translator.\n *\n * @param stringToTranslate\n * @param params - Optional parameters used to format the translated string.\n * @returns - The translated string.\n */\nexport function customTranslateString(\n stringToTranslate: TranslatableString,\n params?: string[],\n): string {\n switch (stringToTranslate) {\n case TranslatableString.NewStringDefault:\n return ''\n default:\n return englishStringTranslator(stringToTranslate, params)\n }\n}\n"],"mappings":";;;;;AAoBA,SAAgB,EACd,IAAgC,EAAE,EAClC,IAA4B,EAAE,EACjB;CACb,IAAM,IACJ,EAA4C,EAAa;AAE3D,QAAO;EACL,SAAS;EAGT,GAAG;EAEH,aAAa;GACX,GAAG,EAAa;GAChB,GAAG,EAAiB;GACrB;EACD,OAAO,CACL,GAAI,EAAiB,SAAS,EAAE,EAEhC;GACE,MAAM;GACN,YAAY;GACb,CACF;EAED,sBAAsB;EACvB;;AAOH,SAAgB,EACd,IAAwD,EAAE,EAC1D;AAMA,QAAO;EACL,GALyC,OAAO,KAChD,EACD,CAAC,QAAQ,GAAM,OAAU;GAAE,GAAG;IAAO,IAAO,EAAE,aAAa,UAAU;GAAE,GAAG,EAAE,CAAC;EAI5E,oBAAoB;GAClB,UAAU;GACV,6BAA6B;GAC9B;EACD,sBAAsB,EACpB,YAAY,GACb;EACF;;AAQH,SAAgB,EACd,GACyB;CACzB,IAAM,IAAuC,EAAE;AAY/C,QAXA,OAAO,KAAK,EAAS,CAAC,SAAQ,MAAO;EACnC,IAAI,IAAQ,EAAS;AACrB,EAAI,MAAM,QAAQ,EAAM,IACtB,IAAQ,EAAM,QAAQ,MAAc,KAAQ,KAAK,EAC5C,EAAQ,EAAM,KACjB,EAAY,KAAO,MAGrB,EAAY,KAAO;GAErB,EACK;;AAGT,SAAgB,EACd,IAAoC,EAAE,EACb;AACzB,QAAO,OAAO,KAAK,EAAS,CAAC,QAC1B,GAA8B,OACzB,EAAS,OAAS,SACpB,EAAI,KAAO,EAAS,KAEf,IAET,EAAE,CACH;;AAQH,SAAgB,EAAwB,GAAoC;AAOxE,QANE,EAAM,UAAU,WAAW,IAAI,GAE1B,EAAM,SAAS,UAAU,GAAG,EAAM,SAAS,SAAS,EAAE,GACpD,EAAM,UAAU,WAAW,IAAI,GACjC,EAAM,SAAS,UAAU,EAAE,GAE3B,EAAM,YAAY;;AAI7B,SAAgB,EACd,GACuB;CAOvB,IAAM,IAAU,EAAQ,IAAQ,MAAS,EAAM,SAAS;AAmCxD,QAlCA,OAAO,KAAK,EAAQ,CAAC,KAAI,MAAY;EACnC,IAAM,IAAa,EAAQ;AAuB3B,EApBsB,EAAW,MAC/B,MAAK,EAAE,YAAY,oCACpB,IAKC,EAAW,OAAM,MACX,EAAM,YAAY,sBAEX,EAAM,YAAY,gCADpB,KAGE,EAAM,YAAY,oCAK7B,IAGe,EAAW,SAAS,MACrC,EAAW,GAAG,UAAU,gDACxB,EAAQ,KAAY,CAAC,EAAW,GAAG;GAErC,EAGF,IAAS,EAAQ,EAAQ,EAGlB;;AAQT,SAAgB,EAAkB,GAA0B;AAIxD,QAHE,MAAM,QAAQ,EAAM,GACf,IAEA,CAAC,EAAM;;AASlB,SAAgB,EACd,GACA,GACS;AAGT,QAAO,GADL,KAAuB,OAAO,KAAK,EAAoB,CAAC,SAAS,KAC1B;;AAW3C,SAAgB,EACd,GAC2B;CAC3B,IAAM,IAAgB,EAAE,EAClB,IAAyB,EAAS;EACtC,MAAM;EACN,MAAM;EACP,CAAC;AACF,MAAK,IAAM,KAAoB,EAC7B,QAAO,OAAO,GAAe,EAAiB;AAMhD,QAHI,EAAS,EAAe,WAAW,IACrC,OAAO,OAAO,GAAe,EAAe,WAAW,EAElD;;AAOT,SAAgB,EACd,GACe;AAKf,QAJI,CAAC,KAAgB,CAAC,EAAa,WAAW,sBAAsB,GAC3D,OAIP,yBACA,EAAa,UAAU,GAAiC;;AAa5D,SAAgB,EACd,GACA,GACQ;AACR,SAAQ,GAAR;EACE,KAAK,EAAmB,iBACtB,QAAO;EACT,QACE,QAAO,EAAwB,GAAmB,EAAO"}
1
+ {"version":3,"file":"AnnotationEditorUtils.js","names":[],"sources":["../../../src/components/SchemaDrivenAnnotationEditor/AnnotationEditorUtils.ts"],"sourcesContent":["import { AdditionalPropertiesSchemaField } from '@/components/SchemaDrivenAnnotationEditor/field/AdditionalPropertiesSchemaField'\nimport {\n englishStringTranslator,\n RJSFValidationError,\n TranslatableString,\n} from '@rjsf/utils'\nimport { JSONSchema7 } from 'json-schema'\nimport { JSONPath } from 'jsonpath-plus'\nimport { flatMap, groupBy, isEmpty, isObject } from 'lodash-es'\n\n/**\n * Generates a JSON schema for the form UI based on the provided validation schema and entity schema base properties.\n *\n * To meet the requirements of the desired form to display, we cannot simply show the validation schema. This is because\n * validation schemas may use conditional logic based on default entity properties (e.g. concreteType) to show/hide fields.\n * This method combines the validation schema with the entity schema base properties to create a new schema that will yield\n * the expected form with desired logic.\n * @param validationSchema\n * @param entitySchema\n */\nexport function getJsonSchemaForForm(\n validationSchema: JSONSchema7 = {},\n entitySchema: JSONSchema7 = {},\n): JSONSchema7 {\n const entitySchemaProperties =\n getPossibleTopLevelPropertiesInObjectSchema(entitySchema)\n\n return {\n $schema: 'http://json-schema.org/draft-07/schema#',\n // Spread the validation schema to ensure all other references are included\n // Top level properties like \"$defs\" get lost if we simply put the entire schema in `allOf`\n ...validationSchema,\n // JSON Schemas for Synapse types use \"definitions\", so it should be manually merged.\n definitions: {\n ...entitySchema.definitions,\n ...validationSchema.definitions,\n },\n allOf: [\n ...(validationSchema.allOf || []),\n // Add in the entity properties\n {\n type: 'object',\n properties: entitySchemaProperties,\n },\n ],\n // Always allow adding additional annotations (though it may violate the validationSchema)\n additionalProperties: true,\n }\n}\n\n/**\n * Generates the UiSchema for the annotations editor.\n * @param entitySchemaBaseProperties\n */\nexport function getUiSchemaForForm(\n entitySchemaBaseProperties: JSONSchema7['properties'] = {},\n) {\n // Each 'base' entity field (id, name, concreteType, etc.) should be hidden\n const uiSchemaWithHiddenEntityProperties = Object.keys(\n entitySchemaBaseProperties,\n ).reduce((prev, curr) => ({ ...prev, [curr]: { 'ui:widget': 'hidden' } }), {})\n\n return {\n ...uiSchemaWithHiddenEntityProperties,\n 'ui:globalOptions': {\n copyable: false, // copy button clutters the UI, is not very useful since schemas are flat objects\n duplicateKeySuffixSeparator: '_', // the default duplicateKeySuffixSeparator creates invalid annotation keys\n },\n additionalProperties: {\n 'ui:field': AdditionalPropertiesSchemaField,\n },\n }\n}\n/**\n * Strips null values from arrays in the provided form data. If the array is empty after\n * removing null values, the key is removed from the form data.\n *\n * This allows users to submit forms with empty array fields (SWC-5762)\n */\nexport function dropNullishArrayValues(\n formData: Record<string, unknown>,\n): Record<string, unknown> {\n const newFormData: Record<string, unknown> = {}\n Object.keys(formData).forEach(key => {\n let value = formData[key]\n if (Array.isArray(value)) {\n value = value.filter((item: any) => item != null)\n if (!isEmpty(value)) {\n newFormData[key] = value\n }\n } else {\n newFormData[key] = value\n }\n })\n return newFormData\n}\n\nexport function dropNullValues(\n formData: Record<string, unknown> = {},\n): Record<string, unknown> {\n return Object.keys(formData).reduce(\n (acc: Record<string, unknown>, key: string) => {\n if (formData[key] !== null) {\n acc[key] = formData[key]\n }\n return acc\n },\n {},\n )\n}\n\n/**\n * Inspects the property of the AjvError and modifies it to be comparable to simple key strings, like entity property keys.\n * @param error\n * @returns\n */\nexport function getFriendlyPropertyName(error: RJSFValidationError): string {\n if (error.property?.startsWith('[')) {\n // Additional properties are surrounded by brackets and quotations, so let's remove them\n return error.property.substring(2, error.property.length - 2)\n } else if (error.property?.startsWith('.')) {\n return error.property.substring(1)\n } else {\n return error.property || ''\n }\n}\n\nexport function transformErrors(\n errors: RJSFValidationError[],\n): RJSFValidationError[] {\n // Transform the errors in the following ways:\n // - Simplify the set of errors when failing to select an enumeration defined with an anyOf (SWC-5724)\n // - Show a custom error message when using a property that collides with an internal entity property (SWC-5678)\n\n // Fixing anyOf errors\n // Group the errors by the property that the error applies to\n const grouped = groupBy(errors, error => error.property)\n Object.keys(grouped).map(property => {\n const errorGroup = grouped[property]\n\n // First, see if it is an anyOf error\n const hasAnyOfError = errorGroup.some(\n e => e.message === 'should match some schema in anyOf',\n )\n\n // We determine if it's an anyOf *enum* error if all error messages in the property match one of these three messages:\n const isEnumError =\n hasAnyOfError &&\n errorGroup.every(error => {\n if (error.message === 'should be string') {\n return true\n } else if (error.message === 'should be equal to constant') {\n return true\n } else if (error.message === 'should match some schema in anyOf') {\n return true\n } else {\n return false\n }\n })\n\n // If it's an anyOf enum error, we just modify the first message and drop the rest\n if (isEnumError && errorGroup.length > 0) {\n errorGroup[0].message = 'should be equal to one of the allowed values'\n grouped[property] = [errorGroup[0]]\n }\n })\n\n // Ungroup the errors after potentially modifying them\n errors = flatMap(grouped)\n\n // Return the transformed errors.\n return errors\n}\n\n/**\n * Custom annotations in Synapse are always arrays. This function converts initial data to be an array type.\n * If the initial data is an array, return the data itself.\n * Otherwise, wrap the data in an array.\n */\nexport function convertToArray<T>(value: T): Array<unknown> {\n if (Array.isArray(value)) {\n return value\n } else {\n return [value]\n }\n}\n\n/**\n * Returns true if the default behavior of the form should be to live validate\n * @param existingAnnotations\n * @param validationSchema\n */\nexport function shouldLiveValidate(\n existingAnnotations: Record<string, unknown> | undefined,\n validationSchema: JSONSchema7 | undefined,\n): boolean {\n const hasExistingAnnotations =\n existingAnnotations && Object.keys(existingAnnotations).length > 0\n return Boolean(hasExistingAnnotations && validationSchema)\n}\n\n/**\n * Returns all possible properties in the schema, including those in nested schemas/definitions. Note that this function\n * only works for 'flat objects', i.e. the schema must\n * - define an object AND\n * - the properties of the object cannot be objects\n * which is compatible with how Synapse Annotations are defined.\n * @param resolvedSchema\n */\nexport function getPossibleTopLevelPropertiesInObjectSchema(\n resolvedSchema: JSONSchema7,\n): JSONSchema7['properties'] {\n const allProperties = {}\n const foundPropertiesObjects = JSONPath({\n path: '$..properties',\n json: resolvedSchema,\n })\n for (const propertiesObject of foundPropertiesObjects) {\n Object.assign(allProperties, propertiesObject)\n }\n // Use the schema.properties to override any properties defined in definitions\n if (isObject(resolvedSchema.properties)) {\n Object.assign(allProperties, resolvedSchema.properties)\n }\n return allProperties\n}\n\n/**\n * Get the Synapse entity schema ID for a particular concrete type.\n * @param concreteType\n */\nexport function getSchemaIdForConcreteType(\n concreteType: string,\n): string | null {\n if (!concreteType || !concreteType.startsWith('org.sagebionetworks')) {\n return null\n }\n // e.g. 'org.sagebionetworks.repo.model.FileEntity' -> 'org.sagebionetworks-repo.model.FileEntity'\n return (\n 'org.sagebionetworks-' +\n concreteType.substring('org.sagebionetworks'.length + 1)\n )\n}\n\n/**\n * Custom string translator for react-jsonschema-form.\n * Overrides the translation for \"NewStringDefault\" by returning an empty string.\n * For all other keys, falls back to the default English string translator.\n *\n * @param stringToTranslate\n * @param params - Optional parameters used to format the translated string.\n * @returns - The translated string.\n */\nexport function customTranslateString(\n stringToTranslate: TranslatableString,\n params?: string[],\n): string {\n switch (stringToTranslate) {\n case TranslatableString.NewStringDefault:\n return ''\n default:\n return englishStringTranslator(stringToTranslate, params)\n }\n}\n"],"mappings":";;;;;AAoBA,SAAgB,EACd,IAAgC,EAAE,EAClC,IAA4B,EAAE,EACjB;CACb,IAAM,IACJ,EAA4C,EAAa;AAE3D,QAAO;EACL,SAAS;EAGT,GAAG;EAEH,aAAa;GACX,GAAG,EAAa;GAChB,GAAG,EAAiB;GACrB;EACD,OAAO,CACL,GAAI,EAAiB,SAAS,EAAE,EAEhC;GACE,MAAM;GACN,YAAY;GACb,CACF;EAED,sBAAsB;EACvB;;AAOH,SAAgB,EACd,IAAwD,EAAE,EAC1D;AAMA,QAAO;EACL,GALyC,OAAO,KAChD,EACD,CAAC,QAAQ,GAAM,OAAU;GAAE,GAAG;IAAO,IAAO,EAAE,aAAa,UAAU;GAAE,GAAG,EAAE,CAGxE;EACH,oBAAoB;GAClB,UAAU;GACV,6BAA6B;GAC9B;EACD,sBAAsB,EACpB,YAAY,GACb;EACF;;AAQH,SAAgB,EACd,GACyB;CACzB,IAAM,IAAuC,EAAE;AAY/C,QAXA,OAAO,KAAK,EAAS,CAAC,SAAQ,MAAO;EACnC,IAAI,IAAQ,EAAS;AACrB,EAAI,MAAM,QAAQ,EAAM,IACtB,IAAQ,EAAM,QAAQ,MAAc,KAAQ,KAAK,EAC5C,EAAQ,EAAM,KACjB,EAAY,KAAO,MAGrB,EAAY,KAAO;GAErB,EACK;;AAGT,SAAgB,EACd,IAAoC,EAAE,EACb;AACzB,QAAO,OAAO,KAAK,EAAS,CAAC,QAC1B,GAA8B,OACzB,EAAS,OAAS,SACpB,EAAI,KAAO,EAAS,KAEf,IAET,EAAE,CACH;;AAQH,SAAgB,EAAwB,GAAoC;AAOxE,QANE,EAAM,UAAU,WAAW,IAAI,GAE1B,EAAM,SAAS,UAAU,GAAG,EAAM,SAAS,SAAS,EAAE,GACpD,EAAM,UAAU,WAAW,IAAI,GACjC,EAAM,SAAS,UAAU,EAAE,GAE3B,EAAM,YAAY;;AAI7B,SAAgB,EACd,GACuB;CAOvB,IAAM,IAAU,EAAQ,IAAQ,MAAS,EAAM,SAAS;AAmCxD,QAlCA,OAAO,KAAK,EAAQ,CAAC,KAAI,MAAY;EACnC,IAAM,IAAa,EAAQ;AAuB3B,EApBsB,EAAW,MAC/B,MAAK,EAAE,YAAY,oCAKnB,IACA,EAAW,OAAM,MACX,EAAM,YAAY,sBAEX,EAAM,YAAY,gCADpB,KAGE,EAAM,YAAY,oCAK7B,IAGe,EAAW,SAAS,MACrC,EAAW,GAAG,UAAU,gDACxB,EAAQ,KAAY,CAAC,EAAW,GAAG;GAErC,EAGF,IAAS,EAAQ,EAAQ,EAGlB;;AAQT,SAAgB,EAAkB,GAA0B;AAIxD,QAHE,MAAM,QAAQ,EAAM,GACf,IAEA,CAAC,EAAM;;AASlB,SAAgB,EACd,GACA,GACS;AAGT,QAAO,GADL,KAAuB,OAAO,KAAK,EAAoB,CAAC,SAAS,KAC1B;;AAW3C,SAAgB,EACd,GAC2B;CAC3B,IAAM,IAAgB,EAAE,EAClB,IAAyB,EAAS;EACtC,MAAM;EACN,MAAM;EACP,CAAC;AACF,MAAK,IAAM,KAAoB,EAC7B,QAAO,OAAO,GAAe,EAAiB;AAMhD,QAHI,EAAS,EAAe,WAAW,IACrC,OAAO,OAAO,GAAe,EAAe,WAAW,EAElD;;AAOT,SAAgB,EACd,GACe;AAKf,QAJI,CAAC,KAAgB,CAAC,EAAa,WAAW,sBAAsB,GAC3D,OAIP,yBACA,EAAa,UAAU,GAAiC;;AAa5D,SAAgB,EACd,GACA,GACQ;AACR,SAAQ,GAAR;EACE,KAAK,EAAmB,iBACtB,QAAO;EACT,QACE,QAAO,EAAwB,GAAmB,EAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"SetAccessRequirementCommonFields.js","names":[],"sources":["../../../src/components/SetAccessRequirementCommonFields/SetAccessRequirementCommonFields.tsx"],"sourcesContent":["import {\n useCreateAccessRequirement,\n useGetAccessRequirements,\n useUpdateAccessRequirement,\n} from '@/synapse-queries'\nimport { spreadSx } from '@/theme/spreadSx'\nimport { HelpOutlineTwoTone } from '@mui/icons-material'\nimport {\n Alert,\n Checkbox,\n FormControlLabel,\n Radio,\n RadioGroup,\n Skeleton,\n Stack,\n TextField,\n Tooltip,\n Typography,\n TypographyProps,\n} from '@mui/material'\nimport { SynapseClientError } from '@sage-bionetworks/synapse-client/util/SynapseClientError'\nimport {\n ACCESS_REQUIREMENT_CONCRETE_TYPE,\n ACCESS_TYPE,\n AccessRequirement,\n MANAGED_ACT_ACCESS_REQUIREMENT_CONCRETE_TYPE_VALUE,\n RestrictableObjectDescriptor,\n RestrictableObjectType,\n SELF_SIGN_ACCESS_REQUIREMENT_CONCRETE_TYPE_VALUE,\n} from '@sage-bionetworks/synapse-types'\nimport pluralize from 'pluralize'\nimport {\n ForwardedRef,\n forwardRef,\n useEffect,\n useImperativeHandle,\n useMemo,\n useState,\n} from 'react'\nimport EntitySubjectsSelector from '../EntitySubjectsSelector'\nimport { SynapseErrorBoundary } from '../error'\nimport TeamSubjectsSelector from '../TeamSubjectsSelector'\n\nexport const EMPTY_SUBJECT_LIST_ERROR_MESSAGE =\n 'Please select at least one resource for this Access Requirement to be associated with.'\nexport const UNSAVED_SUBJECTS_ERROR_MESSAGE = (\n subjectsType: RestrictableObjectType,\n) => {\n const idsText =\n subjectsType === RestrictableObjectType.ENTITY ? 'Synapse' : 'Team'\n const typeText =\n subjectsType[0].toUpperCase() + subjectsType.slice(1).toLowerCase()\n return `${idsText} IDs were specified but not added to the subjects list. Please either clear out the Add ${idsText} IDs textbox or click the Add ${pluralize(\n typeText,\n )} button.`\n}\nconst NAME_HELP_TEXT =\n \"Enter access requirement name. This will also be used when sending notifications for expiring or revoked approval. For example, 'The approval for the name access requirement was revoked...'\"\n\nconst headerProps: Partial<TypographyProps> = {\n variant: 'body1',\n fontWeight: 700,\n}\n\nfunction getAccessType(subjectType: RestrictableObjectType) {\n switch (subjectType) {\n case RestrictableObjectType.ENTITY:\n return ACCESS_TYPE.DOWNLOAD\n case RestrictableObjectType.TEAM:\n return ACCESS_TYPE.PARTICIPATE\n default:\n throw new Error(\n `RestrictableObjectType ${subjectType} does not have an access type specified.`,\n )\n }\n}\n\nexport type SetAccessRequirementCommonFieldsHandle = {\n /* Allow the parent component to trigger saving the AR, so this may be embedded in an arbitrary modal. */\n save: () => void\n}\n\nexport type SetAccessRequirementCommonFieldsProps = {\n /* Provided when creating a new AR */\n subject?: RestrictableObjectDescriptor\n /* Provided when editing an existing AR */\n accessRequirementId?: string\n /* Called when AR has been saved successfully */\n onSave: (\n accessRequirementId: string,\n accessRequirementConreteType: ACCESS_REQUIREMENT_CONCRETE_TYPE,\n ) => void\n /* Called when error saving AR */\n onError: () => void\n}\n\nexport const SetAccessRequirementCommonFields = forwardRef(\n function SetAccessRequirementCommonFields(\n props: SetAccessRequirementCommonFieldsProps,\n ref: ForwardedRef<SetAccessRequirementCommonFieldsHandle>,\n ) {\n const { subject, accessRequirementId, onSave, onError } = props\n\n const isEditing = !subject\n\n const [subjects, setSubjects] = useState<RestrictableObjectDescriptor[]>(\n subject ? [subject] : [],\n )\n const [hasPendingSubjects, setHasPendingSubjects] = useState<boolean>(false)\n const [subjectsError, setSubjectsError] = useState<string | null>(null)\n const [name, setName] = useState<string>('')\n const [subjectsDefinedByAnnotations, setSubjectsDefinedByAnnotations] =\n useState<boolean>(false)\n const [arType, setArType] = useState<ACCESS_REQUIREMENT_CONCRETE_TYPE>(\n subject?.type === RestrictableObjectType.TEAM\n ? SELF_SIGN_ACCESS_REQUIREMENT_CONCRETE_TYPE_VALUE\n : MANAGED_ACT_ACCESS_REQUIREMENT_CONCRETE_TYPE_VALUE,\n )\n const [clientError, setClientError] = useState<string | null>(null)\n\n const onMutationSuccess = (ar: AccessRequirement) => {\n setClientError(null)\n onSave(ar.id.toString(), ar.concreteType)\n }\n\n const onMutationError = (error: SynapseClientError) => {\n setClientError(error.reason)\n onError()\n }\n\n const { mutate: createAccessRequirement } = useCreateAccessRequirement({\n onSuccess: newAr => onMutationSuccess(newAr),\n onError: error => onMutationError(error),\n })\n\n const { mutate: updateAccessRequirement } = useUpdateAccessRequirement({\n onSuccess: updatedAr => onMutationSuccess(updatedAr),\n onError: error => onMutationError(error),\n })\n\n const {\n data: accessRequirement,\n isLoading: isLoadingAr,\n error: getArError,\n } = useGetAccessRequirements(accessRequirementId!, {\n enabled: Boolean(accessRequirementId),\n })\n\n useEffect(() => {\n if (accessRequirement) {\n setArType(accessRequirement.concreteType)\n setName(accessRequirement.name)\n setSubjects(accessRequirement.subjectIds)\n setSubjectsDefinedByAnnotations(\n accessRequirement.subjectsDefinedByAnnotations,\n )\n }\n }, [accessRequirement])\n\n const subjectsType = useMemo(() => {\n if (subject) {\n return subject.type\n }\n if (accessRequirement) {\n const initialSubjects = accessRequirement.subjectIds\n if (initialSubjects.length > 0) {\n return initialSubjects[0].type\n }\n }\n if (subjectsDefinedByAnnotations) {\n return RestrictableObjectType.ENTITY\n }\n return null\n }, [subject, accessRequirement, subjectsDefinedByAnnotations])\n\n const selectorContent = useMemo(() => {\n if (!subjectsType) return <></>\n\n function onUpdate(subjects: RestrictableObjectDescriptor[]) {\n setSubjectsError(null)\n setSubjects(subjects)\n }\n\n function onUpdateIdsTextbox(value: string) {\n setSubjectsError(null)\n setHasPendingSubjects(value.trim() !== '')\n }\n\n if (subjectsDefinedByAnnotations) {\n return <></>\n }\n switch (subjectsType) {\n case RestrictableObjectType.TEAM:\n return (\n <TeamSubjectsSelector\n subjects={subjects}\n onUpdate={subjects => onUpdate(subjects)}\n onUpdateTeamIDsTextbox={value => onUpdateIdsTextbox(value)}\n />\n )\n case RestrictableObjectType.ENTITY:\n return (\n <EntitySubjectsSelector\n subjects={subjects}\n onUpdate={subjects => onUpdate(subjects)}\n onUpdateEntityIDsTextbox={value => onUpdateIdsTextbox(value)}\n />\n )\n default:\n console.error(\n `RestrictableObjectType ${subjectsType} does not have a selector implemented.`,\n )\n return <></>\n }\n }, [subjectsType, subjects, subjectsDefinedByAnnotations])\n\n useImperativeHandle(\n ref,\n () => {\n return {\n save() {\n const isStillLoading =\n (isEditing && !accessRequirement) || !subjectsType\n const hasSubjectsError =\n !subjectsDefinedByAnnotations &&\n (hasPendingSubjects || subjects.length === 0)\n if (isStillLoading || hasSubjectsError) {\n if (hasSubjectsError && !isStillLoading) {\n if (hasPendingSubjects) {\n setSubjectsError(UNSAVED_SUBJECTS_ERROR_MESSAGE(subjectsType))\n } else if (subjects.length === 0) {\n setSubjectsError(EMPTY_SUBJECT_LIST_ERROR_MESSAGE)\n }\n }\n\n onError()\n return\n }\n\n const newAccessType = getAccessType(subjectsType)\n if (!isEditing) {\n const newAr: Partial<AccessRequirement> = {\n concreteType: arType,\n subjectIds: subjects,\n name: name,\n accessType: newAccessType,\n subjectsDefinedByAnnotations: subjectsDefinedByAnnotations,\n }\n createAccessRequirement(newAr)\n }\n\n if (isEditing && accessRequirement) {\n updateAccessRequirement({\n ...accessRequirement,\n subjectIds: subjects,\n name: name,\n accessType: newAccessType,\n subjectsDefinedByAnnotations: subjectsDefinedByAnnotations,\n })\n }\n },\n }\n },\n [\n hasPendingSubjects,\n subjectsType,\n subjects,\n name,\n arType,\n accessRequirement,\n isEditing,\n onError,\n createAccessRequirement,\n updateAccessRequirement,\n subjectsDefinedByAnnotations,\n ],\n )\n\n if (isLoadingAr || !subjectsType) {\n return (\n <>\n <Skeleton width={100} height={30} />\n <Skeleton width={125} height={30} />\n <Skeleton width=\"100%\">\n <TextField />\n </Skeleton>\n <Skeleton width={100} height={30} />\n <Skeleton width=\"100%\">\n <TextField />\n </Skeleton>\n </>\n )\n }\n\n if (getArError) {\n return <Alert severity=\"error\">{getArError.reason}</Alert>\n }\n\n return (\n <>\n <Typography {...headerProps}>Resources</Typography>\n {subjectsType !== RestrictableObjectType.TEAM && (\n <FormControlLabel\n control={<Checkbox />}\n label=\"Associated entities should be defined by annotations (DUO)\"\n checked={subjectsDefinedByAnnotations}\n onChange={() => {\n setSubjectsError(null)\n // if we are switching from DUO to manually defining the subjects (and the AR has been retrieved), then\n // reset to the AR subject IDs or the original subject ID. Otherwise, clear out the subjects.\n let newSubjectIds: RestrictableObjectDescriptor[] = []\n if (subjectsDefinedByAnnotations) {\n if (accessRequirement) {\n newSubjectIds = accessRequirement.subjectIds\n } else if (subject) {\n newSubjectIds = [subject]\n }\n }\n setSubjects(newSubjectIds)\n setSubjectsDefinedByAnnotations(!subjectsDefinedByAnnotations)\n }}\n />\n )}\n <SynapseErrorBoundary>{selectorContent}</SynapseErrorBoundary>\n {subjectsError && <Alert severity=\"error\">{subjectsError}</Alert>}\n <Stack\n direction=\"row\"\n sx={{\n gap: 1,\n alignItems: 'center',\n mb: 1,\n mt: 2,\n }}\n >\n <Typography component=\"label\" htmlFor=\"arName\" {...headerProps}>\n Name\n </Typography>\n <Tooltip title={NAME_HELP_TEXT} placement=\"right\">\n <HelpOutlineTwoTone sx={{ color: 'grey.600' }} />\n </Tooltip>\n </Stack>\n <TextField\n id=\"arName\"\n name=\"arName\"\n value={name}\n placeholder=\"Access requirement name\"\n fullWidth\n onChange={event => setName(event.target.value)}\n />\n {!isEditing && subjectsType !== RestrictableObjectType.TEAM && (\n <>\n <Typography\n {...headerProps}\n sx={spreadSx(\n {\n mt: 2,\n },\n headerProps.sx,\n )}\n >\n Access requirement type\n </Typography>\n <RadioGroup\n value={arType}\n onChange={(_event, value) =>\n setArType(value as ACCESS_REQUIREMENT_CONCRETE_TYPE)\n }\n >\n <FormControlLabel\n value={MANAGED_ACT_ACCESS_REQUIREMENT_CONCRETE_TYPE_VALUE}\n control={<Radio />}\n label=\"Controlled - requests are in Synapse\"\n />\n <FormControlLabel\n value={SELF_SIGN_ACCESS_REQUIREMENT_CONCRETE_TYPE_VALUE}\n control={<Radio />}\n label=\"Click wrap\"\n />\n </RadioGroup>\n </>\n )}\n {clientError && (\n <Alert severity=\"error\" sx={{ marginTop: 2 }}>\n {clientError}\n </Alert>\n )}\n </>\n )\n },\n)\n"],"mappings":"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"}
1
+ {"version":3,"file":"SetAccessRequirementCommonFields.js","names":[],"sources":["../../../src/components/SetAccessRequirementCommonFields/SetAccessRequirementCommonFields.tsx"],"sourcesContent":["import {\n useCreateAccessRequirement,\n useGetAccessRequirements,\n useUpdateAccessRequirement,\n} from '@/synapse-queries'\nimport { spreadSx } from '@/theme/spreadSx'\nimport { HelpOutlineTwoTone } from '@mui/icons-material'\nimport {\n Alert,\n Checkbox,\n FormControlLabel,\n Radio,\n RadioGroup,\n Skeleton,\n Stack,\n TextField,\n Tooltip,\n Typography,\n TypographyProps,\n} from '@mui/material'\nimport { SynapseClientError } from '@sage-bionetworks/synapse-client/util/SynapseClientError'\nimport {\n ACCESS_REQUIREMENT_CONCRETE_TYPE,\n ACCESS_TYPE,\n AccessRequirement,\n MANAGED_ACT_ACCESS_REQUIREMENT_CONCRETE_TYPE_VALUE,\n RestrictableObjectDescriptor,\n RestrictableObjectType,\n SELF_SIGN_ACCESS_REQUIREMENT_CONCRETE_TYPE_VALUE,\n} from '@sage-bionetworks/synapse-types'\nimport pluralize from 'pluralize'\nimport {\n ForwardedRef,\n forwardRef,\n useEffect,\n useImperativeHandle,\n useMemo,\n useState,\n} from 'react'\nimport EntitySubjectsSelector from '../EntitySubjectsSelector'\nimport { SynapseErrorBoundary } from '../error'\nimport TeamSubjectsSelector from '../TeamSubjectsSelector'\n\nexport const EMPTY_SUBJECT_LIST_ERROR_MESSAGE =\n 'Please select at least one resource for this Access Requirement to be associated with.'\nexport const UNSAVED_SUBJECTS_ERROR_MESSAGE = (\n subjectsType: RestrictableObjectType,\n) => {\n const idsText =\n subjectsType === RestrictableObjectType.ENTITY ? 'Synapse' : 'Team'\n const typeText =\n subjectsType[0].toUpperCase() + subjectsType.slice(1).toLowerCase()\n return `${idsText} IDs were specified but not added to the subjects list. Please either clear out the Add ${idsText} IDs textbox or click the Add ${pluralize(\n typeText,\n )} button.`\n}\nconst NAME_HELP_TEXT =\n \"Enter access requirement name. This will also be used when sending notifications for expiring or revoked approval. For example, 'The approval for the name access requirement was revoked...'\"\n\nconst headerProps: Partial<TypographyProps> = {\n variant: 'body1',\n fontWeight: 700,\n}\n\nfunction getAccessType(subjectType: RestrictableObjectType) {\n switch (subjectType) {\n case RestrictableObjectType.ENTITY:\n return ACCESS_TYPE.DOWNLOAD\n case RestrictableObjectType.TEAM:\n return ACCESS_TYPE.PARTICIPATE\n default:\n throw new Error(\n `RestrictableObjectType ${subjectType} does not have an access type specified.`,\n )\n }\n}\n\nexport type SetAccessRequirementCommonFieldsHandle = {\n /* Allow the parent component to trigger saving the AR, so this may be embedded in an arbitrary modal. */\n save: () => void\n}\n\nexport type SetAccessRequirementCommonFieldsProps = {\n /* Provided when creating a new AR */\n subject?: RestrictableObjectDescriptor\n /* Provided when editing an existing AR */\n accessRequirementId?: string\n /* Called when AR has been saved successfully */\n onSave: (\n accessRequirementId: string,\n accessRequirementConreteType: ACCESS_REQUIREMENT_CONCRETE_TYPE,\n ) => void\n /* Called when error saving AR */\n onError: () => void\n}\n\nexport const SetAccessRequirementCommonFields = forwardRef(\n function SetAccessRequirementCommonFields(\n props: SetAccessRequirementCommonFieldsProps,\n ref: ForwardedRef<SetAccessRequirementCommonFieldsHandle>,\n ) {\n const { subject, accessRequirementId, onSave, onError } = props\n\n const isEditing = !subject\n\n const [subjects, setSubjects] = useState<RestrictableObjectDescriptor[]>(\n subject ? [subject] : [],\n )\n const [hasPendingSubjects, setHasPendingSubjects] = useState<boolean>(false)\n const [subjectsError, setSubjectsError] = useState<string | null>(null)\n const [name, setName] = useState<string>('')\n const [subjectsDefinedByAnnotations, setSubjectsDefinedByAnnotations] =\n useState<boolean>(false)\n const [arType, setArType] = useState<ACCESS_REQUIREMENT_CONCRETE_TYPE>(\n subject?.type === RestrictableObjectType.TEAM\n ? SELF_SIGN_ACCESS_REQUIREMENT_CONCRETE_TYPE_VALUE\n : MANAGED_ACT_ACCESS_REQUIREMENT_CONCRETE_TYPE_VALUE,\n )\n const [clientError, setClientError] = useState<string | null>(null)\n\n const onMutationSuccess = (ar: AccessRequirement) => {\n setClientError(null)\n onSave(ar.id.toString(), ar.concreteType)\n }\n\n const onMutationError = (error: SynapseClientError) => {\n setClientError(error.reason)\n onError()\n }\n\n const { mutate: createAccessRequirement } = useCreateAccessRequirement({\n onSuccess: newAr => onMutationSuccess(newAr),\n onError: error => onMutationError(error),\n })\n\n const { mutate: updateAccessRequirement } = useUpdateAccessRequirement({\n onSuccess: updatedAr => onMutationSuccess(updatedAr),\n onError: error => onMutationError(error),\n })\n\n const {\n data: accessRequirement,\n isLoading: isLoadingAr,\n error: getArError,\n } = useGetAccessRequirements(accessRequirementId!, {\n enabled: Boolean(accessRequirementId),\n })\n\n useEffect(() => {\n if (accessRequirement) {\n setArType(accessRequirement.concreteType)\n setName(accessRequirement.name)\n setSubjects(accessRequirement.subjectIds)\n setSubjectsDefinedByAnnotations(\n accessRequirement.subjectsDefinedByAnnotations,\n )\n }\n }, [accessRequirement])\n\n const subjectsType = useMemo(() => {\n if (subject) {\n return subject.type\n }\n if (accessRequirement) {\n const initialSubjects = accessRequirement.subjectIds\n if (initialSubjects.length > 0) {\n return initialSubjects[0].type\n }\n }\n if (subjectsDefinedByAnnotations) {\n return RestrictableObjectType.ENTITY\n }\n return null\n }, [subject, accessRequirement, subjectsDefinedByAnnotations])\n\n const selectorContent = useMemo(() => {\n if (!subjectsType) return <></>\n\n function onUpdate(subjects: RestrictableObjectDescriptor[]) {\n setSubjectsError(null)\n setSubjects(subjects)\n }\n\n function onUpdateIdsTextbox(value: string) {\n setSubjectsError(null)\n setHasPendingSubjects(value.trim() !== '')\n }\n\n if (subjectsDefinedByAnnotations) {\n return <></>\n }\n switch (subjectsType) {\n case RestrictableObjectType.TEAM:\n return (\n <TeamSubjectsSelector\n subjects={subjects}\n onUpdate={subjects => onUpdate(subjects)}\n onUpdateTeamIDsTextbox={value => onUpdateIdsTextbox(value)}\n />\n )\n case RestrictableObjectType.ENTITY:\n return (\n <EntitySubjectsSelector\n subjects={subjects}\n onUpdate={subjects => onUpdate(subjects)}\n onUpdateEntityIDsTextbox={value => onUpdateIdsTextbox(value)}\n />\n )\n default:\n console.error(\n `RestrictableObjectType ${subjectsType} does not have a selector implemented.`,\n )\n return <></>\n }\n }, [subjectsType, subjects, subjectsDefinedByAnnotations])\n\n useImperativeHandle(\n ref,\n () => {\n return {\n save() {\n const isStillLoading =\n (isEditing && !accessRequirement) || !subjectsType\n const hasSubjectsError =\n !subjectsDefinedByAnnotations &&\n (hasPendingSubjects || subjects.length === 0)\n if (isStillLoading || hasSubjectsError) {\n if (hasSubjectsError && !isStillLoading) {\n if (hasPendingSubjects) {\n setSubjectsError(UNSAVED_SUBJECTS_ERROR_MESSAGE(subjectsType))\n } else if (subjects.length === 0) {\n setSubjectsError(EMPTY_SUBJECT_LIST_ERROR_MESSAGE)\n }\n }\n\n onError()\n return\n }\n\n const newAccessType = getAccessType(subjectsType)\n if (!isEditing) {\n const newAr: Partial<AccessRequirement> = {\n concreteType: arType,\n subjectIds: subjects,\n name: name,\n accessType: newAccessType,\n subjectsDefinedByAnnotations: subjectsDefinedByAnnotations,\n }\n createAccessRequirement(newAr)\n }\n\n if (isEditing && accessRequirement) {\n updateAccessRequirement({\n ...accessRequirement,\n subjectIds: subjects,\n name: name,\n accessType: newAccessType,\n subjectsDefinedByAnnotations: subjectsDefinedByAnnotations,\n })\n }\n },\n }\n },\n [\n hasPendingSubjects,\n subjectsType,\n subjects,\n name,\n arType,\n accessRequirement,\n isEditing,\n onError,\n createAccessRequirement,\n updateAccessRequirement,\n subjectsDefinedByAnnotations,\n ],\n )\n\n if (isLoadingAr || !subjectsType) {\n return (\n <>\n <Skeleton width={100} height={30} />\n <Skeleton width={125} height={30} />\n <Skeleton width=\"100%\">\n <TextField />\n </Skeleton>\n <Skeleton width={100} height={30} />\n <Skeleton width=\"100%\">\n <TextField />\n </Skeleton>\n </>\n )\n }\n\n if (getArError) {\n return <Alert severity=\"error\">{getArError.reason}</Alert>\n }\n\n return (\n <>\n <Typography {...headerProps}>Resources</Typography>\n {subjectsType !== RestrictableObjectType.TEAM && (\n <FormControlLabel\n control={<Checkbox />}\n label=\"Associated entities should be defined by annotations (DUO)\"\n checked={subjectsDefinedByAnnotations}\n onChange={() => {\n setSubjectsError(null)\n // if we are switching from DUO to manually defining the subjects (and the AR has been retrieved), then\n // reset to the AR subject IDs or the original subject ID. Otherwise, clear out the subjects.\n let newSubjectIds: RestrictableObjectDescriptor[] = []\n if (subjectsDefinedByAnnotations) {\n if (accessRequirement) {\n newSubjectIds = accessRequirement.subjectIds\n } else if (subject) {\n newSubjectIds = [subject]\n }\n }\n setSubjects(newSubjectIds)\n setSubjectsDefinedByAnnotations(!subjectsDefinedByAnnotations)\n }}\n />\n )}\n <SynapseErrorBoundary>{selectorContent}</SynapseErrorBoundary>\n {subjectsError && <Alert severity=\"error\">{subjectsError}</Alert>}\n <Stack\n direction=\"row\"\n sx={{\n gap: 1,\n alignItems: 'center',\n mb: 1,\n mt: 2,\n }}\n >\n <Typography component=\"label\" htmlFor=\"arName\" {...headerProps}>\n Name\n </Typography>\n <Tooltip title={NAME_HELP_TEXT} placement=\"right\">\n <HelpOutlineTwoTone sx={{ color: 'grey.600' }} />\n </Tooltip>\n </Stack>\n <TextField\n id=\"arName\"\n name=\"arName\"\n value={name}\n placeholder=\"Access requirement name\"\n fullWidth\n onChange={event => setName(event.target.value)}\n />\n {!isEditing && subjectsType !== RestrictableObjectType.TEAM && (\n <>\n <Typography\n {...headerProps}\n sx={spreadSx(\n {\n mt: 2,\n },\n headerProps.sx,\n )}\n >\n Access requirement type\n </Typography>\n <RadioGroup\n value={arType}\n onChange={(_event, value) =>\n setArType(value as ACCESS_REQUIREMENT_CONCRETE_TYPE)\n }\n >\n <FormControlLabel\n value={MANAGED_ACT_ACCESS_REQUIREMENT_CONCRETE_TYPE_VALUE}\n control={<Radio />}\n label=\"Controlled - requests are in Synapse\"\n />\n <FormControlLabel\n value={SELF_SIGN_ACCESS_REQUIREMENT_CONCRETE_TYPE_VALUE}\n control={<Radio />}\n label=\"Click wrap\"\n />\n </RadioGroup>\n </>\n )}\n {clientError && (\n <Alert severity=\"error\" sx={{ marginTop: 2 }}>\n {clientError}\n </Alert>\n )}\n </>\n )\n },\n)\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"SetManagedAccessRequirementFields.js","names":[],"sources":["../../../src/components/SetManagedAccessRequirementFields/SetManagedAccessRequirementFields.tsx"],"sourcesContent":["import {\n useGetAccessRequirements,\n useUpdateAccessRequirement,\n} from '@/synapse-queries'\nimport { DAY_IN_MS } from '@/utils/SynapseConstants'\nimport {\n Alert,\n Box,\n Checkbox,\n FormControlLabel,\n TextField,\n Typography,\n} from '@mui/material'\nimport { SynapseClientError } from '@sage-bionetworks/synapse-client/util/SynapseClientError'\nimport {\n FileHandleAssociateType,\n FileHandleAssociation,\n FileUploadComplete,\n ManagedACTAccessRequirement,\n UploadCallbackResp,\n} from '@sage-bionetworks/synapse-types'\nimport {\n ForwardedRef,\n forwardRef,\n useEffect,\n useImperativeHandle,\n useMemo,\n useState,\n} from 'react'\nimport { UploadDocumentField } from '../AccessRequirementList/ManagedACTAccessRequirementRequestFlow/UploadDocumentField'\nimport { SynapseErrorBoundary } from '../error/ErrorBanner'\nimport { SynapseSpinner } from '../LoadingScreen/LoadingScreen'\nimport {\n AccessorRequirements,\n AccessRequirementWikiInstructions,\n} from '../SetBasicAccessRequirementFields'\n\nexport const DUC_TEMPLATE_UPLOAD_ERROR =\n 'There was an error uploading the DUC template. '\n\nexport const getValidExpirationPeriodOrErrorMessage = (\n expirationPeriodDays: string,\n) => {\n if (expirationPeriodDays === '') return 0\n\n const msgPrefix = 'Please enter a valid expiration period (in days): '\n if (/^[-]?\\d+$/.test(expirationPeriodDays)) {\n const num = Number(expirationPeriodDays)\n if (num < 0) {\n return `${msgPrefix}If expiration period is set, then it must be greater than 0.`\n }\n return num * DAY_IN_MS\n }\n return `${msgPrefix}For input string: \"${expirationPeriodDays}\"`\n}\n\nexport type SetManagedAccessRequirementFieldsHandle = {\n /* Allow the parent component to trigger saving the AR, so this may be embedded in an arbitrary modal. */\n save: () => void\n}\n\nexport type SetManagedAccessRequirementFieldsProps = {\n accessRequirementId: string\n /* Called when AR has been saved successfully */\n onSave: () => void\n /* Called when error saving AR */\n onError: () => void\n}\n\nexport const SetManagedAccessRequirementFields = forwardRef(\n function SetManagedAccessRequirementFields(\n props: SetManagedAccessRequirementFieldsProps,\n ref: ForwardedRef<SetManagedAccessRequirementFieldsHandle>,\n ) {\n const { accessRequirementId, onSave, onError } = props\n\n const { data: accessRequirement, error: getArError } =\n useGetAccessRequirements<ManagedACTAccessRequirement>(\n accessRequirementId,\n { staleTime: Infinity },\n )\n useEffect(() => {\n if (accessRequirement) {\n setUpdatedAr(accessRequirement)\n setExpirationPeriodDays(\n (accessRequirement.expirationPeriod / DAY_IN_MS).toString(),\n )\n }\n }, [accessRequirement])\n\n const [uploadDucTemplateError, setUploadDucTemplateError] = useState<\n string | null\n >(null)\n const [expirationPeriodError, setExpirationPeriodError] = useState<\n string | null\n >(null)\n\n const [updatedAr, setUpdatedAr] =\n useState<ManagedACTAccessRequirement | null>(null)\n const [expirationPeriodDays, setExpirationPeriodDays] = useState<string>('')\n\n const ducTemplateFileHandleAssociation = useMemo(() => {\n if (updatedAr?.ducTemplateFileHandleId) {\n const ducTemplateFileHandleAssociation: FileHandleAssociation = {\n fileHandleId: updatedAr.ducTemplateFileHandleId,\n associateObjectType:\n FileHandleAssociateType.AccessRequirementAttachment,\n associateObjectId: updatedAr.id.toString(),\n }\n return ducTemplateFileHandleAssociation\n }\n return undefined\n }, [updatedAr?.ducTemplateFileHandleId, updatedAr?.id])\n\n const uploadDucTemplateCallback = (data: UploadCallbackResp) => {\n if (data.resp && data.success && updatedAr) {\n setUploadDucTemplateError(null)\n // Files are uploaded and synced with the server immediately\n const uploadResponse: FileUploadComplete = data.resp\n setUpdatedAr({\n ...updatedAr,\n ducTemplateFileHandleId: uploadResponse.fileHandleId,\n })\n } else if (!data.success && data.error) {\n setUploadDucTemplateError(\n `${DUC_TEMPLATE_UPLOAD_ERROR} ${\n (data.error as SynapseClientError).reason\n }`,\n )\n }\n }\n\n const {\n mutate: updateAccessRequirement,\n isPending: isUpdatingAccessRequirement,\n error: updateArError,\n } = useUpdateAccessRequirement<ManagedACTAccessRequirement>({\n onSuccess: () => onSave(),\n onError: () => onError(),\n })\n\n useImperativeHandle(\n ref,\n () => {\n return {\n save() {\n if (updatedAr) {\n const expirationPeriodOrErrorMessage =\n getValidExpirationPeriodOrErrorMessage(expirationPeriodDays)\n if (typeof expirationPeriodOrErrorMessage === 'string') {\n setExpirationPeriodError(expirationPeriodOrErrorMessage)\n onError()\n } else {\n updateAccessRequirement({\n ...updatedAr,\n expirationPeriod: expirationPeriodOrErrorMessage,\n })\n }\n }\n },\n }\n },\n [expirationPeriodDays, updatedAr, updateAccessRequirement, onError],\n )\n\n if (!updatedAr) {\n if (getArError) {\n return <Alert severity=\"error\">{getArError.reason}</Alert>\n } else {\n return <SynapseSpinner />\n }\n }\n\n return (\n <>\n <AccessRequirementWikiInstructions accessRequirement={updatedAr} />\n <Box>\n <Typography\n sx={{\n bgcolor: '#f5f5f5',\n borderBottom: '1px solid #ddd',\n color: '#333',\n px: 2,\n py: 1,\n }}\n >\n Data Access Request Parameters\n </Typography>\n <Box\n sx={{\n mt: 2,\n mb: 4,\n }}\n >\n <AccessorRequirements\n accessRequirement={updatedAr}\n onChange={updatedAr =>\n setUpdatedAr(updatedAr as ManagedACTAccessRequirement)\n }\n />\n <Box\n sx={{\n mb: 2,\n }}\n >\n <Typography\n variant=\"body1\"\n sx={{\n fontWeight: 700,\n }}\n >\n DUC\n </Typography>\n <FormControlLabel\n control={<Checkbox />}\n label=\"DUC is required.\"\n checked={updatedAr.isDUCRequired}\n onChange={(_event, checked: boolean) =>\n setUpdatedAr({\n ...updatedAr,\n isDUCRequired: checked,\n })\n }\n />\n <SynapseErrorBoundary>\n <UploadDocumentField\n id=\"duc\"\n isLoading={isUpdatingAccessRequirement}\n uploadCallback={resp => uploadDucTemplateCallback(resp)}\n documentName=\"Template DUC\"\n fileHandleAssociations={\n ducTemplateFileHandleAssociation\n ? [ducTemplateFileHandleAssociation]\n : undefined\n }\n isMultiFileUpload={false}\n uploadBtnVariant=\"contained\"\n />\n {uploadDucTemplateError && (\n <Alert severity=\"error\" sx={{ marginTop: 2 }}>\n {uploadDucTemplateError}\n </Alert>\n )}\n </SynapseErrorBoundary>\n <FormControlLabel\n label=\"IRB approval is required.\"\n checked={updatedAr.isIRBApprovalRequired}\n control={<Checkbox />}\n onChange={(_event, checked: boolean) =>\n setUpdatedAr({\n ...updatedAr,\n isIRBApprovalRequired: checked,\n })\n }\n sx={{ ml: 0 }}\n />\n <FormControlLabel\n control={<Checkbox />}\n label=\"Other documents are required.\"\n checked={updatedAr.areOtherAttachmentsRequired}\n onChange={(_event, checked: boolean) =>\n setUpdatedAr({\n ...updatedAr,\n areOtherAttachmentsRequired: checked,\n })\n }\n />\n <TextField\n id=\"expirationPeriod\"\n name=\"expirationPeriod\"\n label=\"Expiration period (days)\"\n value={expirationPeriodDays}\n error={Boolean(expirationPeriodError)}\n helperText={expirationPeriodError}\n sx={{ mt: 1 }}\n fullWidth\n onChange={event => {\n setExpirationPeriodError(null)\n setExpirationPeriodDays(event.target.value)\n }}\n onBlur={() => {\n const expirationPeriodOrErrorMessage =\n getValidExpirationPeriodOrErrorMessage(expirationPeriodDays)\n if (typeof expirationPeriodOrErrorMessage === 'string') {\n setExpirationPeriodError(expirationPeriodOrErrorMessage)\n }\n }}\n />\n <Box\n sx={{\n mt: 1,\n }}\n >\n <FormControlLabel\n control={<Checkbox />}\n label=\"Intended Data Use statement is required.\"\n checked={updatedAr.isIDURequired}\n onChange={(_event, checked: boolean) => {\n if (checked) {\n setUpdatedAr({\n ...updatedAr,\n isIDURequired: true,\n })\n } else {\n setUpdatedAr({\n ...updatedAr,\n isIDURequired: false,\n isIDUPublic: false,\n })\n }\n }}\n />\n <FormControlLabel\n control={<Checkbox />}\n label=\"Intended Data Use statements will be publicly available.\"\n checked={updatedAr.isIDUPublic}\n disabled={!updatedAr.isIDURequired}\n onChange={(_event, checked: boolean) =>\n setUpdatedAr({\n ...updatedAr,\n isIDUPublic: checked,\n })\n }\n />\n </Box>\n </Box>\n </Box>\n </Box>\n {updateArError && (\n <Alert severity=\"error\" sx={{ marginTop: 2 }}>\n {updateArError.reason}\n </Alert>\n )}\n </>\n )\n },\n)\n"],"mappings":"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"}
1
+ {"version":3,"file":"SetManagedAccessRequirementFields.js","names":[],"sources":["../../../src/components/SetManagedAccessRequirementFields/SetManagedAccessRequirementFields.tsx"],"sourcesContent":["import {\n useGetAccessRequirements,\n useUpdateAccessRequirement,\n} from '@/synapse-queries'\nimport { DAY_IN_MS } from '@/utils/SynapseConstants'\nimport {\n Alert,\n Box,\n Checkbox,\n FormControlLabel,\n TextField,\n Typography,\n} from '@mui/material'\nimport { SynapseClientError } from '@sage-bionetworks/synapse-client/util/SynapseClientError'\nimport {\n FileHandleAssociateType,\n FileHandleAssociation,\n FileUploadComplete,\n ManagedACTAccessRequirement,\n UploadCallbackResp,\n} from '@sage-bionetworks/synapse-types'\nimport {\n ForwardedRef,\n forwardRef,\n useEffect,\n useImperativeHandle,\n useMemo,\n useState,\n} from 'react'\nimport { UploadDocumentField } from '../AccessRequirementList/ManagedACTAccessRequirementRequestFlow/UploadDocumentField'\nimport { SynapseErrorBoundary } from '../error/ErrorBanner'\nimport { SynapseSpinner } from '../LoadingScreen/LoadingScreen'\nimport {\n AccessorRequirements,\n AccessRequirementWikiInstructions,\n} from '../SetBasicAccessRequirementFields'\n\nexport const DUC_TEMPLATE_UPLOAD_ERROR =\n 'There was an error uploading the DUC template. '\n\nexport const getValidExpirationPeriodOrErrorMessage = (\n expirationPeriodDays: string,\n) => {\n if (expirationPeriodDays === '') return 0\n\n const msgPrefix = 'Please enter a valid expiration period (in days): '\n if (/^[-]?\\d+$/.test(expirationPeriodDays)) {\n const num = Number(expirationPeriodDays)\n if (num < 0) {\n return `${msgPrefix}If expiration period is set, then it must be greater than 0.`\n }\n return num * DAY_IN_MS\n }\n return `${msgPrefix}For input string: \"${expirationPeriodDays}\"`\n}\n\nexport type SetManagedAccessRequirementFieldsHandle = {\n /* Allow the parent component to trigger saving the AR, so this may be embedded in an arbitrary modal. */\n save: () => void\n}\n\nexport type SetManagedAccessRequirementFieldsProps = {\n accessRequirementId: string\n /* Called when AR has been saved successfully */\n onSave: () => void\n /* Called when error saving AR */\n onError: () => void\n}\n\nexport const SetManagedAccessRequirementFields = forwardRef(\n function SetManagedAccessRequirementFields(\n props: SetManagedAccessRequirementFieldsProps,\n ref: ForwardedRef<SetManagedAccessRequirementFieldsHandle>,\n ) {\n const { accessRequirementId, onSave, onError } = props\n\n const { data: accessRequirement, error: getArError } =\n useGetAccessRequirements<ManagedACTAccessRequirement>(\n accessRequirementId,\n { staleTime: Infinity },\n )\n useEffect(() => {\n if (accessRequirement) {\n setUpdatedAr(accessRequirement)\n setExpirationPeriodDays(\n (accessRequirement.expirationPeriod / DAY_IN_MS).toString(),\n )\n }\n }, [accessRequirement])\n\n const [uploadDucTemplateError, setUploadDucTemplateError] = useState<\n string | null\n >(null)\n const [expirationPeriodError, setExpirationPeriodError] = useState<\n string | null\n >(null)\n\n const [updatedAr, setUpdatedAr] =\n useState<ManagedACTAccessRequirement | null>(null)\n const [expirationPeriodDays, setExpirationPeriodDays] = useState<string>('')\n\n const ducTemplateFileHandleAssociation = useMemo(() => {\n if (updatedAr?.ducTemplateFileHandleId) {\n const ducTemplateFileHandleAssociation: FileHandleAssociation = {\n fileHandleId: updatedAr.ducTemplateFileHandleId,\n associateObjectType:\n FileHandleAssociateType.AccessRequirementAttachment,\n associateObjectId: updatedAr.id.toString(),\n }\n return ducTemplateFileHandleAssociation\n }\n return undefined\n }, [updatedAr?.ducTemplateFileHandleId, updatedAr?.id])\n\n const uploadDucTemplateCallback = (data: UploadCallbackResp) => {\n if (data.resp && data.success && updatedAr) {\n setUploadDucTemplateError(null)\n // Files are uploaded and synced with the server immediately\n const uploadResponse: FileUploadComplete = data.resp\n setUpdatedAr({\n ...updatedAr,\n ducTemplateFileHandleId: uploadResponse.fileHandleId,\n })\n } else if (!data.success && data.error) {\n setUploadDucTemplateError(\n `${DUC_TEMPLATE_UPLOAD_ERROR} ${\n (data.error as SynapseClientError).reason\n }`,\n )\n }\n }\n\n const {\n mutate: updateAccessRequirement,\n isPending: isUpdatingAccessRequirement,\n error: updateArError,\n } = useUpdateAccessRequirement<ManagedACTAccessRequirement>({\n onSuccess: () => onSave(),\n onError: () => onError(),\n })\n\n useImperativeHandle(\n ref,\n () => {\n return {\n save() {\n if (updatedAr) {\n const expirationPeriodOrErrorMessage =\n getValidExpirationPeriodOrErrorMessage(expirationPeriodDays)\n if (typeof expirationPeriodOrErrorMessage === 'string') {\n setExpirationPeriodError(expirationPeriodOrErrorMessage)\n onError()\n } else {\n updateAccessRequirement({\n ...updatedAr,\n expirationPeriod: expirationPeriodOrErrorMessage,\n })\n }\n }\n },\n }\n },\n [expirationPeriodDays, updatedAr, updateAccessRequirement, onError],\n )\n\n if (!updatedAr) {\n if (getArError) {\n return <Alert severity=\"error\">{getArError.reason}</Alert>\n } else {\n return <SynapseSpinner />\n }\n }\n\n return (\n <>\n <AccessRequirementWikiInstructions accessRequirement={updatedAr} />\n <Box>\n <Typography\n sx={{\n bgcolor: '#f5f5f5',\n borderBottom: '1px solid #ddd',\n color: '#333',\n px: 2,\n py: 1,\n }}\n >\n Data Access Request Parameters\n </Typography>\n <Box\n sx={{\n mt: 2,\n mb: 4,\n }}\n >\n <AccessorRequirements\n accessRequirement={updatedAr}\n onChange={updatedAr =>\n setUpdatedAr(updatedAr as ManagedACTAccessRequirement)\n }\n />\n <Box\n sx={{\n mb: 2,\n }}\n >\n <Typography\n variant=\"body1\"\n sx={{\n fontWeight: 700,\n }}\n >\n DUC\n </Typography>\n <FormControlLabel\n control={<Checkbox />}\n label=\"DUC is required.\"\n checked={updatedAr.isDUCRequired}\n onChange={(_event, checked: boolean) =>\n setUpdatedAr({\n ...updatedAr,\n isDUCRequired: checked,\n })\n }\n />\n <SynapseErrorBoundary>\n <UploadDocumentField\n id=\"duc\"\n isLoading={isUpdatingAccessRequirement}\n uploadCallback={resp => uploadDucTemplateCallback(resp)}\n documentName=\"Template DUC\"\n fileHandleAssociations={\n ducTemplateFileHandleAssociation\n ? [ducTemplateFileHandleAssociation]\n : undefined\n }\n isMultiFileUpload={false}\n uploadBtnVariant=\"contained\"\n />\n {uploadDucTemplateError && (\n <Alert severity=\"error\" sx={{ marginTop: 2 }}>\n {uploadDucTemplateError}\n </Alert>\n )}\n </SynapseErrorBoundary>\n <FormControlLabel\n label=\"IRB approval is required.\"\n checked={updatedAr.isIRBApprovalRequired}\n control={<Checkbox />}\n onChange={(_event, checked: boolean) =>\n setUpdatedAr({\n ...updatedAr,\n isIRBApprovalRequired: checked,\n })\n }\n sx={{ ml: 0 }}\n />\n <FormControlLabel\n control={<Checkbox />}\n label=\"Other documents are required.\"\n checked={updatedAr.areOtherAttachmentsRequired}\n onChange={(_event, checked: boolean) =>\n setUpdatedAr({\n ...updatedAr,\n areOtherAttachmentsRequired: checked,\n })\n }\n />\n <TextField\n id=\"expirationPeriod\"\n name=\"expirationPeriod\"\n label=\"Expiration period (days)\"\n value={expirationPeriodDays}\n error={Boolean(expirationPeriodError)}\n helperText={expirationPeriodError}\n sx={{ mt: 1 }}\n fullWidth\n onChange={event => {\n setExpirationPeriodError(null)\n setExpirationPeriodDays(event.target.value)\n }}\n onBlur={() => {\n const expirationPeriodOrErrorMessage =\n getValidExpirationPeriodOrErrorMessage(expirationPeriodDays)\n if (typeof expirationPeriodOrErrorMessage === 'string') {\n setExpirationPeriodError(expirationPeriodOrErrorMessage)\n }\n }}\n />\n <Box\n sx={{\n mt: 1,\n }}\n >\n <FormControlLabel\n control={<Checkbox />}\n label=\"Intended Data Use statement is required.\"\n checked={updatedAr.isIDURequired}\n onChange={(_event, checked: boolean) => {\n if (checked) {\n setUpdatedAr({\n ...updatedAr,\n isIDURequired: true,\n })\n } else {\n setUpdatedAr({\n ...updatedAr,\n isIDURequired: false,\n isIDUPublic: false,\n })\n }\n }}\n />\n <FormControlLabel\n control={<Checkbox />}\n label=\"Intended Data Use statements will be publicly available.\"\n checked={updatedAr.isIDUPublic}\n disabled={!updatedAr.isIDURequired}\n onChange={(_event, checked: boolean) =>\n setUpdatedAr({\n ...updatedAr,\n isIDUPublic: checked,\n })\n }\n />\n </Box>\n </Box>\n </Box>\n </Box>\n {updateArError && (\n <Alert severity=\"error\" sx={{ marginTop: 2 }}>\n {updateArError.reason}\n </Alert>\n )}\n </>\n )\n },\n)\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"SmartButton.js","names":[],"sources":["../../../src/components/SmartLink/SmartButton.tsx"],"sourcesContent":["import { Button, ButtonProps } from '@mui/material'\nimport { useSmartLink } from './useSmartLink'\n\ninterface SmartButtonProps extends ButtonProps {\n href?: string\n target?: string\n}\n\nexport function SmartButton({\n href,\n target,\n children,\n ...props\n}: SmartButtonProps) {\n const navProps = useSmartLink(href, target)\n return (\n <Button {...navProps} {...props}>\n {children}\n </Button>\n )\n}\n"],"mappings":";;;;AAQA,SAAgB,EAAY,EAC1B,SACA,WACA,aACA,GAAG,KACgB;AAEnB,QACE,kBAAC,GAAD;EAAQ,GAFO,EAAa,GAAM,EAAO;EAEnB,GAAI;EACvB;EACM,CAAA"}
1
+ {"version":3,"file":"SmartButton.js","names":[],"sources":["../../../src/components/SmartLink/SmartButton.tsx"],"sourcesContent":["import { Button, ButtonProps } from '@mui/material'\nimport { useSmartLink } from './useSmartLink'\n\ninterface SmartButtonProps extends ButtonProps {\n href?: string\n target?: string\n}\n\nexport function SmartButton({\n href,\n target,\n children,\n ...props\n}: SmartButtonProps) {\n const navProps = useSmartLink(href, target)\n return (\n <Button {...navProps} {...props}>\n {children}\n </Button>\n )\n}\n"],"mappings":";;;;AAQA,SAAgB,EAAY,EAC1B,SACA,WACA,aACA,GAAG,KACgB;AAEnB,QACE,kBAAC,GAAD;EAAQ,GAFO,EAAa,GAAM,EAEtB;EAAU,GAAI;EACvB;EACM,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"SmartLink.js","names":[],"sources":["../../../src/components/SmartLink/SmartLink.tsx"],"sourcesContent":["import { Link as MuiLink, LinkProps as MuiLinkProps } from '@mui/material'\nimport { useSmartLink } from './useSmartLink'\n\ninterface SmartLinkProps extends MuiLinkProps {\n href: string\n}\n\nexport function SmartLink({\n href,\n target,\n children,\n ...props\n}: SmartLinkProps) {\n const navProps = useSmartLink(href, target)\n return (\n <MuiLink {...navProps} {...props}>\n {children}\n </MuiLink>\n )\n}\n"],"mappings":";;;;AAOA,SAAgB,EAAU,EACxB,SACA,WACA,aACA,GAAG,KACc;AAEjB,QACE,kBAAC,GAAD;EAAS,GAFM,EAAa,GAAM,EAAO;EAElB,GAAI;EACxB;EACO,CAAA"}
1
+ {"version":3,"file":"SmartLink.js","names":[],"sources":["../../../src/components/SmartLink/SmartLink.tsx"],"sourcesContent":["import { Link as MuiLink, LinkProps as MuiLinkProps } from '@mui/material'\nimport { useSmartLink } from './useSmartLink'\n\ninterface SmartLinkProps extends MuiLinkProps {\n href: string\n}\n\nexport function SmartLink({\n href,\n target,\n children,\n ...props\n}: SmartLinkProps) {\n const navProps = useSmartLink(href, target)\n return (\n <MuiLink {...navProps} {...props}>\n {children}\n </MuiLink>\n )\n}\n"],"mappings":";;;;AAOA,SAAgB,EAAU,EACxB,SACA,WACA,aACA,GAAG,KACc;AAEjB,QACE,kBAAC,GAAD;EAAS,GAFM,EAAa,GAAM,EAErB;EAAU,GAAI;EACxB;EACO,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"SourceAppImage.js","names":[],"sources":["../../src/components/SourceAppImage.tsx"],"sourcesContent":["import { useGetStablePresignedUrl } from '@/synapse-queries'\nimport Skeleton from '@mui/material/Skeleton'\nimport {\n FileHandleAssociateType,\n FileHandleAssociation,\n} from '@sage-bionetworks/synapse-types'\n\nexport type SourceAppImageProps = {\n sourceAppConfigTableID: string\n fileHandleId: string | null\n friendlyName?: string\n}\n\n// Refactored into it's own class, thinking that using a prefetch resource would improve loading performance of the images, but it does not.\nfunction SourceAppImage(props: SourceAppImageProps) {\n const { sourceAppConfigTableID, fileHandleId, friendlyName } = props\n const fha: FileHandleAssociation = {\n associateObjectId: sourceAppConfigTableID,\n associateObjectType: FileHandleAssociateType.TableEntity,\n fileHandleId: fileHandleId ?? '',\n }\n const stablePresignedUrl = useGetStablePresignedUrl(fha, true, {\n enabled: !!fileHandleId,\n })\n\n const dataUrl = stablePresignedUrl?.dataUrl\n const error = stablePresignedUrl?.queryResult?.error\n\n if (error) {\n return <></>\n }\n const icon = dataUrl ? (\n <img\n className=\"SourceAppImage\"\n alt={friendlyName ? `${friendlyName} logo` : 'Application logo'}\n src={dataUrl}\n />\n ) : (\n <Skeleton variant=\"rectangular\" width={250} height={65} />\n )\n\n return icon\n}\n\nexport default SourceAppImage\n"],"mappings":";;;;;;AAcA,SAAS,EAAe,GAA4B;CAClD,IAAM,EAAE,2BAAwB,iBAAc,oBAAiB,GAMzD,IAAqB,EALQ;EACjC,mBAAmB;EACnB,qBAAqB,EAAwB;EAC7C,cAAc,KAAgB;EAC/B,EACwD,IAAM,EAC7D,SAAS,CAAC,CAAC,GACZ,CAAC,EAEI,IAAU,GAAoB;AAgBpC,QAfc,GAAoB,aAAa,QAGtC,kBAAA,GAAA,EAAK,CAAA,GAED,IACX,kBAAC,OAAD;EACE,WAAU;EACV,KAAK,IAAe,GAAG,EAAa,SAAS;EAC7C,KAAK;EACL,CAAA,GAEF,kBAAC,GAAD;EAAU,SAAQ;EAAc,OAAO;EAAK,QAAQ;EAAM,CAAA"}
1
+ {"version":3,"file":"SourceAppImage.js","names":[],"sources":["../../src/components/SourceAppImage.tsx"],"sourcesContent":["import { useGetStablePresignedUrl } from '@/synapse-queries'\nimport Skeleton from '@mui/material/Skeleton'\nimport {\n FileHandleAssociateType,\n FileHandleAssociation,\n} from '@sage-bionetworks/synapse-types'\n\nexport type SourceAppImageProps = {\n sourceAppConfigTableID: string\n fileHandleId: string | null\n friendlyName?: string\n}\n\n// Refactored into it's own class, thinking that using a prefetch resource would improve loading performance of the images, but it does not.\nfunction SourceAppImage(props: SourceAppImageProps) {\n const { sourceAppConfigTableID, fileHandleId, friendlyName } = props\n const fha: FileHandleAssociation = {\n associateObjectId: sourceAppConfigTableID,\n associateObjectType: FileHandleAssociateType.TableEntity,\n fileHandleId: fileHandleId ?? '',\n }\n const stablePresignedUrl = useGetStablePresignedUrl(fha, true, {\n enabled: !!fileHandleId,\n })\n\n const dataUrl = stablePresignedUrl?.dataUrl\n const error = stablePresignedUrl?.queryResult?.error\n\n if (error) {\n return <></>\n }\n const icon = dataUrl ? (\n <img\n className=\"SourceAppImage\"\n alt={friendlyName ? `${friendlyName} logo` : 'Application logo'}\n src={dataUrl}\n />\n ) : (\n <Skeleton variant=\"rectangular\" width={250} height={65} />\n )\n\n return icon\n}\n\nexport default SourceAppImage\n"],"mappings":";;;;;;AAcA,SAAS,EAAe,GAA4B;CAClD,IAAM,EAAE,2BAAwB,iBAAc,oBAAiB,GAMzD,IAAqB,EAAyB;EAJlD,mBAAmB;EACnB,qBAAqB,EAAwB;EAC7C,cAAc,KAAgB;EAEoB,EAAK,IAAM,EAC7D,SAAS,CAAC,CAAC,GACZ,CAAC,EAEI,IAAU,GAAoB;AAgBpC,QAfc,GAAoB,aAAa,QAGtC,kBAAA,GAAA,EAAK,CAAA,GAED,IACX,kBAAC,OAAD;EACE,WAAU;EACV,KAAK,IAAe,GAAG,EAAa,SAAS;EAC7C,KAAK;EACL,CAAA,GAEF,kBAAC,GAAD;EAAU,SAAQ;EAAc,OAAO;EAAK,QAAQ;EAAM,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"StandaloneQueryWrapper.js","names":[],"sources":["../../../src/components/StandaloneQueryWrapper/StandaloneQueryWrapper.tsx"],"sourcesContent":["import { QueryOrDeprecatedSearchParams } from '@/components/CardContainerLogic/CardContainerLogic'\nimport { useGetEntity } from '@/synapse-queries/entity/useEntity'\nimport { SynapseConstants } from '@/utils'\nimport { isTable } from '@/utils/functions/EntityTypeUtils'\nimport {\n getAdditionalFilters,\n parseEntityIdFromSqlStatement,\n} from '@/utils/functions/SqlFunctions'\nimport { DEFAULT_PAGE_SIZE } from '@/utils/SynapseConstants'\nimport { Query, QueryBundleRequest } from '@sage-bionetworks/synapse-types'\nimport { useState } from 'react'\nimport FullTextSearch from '../FullTextSearch/FullTextSearch'\nimport { QueryContextConsumer } from '../QueryContext/QueryContext'\nimport {\n QueryVisualizationContextConsumer,\n QueryVisualizationWrapper,\n QueryVisualizationWrapperProps,\n} from '../QueryVisualizationWrapper'\nimport { QueryWrapper, QueryWrapperProps } from '../QueryWrapper/QueryWrapper'\nimport { QueryWrapperPlotNavProps } from '../QueryWrapperPlotNav/QueryWrapperPlotNav'\nimport { RowSetView } from '../QueryWrapperPlotNav/RowSetView'\nimport { NoContentPlaceholderType } from '../SynapseTable/NoContentPlaceholderType'\nimport SearchV2, { SearchV2Props } from '../SynapseTable/SearchV2'\nimport SqlEditor from '../SynapseTable/SqlEditor'\nimport { SynapseTableConfiguration } from '../SynapseTable/SynapseTable'\nimport TopLevelControls, {\n TopLevelControlsProps,\n CustomControl,\n} from '../SynapseTable/TopLevelControls/TopLevelControls'\nimport { CustomControls } from '../SynapseTable/CustomControls/CustomControls'\nimport TotalQueryResults from '../TotalQueryResults'\n\ntype StandaloneQueryWrapperOwnProps = {\n showTopLevelControls?: boolean\n searchConfiguration?: Omit<\n SearchV2Props,\n 'queryContext' | 'queryVisualizationContext'\n >\n customControls?: CustomControl[]\n} & Omit<TopLevelControlsProps, 'customControls'> &\n Pick<\n QueryVisualizationWrapperProps,\n | 'rgbIndex'\n | 'unitDescription'\n | 'columnAliases'\n | 'noContentPlaceholderType'\n | 'showLastUpdatedOn'\n | 'visibleColumnCount'\n | 'additionalFiltersSessionStorageKey'\n > &\n Pick<\n QueryWrapperProps,\n | 'fileIdColumnName'\n | 'fileNameColumnName'\n | 'fileVersionColumnName'\n | 'onQueryResultBundleChange'\n | 'shouldDeepLink'\n > &\n Pick<QueryWrapperPlotNavProps, 'cardConfiguration' | 'tableConfiguration'>\n\nexport type StandaloneQueryWrapperProps = QueryOrDeprecatedSearchParams &\n SynapseTableConfiguration &\n StandaloneQueryWrapperOwnProps\n\nexport const generateInitQueryRequest = (query: Query): QueryBundleRequest => {\n return {\n partMask:\n SynapseConstants.BUNDLE_MASK_QUERY_FACETS |\n SynapseConstants.BUNDLE_MASK_QUERY_COUNT |\n SynapseConstants.BUNDLE_MASK_QUERY_SELECT_COLUMNS |\n SynapseConstants.BUNDLE_MASK_QUERY_COLUMN_MODELS |\n SynapseConstants.BUNDLE_MASK_QUERY_RESULTS |\n SynapseConstants.BUNDLE_MASK_LAST_UPDATED_ON,\n entityId: parseEntityIdFromSqlStatement(query.sql),\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n query: {\n limit: DEFAULT_PAGE_SIZE,\n offset: 0,\n ...query,\n },\n }\n}\n\nexport function getQueryFromProps(props: StandaloneQueryWrapperProps) {\n if (props.query) {\n // use props.query if set\n return props.query\n } else {\n // use the deprecated sql, searchParams, and sqlOperator\n const additionalFilters = getAdditionalFilters(\n props.searchParams,\n props.sqlOperator,\n props.additionalFiltersSessionStorageKey,\n )\n return {\n sql: props.sql!,\n additionalFilters,\n offset: 0,\n }\n }\n}\n\n/**\n * This component was initially implemented on the portal side. It renders a SynapseTable if a title is provided.\n * If showTopLevelControls is set to true, then the SynapseTable will also include the TopLevelControls (search, export table, column selection).\n */\nfunction StandaloneQueryWrapper(props: StandaloneQueryWrapperProps) {\n /** @deprecated property inherited from SynapseTableProps */\n const { hideDownload } = props\n const {\n showAccessColumn,\n sql: deprecatedSql,\n hideAddToDownloadListColumn = hideDownload,\n hideQueryCount,\n name,\n showTopLevelControls = false,\n searchConfiguration,\n unitDescription = 'Results',\n rgbIndex,\n showLastUpdatedOn,\n noContentPlaceholderType = showTopLevelControls\n ? NoContentPlaceholderType.INTERACTIVE\n : NoContentPlaceholderType.STATIC,\n cardConfiguration,\n tableConfiguration,\n shouldDeepLink,\n customControls,\n ...rest\n } = props\n const [componentKey, setComponentKey] = useState(1)\n const remount = () => {\n setComponentKey(componentKey + 1)\n }\n\n const sql = props.query?.sql ?? deprecatedSql ?? ''\n const query: Query = getQueryFromProps(props)\n const derivedQueryRequestFromSearchParams = generateInitQueryRequest(query)\n const entityId = parseEntityIdFromSqlStatement(sql)\n const { data: entity } = useGetEntity(entityId)\n\n /**\n * Fully re-render the uncontrolled QueryWrapper component when the initial query changes. This eliminates a class of\n * bugs where our 'derived' state (the current query), which should be reset, is out of sync with props.\n *\n * See https://legacy.reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#recommendation-fully-uncontrolled-component-with-a-key\n */\n const queryWrapperKey =\n JSON.stringify(derivedQueryRequestFromSearchParams) + componentKey\n return (\n <QueryWrapper\n {...rest}\n initQueryRequest={derivedQueryRequestFromSearchParams}\n shouldDeepLink={shouldDeepLink}\n key={queryWrapperKey}\n >\n <QueryVisualizationWrapper\n rgbIndex={rgbIndex}\n unitDescription={unitDescription}\n showLastUpdatedOn={showLastUpdatedOn}\n noContentPlaceholderType={noContentPlaceholderType}\n {...rest}\n >\n <QueryContextConsumer>\n {queryContext => {\n if (queryContext === undefined) {\n throw new Error(\n 'No queryContext found when calling QueryContextConsumer',\n )\n }\n return (\n <QueryVisualizationContextConsumer>\n {queryVisualizationContext => {\n if (queryVisualizationContext === undefined) {\n throw new Error(\n 'No queryVisualizationContext found when calling QueryVisualizationContextConsumer',\n )\n }\n\n return (\n <>\n {showTopLevelControls && (\n <TopLevelControls\n showColumnSelection={true}\n name={name}\n hideDownload={hideAddToDownloadListColumn}\n hideQueryCount={hideQueryCount}\n hideFacetFilterControl={true}\n hideVisualizationsControl={true}\n remount={remount}\n customControls={customControls}\n />\n )}\n {entity && isTable(entity) && entity.isSearchEnabled ? (\n <FullTextSearch\n ftsConfig={searchConfiguration?.ftsConfig}\n />\n ) : (\n <SearchV2\n {...searchConfiguration}\n queryContext={queryContext}\n queryVisualizationContext={queryVisualizationContext}\n />\n )}\n <SqlEditor />\n {showTopLevelControls && (\n <TotalQueryResults frontText={''} />\n )}\n <CustomControls\n customControls={props.customControls}\n remount={remount}\n />\n\n <RowSetView\n tableConfiguration={\n cardConfiguration\n ? undefined\n : {\n ...tableConfiguration, // if exist, use tableConfiguration property\n showAccessColumn: showAccessColumn,\n hideAddToDownloadListColumn,\n ...rest,\n }\n }\n cardConfiguration={cardConfiguration} // if exist, use the cardConfiguration property\n />\n </>\n )\n }}\n </QueryVisualizationContextConsumer>\n )\n }}\n </QueryContextConsumer>\n </QueryVisualizationWrapper>\n </QueryWrapper>\n )\n}\n\nexport default StandaloneQueryWrapper\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAgEA,IAAa,KAA4B,OAChC;CACL,UACE;CAMF,UAAU,EAA8B,EAAM,IAAI;CAClD,cAAc;CACd,OAAO;EACL,OAAA;EACA,QAAQ;EACR,GAAG;EACJ;CACF;AAGH,SAAgB,EAAkB,GAAoC;AACpE,KAAI,EAAM,MAER,QAAO,EAAM;CACR;EAEL,IAAM,IAAoB,EACxB,EAAM,cACN,EAAM,aACN,EAAM,mCACP;AACD,SAAO;GACL,KAAK,EAAM;GACX;GACA,QAAQ;GACT;;;AAQL,SAAS,EAAuB,GAAoC;CAElE,IAAM,EAAE,oBAAiB,GACnB,EACJ,qBACA,KAAK,GACL,iCAA8B,GAC9B,mBACA,SACA,0BAAuB,IACvB,wBACA,qBAAkB,WAClB,aACA,sBACA,8BAA2B,IACvB,EAAyB,cACzB,EAAyB,QAC7B,sBACA,uBACA,mBACA,mBACA,GAAG,MACD,GACE,CAAC,GAAc,KAAmB,EAAS,EAAE,EAC7C,UAAgB;AACpB,IAAgB,IAAe,EAAE;IAG7B,IAAM,EAAM,OAAO,OAAO,KAAiB,IAE3C,IAAsC,EADvB,EAAkB,EAAM,CAC8B,EAErE,EAAE,MAAM,MAAW,EADR,EAA8B,EAAI,CACJ,EAQzC,IACJ,KAAK,UAAU,EAAoC,GAAG;AACxD,QACE,kBAAC,GAAD;EACE,GAAI;EACJ,kBAAkB;EACF;EAChB,KAAK;EAgFQ,EA9Eb,kBAAC,GAAD;EACY;EACO;EACE;EACO;EAC1B,GAAI;YAEJ,kBAAC,GAAD,EAAA,WACG,MAAgB;AACf,OAAI,MAAiB,KAAA,EACnB,OAAU,MACR,0DACD;AAEH,UACE,kBAAC,GAAD,EAAA,WACG,MAA6B;AAC5B,QAAI,MAA8B,KAAA,EAChC,OAAU,MACR,oFACD;AAGH,WACE,kBAAA,GAAA,EAAA,UAAA;KACG,KACC,kBAAC,GAAD;MACE,qBAAqB;MACf;MACN,cAAc;MACE;MAChB,wBAAwB;MACxB,2BAA2B;MAClB;MACO;MAChB,CAAA;KAEH,KAAU,EAAQ,EAAO,IAAI,EAAO,kBACnC,kBAAC,GAAD,EACE,WAAW,GAAqB,WAChC,CAAA,GAEF,kBAAC,GAAD;MACE,GAAI;MACU;MACa;MAC3B,CAAA;KAEJ,kBAAC,GAAD,EAAa,CAAA;KACZ,KACC,kBAAC,GAAD,EAAmB,WAAW,IAAM,CAAA;KAEtC,kBAAC,GAAD;MACE,gBAAgB,EAAM;MACb;MACT,CAAA;KAEF,kBAAC,GAAD;MACE,oBACE,IACI,KAAA,IACA;OACE,GAAG;OACe;OAClB;OACA,GAAG;OACJ;MAEY;MACnB,CAAA;KACD,EAAA,CAAA;MAG2B,CAAA;KAGnB,CAAA;EACG,CAAA,CACf"}
1
+ {"version":3,"file":"StandaloneQueryWrapper.js","names":[],"sources":["../../../src/components/StandaloneQueryWrapper/StandaloneQueryWrapper.tsx"],"sourcesContent":["import { QueryOrDeprecatedSearchParams } from '@/components/CardContainerLogic/CardContainerLogic'\nimport { useGetEntity } from '@/synapse-queries/entity/useEntity'\nimport { SynapseConstants } from '@/utils'\nimport { isTable } from '@/utils/functions/EntityTypeUtils'\nimport {\n getAdditionalFilters,\n parseEntityIdFromSqlStatement,\n} from '@/utils/functions/SqlFunctions'\nimport { DEFAULT_PAGE_SIZE } from '@/utils/SynapseConstants'\nimport { Query, QueryBundleRequest } from '@sage-bionetworks/synapse-types'\nimport { useState } from 'react'\nimport FullTextSearch from '../FullTextSearch/FullTextSearch'\nimport { QueryContextConsumer } from '../QueryContext/QueryContext'\nimport {\n QueryVisualizationContextConsumer,\n QueryVisualizationWrapper,\n QueryVisualizationWrapperProps,\n} from '../QueryVisualizationWrapper'\nimport { QueryWrapper, QueryWrapperProps } from '../QueryWrapper/QueryWrapper'\nimport { QueryWrapperPlotNavProps } from '../QueryWrapperPlotNav/QueryWrapperPlotNav'\nimport { RowSetView } from '../QueryWrapperPlotNav/RowSetView'\nimport { NoContentPlaceholderType } from '../SynapseTable/NoContentPlaceholderType'\nimport SearchV2, { SearchV2Props } from '../SynapseTable/SearchV2'\nimport SqlEditor from '../SynapseTable/SqlEditor'\nimport { SynapseTableConfiguration } from '../SynapseTable/SynapseTable'\nimport TopLevelControls, {\n TopLevelControlsProps,\n CustomControl,\n} from '../SynapseTable/TopLevelControls/TopLevelControls'\nimport { CustomControls } from '../SynapseTable/CustomControls/CustomControls'\nimport TotalQueryResults from '../TotalQueryResults'\n\ntype StandaloneQueryWrapperOwnProps = {\n showTopLevelControls?: boolean\n searchConfiguration?: Omit<\n SearchV2Props,\n 'queryContext' | 'queryVisualizationContext'\n >\n customControls?: CustomControl[]\n} & Omit<TopLevelControlsProps, 'customControls'> &\n Pick<\n QueryVisualizationWrapperProps,\n | 'rgbIndex'\n | 'unitDescription'\n | 'columnAliases'\n | 'noContentPlaceholderType'\n | 'showLastUpdatedOn'\n | 'visibleColumnCount'\n | 'additionalFiltersSessionStorageKey'\n > &\n Pick<\n QueryWrapperProps,\n | 'fileIdColumnName'\n | 'fileNameColumnName'\n | 'fileVersionColumnName'\n | 'onQueryResultBundleChange'\n | 'shouldDeepLink'\n > &\n Pick<QueryWrapperPlotNavProps, 'cardConfiguration' | 'tableConfiguration'>\n\nexport type StandaloneQueryWrapperProps = QueryOrDeprecatedSearchParams &\n SynapseTableConfiguration &\n StandaloneQueryWrapperOwnProps\n\nexport const generateInitQueryRequest = (query: Query): QueryBundleRequest => {\n return {\n partMask:\n SynapseConstants.BUNDLE_MASK_QUERY_FACETS |\n SynapseConstants.BUNDLE_MASK_QUERY_COUNT |\n SynapseConstants.BUNDLE_MASK_QUERY_SELECT_COLUMNS |\n SynapseConstants.BUNDLE_MASK_QUERY_COLUMN_MODELS |\n SynapseConstants.BUNDLE_MASK_QUERY_RESULTS |\n SynapseConstants.BUNDLE_MASK_LAST_UPDATED_ON,\n entityId: parseEntityIdFromSqlStatement(query.sql),\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n query: {\n limit: DEFAULT_PAGE_SIZE,\n offset: 0,\n ...query,\n },\n }\n}\n\nexport function getQueryFromProps(props: StandaloneQueryWrapperProps) {\n if (props.query) {\n // use props.query if set\n return props.query\n } else {\n // use the deprecated sql, searchParams, and sqlOperator\n const additionalFilters = getAdditionalFilters(\n props.searchParams,\n props.sqlOperator,\n props.additionalFiltersSessionStorageKey,\n )\n return {\n sql: props.sql!,\n additionalFilters,\n offset: 0,\n }\n }\n}\n\n/**\n * This component was initially implemented on the portal side. It renders a SynapseTable if a title is provided.\n * If showTopLevelControls is set to true, then the SynapseTable will also include the TopLevelControls (search, export table, column selection).\n */\nfunction StandaloneQueryWrapper(props: StandaloneQueryWrapperProps) {\n /** @deprecated property inherited from SynapseTableProps */\n const { hideDownload } = props\n const {\n showAccessColumn,\n sql: deprecatedSql,\n hideAddToDownloadListColumn = hideDownload,\n hideQueryCount,\n name,\n showTopLevelControls = false,\n searchConfiguration,\n unitDescription = 'Results',\n rgbIndex,\n showLastUpdatedOn,\n noContentPlaceholderType = showTopLevelControls\n ? NoContentPlaceholderType.INTERACTIVE\n : NoContentPlaceholderType.STATIC,\n cardConfiguration,\n tableConfiguration,\n shouldDeepLink,\n customControls,\n ...rest\n } = props\n const [componentKey, setComponentKey] = useState(1)\n const remount = () => {\n setComponentKey(componentKey + 1)\n }\n\n const sql = props.query?.sql ?? deprecatedSql ?? ''\n const query: Query = getQueryFromProps(props)\n const derivedQueryRequestFromSearchParams = generateInitQueryRequest(query)\n const entityId = parseEntityIdFromSqlStatement(sql)\n const { data: entity } = useGetEntity(entityId)\n\n /**\n * Fully re-render the uncontrolled QueryWrapper component when the initial query changes. This eliminates a class of\n * bugs where our 'derived' state (the current query), which should be reset, is out of sync with props.\n *\n * See https://legacy.reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#recommendation-fully-uncontrolled-component-with-a-key\n */\n const queryWrapperKey =\n JSON.stringify(derivedQueryRequestFromSearchParams) + componentKey\n return (\n <QueryWrapper\n {...rest}\n initQueryRequest={derivedQueryRequestFromSearchParams}\n shouldDeepLink={shouldDeepLink}\n key={queryWrapperKey}\n >\n <QueryVisualizationWrapper\n rgbIndex={rgbIndex}\n unitDescription={unitDescription}\n showLastUpdatedOn={showLastUpdatedOn}\n noContentPlaceholderType={noContentPlaceholderType}\n {...rest}\n >\n <QueryContextConsumer>\n {queryContext => {\n if (queryContext === undefined) {\n throw new Error(\n 'No queryContext found when calling QueryContextConsumer',\n )\n }\n return (\n <QueryVisualizationContextConsumer>\n {queryVisualizationContext => {\n if (queryVisualizationContext === undefined) {\n throw new Error(\n 'No queryVisualizationContext found when calling QueryVisualizationContextConsumer',\n )\n }\n\n return (\n <>\n {showTopLevelControls && (\n <TopLevelControls\n showColumnSelection={true}\n name={name}\n hideDownload={hideAddToDownloadListColumn}\n hideQueryCount={hideQueryCount}\n hideFacetFilterControl={true}\n hideVisualizationsControl={true}\n remount={remount}\n customControls={customControls}\n />\n )}\n {entity && isTable(entity) && entity.isSearchEnabled ? (\n <FullTextSearch\n ftsConfig={searchConfiguration?.ftsConfig}\n />\n ) : (\n <SearchV2\n {...searchConfiguration}\n queryContext={queryContext}\n queryVisualizationContext={queryVisualizationContext}\n />\n )}\n <SqlEditor />\n {showTopLevelControls && (\n <TotalQueryResults frontText={''} />\n )}\n <CustomControls\n customControls={props.customControls}\n remount={remount}\n />\n\n <RowSetView\n tableConfiguration={\n cardConfiguration\n ? undefined\n : {\n ...tableConfiguration, // if exist, use tableConfiguration property\n showAccessColumn: showAccessColumn,\n hideAddToDownloadListColumn,\n ...rest,\n }\n }\n cardConfiguration={cardConfiguration} // if exist, use the cardConfiguration property\n />\n </>\n )\n }}\n </QueryVisualizationContextConsumer>\n )\n }}\n </QueryContextConsumer>\n </QueryVisualizationWrapper>\n </QueryWrapper>\n )\n}\n\nexport default StandaloneQueryWrapper\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAgEA,IAAa,KAA4B,OAChC;CACL,UACE;CAMF,UAAU,EAA8B,EAAM,IAAI;CAClD,cAAc;CACd,OAAO;EACL,OAAA;EACA,QAAQ;EACR,GAAG;EACJ;CACF;AAGH,SAAgB,EAAkB,GAAoC;AACpE,KAAI,EAAM,MAER,QAAO,EAAM;CACR;EAEL,IAAM,IAAoB,EACxB,EAAM,cACN,EAAM,aACN,EAAM,mCACP;AACD,SAAO;GACL,KAAK,EAAM;GACX;GACA,QAAQ;GACT;;;AAQL,SAAS,EAAuB,GAAoC;CAElE,IAAM,EAAE,oBAAiB,GACnB,EACJ,qBACA,KAAK,GACL,iCAA8B,GAC9B,mBACA,SACA,0BAAuB,IACvB,wBACA,qBAAkB,WAClB,aACA,sBACA,8BAA2B,IACvB,EAAyB,cACzB,EAAyB,QAC7B,sBACA,uBACA,mBACA,mBACA,GAAG,MACD,GACE,CAAC,GAAc,KAAmB,EAAS,EAAE,EAC7C,UAAgB;AACpB,IAAgB,IAAe,EAAE;IAG7B,IAAM,EAAM,OAAO,OAAO,KAAiB,IAE3C,IAAsC,EADvB,EAAkB,EAC8B,CAAM,EAErE,EAAE,MAAM,MAAW,EADR,EAA8B,EACT,CAAS,EAQzC,IACJ,KAAK,UAAU,EAAoC,GAAG;AACxD,QACE,kBAAC,GAAD;EACE,GAAI;EACJ,kBAAkB;EACF;EAChB,KAAK;EAgFQ,EA9Eb,kBAAC,GAAD;EACY;EACO;EACE;EACO;EAC1B,GAAI;YAEJ,kBAAC,GAAD,EAAA,WACG,MAAgB;AACf,OAAI,MAAiB,KAAA,EACnB,OAAU,MACR,0DACD;AAEH,UACE,kBAAC,GAAD,EAAA,WACG,MAA6B;AAC5B,QAAI,MAA8B,KAAA,EAChC,OAAU,MACR,oFACD;AAGH,WACE,kBAAA,GAAA,EAAA,UAAA;KACG,KACC,kBAAC,GAAD;MACE,qBAAqB;MACf;MACN,cAAc;MACE;MAChB,wBAAwB;MACxB,2BAA2B;MAClB;MACO;MAChB,CAAA;KAEH,KAAU,EAAQ,EAAO,IAAI,EAAO,kBACnC,kBAAC,GAAD,EACE,WAAW,GAAqB,WAChC,CAAA,GAEF,kBAAC,GAAD;MACE,GAAI;MACU;MACa;MAC3B,CAAA;KAEJ,kBAAC,GAAD,EAAa,CAAA;KACZ,KACC,kBAAC,GAAD,EAAmB,WAAW,IAAM,CAAA;KAEtC,kBAAC,GAAD;MACE,gBAAgB,EAAM;MACb;MACT,CAAA;KAEF,kBAAC,GAAD;MACE,oBACE,IACI,KAAA,IACA;OACE,GAAG;OACe;OAClB;OACA,GAAG;OACJ;MAEY;MACnB,CAAA;KACD,EAAA,CAAA;MAG2B,CAAA;KAGnB,CAAA;EACG,CAAA,CACf"}
@@ -1 +1 @@
1
- {"version":3,"file":"StatisticsPlot.js","names":[],"sources":["../../src/components/StatisticsPlot.tsx"],"sourcesContent":["import SynapseClient from '@/synapse-client'\nimport { SynapseContext } from '@/utils/context/SynapseContext'\nimport {\n FilesCountStatistics,\n ProjectFilesStatisticsRequest,\n ProjectFilesStatisticsResponse,\n} from '@sage-bionetworks/synapse-types'\nimport { Component, ContextType } from 'react'\nimport Plot from './Plot/Plot'\n\nconst months = [\n 'Jan',\n 'Feb',\n 'Mar',\n 'Apr',\n 'May',\n 'Jun',\n 'Jul',\n 'Aug',\n 'Sep',\n 'Oct',\n 'Nov',\n 'Dec',\n]\n\nexport type StatisticsPlotProps = {\n request: ProjectFilesStatisticsRequest\n title?: string\n xtitle?: string\n ytitle?: string\n isHorizontal?: boolean\n xaxistype?: string\n showlegend?: boolean\n}\n\ntype StatisticsPlotState = {\n isLoaded: boolean\n plotData?: ProjectFilesStatisticsResponse\n}\n\nclass StatisticsPlot extends Component<\n StatisticsPlotProps,\n StatisticsPlotState\n> {\n static contextType = SynapseContext\n declare context: NonNullable<ContextType<typeof SynapseContext>>\n constructor(props: StatisticsPlotProps) {\n super(props)\n this.state = {\n isLoaded: false,\n plotData: {} as ProjectFilesStatisticsResponse,\n }\n }\n\n public componentDidMount() {\n this.fetchPlotlyData()\n }\n /**\n * Get data for plotly\n *\n * @returns data corresponding to plotly widget\n */\n fetchPlotlyData = async () => {\n const { request } = this.props\n return SynapseClient.getProjectStatistics(request, this.context.accessToken)\n .then((data: ProjectFilesStatisticsResponse) => {\n this.setState({\n isLoaded: true,\n plotData: data,\n })\n })\n .catch((err: any) => {\n console.log('Error on call to get statistics ', err)\n })\n }\n\n getTrace = (\n traceName: string,\n stats: FilesCountStatistics[],\n orientation: string,\n markerColor: string,\n ) => {\n const x: string[] = []\n const y: number[] = []\n const trace = {\n orientation,\n x,\n y,\n name: traceName,\n type: 'bar',\n marker: { color: markerColor },\n hovertemplate:\n // see S3 Formatting options: https://github.com/d3/d3-3.x-api-reference/blob/master/Formatting.md#d3_format\n `%{y:n} <br><extra>${traceName}</extra>`,\n }\n for (const statPoint of stats) {\n const statPointDate: Date = new Date(statPoint.rangeStart)\n trace.x.push(\n `${\n months[statPointDate.getUTCMonth()]\n } ${statPointDate.getUTCFullYear()}`,\n )\n trace.y.push(statPoint.filesCount)\n }\n return trace\n }\n\n showPlot = () => {\n if (!this.state.isLoaded || !this.state.plotData) {\n return\n }\n const { title, xtitle, ytitle, isHorizontal, xaxistype, showlegend } =\n this.props\n const plotData = this.state.plotData\n const layout: any = {\n showlegend,\n title,\n barmode: 'stack',\n hovermode: 'x',\n }\n const config: any = {\n displayModeBar: true,\n displaylogo: false,\n // options found here: https://github.com/plotly/plotly.js/blob/master/src/components/modebar/buttons.js\n modeBarButtonsToRemove: [\n 'sendDataToCloud',\n 'hoverCompareCartesian',\n 'select2d',\n 'lasso2d',\n 'zoom2d',\n 'resetScale2d',\n 'hoverClosestCartesian',\n 'toggleSpikelines',\n ],\n }\n if (xtitle) {\n layout.xaxis = {\n title: xtitle,\n }\n }\n if (xaxistype) {\n layout.xaxis = {\n ...layout.xaxis,\n xaxistype: xaxistype.toLowerCase(),\n }\n }\n\n if (ytitle) {\n layout.yaxis = {\n title: ytitle,\n }\n }\n // init plot_data\n const orientation: string = isHorizontal ? 'h' : 'v'\n const traces: any = []\n if (\n plotData.fileDownloads &&\n plotData.fileDownloads.months &&\n plotData.fileDownloads.months.length > 0\n ) {\n // add file downloads trace\n traces.push(\n this.getTrace(\n 'File Downloads',\n plotData.fileDownloads.months,\n orientation,\n '#7CC0C4',\n ),\n )\n }\n if (\n plotData.fileUploads &&\n plotData.fileUploads.months &&\n plotData.fileUploads.months.length > 0\n ) {\n // add file uploads trace\n traces.push(\n this.getTrace(\n 'File Uploads',\n plotData.fileUploads.months,\n orientation,\n '#D4689A',\n ),\n )\n }\n if (traces.length > 0)\n return (\n <Plot\n layout={layout}\n data={traces}\n config={config}\n className=\"SRC-fullWidth\"\n useResizeHandler={true}\n />\n )\n else return <></>\n }\n\n public render() {\n if (!this.state.isLoaded) {\n return null\n }\n return this.showPlot()\n }\n}\nexport default StatisticsPlot\n"],"mappings":";;;;;;AAUA,IAAM,IAAS;CACb;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,EAiBK,IAAN,cAA6B,EAG3B;CACA,OAAO,cAAc;CAErB,YAAY,GAA4B;AAEtC,EADA,MAAM,EAAM,EACZ,KAAK,QAAQ;GACX,UAAU;GACV,UAAU,EAAE;GACb;;CAGH,oBAA2B;AACzB,OAAK,iBAAiB;;CAOxB,kBAAkB,YAAY;EAC5B,IAAM,EAAE,eAAY,KAAK;AACzB,SAAO,EAAc,qBAAqB,GAAS,KAAK,QAAQ,YAAY,CACzE,MAAM,MAAyC;AAC9C,QAAK,SAAS;IACZ,UAAU;IACV,UAAU;IACX,CAAC;IACF,CACD,OAAO,MAAa;AACnB,WAAQ,IAAI,oCAAoC,EAAI;IACpD;;CAGN,YACE,GACA,GACA,GACA,MACG;EAGH,IAAM,IAAQ;GACZ;GACA,GAJkB,EAAE;GAKpB,GAJkB,EAAE;GAKpB,MAAM;GACN,MAAM;GACN,QAAQ,EAAE,OAAO,GAAa;GAC9B,eAEE,qBAAqB,EAAU;GAClC;AACD,OAAK,IAAM,KAAa,GAAO;GAC7B,IAAM,IAAsB,IAAI,KAAK,EAAU,WAAW;AAM1D,GALA,EAAM,EAAE,KACN,GACE,EAAO,EAAc,aAAa,EACnC,GAAG,EAAc,gBAAgB,GACnC,EACD,EAAM,EAAE,KAAK,EAAU,WAAW;;AAEpC,SAAO;;CAGT,iBAAiB;AACf,MAAI,CAAC,KAAK,MAAM,YAAY,CAAC,KAAK,MAAM,SACtC;EAEF,IAAM,EAAE,UAAO,WAAQ,WAAQ,iBAAc,cAAW,kBACtD,KAAK,OACD,IAAW,KAAK,MAAM,UACtB,IAAc;GAClB;GACA;GACA,SAAS;GACT,WAAW;GACZ,EACK,IAAc;GAClB,gBAAgB;GAChB,aAAa;GAEb,wBAAwB;IACtB;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACD;GACF;AAaD,EAZI,MACF,EAAO,QAAQ,EACb,OAAO,GACR,GAEC,MACF,EAAO,QAAQ;GACb,GAAG,EAAO;GACV,WAAW,EAAU,aAAa;GACnC,GAGC,MACF,EAAO,QAAQ,EACb,OAAO,GACR;EAGH,IAAM,IAAsB,IAAe,MAAM,KAC3C,IAAc,EAAE;AAyCjB,SAvCH,EAAS,iBACT,EAAS,cAAc,UACvB,EAAS,cAAc,OAAO,SAAS,KAGvC,EAAO,KACL,KAAK,SACH,kBACA,EAAS,cAAc,QACvB,GACA,UACD,CACF,EAGD,EAAS,eACT,EAAS,YAAY,UACrB,EAAS,YAAY,OAAO,SAAS,KAGrC,EAAO,KACL,KAAK,SACH,gBACA,EAAS,YAAY,QACrB,GACA,UACD,CACF,EAEC,EAAO,SAAS,IAEhB,kBAAC,GAAD;GACU;GACR,MAAM;GACE;GACR,WAAU;GACV,kBAAkB;GAClB,CAAA,GAEM,kBAAA,GAAA,EAAK,CAAA;;CAGnB,SAAgB;AAId,SAHK,KAAK,MAAM,WAGT,KAAK,UAAU,GAFb"}
1
+ {"version":3,"file":"StatisticsPlot.js","names":[],"sources":["../../src/components/StatisticsPlot.tsx"],"sourcesContent":["import SynapseClient from '@/synapse-client'\nimport { SynapseContext } from '@/utils/context/SynapseContext'\nimport {\n FilesCountStatistics,\n ProjectFilesStatisticsRequest,\n ProjectFilesStatisticsResponse,\n} from '@sage-bionetworks/synapse-types'\nimport { Component, ContextType } from 'react'\nimport Plot from './Plot/Plot'\n\nconst months = [\n 'Jan',\n 'Feb',\n 'Mar',\n 'Apr',\n 'May',\n 'Jun',\n 'Jul',\n 'Aug',\n 'Sep',\n 'Oct',\n 'Nov',\n 'Dec',\n]\n\nexport type StatisticsPlotProps = {\n request: ProjectFilesStatisticsRequest\n title?: string\n xtitle?: string\n ytitle?: string\n isHorizontal?: boolean\n xaxistype?: string\n showlegend?: boolean\n}\n\ntype StatisticsPlotState = {\n isLoaded: boolean\n plotData?: ProjectFilesStatisticsResponse\n}\n\nclass StatisticsPlot extends Component<\n StatisticsPlotProps,\n StatisticsPlotState\n> {\n static contextType = SynapseContext\n declare context: NonNullable<ContextType<typeof SynapseContext>>\n constructor(props: StatisticsPlotProps) {\n super(props)\n this.state = {\n isLoaded: false,\n plotData: {} as ProjectFilesStatisticsResponse,\n }\n }\n\n public componentDidMount() {\n this.fetchPlotlyData()\n }\n /**\n * Get data for plotly\n *\n * @returns data corresponding to plotly widget\n */\n fetchPlotlyData = async () => {\n const { request } = this.props\n return SynapseClient.getProjectStatistics(request, this.context.accessToken)\n .then((data: ProjectFilesStatisticsResponse) => {\n this.setState({\n isLoaded: true,\n plotData: data,\n })\n })\n .catch((err: any) => {\n console.log('Error on call to get statistics ', err)\n })\n }\n\n getTrace = (\n traceName: string,\n stats: FilesCountStatistics[],\n orientation: string,\n markerColor: string,\n ) => {\n const x: string[] = []\n const y: number[] = []\n const trace = {\n orientation,\n x,\n y,\n name: traceName,\n type: 'bar',\n marker: { color: markerColor },\n hovertemplate:\n // see S3 Formatting options: https://github.com/d3/d3-3.x-api-reference/blob/master/Formatting.md#d3_format\n `%{y:n} <br><extra>${traceName}</extra>`,\n }\n for (const statPoint of stats) {\n const statPointDate: Date = new Date(statPoint.rangeStart)\n trace.x.push(\n `${\n months[statPointDate.getUTCMonth()]\n } ${statPointDate.getUTCFullYear()}`,\n )\n trace.y.push(statPoint.filesCount)\n }\n return trace\n }\n\n showPlot = () => {\n if (!this.state.isLoaded || !this.state.plotData) {\n return\n }\n const { title, xtitle, ytitle, isHorizontal, xaxistype, showlegend } =\n this.props\n const plotData = this.state.plotData\n const layout: any = {\n showlegend,\n title,\n barmode: 'stack',\n hovermode: 'x',\n }\n const config: any = {\n displayModeBar: true,\n displaylogo: false,\n // options found here: https://github.com/plotly/plotly.js/blob/master/src/components/modebar/buttons.js\n modeBarButtonsToRemove: [\n 'sendDataToCloud',\n 'hoverCompareCartesian',\n 'select2d',\n 'lasso2d',\n 'zoom2d',\n 'resetScale2d',\n 'hoverClosestCartesian',\n 'toggleSpikelines',\n ],\n }\n if (xtitle) {\n layout.xaxis = {\n title: xtitle,\n }\n }\n if (xaxistype) {\n layout.xaxis = {\n ...layout.xaxis,\n xaxistype: xaxistype.toLowerCase(),\n }\n }\n\n if (ytitle) {\n layout.yaxis = {\n title: ytitle,\n }\n }\n // init plot_data\n const orientation: string = isHorizontal ? 'h' : 'v'\n const traces: any = []\n if (\n plotData.fileDownloads &&\n plotData.fileDownloads.months &&\n plotData.fileDownloads.months.length > 0\n ) {\n // add file downloads trace\n traces.push(\n this.getTrace(\n 'File Downloads',\n plotData.fileDownloads.months,\n orientation,\n '#7CC0C4',\n ),\n )\n }\n if (\n plotData.fileUploads &&\n plotData.fileUploads.months &&\n plotData.fileUploads.months.length > 0\n ) {\n // add file uploads trace\n traces.push(\n this.getTrace(\n 'File Uploads',\n plotData.fileUploads.months,\n orientation,\n '#D4689A',\n ),\n )\n }\n if (traces.length > 0)\n return (\n <Plot\n layout={layout}\n data={traces}\n config={config}\n className=\"SRC-fullWidth\"\n useResizeHandler={true}\n />\n )\n else return <></>\n }\n\n public render() {\n if (!this.state.isLoaded) {\n return null\n }\n return this.showPlot()\n }\n}\nexport default StatisticsPlot\n"],"mappings":";;;;;;AAUA,IAAM,IAAS;CACb;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,EAiBK,IAAN,cAA6B,EAG3B;CACA,OAAO,cAAc;CAErB,YAAY,GAA4B;AAEtC,EADA,MAAM,EAAM,EACZ,KAAK,QAAQ;GACX,UAAU;GACV,UAAU,EAAE;GACb;;CAGH,oBAA2B;AACzB,OAAK,iBAAiB;;CAOxB,kBAAkB,YAAY;EAC5B,IAAM,EAAE,eAAY,KAAK;AACzB,SAAO,EAAc,qBAAqB,GAAS,KAAK,QAAQ,YAAY,CACzE,MAAM,MAAyC;AAC9C,QAAK,SAAS;IACZ,UAAU;IACV,UAAU;IACX,CAAC;IACF,CACD,OAAO,MAAa;AACnB,WAAQ,IAAI,oCAAoC,EAAI;IACpD;;CAGN,YACE,GACA,GACA,GACA,MACG;EAGH,IAAM,IAAQ;GACZ;GACA,GAAA,EAAA;GACA,GAAA,EAAA;GACA,MAAM;GACN,MAAM;GACN,QAAQ,EAAE,OAAO,GAAa;GAC9B,eAEE,qBAAqB,EAAU;GAClC;AACD,OAAK,IAAM,KAAa,GAAO;GAC7B,IAAM,IAAsB,IAAI,KAAK,EAAU,WAAW;AAM1D,GALA,EAAM,EAAE,KACN,GACE,EAAO,EAAc,aAAa,EACnC,GAAG,EAAc,gBAAgB,GACnC,EACD,EAAM,EAAE,KAAK,EAAU,WAAW;;AAEpC,SAAO;;CAGT,iBAAiB;AACf,MAAI,CAAC,KAAK,MAAM,YAAY,CAAC,KAAK,MAAM,SACtC;EAEF,IAAM,EAAE,UAAO,WAAQ,WAAQ,iBAAc,cAAW,kBACtD,KAAK,OACD,IAAW,KAAK,MAAM,UACtB,IAAc;GAClB;GACA;GACA,SAAS;GACT,WAAW;GACZ,EACK,IAAc;GAClB,gBAAgB;GAChB,aAAa;GAEb,wBAAwB;IACtB;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACD;GACF;AAaD,EAZI,MACF,EAAO,QAAQ,EACb,OAAO,GACR,GAEC,MACF,EAAO,QAAQ;GACb,GAAG,EAAO;GACV,WAAW,EAAU,aAAa;GACnC,GAGC,MACF,EAAO,QAAQ,EACb,OAAO,GACR;EAGH,IAAM,IAAsB,IAAe,MAAM,KAC3C,IAAc,EAAE;AAyCjB,SAvCH,EAAS,iBACT,EAAS,cAAc,UACvB,EAAS,cAAc,OAAO,SAAS,KAGvC,EAAO,KACL,KAAK,SACH,kBACA,EAAS,cAAc,QACvB,GACA,UACD,CACF,EAGD,EAAS,eACT,EAAS,YAAY,UACrB,EAAS,YAAY,OAAO,SAAS,KAGrC,EAAO,KACL,KAAK,SACH,gBACA,EAAS,YAAY,QACrB,GACA,UACD,CACF,EAEC,EAAO,SAAS,IAEhB,kBAAC,GAAD;GACU;GACR,MAAM;GACE;GACR,WAAU;GACV,kBAAkB;GAClB,CAAA,GAEM,kBAAA,GAAA,EAAK,CAAA;;CAGnB,SAAgB;AAId,SAHK,KAAK,MAAM,WAGT,KAAK,UAAU,GAFb"}
@@ -1 +1 @@
1
- {"version":3,"file":"StorybookComponentWrapper.js","names":[],"sources":["../../src/components/StorybookComponentWrapper.tsx"],"sourcesContent":["import { StandaloneLoginForm } from '@/components/Authentication/index'\nimport SynapseClient from '@/synapse-client'\nimport {\n defaultQueryClientConfig,\n SynapseContextProvider,\n SynapseContextType,\n} from '@/utils'\nimport { ApplicationSessionContextProvider } from '@/utils/AppUtils/session/ApplicationSessionContext'\nimport {\n SynapseSessionManager,\n type SessionState,\n} from '@/utils/AppUtils/session/SynapseSessionManager'\nimport { STACK_MAP, SynapseStack } from '@/utils/functions/getEndpoint'\nimport useDetectSSOCode from '@/utils/hooks/useDetectSSOCode'\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query'\nimport { ReactQueryDevtools } from '@tanstack/react-query-devtools'\nimport {\n ReactNode,\n Suspense,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from 'react'\nimport { createMemoryRouter } from 'react-router'\nimport { RouterProvider } from 'react-router/dom'\nimport { SynapseToastContainer } from './ToastMessage'\n\nconst storybookQueryClient = new QueryClient(defaultQueryClientConfig)\n\n// Module-level session manager instance, stable across story switches (like the QueryClient above)\nconst sessionManager = new SynapseSessionManager({\n onSessionInvalid: () => {\n // In Storybook, just refresh the session instead of reloading the page\n sessionManager.refreshSession()\n },\n})\n\nfunction overrideEndpoint(stack: SynapseStack) {\n const endpointConfig = STACK_MAP[stack]\n ;(window as any)['SRC_OVERRIDE_ENDPOINT_CONFIG'] = endpointConfig\n}\n\n/**\n * Wraps storybook story components to ensure that all components receive required context.\n * @param props\n * @returns\n */\nexport function StorybookComponentWrapper(props: {\n children: ReactNode\n /* This will match the `globalTypes` object in preview.tsx. */\n storybookContext: {\n args: {\n isAuthenticated?: boolean\n }\n globals: {\n stack?: SynapseStack\n showReactQueryDevtools?: boolean\n }\n parameters: {\n stack?: SynapseStack\n withRouter?: boolean\n requireLogin?: boolean\n }\n }\n}) {\n const { storybookContext } = props\n\n const currentStack: SynapseStack = (storybookContext.globals.stack ||\n storybookContext.parameters.stack) as SynapseStack\n\n useEffect(() => {\n overrideEndpoint(currentStack)\n }, [currentStack])\n\n // Subscribe to the framework-agnostic SynapseSessionManager for token/auth state\n // These methods are bound in the SynapseSessionManager constructor, so they are safe to pass directly.\n const sessionState: SessionState = useSyncExternalStore(\n // eslint-disable-next-line @typescript-eslint/unbound-method\n sessionManager.subscribe,\n // eslint-disable-next-line @typescript-eslint/unbound-method\n sessionManager.getSnapshot,\n )\n\n // Track whether we've started the manager so we only start once (module-level instance persists across renders)\n const managerStartedRef = useRef(false)\n\n useEffect(() => {\n if (!managerStartedRef.current) {\n sessionManager.start()\n managerStartedRef.current = true\n }\n return () => {\n sessionManager.dispose()\n managerStartedRef.current = false\n }\n }, [])\n\n // When the stack changes, restart the session manager to pick up the new endpoint\n useEffect(() => {\n if (managerStartedRef.current) {\n sessionManager.dispose()\n sessionManager.start()\n }\n }, [currentStack])\n\n const shouldPromptForLogin =\n storybookContext.parameters.requireLogin &&\n currentStack !== 'mock' &&\n sessionState.hasInitializedSession &&\n !sessionState.isAuthenticated\n\n const { isLoading: isLoadingSSO } = useDetectSSOCode({\n onSignInComplete: () => {\n void sessionManager.refreshSession()\n },\n onError: (err: unknown) => {\n console.error('SSO error in Storybook:', err)\n },\n isInitializingSession: !sessionState.hasInitializedSession,\n isAuthenticated: sessionState.isAuthenticated,\n })\n\n useEffect(() => {\n async function resetCache() {\n await storybookQueryClient.cancelQueries()\n await storybookQueryClient.resetQueries()\n }\n\n void resetCache()\n }, [sessionState.token, currentStack])\n\n const effectiveToken = useMemo(() => {\n if (currentStack === 'mock') {\n return storybookContext.args.isAuthenticated ? 'fake token' : undefined\n }\n return sessionState.token\n }, [sessionState.token, currentStack, storybookContext.args.isAuthenticated])\n\n const effectiveIsAuthenticated = useMemo(() => {\n if (currentStack === 'mock') {\n return !!storybookContext.args.isAuthenticated\n }\n return sessionState.isAuthenticated\n }, [\n sessionState.isAuthenticated,\n currentStack,\n storybookContext.args.isAuthenticated,\n ])\n\n const refreshSession = useCallback(async () => {\n await sessionManager.refreshSession()\n }, [])\n\n const clearSession = useCallback(async () => {\n await sessionManager.clearSession()\n }, [])\n\n const applicationSessionContext = useMemo(\n () => ({\n token: effectiveToken,\n realmId: sessionState.realmId,\n userId: sessionState.userId,\n isAuthenticated: effectiveIsAuthenticated,\n hasInitializedSession: sessionState.hasInitializedSession,\n refreshSession,\n clearSession,\n isLoadingSSO,\n twoFactorAuthSSOErrorResponse: undefined,\n termsOfServiceStatus: undefined,\n twoFactorStatus: undefined,\n }),\n [\n effectiveToken,\n effectiveIsAuthenticated,\n sessionState.realmId,\n sessionState.userId,\n sessionState.hasInitializedSession,\n refreshSession,\n clearSession,\n isLoadingSSO,\n ],\n )\n\n const synapseContext: Partial<SynapseContextType> = useMemo(\n () => ({\n accessToken: effectiveToken,\n isAuthenticated: effectiveIsAuthenticated,\n isInExperimentalMode: SynapseClient.isInSynapseExperimentalMode(),\n utcTime: SynapseClient.getUseUtcTimeFromCookie(),\n withErrorBoundary: true,\n downloadCartPageUrl: '/?path=/story/download-downloadcartpage--demo',\n }),\n [effectiveToken, effectiveIsAuthenticated],\n )\n\n const wrappedStory = (\n <Suspense fallback={'global suspense loading...'}>\n <QueryClientProvider client={storybookQueryClient}>\n <ApplicationSessionContextProvider context={applicationSessionContext}>\n <SynapseContextProvider\n key={currentStack}\n synapseContext={synapseContext}\n >\n {storybookContext.globals.showReactQueryDevtools && (\n <ReactQueryDevtools />\n )}\n <SynapseToastContainer />\n <main>\n {shouldPromptForLogin ? (\n <StandaloneLoginForm\n sessionCallback={() => {\n void sessionManager.refreshSession()\n }}\n />\n ) : (\n props.children\n )}\n </main>\n </SynapseContextProvider>\n </ApplicationSessionContextProvider>\n </QueryClientProvider>\n </Suspense>\n )\n\n if (!storybookContext.parameters.withRouter) {\n return wrappedStory\n }\n\n const router = createMemoryRouter([\n {\n path: '/',\n element: wrappedStory,\n },\n ])\n\n return <RouterProvider router={router} />\n}\n\nexport default StorybookComponentWrapper\n"],"mappings":"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"}
1
+ {"version":3,"file":"StorybookComponentWrapper.js","names":[],"sources":["../../src/components/StorybookComponentWrapper.tsx"],"sourcesContent":["import { StandaloneLoginForm } from '@/components/Authentication/index'\nimport SynapseClient from '@/synapse-client'\nimport {\n defaultQueryClientConfig,\n SynapseContextProvider,\n SynapseContextType,\n} from '@/utils'\nimport { ApplicationSessionContextProvider } from '@/utils/AppUtils/session/ApplicationSessionContext'\nimport {\n SynapseSessionManager,\n type SessionState,\n} from '@/utils/AppUtils/session/SynapseSessionManager'\nimport { STACK_MAP, SynapseStack } from '@/utils/functions/getEndpoint'\nimport useDetectSSOCode from '@/utils/hooks/useDetectSSOCode'\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query'\nimport { ReactQueryDevtools } from '@tanstack/react-query-devtools'\nimport {\n ReactNode,\n Suspense,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from 'react'\nimport { createMemoryRouter } from 'react-router'\nimport { RouterProvider } from 'react-router/dom'\nimport { SynapseToastContainer } from './ToastMessage'\n\nconst storybookQueryClient = new QueryClient(defaultQueryClientConfig)\n\n// Module-level session manager instance, stable across story switches (like the QueryClient above)\nconst sessionManager = new SynapseSessionManager({\n onSessionInvalid: () => {\n // In Storybook, just refresh the session instead of reloading the page\n sessionManager.refreshSession()\n },\n})\n\nfunction overrideEndpoint(stack: SynapseStack) {\n const endpointConfig = STACK_MAP[stack]\n ;(window as any)['SRC_OVERRIDE_ENDPOINT_CONFIG'] = endpointConfig\n}\n\n/**\n * Wraps storybook story components to ensure that all components receive required context.\n * @param props\n * @returns\n */\nexport function StorybookComponentWrapper(props: {\n children: ReactNode\n /* This will match the `globalTypes` object in preview.tsx. */\n storybookContext: {\n args: {\n isAuthenticated?: boolean\n }\n globals: {\n stack?: SynapseStack\n showReactQueryDevtools?: boolean\n }\n parameters: {\n stack?: SynapseStack\n withRouter?: boolean\n requireLogin?: boolean\n }\n }\n}) {\n const { storybookContext } = props\n\n const currentStack: SynapseStack = (storybookContext.globals.stack ||\n storybookContext.parameters.stack) as SynapseStack\n\n useEffect(() => {\n overrideEndpoint(currentStack)\n }, [currentStack])\n\n // Subscribe to the framework-agnostic SynapseSessionManager for token/auth state\n // These methods are bound in the SynapseSessionManager constructor, so they are safe to pass directly.\n const sessionState: SessionState = useSyncExternalStore(\n // eslint-disable-next-line @typescript-eslint/unbound-method\n sessionManager.subscribe,\n // eslint-disable-next-line @typescript-eslint/unbound-method\n sessionManager.getSnapshot,\n )\n\n // Track whether we've started the manager so we only start once (module-level instance persists across renders)\n const managerStartedRef = useRef(false)\n\n useEffect(() => {\n if (!managerStartedRef.current) {\n sessionManager.start()\n managerStartedRef.current = true\n }\n return () => {\n sessionManager.dispose()\n managerStartedRef.current = false\n }\n }, [])\n\n // When the stack changes, restart the session manager to pick up the new endpoint\n useEffect(() => {\n if (managerStartedRef.current) {\n sessionManager.dispose()\n sessionManager.start()\n }\n }, [currentStack])\n\n const shouldPromptForLogin =\n storybookContext.parameters.requireLogin &&\n currentStack !== 'mock' &&\n sessionState.hasInitializedSession &&\n !sessionState.isAuthenticated\n\n const { isLoading: isLoadingSSO } = useDetectSSOCode({\n onSignInComplete: () => {\n void sessionManager.refreshSession()\n },\n onError: (err: unknown) => {\n console.error('SSO error in Storybook:', err)\n },\n isInitializingSession: !sessionState.hasInitializedSession,\n isAuthenticated: sessionState.isAuthenticated,\n })\n\n useEffect(() => {\n async function resetCache() {\n await storybookQueryClient.cancelQueries()\n await storybookQueryClient.resetQueries()\n }\n\n void resetCache()\n }, [sessionState.token, currentStack])\n\n const effectiveToken = useMemo(() => {\n if (currentStack === 'mock') {\n return storybookContext.args.isAuthenticated ? 'fake token' : undefined\n }\n return sessionState.token\n }, [sessionState.token, currentStack, storybookContext.args.isAuthenticated])\n\n const effectiveIsAuthenticated = useMemo(() => {\n if (currentStack === 'mock') {\n return !!storybookContext.args.isAuthenticated\n }\n return sessionState.isAuthenticated\n }, [\n sessionState.isAuthenticated,\n currentStack,\n storybookContext.args.isAuthenticated,\n ])\n\n const refreshSession = useCallback(async () => {\n await sessionManager.refreshSession()\n }, [])\n\n const clearSession = useCallback(async () => {\n await sessionManager.clearSession()\n }, [])\n\n const applicationSessionContext = useMemo(\n () => ({\n token: effectiveToken,\n realmId: sessionState.realmId,\n userId: sessionState.userId,\n isAuthenticated: effectiveIsAuthenticated,\n hasInitializedSession: sessionState.hasInitializedSession,\n refreshSession,\n clearSession,\n isLoadingSSO,\n twoFactorAuthSSOErrorResponse: undefined,\n termsOfServiceStatus: undefined,\n twoFactorStatus: undefined,\n }),\n [\n effectiveToken,\n effectiveIsAuthenticated,\n sessionState.realmId,\n sessionState.userId,\n sessionState.hasInitializedSession,\n refreshSession,\n clearSession,\n isLoadingSSO,\n ],\n )\n\n const synapseContext: Partial<SynapseContextType> = useMemo(\n () => ({\n accessToken: effectiveToken,\n isAuthenticated: effectiveIsAuthenticated,\n isInExperimentalMode: SynapseClient.isInSynapseExperimentalMode(),\n utcTime: SynapseClient.getUseUtcTimeFromCookie(),\n withErrorBoundary: true,\n downloadCartPageUrl: '/?path=/story/download-downloadcartpage--demo',\n }),\n [effectiveToken, effectiveIsAuthenticated],\n )\n\n const wrappedStory = (\n <Suspense fallback={'global suspense loading...'}>\n <QueryClientProvider client={storybookQueryClient}>\n <ApplicationSessionContextProvider context={applicationSessionContext}>\n <SynapseContextProvider\n key={currentStack}\n synapseContext={synapseContext}\n >\n {storybookContext.globals.showReactQueryDevtools && (\n <ReactQueryDevtools />\n )}\n <SynapseToastContainer />\n <main>\n {shouldPromptForLogin ? (\n <StandaloneLoginForm\n sessionCallback={() => {\n void sessionManager.refreshSession()\n }}\n />\n ) : (\n props.children\n )}\n </main>\n </SynapseContextProvider>\n </ApplicationSessionContextProvider>\n </QueryClientProvider>\n </Suspense>\n )\n\n if (!storybookContext.parameters.withRouter) {\n return wrappedStory\n }\n\n const router = createMemoryRouter([\n {\n path: '/',\n element: wrappedStory,\n },\n ])\n\n return <RouterProvider router={router} />\n}\n\nexport default StorybookComponentWrapper\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"SubsectionRowRenderer.js","names":[],"sources":["../../../src/components/SubsectionRowRenderer/SubsectionRowRenderer.tsx"],"sourcesContent":["import SynapseClient from '@/synapse-client'\nimport { SynapseConstants } from '@/utils'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport {\n getAdditionalFilters,\n parseEntityIdFromSqlStatement,\n SQLOperator,\n} from '@/utils/functions/SqlFunctions'\nimport { Typography } from '@mui/material'\nimport {\n ColumnType,\n ColumnTypeEnum,\n QueryBundleRequest,\n RowSet,\n} from '@sage-bionetworks/synapse-types'\nimport { useState } from 'react'\nimport { useDeepCompareEffectNoCheck } from 'use-deep-compare-effect'\nimport { ColumnSpecifiedLink } from '../CardContainerLogic'\nimport MarkdownSynapse from '../Markdown/MarkdownSynapse'\nimport { SkeletonTable } from '../Skeleton/SkeletonTable'\n\nexport type FriendlyValuesMap = {\n [index: string]: string\n}\n\nexport type SubsectionRowRendererProps = {\n sql: string\n isMarkdown?: boolean\n sqlOperator?: SQLOperator\n searchParams?: Record<string, string>\n columnLink?: ColumnSpecifiedLink\n friendlyValuesMap?: FriendlyValuesMap\n columnNameIsSectionTitle?: boolean\n limit?: number\n additionalFiltersSessionStorageKey?: string\n}\n\nconst LIST_COLUMN_TYPES: ColumnType[] = [\n ColumnTypeEnum.BOOLEAN_LIST,\n ColumnTypeEnum.DATE_LIST,\n ColumnTypeEnum.ENTITYID_LIST,\n ColumnTypeEnum.INTEGER_LIST,\n ColumnTypeEnum.STRING_LIST,\n]\n\nfunction SubsectionRowRenderer({\n sql,\n searchParams,\n sqlOperator,\n isMarkdown = false,\n columnLink,\n friendlyValuesMap,\n columnNameIsSectionTitle = false,\n limit,\n additionalFiltersSessionStorageKey,\n}: SubsectionRowRendererProps) {\n const { accessToken } = useSynapseContext()\n const [rowSet, setRowSet] = useState<RowSet>()\n const [isLoading, setIsLoading] = useState<boolean>()\n useDeepCompareEffectNoCheck(() => {\n const fetchData = async function () {\n setIsLoading(true)\n const entityId = parseEntityIdFromSqlStatement(sql)\n const additionalFilters = getAdditionalFilters(\n searchParams,\n sqlOperator,\n additionalFiltersSessionStorageKey,\n )\n const partMask = SynapseConstants.BUNDLE_MASK_QUERY_RESULTS\n const request: QueryBundleRequest = {\n partMask,\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n entityId,\n query: {\n sql,\n limit,\n additionalFilters,\n },\n }\n\n const queryResultBundle = await SynapseClient.getQueryTableResults(\n request,\n accessToken,\n )\n setIsLoading(false)\n const queryResults = queryResultBundle?.queryResult?.queryResults\n if (queryResults) {\n setRowSet(queryResults)\n } else {\n console.log('SubsectionRowRenderer: Error getting data')\n }\n }\n fetchData()\n }, [sql, accessToken, searchParams, sqlOperator])\n\n /**\n * If a \"friendly values map\" was provided, then use the friendly value if any of the raw values match.\n * Otherwise, just return the raw value.\n * @param rawValue\n * @returns\n */\n const getFriendlyValue = (rawValue: string) => {\n if (!friendlyValuesMap) {\n return rawValue\n }\n const friendlyValue = friendlyValuesMap[rawValue]\n return friendlyValue ? friendlyValue : rawValue\n }\n return (\n <div className=\"SubsectionRowRenderer\">\n {isLoading && <SkeletonTable numRows={2} numCols={1} />}\n {!isLoading &&\n rowSet &&\n rowSet.rows.length > 0 &&\n rowSet.headers.map((selectColumn, colIndex) => {\n // If a link column was provided (that contain URLs), do not create a page sub-section for that column.\n if (columnLink && selectColumn.name == columnLink.linkColumnName) {\n return <></>\n }\n return (\n <div\n key={`header-${colIndex}`}\n className=\"SubsectionRowRenderer__item\"\n role=\"table\"\n >\n <Typography\n variant={\n columnNameIsSectionTitle ? 'sectionTitle' : 'subsectionHeader'\n }\n role=\"heading\"\n style={{ paddingTop: '10px', marginBottom: '5px' }}\n >\n {selectColumn.name}\n </Typography>\n {columnNameIsSectionTitle && <hr />}\n <div role=\"rowgroup\">\n {rowSet.rows.map((row, rowIndex) => {\n const cellValue = row.values[colIndex]\n // If the cell value is undefined, then go to the next row.\n if (!cellValue) {\n return <></>\n }\n let values\n // If this cell value represents a multi-value (the select column type is a *_LIST column), then parse it and break it apart\n if (LIST_COLUMN_TYPES.includes(selectColumn.columnType)) {\n const jsonData: string[] = JSON.parse(cellValue)\n values = jsonData.map((val: string, index: number) => {\n return (\n <div\n key={`row-${rowIndex}-col-${colIndex}-multi-value`}\n className=\"SubsectionRowRenderer__item__value\"\n role=\"row\"\n >\n {isMarkdown && (\n <MarkdownSynapse markdown={getFriendlyValue(val)} />\n )}\n {!isMarkdown && <p>{getFriendlyValue(val)}</p>}\n </div>\n )\n })\n } else {\n // If this cell value represents a single value\n let renderedValue\n const friendlyCellValue = getFriendlyValue(cellValue)\n if (isMarkdown) {\n renderedValue = (\n <MarkdownSynapse markdown={friendlyCellValue} />\n )\n } else if (\n columnLink &&\n columnLink.matchColumnName == selectColumn.name\n ) {\n // If a link column was provided, then we need to create links (the url is in this other column)\n const urlColumnIndex = rowSet.headers.findIndex(\n col => col.name == columnLink.linkColumnName,\n )\n const values = row.values as string[]\n if (values.some(value => value === null)) {\n console.warn(\n 'Row has null value(s) when no nulls expected',\n )\n }\n\n if (urlColumnIndex > -1) {\n renderedValue = (\n <a\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n href={values[urlColumnIndex]}\n >\n {friendlyCellValue}\n </a>\n )\n } else {\n renderedValue = <p>{friendlyCellValue}</p>\n }\n } else {\n renderedValue = <p>{friendlyCellValue}</p>\n }\n values = (\n <div\n key={`row-${rowIndex}-col-${colIndex}-single`}\n className=\"SubsectionRowRenderer__item__value\"\n role=\"row\"\n >\n {renderedValue}\n </div>\n )\n }\n return values\n })}\n </div>\n </div>\n )\n })}\n </div>\n )\n}\n\nexport default SubsectionRowRenderer\n"],"mappings":"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"}
1
+ {"version":3,"file":"SubsectionRowRenderer.js","names":[],"sources":["../../../src/components/SubsectionRowRenderer/SubsectionRowRenderer.tsx"],"sourcesContent":["import SynapseClient from '@/synapse-client'\nimport { SynapseConstants } from '@/utils'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport {\n getAdditionalFilters,\n parseEntityIdFromSqlStatement,\n SQLOperator,\n} from '@/utils/functions/SqlFunctions'\nimport { Typography } from '@mui/material'\nimport {\n ColumnType,\n ColumnTypeEnum,\n QueryBundleRequest,\n RowSet,\n} from '@sage-bionetworks/synapse-types'\nimport { useState } from 'react'\nimport { useDeepCompareEffectNoCheck } from 'use-deep-compare-effect'\nimport { ColumnSpecifiedLink } from '../CardContainerLogic'\nimport MarkdownSynapse from '../Markdown/MarkdownSynapse'\nimport { SkeletonTable } from '../Skeleton/SkeletonTable'\n\nexport type FriendlyValuesMap = {\n [index: string]: string\n}\n\nexport type SubsectionRowRendererProps = {\n sql: string\n isMarkdown?: boolean\n sqlOperator?: SQLOperator\n searchParams?: Record<string, string>\n columnLink?: ColumnSpecifiedLink\n friendlyValuesMap?: FriendlyValuesMap\n columnNameIsSectionTitle?: boolean\n limit?: number\n additionalFiltersSessionStorageKey?: string\n}\n\nconst LIST_COLUMN_TYPES: ColumnType[] = [\n ColumnTypeEnum.BOOLEAN_LIST,\n ColumnTypeEnum.DATE_LIST,\n ColumnTypeEnum.ENTITYID_LIST,\n ColumnTypeEnum.INTEGER_LIST,\n ColumnTypeEnum.STRING_LIST,\n]\n\nfunction SubsectionRowRenderer({\n sql,\n searchParams,\n sqlOperator,\n isMarkdown = false,\n columnLink,\n friendlyValuesMap,\n columnNameIsSectionTitle = false,\n limit,\n additionalFiltersSessionStorageKey,\n}: SubsectionRowRendererProps) {\n const { accessToken } = useSynapseContext()\n const [rowSet, setRowSet] = useState<RowSet>()\n const [isLoading, setIsLoading] = useState<boolean>()\n useDeepCompareEffectNoCheck(() => {\n const fetchData = async function () {\n setIsLoading(true)\n const entityId = parseEntityIdFromSqlStatement(sql)\n const additionalFilters = getAdditionalFilters(\n searchParams,\n sqlOperator,\n additionalFiltersSessionStorageKey,\n )\n const partMask = SynapseConstants.BUNDLE_MASK_QUERY_RESULTS\n const request: QueryBundleRequest = {\n partMask,\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n entityId,\n query: {\n sql,\n limit,\n additionalFilters,\n },\n }\n\n const queryResultBundle = await SynapseClient.getQueryTableResults(\n request,\n accessToken,\n )\n setIsLoading(false)\n const queryResults = queryResultBundle?.queryResult?.queryResults\n if (queryResults) {\n setRowSet(queryResults)\n } else {\n console.log('SubsectionRowRenderer: Error getting data')\n }\n }\n fetchData()\n }, [sql, accessToken, searchParams, sqlOperator])\n\n /**\n * If a \"friendly values map\" was provided, then use the friendly value if any of the raw values match.\n * Otherwise, just return the raw value.\n * @param rawValue\n * @returns\n */\n const getFriendlyValue = (rawValue: string) => {\n if (!friendlyValuesMap) {\n return rawValue\n }\n const friendlyValue = friendlyValuesMap[rawValue]\n return friendlyValue ? friendlyValue : rawValue\n }\n return (\n <div className=\"SubsectionRowRenderer\">\n {isLoading && <SkeletonTable numRows={2} numCols={1} />}\n {!isLoading &&\n rowSet &&\n rowSet.rows.length > 0 &&\n rowSet.headers.map((selectColumn, colIndex) => {\n // If a link column was provided (that contain URLs), do not create a page sub-section for that column.\n if (columnLink && selectColumn.name == columnLink.linkColumnName) {\n return <></>\n }\n return (\n <div\n key={`header-${colIndex}`}\n className=\"SubsectionRowRenderer__item\"\n role=\"table\"\n >\n <Typography\n variant={\n columnNameIsSectionTitle ? 'sectionTitle' : 'subsectionHeader'\n }\n role=\"heading\"\n style={{ paddingTop: '10px', marginBottom: '5px' }}\n >\n {selectColumn.name}\n </Typography>\n {columnNameIsSectionTitle && <hr />}\n <div role=\"rowgroup\">\n {rowSet.rows.map((row, rowIndex) => {\n const cellValue = row.values[colIndex]\n // If the cell value is undefined, then go to the next row.\n if (!cellValue) {\n return <></>\n }\n let values\n // If this cell value represents a multi-value (the select column type is a *_LIST column), then parse it and break it apart\n if (LIST_COLUMN_TYPES.includes(selectColumn.columnType)) {\n const jsonData: string[] = JSON.parse(cellValue)\n values = jsonData.map((val: string, index: number) => {\n return (\n <div\n key={`row-${rowIndex}-col-${colIndex}-multi-value`}\n className=\"SubsectionRowRenderer__item__value\"\n role=\"row\"\n >\n {isMarkdown && (\n <MarkdownSynapse markdown={getFriendlyValue(val)} />\n )}\n {!isMarkdown && <p>{getFriendlyValue(val)}</p>}\n </div>\n )\n })\n } else {\n // If this cell value represents a single value\n let renderedValue\n const friendlyCellValue = getFriendlyValue(cellValue)\n if (isMarkdown) {\n renderedValue = (\n <MarkdownSynapse markdown={friendlyCellValue} />\n )\n } else if (\n columnLink &&\n columnLink.matchColumnName == selectColumn.name\n ) {\n // If a link column was provided, then we need to create links (the url is in this other column)\n const urlColumnIndex = rowSet.headers.findIndex(\n col => col.name == columnLink.linkColumnName,\n )\n const values = row.values as string[]\n if (values.some(value => value === null)) {\n console.warn(\n 'Row has null value(s) when no nulls expected',\n )\n }\n\n if (urlColumnIndex > -1) {\n renderedValue = (\n <a\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n href={values[urlColumnIndex]}\n >\n {friendlyCellValue}\n </a>\n )\n } else {\n renderedValue = <p>{friendlyCellValue}</p>\n }\n } else {\n renderedValue = <p>{friendlyCellValue}</p>\n }\n values = (\n <div\n key={`row-${rowIndex}-col-${colIndex}-single`}\n className=\"SubsectionRowRenderer__item__value\"\n role=\"row\"\n >\n {renderedValue}\n </div>\n )\n }\n return values\n })}\n </div>\n </div>\n )\n })}\n </div>\n )\n}\n\nexport default SubsectionRowRenderer\n"],"mappings":";;;;;;;;;;;;;AAqCA,IAAM,IAAkC;CACtC,EAAe;CACf,EAAe;CACf,EAAe;CACf,EAAe;CACf,EAAe;CAChB;AAED,SAAS,EAAsB,EAC7B,QACA,iBACA,gBACA,gBAAa,IACb,eACA,sBACA,8BAA2B,IAC3B,UACA,yCAC6B;CAC7B,IAAM,EAAE,mBAAgB,GAAmB,EACrC,CAAC,GAAQ,KAAa,GAAkB,EACxC,CAAC,GAAW,KAAgB,GAAmB;AACrD,SAAkC;AAiChC,oBAhCoC;AAClC,KAAa,GAAK;GAQlB,IAAM,IAA8B;IAClC,UAAA;IACA,cAAc;IACd,UAVe,EAA8B,EAU7C;IACA,OAAO;KACL;KACA;KACA,mBAbsB,EACxB,GACA,GACA,EAUE;KACD;IACF,EAEK,IAAoB,MAAM,EAAc,qBAC5C,GACA,EACD;AACD,KAAa,GAAM;GACnB,IAAM,IAAe,GAAmB,aAAa;AACrD,GAAI,IACF,EAAU,EAAa,GAEvB,QAAQ,IAAI,4CAA4C;MAGjD;IACV;EAAC;EAAK;EAAa;EAAc;EAAY,CAAC;CAQjD,IAAM,KAAoB,MACnB,KAGiB,EAAkB,MAF/B;AAKX,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACG,KAAa,kBAAC,GAAD;GAAe,SAAS;GAAG,SAAS;GAAK,CAAA,EACtD,CAAC,KACA,KACA,EAAO,KAAK,SAAS,KACrB,EAAO,QAAQ,KAAK,GAAc,MAE5B,KAAc,EAAa,QAAQ,EAAW,iBACzC,kBAAA,GAAA,EAAK,CAAA,GAGZ,kBAAC,OAAD;GAEE,WAAU;GACV,MAAK;aAHP;IAKE,kBAAC,GAAD;KACE,SACE,IAA2B,iBAAiB;KAE9C,MAAK;KACL,OAAO;MAAE,YAAY;MAAQ,cAAc;MAAO;eAEjD,EAAa;KACH,CAAA;IACZ,KAA4B,kBAAC,MAAD,EAAM,CAAA;IACnC,kBAAC,OAAD;KAAK,MAAK;eACP,EAAO,KAAK,KAAK,GAAK,MAAa;MAClC,IAAM,IAAY,EAAI,OAAO;AAE7B,UAAI,CAAC,EACH,QAAO,kBAAA,GAAA,EAAK,CAAA;MAEd,IAAI;AAEJ,UAAI,EAAkB,SAAS,EAAa,WAAW,CAErD,KAD2B,KAAK,MAAM,EAC7B,CAAS,KAAK,GAAa,MAEhC,kBAAC,OAAD;OAEE,WAAU;OACV,MAAK;iBAHP,CAKG,KACC,kBAAC,GAAD,EAAiB,UAAU,EAAiB,EAAI,EAAI,CAAA,EAErD,CAAC,KAAc,kBAAC,KAAD,EAAA,UAAI,EAAiB,EAAI,EAAK,CAAA,CAC1C;SARC,OAAO,EAAS,OAAO,EAAS,cAQjC,CAER;WACG;OAEL,IAAI,GACE,IAAoB,EAAiB,EAAU;AACrD,WAAI,EACF,KACE,kBAAC,GAAD,EAAiB,UAAU,GAAqB,CAAA;gBAGlD,KACA,EAAW,mBAAmB,EAAa,MAC3C;QAEA,IAAM,IAAiB,EAAO,QAAQ,WACpC,MAAO,EAAI,QAAQ,EAAW,eAC/B,EACK,IAAS,EAAI;AAOnB,QANI,EAAO,MAAK,MAAS,MAAU,KAAK,IACtC,QAAQ,KACN,+CACD,EAGH,AAWE,IAXE,IAAiB,KAEjB,kBAAC,KAAD;SACE,KAAI;SACJ,QAAO;SACP,MAAM,EAAO;mBAEZ;SACC,CAAA,GAGU,kBAAC,KAAD,EAAA,UAAI,GAAsB,CAAA;aAG5C,KAAgB,kBAAC,KAAD,EAAA,UAAI,GAAsB,CAAA;AAE5C,WACE,kBAAC,OAAD;QAEE,WAAU;QACV,MAAK;kBAEJ;QACG,EALC,OAAO,EAAS,OAAO,EAAS,SAKjC;;AAGV,aAAO;OACP;KACE,CAAA;IACF;KA3FC,UAAU,IA2FX,CAER,CACA"}
@@ -1 +1 @@
1
- {"version":3,"file":"SustainabilityScorecard.js","names":[],"sources":["../../../src/components/SustainabilityScorecard/SustainabilityScorecard.tsx"],"sourcesContent":["import {\n Box,\n Link as MuiLink,\n Skeleton,\n Stack,\n Tooltip,\n Typography,\n} from '@mui/material'\nimport React from 'react'\nimport CloseIcon from '@mui/icons-material/Close'\nimport useGetQueryResultBundle from '@/synapse-queries/entity/useGetQueryResultBundle'\nimport { getFieldIndex } from '@/utils/functions/queryUtils'\n\nimport { SxProps, Theme } from '@mui/material'\nimport {\n getMetricValues,\n SUSTAINABILITY_ICON_COLORS,\n SustainabilityScorecardBaseProps,\n} from './SustainabilityScorecardUtils'\nimport { InfoTwoTone } from '@mui/icons-material'\nimport { CheckIcon } from '@/assets/icons/terms/CheckIcon'\nimport NoContentAvailable from '../SynapseTable/NoContentAvailable'\nimport Dial from './Dial'\nimport { Link as RouterLink, useLocation } from 'react-router'\n\nexport type MetricsConfig = {\n /** Name of the metric column in the table */\n key: string\n /** Display label for the metric */\n label: string\n /** Shown as a tooltip in SustainabilityScorecard and as summary text in SustainabilityScorecardSummary */\n text?: string\n}\n\nexport type SustainabilityScorecardProps = SustainabilityScorecardBaseProps & {\n sx?: SxProps<Theme>\n sustainabilityReportLink?: string\n}\n\ntype MetricRowProps = {\n metricValues: string[]\n metricsConfig: MetricsConfig[]\n}\n\nconst MetricRow = ({\n metricValues,\n metricsConfig,\n}: MetricRowProps): React.ReactNode => {\n return (\n <>\n {metricsConfig.map((metric, index) => (\n <Box sx={{ display: 'flex', padding: '4px 20px' }} key={metric.key}>\n <Typography\n variant=\"smallText1\"\n sx={{ alignItems: 'center', display: 'flex', gap: '8px' }}\n >\n {metric.label}\n <Tooltip title={metric.text} placement=\"top\">\n <InfoTwoTone\n sx={{\n width: '18px',\n height: '18px',\n color: 'primary.contrastText',\n }}\n />\n </Tooltip>\n </Typography>\n {metricValues[index] === 'true' ? (\n <Box\n sx={{\n backgroundColor: SUSTAINABILITY_ICON_COLORS.check,\n borderRadius: '50%',\n width: 18,\n height: 18,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n marginLeft: 'auto',\n }}\n >\n <CheckIcon\n sx={{ color: 'primary.contrastText', fontSize: '11px' }}\n />\n </Box>\n ) : (\n <Box\n sx={{\n backgroundColor: SUSTAINABILITY_ICON_COLORS.close,\n borderRadius: '50%',\n width: 18,\n height: 18,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n marginLeft: 'auto',\n }}\n >\n <CloseIcon\n sx={{ color: 'primary.contrastText', fontSize: '14px' }}\n />\n </Box>\n )}\n </Box>\n ))}\n </>\n )\n}\n\n/* SustainabilityScorecard component displays sustainability metrics and a dial based on the sustainability score of the entity. */\nconst SustainabilityScorecard = ({\n metricsConfig,\n scoreDescriptorColumnName,\n queryRequest,\n sx,\n sustainabilityReportLink,\n}: SustainabilityScorecardProps): React.ReactNode => {\n const { data: queryResultBundle, isLoading } =\n useGetQueryResultBundle(queryRequest)\n const location = useLocation()\n const search = location.search\n\n if (isLoading) {\n return <Skeleton width={'100%'} height={'100%'} />\n }\n\n const data = queryResultBundle?.queryResult!.queryResults\n\n if (data?.rows?.length === 0) {\n return (\n <Stack sx={{ display: 'flex', padding: '20px', ...sx }}>\n <Typography sx={{ paddingBottom: '20px' }} variant=\"subsectionHeader\">\n Sustainability Index\n </Typography>\n <NoContentAvailable />\n </Stack>\n )\n }\n\n const scoreDescriptorColIndex = getFieldIndex(\n scoreDescriptorColumnName,\n queryResultBundle,\n )\n\n const scoreDescriptor = data?.rows[0].values[scoreDescriptorColIndex]\n\n const metricValues = getMetricValues(\n data?.rows[0],\n queryResultBundle,\n metricsConfig,\n )\n\n return (\n <Box\n sx={{\n display: 'flex',\n flexDirection: { xs: 'column', sm: 'row' },\n padding: '20px',\n gap: '20px',\n ...sx,\n }}\n >\n <Stack sx={{ display: 'flex', gap: '20px', alignItems: 'center' }}>\n <Typography variant=\"subsectionHeader\">Sustainability Index</Typography>\n <Dial scoreDescriptor={scoreDescriptor ?? ''} />\n </Stack>\n <Stack sx={{ flex: 1, gap: '2px' }}>\n <MetricRow metricValues={metricValues} metricsConfig={metricsConfig} />\n {sustainabilityReportLink && (\n <MuiLink\n component={RouterLink}\n to={{ pathname: sustainabilityReportLink, search }}\n sx={{ padding: '4px 20px', fontSize: '14px' }}\n >\n View this tool’s sustainability and reusability report\n </MuiLink>\n )}\n </Stack>\n </Box>\n )\n}\n\nexport default SustainabilityScorecard\n"],"mappings":";;;;;;;;;;;;;AA4CA,IAAM,KAAa,EACjB,iBACA,uBAGE,kBAAA,GAAA,EAAA,UACG,EAAc,KAAK,GAAQ,MAC1B,kBAAC,GAAD;CAAK,IAAI;EAAE,SAAS;EAAQ,SAAS;EAAY;WAAjD,CACE,kBAAC,GAAD;EACE,SAAQ;EACR,IAAI;GAAE,YAAY;GAAU,SAAS;GAAQ,KAAK;GAAO;YAF3D,CAIG,EAAO,OACR,kBAAC,GAAD;GAAS,OAAO,EAAO;GAAM,WAAU;aACrC,kBAAC,GAAD,EACE,IAAI;IACF,OAAO;IACP,QAAQ;IACR,OAAO;IACR,EACD,CAAA;GACM,CAAA,CACC;KACZ,EAAa,OAAW,SACvB,kBAAC,GAAD;EACE,IAAI;GACF,iBAAiB,EAA2B;GAC5C,cAAc;GACd,OAAO;GACP,QAAQ;GACR,SAAS;GACT,YAAY;GACZ,gBAAgB;GAChB,YAAY;GACb;YAED,kBAAC,GAAD,EACE,IAAI;GAAE,OAAO;GAAwB,UAAU;GAAQ,EACvD,CAAA;EACE,CAAA,GAEN,kBAAC,GAAD;EACE,IAAI;GACF,iBAAiB,EAA2B;GAC5C,cAAc;GACd,OAAO;GACP,QAAQ;GACR,SAAS;GACT,YAAY;GACZ,gBAAgB;GAChB,YAAY;GACb;YAED,kBAAC,GAAD,EACE,IAAI;GAAE,OAAO;GAAwB,UAAU;GAAQ,EACvD,CAAA;EACE,CAAA,CAEJ;GAnDkD,EAAO,IAmDzD,CACN,EACD,CAAA,EAKD,KAA2B,EAC/B,kBACA,8BACA,iBACA,OACA,kCACmD;CACnD,IAAM,EAAE,MAAM,GAAmB,iBAC/B,EAAwB,EAAa,EAEjC,IADW,GAAa,CACN;AAExB,KAAI,EACF,QAAO,kBAAC,GAAD;EAAU,OAAO;EAAQ,QAAQ;EAAU,CAAA;CAGpD,IAAM,IAAO,GAAmB,YAAa;AAE7C,KAAI,GAAM,MAAM,WAAW,EACzB,QACE,kBAAC,GAAD;EAAO,IAAI;GAAE,SAAS;GAAQ,SAAS;GAAQ,GAAG;GAAI;YAAtD,CACE,kBAAC,GAAD;GAAY,IAAI,EAAE,eAAe,QAAQ;GAAE,SAAQ;aAAmB;GAEzD,CAAA,EACb,kBAAC,GAAD,EAAsB,CAAA,CAChB;;CAIZ,IAAM,IAA0B,EAC9B,GACA,EACD,EAEK,IAAkB,GAAM,KAAK,GAAG,OAAO,IAEvC,IAAe,EACnB,GAAM,KAAK,IACX,GACA,EACD;AAED,QACE,kBAAC,GAAD;EACE,IAAI;GACF,SAAS;GACT,eAAe;IAAE,IAAI;IAAU,IAAI;IAAO;GAC1C,SAAS;GACT,KAAK;GACL,GAAG;GACJ;YAPH,CASE,kBAAC,GAAD;GAAO,IAAI;IAAE,SAAS;IAAQ,KAAK;IAAQ,YAAY;IAAU;aAAjE,CACE,kBAAC,GAAD;IAAY,SAAQ;cAAmB;IAAiC,CAAA,EACxE,kBAAC,GAAD,EAAM,iBAAiB,KAAmB,IAAM,CAAA,CAC1C;MACR,kBAAC,GAAD;GAAO,IAAI;IAAE,MAAM;IAAG,KAAK;IAAO;aAAlC,CACE,kBAAC,GAAD;IAAyB;IAA6B;IAAiB,CAAA,EACtE,KACC,kBAAC,GAAD;IACE,WAAW;IACX,IAAI;KAAE,UAAU;KAA0B;KAAQ;IAClD,IAAI;KAAE,SAAS;KAAY,UAAU;KAAQ;cAC9C;IAES,CAAA,CAEN;KACJ"}
1
+ {"version":3,"file":"SustainabilityScorecard.js","names":[],"sources":["../../../src/components/SustainabilityScorecard/SustainabilityScorecard.tsx"],"sourcesContent":["import {\n Box,\n Link as MuiLink,\n Skeleton,\n Stack,\n Tooltip,\n Typography,\n} from '@mui/material'\nimport React from 'react'\nimport CloseIcon from '@mui/icons-material/Close'\nimport useGetQueryResultBundle from '@/synapse-queries/entity/useGetQueryResultBundle'\nimport { getFieldIndex } from '@/utils/functions/queryUtils'\n\nimport { SxProps, Theme } from '@mui/material'\nimport {\n getMetricValues,\n SUSTAINABILITY_ICON_COLORS,\n SustainabilityScorecardBaseProps,\n} from './SustainabilityScorecardUtils'\nimport { InfoTwoTone } from '@mui/icons-material'\nimport { CheckIcon } from '@/assets/icons/terms/CheckIcon'\nimport NoContentAvailable from '../SynapseTable/NoContentAvailable'\nimport Dial from './Dial'\nimport { Link as RouterLink, useLocation } from 'react-router'\n\nexport type MetricsConfig = {\n /** Name of the metric column in the table */\n key: string\n /** Display label for the metric */\n label: string\n /** Shown as a tooltip in SustainabilityScorecard and as summary text in SustainabilityScorecardSummary */\n text?: string\n}\n\nexport type SustainabilityScorecardProps = SustainabilityScorecardBaseProps & {\n sx?: SxProps<Theme>\n sustainabilityReportLink?: string\n}\n\ntype MetricRowProps = {\n metricValues: string[]\n metricsConfig: MetricsConfig[]\n}\n\nconst MetricRow = ({\n metricValues,\n metricsConfig,\n}: MetricRowProps): React.ReactNode => {\n return (\n <>\n {metricsConfig.map((metric, index) => (\n <Box sx={{ display: 'flex', padding: '4px 20px' }} key={metric.key}>\n <Typography\n variant=\"smallText1\"\n sx={{ alignItems: 'center', display: 'flex', gap: '8px' }}\n >\n {metric.label}\n <Tooltip title={metric.text} placement=\"top\">\n <InfoTwoTone\n sx={{\n width: '18px',\n height: '18px',\n color: 'primary.contrastText',\n }}\n />\n </Tooltip>\n </Typography>\n {metricValues[index] === 'true' ? (\n <Box\n sx={{\n backgroundColor: SUSTAINABILITY_ICON_COLORS.check,\n borderRadius: '50%',\n width: 18,\n height: 18,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n marginLeft: 'auto',\n }}\n >\n <CheckIcon\n sx={{ color: 'primary.contrastText', fontSize: '11px' }}\n />\n </Box>\n ) : (\n <Box\n sx={{\n backgroundColor: SUSTAINABILITY_ICON_COLORS.close,\n borderRadius: '50%',\n width: 18,\n height: 18,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n marginLeft: 'auto',\n }}\n >\n <CloseIcon\n sx={{ color: 'primary.contrastText', fontSize: '14px' }}\n />\n </Box>\n )}\n </Box>\n ))}\n </>\n )\n}\n\n/* SustainabilityScorecard component displays sustainability metrics and a dial based on the sustainability score of the entity. */\nconst SustainabilityScorecard = ({\n metricsConfig,\n scoreDescriptorColumnName,\n queryRequest,\n sx,\n sustainabilityReportLink,\n}: SustainabilityScorecardProps): React.ReactNode => {\n const { data: queryResultBundle, isLoading } =\n useGetQueryResultBundle(queryRequest)\n const location = useLocation()\n const search = location.search\n\n if (isLoading) {\n return <Skeleton width={'100%'} height={'100%'} />\n }\n\n const data = queryResultBundle?.queryResult!.queryResults\n\n if (data?.rows?.length === 0) {\n return (\n <Stack sx={{ display: 'flex', padding: '20px', ...sx }}>\n <Typography sx={{ paddingBottom: '20px' }} variant=\"subsectionHeader\">\n Sustainability Index\n </Typography>\n <NoContentAvailable />\n </Stack>\n )\n }\n\n const scoreDescriptorColIndex = getFieldIndex(\n scoreDescriptorColumnName,\n queryResultBundle,\n )\n\n const scoreDescriptor = data?.rows[0].values[scoreDescriptorColIndex]\n\n const metricValues = getMetricValues(\n data?.rows[0],\n queryResultBundle,\n metricsConfig,\n )\n\n return (\n <Box\n sx={{\n display: 'flex',\n flexDirection: { xs: 'column', sm: 'row' },\n padding: '20px',\n gap: '20px',\n ...sx,\n }}\n >\n <Stack sx={{ display: 'flex', gap: '20px', alignItems: 'center' }}>\n <Typography variant=\"subsectionHeader\">Sustainability Index</Typography>\n <Dial scoreDescriptor={scoreDescriptor ?? ''} />\n </Stack>\n <Stack sx={{ flex: 1, gap: '2px' }}>\n <MetricRow metricValues={metricValues} metricsConfig={metricsConfig} />\n {sustainabilityReportLink && (\n <MuiLink\n component={RouterLink}\n to={{ pathname: sustainabilityReportLink, search }}\n sx={{ padding: '4px 20px', fontSize: '14px' }}\n >\n View this tool’s sustainability and reusability report\n </MuiLink>\n )}\n </Stack>\n </Box>\n )\n}\n\nexport default SustainabilityScorecard\n"],"mappings":";;;;;;;;;;;;;AA4CA,IAAM,KAAa,EACjB,iBACA,uBAGE,kBAAA,GAAA,EAAA,UACG,EAAc,KAAK,GAAQ,MAC1B,kBAAC,GAAD;CAAK,IAAI;EAAE,SAAS;EAAQ,SAAS;EAAY;WAAjD,CACE,kBAAC,GAAD;EACE,SAAQ;EACR,IAAI;GAAE,YAAY;GAAU,SAAS;GAAQ,KAAK;GAAO;YAF3D,CAIG,EAAO,OACR,kBAAC,GAAD;GAAS,OAAO,EAAO;GAAM,WAAU;aACrC,kBAAC,GAAD,EACE,IAAI;IACF,OAAO;IACP,QAAQ;IACR,OAAO;IACR,EACD,CAAA;GACM,CAAA,CACC;KACZ,EAAa,OAAW,SACvB,kBAAC,GAAD;EACE,IAAI;GACF,iBAAiB,EAA2B;GAC5C,cAAc;GACd,OAAO;GACP,QAAQ;GACR,SAAS;GACT,YAAY;GACZ,gBAAgB;GAChB,YAAY;GACb;YAED,kBAAC,GAAD,EACE,IAAI;GAAE,OAAO;GAAwB,UAAU;GAAQ,EACvD,CAAA;EACE,CAAA,GAEN,kBAAC,GAAD;EACE,IAAI;GACF,iBAAiB,EAA2B;GAC5C,cAAc;GACd,OAAO;GACP,QAAQ;GACR,SAAS;GACT,YAAY;GACZ,gBAAgB;GAChB,YAAY;GACb;YAED,kBAAC,GAAD,EACE,IAAI;GAAE,OAAO;GAAwB,UAAU;GAAQ,EACvD,CAAA;EACE,CAAA,CAEJ;GAnDkD,EAAO,IAmDzD,CACN,EACD,CAAA,EAKD,KAA2B,EAC/B,kBACA,8BACA,iBACA,OACA,kCACmD;CACnD,IAAM,EAAE,MAAM,GAAmB,iBAC/B,EAAwB,EAAa,EAEjC,IADW,GACF,CAAS;AAExB,KAAI,EACF,QAAO,kBAAC,GAAD;EAAU,OAAO;EAAQ,QAAQ;EAAU,CAAA;CAGpD,IAAM,IAAO,GAAmB,YAAa;AAE7C,KAAI,GAAM,MAAM,WAAW,EACzB,QACE,kBAAC,GAAD;EAAO,IAAI;GAAE,SAAS;GAAQ,SAAS;GAAQ,GAAG;GAAI;YAAtD,CACE,kBAAC,GAAD;GAAY,IAAI,EAAE,eAAe,QAAQ;GAAE,SAAQ;aAAmB;GAEzD,CAAA,EACb,kBAAC,GAAD,EAAsB,CAAA,CAChB;;CAIZ,IAAM,IAA0B,EAC9B,GACA,EACD,EAEK,IAAkB,GAAM,KAAK,GAAG,OAAO,IAEvC,IAAe,EACnB,GAAM,KAAK,IACX,GACA,EACD;AAED,QACE,kBAAC,GAAD;EACE,IAAI;GACF,SAAS;GACT,eAAe;IAAE,IAAI;IAAU,IAAI;IAAO;GAC1C,SAAS;GACT,KAAK;GACL,GAAG;GACJ;YAPH,CASE,kBAAC,GAAD;GAAO,IAAI;IAAE,SAAS;IAAQ,KAAK;IAAQ,YAAY;IAAU;aAAjE,CACE,kBAAC,GAAD;IAAY,SAAQ;cAAmB;IAAiC,CAAA,EACxE,kBAAC,GAAD,EAAM,iBAAiB,KAAmB,IAAM,CAAA,CAC1C;MACR,kBAAC,GAAD;GAAO,IAAI;IAAE,MAAM;IAAG,KAAK;IAAO;aAAlC,CACE,kBAAC,GAAD;IAAyB;IAA6B;IAAiB,CAAA,EACtE,KACC,kBAAC,GAAD;IACE,WAAW;IACX,IAAI;KAAE,UAAU;KAA0B;KAAQ;IAClD,IAAI;KAAE,SAAS;KAAY,UAAU;KAAQ;cAC9C;IAES,CAAA,CAEN;KACJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"GridAgentChat.js","names":[],"sources":["../../../src/components/SynapseChat/GridAgentChat.tsx"],"sourcesContent":["import { useChatState } from '@/components/SynapseChat/useChatState'\nimport { GridAgentSessionContext } from '@sage-bionetworks/synapse-client'\nimport { AgentAccessLevel, AgentSession } from '@sage-bionetworks/synapse-types'\nimport { useState } from 'react'\nimport DraggableDialog from '../DraggableDialog/DraggableDialog'\nimport { SynapseChat } from './index'\n\nexport type GridAgentChatProps = {\n gridSessionId: string\n usersReplicaId: number\n chatbotName?: string\n initialMessage?: string\n open: boolean\n onClose: () => void\n /** Optional ID to use a different agent registered in Synapse */\n agentRegistrationId?: string\n}\n\nexport function GridAgentChat({\n gridSessionId,\n usersReplicaId,\n chatbotName = 'Grid Assistant',\n initialMessage,\n open,\n onClose,\n agentRegistrationId,\n}: GridAgentChatProps) {\n // Storing state for the chat session here preserves chat history while the dialog is opened and closed.\n const [agentSession, setAgentSession] = useState<AgentSession | undefined>()\n const chatState = useChatState(agentSession)\n\n // Create session context for grid sessions\n const sessionContext: GridAgentSessionContext = {\n concreteType:\n 'org.sagebionetworks.repo.model.agent.GridAgentSessionContext',\n gridSessionId,\n usersReplicaId,\n }\n\n return (\n <DraggableDialog open={open} onClose={onClose} title={chatbotName}>\n <SynapseChat\n agentRegistrationId={agentRegistrationId}\n chatbotName={chatbotName}\n initialMessage={initialMessage}\n sessionContext={sessionContext}\n textboxPositionOffset=\"16px\"\n hideTitle={true}\n showAccessLevelMenu={false}\n defaultAgentAccessLevel={AgentAccessLevel.WRITE_YOUR_PRIVATE_DATA}\n // lift state: allow GridAgentChat to control the agent session and interactions\n externalSession={agentSession}\n setExternalSession={setAgentSession}\n externalChatState={chatState}\n />\n </DraggableDialog>\n )\n}\n\nexport default GridAgentChat\n"],"mappings":";;;;;;;;AAkBA,SAAgB,EAAc,EAC5B,kBACA,mBACA,iBAAc,kBACd,mBACA,SACA,YACA,0BACqB;CAErB,IAAM,CAAC,GAAc,KAAmB,GAAoC,EACtE,IAAY,EAAa,EAAa;AAU5C,QACE,kBAAC,GAAD;EAAuB;EAAe;EAAS,OAAO;YACpD,kBAAC,GAAD;GACuB;GACR;GACG;GACA,gBAb0B;IAC9C,cACE;IACF;IACA;IACD;GASK,uBAAsB;GACtB,WAAW;GACX,qBAAqB;GACrB,yBAAyB,EAAiB;GAE1C,iBAAiB;GACjB,oBAAoB;GACpB,mBAAmB;GACnB,CAAA;EACc,CAAA"}
1
+ {"version":3,"file":"GridAgentChat.js","names":[],"sources":["../../../src/components/SynapseChat/GridAgentChat.tsx"],"sourcesContent":["import { useChatState } from '@/components/SynapseChat/useChatState'\nimport { GridAgentSessionContext } from '@sage-bionetworks/synapse-client'\nimport { AgentAccessLevel, AgentSession } from '@sage-bionetworks/synapse-types'\nimport { useState } from 'react'\nimport DraggableDialog from '../DraggableDialog/DraggableDialog'\nimport { SynapseChat } from './index'\n\nexport type GridAgentChatProps = {\n gridSessionId: string\n usersReplicaId: number\n chatbotName?: string\n initialMessage?: string\n open: boolean\n onClose: () => void\n /** Optional ID to use a different agent registered in Synapse */\n agentRegistrationId?: string\n}\n\nexport function GridAgentChat({\n gridSessionId,\n usersReplicaId,\n chatbotName = 'Grid Assistant',\n initialMessage,\n open,\n onClose,\n agentRegistrationId,\n}: GridAgentChatProps) {\n // Storing state for the chat session here preserves chat history while the dialog is opened and closed.\n const [agentSession, setAgentSession] = useState<AgentSession | undefined>()\n const chatState = useChatState(agentSession)\n\n // Create session context for grid sessions\n const sessionContext: GridAgentSessionContext = {\n concreteType:\n 'org.sagebionetworks.repo.model.agent.GridAgentSessionContext',\n gridSessionId,\n usersReplicaId,\n }\n\n return (\n <DraggableDialog open={open} onClose={onClose} title={chatbotName}>\n <SynapseChat\n agentRegistrationId={agentRegistrationId}\n chatbotName={chatbotName}\n initialMessage={initialMessage}\n sessionContext={sessionContext}\n textboxPositionOffset=\"16px\"\n hideTitle={true}\n showAccessLevelMenu={false}\n defaultAgentAccessLevel={AgentAccessLevel.WRITE_YOUR_PRIVATE_DATA}\n // lift state: allow GridAgentChat to control the agent session and interactions\n externalSession={agentSession}\n setExternalSession={setAgentSession}\n externalChatState={chatState}\n />\n </DraggableDialog>\n )\n}\n\nexport default GridAgentChat\n"],"mappings":";;;;;;;;AAkBA,SAAgB,EAAc,EAC5B,kBACA,mBACA,iBAAc,kBACd,mBACA,SACA,YACA,0BACqB;CAErB,IAAM,CAAC,GAAc,KAAmB,GAAoC,EACtE,IAAY,EAAa,EAAa;AAU5C,QACE,kBAAC,GAAD;EAAuB;EAAe;EAAS,OAAO;YACpD,kBAAC,GAAD;GACuB;GACR;GACG;GACA,gBAAA;IAZpB,cACE;IACF;IACA;IASoB;GAChB,uBAAsB;GACtB,WAAW;GACX,qBAAqB;GACrB,yBAAyB,EAAiB;GAE1C,iBAAiB;GACjB,oBAAoB;GACpB,mBAAmB;GACnB,CAAA;EACc,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"SynapseChatInteraction.js","names":[],"sources":["../../../src/components/SynapseChat/SynapseChatInteraction.tsx"],"sourcesContent":["import { SynapseSpinner } from '@/components/LoadingScreen/LoadingScreen'\nimport extractMessageFromTraceEvent, {\n TraceMessage,\n} from '@/components/SynapseChat/extractMessageFromTraceEvent'\nimport {\n KeyboardArrowDown,\n KeyboardArrowRight,\n SmartToyTwoTone,\n} from '@mui/icons-material'\nimport {\n Alert,\n Box,\n Button,\n Chip,\n Collapse,\n ListItem,\n ListItemText,\n Stack,\n Tooltip,\n useTheme,\n} from '@mui/material'\nimport { Color } from '@mui/material/styles'\nimport { TraceEvent } from '@sage-bionetworks/synapse-types'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport MarkdownSynapse from '../Markdown/MarkdownSynapse'\n\nexport type SynapseChatInteractionProps = {\n userMessage: string\n chatResponseText?: string\n chatResponseTrace?: TraceEvent[]\n scrollIntoView?: boolean\n chatErrorReason?: string\n onSendChat?: (message: string) => void\n}\n\n// Show tool calls in the trace. Useful for development. We may want to show them to users in the future.\nconst SHOW_TOOL_USE = false\n\nfunction getMarkdownForTraceMessage(traceMessage: TraceMessage): string {\n if ('reasoningText' in traceMessage) {\n return traceMessage.reasoningText\n }\n if (SHOW_TOOL_USE && 'toolName' in traceMessage) {\n return `**Tool Used:** \\`${\n traceMessage.toolName\n }\\`\\n\\n**Tool Input:**\\n\\`\\`\\`json\\n${JSON.stringify(\n traceMessage.toolInput,\n null,\n 2,\n )}\\n\\`\\`\\`\\n`\n }\n return ''\n}\n\nexport function SynapseChatInteraction({\n userMessage,\n chatResponseText,\n chatErrorReason,\n chatResponseTrace,\n scrollIntoView = false,\n onSendChat,\n}: SynapseChatInteractionProps) {\n const theme = useTheme()\n const ref = useRef<HTMLLIElement | null>(null)\n const [showTrace, setShowTrace] = useState(false)\n\n useEffect(() => {\n // on mount, scroll into view if instructed\n if (scrollIntoView) {\n if (ref.current) {\n ref.current.scrollIntoView({ behavior: 'smooth' })\n }\n }\n }, [ref, scrollIntoView])\n\n const isLoading = !chatResponseText && !chatErrorReason\n\n const traceMessages = useMemo(\n () =>\n (chatResponseTrace ?? [])\n .flatMap(traceEvent => extractMessageFromTraceEvent(traceEvent))\n ?.filter(trace => !!trace),\n [chatResponseTrace],\n )\n\n const hasTraceInfo = traceMessages.length > 0\n\n const lastReasoningMessage = useMemo(\n () => traceMessages.filter(trace => 'reasoningText' in trace).at(-1),\n [traceMessages],\n )\n\n const traceButtonLoadingText =\n lastReasoningMessage == null\n ? 'Thinking...'\n : lastReasoningMessage.reasoningText\n\n const traceButtonText = isLoading\n ? traceButtonLoadingText\n : `${showTrace ? 'Hide' : 'Show'} Trace`\n\n const { textContent, guidePrompts } = useMemo(() => {\n try {\n const parser = new DOMParser()\n const doc = parser.parseFromString(chatResponseText ?? '', 'text/html')\n\n // Remove tool_name and actions elements (AI XML tags not for display)\n doc\n .querySelectorAll('tool_name, actions')\n .forEach(element => element.remove())\n\n // Extract guideprompts before removing them\n const extractedGuidePrompts = Array.from(\n doc.querySelectorAll('guideprompt'),\n )\n .map(el => el.textContent?.trim())\n .filter((t): t is string => !!t)\n\n // Remove guideprompt elements\n doc.querySelectorAll('guideprompt').forEach(element => element.remove())\n\n // Extract text from <chat> element if present, otherwise use full body text\n const chatElement = doc.querySelector('chat')\n return {\n textContent: chatElement\n ? chatElement.textContent ?? ''\n : doc.body.textContent ?? '',\n guidePrompts: extractedGuidePrompts,\n }\n } catch (e) {\n console.error(e)\n return { textContent: chatResponseText ?? '', guidePrompts: [] }\n }\n }, [chatResponseText])\n\n return (\n <>\n <ListItem\n ref={ref}\n sx={{\n alignSelf: 'flex-end',\n backgroundColor: (theme.palette.secondary as unknown as Color)[100],\n borderRadius: '24px',\n maxWidth: '70%',\n display: 'block',\n mb: '5px',\n p: '8px 12px',\n wordWrap: 'break-word',\n width: 'auto',\n }}\n >\n <ListItemText primary={userMessage} />\n </ListItem>\n <ListItem\n sx={{\n display: 'grid',\n gridTemplateColumns: '50px auto',\n columnGap: '0px',\n justifyItems: 'center',\n alignItems: 'start',\n p: '0px',\n }}\n >\n <Box\n sx={{\n p: '3px',\n mt: '10px',\n height: '31px',\n borderRadius: '50%',\n borderStyle: 'solid',\n borderWidth: '1px',\n borderColor: 'grey.300',\n }}\n >\n <SmartToyTwoTone sx={{ color: 'secondary.main' }} />\n </Box>\n <Box\n sx={{\n borderRadius: '10px',\n padding: '10px',\n maxWidth: '100%',\n overflow: 'auto',\n }}\n >\n <Box\n component={'aside'}\n sx={{\n '.markdown': {\n fontStyle: 'italic',\n borderLeft: `4px solid ${theme.palette.grey[300]}`,\n marginLeft: '4px',\n paddingLeft: '8px',\n mt: 1,\n mb: 2,\n },\n }}\n >\n <Button\n variant={'outlined'}\n size={'small'}\n startIcon={\n isLoading ? (\n <SynapseSpinner size={14} />\n ) : showTrace ? (\n <KeyboardArrowDown sx={{ width: '14px' }} />\n ) : (\n <KeyboardArrowRight sx={{ width: '14px' }} />\n )\n }\n disabled={!hasTraceInfo}\n onClick={() => {\n setShowTrace(v => !v)\n }}\n sx={{\n height: '20px',\n fontSize: '12px',\n fontWeight: 600,\n mb: 1,\n border: 'none !important',\n color: 'grey.700',\n justifyContent: 'flex-start',\n whiteSpace: 'nowrap',\n maxWidth: '325px',\n textTransform: 'none',\n pl: 0,\n '.MuiButton-startIcon': { mr: 0.5 },\n }}\n >\n <Box sx={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>\n {traceButtonText}\n </Box>\n </Button>\n {chatResponseTrace && (\n <Collapse in={showTrace}>\n <MarkdownSynapse\n markdown={traceMessages\n .map(getMarkdownForTraceMessage)\n .filter(md => md.trim().length > 0)\n .join('<br/><br/>')}\n />\n </Collapse>\n )}\n </Box>\n {textContent && <MarkdownSynapse markdown={textContent} />}\n {onSendChat && guidePrompts.length > 0 && (\n <Stack direction=\"row\" flexWrap=\"wrap\" gap={1} mt={1}>\n {guidePrompts.map(prompt => (\n <Tooltip key={prompt} title={prompt}>\n <Chip\n label={prompt}\n variant=\"outlined\"\n color=\"primary\"\n clickable\n onClick={() => onSendChat(prompt)}\n sx={{ maxWidth: 200 }}\n />\n </Tooltip>\n ))}\n </Stack>\n )}\n </Box>\n </ListItem>\n {chatErrorReason && (\n <Alert severity={'error'} sx={{ my: 2 }}>\n {chatErrorReason}\n </Alert>\n )}\n </>\n )\n}\n\nexport default SynapseChatInteraction\n"],"mappings":";;;;;;;;AAsCA,SAAS,EAA2B,GAAoC;AAatE,QAZI,mBAAmB,IACd,EAAa,gBAWf;;AAGT,SAAgB,EAAuB,EACrC,gBACA,qBACA,oBACA,sBACA,oBAAiB,IACjB,iBAC8B;CAC9B,IAAM,IAAQ,GAAU,EAClB,IAAM,EAA6B,KAAK,EACxC,CAAC,GAAW,KAAgB,EAAS,GAAM;AAEjD,SAAgB;AAEd,EAAI,KACE,EAAI,WACN,EAAI,QAAQ,eAAe,EAAE,UAAU,UAAU,CAAC;IAGrD,CAAC,GAAK,EAAe,CAAC;CAEzB,IAAM,IAAY,CAAC,KAAoB,CAAC,GAElC,IAAgB,SAEjB,KAAqB,EAAE,EACrB,SAAQ,MAAc,EAA6B,EAAW,CAAC,EAC9D,QAAO,MAAS,CAAC,CAAC,EAAM,EAC9B,CAAC,EAAkB,CACpB,EAEK,IAAe,EAAc,SAAS,GAEtC,IAAuB,QACrB,EAAc,QAAO,MAAS,mBAAmB,EAAM,CAAC,GAAG,GAAG,EACpE,CAAC,EAAc,CAChB,EAEK,IACJ,KAAwB,OACpB,gBACA,EAAqB,eAErB,IAAkB,IACpB,IACA,GAAG,IAAY,SAAS,OAAO,SAE7B,EAAE,gBAAa,oBAAiB,QAAc;AAClD,MAAI;GAEF,IAAM,IADS,IAAI,WAAW,CACX,gBAAgB,KAAoB,IAAI,YAAY;AAGvE,KACG,iBAAiB,qBAAqB,CACtC,SAAQ,MAAW,EAAQ,QAAQ,CAAC;GAGvC,IAAM,IAAwB,MAAM,KAClC,EAAI,iBAAiB,cAAc,CACpC,CACE,KAAI,MAAM,EAAG,aAAa,MAAM,CAAC,CACjC,QAAQ,MAAmB,CAAC,CAAC,EAAE;AAGlC,KAAI,iBAAiB,cAAc,CAAC,SAAQ,MAAW,EAAQ,QAAQ,CAAC;GAGxE,IAAM,IAAc,EAAI,cAAc,OAAO;AAC7C,UAAO;IACL,aAAa,IACT,EAAY,eAAe,KAC3B,EAAI,KAAK,eAAe;IAC5B,cAAc;IACf;WACM,GAAG;AAEV,UADA,QAAQ,MAAM,EAAE,EACT;IAAE,aAAa,KAAoB;IAAI,cAAc,EAAE;IAAE;;IAEjE,CAAC,EAAiB,CAAC;AAEtB,QACE,kBAAA,GAAA,EAAA,UAAA;EACE,kBAAC,GAAD;GACO;GACL,IAAI;IACF,WAAW;IACX,iBAAkB,EAAM,QAAQ,UAA+B;IAC/D,cAAc;IACd,UAAU;IACV,SAAS;IACT,IAAI;IACJ,GAAG;IACH,UAAU;IACV,OAAO;IACR;aAED,kBAAC,GAAD,EAAc,SAAS,GAAe,CAAA;GAC7B,CAAA;EACX,kBAAC,GAAD;GACE,IAAI;IACF,SAAS;IACT,qBAAqB;IACrB,WAAW;IACX,cAAc;IACd,YAAY;IACZ,GAAG;IACJ;aARH,CAUE,kBAAC,GAAD;IACE,IAAI;KACF,GAAG;KACH,IAAI;KACJ,QAAQ;KACR,cAAc;KACd,aAAa;KACb,aAAa;KACb,aAAa;KACd;cAED,kBAAC,GAAD,EAAiB,IAAI,EAAE,OAAO,kBAAkB,EAAI,CAAA;IAChD,CAAA,EACN,kBAAC,GAAD;IACE,IAAI;KACF,cAAc;KACd,SAAS;KACT,UAAU;KACV,UAAU;KACX;cANH;KAQE,kBAAC,GAAD;MACE,WAAW;MACX,IAAI,EACF,aAAa;OACX,WAAW;OACX,YAAY,aAAa,EAAM,QAAQ,KAAK;OAC5C,YAAY;OACZ,aAAa;OACb,IAAI;OACJ,IAAI;OACL,EACF;gBAXH,CAaE,kBAAC,GAAD;OACE,SAAS;OACT,MAAM;OACN,WACE,IACE,kBAAC,GAAD,EAAgB,MAAM,IAAM,CAAA,GAE5B,EADE,IACD,IAEA,GAFD,EAAmB,IAAI,EAAE,OAAO,QAAQ,EAAI,CAEC;OAGjD,UAAU,CAAC;OACX,eAAe;AACb,WAAa,MAAK,CAAC,EAAE;;OAEvB,IAAI;QACF,QAAQ;QACR,UAAU;QACV,YAAY;QACZ,IAAI;QACJ,QAAQ;QACR,OAAO;QACP,gBAAgB;QAChB,YAAY;QACZ,UAAU;QACV,eAAe;QACf,IAAI;QACJ,wBAAwB,EAAE,IAAI,IAAK;QACpC;iBAED,kBAAC,GAAD;QAAK,IAAI;SAAE,UAAU;SAAU,cAAc;SAAY;kBACtD;QACG,CAAA;OACC,CAAA,EACR,KACC,kBAAC,GAAD;OAAU,IAAI;iBACZ,kBAAC,GAAD,EACE,UAAU,EACP,IAAI,EAA2B,CAC/B,QAAO,MAAM,EAAG,MAAM,CAAC,SAAS,EAAE,CAClC,KAAK,aAAa,EACrB,CAAA;OACO,CAAA,CAET;;KACL,KAAe,kBAAC,GAAD,EAAiB,UAAU,GAAe,CAAA;KACzD,KAAc,EAAa,SAAS,KACnC,kBAAC,GAAD;MAAO,WAAU;MAAM,UAAS;MAAO,KAAK;MAAG,IAAI;gBAChD,EAAa,KAAI,MAChB,kBAAC,GAAD;OAAsB,OAAO;iBAC3B,kBAAC,GAAD;QACE,OAAO;QACP,SAAQ;QACR,OAAM;QACN,WAAA;QACA,eAAe,EAAW,EAAO;QACjC,IAAI,EAAE,UAAU,KAAK;QACrB,CAAA;OACM,EATI,EASJ,CACV;MACI,CAAA;KAEN;MACG;;EACV,KACC,kBAAC,GAAD;GAAO,UAAU;GAAS,IAAI,EAAE,IAAI,GAAG;aACpC;GACK,CAAA;EAET,EAAA,CAAA"}
1
+ {"version":3,"file":"SynapseChatInteraction.js","names":[],"sources":["../../../src/components/SynapseChat/SynapseChatInteraction.tsx"],"sourcesContent":["import { SynapseSpinner } from '@/components/LoadingScreen/LoadingScreen'\nimport extractMessageFromTraceEvent, {\n TraceMessage,\n} from '@/components/SynapseChat/extractMessageFromTraceEvent'\nimport {\n KeyboardArrowDown,\n KeyboardArrowRight,\n SmartToyTwoTone,\n} from '@mui/icons-material'\nimport {\n Alert,\n Box,\n Button,\n Chip,\n Collapse,\n ListItem,\n ListItemText,\n Stack,\n Tooltip,\n useTheme,\n} from '@mui/material'\nimport { Color } from '@mui/material/styles'\nimport { TraceEvent } from '@sage-bionetworks/synapse-types'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport MarkdownSynapse from '../Markdown/MarkdownSynapse'\n\nexport type SynapseChatInteractionProps = {\n userMessage: string\n chatResponseText?: string\n chatResponseTrace?: TraceEvent[]\n scrollIntoView?: boolean\n chatErrorReason?: string\n onSendChat?: (message: string) => void\n}\n\n// Show tool calls in the trace. Useful for development. We may want to show them to users in the future.\nconst SHOW_TOOL_USE = false\n\nfunction getMarkdownForTraceMessage(traceMessage: TraceMessage): string {\n if ('reasoningText' in traceMessage) {\n return traceMessage.reasoningText\n }\n if (SHOW_TOOL_USE && 'toolName' in traceMessage) {\n return `**Tool Used:** \\`${\n traceMessage.toolName\n }\\`\\n\\n**Tool Input:**\\n\\`\\`\\`json\\n${JSON.stringify(\n traceMessage.toolInput,\n null,\n 2,\n )}\\n\\`\\`\\`\\n`\n }\n return ''\n}\n\nexport function SynapseChatInteraction({\n userMessage,\n chatResponseText,\n chatErrorReason,\n chatResponseTrace,\n scrollIntoView = false,\n onSendChat,\n}: SynapseChatInteractionProps) {\n const theme = useTheme()\n const ref = useRef<HTMLLIElement | null>(null)\n const [showTrace, setShowTrace] = useState(false)\n\n useEffect(() => {\n // on mount, scroll into view if instructed\n if (scrollIntoView) {\n if (ref.current) {\n ref.current.scrollIntoView({ behavior: 'smooth' })\n }\n }\n }, [ref, scrollIntoView])\n\n const isLoading = !chatResponseText && !chatErrorReason\n\n const traceMessages = useMemo(\n () =>\n (chatResponseTrace ?? [])\n .flatMap(traceEvent => extractMessageFromTraceEvent(traceEvent))\n ?.filter(trace => !!trace),\n [chatResponseTrace],\n )\n\n const hasTraceInfo = traceMessages.length > 0\n\n const lastReasoningMessage = useMemo(\n () => traceMessages.filter(trace => 'reasoningText' in trace).at(-1),\n [traceMessages],\n )\n\n const traceButtonLoadingText =\n lastReasoningMessage == null\n ? 'Thinking...'\n : lastReasoningMessage.reasoningText\n\n const traceButtonText = isLoading\n ? traceButtonLoadingText\n : `${showTrace ? 'Hide' : 'Show'} Trace`\n\n const { textContent, guidePrompts } = useMemo(() => {\n try {\n const parser = new DOMParser()\n const doc = parser.parseFromString(chatResponseText ?? '', 'text/html')\n\n // Remove tool_name and actions elements (AI XML tags not for display)\n doc\n .querySelectorAll('tool_name, actions')\n .forEach(element => element.remove())\n\n // Extract guideprompts before removing them\n const extractedGuidePrompts = Array.from(\n doc.querySelectorAll('guideprompt'),\n )\n .map(el => el.textContent?.trim())\n .filter((t): t is string => !!t)\n\n // Remove guideprompt elements\n doc.querySelectorAll('guideprompt').forEach(element => element.remove())\n\n // Extract text from <chat> element if present, otherwise use full body text\n const chatElement = doc.querySelector('chat')\n return {\n textContent: chatElement\n ? chatElement.textContent ?? ''\n : doc.body.textContent ?? '',\n guidePrompts: extractedGuidePrompts,\n }\n } catch (e) {\n console.error(e)\n return { textContent: chatResponseText ?? '', guidePrompts: [] }\n }\n }, [chatResponseText])\n\n return (\n <>\n <ListItem\n ref={ref}\n sx={{\n alignSelf: 'flex-end',\n backgroundColor: (theme.palette.secondary as unknown as Color)[100],\n borderRadius: '24px',\n maxWidth: '70%',\n display: 'block',\n mb: '5px',\n p: '8px 12px',\n wordWrap: 'break-word',\n width: 'auto',\n }}\n >\n <ListItemText primary={userMessage} />\n </ListItem>\n <ListItem\n sx={{\n display: 'grid',\n gridTemplateColumns: '50px auto',\n columnGap: '0px',\n justifyItems: 'center',\n alignItems: 'start',\n p: '0px',\n }}\n >\n <Box\n sx={{\n p: '3px',\n mt: '10px',\n height: '31px',\n borderRadius: '50%',\n borderStyle: 'solid',\n borderWidth: '1px',\n borderColor: 'grey.300',\n }}\n >\n <SmartToyTwoTone sx={{ color: 'secondary.main' }} />\n </Box>\n <Box\n sx={{\n borderRadius: '10px',\n padding: '10px',\n maxWidth: '100%',\n overflow: 'auto',\n }}\n >\n <Box\n component={'aside'}\n sx={{\n '.markdown': {\n fontStyle: 'italic',\n borderLeft: `4px solid ${theme.palette.grey[300]}`,\n marginLeft: '4px',\n paddingLeft: '8px',\n mt: 1,\n mb: 2,\n },\n }}\n >\n <Button\n variant={'outlined'}\n size={'small'}\n startIcon={\n isLoading ? (\n <SynapseSpinner size={14} />\n ) : showTrace ? (\n <KeyboardArrowDown sx={{ width: '14px' }} />\n ) : (\n <KeyboardArrowRight sx={{ width: '14px' }} />\n )\n }\n disabled={!hasTraceInfo}\n onClick={() => {\n setShowTrace(v => !v)\n }}\n sx={{\n height: '20px',\n fontSize: '12px',\n fontWeight: 600,\n mb: 1,\n border: 'none !important',\n color: 'grey.700',\n justifyContent: 'flex-start',\n whiteSpace: 'nowrap',\n maxWidth: '325px',\n textTransform: 'none',\n pl: 0,\n '.MuiButton-startIcon': { mr: 0.5 },\n }}\n >\n <Box sx={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>\n {traceButtonText}\n </Box>\n </Button>\n {chatResponseTrace && (\n <Collapse in={showTrace}>\n <MarkdownSynapse\n markdown={traceMessages\n .map(getMarkdownForTraceMessage)\n .filter(md => md.trim().length > 0)\n .join('<br/><br/>')}\n />\n </Collapse>\n )}\n </Box>\n {textContent && <MarkdownSynapse markdown={textContent} />}\n {onSendChat && guidePrompts.length > 0 && (\n <Stack direction=\"row\" flexWrap=\"wrap\" gap={1} mt={1}>\n {guidePrompts.map(prompt => (\n <Tooltip key={prompt} title={prompt}>\n <Chip\n label={prompt}\n variant=\"outlined\"\n color=\"primary\"\n clickable\n onClick={() => onSendChat(prompt)}\n sx={{ maxWidth: 200 }}\n />\n </Tooltip>\n ))}\n </Stack>\n )}\n </Box>\n </ListItem>\n {chatErrorReason && (\n <Alert severity={'error'} sx={{ my: 2 }}>\n {chatErrorReason}\n </Alert>\n )}\n </>\n )\n}\n\nexport default SynapseChatInteraction\n"],"mappings":"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"}