synapse-react-client 4.0.16 → 4.0.18

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 (229) hide show
  1. package/README.md +5 -3
  2. package/dist/SWC.index.d.ts +1 -0
  3. package/dist/SWC.index.d.ts.map +1 -1
  4. package/dist/SWC.index.js +2 -1
  5. package/dist/SWC.index.js.map +1 -1
  6. package/dist/assets/homepage/BlinkingLiveIcon.d.ts +1 -1
  7. package/dist/components/AccessRequirementAclEditor/AccessRequirementAclEditor.d.ts.map +1 -1
  8. package/dist/components/AccessRequirementAclEditor/AccessRequirementAclEditor.js.map +1 -1
  9. package/dist/components/AccessRequirementList/AccessRequirementList.js.map +1 -1
  10. package/dist/components/AccessRequirementList/RequirementItem/CertificationRequirement.js.map +1 -1
  11. package/dist/components/AccessRequirementList/RequirementItem/SelfSignAccessRequirementItem.js.map +1 -1
  12. package/dist/components/AccessRequirementList/RequirementItem/UnmanagedACTAccessRequirementItem.js.map +1 -1
  13. package/dist/components/AccessRequirementList/RequirementItem/ValidationRequirement.js.map +1 -1
  14. package/dist/components/AccessTokenPage/CreateAccessTokenModal.d.ts.map +1 -1
  15. package/dist/components/AccessTokenPage/CreateAccessTokenModal.js +56 -54
  16. package/dist/components/AccessTokenPage/CreateAccessTokenModal.js.map +1 -1
  17. package/dist/components/Authentication/PasswordField.d.ts +1 -1
  18. package/dist/components/Authentication/PasswordField.d.ts.map +1 -1
  19. package/dist/components/Authentication/PasswordField.js.map +1 -1
  20. package/dist/components/Authentication/TwoFactorEnrollmentForm.d.ts.map +1 -1
  21. package/dist/components/Authentication/TwoFactorEnrollmentForm.js +1 -2
  22. package/dist/components/Authentication/TwoFactorEnrollmentForm.js.map +1 -1
  23. package/dist/components/Authentication/UsernamePasswordForm.d.ts.map +1 -1
  24. package/dist/components/Authentication/UsernamePasswordForm.js +32 -29
  25. package/dist/components/Authentication/UsernamePasswordForm.js.map +1 -1
  26. package/dist/components/CardContainer/CardLink.d.ts +2 -2
  27. package/dist/components/CardContainer/CardLink.d.ts.map +1 -1
  28. package/dist/components/CardDeck/CardDeckCardProps.d.ts.map +1 -1
  29. package/dist/components/ChallengeSubmission/SubmissionDirectoryList.js.map +1 -1
  30. package/dist/components/ChallengeTeamWizard/CreateChallengeTeam.d.ts.map +1 -1
  31. package/dist/components/ChallengeTeamWizard/CreateChallengeTeam.js +106 -103
  32. package/dist/components/ChallengeTeamWizard/CreateChallengeTeam.js.map +1 -1
  33. package/dist/components/ChallengeTeamWizard/MembershipRequestForm.d.ts.map +1 -1
  34. package/dist/components/ChallengeTeamWizard/MembershipRequestForm.js.map +1 -1
  35. package/dist/components/ChallengeTeamWizard/useCreateAndRegisterChallengeTeam.d.ts.map +1 -1
  36. package/dist/components/ChallengeTeamWizard/useCreateAndRegisterChallengeTeam.js.map +1 -1
  37. package/dist/components/CreateProjectModal/CreateProjectModal.d.ts.map +1 -1
  38. package/dist/components/CreateProjectModal/CreateProjectModal.js +4 -4
  39. package/dist/components/CreateProjectModal/CreateProjectModal.js.map +1 -1
  40. package/dist/components/CreateTableViewWizard/TableNameForm.js +6 -6
  41. package/dist/components/CreateTableViewWizard/TableNameForm.js.map +1 -1
  42. package/dist/components/CrispChat/CrispChat.js +4 -4
  43. package/dist/components/CrispChat/CrispChat.js.map +1 -1
  44. package/dist/components/DataGrid/utils/json-rx/JsonRxResponseComplete.js.map +1 -1
  45. package/dist/components/DownloadCart/RequestDownloadCard.js +14 -14
  46. package/dist/components/DownloadCart/RequestDownloadCard.js.map +1 -1
  47. package/dist/components/EntityAclEditor/EntityAclEditor.d.ts.map +1 -1
  48. package/dist/components/EntityAclEditor/EntityAclEditor.js.map +1 -1
  49. package/dist/components/EntityBadgeIcons/EntityBadgeIcons.d.ts.map +1 -1
  50. package/dist/components/EntityBadgeIcons/EntityBadgeIcons.js.map +1 -1
  51. package/dist/components/EntityCitation/EntityCitationUtils.js.map +1 -1
  52. package/dist/components/EntityDownloadConfirmation/EntityDownloadConfirmation.js.map +1 -1
  53. package/dist/components/EntityFinder/EntityFinder.js.map +1 -1
  54. package/dist/components/EntityFinder/EntityIdTextField.d.ts +17 -0
  55. package/dist/components/EntityFinder/EntityIdTextField.d.ts.map +1 -0
  56. package/dist/components/EntityFinder/EntityIdTextField.js +35 -0
  57. package/dist/components/EntityFinder/EntityIdTextField.js.map +1 -0
  58. package/dist/components/EntityIcon.d.ts.map +1 -1
  59. package/dist/components/EntityIcon.js +2 -1
  60. package/dist/components/EntityIcon.js.map +1 -1
  61. package/dist/components/Evaluation/round_limits/EvaluationRoundLimitOptions.d.ts.map +1 -1
  62. package/dist/components/Evaluation/round_limits/EvaluationRoundLimitOptions.js +22 -16
  63. package/dist/components/Evaluation/round_limits/EvaluationRoundLimitOptions.js.map +1 -1
  64. package/dist/components/FeaturedDataTabs/FacetPlotsCardGrid.js.map +1 -1
  65. package/dist/components/Forum/ForumThreadEditor.js.map +1 -1
  66. package/dist/components/FullWidthAlert/FullWidthAlert.d.ts.map +1 -1
  67. package/dist/components/FullWidthAlert/FullWidthAlert.js.map +1 -1
  68. package/dist/components/GenericCard/PortalDOI/PortalDOIUtils.d.ts.map +1 -1
  69. package/dist/components/GenericCard/PortalDOI/PortalDOIUtils.js.map +1 -1
  70. package/dist/components/Markdown/widget/MarkdownSynapsePlot.js.map +1 -1
  71. package/dist/components/OAuthClientAclEditor/OAuthClientAclEditor.d.ts.map +1 -1
  72. package/dist/components/OAuthClientAclEditor/OAuthClientAclEditor.js.map +1 -1
  73. package/dist/components/PortalAclEditor/PortalAclEditor.d.ts.map +1 -1
  74. package/dist/components/PortalAclEditor/PortalAclEditor.js.map +1 -1
  75. package/dist/components/PortalHomePageHeader/PortalHomePageHeader.d.ts +1 -1
  76. package/dist/components/PortalHomePageHeader/PortalHomePageHeader.d.ts.map +1 -1
  77. package/dist/components/PortalHomePageHeader/PortalHomePageHeader.js +1 -1
  78. package/dist/components/PortalHomePageHeader/PortalHomePageHeader.js.map +1 -1
  79. package/dist/components/PortalList/CreatePortalModal.d.ts.map +1 -1
  80. package/dist/components/PortalList/CreatePortalModal.js +34 -33
  81. package/dist/components/PortalList/CreatePortalModal.js.map +1 -1
  82. package/dist/components/QueryVisualizationWrapper/QueryVisualizationWrapper.d.ts.map +1 -1
  83. package/dist/components/QueryVisualizationWrapper/QueryVisualizationWrapper.js.map +1 -1
  84. package/dist/components/QueryWrapperPlotNav/RowSetView.d.ts.map +1 -1
  85. package/dist/components/QueryWrapperPlotNav/RowSetView.js.map +1 -1
  86. package/dist/components/Resources/Resources.Desktop.js.map +1 -1
  87. package/dist/components/SearchQueryWrapper/SearchQueryUseQueryOptions.js.map +1 -1
  88. package/dist/components/SetAccessRequirementCommonFields/SetAccessRequirementCommonFields.d.ts.map +1 -1
  89. package/dist/components/SetAccessRequirementCommonFields/SetAccessRequirementCommonFields.js.map +1 -1
  90. package/dist/components/SetBasicAccessRequirementFields/SetBasicAccessRequirementFields.d.ts.map +1 -1
  91. package/dist/components/SetBasicAccessRequirementFields/SetBasicAccessRequirementFields.js.map +1 -1
  92. package/dist/components/SetManagedAccessRequirementFields/SetManagedAccessRequirementFields.d.ts.map +1 -1
  93. package/dist/components/SetManagedAccessRequirementFields/SetManagedAccessRequirementFields.js.map +1 -1
  94. package/dist/components/SynapseChat/SynapseChatInteraction.js.map +1 -1
  95. package/dist/components/SynapsePortalBanners/SynapsePortalBanners.d.ts.map +1 -1
  96. package/dist/components/SynapsePortalBanners/SynapsePortalBanners.js +1 -1
  97. package/dist/components/SynapsePortalBanners/SynapsePortalBanners.js.map +1 -1
  98. package/dist/components/SynapseTable/SearchV2.js.map +1 -1
  99. package/dist/components/SynapseTable/SynapseTable.js.map +1 -1
  100. package/dist/components/SynapseTable/SynapseTableUtils.d.ts.map +1 -1
  101. package/dist/components/SynapseTable/SynapseTableUtils.js.map +1 -1
  102. package/dist/components/SynapseTable/datasets/DatasetItemsEditor.js.map +1 -1
  103. package/dist/components/TableColumnSchemaEditor/ColumnModelForm.js.map +1 -1
  104. package/dist/components/TableColumnSchemaEditor/TableColumnSchemaForm.d.ts.map +1 -1
  105. package/dist/components/TableColumnSchemaEditor/TableColumnSchemaForm.js.map +1 -1
  106. package/dist/components/TanStackTable/TanStackTableUtils.js.map +1 -1
  107. package/dist/components/TextField/TextField.css +1 -1
  108. package/dist/components/TextField/TextField.d.ts +14 -3
  109. package/dist/components/TextField/TextField.d.ts.map +1 -1
  110. package/dist/components/TextField/TextField.js +41 -43
  111. package/dist/components/TextField/TextField.js.map +1 -1
  112. package/dist/components/TextField/TextField.module.js +3 -4
  113. package/dist/components/TextField/TextField.module.js.map +1 -1
  114. package/dist/components/TextField/TextField.module.scss +18 -10
  115. package/dist/components/TimelinePlot/TimelinePlotSpeciesSelector.d.ts.map +1 -1
  116. package/dist/components/TimelinePlot/TimelinePlotSpeciesSelector.js +20 -16
  117. package/dist/components/TimelinePlot/TimelinePlotSpeciesSelector.js.map +1 -1
  118. package/dist/components/UserCardList/UserCardList.d.ts.map +1 -1
  119. package/dist/components/UserCardList/UserCardList.js.map +1 -1
  120. package/dist/components/UserCardList/UserCardListGroups/UserCardListGroups.Desktop.js.map +1 -1
  121. package/dist/components/UserOrTeamBadge/useUserOrTeam.js.map +1 -1
  122. package/dist/components/UserSearchBox/UserSearchBox.d.ts.map +1 -1
  123. package/dist/components/UserSearchBox/UserSearchBox.js.map +1 -1
  124. package/dist/components/WikiMarkdownEditorButton/WikiMarkdownEditorButton.js.map +1 -1
  125. package/dist/components/dataaccess/SubmissionPage/SubmissionPage.js.map +1 -1
  126. package/dist/components/doi/CreateOrUpdateDoiModal.js +13 -13
  127. package/dist/components/doi/CreateOrUpdateDoiModal.js.map +1 -1
  128. package/dist/components/entity/page/title_bar/TitleBarProperties.js +23 -23
  129. package/dist/components/entity/page/title_bar/TitleBarProperties.js.map +1 -1
  130. package/dist/components/entity/page/title_bar/useGetMentions.js.map +1 -1
  131. package/dist/components/index.js +17 -17
  132. package/dist/components/styled/StyledFormControl.d.ts +15 -0
  133. package/dist/components/styled/StyledFormControl.d.ts.map +1 -1
  134. package/dist/components/styled/StyledFormControl.js +1 -0
  135. package/dist/components/styled/StyledFormControl.js.map +1 -1
  136. package/dist/components/styled/index.js +3 -3
  137. package/dist/components/utils/ConditionalWrapper.d.ts.map +1 -1
  138. package/dist/components/utils/ConditionalWrapper.js.map +1 -1
  139. package/dist/components/widgets/ElementWithTooltip.js.map +1 -1
  140. package/dist/components/widgets/facet-nav/FacetNavPanel.d.ts.map +1 -1
  141. package/dist/components/widgets/facet-nav/FacetNavPanel.js +69 -62
  142. package/dist/components/widgets/facet-nav/FacetNavPanel.js.map +1 -1
  143. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilter.d.ts +1 -0
  144. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilter.d.ts.map +1 -1
  145. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilter.js +27 -26
  146. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilter.js.map +1 -1
  147. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterDropdown.d.ts +1 -0
  148. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterDropdown.d.ts.map +1 -1
  149. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterDropdown.js +2 -1
  150. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterDropdown.js.map +1 -1
  151. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterUI.d.ts +1 -0
  152. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterUI.d.ts.map +1 -1
  153. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterUI.js +44 -43
  154. package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterUI.js.map +1 -1
  155. package/dist/features/entity/metadata-task/components/CreateOrUpdateCurationTaskDialog.d.ts +13 -0
  156. package/dist/features/entity/metadata-task/components/CreateOrUpdateCurationTaskDialog.d.ts.map +1 -0
  157. package/dist/features/entity/metadata-task/components/CreateOrUpdateCurationTaskDialog.js +398 -0
  158. package/dist/features/entity/metadata-task/components/CreateOrUpdateCurationTaskDialog.js.map +1 -0
  159. package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.d.ts.map +1 -1
  160. package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.js +49 -19
  161. package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.js.map +1 -1
  162. package/dist/features/entity/metadata-task/components/MetadataTasksPage.d.ts.map +1 -1
  163. package/dist/features/entity/metadata-task/components/MetadataTasksPage.js +46 -25
  164. package/dist/features/entity/metadata-task/components/MetadataTasksPage.js.map +1 -1
  165. package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask.d.ts +0 -1
  166. package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask.d.ts.map +1 -1
  167. package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask.js +20 -22
  168. package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask.js.map +1 -1
  169. package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.d.ts.map +1 -1
  170. package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.js +25 -27
  171. package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.js.map +1 -1
  172. package/dist/features/entity/metadata-task/utils/constants.d.ts +26 -0
  173. package/dist/features/entity/metadata-task/utils/constants.d.ts.map +1 -1
  174. package/dist/features/entity/metadata-task/utils/constants.js +2 -2
  175. package/dist/features/entity/metadata-task/utils/constants.js.map +1 -1
  176. package/dist/index.js +17 -17
  177. package/dist/mockServiceWorker.js +6 -8
  178. package/dist/mocks/curation/mockCurationTask.d.ts +2 -2
  179. package/dist/mocks/curation/mockCurationTask.d.ts.map +1 -1
  180. package/dist/mocks/curation/mockCurationTask.js +9 -5
  181. package/dist/mocks/curation/mockCurationTask.js.map +1 -1
  182. package/dist/mocks/msw/handlers/featureFlagHandlers.d.ts +1 -1
  183. package/dist/mocks/msw/handlers/featureFlagHandlers.d.ts.map +1 -1
  184. package/dist/mocks/msw/handlers/featureFlagHandlers.js +1 -1
  185. package/dist/mocks/msw/handlers/featureFlagHandlers.js.map +1 -1
  186. package/dist/style/components/_cards.scss +0 -3
  187. package/dist/style/components/_data-grid-extra.scss +2 -2
  188. package/dist/style/components/_login.scss +6 -2
  189. package/dist/style/main.css +1 -1
  190. package/dist/synapse-client/SynapseClient.d.ts +2 -1
  191. package/dist/synapse-client/SynapseClient.d.ts.map +1 -1
  192. package/dist/synapse-client/SynapseClient.js.map +1 -1
  193. package/dist/synapse-queries/QueryFilterUtils.js.map +1 -1
  194. package/dist/synapse-queries/curation/task/useCurationTask.d.ts +1 -0
  195. package/dist/synapse-queries/curation/task/useCurationTask.d.ts.map +1 -1
  196. package/dist/synapse-queries/curation/task/useCurationTask.js +16 -6
  197. package/dist/synapse-queries/curation/task/useCurationTask.js.map +1 -1
  198. package/dist/synapse-queries/dataaccess/useAccessRequirements.d.ts.map +1 -1
  199. package/dist/synapse-queries/dataaccess/useAccessRequirements.js.map +1 -1
  200. package/dist/synapse-queries/entity/useGetQueryResultBundle.js.map +1 -1
  201. package/dist/synapse-queries/featureflags/useGetFeatureFlag.d.ts +1 -1
  202. package/dist/synapse-queries/featureflags/useGetFeatureFlag.d.ts.map +1 -1
  203. package/dist/synapse-queries/featureflags/useGetFeatureFlag.js.map +1 -1
  204. package/dist/synapse-queries/file/useFiles.d.ts.map +1 -1
  205. package/dist/synapse-queries/file/useFiles.js.map +1 -1
  206. package/dist/synapse-queries/termsOfService/useTermsOfService.d.ts.map +1 -1
  207. package/dist/synapse-queries/termsOfService/useTermsOfService.js.map +1 -1
  208. package/dist/synapse-queries/user/useGetUserChallenges.d.ts.map +1 -1
  209. package/dist/synapse-queries/user/useGetUserChallenges.js.map +1 -1
  210. package/dist/testutils/ReactQueryMockUtils.js.map +1 -1
  211. package/dist/theme/palette/Palettes.d.ts +2 -2
  212. package/dist/theme/palette/Palettes.d.ts.map +1 -1
  213. package/dist/theme/palette/Palettes.js +2 -2
  214. package/dist/theme/palette/Palettes.js.map +1 -1
  215. package/dist/tsconfig.build.tsbuildinfo +1 -1
  216. package/dist/types/ThemeTypes.d.ts +5 -6
  217. package/dist/utils/AppUtils/session/SynapseSessionManager.d.ts.map +1 -1
  218. package/dist/utils/AppUtils/session/SynapseSessionManager.js.map +1 -1
  219. package/dist/utils/featureflag/FeatureFlags.d.ts +12 -0
  220. package/dist/utils/featureflag/FeatureFlags.d.ts.map +1 -0
  221. package/dist/utils/featureflag/FeatureFlags.js +8 -0
  222. package/dist/utils/featureflag/FeatureFlags.js.map +1 -0
  223. package/dist/utils/functions/SanitizeHtmlUtils.js.map +1 -1
  224. package/dist/utils/functions/queryUtils.js.map +1 -1
  225. package/dist/utils/hooks/useGetInfoFromIds.d.ts.map +1 -1
  226. package/dist/utils/hooks/useGetInfoFromIds.js.map +1 -1
  227. package/dist/utils/slots/SlotUtils.d.ts.map +1 -1
  228. package/dist/utils/slots/SlotUtils.js.map +1 -1
  229. package/package.json +5 -6
@@ -1 +1 @@
1
- {"version":3,"file":"TimelinePlotSpeciesSelector.js","names":[],"sources":["../../../src/components/TimelinePlot/TimelinePlotSpeciesSelector.tsx"],"sourcesContent":["import React from 'react'\nimport { StyledFormControl } from '@/components/styled'\nimport { useGetFullTableQueryResults } from '@/synapse-queries'\nimport { parseEntityIdFromSqlStatement } from '@/utils/functions'\nimport { BUNDLE_MASK_QUERY_RESULTS } from '@/utils/SynapseConstants'\nimport { InputLabel, MenuItem, Select } from '@mui/material'\nimport { Box } from '@mui/system'\nimport { QueryFilter } from '@sage-bionetworks/synapse-types'\nimport { Dispatch, SetStateAction } from 'react'\n\nexport type TimelinePlotSpeciesSelectorProps = {\n sql: string\n additionalFilters?: QueryFilter[]\n species?: string | null\n setSpecies: Dispatch<SetStateAction<string | null | undefined>>\n}\nexport const TimelinePlotSpeciesSelector = ({\n sql,\n additionalFilters,\n species,\n setSpecies,\n}: TimelinePlotSpeciesSelectorProps): React.ReactNode => {\n const eventsTableId = parseEntityIdFromSqlStatement(sql)\n // Fetch the species\n const eventTableQuery = useGetFullTableQueryResults({\n entityId: eventsTableId,\n query: {\n sql: `SELECT distinct unnest(species) FROM ${eventsTableId} WHERE species IS NOT NULL AND observationTime IS NOT NULL GROUP BY species`,\n additionalFilters: additionalFilters,\n },\n partMask: BUNDLE_MASK_QUERY_RESULTS,\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n })\n\n const { data: speciesData, isLoading } = eventTableQuery\n const rows = speciesData?.queryResult?.queryResults?.rows\n const defaultSpecies = rows && rows.length > 0 ? rows[0].values[0] : undefined\n if (species == undefined && defaultSpecies != undefined) {\n setSpecies(defaultSpecies)\n }\n // Hide if loading, there are no rows, or there's only 1 species option\n if (isLoading || !rows || rows.length < 2) {\n return <></>\n }\n\n return (\n <Box>\n <StyledFormControl>\n <InputLabel>Species</InputLabel>\n <Select\n sx={{ marginLeft: '2px', marginBottom: '2px' }}\n value={species}\n label=\"Species\"\n onChange={event => {\n setSpecies(event.target.value)\n }}\n >\n {rows?.map(row => {\n const species = row.values[0]!\n return (\n <MenuItem key={species} value={species}>\n {species}\n </MenuItem>\n )\n })}\n </Select>\n </StyledFormControl>\n </Box>\n )\n}\nexport default TimelinePlotSpeciesSelector\n"],"mappings":";;;;;;;;;;;;AAgBA,IAAa,KAA+B,EAC1C,QACA,sBACA,YACA,oBACuD;CACvD,IAAM,IAAgB,EAA8B,EAAI,EAYlD,EAAE,MAAM,GAAa,iBAVH,EAA4B;EAClD,UAAU;EACV,OAAO;GACL,KAAK,wCAAwC,EAAc;GACxC;GACpB;EACD,UAAA;EACA,cAAc;EACf,CAEwC,EACnC,IAAO,GAAa,aAAa,cAAc,MAC/C,IAAiB,KAAQ,EAAK,SAAS,IAAI,EAAK,GAAG,OAAO,KAAK,KAAA;AASrE,QARI,KAAW,QAAa,KAAkB,QAC5C,EAAW,EAAe,EAGxB,KAAa,CAAC,KAAQ,EAAK,SAAS,IAC/B,kBAAA,GAAA,EAAK,CAAA,GAIZ,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAY,WAAoB,CAAA,EAChC,kBAAC,GAAD;EACE,IAAI;GAAE,YAAY;GAAO,cAAc;GAAO;EAC9C,OAAO;EACP,OAAM;EACN,WAAU,MAAS;AACjB,KAAW,EAAM,OAAO,MAAM;;YAG/B,GAAM,KAAI,MAAO;GAChB,IAAM,IAAU,EAAI,OAAO;AAC3B,UACE,kBAAC,GAAD;IAAwB,OAAO;cAC5B;IACQ,EAFI,EAEJ;IAEb;EACK,CAAA,CACS,EAAA,CAAA,EAChB,CAAA"}
1
+ {"version":3,"file":"TimelinePlotSpeciesSelector.js","names":[],"sources":["../../../src/components/TimelinePlot/TimelinePlotSpeciesSelector.tsx"],"sourcesContent":["import React, { useId } from 'react'\nimport { StyledFormControl } from '@/components/styled'\nimport { useGetFullTableQueryResults } from '@/synapse-queries'\nimport { parseEntityIdFromSqlStatement } from '@/utils/functions'\nimport { BUNDLE_MASK_QUERY_RESULTS } from '@/utils/SynapseConstants'\nimport { InputLabel, MenuItem, Select } from '@mui/material'\nimport { Box } from '@mui/system'\nimport { QueryFilter } from '@sage-bionetworks/synapse-types'\nimport { Dispatch, SetStateAction } from 'react'\n\nexport type TimelinePlotSpeciesSelectorProps = {\n sql: string\n additionalFilters?: QueryFilter[]\n species?: string | null\n setSpecies: Dispatch<SetStateAction<string | null | undefined>>\n}\nexport const TimelinePlotSpeciesSelector = ({\n sql,\n additionalFilters,\n species,\n setSpecies,\n}: TimelinePlotSpeciesSelectorProps): React.ReactNode => {\n const speciesLabelId = useId()\n\n const eventsTableId = parseEntityIdFromSqlStatement(sql)\n // Fetch the species\n const eventTableQuery = useGetFullTableQueryResults({\n entityId: eventsTableId,\n query: {\n sql: `SELECT distinct unnest(species) FROM ${eventsTableId} WHERE species IS NOT NULL AND observationTime IS NOT NULL GROUP BY species`,\n additionalFilters: additionalFilters,\n },\n partMask: BUNDLE_MASK_QUERY_RESULTS,\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n })\n\n const { data: speciesData, isLoading } = eventTableQuery\n const rows = speciesData?.queryResult?.queryResults?.rows\n const defaultSpecies = rows && rows.length > 0 ? rows[0].values[0] : undefined\n if (species == undefined && defaultSpecies != undefined) {\n setSpecies(defaultSpecies)\n }\n // Hide if loading, there are no rows, or there's only 1 species option\n if (isLoading || !rows || rows.length < 2) {\n return <></>\n }\n\n return (\n <Box>\n <StyledFormControl>\n <InputLabel id={speciesLabelId}>Species</InputLabel>\n <Select\n sx={{ marginLeft: '2px', marginBottom: '2px' }}\n labelId={speciesLabelId}\n value={species}\n label=\"Species\"\n onChange={event => {\n setSpecies(event.target.value)\n }}\n >\n {rows?.map(row => {\n const species = row.values[0]!\n return (\n <MenuItem key={species} value={species}>\n {species}\n </MenuItem>\n )\n })}\n </Select>\n </StyledFormControl>\n </Box>\n )\n}\nexport default TimelinePlotSpeciesSelector\n"],"mappings":";;;;;;;;;;;;AAgBA,IAAa,KAA+B,EAC1C,QACA,sBACA,YACA,oBACuD;CACvD,IAAM,IAAiB,GAAO,EAExB,IAAgB,EAA8B,EAAI,EAYlD,EAAE,MAAM,GAAa,iBAVH,EAA4B;EAClD,UAAU;EACV,OAAO;GACL,KAAK,wCAAwC,EAAc;GACxC;GACpB;EACD,UAAA;EACA,cAAc;EACf,CAEwC,EACnC,IAAO,GAAa,aAAa,cAAc,MAC/C,IAAiB,KAAQ,EAAK,SAAS,IAAI,EAAK,GAAG,OAAO,KAAK,KAAA;AASrE,QARI,KAAW,QAAa,KAAkB,QAC5C,EAAW,EAAe,EAGxB,KAAa,CAAC,KAAQ,EAAK,SAAS,IAC/B,kBAAA,GAAA,EAAK,CAAA,GAIZ,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;EAAY,IAAI;YAAgB;EAAoB,CAAA,EACpD,kBAAC,GAAD;EACE,IAAI;GAAE,YAAY;GAAO,cAAc;GAAO;EAC9C,SAAS;EACT,OAAO;EACP,OAAM;EACN,WAAU,MAAS;AACjB,KAAW,EAAM,OAAO,MAAM;;YAG/B,GAAM,KAAI,MAAO;GAChB,IAAM,IAAU,EAAI,OAAO;AAC3B,UACE,kBAAC,GAAD;IAAwB,OAAO;cAC5B;IACQ,EAFI,EAEJ;IAEb;EACK,CAAA,CACS,EAAA,CAAA,EAChB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"UserCardList.d.ts","sourceRoot":"","sources":["../../../src/components/UserCardList/UserCardList.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAoB,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACzE,OAAO,EAEL,MAAM,EACN,WAAW,EACZ,MAAM,iCAAiC,CAAA;AAExC,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGjC,MAAM,MAAM,iBAAiB,GAAG;IAE9B,IAAI,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAA;IACvB,IAAI,CAAC,EAAE,YAAY,CAAA;IAGnB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;CAC5C,CAAA;AACD,qBAAa,YAAa,SAAQ,SAAS,CACzC,iBAAiB,EACjB,iBAAiB,CAClB;gBACa,KAAK,EAAE,iBAAiB;IAQpC,iBAAiB;IAKjB,kBAAkB,CAAC,SAAS,EAAE,iBAAiB;IAY/C,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE;IAmB9B;;;;;;OAMG;IACH,mBAAmB,CAAC,MAAM,EAAE,MAAM;IAwBlC,MAAM;CAqDP;AACD,eAAe,YAAY,CAAA"}
1
+ {"version":3,"file":"UserCardList.d.ts","sourceRoot":"","sources":["../../../src/components/UserCardList/UserCardList.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAoB,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACzE,OAAO,EAEL,MAAM,EACN,WAAW,EACZ,MAAM,iCAAiC,CAAA;AAExC,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGjC,MAAM,MAAM,iBAAiB,GAAG;IAE9B,IAAI,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAA;IACvB,IAAI,CAAC,EAAE,YAAY,CAAA;IAGnB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;CAC5C,CAAA;AACD,qBAAa,YAAa,SAAQ,SAAS,CACzC,iBAAiB,EACjB,iBAAiB,CAClB;gBACa,KAAK,EAAE,iBAAiB;IAQpC,iBAAiB;IAKjB,kBAAkB,CAAC,SAAS,EAAE,iBAAiB;IAY/C,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE;IAmB9B;;;;;;OAMG;IACH,mBAAmB,CAAC,MAAM,EAAE,MAAM;IA0BlC,MAAM;CAqDP;AACD,eAAe,YAAY,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"UserCardList.js","names":[],"sources":["../../../src/components/UserCardList/UserCardList.tsx"],"sourcesContent":["import { UserProfileList } from '@/synapse-client/SynapseClient'\nimport { getUserProfileWithProfilePicAttached } from '@/utils/functions/getUserData'\nimport { MEDIUM_USER_CARD, UserCardSize } from '@/utils/SynapseConstants'\nimport {\n ColumnTypeEnum,\n RowSet,\n UserProfile,\n} from '@sage-bionetworks/synapse-types'\nimport { without } from 'lodash-es'\nimport { Component } from 'react'\nimport UserCard from '../UserCard/UserCard'\n\nexport type UserCardListProps = {\n /* The list of user IDs or null values to render. For null values, the card will be rendered with table data supplied by `firstName`, `lastName`, and `institution` columns supplied by the data prop. */\n list: (string | null)[]\n size?: UserCardSize\n // Data should not be needed, however, it gives the option to fill in a user profile with other column\n // fields. This is required specifically by AMP-AD Explore/People page\n rowSet?: RowSet\n}\n\nexport type UserCardListState = {\n userProfileMap: Record<string, UserProfile>\n}\nexport class UserCardList extends Component<\n UserCardListProps,\n UserCardListState\n> {\n constructor(props: UserCardListProps) {\n super(props)\n this.state = {\n userProfileMap: {},\n }\n this.update = this.update.bind(this)\n }\n\n componentDidMount() {\n const { list } = this.props\n this.update(list)\n }\n\n componentDidUpdate(prevProps: UserCardListProps) {\n const priorListOfIds = prevProps.list\n const newValues = without(\n this.props.list.filter(el => el),\n ...priorListOfIds,\n )\n // check that the props have changed by seeing that at least one element is different\n if (newValues.length > 0) {\n this.update(newValues)\n }\n }\n\n update(list: (string | null)[]) {\n getUserProfileWithProfilePicAttached(\n list.filter((el): el is string => !!el),\n )\n .then((data: UserProfileList) => {\n const newEntries: Record<string, UserProfile> = {}\n data.list.forEach(el => {\n const { ownerId } = el\n newEntries[ownerId] = el\n })\n this.setState({\n userProfileMap: { ...this.state.userProfileMap, ...newEntries },\n })\n })\n .catch((err: string) => {\n console.error('Error on batch call =', err)\n })\n }\n\n /**\n * Given data this will find rows where there is no userId columnType and create faux user profiles\n * using firstName, lastName, and institution (company in UserProfile object).\n * @param {RowSet} rowSet\n * @returns list of UserProfiles with firstName, lastName, company, userName (first letter of firstName) filled out.\n * @memberof UserCardList\n */\n manuallyExtractData(rowSet: RowSet) {\n const firstNameIndex = rowSet.headers.findIndex(\n el => el.name === 'firstName',\n )\n const lastNameIndex = rowSet.headers.findIndex(el => el.name === 'lastName')\n const institutionIndex = rowSet.headers.findIndex(\n el => el.name === 'institution',\n )\n const ownerId = rowSet.headers.findIndex(\n el => el.columnType === ColumnTypeEnum.USERID,\n )\n const nullOwnerIdsRows = rowSet.rows.filter(el => !el.values[ownerId])\n return nullOwnerIdsRows.map<Omit<UserProfile, 'ownerId'>>(el => {\n const values = el.values\n return {\n firstName: values[firstNameIndex] ?? '',\n lastName: values[lastNameIndex] ?? '',\n company: values[institutionIndex] ?? undefined,\n ownerId: null,\n userName: values[firstNameIndex] ? values[firstNameIndex][0] ?? '' : '',\n }\n })\n }\n\n render() {\n const { size = MEDIUM_USER_CARD, rowSet, list } = this.props\n const { userProfileMap = {} } = this.state\n const fauxUserProfilesList = rowSet && this.manuallyExtractData(rowSet)\n let fauxUserProfileIndex = 0\n return (\n <div className=\"SRC-card-grid-row\">\n {\n // we loop through the list from the props because thats the 'active set of data' whereas the data stored in state could be stale\n list.map(ownerId => {\n const userProfile = ownerId != null ? userProfileMap[ownerId] : null\n if (userProfile) {\n return (\n <div\n key={JSON.stringify(userProfile)}\n className=\"SRC-grid-item SRC-narrow-grid-item\"\n >\n <UserCard\n size={size}\n preSignedURL={userProfile.clientPreSignedURL}\n userProfile={userProfile}\n />\n </div>\n )\n }\n const fauxUserProfile =\n fauxUserProfilesList && fauxUserProfilesList[fauxUserProfileIndex]\n if (!fauxUserProfile) {\n // This could happen in one of two cases:\n // - The props just updated with a new userlist where the data is being gathered for this particular user\n // OR there is no mapping for this user\n return false\n }\n fauxUserProfileIndex += 1\n return (\n <div\n key={JSON.stringify(fauxUserProfile)}\n className=\"SRC-grid-item SRC-narrow-grid-item\"\n >\n <UserCard\n disableLink={true}\n hideEmail={true}\n size={size}\n // TODO: Modify UserCard to accept a fake profile with no ownerId field, and remove this cast.\n userProfile={fauxUserProfile as UserProfile}\n />\n </div>\n )\n })\n }\n </div>\n )\n }\n}\nexport default UserCardList\n"],"mappings":";;;;;;;;AAwBA,IAAa,IAAb,cAAkC,EAGhC;CACA,YAAY,GAA0B;AAKpC,EAJA,MAAM,EAAM,EACZ,KAAK,QAAQ,EACX,gBAAgB,EAAE,EACnB,EACD,KAAK,SAAS,KAAK,OAAO,KAAK,KAAK;;CAGtC,oBAAoB;EAClB,IAAM,EAAE,YAAS,KAAK;AACtB,OAAK,OAAO,EAAK;;CAGnB,mBAAmB,GAA8B;EAC/C,IAAM,IAAiB,EAAU,MAC3B,IAAY,EAChB,KAAK,MAAM,KAAK,QAAO,MAAM,EAAG,EAChC,GAAG,EACJ;AAED,EAAI,EAAU,SAAS,KACrB,KAAK,OAAO,EAAU;;CAI1B,OAAO,GAAyB;AAC9B,IACE,EAAK,QAAQ,MAAqB,CAAC,CAAC,EAAG,CACxC,CACE,MAAM,MAA0B;GAC/B,IAAM,IAA0C,EAAE;AAKlD,GAJA,EAAK,KAAK,SAAQ,MAAM;IACtB,IAAM,EAAE,eAAY;AACpB,MAAW,KAAW;KACtB,EACF,KAAK,SAAS,EACZ,gBAAgB;IAAE,GAAG,KAAK,MAAM;IAAgB,GAAG;IAAY,EAChE,CAAC;IACF,CACD,OAAO,MAAgB;AACtB,WAAQ,MAAM,yBAAyB,EAAI;IAC3C;;CAUN,oBAAoB,GAAgB;EAClC,IAAM,IAAiB,EAAO,QAAQ,WACpC,MAAM,EAAG,SAAS,YACnB,EACK,IAAgB,EAAO,QAAQ,WAAU,MAAM,EAAG,SAAS,WAAW,EACtE,IAAmB,EAAO,QAAQ,WACtC,MAAM,EAAG,SAAS,cACnB,EACK,IAAU,EAAO,QAAQ,WAC7B,MAAM,EAAG,eAAe,EAAe,OACxC;AAED,SADyB,EAAO,KAAK,QAAO,MAAM,CAAC,EAAG,OAAO,GACtD,CAAiB,KAAkC,MAAM;GAC9D,IAAM,IAAS,EAAG;AAClB,UAAO;IACL,WAAW,EAAO,MAAmB;IACrC,UAAU,EAAO,MAAkB;IACnC,SAAS,EAAO,MAAqB,KAAA;IACrC,SAAS;IACT,UAAU,EAAO,KAAkB,EAAO,GAAgB,MAAM,KAAK;IACtE;IACD;;CAGJ,SAAS;EACP,IAAM,EAAE,UAAO,GAAkB,WAAQ,YAAS,KAAK,OACjD,EAAE,oBAAiB,EAAE,KAAK,KAAK,OAC/B,IAAuB,KAAU,KAAK,oBAAoB,EAAO,EACnE,IAAuB;AAC3B,SACE,kBAAC,OAAD;GAAK,WAAU;aAGX,EAAK,KAAI,MAAW;IAClB,IAAM,IAAc,KAAW,OAAiC,OAA1B,EAAe;AACrD,QAAI,EACF,QACE,kBAAC,OAAD;KAEE,WAAU;eAEV,kBAAC,GAAD;MACQ;MACN,cAAc,EAAY;MACb;MACb,CAAA;KACE,EARC,KAAK,UAAU,EAAY,CAQ5B;IAGV,IAAM,IACJ,KAAwB,EAAqB;AAQ/C,WAPK,KAML,KAAwB,GAEtB,kBAAC,OAAD;KAEE,WAAU;eAEV,kBAAC,GAAD;MACE,aAAa;MACb,WAAW;MACL;MAEN,aAAa;MACb,CAAA;KACE,EAVC,KAAK,UAAU,EAAgB,CAUhC,IAfC;KAiBT;GAEA,CAAA"}
1
+ {"version":3,"file":"UserCardList.js","names":[],"sources":["../../../src/components/UserCardList/UserCardList.tsx"],"sourcesContent":["import { UserProfileList } from '@/synapse-client/SynapseClient'\nimport { getUserProfileWithProfilePicAttached } from '@/utils/functions/getUserData'\nimport { MEDIUM_USER_CARD, UserCardSize } from '@/utils/SynapseConstants'\nimport {\n ColumnTypeEnum,\n RowSet,\n UserProfile,\n} from '@sage-bionetworks/synapse-types'\nimport { without } from 'lodash-es'\nimport { Component } from 'react'\nimport UserCard from '../UserCard/UserCard'\n\nexport type UserCardListProps = {\n /* The list of user IDs or null values to render. For null values, the card will be rendered with table data supplied by `firstName`, `lastName`, and `institution` columns supplied by the data prop. */\n list: (string | null)[]\n size?: UserCardSize\n // Data should not be needed, however, it gives the option to fill in a user profile with other column\n // fields. This is required specifically by AMP-AD Explore/People page\n rowSet?: RowSet\n}\n\nexport type UserCardListState = {\n userProfileMap: Record<string, UserProfile>\n}\nexport class UserCardList extends Component<\n UserCardListProps,\n UserCardListState\n> {\n constructor(props: UserCardListProps) {\n super(props)\n this.state = {\n userProfileMap: {},\n }\n this.update = this.update.bind(this)\n }\n\n componentDidMount() {\n const { list } = this.props\n this.update(list)\n }\n\n componentDidUpdate(prevProps: UserCardListProps) {\n const priorListOfIds = prevProps.list\n const newValues = without(\n this.props.list.filter(el => el),\n ...priorListOfIds,\n )\n // check that the props have changed by seeing that at least one element is different\n if (newValues.length > 0) {\n this.update(newValues)\n }\n }\n\n update(list: (string | null)[]) {\n getUserProfileWithProfilePicAttached(\n list.filter((el): el is string => !!el),\n )\n .then((data: UserProfileList) => {\n const newEntries: Record<string, UserProfile> = {}\n data.list.forEach(el => {\n const { ownerId } = el\n newEntries[ownerId] = el\n })\n this.setState({\n userProfileMap: { ...this.state.userProfileMap, ...newEntries },\n })\n })\n .catch((err: string) => {\n console.error('Error on batch call =', err)\n })\n }\n\n /**\n * Given data this will find rows where there is no userId columnType and create faux user profiles\n * using firstName, lastName, and institution (company in UserProfile object).\n * @param {RowSet} rowSet\n * @returns list of UserProfiles with firstName, lastName, company, userName (first letter of firstName) filled out.\n * @memberof UserCardList\n */\n manuallyExtractData(rowSet: RowSet) {\n const firstNameIndex = rowSet.headers.findIndex(\n el => el.name === 'firstName',\n )\n const lastNameIndex = rowSet.headers.findIndex(el => el.name === 'lastName')\n const institutionIndex = rowSet.headers.findIndex(\n el => el.name === 'institution',\n )\n const ownerId = rowSet.headers.findIndex(\n el => el.columnType === ColumnTypeEnum.USERID,\n )\n const nullOwnerIdsRows = rowSet.rows.filter(el => !el.values[ownerId])\n return nullOwnerIdsRows.map<Omit<UserProfile, 'ownerId'>>(el => {\n const values = el.values\n return {\n firstName: values[firstNameIndex] ?? '',\n lastName: values[lastNameIndex] ?? '',\n company: values[institutionIndex] ?? undefined,\n ownerId: null,\n userName: values[firstNameIndex]\n ? (values[firstNameIndex][0] ?? '')\n : '',\n }\n })\n }\n\n render() {\n const { size = MEDIUM_USER_CARD, rowSet, list } = this.props\n const { userProfileMap = {} } = this.state\n const fauxUserProfilesList = rowSet && this.manuallyExtractData(rowSet)\n let fauxUserProfileIndex = 0\n return (\n <div className=\"SRC-card-grid-row\">\n {\n // we loop through the list from the props because thats the 'active set of data' whereas the data stored in state could be stale\n list.map(ownerId => {\n const userProfile = ownerId != null ? userProfileMap[ownerId] : null\n if (userProfile) {\n return (\n <div\n key={JSON.stringify(userProfile)}\n className=\"SRC-grid-item SRC-narrow-grid-item\"\n >\n <UserCard\n size={size}\n preSignedURL={userProfile.clientPreSignedURL}\n userProfile={userProfile}\n />\n </div>\n )\n }\n const fauxUserProfile =\n fauxUserProfilesList && fauxUserProfilesList[fauxUserProfileIndex]\n if (!fauxUserProfile) {\n // This could happen in one of two cases:\n // - The props just updated with a new userlist where the data is being gathered for this particular user\n // OR there is no mapping for this user\n return false\n }\n fauxUserProfileIndex += 1\n return (\n <div\n key={JSON.stringify(fauxUserProfile)}\n className=\"SRC-grid-item SRC-narrow-grid-item\"\n >\n <UserCard\n disableLink={true}\n hideEmail={true}\n size={size}\n // TODO: Modify UserCard to accept a fake profile with no ownerId field, and remove this cast.\n userProfile={fauxUserProfile as UserProfile}\n />\n </div>\n )\n })\n }\n </div>\n )\n }\n}\nexport default UserCardList\n"],"mappings":";;;;;;;;AAwBA,IAAa,IAAb,cAAkC,EAGhC;CACA,YAAY,GAA0B;AAKpC,EAJA,MAAM,EAAM,EACZ,KAAK,QAAQ,EACX,gBAAgB,EAAE,EACnB,EACD,KAAK,SAAS,KAAK,OAAO,KAAK,KAAK;;CAGtC,oBAAoB;EAClB,IAAM,EAAE,YAAS,KAAK;AACtB,OAAK,OAAO,EAAK;;CAGnB,mBAAmB,GAA8B;EAC/C,IAAM,IAAiB,EAAU,MAC3B,IAAY,EAChB,KAAK,MAAM,KAAK,QAAO,MAAM,EAAG,EAChC,GAAG,EACJ;AAED,EAAI,EAAU,SAAS,KACrB,KAAK,OAAO,EAAU;;CAI1B,OAAO,GAAyB;AAC9B,IACE,EAAK,QAAQ,MAAqB,CAAC,CAAC,EAAG,CACxC,CACE,MAAM,MAA0B;GAC/B,IAAM,IAA0C,EAAE;AAKlD,GAJA,EAAK,KAAK,SAAQ,MAAM;IACtB,IAAM,EAAE,eAAY;AACpB,MAAW,KAAW;KACtB,EACF,KAAK,SAAS,EACZ,gBAAgB;IAAE,GAAG,KAAK,MAAM;IAAgB,GAAG;IAAY,EAChE,CAAC;IACF,CACD,OAAO,MAAgB;AACtB,WAAQ,MAAM,yBAAyB,EAAI;IAC3C;;CAUN,oBAAoB,GAAgB;EAClC,IAAM,IAAiB,EAAO,QAAQ,WACpC,MAAM,EAAG,SAAS,YACnB,EACK,IAAgB,EAAO,QAAQ,WAAU,MAAM,EAAG,SAAS,WAAW,EACtE,IAAmB,EAAO,QAAQ,WACtC,MAAM,EAAG,SAAS,cACnB,EACK,IAAU,EAAO,QAAQ,WAC7B,MAAM,EAAG,eAAe,EAAe,OACxC;AAED,SADyB,EAAO,KAAK,QAAO,MAAM,CAAC,EAAG,OAAO,GACtD,CAAiB,KAAkC,MAAM;GAC9D,IAAM,IAAS,EAAG;AAClB,UAAO;IACL,WAAW,EAAO,MAAmB;IACrC,UAAU,EAAO,MAAkB;IACnC,SAAS,EAAO,MAAqB,KAAA;IACrC,SAAS;IACT,UAAU,EAAO,KACZ,EAAO,GAAgB,MAAM,KAC9B;IACL;IACD;;CAGJ,SAAS;EACP,IAAM,EAAE,UAAO,GAAkB,WAAQ,YAAS,KAAK,OACjD,EAAE,oBAAiB,EAAE,KAAK,KAAK,OAC/B,IAAuB,KAAU,KAAK,oBAAoB,EAAO,EACnE,IAAuB;AAC3B,SACE,kBAAC,OAAD;GAAK,WAAU;aAGX,EAAK,KAAI,MAAW;IAClB,IAAM,IAAc,KAAW,OAAiC,OAA1B,EAAe;AACrD,QAAI,EACF,QACE,kBAAC,OAAD;KAEE,WAAU;eAEV,kBAAC,GAAD;MACQ;MACN,cAAc,EAAY;MACb;MACb,CAAA;KACE,EARC,KAAK,UAAU,EAAY,CAQ5B;IAGV,IAAM,IACJ,KAAwB,EAAqB;AAQ/C,WAPK,KAML,KAAwB,GAEtB,kBAAC,OAAD;KAEE,WAAU;eAEV,kBAAC,GAAD;MACE,aAAa;MACb,WAAW;MACL;MAEN,aAAa;MACb,CAAA;KACE,EAVC,KAAK,UAAU,EAAgB,CAUhC,IAfC;KAiBT;GAEA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"UserCardListGroups.Desktop.js","names":[],"sources":["../../../../src/components/UserCardList/UserCardListGroups/UserCardListGroups.Desktop.tsx"],"sourcesContent":["import { useState } from 'react'\nimport UserCardListRotate from '../UserCardListRotate'\nimport { FacetColumnValuesRequest } from '@sage-bionetworks/synapse-types'\nimport { UserCardListGroupsProps } from './UserCardListGroups'\n\nexport default function UserCardListGroupsDesktop(\n props: UserCardListGroupsProps,\n) {\n const [selectedGroupIndex, setSelectedGroupIndex] = useState<number>(0)\n const { columnName, facetValues, ...rest } = props\n const selectedFacet: FacetColumnValuesRequest = {\n columnName,\n facetValues: [facetValues[selectedGroupIndex]],\n concreteType:\n 'org.sagebionetworks.repo.model.table.FacetColumnValuesRequest',\n }\n return (\n <div className=\"control-container\">\n <div className=\"button-container\">\n {facetValues?.map((el, curIndex) => {\n return (\n <button\n className={selectedGroupIndex === curIndex ? 'isSelected' : ''}\n onClick={() => setSelectedGroupIndex(curIndex)}\n key={el}\n >\n {el}\n </button>\n )\n })}\n {/* \n This button keeps the border line in the button container running from top to bottom,\n it doesn't have any functionality.\n */}\n <button className=\"gap-fill\" />\n </div>\n <div className=\"content-container\">\n <UserCardListRotate\n key={`UserCardListGroup-${selectedGroupIndex}`}\n {...rest}\n selectedFacets={[selectedFacet]}\n />\n </div>\n </div>\n )\n}\n"],"mappings":";;;;AAKA,SAAwB,EACtB,GACA;CACA,IAAM,CAAC,GAAoB,KAAyB,EAAiB,EAAE,EACjE,EAAE,eAAY,gBAAa,GAAG,MAAS,GACvC,IAA0C;EAC9C;EACA,aAAa,CAAC,EAAY,GAAoB;EAC9C,cACE;EACH;AACD,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACG,GAAa,KAAK,GAAI,MAEnB,kBAAC,UAAD;IACE,WAAW,MAAuB,IAAW,eAAe;IAC5D,eAAe,EAAsB,EAAS;cAG7C;IACM,EAHF,EAGE,CAEX,EAKF,kBAAC,UAAD,EAAQ,WAAU,YAAa,CAAA,CAC3B;MACN,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,GAAD;IAEE,GAAI;IACJ,gBAAgB,CAAC,EAAc;IAC/B,EAHK,qBAAqB,IAG1B;GACE,CAAA,CACF"}
1
+ {"version":3,"file":"UserCardListGroups.Desktop.js","names":[],"sources":["../../../../src/components/UserCardList/UserCardListGroups/UserCardListGroups.Desktop.tsx"],"sourcesContent":["import { useState } from 'react'\nimport UserCardListRotate from '../UserCardListRotate'\nimport { FacetColumnValuesRequest } from '@sage-bionetworks/synapse-types'\nimport { UserCardListGroupsProps } from './UserCardListGroups'\n\nexport default function UserCardListGroupsDesktop(\n props: UserCardListGroupsProps,\n) {\n const [selectedGroupIndex, setSelectedGroupIndex] = useState<number>(0)\n const { columnName, facetValues, ...rest } = props\n const selectedFacet: FacetColumnValuesRequest = {\n columnName,\n facetValues: [facetValues[selectedGroupIndex]],\n concreteType:\n 'org.sagebionetworks.repo.model.table.FacetColumnValuesRequest',\n }\n return (\n <div className=\"control-container\">\n <div className=\"button-container\">\n {facetValues?.map((el, curIndex) => {\n return (\n <button\n className={selectedGroupIndex === curIndex ? 'isSelected' : ''}\n onClick={() => setSelectedGroupIndex(curIndex)}\n key={el}\n >\n {el}\n </button>\n )\n })}\n {/*\n This button keeps the border line in the button container running from top to bottom,\n it doesn't have any functionality.\n */}\n <button className=\"gap-fill\" />\n </div>\n <div className=\"content-container\">\n <UserCardListRotate\n key={`UserCardListGroup-${selectedGroupIndex}`}\n {...rest}\n selectedFacets={[selectedFacet]}\n />\n </div>\n </div>\n )\n}\n"],"mappings":";;;;AAKA,SAAwB,EACtB,GACA;CACA,IAAM,CAAC,GAAoB,KAAyB,EAAiB,EAAE,EACjE,EAAE,eAAY,gBAAa,GAAG,MAAS,GACvC,IAA0C;EAC9C;EACA,aAAa,CAAC,EAAY,GAAoB;EAC9C,cACE;EACH;AACD,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACG,GAAa,KAAK,GAAI,MAEnB,kBAAC,UAAD;IACE,WAAW,MAAuB,IAAW,eAAe;IAC5D,eAAe,EAAsB,EAAS;cAG7C;IACM,EAHF,EAGE,CAEX,EAKF,kBAAC,UAAD,EAAQ,WAAU,YAAa,CAAA,CAC3B;MACN,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,GAAD;IAEE,GAAI;IACJ,gBAAgB,CAAC,EAAc;IAC/B,EAHK,qBAAqB,IAG1B;GACE,CAAA,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"useUserOrTeam.js","names":[],"sources":["../../../src/components/UserOrTeamBadge/useUserOrTeam.tsx"],"sourcesContent":["import {\n useGetProfileImage,\n useGetStablePresignedUrl,\n} from '@/synapse-queries/file/useFiles'\nimport { useGetUserGroupHeader } from '@/synapse-queries/user/useUserGroupHeader'\nimport { useGetRealmPrincipals } from '@/synapse-queries/realm/useRealmPrincipals'\nimport { useGetTeam } from '@/synapse-queries/team/useTeam'\nimport { useCreateUrlForData } from '@/utils/hooks/usePreFetchResource'\nimport {\n FileHandleAssociateType,\n UserGroupHeader,\n UserProfile,\n} from '@sage-bionetworks/synapse-types'\nimport { Avatar as MUIAvatar } from '@mui/material'\nimport React, { useMemo } from 'react'\nimport { Avatar, AvatarSize } from '../UserCard/Avatar'\nimport IconSvg from '../IconSvg/IconSvg'\n\nexport type UseUserOrTeamResult = {\n /** The lightweight header for the resolved principal (user or team). Undefined while loading. */\n userGroupHeader: UserGroupHeader | undefined\n /** True while the `userGroupHeader` is being fetched. */\n isLoading: boolean\n /**\n * A stable React component that renders the icon for the resolved principal.\n *\n * - **Individual user**: renders an `Avatar` with the user's profile image, falling back to\n * colored initials when no image is available.\n * - **Regular team**: renders a team icon (`IconSvg icon=\"team\"`), or the team's custom image\n * when `Team.icon` (a file-handle ID) is set.\n * - **Public / authenticated-users group**: renders a globe icon (`IconSvg icon=\"public\"`).\n *\n * Accepts an optional `avatarSize` prop (`'SMALL' | 'MEDIUM' | 'LARGE'`, default `'SMALL'`)\n * for caller-controlled sizing. Returns `null` while the principal's identity has not yet\n * been resolved (i.e., while `isLoading` is true).\n */\n IconComponent: React.ComponentType<{ avatarSize?: AvatarSize }>\n /**\n * Identifies Synapse realm special groups.\n *\n * - `'authenticatedUsers'` — the principal is the \"All registered Synapse users\" group.\n * - `'publicGroup'` — the principal is the \"Anyone on the web\" group.\n * - `null` — the principal is an individual user, a regular team, or realm data is still loading.\n */\n specialGroupType: 'authenticatedUsers' | 'publicGroup' | null\n}\n\nfunction UserAvatarIcon({\n ownerId,\n syntheticProfile,\n avatarSize = 'SMALL',\n}: {\n ownerId: string\n syntheticProfile: UserProfile\n avatarSize?: AvatarSize\n}) {\n const { data: blob, isLoading } = useGetProfileImage(ownerId)\n const imageURL = useCreateUrlForData(blob)\n return (\n <Avatar\n userProfile={syntheticProfile}\n imageURL={imageURL}\n avatarSize={avatarSize}\n showCardOnHover={false}\n isLoadingAvatar={isLoading}\n />\n )\n}\n\nconst avatarSizePx: Record<AvatarSize, number> = {\n SMALL: 20,\n MEDIUM: 30,\n LARGE: 80,\n}\n\nfunction TeamAvatarIcon({\n ownerId,\n isPublicGroup,\n avatarSize = 'SMALL',\n}: {\n ownerId: string\n isPublicGroup: boolean\n avatarSize?: AvatarSize\n}) {\n const { data: team } = useGetTeam(ownerId, { enabled: !isPublicGroup })\n\n const { dataUrl: teamIconUrl } =\n useGetStablePresignedUrl(\n {\n fileHandleId: team?.icon ?? '',\n associateObjectId: ownerId,\n associateObjectType: FileHandleAssociateType.TeamAttachment,\n },\n false,\n { enabled: !isPublicGroup && !!team?.icon },\n ) ?? {}\n\n const size = avatarSizePx[avatarSize]\n\n if (isPublicGroup) {\n return <IconSvg icon=\"public\" wrap={false} sx={{ fontSize: size }} />\n }\n\n if (teamIconUrl) {\n return (\n <MUIAvatar\n src={teamIconUrl}\n sx={{ width: size, height: size, bgcolor: 'background.default' }}\n />\n )\n }\n\n return <IconSvg icon=\"team\" wrap={false} sx={{ fontSize: size }} />\n}\n\n/**\n * Resolves a Synapse principal (user or team) by ID and returns display data plus a\n * ready-to-render icon component.\n *\n * @param principalId - The numeric or string Synapse principal ID. If omitted, falls back to\n * `providedUserGroupHeader.ownerId`. Pass `undefined` when the ID is not yet known — the\n * hook will return `isLoading: false` with all fields undefined/null until an ID is provided.\n * @param providedUserGroupHeader - An already-fetched `UserGroupHeader`. When supplied, the\n * network fetch for the header is skipped entirely and this value is used directly. Useful\n * when the caller already has header data (e.g., from a list response).\n */\nexport function useUserOrTeam(\n principalId?: string | number,\n providedUserGroupHeader?: UserGroupHeader,\n): UseUserOrTeamResult {\n const resolvedPrincipalId = (\n principalId ??\n providedUserGroupHeader?.ownerId ??\n ''\n ).toString()\n\n const { data: fetchedUserGroupHeader, isLoading } = useGetUserGroupHeader(\n resolvedPrincipalId,\n { enabled: !providedUserGroupHeader && !!resolvedPrincipalId },\n )\n\n const userGroupHeader = providedUserGroupHeader ?? fetchedUserGroupHeader\n\n const ownerId = userGroupHeader?.ownerId\n const isIndividual = userGroupHeader?.isIndividual\n const userName = userGroupHeader?.userName\n const firstName = userGroupHeader?.firstName\n\n const { data: realmPrincipals } = useGetRealmPrincipals()\n\n const specialGroupType: 'authenticatedUsers' | 'publicGroup' | null =\n isIndividual === false\n ? realmPrincipals?.authenticatedUsers === resolvedPrincipalId\n ? 'authenticatedUsers'\n : realmPrincipals?.publicGroup === resolvedPrincipalId\n ? 'publicGroup'\n : null\n : null\n\n const isPublicGroup = specialGroupType !== null\n\n const IconComponent = useMemo<\n React.ComponentType<{\n avatarSize?: AvatarSize\n }>\n >(() => {\n if (ownerId == null || isIndividual == null) return () => null\n\n if (isIndividual) {\n const syntheticProfile = {\n ownerId,\n userName,\n firstName,\n } as unknown as UserProfile\n return ({ avatarSize }: { avatarSize?: AvatarSize }) => (\n <UserAvatarIcon\n ownerId={ownerId}\n syntheticProfile={syntheticProfile}\n avatarSize={avatarSize}\n />\n )\n } else {\n return ({ avatarSize }: { avatarSize?: AvatarSize }) => (\n <TeamAvatarIcon\n ownerId={ownerId}\n isPublicGroup={isPublicGroup}\n avatarSize={avatarSize}\n />\n )\n }\n }, [ownerId, isIndividual, userName, firstName, isPublicGroup])\n\n return { userGroupHeader, isLoading, IconComponent, specialGroupType }\n}\n"],"mappings":";;;;;;;;;;;;AA+CA,SAAS,EAAe,EACtB,YACA,qBACA,gBAAa,WAKZ;CACD,IAAM,EAAE,MAAM,GAAM,iBAAc,EAAmB,EAAQ;AAE7D,QACE,kBAAC,GAAD;EACE,aAAa;EACH,UAJG,EAAoB,EAIvB;EACE;EACZ,iBAAiB;EACjB,iBAAiB;EACjB,CAAA;;AAIN,IAAM,IAA2C;CAC/C,OAAO;CACP,QAAQ;CACR,OAAO;CACR;AAED,SAAS,EAAe,EACtB,YACA,kBACA,gBAAa,WAKZ;CACD,IAAM,EAAE,MAAM,MAAS,EAAW,GAAS,EAAE,SAAS,CAAC,GAAe,CAAC,EAEjE,EAAE,SAAS,MACf,EACE;EACE,cAAc,GAAM,QAAQ;EAC5B,mBAAmB;EACnB,qBAAqB,EAAwB;EAC9C,EACD,IACA,EAAE,SAAS,CAAC,KAAiB,CAAC,CAAC,GAAM,MAAM,CAC5C,IAAI,EAAE,EAEH,IAAO,EAAa;AAe1B,QAbI,IACK,kBAAC,GAAD;EAAS,MAAK;EAAS,MAAM;EAAO,IAAI,EAAE,UAAU,GAAM;EAAI,CAAA,GAGnE,IAEA,kBAAC,GAAD;EACE,KAAK;EACL,IAAI;GAAE,OAAO;GAAM,QAAQ;GAAM,SAAS;GAAsB;EAChE,CAAA,GAIC,kBAAC,GAAD;EAAS,MAAK;EAAO,MAAM;EAAO,IAAI,EAAE,UAAU,GAAM;EAAI,CAAA;;AAcrE,SAAgB,EACd,GACA,GACqB;CACrB,IAAM,KACJ,KACA,GAAyB,WACzB,IACA,UAAU,EAEN,EAAE,MAAM,GAAwB,iBAAc,EAClD,GACA,EAAE,SAAS,CAAC,KAA2B,CAAC,CAAC,GAAqB,CAC/D,EAEK,IAAkB,KAA2B,GAE7C,IAAU,GAAiB,SAC3B,IAAe,GAAiB,cAChC,IAAW,GAAiB,UAC5B,IAAY,GAAiB,WAE7B,EAAE,MAAM,MAAoB,GAAuB,EAEnD,IACJ,MAAiB,KACb,GAAiB,uBAAuB,IACtC,uBACA,GAAiB,gBAAgB,IACjC,gBACA,OACF,MAEA,IAAgB,MAAqB;AAiC3C,QAAO;EAAE;EAAiB;EAAW,eA/Bf,QAId;AACN,OAAI,KAAW,QAAQ,KAAgB,KAAM,cAAa;AAE1D,OAAI,GAAc;IAChB,IAAM,IAAmB;KACvB;KACA;KACA;KACD;AACD,YAAQ,EAAE,oBACR,kBAAC,GAAD;KACW;KACS;KACN;KACZ,CAAA;SAGJ,SAAQ,EAAE,oBACR,kBAAC,GAAD;IACW;IACM;IACH;IACZ,CAAA;KAGL;GAAC;GAAS;GAAc;GAAU;GAAW;GAAc,CAEzB;EAAe;EAAkB"}
1
+ {"version":3,"file":"useUserOrTeam.js","names":[],"sources":["../../../src/components/UserOrTeamBadge/useUserOrTeam.tsx"],"sourcesContent":["import {\n useGetProfileImage,\n useGetStablePresignedUrl,\n} from '@/synapse-queries/file/useFiles'\nimport { useGetUserGroupHeader } from '@/synapse-queries/user/useUserGroupHeader'\nimport { useGetRealmPrincipals } from '@/synapse-queries/realm/useRealmPrincipals'\nimport { useGetTeam } from '@/synapse-queries/team/useTeam'\nimport { useCreateUrlForData } from '@/utils/hooks/usePreFetchResource'\nimport {\n FileHandleAssociateType,\n UserGroupHeader,\n UserProfile,\n} from '@sage-bionetworks/synapse-types'\nimport { Avatar as MUIAvatar } from '@mui/material'\nimport React, { useMemo } from 'react'\nimport { Avatar, AvatarSize } from '../UserCard/Avatar'\nimport IconSvg from '../IconSvg/IconSvg'\n\nexport type UseUserOrTeamResult = {\n /** The lightweight header for the resolved principal (user or team). Undefined while loading. */\n userGroupHeader: UserGroupHeader | undefined\n /** True while the `userGroupHeader` is being fetched. */\n isLoading: boolean\n /**\n * A stable React component that renders the icon for the resolved principal.\n *\n * - **Individual user**: renders an `Avatar` with the user's profile image, falling back to\n * colored initials when no image is available.\n * - **Regular team**: renders a team icon (`IconSvg icon=\"team\"`), or the team's custom image\n * when `Team.icon` (a file-handle ID) is set.\n * - **Public / authenticated-users group**: renders a globe icon (`IconSvg icon=\"public\"`).\n *\n * Accepts an optional `avatarSize` prop (`'SMALL' | 'MEDIUM' | 'LARGE'`, default `'SMALL'`)\n * for caller-controlled sizing. Returns `null` while the principal's identity has not yet\n * been resolved (i.e., while `isLoading` is true).\n */\n IconComponent: React.ComponentType<{ avatarSize?: AvatarSize }>\n /**\n * Identifies Synapse realm special groups.\n *\n * - `'authenticatedUsers'` — the principal is the \"All registered Synapse users\" group.\n * - `'publicGroup'` — the principal is the \"Anyone on the web\" group.\n * - `null` — the principal is an individual user, a regular team, or realm data is still loading.\n */\n specialGroupType: 'authenticatedUsers' | 'publicGroup' | null\n}\n\nfunction UserAvatarIcon({\n ownerId,\n syntheticProfile,\n avatarSize = 'SMALL',\n}: {\n ownerId: string\n syntheticProfile: UserProfile\n avatarSize?: AvatarSize\n}) {\n const { data: blob, isLoading } = useGetProfileImage(ownerId)\n const imageURL = useCreateUrlForData(blob)\n return (\n <Avatar\n userProfile={syntheticProfile}\n imageURL={imageURL}\n avatarSize={avatarSize}\n showCardOnHover={false}\n isLoadingAvatar={isLoading}\n />\n )\n}\n\nconst avatarSizePx: Record<AvatarSize, number> = {\n SMALL: 20,\n MEDIUM: 30,\n LARGE: 80,\n}\n\nfunction TeamAvatarIcon({\n ownerId,\n isPublicGroup,\n avatarSize = 'SMALL',\n}: {\n ownerId: string\n isPublicGroup: boolean\n avatarSize?: AvatarSize\n}) {\n const { data: team } = useGetTeam(ownerId, { enabled: !isPublicGroup })\n\n const { dataUrl: teamIconUrl } =\n useGetStablePresignedUrl(\n {\n fileHandleId: team?.icon ?? '',\n associateObjectId: ownerId,\n associateObjectType: FileHandleAssociateType.TeamAttachment,\n },\n false,\n { enabled: !isPublicGroup && !!team?.icon },\n ) ?? {}\n\n const size = avatarSizePx[avatarSize]\n\n if (isPublicGroup) {\n return <IconSvg icon=\"public\" wrap={false} sx={{ fontSize: size }} />\n }\n\n if (teamIconUrl) {\n return (\n <MUIAvatar\n src={teamIconUrl}\n sx={{ width: size, height: size, bgcolor: 'background.default' }}\n />\n )\n }\n\n return <IconSvg icon=\"team\" wrap={false} sx={{ fontSize: size }} />\n}\n\n/**\n * Resolves a Synapse principal (user or team) by ID and returns display data plus a\n * ready-to-render icon component.\n *\n * @param principalId - The numeric or string Synapse principal ID. If omitted, falls back to\n * `providedUserGroupHeader.ownerId`. Pass `undefined` when the ID is not yet known — the\n * hook will return `isLoading: false` with all fields undefined/null until an ID is provided.\n * @param providedUserGroupHeader - An already-fetched `UserGroupHeader`. When supplied, the\n * network fetch for the header is skipped entirely and this value is used directly. Useful\n * when the caller already has header data (e.g., from a list response).\n */\nexport function useUserOrTeam(\n principalId?: string | number,\n providedUserGroupHeader?: UserGroupHeader,\n): UseUserOrTeamResult {\n const resolvedPrincipalId = (\n principalId ??\n providedUserGroupHeader?.ownerId ??\n ''\n ).toString()\n\n const { data: fetchedUserGroupHeader, isLoading } = useGetUserGroupHeader(\n resolvedPrincipalId,\n { enabled: !providedUserGroupHeader && !!resolvedPrincipalId },\n )\n\n const userGroupHeader = providedUserGroupHeader ?? fetchedUserGroupHeader\n\n const ownerId = userGroupHeader?.ownerId\n const isIndividual = userGroupHeader?.isIndividual\n const userName = userGroupHeader?.userName\n const firstName = userGroupHeader?.firstName\n\n const { data: realmPrincipals } = useGetRealmPrincipals()\n\n const specialGroupType: 'authenticatedUsers' | 'publicGroup' | null =\n isIndividual === false\n ? realmPrincipals?.authenticatedUsers === resolvedPrincipalId\n ? 'authenticatedUsers'\n : realmPrincipals?.publicGroup === resolvedPrincipalId\n ? 'publicGroup'\n : null\n : null\n\n const isPublicGroup = specialGroupType !== null\n\n const IconComponent = useMemo<\n React.ComponentType<{\n avatarSize?: AvatarSize\n }>\n >(() => {\n if (ownerId == null || isIndividual == null) return () => null\n\n if (isIndividual) {\n const syntheticProfile = {\n ownerId,\n userName,\n firstName,\n } as unknown as UserProfile\n return ({ avatarSize }: { avatarSize?: AvatarSize }) => (\n <UserAvatarIcon\n ownerId={ownerId}\n syntheticProfile={syntheticProfile}\n avatarSize={avatarSize}\n />\n )\n } else {\n return ({ avatarSize }: { avatarSize?: AvatarSize }) => (\n <TeamAvatarIcon\n ownerId={ownerId}\n isPublicGroup={isPublicGroup}\n avatarSize={avatarSize}\n />\n )\n }\n }, [ownerId, isIndividual, userName, firstName, isPublicGroup])\n\n return { userGroupHeader, isLoading, IconComponent, specialGroupType }\n}\n"],"mappings":";;;;;;;;;;;;AA+CA,SAAS,EAAe,EACtB,YACA,qBACA,gBAAa,WAKZ;CACD,IAAM,EAAE,MAAM,GAAM,iBAAc,EAAmB,EAAQ;AAE7D,QACE,kBAAC,GAAD;EACE,aAAa;EACH,UAJG,EAAoB,EAIvB;EACE;EACZ,iBAAiB;EACjB,iBAAiB;EACjB,CAAA;;AAIN,IAAM,IAA2C;CAC/C,OAAO;CACP,QAAQ;CACR,OAAO;CACR;AAED,SAAS,EAAe,EACtB,YACA,kBACA,gBAAa,WAKZ;CACD,IAAM,EAAE,MAAM,MAAS,EAAW,GAAS,EAAE,SAAS,CAAC,GAAe,CAAC,EAEjE,EAAE,SAAS,MACf,EACE;EACE,cAAc,GAAM,QAAQ;EAC5B,mBAAmB;EACnB,qBAAqB,EAAwB;EAC9C,EACD,IACA,EAAE,SAAS,CAAC,KAAiB,CAAC,CAAC,GAAM,MAAM,CAC5C,IAAI,EAAE,EAEH,IAAO,EAAa;AAe1B,QAbI,IACK,kBAAC,GAAD;EAAS,MAAK;EAAS,MAAM;EAAO,IAAI,EAAE,UAAU,GAAM;EAAI,CAAA,GAGnE,IAEA,kBAAC,GAAD;EACE,KAAK;EACL,IAAI;GAAE,OAAO;GAAM,QAAQ;GAAM,SAAS;GAAsB;EAChE,CAAA,GAIC,kBAAC,GAAD;EAAS,MAAK;EAAO,MAAM;EAAO,IAAI,EAAE,UAAU,GAAM;EAAI,CAAA;;AAcrE,SAAgB,EACd,GACA,GACqB;CACrB,IAAM,KACJ,KACA,GAAyB,WACzB,IACA,UAAU,EAEN,EAAE,MAAM,GAAwB,iBAAc,EAClD,GACA,EAAE,SAAS,CAAC,KAA2B,CAAC,CAAC,GAAqB,CAC/D,EAEK,IAAkB,KAA2B,GAE7C,IAAU,GAAiB,SAC3B,IAAe,GAAiB,cAChC,IAAW,GAAiB,UAC5B,IAAY,GAAiB,WAE7B,EAAE,MAAM,MAAoB,GAAuB,EAEnD,IACJ,MAAiB,KACb,GAAiB,uBAAuB,IACtC,uBACA,GAAiB,gBAAgB,IAC/B,gBACA,OACJ,MAEA,IAAgB,MAAqB;AAiC3C,QAAO;EAAE;EAAiB;EAAW,eA/Bf,QAId;AACN,OAAI,KAAW,QAAQ,KAAgB,KAAM,cAAa;AAE1D,OAAI,GAAc;IAChB,IAAM,IAAmB;KACvB;KACA;KACA;KACD;AACD,YAAQ,EAAE,oBACR,kBAAC,GAAD;KACW;KACS;KACN;KACZ,CAAA;SAGJ,SAAQ,EAAE,oBACR,kBAAC,GAAD;IACW;IACM;IACH;IACZ,CAAA;KAGL;GAAC;GAAS;GAAc;GAAU;GAAW;GAAc,CAEzB;EAAe;EAAkB"}
@@ -1 +1 @@
1
- {"version":3,"file":"UserSearchBox.d.ts","sourceRoot":"","sources":["../../../src/components/UserSearchBox/UserSearchBox.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AAI9E,MAAM,MAAM,kBAAkB,GAAG;IAE/B,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,CACT,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,MAAM,EAAE,eAAe,GAAG,IAAI,KAC3B,IAAI,CAAA;IACT,UAAU,CAAC,EAAE,WAAW,CAAA;IACxB,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,OAAO,CAAA;IACpD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACtB,CAAA;AAED;;GAEG;AACH,iBAAS,aAAa,CAAC,KAAK,EAAE,kBAAkB,2CAmL/C;AAED,eAAe,aAAa,CAAA"}
1
+ {"version":3,"file":"UserSearchBox.d.ts","sourceRoot":"","sources":["../../../src/components/UserSearchBox/UserSearchBox.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AAI9E,MAAM,MAAM,kBAAkB,GAAG;IAE/B,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,CACT,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,MAAM,EAAE,eAAe,GAAG,IAAI,KAC3B,IAAI,CAAA;IACT,UAAU,CAAC,EAAE,WAAW,CAAA;IACxB,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,OAAO,CAAA;IACpD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACtB,CAAA;AAED;;GAEG;AACH,iBAAS,aAAa,CAAC,KAAK,EAAE,kBAAkB,2CAqL/C;AAED,eAAe,aAAa,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"UserSearchBox.js","names":[],"sources":["../../../src/components/UserSearchBox/UserSearchBox.tsx"],"sourcesContent":["import {\n useGetUserGroupHeader,\n useSearchUserGroupHeaders,\n} from '@/synapse-queries'\nimport { useDebouncedEffect } from '@/utils/hooks/useDebouncedEffect'\nimport { Autocomplete, Box, Skeleton, TextField } from '@mui/material'\nimport { TYPE_FILTER, UserGroupHeader } from '@sage-bionetworks/synapse-types'\nimport { useMemo, useState } from 'react'\nimport UserOrTeamBadge from '../UserOrTeamBadge/UserOrTeamBadge'\n\nexport type UserSearchBoxProps = {\n /* id for the input element, for associating with a <label> */\n inputId?: string\n /* The initial principal ID (uncontrolled). Ignored if `value` is provided. */\n defaultValue?: string\n onChange?: (\n principalId: string | null,\n header: UserGroupHeader | null,\n ) => void\n typeFilter?: TYPE_FILTER\n filterPredicate?: (item: UserGroupHeader) => boolean\n placeholder?: string\n autoFocus?: boolean\n /**\n * The principal ID of the currently selected user or team.\n * - `undefined`: uncontrolled — the component manages its own selection state\n * - `null`: controlled with no selection (clears the field)\n * - string: controlled with the given principal ID selected\n */\n value?: string | null\n}\n\n/**\n * Autocomplete component used to search for and select a user or team.\n */\nfunction UserSearchBox(props: UserSearchBoxProps) {\n const {\n inputId,\n defaultValue = null,\n onChange,\n filterPredicate,\n typeFilter,\n placeholder,\n autoFocus = false,\n value: valueProp,\n } = props\n\n const isControlled = valueProp !== undefined\n\n const [inputValue, setInputValue] = useState('')\n const [debouncedInput, setDebouncedInput] = useState('')\n useDebouncedEffect(\n () => {\n setDebouncedInput(inputValue)\n },\n [inputValue],\n 500,\n )\n\n // Tracks whether the dropdown is open, used to toggle between badge display\n // and text-input search mode.\n const [isSearching, setIsSearching] = useState(false)\n\n // Resolve defaultValue principalId → UserGroupHeader for the initial uncontrolled state\n const { data: defaultUserGroupHeader, isLoading: isLoadingDefaultValue } =\n useGetUserGroupHeader(defaultValue ?? '', {\n enabled: !!defaultValue && !isControlled,\n })\n\n // Resolve controlled string principalId → UserGroupHeader\n const controlledPrincipalId =\n isControlled && typeof valueProp === 'string' ? valueProp : null\n\n const {\n data: resolvedControlledHeader,\n isLoading: isLoadingControlledValue,\n } = useGetUserGroupHeader(controlledPrincipalId ?? '', {\n enabled: !!controlledPrincipalId,\n })\n\n // Internal state for uncontrolled mode.\n // undefined = user hasn't interacted yet → falls back to defaultUserGroupHeader\n // null = user explicitly cleared the selection\n // header = user's current selection\n const [internalValue, setInternalValue] = useState<\n UserGroupHeader | null | undefined\n >(undefined)\n\n const controlledValue =\n typeof valueProp === 'string' ? resolvedControlledHeader ?? null : null\n const uncontrolledValue =\n internalValue !== undefined ? internalValue : defaultUserGroupHeader ?? null\n const resolvedValue: UserGroupHeader | null = isControlled\n ? controlledValue\n : uncontrolledValue\n\n // Show the badge in the input field when a value is selected and the user\n // is not actively searching.\n const showBadge = resolvedValue !== null && !isSearching\n\n const isSearchEnabled = !!debouncedInput\n const { data, isLoading } = useSearchUserGroupHeaders(\n debouncedInput,\n typeFilter,\n {\n enabled: isSearchEnabled,\n },\n )\n\n const options = useMemo(\n () => (data ?? []).filter(filterPredicate ?? (() => true)),\n [data, filterPredicate],\n )\n\n const placeholderText = useMemo(() => {\n if (placeholder !== undefined) {\n return placeholder\n } else if (typeFilter == TYPE_FILTER.USERS_ONLY) {\n return 'Name (first and last)'\n } else if (typeFilter == TYPE_FILTER.TEAMS_ONLY) {\n return 'Team name'\n } else {\n return 'Name (first and last) or team name'\n }\n }, [placeholder, typeFilter])\n\n if (isLoadingDefaultValue || isLoadingControlledValue) {\n return <Skeleton width=\"100%\" />\n }\n\n return (\n <Autocomplete<UserGroupHeader, false, false, false>\n id={inputId}\n value={resolvedValue}\n inputValue={inputValue}\n onInputChange={(_event, newInputValue, reason) => {\n if (reason === 'selectOption' || reason === 'reset') {\n // After an option is selected/removed, clear the input text so it's ready for the next search.\n setInputValue('')\n } else {\n setInputValue(newInputValue)\n }\n }}\n // When a value is selected, clicking the badge area should re-open the search.\n openOnFocus={resolvedValue !== null}\n onOpen={() => {\n setIsSearching(true)\n }}\n onClose={() => setIsSearching(false)}\n options={options}\n filterOptions={x => x}\n loading={isLoading || inputValue !== debouncedInput}\n isOptionEqualToValue={(option, val) => option.ownerId === val.ownerId}\n getOptionLabel={option => option.userName}\n renderOption={(optionProps, option) => (\n <li {...optionProps} key={option.ownerId}>\n <UserOrTeamBadge\n userGroupHeader={option}\n disableHref\n showFullName\n showCardOnHover={false}\n />\n </li>\n )}\n renderInput={({\n inputProps: inputPropsFromParams,\n InputProps: InputPropsFromParams,\n ...params\n }) => (\n <TextField\n {...params}\n placeholder={showBadge ? undefined : placeholderText}\n autoFocus={autoFocus}\n slotProps={{\n htmlInput: {\n ...inputPropsFromParams,\n // While the badge is displayed, hide the underlying input text and cursor.\n // Merge custom styles with parent styles to preserve mouse selection and other behaviors.\n style: {\n ...inputPropsFromParams.style,\n ...(showBadge ? { color: 'transparent' } : {}),\n },\n },\n input: {\n ...InputPropsFromParams,\n startAdornment: showBadge ? (\n <Box sx={{ ml: 1 }}>\n <UserOrTeamBadge\n userGroupHeader={resolvedValue}\n disableHref\n showFullName\n showCardOnHover={false}\n />\n </Box>\n ) : undefined,\n },\n }}\n />\n )}\n onChange={(_event, newValue) => {\n if (!isControlled) {\n setInternalValue(newValue)\n }\n onChange?.(\n newValue?.ownerId != null ? newValue.ownerId.toString() : null,\n newValue ?? null,\n )\n }}\n noOptionsText={\n isLoading || inputValue !== debouncedInput ? 'Loading…' : 'No options'\n }\n clearOnEscape\n />\n )\n}\n\nexport default UserSearchBox\n"],"mappings":";;;;;;;;;AAmCA,SAAS,EAAc,GAA2B;CAChD,IAAM,EACJ,YACA,kBAAe,MACf,aACA,oBACA,eACA,gBACA,eAAY,IACZ,OAAO,MACL,GAEE,IAAe,MAAc,KAAA,GAE7B,CAAC,GAAY,KAAiB,EAAS,GAAG,EAC1C,CAAC,GAAgB,KAAqB,EAAS,GAAG;AACxD,SACQ;AACJ,IAAkB,EAAW;IAE/B,CAAC,EAAW,EACZ,IACD;CAID,IAAM,CAAC,GAAa,KAAkB,EAAS,GAAM,EAG/C,EAAE,MAAM,GAAwB,WAAW,MAC/C,EAAsB,KAAgB,IAAI,EACxC,SAAS,CAAC,CAAC,KAAgB,CAAC,GAC7B,CAAC,EAGE,IACJ,KAAgB,OAAO,KAAc,WAAW,IAAY,MAExD,EACJ,MAAM,GACN,WAAW,MACT,EAAsB,KAAyB,IAAI,EACrD,SAAS,CAAC,CAAC,GACZ,CAAC,EAMI,CAAC,GAAe,KAAoB,EAExC,KAAA,EAAU,EAMN,IAAwC,IAH5C,OAAO,KAAc,WAAW,KAA4B,OAAO,OAEnE,MAAkB,KAAA,IAA4B,KAA0B,OAA1C,GAO1B,IAAY,MAAkB,QAAQ,CAAC,GAGvC,EAAE,SAAM,iBAAc,EAC1B,GACA,GACA,EACE,SAAS,CALY,CAAC,GAMvB,CACF,EAEK,IAAU,SACP,KAAQ,EAAE,EAAE,OAAO,YAA0B,IAAM,EAC1D,CAAC,GAAM,EAAgB,CACxB,EAEK,IAAkB,QAClB,MAAgB,KAAA,IAET,KAAc,EAAY,aAC5B,0BACE,KAAc,EAAY,aAC5B,cAEA,uCANA,GAQR,CAAC,GAAa,EAAW,CAAC;AAM7B,QAJI,KAAyB,IACpB,kBAAC,GAAD,EAAU,OAAM,QAAS,CAAA,GAIhC,kBAAC,GAAD;EACE,IAAI;EACJ,OAAO;EACK;EACZ,gBAAgB,GAAQ,GAAe,MAAW;AAChD,GAEE,EAFE,MAAW,kBAAkB,MAAW,UAE5B,KAEA,EAAc;;EAIhC,aAAa,MAAkB;EAC/B,cAAc;AACZ,KAAe,GAAK;;EAEtB,eAAe,EAAe,GAAM;EAC3B;EACT,gBAAe,MAAK;EACpB,SAAS,KAAa,MAAe;EACrC,uBAAuB,GAAQ,MAAQ,EAAO,YAAY,EAAI;EAC9D,iBAAgB,MAAU,EAAO;EACjC,eAAe,GAAa,MAC1B,kBAAC,MAAD;GAAI,GAAI;GAAa,KAAK,EAAO;GAO5B,EANH,kBAAC,GAAD;GACE,iBAAiB;GACjB,aAAA;GACA,cAAA;GACA,iBAAiB;GACjB,CAAA,CACC;EAEP,cAAc,EACZ,YAAY,GACZ,YAAY,GACZ,GAAG,QAEH,kBAAC,GAAD;GACE,GAAI;GACJ,aAAa,IAAY,KAAA,IAAY;GAC1B;GACX,WAAW;IACT,WAAW;KACT,GAAG;KAGH,OAAO;MACL,GAAG,EAAqB;MACxB,GAAI,IAAY,EAAE,OAAO,eAAe,GAAG,EAAE;MAC9C;KACF;IACD,OAAO;KACL,GAAG;KACH,gBAAgB,IACd,kBAAC,GAAD;MAAK,IAAI,EAAE,IAAI,GAAG;gBAChB,kBAAC,GAAD;OACE,iBAAiB;OACjB,aAAA;OACA,cAAA;OACA,iBAAiB;OACjB,CAAA;MACE,CAAA,GACJ,KAAA;KACL;IACF;GACD,CAAA;EAEJ,WAAW,GAAQ,MAAa;AAI9B,GAHK,KACH,EAAiB,EAAS,EAE5B,IACE,GAAU,WAAW,OAAqC,OAA9B,EAAS,QAAQ,UAAU,EACvD,KAAY,KACb;;EAEH,eACE,KAAa,MAAe,IAAiB,aAAa;EAE5D,eAAA;EACA,CAAA"}
1
+ {"version":3,"file":"UserSearchBox.js","names":[],"sources":["../../../src/components/UserSearchBox/UserSearchBox.tsx"],"sourcesContent":["import {\n useGetUserGroupHeader,\n useSearchUserGroupHeaders,\n} from '@/synapse-queries'\nimport { useDebouncedEffect } from '@/utils/hooks/useDebouncedEffect'\nimport { Autocomplete, Box, Skeleton, TextField } from '@mui/material'\nimport { TYPE_FILTER, UserGroupHeader } from '@sage-bionetworks/synapse-types'\nimport { useMemo, useState } from 'react'\nimport UserOrTeamBadge from '../UserOrTeamBadge/UserOrTeamBadge'\n\nexport type UserSearchBoxProps = {\n /* id for the input element, for associating with a <label> */\n inputId?: string\n /* The initial principal ID (uncontrolled). Ignored if `value` is provided. */\n defaultValue?: string\n onChange?: (\n principalId: string | null,\n header: UserGroupHeader | null,\n ) => void\n typeFilter?: TYPE_FILTER\n filterPredicate?: (item: UserGroupHeader) => boolean\n placeholder?: string\n autoFocus?: boolean\n /**\n * The principal ID of the currently selected user or team.\n * - `undefined`: uncontrolled — the component manages its own selection state\n * - `null`: controlled with no selection (clears the field)\n * - string: controlled with the given principal ID selected\n */\n value?: string | null\n}\n\n/**\n * Autocomplete component used to search for and select a user or team.\n */\nfunction UserSearchBox(props: UserSearchBoxProps) {\n const {\n inputId,\n defaultValue = null,\n onChange,\n filterPredicate,\n typeFilter,\n placeholder,\n autoFocus = false,\n value: valueProp,\n } = props\n\n const isControlled = valueProp !== undefined\n\n const [inputValue, setInputValue] = useState('')\n const [debouncedInput, setDebouncedInput] = useState('')\n useDebouncedEffect(\n () => {\n setDebouncedInput(inputValue)\n },\n [inputValue],\n 500,\n )\n\n // Tracks whether the dropdown is open, used to toggle between badge display\n // and text-input search mode.\n const [isSearching, setIsSearching] = useState(false)\n\n // Resolve defaultValue principalId → UserGroupHeader for the initial uncontrolled state\n const { data: defaultUserGroupHeader, isLoading: isLoadingDefaultValue } =\n useGetUserGroupHeader(defaultValue ?? '', {\n enabled: !!defaultValue && !isControlled,\n })\n\n // Resolve controlled string principalId → UserGroupHeader\n const controlledPrincipalId =\n isControlled && typeof valueProp === 'string' ? valueProp : null\n\n const {\n data: resolvedControlledHeader,\n isLoading: isLoadingControlledValue,\n } = useGetUserGroupHeader(controlledPrincipalId ?? '', {\n enabled: !!controlledPrincipalId,\n })\n\n // Internal state for uncontrolled mode.\n // undefined = user hasn't interacted yet → falls back to defaultUserGroupHeader\n // null = user explicitly cleared the selection\n // header = user's current selection\n const [internalValue, setInternalValue] = useState<\n UserGroupHeader | null | undefined\n >(undefined)\n\n const controlledValue =\n typeof valueProp === 'string' ? (resolvedControlledHeader ?? null) : null\n const uncontrolledValue =\n internalValue !== undefined\n ? internalValue\n : (defaultUserGroupHeader ?? null)\n const resolvedValue: UserGroupHeader | null = isControlled\n ? controlledValue\n : uncontrolledValue\n\n // Show the badge in the input field when a value is selected and the user\n // is not actively searching.\n const showBadge = resolvedValue !== null && !isSearching\n\n const isSearchEnabled = !!debouncedInput\n const { data, isLoading } = useSearchUserGroupHeaders(\n debouncedInput,\n typeFilter,\n {\n enabled: isSearchEnabled,\n },\n )\n\n const options = useMemo(\n () => (data ?? []).filter(filterPredicate ?? (() => true)),\n [data, filterPredicate],\n )\n\n const placeholderText = useMemo(() => {\n if (placeholder !== undefined) {\n return placeholder\n } else if (typeFilter == TYPE_FILTER.USERS_ONLY) {\n return 'Name (first and last)'\n } else if (typeFilter == TYPE_FILTER.TEAMS_ONLY) {\n return 'Team name'\n } else {\n return 'Name (first and last) or team name'\n }\n }, [placeholder, typeFilter])\n\n if (isLoadingDefaultValue || isLoadingControlledValue) {\n return <Skeleton width=\"100%\" />\n }\n\n return (\n <Autocomplete<UserGroupHeader, false, false, false>\n id={inputId}\n value={resolvedValue}\n inputValue={inputValue}\n onInputChange={(_event, newInputValue, reason) => {\n if (reason === 'selectOption' || reason === 'reset') {\n // After an option is selected/removed, clear the input text so it's ready for the next search.\n setInputValue('')\n } else {\n setInputValue(newInputValue)\n }\n }}\n // When a value is selected, clicking the badge area should re-open the search.\n openOnFocus={resolvedValue !== null}\n onOpen={() => {\n setIsSearching(true)\n }}\n onClose={() => setIsSearching(false)}\n options={options}\n filterOptions={x => x}\n loading={isLoading || inputValue !== debouncedInput}\n isOptionEqualToValue={(option, val) => option.ownerId === val.ownerId}\n getOptionLabel={option => option.userName}\n renderOption={(optionProps, option) => (\n <li {...optionProps} key={option.ownerId}>\n <UserOrTeamBadge\n userGroupHeader={option}\n disableHref\n showFullName\n showCardOnHover={false}\n />\n </li>\n )}\n renderInput={({\n inputProps: inputPropsFromParams,\n InputProps: InputPropsFromParams,\n ...params\n }) => (\n <TextField\n {...params}\n placeholder={showBadge ? undefined : placeholderText}\n autoFocus={autoFocus}\n slotProps={{\n htmlInput: {\n ...inputPropsFromParams,\n // While the badge is displayed, hide the underlying input text and cursor.\n // Merge custom styles with parent styles to preserve mouse selection and other behaviors.\n style: {\n ...inputPropsFromParams.style,\n ...(showBadge ? { color: 'transparent' } : {}),\n },\n },\n input: {\n ...InputPropsFromParams,\n startAdornment: showBadge ? (\n <Box sx={{ ml: 1 }}>\n <UserOrTeamBadge\n userGroupHeader={resolvedValue}\n disableHref\n showFullName\n showCardOnHover={false}\n />\n </Box>\n ) : undefined,\n },\n }}\n />\n )}\n onChange={(_event, newValue) => {\n if (!isControlled) {\n setInternalValue(newValue)\n }\n onChange?.(\n newValue?.ownerId != null ? newValue.ownerId.toString() : null,\n newValue ?? null,\n )\n }}\n noOptionsText={\n isLoading || inputValue !== debouncedInput ? 'Loading…' : 'No options'\n }\n clearOnEscape\n />\n )\n}\n\nexport default UserSearchBox\n"],"mappings":";;;;;;;;;AAmCA,SAAS,EAAc,GAA2B;CAChD,IAAM,EACJ,YACA,kBAAe,MACf,aACA,oBACA,eACA,gBACA,eAAY,IACZ,OAAO,MACL,GAEE,IAAe,MAAc,KAAA,GAE7B,CAAC,GAAY,KAAiB,EAAS,GAAG,EAC1C,CAAC,GAAgB,KAAqB,EAAS,GAAG;AACxD,SACQ;AACJ,IAAkB,EAAW;IAE/B,CAAC,EAAW,EACZ,IACD;CAID,IAAM,CAAC,GAAa,KAAkB,EAAS,GAAM,EAG/C,EAAE,MAAM,GAAwB,WAAW,MAC/C,EAAsB,KAAgB,IAAI,EACxC,SAAS,CAAC,CAAC,KAAgB,CAAC,GAC7B,CAAC,EAGE,IACJ,KAAgB,OAAO,KAAc,WAAW,IAAY,MAExD,EACJ,MAAM,GACN,WAAW,MACT,EAAsB,KAAyB,IAAI,EACrD,SAAS,CAAC,CAAC,GACZ,CAAC,EAMI,CAAC,GAAe,KAAoB,EAExC,KAAA,EAAU,EAQN,IAAwC,IAL5C,OAAO,KAAc,WAAY,KAA4B,OAAQ,OAErE,MAAkB,KAAA,IAEb,KAA0B,OAD3B,GAQA,IAAY,MAAkB,QAAQ,CAAC,GAGvC,EAAE,SAAM,iBAAc,EAC1B,GACA,GACA,EACE,SAAS,CALY,CAAC,GAMvB,CACF,EAEK,IAAU,SACP,KAAQ,EAAE,EAAE,OAAO,YAA0B,IAAM,EAC1D,CAAC,GAAM,EAAgB,CACxB,EAEK,IAAkB,QAClB,MAAgB,KAAA,IAET,KAAc,EAAY,aAC5B,0BACE,KAAc,EAAY,aAC5B,cAEA,uCANA,GAQR,CAAC,GAAa,EAAW,CAAC;AAM7B,QAJI,KAAyB,IACpB,kBAAC,GAAD,EAAU,OAAM,QAAS,CAAA,GAIhC,kBAAC,GAAD;EACE,IAAI;EACJ,OAAO;EACK;EACZ,gBAAgB,GAAQ,GAAe,MAAW;AAChD,GAEE,EAFE,MAAW,kBAAkB,MAAW,UAE5B,KAEA,EAAc;;EAIhC,aAAa,MAAkB;EAC/B,cAAc;AACZ,KAAe,GAAK;;EAEtB,eAAe,EAAe,GAAM;EAC3B;EACT,gBAAe,MAAK;EACpB,SAAS,KAAa,MAAe;EACrC,uBAAuB,GAAQ,MAAQ,EAAO,YAAY,EAAI;EAC9D,iBAAgB,MAAU,EAAO;EACjC,eAAe,GAAa,MAC1B,kBAAC,MAAD;GAAI,GAAI;GAAa,KAAK,EAAO;GAO5B,EANH,kBAAC,GAAD;GACE,iBAAiB;GACjB,aAAA;GACA,cAAA;GACA,iBAAiB;GACjB,CAAA,CACC;EAEP,cAAc,EACZ,YAAY,GACZ,YAAY,GACZ,GAAG,QAEH,kBAAC,GAAD;GACE,GAAI;GACJ,aAAa,IAAY,KAAA,IAAY;GAC1B;GACX,WAAW;IACT,WAAW;KACT,GAAG;KAGH,OAAO;MACL,GAAG,EAAqB;MACxB,GAAI,IAAY,EAAE,OAAO,eAAe,GAAG,EAAE;MAC9C;KACF;IACD,OAAO;KACL,GAAG;KACH,gBAAgB,IACd,kBAAC,GAAD;MAAK,IAAI,EAAE,IAAI,GAAG;gBAChB,kBAAC,GAAD;OACE,iBAAiB;OACjB,aAAA;OACA,cAAA;OACA,iBAAiB;OACjB,CAAA;MACE,CAAA,GACJ,KAAA;KACL;IACF;GACD,CAAA;EAEJ,WAAW,GAAQ,MAAa;AAI9B,GAHK,KACH,EAAiB,EAAS,EAE5B,IACE,GAAU,WAAW,OAAqC,OAA9B,EAAS,QAAQ,UAAU,EACvD,KAAY,KACb;;EAEH,eACE,KAAa,MAAe,IAAiB,aAAa;EAE5D,eAAA;EACA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"WikiMarkdownEditorButton.js","names":[],"sources":["../../../src/components/WikiMarkdownEditorButton/WikiMarkdownEditorButton.tsx"],"sourcesContent":["import {\n CreateWikiPageInput,\n useCreateWikiPage,\n useGetRootWikiPageKey,\n useGetWikiPage,\n} from '@/synapse-queries'\nimport { Alert, Box, Button, ButtonProps } from '@mui/material'\nimport { ObjectType, WikiPageKey } from '@sage-bionetworks/synapse-types'\nimport { defaults } from 'lodash-es'\nimport { useMemo, useState } from 'react'\nimport { SynapseSpinner } from '../LoadingScreen/LoadingScreen'\nimport MarkdownSynapse, {\n MarkdownSynapseProps,\n} from '../Markdown/MarkdownSynapse'\nimport WikiMarkdownEditor from '../WikiMarkdownEditor/WikiMarkdownEditor'\n\nexport const ERROR_LOADING_WIKI_FAILED = 'Failed to load the wiki page: '\nexport const DEFAULT_BUTTON_TEXT = 'Edit Wiki Page'\nconst DEFAULT_BUTTON_PROPS: Omit<ButtonProps, 'onClick'> = {\n children: DEFAULT_BUTTON_TEXT,\n color: 'primary',\n variant: 'contained',\n}\n\nexport type WikiMarkdownEditorButtonProps = {\n ownerObjectType: ObjectType\n ownerObjectId: string\n // if wikiPageId is undefined, will get (or create) the root WikiPage for this ownerObject\n // otherwise, will get the WikiPage with the specified wikiPageId\n wikiPageId?: string\n buttonProps?: Omit<ButtonProps, 'onClick' | 'disabled'>\n displayWikiMarkdown?: boolean\n}\n\nexport function WikiMarkdownEditorButton(props: WikiMarkdownEditorButtonProps) {\n const {\n ownerObjectType,\n ownerObjectId,\n wikiPageId: initialWikiPageId,\n displayWikiMarkdown = false,\n } = props\n\n const buttonProps: Omit<ButtonProps, 'onClick' | 'disabled'> = defaults(\n {},\n props.buttonProps,\n DEFAULT_BUTTON_PROPS,\n )\n\n const [open, setOpen] = useState<boolean>(false)\n\n const {\n data: rootWikiPageKey,\n isLoading: isLoadingRootWikiPageKey,\n error: errorLoadingRootWikiPageKey,\n } = useGetRootWikiPageKey(ownerObjectType, ownerObjectId, {\n enabled: initialWikiPageId === undefined,\n })\n\n const {\n mutate: createWikiPage,\n isPending: isCreatingWikiPage,\n error: errorCreatingWikiPage,\n } = useCreateWikiPage({\n onSuccess: () => setOpen(true),\n })\n\n const wikiPageKey = useMemo(() => {\n const wikiPageId = initialWikiPageId || rootWikiPageKey?.wikiPageId || ''\n const wikiPageKey: WikiPageKey = {\n ownerObjectType,\n ownerObjectId,\n wikiPageId: wikiPageId,\n }\n return wikiPageKey\n }, [initialWikiPageId, rootWikiPageKey, ownerObjectId, ownerObjectType])\n\n const {\n data: wikiPage,\n isLoading: isLoadingWikiPage,\n error: errorLoadingWikiPage,\n } = useGetWikiPage(wikiPageKey, {\n enabled: wikiPageKey.wikiPageId !== '',\n // Set staleTime to infinity to prevent re-fetching while editing\n staleTime: Infinity,\n })\n\n const error = useMemo(() => {\n if (errorLoadingRootWikiPageKey) {\n return ERROR_LOADING_WIKI_FAILED + errorLoadingRootWikiPageKey.reason\n }\n if (errorLoadingWikiPage) {\n return ERROR_LOADING_WIKI_FAILED + errorLoadingWikiPage.reason\n }\n if (errorCreatingWikiPage) {\n return errorCreatingWikiPage.reason\n }\n return null\n }, [errorLoadingRootWikiPageKey, errorLoadingWikiPage, errorCreatingWikiPage])\n\n const handleClick = () => {\n if (wikiPage) {\n setOpen(true)\n } else if (rootWikiPageKey === null) {\n // root WikiPageKey was not found,\n // then create a root WikiPage for this ownerObject\n const rootWikiPage: CreateWikiPageInput['wikiPage'] = {\n parentWikiId: undefined,\n title: '',\n markdown: '',\n attachmentFileHandleIds: [],\n }\n const input: CreateWikiPageInput = {\n ownerObjectId,\n ownerObjectType,\n wikiPage: rootWikiPage,\n }\n createWikiPage(input)\n } else {\n // Should only reach this block if there was:\n // - a non-404 error fetching the root WikiPageKey\n // - an error fetching a specific wikiPage\n // Otherwise the button should be disabled.\n console.warn(\n 'There was an error fetching the root WikiPageKey or WikiPage - address that error first.',\n )\n }\n }\n\n /* TODO - pass ownerId, objectType, wikiId directly to MarkdownSynapse after \n MarkdownSynapse is updated to fetch root WikiPages for ACCESS_REQUIREMENT object types.\n See https://sagebionetworks.jira.com/browse/SWC-6791. */\n const markdownSynapseProps = useMemo(() => {\n const markdownSynapseProps: MarkdownSynapseProps = {\n showPlaceholderIfNoWikiContent: true,\n }\n if (wikiPage) {\n return {\n ...markdownSynapseProps,\n ownerId: ownerObjectId,\n objectType: ownerObjectType,\n wikiId: wikiPage.id,\n }\n } else {\n // use a placeholder value for markdown so that MarkdownSynapse\n // displays no content placeholder for owners without root wiki pages\n return { ...markdownSynapseProps, markdown: '' }\n }\n }, [ownerObjectId, ownerObjectType, wikiPage])\n\n return (\n <>\n {displayWikiMarkdown && (\n <Box\n sx={{\n mb: 1,\n }}\n >\n {isLoadingWikiPage || isLoadingRootWikiPageKey ? (\n <SynapseSpinner />\n ) : (\n // TODO - remove key once MarkdownSynapse uses tanstack-query\n <MarkdownSynapse\n key={wikiPage?.markdown}\n {...markdownSynapseProps}\n />\n )}\n </Box>\n )}\n <Button\n onClick={handleClick}\n disabled={\n isLoadingWikiPage || isLoadingRootWikiPageKey || isCreatingWikiPage\n }\n {...buttonProps}\n />\n {error && (\n <Alert severity=\"error\" sx={{ marginTop: 2 }}>\n {error}\n </Alert>\n )}\n {wikiPage && (\n <WikiMarkdownEditor\n // Specify a key so that uncommitted changes in WikiMarkdownEditor\n // are not displayed when editor is re-opened\n key={open.toString()}\n open={open}\n ownerObjectType={ownerObjectType}\n ownerObjectId={ownerObjectId}\n wikiPage={wikiPage}\n onSave={() => setOpen(false)}\n onCancel={() => setOpen(false)}\n />\n )}\n </>\n )\n}\n\nexport default WikiMarkdownEditorButton\n"],"mappings":";;;;;;;;;;AAgBA,IAAa,IAA4B,kCAC5B,IAAsB,kBAC7B,IAAqD;CACzD,UAAU;CACV,OAAO;CACP,SAAS;CACV;AAYD,SAAgB,EAAyB,GAAsC;CAC7E,IAAM,EACJ,oBACA,kBACA,YAAY,GACZ,yBAAsB,OACpB,GAEE,IAAyD,EAC7D,EAAE,EACF,EAAM,aACN,EACD,EAEK,CAAC,GAAM,KAAW,EAAkB,GAAM,EAE1C,EACJ,MAAM,GACN,WAAW,GACX,OAAO,MACL,EAAsB,GAAiB,GAAe,EACxD,SAAS,MAAsB,KAAA,GAChC,CAAC,EAEI,EACJ,QAAQ,GACR,WAAW,GACX,OAAO,MACL,EAAkB,EACpB,iBAAiB,EAAQ,GAAK,EAC/B,CAAC,EAEI,IAAc,SAOX;EAJL;EACA;EACY,YAJK,KAAqB,GAAiB,cAAc;EAMhE,GACN;EAAC;EAAmB;EAAiB;EAAe;EAAgB,CAAC,EAElE,EACJ,MAAM,GACN,WAAW,GACX,OAAO,MACL,EAAe,GAAa;EAC9B,SAAS,EAAY,eAAe;EAEpC,WAAW;EACZ,CAAC,EAEI,IAAQ,QACR,IACK,IAA4B,EAA4B,SAE7D,IACK,IAA4B,EAAqB,SAEtD,IACK,EAAsB,SAExB,MACN;EAAC;EAA6B;EAAsB;EAAsB,CAAC,EAExE,UAAoB;AACxB,EAAI,IACF,EAAQ,GAAK,GACJ,MAAoB,OAc7B,EAAe;GAJb;GACA;GACA,UAAU;IARV,cAAc,KAAA;IACd,OAAO;IACP,UAAU;IACV,yBAAyB,EAAE;IAKjB;GAEG,CAAM,GAMrB,QAAQ,KACN,2FACD;IAOC,IAAuB,QAAc;EACzC,IAAM,IAA6C,EACjD,gCAAgC,IACjC;AAWC,SAVE,IACK;GACL,GAAG;GACH,SAAS;GACT,YAAY;GACZ,QAAQ,EAAS;GAClB,GAIM;GAAE,GAAG;GAAsB,UAAU;GAAI;IAEjD;EAAC;EAAe;EAAiB;EAAS,CAAC;AAE9C,QACE,kBAAA,GAAA,EAAA,UAAA;EACG,KACC,kBAAC,GAAD;GACE,IAAI,EACF,IAAI,GACL;aAEA,KAAqB,IACpB,kBAAC,GAAD,EAAkB,CAAA,GAGlB,kBAAC,GAAD,EAEE,GAAI,GACJ,EAFK,GAAU,SAEf;GAEA,CAAA;EAER,kBAAC,GAAD;GACE,SAAS;GACT,UACE,KAAqB,KAA4B;GAEnD,GAAI;GACJ,CAAA;EACD,KACC,kBAAC,GAAD;GAAO,UAAS;GAAQ,IAAI,EAAE,WAAW,GAAG;aACzC;GACK,CAAA;EAET,KACC,kBAAC,GAAD;GAIQ;GACW;GACF;GACL;GACV,cAAc,EAAQ,GAAM;GAC5B,gBAAgB,EAAQ,GAAM;GAC9B,EAPK,EAAK,UAAU,CAOpB;EAEH,EAAA,CAAA"}
1
+ {"version":3,"file":"WikiMarkdownEditorButton.js","names":[],"sources":["../../../src/components/WikiMarkdownEditorButton/WikiMarkdownEditorButton.tsx"],"sourcesContent":["import {\n CreateWikiPageInput,\n useCreateWikiPage,\n useGetRootWikiPageKey,\n useGetWikiPage,\n} from '@/synapse-queries'\nimport { Alert, Box, Button, ButtonProps } from '@mui/material'\nimport { ObjectType, WikiPageKey } from '@sage-bionetworks/synapse-types'\nimport { defaults } from 'lodash-es'\nimport { useMemo, useState } from 'react'\nimport { SynapseSpinner } from '../LoadingScreen/LoadingScreen'\nimport MarkdownSynapse, {\n MarkdownSynapseProps,\n} from '../Markdown/MarkdownSynapse'\nimport WikiMarkdownEditor from '../WikiMarkdownEditor/WikiMarkdownEditor'\n\nexport const ERROR_LOADING_WIKI_FAILED = 'Failed to load the wiki page: '\nexport const DEFAULT_BUTTON_TEXT = 'Edit Wiki Page'\nconst DEFAULT_BUTTON_PROPS: Omit<ButtonProps, 'onClick'> = {\n children: DEFAULT_BUTTON_TEXT,\n color: 'primary',\n variant: 'contained',\n}\n\nexport type WikiMarkdownEditorButtonProps = {\n ownerObjectType: ObjectType\n ownerObjectId: string\n // if wikiPageId is undefined, will get (or create) the root WikiPage for this ownerObject\n // otherwise, will get the WikiPage with the specified wikiPageId\n wikiPageId?: string\n buttonProps?: Omit<ButtonProps, 'onClick' | 'disabled'>\n displayWikiMarkdown?: boolean\n}\n\nexport function WikiMarkdownEditorButton(props: WikiMarkdownEditorButtonProps) {\n const {\n ownerObjectType,\n ownerObjectId,\n wikiPageId: initialWikiPageId,\n displayWikiMarkdown = false,\n } = props\n\n const buttonProps: Omit<ButtonProps, 'onClick' | 'disabled'> = defaults(\n {},\n props.buttonProps,\n DEFAULT_BUTTON_PROPS,\n )\n\n const [open, setOpen] = useState<boolean>(false)\n\n const {\n data: rootWikiPageKey,\n isLoading: isLoadingRootWikiPageKey,\n error: errorLoadingRootWikiPageKey,\n } = useGetRootWikiPageKey(ownerObjectType, ownerObjectId, {\n enabled: initialWikiPageId === undefined,\n })\n\n const {\n mutate: createWikiPage,\n isPending: isCreatingWikiPage,\n error: errorCreatingWikiPage,\n } = useCreateWikiPage({\n onSuccess: () => setOpen(true),\n })\n\n const wikiPageKey = useMemo(() => {\n const wikiPageId = initialWikiPageId || rootWikiPageKey?.wikiPageId || ''\n const wikiPageKey: WikiPageKey = {\n ownerObjectType,\n ownerObjectId,\n wikiPageId: wikiPageId,\n }\n return wikiPageKey\n }, [initialWikiPageId, rootWikiPageKey, ownerObjectId, ownerObjectType])\n\n const {\n data: wikiPage,\n isLoading: isLoadingWikiPage,\n error: errorLoadingWikiPage,\n } = useGetWikiPage(wikiPageKey, {\n enabled: wikiPageKey.wikiPageId !== '',\n // Set staleTime to infinity to prevent re-fetching while editing\n staleTime: Infinity,\n })\n\n const error = useMemo(() => {\n if (errorLoadingRootWikiPageKey) {\n return ERROR_LOADING_WIKI_FAILED + errorLoadingRootWikiPageKey.reason\n }\n if (errorLoadingWikiPage) {\n return ERROR_LOADING_WIKI_FAILED + errorLoadingWikiPage.reason\n }\n if (errorCreatingWikiPage) {\n return errorCreatingWikiPage.reason\n }\n return null\n }, [errorLoadingRootWikiPageKey, errorLoadingWikiPage, errorCreatingWikiPage])\n\n const handleClick = () => {\n if (wikiPage) {\n setOpen(true)\n } else if (rootWikiPageKey === null) {\n // root WikiPageKey was not found,\n // then create a root WikiPage for this ownerObject\n const rootWikiPage: CreateWikiPageInput['wikiPage'] = {\n parentWikiId: undefined,\n title: '',\n markdown: '',\n attachmentFileHandleIds: [],\n }\n const input: CreateWikiPageInput = {\n ownerObjectId,\n ownerObjectType,\n wikiPage: rootWikiPage,\n }\n createWikiPage(input)\n } else {\n // Should only reach this block if there was:\n // - a non-404 error fetching the root WikiPageKey\n // - an error fetching a specific wikiPage\n // Otherwise the button should be disabled.\n console.warn(\n 'There was an error fetching the root WikiPageKey or WikiPage - address that error first.',\n )\n }\n }\n\n /* TODO - pass ownerId, objectType, wikiId directly to MarkdownSynapse after\n MarkdownSynapse is updated to fetch root WikiPages for ACCESS_REQUIREMENT object types.\n See https://sagebionetworks.jira.com/browse/SWC-6791. */\n const markdownSynapseProps = useMemo(() => {\n const markdownSynapseProps: MarkdownSynapseProps = {\n showPlaceholderIfNoWikiContent: true,\n }\n if (wikiPage) {\n return {\n ...markdownSynapseProps,\n ownerId: ownerObjectId,\n objectType: ownerObjectType,\n wikiId: wikiPage.id,\n }\n } else {\n // use a placeholder value for markdown so that MarkdownSynapse\n // displays no content placeholder for owners without root wiki pages\n return { ...markdownSynapseProps, markdown: '' }\n }\n }, [ownerObjectId, ownerObjectType, wikiPage])\n\n return (\n <>\n {displayWikiMarkdown && (\n <Box\n sx={{\n mb: 1,\n }}\n >\n {isLoadingWikiPage || isLoadingRootWikiPageKey ? (\n <SynapseSpinner />\n ) : (\n // TODO - remove key once MarkdownSynapse uses tanstack-query\n <MarkdownSynapse\n key={wikiPage?.markdown}\n {...markdownSynapseProps}\n />\n )}\n </Box>\n )}\n <Button\n onClick={handleClick}\n disabled={\n isLoadingWikiPage || isLoadingRootWikiPageKey || isCreatingWikiPage\n }\n {...buttonProps}\n />\n {error && (\n <Alert severity=\"error\" sx={{ marginTop: 2 }}>\n {error}\n </Alert>\n )}\n {wikiPage && (\n <WikiMarkdownEditor\n // Specify a key so that uncommitted changes in WikiMarkdownEditor\n // are not displayed when editor is re-opened\n key={open.toString()}\n open={open}\n ownerObjectType={ownerObjectType}\n ownerObjectId={ownerObjectId}\n wikiPage={wikiPage}\n onSave={() => setOpen(false)}\n onCancel={() => setOpen(false)}\n />\n )}\n </>\n )\n}\n\nexport default WikiMarkdownEditorButton\n"],"mappings":";;;;;;;;;;AAgBA,IAAa,IAA4B,kCAC5B,IAAsB,kBAC7B,IAAqD;CACzD,UAAU;CACV,OAAO;CACP,SAAS;CACV;AAYD,SAAgB,EAAyB,GAAsC;CAC7E,IAAM,EACJ,oBACA,kBACA,YAAY,GACZ,yBAAsB,OACpB,GAEE,IAAyD,EAC7D,EAAE,EACF,EAAM,aACN,EACD,EAEK,CAAC,GAAM,KAAW,EAAkB,GAAM,EAE1C,EACJ,MAAM,GACN,WAAW,GACX,OAAO,MACL,EAAsB,GAAiB,GAAe,EACxD,SAAS,MAAsB,KAAA,GAChC,CAAC,EAEI,EACJ,QAAQ,GACR,WAAW,GACX,OAAO,MACL,EAAkB,EACpB,iBAAiB,EAAQ,GAAK,EAC/B,CAAC,EAEI,IAAc,SAOX;EAJL;EACA;EACY,YAJK,KAAqB,GAAiB,cAAc;EAMhE,GACN;EAAC;EAAmB;EAAiB;EAAe;EAAgB,CAAC,EAElE,EACJ,MAAM,GACN,WAAW,GACX,OAAO,MACL,EAAe,GAAa;EAC9B,SAAS,EAAY,eAAe;EAEpC,WAAW;EACZ,CAAC,EAEI,IAAQ,QACR,IACK,IAA4B,EAA4B,SAE7D,IACK,IAA4B,EAAqB,SAEtD,IACK,EAAsB,SAExB,MACN;EAAC;EAA6B;EAAsB;EAAsB,CAAC,EAExE,UAAoB;AACxB,EAAI,IACF,EAAQ,GAAK,GACJ,MAAoB,OAc7B,EAAe;GAJb;GACA;GACA,UAAU;IARV,cAAc,KAAA;IACd,OAAO;IACP,UAAU;IACV,yBAAyB,EAAE;IAKjB;GAEG,CAAM,GAMrB,QAAQ,KACN,2FACD;IAOC,IAAuB,QAAc;EACzC,IAAM,IAA6C,EACjD,gCAAgC,IACjC;AAWC,SAVE,IACK;GACL,GAAG;GACH,SAAS;GACT,YAAY;GACZ,QAAQ,EAAS;GAClB,GAIM;GAAE,GAAG;GAAsB,UAAU;GAAI;IAEjD;EAAC;EAAe;EAAiB;EAAS,CAAC;AAE9C,QACE,kBAAA,GAAA,EAAA,UAAA;EACG,KACC,kBAAC,GAAD;GACE,IAAI,EACF,IAAI,GACL;aAEA,KAAqB,IACpB,kBAAC,GAAD,EAAkB,CAAA,GAGlB,kBAAC,GAAD,EAEE,GAAI,GACJ,EAFK,GAAU,SAEf;GAEA,CAAA;EAER,kBAAC,GAAD;GACE,SAAS;GACT,UACE,KAAqB,KAA4B;GAEnD,GAAI;GACJ,CAAA;EACD,KACC,kBAAC,GAAD;GAAO,UAAS;GAAQ,IAAI,EAAE,WAAW,GAAG;aACzC;GACK,CAAA;EAET,KACC,kBAAC,GAAD;GAIQ;GACW;GACF;GACL;GACV,cAAc,EAAQ,GAAM;GAC5B,gBAAgB,EAAQ,GAAM;GAC9B,EAPK,EAAK,UAAU,CAOpB;EAEH,EAAA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"SubmissionPage.js","names":[],"sources":["../../../../src/components/dataaccess/SubmissionPage/SubmissionPage.tsx"],"sourcesContent":["import AccessRequirementList from '@/components/AccessRequirementList/AccessRequirementList'\nimport { CancelDataAccessRequestConfirmationModal } from '@/components/dataaccess/SubmissionPage/CancelDataAccessRequestConfirmationModal'\nimport { ApproveSubmissionConfirmationModal } from '@/components/dataaccess/SubmissionPage/ApproveSubmissionConfirmationModal'\nimport { displayToast } from '@/components/ToastMessage'\nimport {\n useGetAccessRequirementACL,\n useGetAccessRequirements,\n useGetAccessRequirementWikiPageKey,\n} from '@/synapse-queries/dataaccess/useAccessRequirements'\nimport useGetDataAccessSubmission from '@/synapse-queries/dataaccess/useDataAccessSubmission'\nimport { useGetThreadForSubmission } from '@/synapse-queries/forum/useThread'\nimport { useGetCurrentUserProfile } from '@/synapse-queries/user'\nimport { useGetUserAccessApproval } from '@/synapse-queries/dataaccess/useAccessApprovals'\nimport { formatDate } from '@/utils/functions/DateFormatter'\nimport { ACT_TEAM_ID } from '@/utils/SynapseConstants'\nimport { Button, Grid, Skeleton, Stack, Typography } from '@mui/material'\nimport {\n ACCESS_TYPE,\n FileHandleAssociateType,\n ManagedACTAccessRequirement,\n Submission,\n SubmissionState,\n} from '@sage-bionetworks/synapse-types'\nimport dayjs from 'dayjs'\nimport duration from 'dayjs/plugin/duration'\nimport { isEmpty, toLower, upperFirst } from 'lodash-es'\nimport { Fragment, ReactNode, useMemo, useState } from 'react'\nimport { useNavigate } from 'react-router'\nimport { SynapseErrorBoundary } from '../../error/ErrorBanner'\nimport MarkdownSynapse from '../../Markdown/MarkdownSynapse'\nimport { UserBadge } from '../../UserCard/UserBadge'\nimport UserOrTeamBadge from '../../UserOrTeamBadge/UserOrTeamBadge'\nimport { FileHandleLink } from '../../widgets/FileHandleLink'\nimport RejectDataAccessRequestModal from '../RejectDataAccessRequestModal'\nimport { DiscussionThread } from '@/components/Forum'\n\ndayjs.extend(duration)\n\nexport type SubmissionPageProps = {\n /** The ID of the submission to view */\n submissionId: string | number\n /** If true, display reviewer controls on the page */\n isReviewer: boolean // There is currently no API to check if a user has review permissions on a specific submission ID\n}\n\nconst THREAD_BODY =\n 'Use this thread to communicate with the reviewers about this access request.'\n\nfunction DataAccessSubmissionFileHandleLink(props: {\n submissionId: string\n fileHandleId: string\n}) {\n const { submissionId, fileHandleId } = props\n const fileHandleAssociation = useMemo(\n () => ({\n fileHandleId: fileHandleId,\n associateObjectId: submissionId,\n associateObjectType:\n FileHandleAssociateType.DataAccessSubmissionAttachment,\n }),\n [fileHandleId, submissionId],\n )\n return (\n <FileHandleLink\n key={fileHandleId}\n showDownloadIcon={true}\n fileHandleAssociation={fileHandleAssociation}\n />\n )\n}\n\ntype AccessRequirementWikiType = {\n accessRequirementId: string\n}\n\nfunction AccessRequirementWiki(props: AccessRequirementWikiType) {\n const { data: wikiPageKey } = useGetAccessRequirementWikiPageKey(\n props.accessRequirementId,\n {\n throwOnError: true,\n },\n )\n\n return wikiPageKey ? (\n <div className=\"AccessRequirementWikiContainer\">\n <div className=\"AccessRequirementWikiContent\">\n <Typography variant=\"headline1\">Access Requirement</Typography>\n <hr />\n <MarkdownSynapse\n wikiId={wikiPageKey?.wikiPageId}\n ownerId={wikiPageKey?.ownerObjectId}\n objectType={wikiPageKey?.ownerObjectType}\n />\n </div>\n </div>\n ) : (\n <Skeleton width={'100%'} height={'600px'} />\n )\n}\n\n/**\n * returns true iff the userId is a requester and/or listed on the accessor changes on the submission.\n * @param userId\n * @param submission\n */\nfunction isRequesterOnSubmission(userId: string, submission: Submission) {\n return (\n submission.submittedBy === userId ||\n Boolean(submission.accessorChanges.find(acc => acc.userId === userId))\n )\n}\n\n/**\n * Page for a Data Access Submission. Supports the following user types:\n * - ACT member or other designated reviewer can view, and choose to approve or reject.\n * - Data Access Request submitter can view and modify their own submission.\n * - Data Access Request requester (who is not a submitter) can view their own submission.\n */\nexport default function SubmissionPage(props: SubmissionPageProps) {\n const { submissionId, isReviewer } = props\n const [showRejectionDialog, setShowRejectionDialog] = useState(false)\n\n const { data: currentUserProfile } = useGetCurrentUserProfile()\n\n const { data: submission, isLoading: isLoadingSubmission } =\n useGetDataAccessSubmission(submissionId, {\n throwOnError: true,\n })\n const isRequester = Boolean(\n submission &&\n currentUserProfile &&\n isRequesterOnSubmission(currentUserProfile.ownerId, submission),\n )\n\n const { data: accessApproval, isLoading: isLoadingAccessApproval } =\n useGetUserAccessApproval(String(submissionId), {\n enabled:\n isRequester &&\n submission &&\n submission.state === SubmissionState.APPROVED,\n })\n\n const isExpired = Boolean(\n accessApproval && dayjs(accessApproval.expiredOn).isBefore(dayjs()),\n )\n\n const isSubmitter =\n submission && submission.submittedBy === currentUserProfile?.ownerId\n\n const { data: accessRequirement } =\n useGetAccessRequirements<ManagedACTAccessRequirement>(\n parseInt(submission?.accessRequirementId!),\n { enabled: !!submission },\n )\n\n const { data: acl, isLoading: isLoadingACL } = useGetAccessRequirementACL(\n submission?.accessRequirementId!,\n { enabled: !!submission, throwOnError: true },\n )\n\n const { data: thread } = useGetThreadForSubmission(submissionId)\n\n const [showUpdateRequestDialog, setShowUpdateRequestDialog] = useState(false)\n const [\n showCancelRequestConfirmationDialog,\n setShowCancelRequestConfirmationDialog,\n ] = useState(false)\n const [showApprovalConfirmation, setShowApprovalConfirmation] =\n useState(false)\n\n const navigate = useNavigate()\n\n const reviewerIds = acl?.resourceAccess\n .filter(ra => ra.accessType.includes(ACCESS_TYPE.REVIEW_SUBMISSIONS))\n .map(ra => ra.principalId)\n\n const displayedSubmissionState: ReactNode = useMemo(() => {\n if (submission && !isLoadingAccessApproval) {\n if (isExpired) {\n return 'Expired'\n }\n return submission.state\n }\n return <Skeleton width={100} />\n }, [isExpired, isLoadingAccessApproval, submission])\n\n return (\n <Grid container={true} spacing={4} className=\"SubmissionPage\">\n {showUpdateRequestDialog && accessRequirement && (\n <AccessRequirementList\n renderAsModal={true}\n accessRequirementFromProps={[accessRequirement]}\n onHide={() => setShowUpdateRequestDialog(false)}\n onSubmissionCreated={submissionId => {\n setShowUpdateRequestDialog(false)\n displayToast('Data access request submitted', 'success', {\n primaryButtonConfig: {\n text: 'View Request',\n onClick: () => {\n navigate('/submissions/' + submissionId)\n },\n },\n })\n }}\n />\n )}\n <ApproveSubmissionConfirmationModal\n open={showApprovalConfirmation}\n onClose={() => {\n setShowApprovalConfirmation(false)\n }}\n submissionId={String(submissionId)}\n />\n {showRejectionDialog && (\n <RejectDataAccessRequestModal\n // Previously, we used a 'key' prop to reset the modal form when it was opened,\n // but removing the key and re-rendering the JSX achieves the same functionality in a more straightforward way.\n submissionId={submissionId}\n open={showRejectionDialog}\n onClose={() => setShowRejectionDialog(false)}\n />\n )}\n <Grid\n className=\"SubmissionSummary\"\n size={{\n xs: 12,\n sm: 4,\n lg: 3,\n }}\n >\n <Typography variant=\"dataFieldKey\" gutterBottom>\n Status\n </Typography>\n <Typography\n variant=\"headline3\"\n sx={{ textTransform: 'uppercase' }}\n gutterBottom\n >\n {displayedSubmissionState}\n </Typography>\n <br />\n {isLoadingSubmission && <Skeleton width={200} />}\n {submission &&\n isReviewer &&\n submission.state === SubmissionState.SUBMITTED && (\n <div className=\"ButtonContainer\">\n <Button\n onClick={() => {\n setShowApprovalConfirmation(true)\n }}\n color=\"success\"\n variant=\"contained\"\n >\n Approve\n </Button>\n <Button\n onClick={() => {\n setShowRejectionDialog(true)\n }}\n color=\"error\"\n variant=\"contained\"\n >\n Reject\n </Button>\n </div>\n )}\n\n {submission && isSubmitter && (\n <div className=\"ButtonContainer\">\n <CancelDataAccessRequestConfirmationModal\n open={showCancelRequestConfirmationDialog}\n submissionId={String(submissionId)}\n accessRequirementId={submission?.accessRequirementId || ''}\n onClose={() => setShowCancelRequestConfirmationDialog(false)}\n />\n {submission.state === SubmissionState.SUBMITTED && (\n <Button\n onClick={() => {\n setShowCancelRequestConfirmationDialog(true)\n }}\n color=\"primary\"\n variant=\"outlined\"\n >\n Cancel Request\n </Button>\n )}\n {submission.state !== SubmissionState.SUBMITTED && (\n <Button\n onClick={() => {\n setShowUpdateRequestDialog(true)\n }}\n color=\"primary\"\n variant=\"outlined\"\n >\n {submission.state === SubmissionState.APPROVED\n ? 'Update'\n : 'Modify'}{' '}\n Request\n </Button>\n )}\n </div>\n )}\n <Typography variant=\"dataFieldKey\" gutterBottom>\n Access Requirement Name\n </Typography>\n\n <Typography variant=\"smallText1\" gutterBottom>\n {accessRequirement?.name ?? <Skeleton width={100} />}\n </Typography>\n <br />\n\n {isReviewer && (\n <>\n <Typography variant=\"dataFieldKey\" gutterBottom>\n Assigned Reviewer\n </Typography>\n <Stack>\n {isLoadingACL && <Skeleton width={100} />}\n {!isLoadingACL &&\n !isEmpty(reviewerIds) &&\n reviewerIds!.map(id => {\n return <UserOrTeamBadge key={id} principalId={id} />\n })}\n {!isLoadingACL && isEmpty(reviewerIds) && (\n <UserOrTeamBadge principalId={ACT_TEAM_ID} />\n )}\n </Stack>\n <br />\n </>\n )}\n <Typography variant=\"dataFieldKey\" gutterBottom>\n Conditions\n </Typography>\n {accessRequirement ? (\n <Typography variant=\"smallText1\" component={'div'} gutterBottom>\n <ul>\n <li>\n Expiration period:{' '}\n {dayjs\n .duration({\n milliseconds: accessRequirement.expirationPeriod,\n })\n .asDays()}{' '}\n day(s)\n {accessRequirement.expirationPeriod === 0 && ' (no expiration)'}\n </li>\n\n {accessRequirement.isCertifiedUserRequired && (\n <li>User must be Certified</li>\n )}\n {accessRequirement.isValidatedProfileRequired && (\n <li>User Profile must be Validated</li>\n )}\n {accessRequirement.isDUCRequired && <li>DUC is required</li>}\n {accessRequirement.isIDURequired && <li>IDU is required</li>}\n {accessRequirement.isIDUPublic && (\n <li>IDU will be made public</li>\n )}\n {accessRequirement.isIRBApprovalRequired && (\n <li>IRB Approval is required</li>\n )}\n {accessRequirement.areOtherAttachmentsRequired && (\n <li>Other attachments are required</li>\n )}\n </ul>\n </Typography>\n ) : (\n <Skeleton width={100} />\n )}\n <br />\n <div className=\"SubmissionSummaryGrid\">\n <Typography variant=\"dataFieldKey\">Submitted By</Typography>\n <Typography variant=\"smallText1\">\n {submission ? (\n <UserBadge userId={submission.submittedBy} />\n ) : (\n <Skeleton width={100} />\n )}\n </Typography>\n <Typography variant=\"dataFieldKey\">Submitted On</Typography>\n <Typography variant=\"smallText1\">\n {submission ? (\n formatDate(dayjs(submission.submittedOn))\n ) : (\n <Skeleton width={100} />\n )}\n </Typography>\n {isReviewer && (\n <>\n <Typography variant=\"dataFieldKey\">Modified By</Typography>\n <Typography variant=\"smallText1\">\n {submission ? (\n <UserBadge userId={submission.modifiedBy} />\n ) : (\n <Skeleton width={100} />\n )}\n </Typography>\n </>\n )}\n <Typography variant=\"dataFieldKey\">Modified On</Typography>\n <Typography variant=\"smallText1\">\n {submission ? (\n formatDate(dayjs(submission.modifiedOn))\n ) : (\n <Skeleton width={100} />\n )}\n </Typography>\n <Typography className=\"Key\" variant=\"dataFieldKey\">\n Data Requesters\n {`${submission ? ` (${submission.accessorChanges.length})` : ''}`}\n </Typography>\n {submission ? (\n submission.accessorChanges.map(accessorChange => (\n <Fragment key={accessorChange.userId}>\n <Typography className=\"Key DataAccessor\" variant=\"smallText1\">\n <span style={{ whiteSpace: 'nowrap' }}>\n <UserBadge\n key={accessorChange.userId}\n userId={accessorChange.userId}\n />\n </span>\n </Typography>\n <Typography className=\"Value DataAccessor\" variant=\"smallText1\">\n {upperFirst(\n toLower(\n accessorChange.type.substring(\n 0,\n accessorChange.type.indexOf('_'),\n ),\n ),\n )}\n </Typography>\n </Fragment>\n ))\n ) : (\n <Skeleton width={100} />\n )}\n <Typography className=\"Key\" variant=\"dataFieldKey\">\n Institution\n </Typography>\n <Typography className=\"Value\" variant=\"smallText1\">\n {submission ? (\n submission.researchProjectSnapshot.institution\n ) : (\n <Skeleton width={100} />\n )}\n </Typography>\n <Typography className=\"Key\" variant=\"dataFieldKey\">\n Project Lead\n </Typography>\n <Typography className=\"Value\" variant=\"smallText1\">\n {submission ? (\n submission.researchProjectSnapshot.projectLead\n ) : (\n <Skeleton width={100} />\n )}\n </Typography>\n </div>\n </Grid>\n <Grid\n size={{\n xs: 12,\n sm: 8,\n lg: 9,\n }}\n >\n <Stack sx={{ gap: 2 }}>\n <SynapseErrorBoundary>\n {submission ? (\n <AccessRequirementWiki\n accessRequirementId={submission.accessRequirementId}\n />\n ) : (\n <></>\n )}\n </SynapseErrorBoundary>\n {submission?.rejectedReason && (\n <section>\n <Typography variant=\"headline1\" gutterBottom>\n Reason for rejection given by reviewer\n </Typography>\n <hr />\n <Typography\n variant=\"body1\"\n style={{ whiteSpace: 'pre-line' }}\n gutterBottom\n >\n {submission.rejectedReason}\n </Typography>\n </section>\n )}\n <section>\n <Typography variant=\"headline1\">\n Contents of the Access Request\n <hr />\n </Typography>\n <Stack\n sx={{\n gap: 2,\n }}\n >\n {submission?.researchProjectSnapshot\n ?.intendedDataUseStatement && (\n <section>\n <Typography variant=\"headline2\" gutterBottom>\n Intended Data Use Statement\n </Typography>\n <Typography\n variant=\"body1\"\n style={{ whiteSpace: 'pre-line' }}\n gutterBottom\n >\n {\n submission.researchProjectSnapshot\n .intendedDataUseStatement\n }\n </Typography>\n </section>\n )}\n <Typography variant=\"headline2\" gutterBottom>\n Documents\n </Typography>\n {submission?.ducFileHandleId && (\n <section>\n <Typography variant=\"smallText2\">\n Data Use Certificate (DUC)\n </Typography>\n <DataAccessSubmissionFileHandleLink\n submissionId={submission.id}\n fileHandleId={submission.ducFileHandleId}\n />\n </section>\n )}\n {submission?.irbFileHandleId && (\n <section>\n <Typography variant=\"smallText2\" gutterBottom>\n IRB Approval Letter\n </Typography>\n <DataAccessSubmissionFileHandleLink\n submissionId={submission.id}\n fileHandleId={submission.irbFileHandleId}\n />\n </section>\n )}\n {submission?.attachments && (\n <section>\n <Typography variant=\"smallText2\" gutterBottom>\n Other Attachments\n </Typography>\n {submission.attachments.map(fileHandleId => (\n <Fragment key={fileHandleId}>\n <DataAccessSubmissionFileHandleLink\n submissionId={submission.id}\n fileHandleId={fileHandleId}\n />\n <br />\n </Fragment>\n ))}\n </section>\n )}\n </Stack>\n </section>\n {thread?.id && (\n <DiscussionThread\n threadId={thread.id}\n limit={25}\n emptyBodyContent={THREAD_BODY}\n />\n )}\n </Stack>\n </Grid>\n </Grid>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"SubmissionPage.js","names":[],"sources":["../../../../src/components/dataaccess/SubmissionPage/SubmissionPage.tsx"],"sourcesContent":["import AccessRequirementList from '@/components/AccessRequirementList/AccessRequirementList'\nimport { CancelDataAccessRequestConfirmationModal } from '@/components/dataaccess/SubmissionPage/CancelDataAccessRequestConfirmationModal'\nimport { ApproveSubmissionConfirmationModal } from '@/components/dataaccess/SubmissionPage/ApproveSubmissionConfirmationModal'\nimport { displayToast } from '@/components/ToastMessage'\nimport {\n useGetAccessRequirementACL,\n useGetAccessRequirements,\n useGetAccessRequirementWikiPageKey,\n} from '@/synapse-queries/dataaccess/useAccessRequirements'\nimport useGetDataAccessSubmission from '@/synapse-queries/dataaccess/useDataAccessSubmission'\nimport { useGetThreadForSubmission } from '@/synapse-queries/forum/useThread'\nimport { useGetCurrentUserProfile } from '@/synapse-queries/user'\nimport { useGetUserAccessApproval } from '@/synapse-queries/dataaccess/useAccessApprovals'\nimport { formatDate } from '@/utils/functions/DateFormatter'\nimport { ACT_TEAM_ID } from '@/utils/SynapseConstants'\nimport { Button, Grid, Skeleton, Stack, Typography } from '@mui/material'\nimport {\n ACCESS_TYPE,\n FileHandleAssociateType,\n ManagedACTAccessRequirement,\n Submission,\n SubmissionState,\n} from '@sage-bionetworks/synapse-types'\nimport dayjs from 'dayjs'\nimport duration from 'dayjs/plugin/duration'\nimport { isEmpty, toLower, upperFirst } from 'lodash-es'\nimport { Fragment, ReactNode, useMemo, useState } from 'react'\nimport { useNavigate } from 'react-router'\nimport { SynapseErrorBoundary } from '../../error/ErrorBanner'\nimport MarkdownSynapse from '../../Markdown/MarkdownSynapse'\nimport { UserBadge } from '../../UserCard/UserBadge'\nimport UserOrTeamBadge from '../../UserOrTeamBadge/UserOrTeamBadge'\nimport { FileHandleLink } from '../../widgets/FileHandleLink'\nimport RejectDataAccessRequestModal from '../RejectDataAccessRequestModal'\nimport { DiscussionThread } from '@/components/Forum'\n\ndayjs.extend(duration)\n\nexport type SubmissionPageProps = {\n /** The ID of the submission to view */\n submissionId: string | number\n /** If true, display reviewer controls on the page */\n isReviewer: boolean // There is currently no API to check if a user has review permissions on a specific submission ID\n}\n\nconst THREAD_BODY =\n 'Use this thread to communicate with the reviewers about this access request.'\n\nfunction DataAccessSubmissionFileHandleLink(props: {\n submissionId: string\n fileHandleId: string\n}) {\n const { submissionId, fileHandleId } = props\n const fileHandleAssociation = useMemo(\n () => ({\n fileHandleId: fileHandleId,\n associateObjectId: submissionId,\n associateObjectType:\n FileHandleAssociateType.DataAccessSubmissionAttachment,\n }),\n [fileHandleId, submissionId],\n )\n return (\n <FileHandleLink\n key={fileHandleId}\n showDownloadIcon={true}\n fileHandleAssociation={fileHandleAssociation}\n />\n )\n}\n\ntype AccessRequirementWikiType = {\n accessRequirementId: string\n}\n\nfunction AccessRequirementWiki(props: AccessRequirementWikiType) {\n const { data: wikiPageKey } = useGetAccessRequirementWikiPageKey(\n props.accessRequirementId,\n {\n throwOnError: true,\n },\n )\n\n return wikiPageKey ? (\n <div className=\"AccessRequirementWikiContainer\">\n <div className=\"AccessRequirementWikiContent\">\n <Typography variant=\"headline1\">Access Requirement</Typography>\n <hr />\n <MarkdownSynapse\n wikiId={wikiPageKey?.wikiPageId}\n ownerId={wikiPageKey?.ownerObjectId}\n objectType={wikiPageKey?.ownerObjectType}\n />\n </div>\n </div>\n ) : (\n <Skeleton width={'100%'} height={'600px'} />\n )\n}\n\n/**\n * returns true iff the userId is a requester and/or listed on the accessor changes on the submission.\n * @param userId\n * @param submission\n */\nfunction isRequesterOnSubmission(userId: string, submission: Submission) {\n return (\n submission.submittedBy === userId ||\n Boolean(submission.accessorChanges.find(acc => acc.userId === userId))\n )\n}\n\n/**\n * Page for a Data Access Submission. Supports the following user types:\n * - ACT member or other designated reviewer can view, and choose to approve or reject.\n * - Data Access Request submitter can view and modify their own submission.\n * - Data Access Request requester (who is not a submitter) can view their own submission.\n */\nexport default function SubmissionPage(props: SubmissionPageProps) {\n const { submissionId, isReviewer } = props\n const [showRejectionDialog, setShowRejectionDialog] = useState(false)\n\n const { data: currentUserProfile } = useGetCurrentUserProfile()\n\n const { data: submission, isLoading: isLoadingSubmission } =\n useGetDataAccessSubmission(submissionId, {\n throwOnError: true,\n })\n const isRequester = Boolean(\n submission &&\n currentUserProfile &&\n isRequesterOnSubmission(currentUserProfile.ownerId, submission),\n )\n\n const { data: accessApproval, isLoading: isLoadingAccessApproval } =\n useGetUserAccessApproval(String(submissionId), {\n enabled:\n isRequester &&\n submission &&\n submission.state === SubmissionState.APPROVED,\n })\n\n const isExpired = Boolean(\n accessApproval && dayjs(accessApproval.expiredOn).isBefore(dayjs()),\n )\n\n const isSubmitter =\n submission && submission.submittedBy === currentUserProfile?.ownerId\n\n const { data: accessRequirement } =\n useGetAccessRequirements<ManagedACTAccessRequirement>(\n parseInt(submission?.accessRequirementId!),\n { enabled: !!submission },\n )\n\n const { data: acl, isLoading: isLoadingACL } = useGetAccessRequirementACL(\n submission?.accessRequirementId!,\n { enabled: !!submission, throwOnError: true },\n )\n\n const { data: thread } = useGetThreadForSubmission(submissionId)\n\n const [showUpdateRequestDialog, setShowUpdateRequestDialog] = useState(false)\n const [\n showCancelRequestConfirmationDialog,\n setShowCancelRequestConfirmationDialog,\n ] = useState(false)\n const [showApprovalConfirmation, setShowApprovalConfirmation] =\n useState(false)\n\n const navigate = useNavigate()\n\n const reviewerIds = acl?.resourceAccess\n .filter(ra => ra.accessType.includes(ACCESS_TYPE.REVIEW_SUBMISSIONS))\n .map(ra => ra.principalId)\n\n const displayedSubmissionState: ReactNode = useMemo(() => {\n if (submission && !isLoadingAccessApproval) {\n if (isExpired) {\n return 'Expired'\n }\n return submission.state\n }\n return <Skeleton width={100} />\n }, [isExpired, isLoadingAccessApproval, submission])\n\n return (\n <Grid container={true} spacing={4} className=\"SubmissionPage\">\n {showUpdateRequestDialog && accessRequirement && (\n <AccessRequirementList\n renderAsModal={true}\n accessRequirementFromProps={[accessRequirement]}\n onHide={() => setShowUpdateRequestDialog(false)}\n onSubmissionCreated={submissionId => {\n setShowUpdateRequestDialog(false)\n displayToast('Data access request submitted', 'success', {\n primaryButtonConfig: {\n text: 'View Request',\n onClick: () => {\n navigate('/submissions/' + submissionId)\n },\n },\n })\n }}\n />\n )}\n <ApproveSubmissionConfirmationModal\n open={showApprovalConfirmation}\n onClose={() => {\n setShowApprovalConfirmation(false)\n }}\n submissionId={String(submissionId)}\n />\n {showRejectionDialog && (\n <RejectDataAccessRequestModal\n // Previously, we used a 'key' prop to reset the modal form when it was opened,\n // but removing the key and re-rendering the JSX achieves the same functionality in a more straightforward way.\n submissionId={submissionId}\n open={showRejectionDialog}\n onClose={() => setShowRejectionDialog(false)}\n />\n )}\n <Grid\n className=\"SubmissionSummary\"\n size={{\n xs: 12,\n sm: 4,\n lg: 3,\n }}\n >\n <Typography variant=\"dataFieldKey\" gutterBottom>\n Status\n </Typography>\n <Typography\n variant=\"headline3\"\n sx={{ textTransform: 'uppercase' }}\n gutterBottom\n >\n {displayedSubmissionState}\n </Typography>\n <br />\n {isLoadingSubmission && <Skeleton width={200} />}\n {submission &&\n isReviewer &&\n submission.state === SubmissionState.SUBMITTED && (\n <div className=\"ButtonContainer\">\n <Button\n onClick={() => {\n setShowApprovalConfirmation(true)\n }}\n color=\"success\"\n variant=\"contained\"\n >\n Approve\n </Button>\n <Button\n onClick={() => {\n setShowRejectionDialog(true)\n }}\n color=\"error\"\n variant=\"contained\"\n >\n Reject\n </Button>\n </div>\n )}\n\n {submission && isSubmitter && (\n <div className=\"ButtonContainer\">\n <CancelDataAccessRequestConfirmationModal\n open={showCancelRequestConfirmationDialog}\n submissionId={String(submissionId)}\n accessRequirementId={submission?.accessRequirementId || ''}\n onClose={() => setShowCancelRequestConfirmationDialog(false)}\n />\n {submission.state === SubmissionState.SUBMITTED && (\n <Button\n onClick={() => {\n setShowCancelRequestConfirmationDialog(true)\n }}\n color=\"primary\"\n variant=\"outlined\"\n >\n Cancel Request\n </Button>\n )}\n {submission.state !== SubmissionState.SUBMITTED && (\n <Button\n onClick={() => {\n setShowUpdateRequestDialog(true)\n }}\n color=\"primary\"\n variant=\"outlined\"\n >\n {submission.state === SubmissionState.APPROVED\n ? 'Update'\n : 'Modify'}{' '}\n Request\n </Button>\n )}\n </div>\n )}\n <Typography variant=\"dataFieldKey\" gutterBottom>\n Access Requirement Name\n </Typography>\n\n <Typography variant=\"smallText1\" gutterBottom>\n {accessRequirement?.name ?? <Skeleton width={100} />}\n </Typography>\n <br />\n\n {isReviewer && (\n <>\n <Typography variant=\"dataFieldKey\" gutterBottom>\n Assigned Reviewer\n </Typography>\n <Stack>\n {isLoadingACL && <Skeleton width={100} />}\n {!isLoadingACL &&\n !isEmpty(reviewerIds) &&\n reviewerIds!.map(id => {\n return <UserOrTeamBadge key={id} principalId={id} />\n })}\n {!isLoadingACL && isEmpty(reviewerIds) && (\n <UserOrTeamBadge principalId={ACT_TEAM_ID} />\n )}\n </Stack>\n <br />\n </>\n )}\n <Typography variant=\"dataFieldKey\" gutterBottom>\n Conditions\n </Typography>\n {accessRequirement ? (\n <Typography variant=\"smallText1\" component={'div'} gutterBottom>\n <ul>\n <li>\n Expiration period:{' '}\n {dayjs\n .duration({\n milliseconds: accessRequirement.expirationPeriod,\n })\n .asDays()}{' '}\n day(s)\n {accessRequirement.expirationPeriod === 0 && ' (no expiration)'}\n </li>\n\n {accessRequirement.isCertifiedUserRequired && (\n <li>User must be Certified</li>\n )}\n {accessRequirement.isValidatedProfileRequired && (\n <li>User Profile must be Validated</li>\n )}\n {accessRequirement.isDUCRequired && <li>DUC is required</li>}\n {accessRequirement.isIDURequired && <li>IDU is required</li>}\n {accessRequirement.isIDUPublic && (\n <li>IDU will be made public</li>\n )}\n {accessRequirement.isIRBApprovalRequired && (\n <li>IRB Approval is required</li>\n )}\n {accessRequirement.areOtherAttachmentsRequired && (\n <li>Other attachments are required</li>\n )}\n </ul>\n </Typography>\n ) : (\n <Skeleton width={100} />\n )}\n <br />\n <div className=\"SubmissionSummaryGrid\">\n <Typography variant=\"dataFieldKey\">Submitted By</Typography>\n <Typography variant=\"smallText1\">\n {submission ? (\n <UserBadge userId={submission.submittedBy} />\n ) : (\n <Skeleton width={100} />\n )}\n </Typography>\n <Typography variant=\"dataFieldKey\">Submitted On</Typography>\n <Typography variant=\"smallText1\">\n {submission ? (\n formatDate(dayjs(submission.submittedOn))\n ) : (\n <Skeleton width={100} />\n )}\n </Typography>\n {isReviewer && (\n <>\n <Typography variant=\"dataFieldKey\">Modified By</Typography>\n <Typography variant=\"smallText1\">\n {submission ? (\n <UserBadge userId={submission.modifiedBy} />\n ) : (\n <Skeleton width={100} />\n )}\n </Typography>\n </>\n )}\n <Typography variant=\"dataFieldKey\">Modified On</Typography>\n <Typography variant=\"smallText1\">\n {submission ? (\n formatDate(dayjs(submission.modifiedOn))\n ) : (\n <Skeleton width={100} />\n )}\n </Typography>\n <Typography className=\"Key\" variant=\"dataFieldKey\">\n Data Requesters\n {`${submission ? ` (${submission.accessorChanges.length})` : ''}`}\n </Typography>\n {submission ? (\n submission.accessorChanges.map(accessorChange => (\n <Fragment key={accessorChange.userId}>\n <Typography className=\"Key DataAccessor\" variant=\"smallText1\">\n <span style={{ whiteSpace: 'nowrap' }}>\n <UserBadge\n key={accessorChange.userId}\n userId={accessorChange.userId}\n />\n </span>\n </Typography>\n <Typography className=\"Value DataAccessor\" variant=\"smallText1\">\n {upperFirst(\n toLower(\n accessorChange.type.substring(\n 0,\n accessorChange.type.indexOf('_'),\n ),\n ),\n )}\n </Typography>\n </Fragment>\n ))\n ) : (\n <Skeleton width={100} />\n )}\n <Typography className=\"Key\" variant=\"dataFieldKey\">\n Institution\n </Typography>\n <Typography className=\"Value\" variant=\"smallText1\">\n {submission ? (\n submission.researchProjectSnapshot.institution\n ) : (\n <Skeleton width={100} />\n )}\n </Typography>\n <Typography className=\"Key\" variant=\"dataFieldKey\">\n Project Lead\n </Typography>\n <Typography className=\"Value\" variant=\"smallText1\">\n {submission ? (\n submission.researchProjectSnapshot.projectLead\n ) : (\n <Skeleton width={100} />\n )}\n </Typography>\n </div>\n </Grid>\n <Grid\n size={{\n xs: 12,\n sm: 8,\n lg: 9,\n }}\n >\n <Stack sx={{ gap: 2 }}>\n <SynapseErrorBoundary>\n {submission ? (\n <AccessRequirementWiki\n accessRequirementId={submission.accessRequirementId}\n />\n ) : (\n <></>\n )}\n </SynapseErrorBoundary>\n {submission?.rejectedReason && (\n <section>\n <Typography variant=\"headline1\" gutterBottom>\n Reason for rejection given by reviewer\n </Typography>\n <hr />\n <Typography\n variant=\"body1\"\n style={{ whiteSpace: 'pre-line' }}\n gutterBottom\n >\n {submission.rejectedReason}\n </Typography>\n </section>\n )}\n <section>\n <Typography variant=\"headline1\">\n Contents of the Access Request\n <hr />\n </Typography>\n <Stack\n sx={{\n gap: 2,\n }}\n >\n {submission?.researchProjectSnapshot\n ?.intendedDataUseStatement && (\n <section>\n <Typography variant=\"headline2\" gutterBottom>\n Intended Data Use Statement\n </Typography>\n <Typography\n variant=\"body1\"\n style={{ whiteSpace: 'pre-line' }}\n gutterBottom\n >\n {\n submission.researchProjectSnapshot\n .intendedDataUseStatement\n }\n </Typography>\n </section>\n )}\n <Typography variant=\"headline2\" gutterBottom>\n Documents\n </Typography>\n {submission?.ducFileHandleId && (\n <section>\n <Typography variant=\"smallText2\">\n Data Use Certificate (DUC)\n </Typography>\n <DataAccessSubmissionFileHandleLink\n submissionId={submission.id}\n fileHandleId={submission.ducFileHandleId}\n />\n </section>\n )}\n {submission?.irbFileHandleId && (\n <section>\n <Typography variant=\"smallText2\" gutterBottom>\n IRB Approval Letter\n </Typography>\n <DataAccessSubmissionFileHandleLink\n submissionId={submission.id}\n fileHandleId={submission.irbFileHandleId}\n />\n </section>\n )}\n {submission?.attachments && (\n <section>\n <Typography variant=\"smallText2\" gutterBottom>\n Other Attachments\n </Typography>\n {submission.attachments.map(fileHandleId => (\n <Fragment key={fileHandleId}>\n <DataAccessSubmissionFileHandleLink\n submissionId={submission.id}\n fileHandleId={fileHandleId}\n />\n <br />\n </Fragment>\n ))}\n </section>\n )}\n </Stack>\n </section>\n {thread?.id && (\n <DiscussionThread\n threadId={thread.id}\n limit={25}\n emptyBodyContent={THREAD_BODY}\n />\n )}\n </Stack>\n </Grid>\n </Grid>\n )\n}\n"],"mappings":"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"}
@@ -12,11 +12,11 @@ import { useGetCurrentUserProfile as i } from "../../synapse-queries/user/useUse
12
12
  import { useCreateOrUpdateDOI as a, useGetDOI as ue } from "../../synapse-queries/doi/useDOI.js";
13
13
  import { MarkdownPopover as de } from "../Markdown/MarkdownPopover.js";
14
14
  import { DialogBase as fe } from "../DialogBase.js";
15
- import { StyledFormControl as o } from "../styled/StyledFormControl.js";
16
- import pe from "../Dialog/ConfirmCloseWithoutSavingDialog.js";
17
- import { doiFormSchema as me, doiFormUiSchema as he } from "./DoiFormSchemas.js";
18
- import { PrivateEntityDoiWarning as ge } from "./PrivateEntityDoiWarning.js";
19
- import { JsonSchemaForm as _e } from "../JsonSchemaForm/JsonSchemaForm.js";
15
+ import o from "../Dialog/ConfirmCloseWithoutSavingDialog.js";
16
+ import { doiFormSchema as pe, doiFormUiSchema as me } from "./DoiFormSchemas.js";
17
+ import { PrivateEntityDoiWarning as he } from "./PrivateEntityDoiWarning.js";
18
+ import { JsonSchemaForm as ge } from "../JsonSchemaForm/JsonSchemaForm.js";
19
+ import { StyledFormControl as _e } from "../styled/StyledFormControl.js";
20
20
  import { isEntityPublic as ve } from "../../utils/functions/AccessControlListUtils.js";
21
21
  import { useEffect as s, useMemo as ye, useRef as c, useState as l } from "react";
22
22
  import { isEmpty as u } from "lodash-es";
@@ -153,12 +153,12 @@ function E(u) {
153
153
  value: Ee?.name || "",
154
154
  disabled: !0
155
155
  }),
156
- K && /* @__PURE__ */ _(o, {
156
+ K && /* @__PURE__ */ _(_e, {
157
157
  className: "limit-type",
158
158
  fullWidth: !0,
159
159
  sx: { my: 2 },
160
160
  children: [/* @__PURE__ */ _(be, {
161
- htmlFor: "doi-version-select",
161
+ id: "doi-version-select",
162
162
  sx: {
163
163
  display: "flex",
164
164
  alignItems: "center",
@@ -171,7 +171,7 @@ function E(u) {
171
171
  children: /* @__PURE__ */ g(x, { className: "HelpButton" })
172
172
  })]
173
173
  }), /* @__PURE__ */ _(Se, {
174
- id: "doi-version-select",
174
+ labelId: "doi-version-select",
175
175
  value: L ?? -1,
176
176
  onChange: (e) => {
177
177
  e.target.value === -1 ? R(void 0) : R(e.target.value);
@@ -191,15 +191,15 @@ function E(u) {
191
191
  }),
192
192
  /* @__PURE__ */ g("div", {
193
193
  className: "JsonSchemaFormContainer",
194
- children: /* @__PURE__ */ g(_e, {
194
+ children: /* @__PURE__ */ g(ge, {
195
195
  formRef: J,
196
196
  disabled: Q || $,
197
- schema: me,
197
+ schema: pe,
198
198
  formData: z,
199
199
  onChange: (e) => {
200
200
  B(e.formData);
201
201
  },
202
- uiSchema: he,
202
+ uiSchema: me,
203
203
  showErrorList: !1
204
204
  })
205
205
  }),
@@ -227,7 +227,7 @@ function E(u) {
227
227
  })
228
228
  })
229
229
  ] });
230
- return /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(pe, {
230
+ return /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(o, {
231
231
  open: we,
232
232
  onCancel: () => {
233
233
  j(!1);
@@ -239,7 +239,7 @@ function E(u) {
239
239
  open: y,
240
240
  onCancel: I,
241
241
  title: M === "warning" ? "This page is private" : "Create or Update a DOI",
242
- content: M ? /* @__PURE__ */ _(h, { children: [M === "warning" && /* @__PURE__ */ g(ge, {}), M === "form" && Pe] }) : /* @__PURE__ */ g(le, {}),
242
+ content: M ? /* @__PURE__ */ _(h, { children: [M === "warning" && /* @__PURE__ */ g(he, {}), M === "form" && Pe] }) : /* @__PURE__ */ g(le, {}),
243
243
  actions: /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(f, {
244
244
  variant: "outlined",
245
245
  disabled: Q,
@@ -1 +1 @@
1
- {"version":3,"file":"CreateOrUpdateDoiModal.js","names":[],"sources":["../../../src/components/doi/CreateOrUpdateDoiModal.tsx"],"sourcesContent":["import ConfirmCloseWithoutSavingDialog from '@/components/Dialog/ConfirmCloseWithoutSavingDialog'\nimport { DialogBase } from '@/components/DialogBase'\nimport { doiFormSchema, doiFormUiSchema } from '@/components/doi/DoiFormSchemas'\nimport { PrivateEntityDoiWarning } from '@/components/doi/PrivateEntityDoiWarning'\nimport { JsonSchemaForm } from '@/components/JsonSchemaForm/JsonSchemaForm'\nimport { MarkdownPopover } from '@/components/Markdown/MarkdownPopover'\nimport { StyledFormControl } from '@/components/styled/StyledFormControl'\nimport { displayToast } from '@/components/ToastMessage/ToastMessage'\nimport { useCreateOrUpdateDOI, useGetDOI } from '@/synapse-queries/doi/useDOI'\nimport { useGetVersions } from '@/synapse-queries/entity/useEntity'\nimport { useGetEntityBundle } from '@/synapse-queries/entity/useEntityBundle'\nimport { useGetPortal } from '@/synapse-queries/portal/usePortal'\nimport { useGetRealmPrincipals } from '@/synapse-queries/realm/useRealmPrincipals'\nimport { useGetCurrentUserProfile } from '@/synapse-queries/user/useUserBundle'\nimport { useGlobalIsEditingContext } from '@/utils/context/GlobalIsEditingContext'\nimport { isEntityPublic } from '@/utils/functions/AccessControlListUtils'\nimport {\n entityTypeToFriendlyName,\n isDataset,\n isTable,\n isVersionableEntity,\n} from '@/utils/functions/EntityTypeUtils'\nimport {\n BackendDestinationEnum,\n getEndpoint,\n} from '@/utils/functions/getEndpoint'\nimport { DATA_CATALOG_PATH_SEGMENT } from '@/utils/SynapseConstants'\nimport { HelpTwoTone } from '@mui/icons-material'\nimport {\n Alert,\n Button,\n InputLabel,\n Link,\n MenuItem,\n Select,\n TextField,\n Typography,\n} from '@mui/material'\nimport RJSF from '@rjsf/core'\nimport {\n DoiObjectType,\n DoiResourceTypeGeneral,\n DoiResourceTypeResourceTypeGeneralEnum,\n EntityType,\n V2Doi,\n} from '@sage-bionetworks/synapse-client'\nimport { isEmpty } from 'lodash-es'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport { SynapseSpinner } from '../LoadingScreen/LoadingScreen'\n\ntype CreateOrUpdateDoiModalStep = 'warning' | 'form'\n\nexport type CreateOrUpdateDoiModalProps = {\n /** Whether the dialog is open */\n open: boolean\n /** Callback to call when the dialog is closed */\n onClose: () => void\n /** The type of object */\n objectType: DoiObjectType\n /** The ID of the object */\n objectId: string\n /** The optional version number of the object used to populate the form. */\n defaultVersionNumber?: number\n /** If minting a DOI for a portal, the ID of the portal object in Synapse */\n portalId?: string\n}\n\ntype DoiFormData = {\n titles?: string[]\n creators?: string[]\n resourceTypeGeneral?: DoiResourceTypeResourceTypeGeneralEnum\n publicationYear?: number\n}\n\nfunction getSuggestedResourceTypeGeneral(\n type: EntityType,\n): DoiResourceTypeGeneral {\n if (type === EntityType.project || type === EntityType.folder) {\n return DoiResourceTypeGeneral.Collection\n } else {\n return DoiResourceTypeGeneral.Dataset\n }\n}\n\nfunction convertDoiToFormData(doi: V2Doi): DoiFormData {\n return {\n titles: (doi.titles || []).map(title => title.title!),\n creators: (doi.creators || []).map(creator => creator.creatorName!),\n resourceTypeGeneral: doi.resourceType?.resourceTypeGeneral,\n publicationYear: doi.publicationYear,\n }\n}\n\n/**\n * Returns true if the DOI has fields that are not exposed in the UI, so we can let the user know that any changes\n * may be destructive to hidden fields.\n */\nfunction getWasModifiedViaAPI(doi: V2Doi) {\n if (doi.creators?.some(creator => !isEmpty(creator.nameIdentifiers))) {\n return true\n }\n return false\n}\n\nfunction convertFormDataToDoi(formData: DoiFormData): V2Doi {\n return {\n titles: formData.titles?.map(title => ({ title })) || [],\n creators:\n formData.creators?.map(creator => ({ creatorName: creator })) || [],\n resourceType: {\n resourceTypeGeneral: formData.resourceTypeGeneral,\n },\n publicationYear: formData.publicationYear,\n }\n}\n\nexport function CreateOrUpdateDoiModal(props: CreateOrUpdateDoiModalProps) {\n const {\n open,\n onClose,\n objectType,\n objectId,\n defaultVersionNumber,\n portalId,\n } = props\n\n const [showConfirmCloseModal, setShowConfirmCloseDialog] = useState(false)\n const [currentStep, setCurrentStep] =\n useState<CreateOrUpdateDoiModalStep | null>(null)\n const hasSetInitialStepForThisSession = useRef(false)\n const { isEditing, setIsEditing } = useGlobalIsEditingContext()\n useEffect(() => {\n setIsEditing(open)\n\n return () => {\n setIsEditing(false)\n }\n }, [open, setIsEditing])\n\n function handleClose() {\n if (isEditing) {\n setShowConfirmCloseDialog(true)\n } else {\n onClose()\n }\n }\n\n const [selectedVersionNumber, setSelectedVersionNumber] =\n useState(defaultVersionNumber)\n\n const { data: portal } = useGetPortal(portalId!, {\n enabled: Boolean(portalId),\n })\n\n const [formData, setFormData] = useState<DoiFormData>({\n titles: [''],\n creators: [''],\n })\n const { data: currentUser, isLoading: isLoadingCurrentUser } =\n useGetCurrentUserProfile()\n const { data: entityBundle, isLoading: isLoadingEntity } = useGetEntityBundle(\n objectId,\n selectedVersionNumber,\n {\n includeEntity: true,\n includeBenefactorACL: true,\n },\n {\n enabled: objectType === DoiObjectType.ENTITY,\n staleTime: Infinity,\n throwOnError: true,\n },\n )\n const { data: realmPrincipals, isLoading: isLoadingRealmPrincipals } =\n useGetRealmPrincipals()\n const { data: doi, isLoading: isLoadingDoi } = useGetDOI(\n {\n id: objectId,\n version: selectedVersionNumber,\n type: objectType,\n portalId: portalId,\n },\n {\n staleTime: Infinity,\n throwOnError: true,\n },\n )\n\n const shouldShowWarning = useMemo(() => {\n if (objectType !== DoiObjectType.ENTITY) {\n return false\n }\n return (\n open &&\n doi === null && // Creating new DOI\n entityBundle?.benefactorAcl &&\n realmPrincipals &&\n !isEntityPublic(\n entityBundle.benefactorAcl.resourceAccess,\n realmPrincipals,\n )\n )\n }, [open, doi, entityBundle, realmPrincipals, objectType])\n\n useEffect(() => {\n if (\n open &&\n !hasSetInitialStepForThisSession.current &&\n doi !== undefined && // Wait for DOI query to resolve before determining step\n shouldShowWarning !== undefined\n ) {\n const newStep = shouldShowWarning ? 'warning' : 'form'\n setCurrentStep(newStep)\n hasSetInitialStepForThisSession.current = true\n } else if (!open) {\n setCurrentStep(null)\n hasSetInitialStepForThisSession.current = false\n }\n }, [shouldShowWarning, open, doi])\n\n const doiCanBeAppliedToVersion =\n objectType === DoiObjectType.ENTITY &&\n entityBundle?.entity &&\n isVersionableEntity(entityBundle.entity)\n\n const { data: entityVersions } = useGetVersions(\n objectId,\n undefined,\n undefined,\n {\n enabled: doiCanBeAppliedToVersion,\n },\n )\n const formRef = useRef<RJSF>(null)\n\n const entityType = entityBundle?.entityType ?? EntityType.file\n const entityTypeDisplay = entityTypeToFriendlyName(entityType)\n let versionHelpMarkdown = `A DOI can be associated with a specific version of this ${entityTypeDisplay}.\n \n Versioned DOIs will link to the specified version of the ${entityTypeDisplay}.\n \n A DOI without a version will always link to the newest version of this ${entityTypeDisplay},\n so the data that someone retrieves using the DOI may change over time.`\n if (entityBundle?.entity && isTable(entityBundle.entity)) {\n const tableVersionCopy = isDataset(entityBundle.entity)\n ? 'version'\n : 'snapshot'\n versionHelpMarkdown += `\\n\\nTo create a DOI that will always link to the current set of data in the ${entityTypeDisplay},\n create a new ${tableVersionCopy} and mint a DOI for that ${tableVersionCopy}.`\n }\n\n const {\n mutate: createOrUpdateDoi,\n isPending: updateIsPending,\n error: updateDoiError,\n } = useCreateOrUpdateDOI({\n onSuccess: () => {\n displayToast('The DOI was successfully updated.', 'success')\n onClose()\n },\n })\n\n const isLoading =\n updateIsPending ||\n isLoadingCurrentUser ||\n isLoadingEntity ||\n isLoadingDoi ||\n isLoadingRealmPrincipals\n\n const wasModifiedViaAPI = Boolean(doi && getWasModifiedViaAPI(doi))\n\n useEffect(() => {\n if (doi) {\n setFormData(convertDoiToFormData(doi))\n }\n // If there is no DOI, then pre-fill the form.\n if (currentUser && entityBundle?.entity && doi === null) {\n const newFormData = {\n titles: [entityBundle.entity.name],\n creators: new Array<string>(),\n resourceTypeGeneral: getSuggestedResourceTypeGeneral(\n entityBundle.entityType,\n ),\n publicationYear: new Date().getFullYear(),\n } satisfies DoiFormData\n if (currentUser.lastName && currentUser.firstName) {\n newFormData.creators.push(\n `${currentUser.lastName}, ${currentUser.firstName}`,\n )\n }\n setFormData(newFormData)\n }\n }, [currentUser, doi, entityBundle])\n\n function onSave() {\n if (formRef.current && formRef.current.validateForm()) {\n const requestDoi: V2Doi = convertFormDataToDoi(formData)\n requestDoi.objectType = objectType\n requestDoi.objectId = objectId\n requestDoi.objectVersion = selectedVersionNumber\n requestDoi.etag = doi?.etag\n requestDoi.portalId = portalId\n createOrUpdateDoi({\n doi: requestDoi,\n concreteType: 'org.sagebionetworks.repo.model.doi.v2.DoiRequest',\n })\n }\n }\n\n const dialogContent = (\n <>\n <Typography variant={'body1'} gutterBottom>\n Minting a DOI allows you to credit contributors and makes it easy to\n cite your work.\n </Typography>\n <Typography variant={'body1'} gutterBottom sx={{ mb: 2 }}>\n Note that while the DOI and its associated metadata will be publicly\n visible outside of Synapse, your data will still adhere to its existing\n access conditions. If your data is private, it will remain restricted,\n but the DOI will still be listed. Resources with DOIs may be added to\n the{' '}\n <Link\n href={`${getEndpoint(\n BackendDestinationEnum.PORTAL_ENDPOINT,\n )}${DATA_CATALOG_PATH_SEGMENT}`}\n target=\"_blank\"\n rel=\"noopener\"\n >\n Synapse Data Catalog\n </Link>\n .\n </Typography>\n {portalId && (\n <TextField\n label={'Publisher'}\n fullWidth\n value={portal?.name || ''}\n disabled\n />\n )}\n {doiCanBeAppliedToVersion && (\n <StyledFormControl className=\"limit-type\" fullWidth sx={{ my: 2 }}>\n <InputLabel\n htmlFor=\"doi-version-select\"\n sx={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n width: '100%',\n }}\n >\n <span>Version</span>\n <MarkdownPopover\n contentProps={{ markdown: versionHelpMarkdown }}\n maxWidth=\"350px\"\n >\n <HelpTwoTone className={`HelpButton`} />\n </MarkdownPopover>\n </InputLabel>\n <Select\n id=\"doi-version-select\"\n value={selectedVersionNumber ?? -1}\n onChange={e => {\n if (e.target.value === -1) {\n setSelectedVersionNumber(undefined)\n } else {\n setSelectedVersionNumber(e.target.value)\n }\n }}\n >\n <MenuItem value={-1}>No version</MenuItem>\n {entityVersions &&\n entityVersions.results.map(version => (\n <MenuItem\n key={version.versionNumber}\n value={version.versionNumber}\n >\n Version {version.versionNumber}\n {/* display the version label if it exists & is different from the number itself */}\n {version.versionLabel &&\n version.versionLabel !== String(version.versionNumber)\n ? ` / ${version.versionLabel}`\n : ''}\n </MenuItem>\n ))}\n </Select>\n </StyledFormControl>\n )}\n <div className=\"JsonSchemaFormContainer\">\n <JsonSchemaForm\n formRef={formRef}\n disabled={isLoading || wasModifiedViaAPI}\n schema={doiFormSchema}\n formData={formData}\n onChange={e => {\n setFormData(e.formData)\n }}\n uiSchema={doiFormUiSchema}\n showErrorList={false}\n />\n </div>\n {doi && (\n <Alert severity={'warning'}>\n <Typography variant={'body1'}>\n A DOI has already been created. Updating the DOI information will\n cause old information to be lost!\n </Typography>\n </Alert>\n )}\n {wasModifiedViaAPI && (\n <Alert severity={'warning'} sx={{ my: 1 }}>\n <Typography variant={'body1'}>\n The metadata for this DOI was modified using a programmatic client,\n so data may be hidden from this view. Any changes may result in\n metadata being lost.\n </Typography>\n </Alert>\n )}\n {updateDoiError && (\n <Alert severity={'error'} sx={{ mt: 1 }}>\n <Typography variant={'body1'}>{updateDoiError.message}</Typography>\n </Alert>\n )}\n </>\n )\n\n const dialogActions = (\n <>\n <Button variant=\"outlined\" disabled={isLoading} onClick={handleClose}>\n Cancel\n </Button>\n <Button\n variant=\"contained\"\n disabled={isLoading}\n onClick={\n currentStep === 'warning'\n ? () => setCurrentStep('form')\n : e => {\n // SWC-7055 - The default action may trigger `beforeunload` and erroneously warn the user about leaving the page.\n e.preventDefault()\n onSave()\n }\n }\n >\n {currentStep === 'warning' ? 'Continue' : 'Save'}\n </Button>\n </>\n )\n\n return (\n <>\n <ConfirmCloseWithoutSavingDialog\n open={showConfirmCloseModal}\n onCancel={() => {\n setShowConfirmCloseDialog(false)\n }}\n onConfirm={() => {\n setShowConfirmCloseDialog(false)\n onClose()\n }}\n />\n <DialogBase\n open={open}\n onCancel={handleClose}\n title={\n currentStep === 'warning'\n ? 'This page is private'\n : 'Create or Update a DOI'\n }\n content={\n !currentStep ? (\n <SynapseSpinner />\n ) : (\n <>\n {currentStep === 'warning' && <PrivateEntityDoiWarning />}\n {currentStep === 'form' && dialogContent}\n </>\n )\n }\n actions={dialogActions}\n />\n </>\n )\n}\n\nexport default CreateOrUpdateDoiModal\n"],"mappings":"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"}
1
+ {"version":3,"file":"CreateOrUpdateDoiModal.js","names":[],"sources":["../../../src/components/doi/CreateOrUpdateDoiModal.tsx"],"sourcesContent":["import ConfirmCloseWithoutSavingDialog from '@/components/Dialog/ConfirmCloseWithoutSavingDialog'\nimport { DialogBase } from '@/components/DialogBase'\nimport { doiFormSchema, doiFormUiSchema } from '@/components/doi/DoiFormSchemas'\nimport { PrivateEntityDoiWarning } from '@/components/doi/PrivateEntityDoiWarning'\nimport { JsonSchemaForm } from '@/components/JsonSchemaForm/JsonSchemaForm'\nimport { MarkdownPopover } from '@/components/Markdown/MarkdownPopover'\nimport { StyledFormControl } from '@/components/styled/StyledFormControl'\nimport { displayToast } from '@/components/ToastMessage/ToastMessage'\nimport { useCreateOrUpdateDOI, useGetDOI } from '@/synapse-queries/doi/useDOI'\nimport { useGetVersions } from '@/synapse-queries/entity/useEntity'\nimport { useGetEntityBundle } from '@/synapse-queries/entity/useEntityBundle'\nimport { useGetPortal } from '@/synapse-queries/portal/usePortal'\nimport { useGetRealmPrincipals } from '@/synapse-queries/realm/useRealmPrincipals'\nimport { useGetCurrentUserProfile } from '@/synapse-queries/user/useUserBundle'\nimport { useGlobalIsEditingContext } from '@/utils/context/GlobalIsEditingContext'\nimport { isEntityPublic } from '@/utils/functions/AccessControlListUtils'\nimport {\n entityTypeToFriendlyName,\n isDataset,\n isTable,\n isVersionableEntity,\n} from '@/utils/functions/EntityTypeUtils'\nimport {\n BackendDestinationEnum,\n getEndpoint,\n} from '@/utils/functions/getEndpoint'\nimport { DATA_CATALOG_PATH_SEGMENT } from '@/utils/SynapseConstants'\nimport { HelpTwoTone } from '@mui/icons-material'\nimport {\n Alert,\n Button,\n InputLabel,\n Link,\n MenuItem,\n Select,\n TextField,\n Typography,\n} from '@mui/material'\nimport RJSF from '@rjsf/core'\nimport {\n DoiObjectType,\n DoiResourceTypeGeneral,\n DoiResourceTypeResourceTypeGeneralEnum,\n EntityType,\n V2Doi,\n} from '@sage-bionetworks/synapse-client'\nimport { isEmpty } from 'lodash-es'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport { SynapseSpinner } from '../LoadingScreen/LoadingScreen'\n\ntype CreateOrUpdateDoiModalStep = 'warning' | 'form'\n\nexport type CreateOrUpdateDoiModalProps = {\n /** Whether the dialog is open */\n open: boolean\n /** Callback to call when the dialog is closed */\n onClose: () => void\n /** The type of object */\n objectType: DoiObjectType\n /** The ID of the object */\n objectId: string\n /** The optional version number of the object used to populate the form. */\n defaultVersionNumber?: number\n /** If minting a DOI for a portal, the ID of the portal object in Synapse */\n portalId?: string\n}\n\ntype DoiFormData = {\n titles?: string[]\n creators?: string[]\n resourceTypeGeneral?: DoiResourceTypeResourceTypeGeneralEnum\n publicationYear?: number\n}\n\nfunction getSuggestedResourceTypeGeneral(\n type: EntityType,\n): DoiResourceTypeGeneral {\n if (type === EntityType.project || type === EntityType.folder) {\n return DoiResourceTypeGeneral.Collection\n } else {\n return DoiResourceTypeGeneral.Dataset\n }\n}\n\nfunction convertDoiToFormData(doi: V2Doi): DoiFormData {\n return {\n titles: (doi.titles || []).map(title => title.title!),\n creators: (doi.creators || []).map(creator => creator.creatorName!),\n resourceTypeGeneral: doi.resourceType?.resourceTypeGeneral,\n publicationYear: doi.publicationYear,\n }\n}\n\n/**\n * Returns true if the DOI has fields that are not exposed in the UI, so we can let the user know that any changes\n * may be destructive to hidden fields.\n */\nfunction getWasModifiedViaAPI(doi: V2Doi) {\n if (doi.creators?.some(creator => !isEmpty(creator.nameIdentifiers))) {\n return true\n }\n return false\n}\n\nfunction convertFormDataToDoi(formData: DoiFormData): V2Doi {\n return {\n titles: formData.titles?.map(title => ({ title })) || [],\n creators:\n formData.creators?.map(creator => ({ creatorName: creator })) || [],\n resourceType: {\n resourceTypeGeneral: formData.resourceTypeGeneral,\n },\n publicationYear: formData.publicationYear,\n }\n}\n\nexport function CreateOrUpdateDoiModal(props: CreateOrUpdateDoiModalProps) {\n const {\n open,\n onClose,\n objectType,\n objectId,\n defaultVersionNumber,\n portalId,\n } = props\n\n const [showConfirmCloseModal, setShowConfirmCloseDialog] = useState(false)\n const [currentStep, setCurrentStep] =\n useState<CreateOrUpdateDoiModalStep | null>(null)\n const hasSetInitialStepForThisSession = useRef(false)\n const { isEditing, setIsEditing } = useGlobalIsEditingContext()\n useEffect(() => {\n setIsEditing(open)\n\n return () => {\n setIsEditing(false)\n }\n }, [open, setIsEditing])\n\n function handleClose() {\n if (isEditing) {\n setShowConfirmCloseDialog(true)\n } else {\n onClose()\n }\n }\n\n const [selectedVersionNumber, setSelectedVersionNumber] =\n useState(defaultVersionNumber)\n\n const { data: portal } = useGetPortal(portalId!, {\n enabled: Boolean(portalId),\n })\n\n const [formData, setFormData] = useState<DoiFormData>({\n titles: [''],\n creators: [''],\n })\n const { data: currentUser, isLoading: isLoadingCurrentUser } =\n useGetCurrentUserProfile()\n const { data: entityBundle, isLoading: isLoadingEntity } = useGetEntityBundle(\n objectId,\n selectedVersionNumber,\n {\n includeEntity: true,\n includeBenefactorACL: true,\n },\n {\n enabled: objectType === DoiObjectType.ENTITY,\n staleTime: Infinity,\n throwOnError: true,\n },\n )\n const { data: realmPrincipals, isLoading: isLoadingRealmPrincipals } =\n useGetRealmPrincipals()\n const { data: doi, isLoading: isLoadingDoi } = useGetDOI(\n {\n id: objectId,\n version: selectedVersionNumber,\n type: objectType,\n portalId: portalId,\n },\n {\n staleTime: Infinity,\n throwOnError: true,\n },\n )\n\n const shouldShowWarning = useMemo(() => {\n if (objectType !== DoiObjectType.ENTITY) {\n return false\n }\n return (\n open &&\n doi === null && // Creating new DOI\n entityBundle?.benefactorAcl &&\n realmPrincipals &&\n !isEntityPublic(\n entityBundle.benefactorAcl.resourceAccess,\n realmPrincipals,\n )\n )\n }, [open, doi, entityBundle, realmPrincipals, objectType])\n\n useEffect(() => {\n if (\n open &&\n !hasSetInitialStepForThisSession.current &&\n doi !== undefined && // Wait for DOI query to resolve before determining step\n shouldShowWarning !== undefined\n ) {\n const newStep = shouldShowWarning ? 'warning' : 'form'\n setCurrentStep(newStep)\n hasSetInitialStepForThisSession.current = true\n } else if (!open) {\n setCurrentStep(null)\n hasSetInitialStepForThisSession.current = false\n }\n }, [shouldShowWarning, open, doi])\n\n const doiCanBeAppliedToVersion =\n objectType === DoiObjectType.ENTITY &&\n entityBundle?.entity &&\n isVersionableEntity(entityBundle.entity)\n\n const { data: entityVersions } = useGetVersions(\n objectId,\n undefined,\n undefined,\n {\n enabled: doiCanBeAppliedToVersion,\n },\n )\n const formRef = useRef<RJSF>(null)\n\n const entityType = entityBundle?.entityType ?? EntityType.file\n const entityTypeDisplay = entityTypeToFriendlyName(entityType)\n let versionHelpMarkdown = `A DOI can be associated with a specific version of this ${entityTypeDisplay}.\n \n Versioned DOIs will link to the specified version of the ${entityTypeDisplay}.\n \n A DOI without a version will always link to the newest version of this ${entityTypeDisplay},\n so the data that someone retrieves using the DOI may change over time.`\n if (entityBundle?.entity && isTable(entityBundle.entity)) {\n const tableVersionCopy = isDataset(entityBundle.entity)\n ? 'version'\n : 'snapshot'\n versionHelpMarkdown += `\\n\\nTo create a DOI that will always link to the current set of data in the ${entityTypeDisplay},\n create a new ${tableVersionCopy} and mint a DOI for that ${tableVersionCopy}.`\n }\n\n const {\n mutate: createOrUpdateDoi,\n isPending: updateIsPending,\n error: updateDoiError,\n } = useCreateOrUpdateDOI({\n onSuccess: () => {\n displayToast('The DOI was successfully updated.', 'success')\n onClose()\n },\n })\n\n const isLoading =\n updateIsPending ||\n isLoadingCurrentUser ||\n isLoadingEntity ||\n isLoadingDoi ||\n isLoadingRealmPrincipals\n\n const wasModifiedViaAPI = Boolean(doi && getWasModifiedViaAPI(doi))\n\n useEffect(() => {\n if (doi) {\n setFormData(convertDoiToFormData(doi))\n }\n // If there is no DOI, then pre-fill the form.\n if (currentUser && entityBundle?.entity && doi === null) {\n const newFormData = {\n titles: [entityBundle.entity.name],\n creators: new Array<string>(),\n resourceTypeGeneral: getSuggestedResourceTypeGeneral(\n entityBundle.entityType,\n ),\n publicationYear: new Date().getFullYear(),\n } satisfies DoiFormData\n if (currentUser.lastName && currentUser.firstName) {\n newFormData.creators.push(\n `${currentUser.lastName}, ${currentUser.firstName}`,\n )\n }\n setFormData(newFormData)\n }\n }, [currentUser, doi, entityBundle])\n\n function onSave() {\n if (formRef.current && formRef.current.validateForm()) {\n const requestDoi: V2Doi = convertFormDataToDoi(formData)\n requestDoi.objectType = objectType\n requestDoi.objectId = objectId\n requestDoi.objectVersion = selectedVersionNumber\n requestDoi.etag = doi?.etag\n requestDoi.portalId = portalId\n createOrUpdateDoi({\n doi: requestDoi,\n concreteType: 'org.sagebionetworks.repo.model.doi.v2.DoiRequest',\n })\n }\n }\n\n const dialogContent = (\n <>\n <Typography variant={'body1'} gutterBottom>\n Minting a DOI allows you to credit contributors and makes it easy to\n cite your work.\n </Typography>\n <Typography variant={'body1'} gutterBottom sx={{ mb: 2 }}>\n Note that while the DOI and its associated metadata will be publicly\n visible outside of Synapse, your data will still adhere to its existing\n access conditions. If your data is private, it will remain restricted,\n but the DOI will still be listed. Resources with DOIs may be added to\n the{' '}\n <Link\n href={`${getEndpoint(\n BackendDestinationEnum.PORTAL_ENDPOINT,\n )}${DATA_CATALOG_PATH_SEGMENT}`}\n target=\"_blank\"\n rel=\"noopener\"\n >\n Synapse Data Catalog\n </Link>\n .\n </Typography>\n {portalId && (\n <TextField\n label={'Publisher'}\n fullWidth\n value={portal?.name || ''}\n disabled\n />\n )}\n {doiCanBeAppliedToVersion && (\n <StyledFormControl className=\"limit-type\" fullWidth sx={{ my: 2 }}>\n <InputLabel\n id=\"doi-version-select\"\n sx={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n width: '100%',\n }}\n >\n <span>Version</span>\n <MarkdownPopover\n contentProps={{ markdown: versionHelpMarkdown }}\n maxWidth=\"350px\"\n >\n <HelpTwoTone className={`HelpButton`} />\n </MarkdownPopover>\n </InputLabel>\n <Select\n labelId=\"doi-version-select\"\n value={selectedVersionNumber ?? -1}\n onChange={e => {\n if (e.target.value === -1) {\n setSelectedVersionNumber(undefined)\n } else {\n setSelectedVersionNumber(e.target.value)\n }\n }}\n >\n <MenuItem value={-1}>No version</MenuItem>\n {entityVersions &&\n entityVersions.results.map(version => (\n <MenuItem\n key={version.versionNumber}\n value={version.versionNumber}\n >\n Version {version.versionNumber}\n {/* display the version label if it exists & is different from the number itself */}\n {version.versionLabel &&\n version.versionLabel !== String(version.versionNumber)\n ? ` / ${version.versionLabel}`\n : ''}\n </MenuItem>\n ))}\n </Select>\n </StyledFormControl>\n )}\n <div className=\"JsonSchemaFormContainer\">\n <JsonSchemaForm\n formRef={formRef}\n disabled={isLoading || wasModifiedViaAPI}\n schema={doiFormSchema}\n formData={formData}\n onChange={e => {\n setFormData(e.formData)\n }}\n uiSchema={doiFormUiSchema}\n showErrorList={false}\n />\n </div>\n {doi && (\n <Alert severity={'warning'}>\n <Typography variant={'body1'}>\n A DOI has already been created. Updating the DOI information will\n cause old information to be lost!\n </Typography>\n </Alert>\n )}\n {wasModifiedViaAPI && (\n <Alert severity={'warning'} sx={{ my: 1 }}>\n <Typography variant={'body1'}>\n The metadata for this DOI was modified using a programmatic client,\n so data may be hidden from this view. Any changes may result in\n metadata being lost.\n </Typography>\n </Alert>\n )}\n {updateDoiError && (\n <Alert severity={'error'} sx={{ mt: 1 }}>\n <Typography variant={'body1'}>{updateDoiError.message}</Typography>\n </Alert>\n )}\n </>\n )\n\n const dialogActions = (\n <>\n <Button variant=\"outlined\" disabled={isLoading} onClick={handleClose}>\n Cancel\n </Button>\n <Button\n variant=\"contained\"\n disabled={isLoading}\n onClick={\n currentStep === 'warning'\n ? () => setCurrentStep('form')\n : e => {\n // SWC-7055 - The default action may trigger `beforeunload` and erroneously warn the user about leaving the page.\n e.preventDefault()\n onSave()\n }\n }\n >\n {currentStep === 'warning' ? 'Continue' : 'Save'}\n </Button>\n </>\n )\n\n return (\n <>\n <ConfirmCloseWithoutSavingDialog\n open={showConfirmCloseModal}\n onCancel={() => {\n setShowConfirmCloseDialog(false)\n }}\n onConfirm={() => {\n setShowConfirmCloseDialog(false)\n onClose()\n }}\n />\n <DialogBase\n open={open}\n onCancel={handleClose}\n title={\n currentStep === 'warning'\n ? 'This page is private'\n : 'Create or Update a DOI'\n }\n content={\n !currentStep ? (\n <SynapseSpinner />\n ) : (\n <>\n {currentStep === 'warning' && <PrivateEntityDoiWarning />}\n {currentStep === 'form' && dialogContent}\n </>\n )\n }\n actions={dialogActions}\n />\n </>\n )\n}\n\nexport default CreateOrUpdateDoiModal\n"],"mappings":"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"}