synapse-react-client 4.0.9 → 4.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/SWC.index.d.ts +1 -0
- package/dist/SWC.index.d.ts.map +1 -1
- package/dist/SWC.index.js +2 -1
- package/dist/SWC.index.js.map +1 -1
- package/dist/aridhia-queries/aridhiaTokenExchange.js.map +1 -1
- package/dist/aridhia-queries/useGetAridhiaRequests.js.map +1 -1
- package/dist/assets/icons/CloudWarning.d.ts +5 -0
- package/dist/assets/icons/CloudWarning.d.ts.map +1 -0
- package/dist/assets/icons/CloudWarning.js +47 -0
- package/dist/assets/icons/CloudWarning.js.map +1 -0
- package/dist/assets/icons/TasksIcon.d.ts.map +1 -1
- package/dist/assets/icons/TasksIcon.js +6 -10
- package/dist/assets/icons/TasksIcon.js.map +1 -1
- package/dist/components/AccessRequirementAclEditor/AccessRequirementAclEditor.d.ts.map +1 -1
- package/dist/components/AccessRequirementAclEditor/AccessRequirementAclEditor.js +69 -63
- package/dist/components/AccessRequirementAclEditor/AccessRequirementAclEditor.js.map +1 -1
- package/dist/components/AccessRequirementList/AccessApprovalCheckMark.js.map +1 -1
- package/dist/components/AccessRequirementList/AccessRequirementList.js.map +1 -1
- package/dist/components/AccessRequirementList/AccessRequirementListUtils.js.map +1 -1
- package/dist/components/AccessRequirementList/ManagedACTAccessRequirementRequestFlow/DataAccessRequestAccessorsEditor.js.map +1 -1
- package/dist/components/AccessRequirementList/RequirementItem/SelfSignAccessRequirementItem.js.map +1 -1
- package/dist/components/AccessRequirementRelatedProjectsList/AccessRequirementRelatedProjectsList.js.map +1 -1
- package/dist/components/AccessTokenPage/AccessTokenCard/AccessTokenCard.js.map +1 -1
- package/dist/components/AcknowledgementsPage/StudyAcknowledgements.js.map +1 -1
- package/dist/components/AclEditor/PermissionLevelMenu.js.map +1 -1
- package/dist/components/AclEditor/ResourceAccessAndUserGroupHeader.js.map +1 -1
- package/dist/components/AclEditor/useSortResourceAccessList.js.map +1 -1
- package/dist/components/AclEditor/useUpdateAcl.js.map +1 -1
- package/dist/components/Aridhia/AridhiaAccessStatus.js.map +1 -1
- package/dist/components/Authentication/AuthenticationMethodSelection.d.ts.map +1 -1
- package/dist/components/Authentication/AuthenticationMethodSelection.js +38 -37
- package/dist/components/Authentication/AuthenticationMethodSelection.js.map +1 -1
- package/dist/components/Authentication/Constants.d.ts +1 -0
- package/dist/components/Authentication/Constants.d.ts.map +1 -1
- package/dist/components/Authentication/Constants.js +2 -2
- package/dist/components/Authentication/Constants.js.map +1 -1
- package/dist/components/Authentication/LastLoginInfo.js.map +1 -1
- package/dist/components/Authentication/RecoveryCodeForm.js.map +1 -1
- package/dist/components/Authentication/RecoveryCodeGrid.js.map +1 -1
- package/dist/components/Authentication/RegenerateBackupCodesWarning.js.map +1 -1
- package/dist/components/Authentication/Reset2FAWarning.js.map +1 -1
- package/dist/components/Authentication/StandaloneLoginForm.js +1 -1
- package/dist/components/Authentication/TwoFactorBackupCodes.js.map +1 -1
- package/dist/components/Authentication/TwoFactorEnrollmentForm.d.ts.map +1 -1
- package/dist/components/Authentication/TwoFactorEnrollmentForm.js +2 -1
- package/dist/components/Authentication/TwoFactorEnrollmentForm.js.map +1 -1
- package/dist/components/BasePortalCard/ColorfulPortalCardWithChips/ColorfulPortalCardWithChips.js.map +1 -1
- package/dist/components/CardContainer/CardContainer.js.map +1 -1
- package/dist/components/CardDeck/CardDeck.Mobile.js.map +1 -1
- package/dist/components/CardDeck/TableQueryCardDeck.js.map +1 -1
- package/dist/components/CertificationQuiz/CertificationQuiz.js.map +1 -1
- package/dist/components/ChallengeDataDownload/ChallengeDataDownload.js.map +1 -1
- package/dist/components/ChallengeSubmission/ChallengeSubmission.js.map +1 -1
- package/dist/components/ChallengeSubmission/ChallengeSubmissionStepper.js.map +1 -1
- package/dist/components/ChallengeSubmission/EvaluationQueueCurrentRoundInfo.js.map +1 -1
- package/dist/components/ChallengeSubmission/EvaluationQueueList.js.map +1 -1
- package/dist/components/ChallengeSubmission/SubmissionDirectoryList.d.ts.map +1 -1
- package/dist/components/ChallengeSubmission/SubmissionDirectoryList.js +143 -140
- package/dist/components/ChallengeSubmission/SubmissionDirectoryList.js.map +1 -1
- package/dist/components/ChallengeTeamWizard/ChallengeTeamWizard.js.map +1 -1
- package/dist/components/ChallengeTeamWizard/CreateChallengeTeam.js.map +1 -1
- package/dist/components/ChangePassword/ChangePassword.js.map +1 -1
- package/dist/components/ChangePassword/ChangePasswordWithToken.js.map +1 -1
- package/dist/components/ChangePassword/useChangePasswordFormState.js +1 -1
- package/dist/components/ChangePassword/useChangePasswordFormState.js.map +1 -1
- package/dist/components/CitationPopover/CitationPopoverContent.js.map +1 -1
- package/dist/components/ColumnFilter/ColumnFilter.js.map +1 -1
- package/dist/components/ComponentCollapse.js.map +1 -1
- package/dist/components/CookiesNotification/CookiesNotification.js.map +1 -1
- package/dist/components/CreateProjectModal/CreateProjectModal.js.map +1 -1
- package/dist/components/CreateTableViewWizard/CreateTableViewWizardUtils.js.map +1 -1
- package/dist/components/DataGrid/DataGrid.d.ts +0 -1
- package/dist/components/DataGrid/DataGrid.d.ts.map +1 -1
- package/dist/components/DataGrid/DataGrid.js +72 -72
- package/dist/components/DataGrid/DataGrid.js.map +1 -1
- package/dist/components/DataGrid/DataGridWebSocket.d.ts +4 -0
- package/dist/components/DataGrid/DataGridWebSocket.d.ts.map +1 -1
- package/dist/components/DataGrid/DataGridWebSocket.js +9 -8
- package/dist/components/DataGrid/DataGridWebSocket.js.map +1 -1
- package/dist/components/DataGrid/SynapseGrid.d.ts.map +1 -1
- package/dist/components/DataGrid/SynapseGrid.js +326 -268
- package/dist/components/DataGrid/SynapseGrid.js.map +1 -1
- package/dist/components/DataGrid/columns/AutocompleteColumn.d.ts +2 -0
- package/dist/components/DataGrid/columns/AutocompleteColumn.d.ts.map +1 -1
- package/dist/components/DataGrid/columns/AutocompleteColumn.js +124 -67
- package/dist/components/DataGrid/columns/AutocompleteColumn.js.map +1 -1
- package/dist/components/DataGrid/columns/AutocompleteMultipleEnumColumn.d.ts +2 -1
- package/dist/components/DataGrid/columns/AutocompleteMultipleEnumColumn.d.ts.map +1 -1
- package/dist/components/DataGrid/columns/AutocompleteMultipleEnumColumn.js +126 -122
- package/dist/components/DataGrid/columns/AutocompleteMultipleEnumColumn.js.map +1 -1
- package/dist/components/DataGrid/columns/useGridAutocompleteState.d.ts +58 -0
- package/dist/components/DataGrid/columns/useGridAutocompleteState.d.ts.map +1 -0
- package/dist/components/DataGrid/columns/useGridAutocompleteState.js +52 -0
- package/dist/components/DataGrid/columns/useGridAutocompleteState.js.map +1 -0
- package/dist/components/DataGrid/components/ValidationAlert.d.ts +5 -2
- package/dist/components/DataGrid/components/ValidationAlert.d.ts.map +1 -1
- package/dist/components/DataGrid/components/ValidationAlert.js +429 -24
- package/dist/components/DataGrid/components/ValidationAlert.js.map +1 -1
- package/dist/components/DataGrid/hooks/useColumnResizeHandles.js.map +1 -1
- package/dist/components/DataGrid/hooks/useGetSchemaForGrid.js.map +1 -1
- package/dist/components/DataGrid/hooks/useGridUndoRedo.js.map +1 -1
- package/dist/components/DataGrid/hooks/useStack.js.map +1 -1
- package/dist/components/DataGrid/useCRDTModelView.js.map +1 -1
- package/dist/components/DataGrid/useDataGridWebsocket.d.ts +7 -0
- package/dist/components/DataGrid/useDataGridWebsocket.d.ts.map +1 -1
- package/dist/components/DataGrid/useDataGridWebsocket.js +16 -2
- package/dist/components/DataGrid/useDataGridWebsocket.js.map +1 -1
- package/dist/components/DataGrid/useInitializeGridConnection.js.map +1 -1
- package/dist/components/DataGrid/useMergeGridWithRecordSet.js.map +1 -1
- package/dist/components/DataGrid/useMergeGridWithSource.js.map +1 -1
- package/dist/components/DataGrid/useMergeGridWithTable.js.map +1 -1
- package/dist/components/DataGrid/utils/DataGridUtils.js.map +1 -1
- package/dist/components/DataGrid/utils/applyModelChange.d.ts +1 -1
- package/dist/components/DataGrid/utils/applyModelChange.d.ts.map +1 -1
- package/dist/components/DataGrid/utils/applyModelChange.js +27 -24
- package/dist/components/DataGrid/utils/applyModelChange.js.map +1 -1
- package/dist/components/DataGrid/utils/columnFactory.d.ts +8 -0
- package/dist/components/DataGrid/utils/columnFactory.d.ts.map +1 -1
- package/dist/components/DataGrid/utils/columnFactory.js +47 -44
- package/dist/components/DataGrid/utils/columnFactory.js.map +1 -1
- package/dist/components/DataGrid/utils/computeReplicaSelectionModel.js.map +1 -1
- package/dist/components/DataGrid/utils/extractColumnValidationMessages.js.map +1 -1
- package/dist/components/DataGrid/utils/getCellClassName.d.ts.map +1 -1
- package/dist/components/DataGrid/utils/getCellClassName.js +8 -8
- package/dist/components/DataGrid/utils/getCellClassName.js.map +1 -1
- package/dist/components/DataGrid/utils/getEmptyValue.d.ts +2 -0
- package/dist/components/DataGrid/utils/getEmptyValue.d.ts.map +1 -0
- package/dist/components/DataGrid/utils/getEmptyValue.js +8 -0
- package/dist/components/DataGrid/utils/getEmptyValue.js.map +1 -0
- package/dist/components/DataGrid/utils/json-rx/JsonRx.js.map +1 -1
- package/dist/components/DataGrid/utils/modelColsToGrid.d.ts.map +1 -1
- package/dist/components/DataGrid/utils/modelColsToGrid.js +2 -1
- package/dist/components/DataGrid/utils/modelColsToGrid.js.map +1 -1
- package/dist/components/DataGrid/utils/modelRowsToGrid.js.map +1 -1
- package/dist/components/DataGrid/utils/parseFreeTextUsingJsonSchemaType.js.map +1 -1
- package/dist/components/DataGrid/utils/schemaAwarePasteValue.d.ts +32 -0
- package/dist/components/DataGrid/utils/schemaAwarePasteValue.d.ts.map +1 -0
- package/dist/components/DataGrid/utils/schemaAwarePasteValue.js +22 -0
- package/dist/components/DataGrid/utils/schemaAwarePasteValue.js.map +1 -0
- package/dist/components/DataGrid/utils/splitPatch.js.map +1 -1
- package/dist/components/DateTimePicker/DateTimePicker.js.map +1 -1
- package/dist/components/DirectDownload/DirectDownload.js.map +1 -1
- package/dist/components/DirectDownloadButton.js.map +1 -1
- package/dist/components/DownloadCart/CreatePackageV2.js.map +1 -1
- package/dist/components/DownloadCart/DownloadIneligibleForPackagingFilesFromListButton.css +1 -0
- package/dist/components/DownloadCart/DownloadIneligibleForPackagingFilesFromListButton.d.ts.map +1 -1
- package/dist/components/DownloadCart/DownloadIneligibleForPackagingFilesFromListButton.js +199 -132
- package/dist/components/DownloadCart/DownloadIneligibleForPackagingFilesFromListButton.js.map +1 -1
- package/dist/components/DownloadCart/DownloadIneligibleForPackagingFilesFromListButton.module.js +22 -0
- package/dist/components/DownloadCart/DownloadIneligibleForPackagingFilesFromListButton.module.js.map +1 -0
- package/dist/components/DownloadCart/DownloadIneligibleForPackagingFilesFromListButton.module.scss +170 -0
- package/dist/components/DownloadCart/DownloadListActionsRequired.js.map +1 -1
- package/dist/components/DownloadCart/DownloadListTable.js.map +1 -1
- package/dist/components/DownloadCart/fileNameUtils.js.map +1 -1
- package/dist/components/DraggableDialog/DraggableDialog.js.map +1 -1
- package/dist/components/DynamicForm/DynamicFormModal.js.map +1 -1
- package/dist/components/Ecosystem/TableQueryEcosystem.js.map +1 -1
- package/dist/components/EntityAclEditor/EntityAclEditor.d.ts.map +1 -1
- package/dist/components/EntityAclEditor/EntityAclEditor.js +103 -103
- package/dist/components/EntityAclEditor/EntityAclEditor.js.map +1 -1
- package/dist/components/EntityAclEditor/useNotifyNewACLUsers.js.map +1 -1
- package/dist/components/EntityBadgeIcons/EntityBadgeIcons.js.map +1 -1
- package/dist/components/EntityCitation/EntityCitation.js.map +1 -1
- package/dist/components/EntityDownloadButton/EntityDownloadButton.d.ts.map +1 -1
- package/dist/components/EntityDownloadButton/EntityDownloadButton.js +1 -0
- package/dist/components/EntityDownloadButton/EntityDownloadButton.js.map +1 -1
- package/dist/components/EntityDownloadConfirmation/EntityDownloadConfirmation.d.ts.map +1 -1
- package/dist/components/EntityDownloadConfirmation/EntityDownloadConfirmation.js +36 -30
- package/dist/components/EntityDownloadConfirmation/EntityDownloadConfirmation.js.map +1 -1
- package/dist/components/EntityFinder/EntityFinder.js.map +1 -1
- package/dist/components/EntityFinder/VersionSelectionType.js.map +1 -1
- package/dist/components/EntityFinder/details/configurations/EntityChildrenDetails.js.map +1 -1
- package/dist/components/EntityFinder/details/configurations/FavoritesDetails.js.map +1 -1
- package/dist/components/EntityFinder/details/configurations/ProjectListDetails.js.map +1 -1
- package/dist/components/EntityFinder/details/view/DetailsView.js.map +1 -1
- package/dist/components/EntityFinder/tree/EntityTree.js.map +1 -1
- package/dist/components/EntityFinder/tree/VirtualizedTree.js.map +1 -1
- package/dist/components/EntityFinder/useEntitySelection.js.map +1 -1
- package/dist/components/EntityForm/EntityForm.js.map +1 -1
- package/dist/components/EntityHeaderTable/EntityHeaderTable.js.map +1 -1
- package/dist/components/EntityHeaderTable/Filter.js.map +1 -1
- package/dist/components/EntityHeaderTable/useEntityHeaderTableState.js.map +1 -1
- package/dist/components/EntitySubjectsSelector/EntitySubjectsSelector.js.map +1 -1
- package/dist/components/EntityTreeTable/components/IdColumnHeader.js.map +1 -1
- package/dist/components/EntityTreeTable/hooks/useEntityTreeState.js.map +1 -1
- package/dist/components/EntityTreeTable/hooks/useTableColumns.js.map +1 -1
- package/dist/components/EntityTreeTable/hooks/useTableData.js.map +1 -1
- package/dist/components/EntityTreeTable/hooks/useTreeOperationsWithDirectFetch.js.map +1 -1
- package/dist/components/EntityUpload/EntityUpload.js.map +1 -1
- package/dist/components/EntityViewScopeEditor/EntityViewMaskEditor.d.ts.map +1 -1
- package/dist/components/EntityViewScopeEditor/EntityViewMaskEditor.js +15 -14
- package/dist/components/EntityViewScopeEditor/EntityViewMaskEditor.js.map +1 -1
- package/dist/components/ExperimentalMode/ExperimentalMode.js.map +1 -1
- package/dist/components/ExternalFileHandleLink/ExternalFileHandleLink.js.map +1 -1
- package/dist/components/FeaturedDataTabs/FacetPlotsCard.js.map +1 -1
- package/dist/components/FeaturedDataTabs/QueryPerFacetPlotsCard.js.map +1 -1
- package/dist/components/FeaturedDataTabs/SingleQueryFacetPlotsCards.js.map +1 -1
- package/dist/components/FeaturedResearch/FeaturedResearch.js.map +1 -1
- package/dist/components/FeaturedToolsList/FeaturedToolsList.js.map +1 -1
- package/dist/components/FilePreview/FileHandleContentRenderer.js.map +1 -1
- package/dist/components/FilePreview/HtmlPreview/HtmlPreview.js.map +1 -1
- package/dist/components/FilePreview/PreviewRendererType.js.map +1 -1
- package/dist/components/Forum/DiscussionReply.d.ts +1 -0
- package/dist/components/Forum/DiscussionReply.d.ts.map +1 -1
- package/dist/components/Forum/DiscussionReply.js +19 -19
- package/dist/components/Forum/DiscussionReply.js.map +1 -1
- package/dist/components/Forum/DiscussionSearchResult.js.map +1 -1
- package/dist/components/Forum/DiscussionThread.d.ts +1 -0
- package/dist/components/Forum/DiscussionThread.d.ts.map +1 -1
- package/dist/components/Forum/DiscussionThread.js +73 -72
- package/dist/components/Forum/DiscussionThread.js.map +1 -1
- package/dist/components/Forum/ForumTable.js.map +1 -1
- package/dist/components/Forum/ForumThreadEditor.js.map +1 -1
- package/dist/components/FullTextSearch/FullTextSearchUtils.js.map +1 -1
- package/dist/components/GenericCard/BioregistryRules.d.ts.map +1 -1
- package/dist/components/GenericCard/BioregistryRules.js +7 -3
- package/dist/components/GenericCard/BioregistryRules.js.map +1 -1
- package/dist/components/GenericCard/GenericCard.d.ts.map +1 -1
- package/dist/components/GenericCard/GenericCard.js +12 -7
- package/dist/components/GenericCard/GenericCard.js.map +1 -1
- package/dist/components/GenericCard/Linkify.js.map +1 -1
- package/dist/components/GenericCard/SynapseCardLabel.js.map +1 -1
- package/dist/components/GenericCard/TableRowGenericCard.js +105 -105
- package/dist/components/GenericCard/TableRowGenericCard.js.map +1 -1
- package/dist/components/Goals/Goals.Mobile.js.map +1 -1
- package/dist/components/Goals/Goals.js.map +1 -1
- package/dist/components/GoalsV2/GoalsV2.Mobile.js.map +1 -1
- package/dist/components/GoalsV2/GoalsV2.js.map +1 -1
- package/dist/components/GoalsV3/GoalsV3.Mobile.js.map +1 -1
- package/dist/components/GoalsV3/GoalsV3.js.map +1 -1
- package/dist/components/GoogleMap/SynapseUserMarker.js.map +1 -1
- package/dist/components/HasAccess/AccessIcon.js.map +1 -1
- package/dist/components/HasAccess/useHasAccess.js.map +1 -1
- package/dist/components/HeaderCard/HeaderCardV2.js.map +1 -1
- package/dist/components/HeaderCard.d.ts +6 -1
- package/dist/components/HeaderCard.d.ts.map +1 -1
- package/dist/components/HeaderCard.js +107 -76
- package/dist/components/HeaderCard.js.map +1 -1
- package/dist/components/HexGrid/HexGrid.js.map +1 -1
- package/dist/components/IconList.js.map +1 -1
- package/dist/components/IconSvg/IconSvg.d.ts.map +1 -1
- package/dist/components/IconSvg/IconSvg.js +2 -1
- package/dist/components/IconSvg/IconSvg.js.map +1 -1
- package/dist/components/ImageCardGridWithLinks/ImageCardGridWithLinks.js.map +1 -1
- package/dist/components/ImageFromSynapseTable.js.map +1 -1
- package/dist/components/JSONArrayEditor/useParseCsv.js.map +1 -1
- package/dist/components/JsonSchemaForm/templates/ArrayFieldDescriptionTemplate.js.map +1 -1
- package/dist/components/JsonSchemaForm/templates/ArrayFieldItemTemplate.js.map +1 -1
- package/dist/components/JsonSchemaForm/templates/BaseInputTemplate.js.map +1 -1
- package/dist/components/JsonSchemaForm/templates/FieldTemplate.js.map +1 -1
- package/dist/components/JsonSchemaForm/templates/RJSFInputLabel.js.map +1 -1
- package/dist/components/Markdown/MarkdownGithub.js.map +1 -1
- package/dist/components/Markdown/MarkdownSynapse.js.map +1 -1
- package/dist/components/Markdown/MarkdownUtils.js.map +1 -1
- package/dist/components/Markdown/SynapseWikiContext.js.map +1 -1
- package/dist/components/Markdown/UserMentionModal.js.map +1 -1
- package/dist/components/Markdown/widget/MarkdownProvenanceGraph.js.map +1 -1
- package/dist/components/MissingQueryResultsWarning/MissingQueryResultsWarning.js.map +1 -1
- package/dist/components/ModalDownload/ModalDownload.js.map +1 -1
- package/dist/components/OAuthClientAclEditor/OAuthClientAclEditor.d.ts.map +1 -1
- package/dist/components/OAuthClientAclEditor/OAuthClientAclEditor.js +45 -39
- package/dist/components/OAuthClientAclEditor/OAuthClientAclEditor.js.map +1 -1
- package/dist/components/OAuthClientManagement/OAuthManagement.js.map +1 -1
- package/dist/components/PageProgress/PageProgress.js.map +1 -1
- package/dist/components/Plot/DotPlot.js.map +1 -1
- package/dist/components/Plot/Plot.js.map +1 -1
- package/dist/components/Plot/SynapsePlot.js.map +1 -1
- package/dist/components/Plot/ThemesPlot.js.map +1 -1
- package/dist/components/Plot/UpsetPlot.js.map +1 -1
- package/dist/components/PortalAclEditor/PortalAclEditor.d.ts.map +1 -1
- package/dist/components/PortalAclEditor/PortalAclEditor.js +43 -41
- package/dist/components/PortalAclEditor/PortalAclEditor.js.map +1 -1
- package/dist/components/PortalFeaturedPartners/PortalFeaturedPartners.js.map +1 -1
- package/dist/components/PortalList/CreatePortalModal.js.map +1 -1
- package/dist/components/ProgrammaticInstructionsModal/ProgrammaticInstructionsModal.js.map +1 -1
- package/dist/components/ProgrammaticTableDownload/ProgrammaticTableDownload.js.map +1 -1
- package/dist/components/Programs/Programs.Mobile.js.map +1 -1
- package/dist/components/Programs/Programs.js.map +1 -1
- package/dist/components/ProvenanceGraph/ProvenanceExternalIcon.js.map +1 -1
- package/dist/components/ProvenanceGraph/ProvenanceGraph.js.map +1 -1
- package/dist/components/ProvenanceGraph/ProvenanceGraphUtils.js.map +1 -1
- package/dist/components/ProvenanceGraph/ProvenanceUtils.js.map +1 -1
- package/dist/components/QueryCount/QueryCount.js.map +1 -1
- package/dist/components/QueryCountButton/QueryCountButton.js.map +1 -1
- package/dist/components/QueryVisualizationWrapper/QueryVisualizationWrapper.js.map +1 -1
- package/dist/components/QueryWrapper/QueryWrapper.js.map +1 -1
- package/dist/components/QueryWrapper/TableQueryUseQueryOptions.js.map +1 -1
- package/dist/components/QueryWrapper/TableRowSelectionState.js.map +1 -1
- package/dist/components/QueryWrapper/generateEncodedPathAndQueryForSelectedFacetURL.js.map +1 -1
- package/dist/components/QueryWrapper/useGetQueryMetadata.js.map +1 -1
- package/dist/components/QueryWrapperErrorBoundary.js.map +1 -1
- package/dist/components/QueryWrapperPlotNav/QueryWrapperPlotNav.js.map +1 -1
- package/dist/components/QueryWrapperPlotNav/UseRowSet.js.map +1 -1
- package/dist/components/RecentPublicationsGrid/RecentPublicationsGrid.js.map +1 -1
- package/dist/components/ReleaseCard/ReleaseCardUtils.js.map +1 -1
- package/dist/components/ResizableContainer/hooks/useResizable.js.map +1 -1
- package/dist/components/Resources/Resources.Mobile.js.map +1 -1
- package/dist/components/Resources/Resources.js.map +1 -1
- package/dist/components/RowDataTable/RowDataTableWithQuery.js.map +1 -1
- package/dist/components/SageResourcesPopover/SageResourcesPopover.js.map +1 -1
- package/dist/components/SchemaDrivenAnnotationEditor/AnnotationEditorUtils.js.map +1 -1
- package/dist/components/SetAccessRequirementCommonFields/SetAccessRequirementCommonFields.js.map +1 -1
- package/dist/components/SetManagedAccessRequirementFields/SetManagedAccessRequirementFields.js.map +1 -1
- package/dist/components/SmartLink/SmartButton.js.map +1 -1
- package/dist/components/SmartLink/SmartLink.js.map +1 -1
- package/dist/components/SourceAppImage.js.map +1 -1
- package/dist/components/StandaloneQueryWrapper/StandaloneQueryWrapper.js.map +1 -1
- package/dist/components/StatisticsPlot.js.map +1 -1
- package/dist/components/StorybookComponentWrapper.js.map +1 -1
- package/dist/components/SubsectionRowRenderer/SubsectionRowRenderer.js.map +1 -1
- package/dist/components/SustainabilityScorecard/SustainabilityScorecard.js.map +1 -1
- package/dist/components/SynapseChat/GridAgentChat.js.map +1 -1
- package/dist/components/SynapseChat/SynapseChatInteraction.js.map +1 -1
- package/dist/components/SynapseChat/SynapseChatMessage.js.map +1 -1
- package/dist/components/SynapseChat/extractMessageFromTraceEvent.js.map +1 -1
- package/dist/components/SynapseForm/StepsSideNav.js.map +1 -1
- package/dist/components/SynapseForm/SummaryTable.js.map +1 -1
- package/dist/components/SynapseForm/SynapseForm.js +4 -2
- package/dist/components/SynapseForm/SynapseForm.js.map +1 -1
- package/dist/components/SynapseForm/SynapseFormWrapper.js.map +1 -1
- package/dist/components/SynapseHomepageV2/SynapseByTheNumbersItem.js.map +1 -1
- package/dist/components/SynapseHomepageV2/SynapseFeatureItem.js.map +1 -1
- package/dist/components/SynapseHomepageV2/SynapseHomepageChatSearch.js.map +1 -1
- package/dist/components/SynapseHomepageV2/SynapseHomepageSearch.js.map +1 -1
- package/dist/components/SynapseHomepageV2/SynapseInActionItem.js.map +1 -1
- package/dist/components/SynapseHomepageV2/SynapsePlans.js.map +1 -1
- package/dist/components/SynapseHomepageV2/SynapseTrendingProjects.js.map +1 -1
- package/dist/components/SynapseNavDrawer/SynapseNavDrawer.d.ts +8 -7
- package/dist/components/SynapseNavDrawer/SynapseNavDrawer.d.ts.map +1 -1
- package/dist/components/SynapseNavDrawer/SynapseNavDrawer.js +173 -164
- package/dist/components/SynapseNavDrawer/SynapseNavDrawer.js.map +1 -1
- package/dist/components/SynapsePortalBanners/SynapsePortalBanners.js.map +1 -1
- package/dist/components/SynapseSearchPageResults/SearchFacetPanel/SearchFacetPanel.js.map +1 -1
- package/dist/components/SynapseSearchPageResults/SearchFacetPanel/SearchFacetPanelUtils.js.map +1 -1
- package/dist/components/SynapseSearchPageResults/SynapseSearchPageResults.js.map +1 -1
- package/dist/components/SynapseTable/EntityIDColumnCopyIcon.js.map +1 -1
- package/dist/components/SynapseTable/NoContentPlaceholderType.js.map +1 -1
- package/dist/components/SynapseTable/RowSelection/RowSelectionControls.js.map +1 -1
- package/dist/components/SynapseTable/SynapseTableCell/SynapseTableCell.js.map +1 -1
- package/dist/components/SynapseTable/SynapseTableRenderers.js.map +1 -1
- package/dist/components/SynapseTable/datasets/DatasetItemsEditor.js.map +1 -1
- package/dist/components/SynapseTable/table-top/ColumnSelection.js.map +1 -1
- package/dist/components/SynapseTable/table-top/DownloadOptions.js.map +1 -1
- package/dist/components/SynapseTable/usePrefetchTableData.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/ColumnModelForm.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/ColumnModelFormFields/DefaultValueField.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/ImportTableColumnsButton.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/TableColumnSchemaEditorUtils.d.ts +1 -1
- package/dist/components/TableColumnSchemaEditor/TableColumnSchemaEditorUtils.d.ts.map +1 -1
- package/dist/components/TableColumnSchemaEditor/TableColumnSchemaEditorUtils.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/TableColumnSchemaForm.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/TableColumnSchemaFormReducer.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/Validators/ColumnModelValidator.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/Validators/DatetimeSchema.js.map +1 -1
- package/dist/components/TanStackTable/ColumnHeader.d.ts +1 -0
- package/dist/components/TanStackTable/ColumnHeader.d.ts.map +1 -1
- package/dist/components/TanStackTable/ColumnHeader.js +8 -8
- package/dist/components/TanStackTable/ColumnHeader.js.map +1 -1
- package/dist/components/TanStackTable/ColumnHeaderEnumFilter.js.map +1 -1
- package/dist/components/TanStackTable/TableBody.js.map +1 -1
- package/dist/components/TeamSubjectsSelector/TeamSubjectsSelector.js.map +1 -1
- package/dist/components/TextField/TextField.js.map +1 -1
- package/dist/components/TimelinePlot/TimelinePhase.js.map +1 -1
- package/dist/components/TimelinePlot/TimelinePlot.js.map +1 -1
- package/dist/components/TimelinePlot/TimelinePlotSpeciesSelector.js.map +1 -1
- package/dist/components/UserCard/Avatar.js.map +1 -1
- package/dist/components/UserCardList/UserCardList.js.map +1 -1
- package/dist/components/UserCardList/UserCardListGroups/UserCardListGroups.Mobile.js.map +1 -1
- package/dist/components/UserCardList/UserCardListRotate.js.map +1 -1
- package/dist/components/UserOrTeamBadge/useUserOrTeam.js.map +1 -1
- package/dist/components/UserProfileLinks/UserProjects.js.map +1 -1
- package/dist/components/UserSearchBox/UserSearchBox.js.map +1 -1
- package/dist/components/Webhook/WebhookDashboard.js.map +1 -1
- package/dist/components/WikiMarkdownEditor/WikiMarkdownEditor.js.map +1 -1
- package/dist/components/WikiMarkdownEditorButton/WikiMarkdownEditorButton.js.map +1 -1
- package/dist/components/dataaccess/AccessApprovalsTable.js.map +1 -1
- package/dist/components/dataaccess/AccessRequestSubmissionTable.js.map +1 -1
- package/dist/components/dataaccess/SubmissionPage/SubmissionPage.d.ts.map +1 -1
- package/dist/components/dataaccess/SubmissionPage/SubmissionPage.js +157 -148
- package/dist/components/dataaccess/SubmissionPage/SubmissionPage.js.map +1 -1
- package/dist/components/dataaccess/UseAccessRequirementTable.js.map +1 -1
- package/dist/components/dataaccess/UserAccessRequestHistory/UserAccessRequestHistoryTable.js.map +1 -1
- package/dist/components/doi/CreateOrUpdateDoiModal.d.ts.map +1 -1
- package/dist/components/doi/CreateOrUpdateDoiModal.js +20 -19
- package/dist/components/doi/CreateOrUpdateDoiModal.js.map +1 -1
- package/dist/components/entity/page/CreatedByModifiedBy.js.map +1 -1
- package/dist/components/entity/page/action_menu/EntityActionMenu.js.map +1 -1
- package/dist/components/entity/page/title_bar/useDataCiteUsage.js.map +1 -1
- package/dist/components/entity/page/title_bar/useGetMentions.js.map +1 -1
- package/dist/components/error/ErrorPage.js.map +1 -1
- package/dist/components/favorites/FavoritesPage.js.map +1 -1
- package/dist/components/file/upload/BasicFileHandleUpload.js.map +1 -1
- package/dist/components/layout/SWCHeader.d.ts +9 -0
- package/dist/components/layout/SWCHeader.d.ts.map +1 -0
- package/dist/components/layout/SWCHeader.js +19 -0
- package/dist/components/layout/SWCHeader.js.map +1 -0
- package/dist/components/layout/SWCPageLayout.d.ts +9 -0
- package/dist/components/layout/SWCPageLayout.d.ts.map +1 -0
- package/dist/components/layout/SWCPageLayout.js +14 -0
- package/dist/components/layout/SWCPageLayout.js.map +1 -0
- package/dist/components/menu/ComplexMenu.js.map +1 -1
- package/dist/components/row_renderers/utils/ChipContainer.js.map +1 -1
- package/dist/components/styled/StyledPopover.js.map +1 -1
- package/dist/components/table/CsvPreview/CsvPreview.js +2 -1
- package/dist/components/table/CsvPreview/CsvPreview.js.map +1 -1
- package/dist/components/table/CsvPreview/CsvPreviewDialog.js.map +1 -1
- package/dist/components/trash/TrashCanList.js.map +1 -1
- package/dist/components/widgets/FileHandleLink.js.map +1 -1
- package/dist/components/widgets/RangeSlider/RangeSlider.js.map +1 -1
- package/dist/components/widgets/SynapseVideo.js.map +1 -1
- package/dist/components/widgets/facet-nav/FacetNavPanel.js.map +1 -1
- package/dist/components/widgets/facet-nav/PlotsContainer.js.map +1 -1
- package/dist/components/widgets/facet-nav/SelectionCriteriaPills.js.map +1 -1
- package/dist/components/widgets/facet-nav/useFacetPlots.js.map +1 -1
- package/dist/components/widgets/query-filter/CombinedRangeFacetFilter.js.map +1 -1
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilter.js.map +1 -1
- package/dist/components/widgets/query-filter/FacetFilterControls.js.map +1 -1
- package/dist/components/widgets/query-filter/RangeFacetFilter.js.map +1 -1
- package/dist/components/widgets/query-filter/RangeFacetFilterUI.js.map +1 -1
- package/dist/features/curator/GridPage/components/GridPageTitle.d.ts.map +1 -1
- package/dist/features/curator/GridPage/components/GridPageTitle.js +23 -30
- package/dist/features/curator/GridPage/components/GridPageTitle.js.map +1 -1
- package/dist/features/curator/dashboard/CuratorDashboard.d.ts +2 -0
- package/dist/features/curator/dashboard/CuratorDashboard.d.ts.map +1 -0
- package/dist/features/curator/dashboard/CuratorDashboard.js +45 -0
- package/dist/features/curator/dashboard/CuratorDashboard.js.map +1 -0
- package/dist/features/curator/dashboard/components/CurationTaskCard.css +1 -0
- package/dist/features/curator/dashboard/components/CurationTaskCard.d.ts +9 -0
- package/dist/features/curator/dashboard/components/CurationTaskCard.d.ts.map +1 -0
- package/dist/features/curator/dashboard/components/CurationTaskCard.js +106 -0
- package/dist/features/curator/dashboard/components/CurationTaskCard.js.map +1 -0
- package/dist/features/curator/dashboard/components/CurationTaskCard.module.js +12 -0
- package/dist/features/curator/dashboard/components/CurationTaskCard.module.js.map +1 -0
- package/dist/features/curator/dashboard/components/CurationTaskCard.module.scss +52 -0
- package/dist/features/curator/dashboard/components/NextStepButton.css +1 -0
- package/dist/features/curator/dashboard/components/NextStepButton.d.ts +14 -0
- package/dist/features/curator/dashboard/components/NextStepButton.d.ts.map +1 -0
- package/dist/features/curator/dashboard/components/NextStepButton.js +35 -0
- package/dist/features/curator/dashboard/components/NextStepButton.js.map +1 -0
- package/dist/features/curator/dashboard/components/NextStepButton.module.js +11 -0
- package/dist/features/curator/dashboard/components/NextStepButton.module.js.map +1 -0
- package/dist/features/curator/dashboard/components/NextStepButton.module.scss +57 -0
- package/dist/features/curator/dashboard/components/UserOrTeamChip.css +1 -1
- package/dist/features/curator/dashboard/components/UserOrTeamChip.module.js +1 -1
- package/dist/features/curator/dashboard/components/UserOrTeamChip.module.js.map +1 -1
- package/dist/features/curator/dashboard/components/UserOrTeamChip.module.scss +5 -5
- package/dist/features/curator/dashboard/components/shared.css +1 -0
- package/dist/features/curator/dashboard/components/shared.module.js +5 -0
- package/dist/features/curator/dashboard/components/shared.module.js.map +1 -0
- package/dist/features/curator/dashboard/components/shared.module.scss +8 -0
- package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.d.ts +0 -2
- package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.d.ts.map +1 -1
- package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.js +16 -34
- package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.js.map +1 -1
- package/dist/features/entity/metadata-task/components/MetadataTasksTableAssigneeCell.d.ts.map +1 -1
- package/dist/features/entity/metadata-task/components/MetadataTasksTableAssigneeCell.js +1 -1
- package/dist/features/entity/metadata-task/components/MetadataTasksTableAssigneeCell.js.map +1 -1
- package/dist/features/entity/metadata-task/hooks/useGetOrCreateGridSessionForSource.js.map +1 -1
- package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask.js.map +1 -1
- package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask_legacy.js.map +1 -1
- package/dist/features/entity/metadata-task/hooks/useMetadataTaskTable.js +1 -1
- package/dist/features/entity/metadata-task/hooks/useMetadataTaskTable.js.map +1 -1
- package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.d.ts +10 -0
- package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.d.ts.map +1 -0
- package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.js +37 -0
- package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.js.map +1 -0
- package/dist/features/entity/metadata-task/utils/constants.d.ts +5 -0
- package/dist/features/entity/metadata-task/utils/constants.d.ts.map +1 -0
- package/dist/features/entity/metadata-task/utils/constants.js +6 -0
- package/dist/features/entity/metadata-task/utils/constants.js.map +1 -0
- package/dist/mocks/challenge/mockChallenge.js.map +1 -1
- package/dist/mocks/entity/mockDataset.js.map +1 -1
- package/dist/mocks/entity/mockDatasetCollection.js.map +1 -1
- package/dist/mocks/entity/mockFileEntity.js.map +1 -1
- package/dist/mocks/entity/mockFileView.js.map +1 -1
- package/dist/mocks/entity/mockGeneratedEntityData.js.map +1 -1
- package/dist/mocks/entity/mockProject.js.map +1 -1
- package/dist/mocks/entity/mockProjectView.js.map +1 -1
- package/dist/mocks/entity/mockRootEntity.js.map +1 -1
- package/dist/mocks/entity/mockTableEntity.js.map +1 -1
- package/dist/mocks/mockWiki.js.map +1 -1
- package/dist/mocks/msw/handlers/asyncJobHandlers.js.map +1 -1
- package/dist/mocks/msw/handlers/challengeHandlers.js.map +1 -1
- package/dist/mocks/msw/handlers/changePasswordHandlers.js.map +1 -1
- package/dist/mocks/msw/handlers/discussionHandlers.js.map +1 -1
- package/dist/mocks/msw/handlers/entityHandlers.js.map +1 -1
- package/dist/mocks/msw/handlers/fileHandlers.js.map +1 -1
- package/dist/mocks/msw/handlers/gridHandlers.js.map +1 -1
- package/dist/mocks/msw/handlers/personalAccessTokenHandlers.js.map +1 -1
- package/dist/mocks/msw/handlers/subscriptionHandlers.js.map +1 -1
- package/dist/mocks/msw/handlers/teamHandlers.js.map +1 -1
- package/dist/mocks/msw/handlers/userProfileHandlers.js.map +1 -1
- package/dist/mocks/msw/handlers/wikiHandlers.js.map +1 -1
- package/dist/mocks/provenance/mockActivity.js.map +1 -1
- package/dist/mocks/query/mockReleaseCardsTableQueryResultBundle.js.map +1 -1
- package/dist/ror-client/index.js.map +1 -1
- package/dist/style/components/_cards.scss +4 -0
- package/dist/style/components/_data-grid-extra.css +1 -1
- package/dist/style/components/_data-grid-extra.scss +2 -0
- package/dist/style/main.css +1 -1
- package/dist/synapse-client/HttpClient.js.map +1 -1
- package/dist/synapse-client/SynapseClient.js.map +1 -1
- package/dist/synapse-queries/KeyFactory.d.ts +1 -0
- package/dist/synapse-queries/KeyFactory.d.ts.map +1 -1
- package/dist/synapse-queries/KeyFactory.js +3 -0
- package/dist/synapse-queries/KeyFactory.js.map +1 -1
- package/dist/synapse-queries/QueryMatching.test-utils.js.map +1 -1
- package/dist/synapse-queries/auth/useTwoFactorEnrollment.js.map +1 -1
- package/dist/synapse-queries/curation/task/useCurationTask.d.ts +1 -1
- package/dist/synapse-queries/curation/task/useCurationTask.d.ts.map +1 -1
- package/dist/synapse-queries/curation/task/useCurationTask.js +1 -1
- package/dist/synapse-queries/curation/task/useCurationTask.js.map +1 -1
- package/dist/synapse-queries/dataaccess/useRestrictionInformation.js.map +1 -1
- package/dist/synapse-queries/doi/useDOI.js.map +1 -1
- package/dist/synapse-queries/download/useDownloadList.js.map +1 -1
- package/dist/synapse-queries/entity/useEntity.js.map +1 -1
- package/dist/synapse-queries/entity/useEntityBundle.js.map +1 -1
- package/dist/synapse-queries/entity/useExportTableQueryToAnalysisPlatform.js.map +1 -1
- package/dist/synapse-queries/entity/useExportToTerra.js.map +1 -1
- package/dist/synapse-queries/entity/useGetQueryResultBundle.js.map +1 -1
- package/dist/synapse-queries/entity/useSchema.js.map +1 -1
- package/dist/synapse-queries/file/UploadToS3.js.map +1 -1
- package/dist/synapse-queries/file/useDirectUploadToS3.js.map +1 -1
- package/dist/synapse-queries/file/useFiles.js.map +1 -1
- package/dist/synapse-queries/forum/useReply.js.map +1 -1
- package/dist/synapse-queries/forum/useThread.d.ts +1 -0
- package/dist/synapse-queries/forum/useThread.d.ts.map +1 -1
- package/dist/synapse-queries/forum/useThread.js +19 -12
- package/dist/synapse-queries/forum/useThread.js.map +1 -1
- package/dist/synapse-queries/grid/useEstablishWebsocketConnection.d.ts +2 -0
- package/dist/synapse-queries/grid/useEstablishWebsocketConnection.d.ts.map +1 -1
- package/dist/synapse-queries/grid/useEstablishWebsocketConnection.js.map +1 -1
- package/dist/synapse-queries/grid/useExportGrid.js.map +1 -1
- package/dist/synapse-queries/grid/useGridSession.js.map +1 -1
- package/dist/synapse-queries/grid/useImportCsvIntoGrid.js.map +1 -1
- package/dist/synapse-queries/subscription/useSubscription.js.map +1 -1
- package/dist/synapse-queries/table/useGetCsvPreview.js.map +1 -1
- package/dist/synapse-queries/table/useTableUpdateTransaction.js.map +1 -1
- package/dist/synapse-queries/team/useTeamMembers.js.map +1 -1
- package/dist/synapse-queries/user/useGetUserChallenges.js.map +1 -1
- package/dist/synapse-queries/user/useUserBundle.js.map +1 -1
- package/dist/synapse-queries/user/useUserGroupHeader.js.map +1 -1
- package/dist/testutils/ReactQueryMockUtils.js.map +1 -1
- package/dist/theme/ThemeProvider.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utils/APIConstants.d.ts +1 -0
- package/dist/utils/APIConstants.d.ts.map +1 -1
- package/dist/utils/APIConstants.js +2 -2
- package/dist/utils/APIConstants.js.map +1 -1
- package/dist/utils/AppUtils/session/ApplicationSessionManager.d.ts.map +1 -1
- package/dist/utils/AppUtils/session/ApplicationSessionManager.js +7 -4
- package/dist/utils/AppUtils/session/ApplicationSessionManager.js.map +1 -1
- package/dist/utils/AppUtils/session/SynapseSessionManager.js.map +1 -1
- package/dist/utils/AppUtils/session/useSessionManager.js.map +1 -1
- package/dist/utils/PermissionLevelToAccessType.js.map +1 -1
- package/dist/utils/challenge/evaluation/EvaluationUtils.js.map +1 -1
- package/dist/utils/context/SynapseContext.js.map +1 -1
- package/dist/utils/functions/AccessControlListUtils.d.ts +4 -0
- package/dist/utils/functions/AccessControlListUtils.d.ts.map +1 -1
- package/dist/utils/functions/AccessControlListUtils.js +12 -1
- package/dist/utils/functions/AccessControlListUtils.js.map +1 -1
- package/dist/utils/functions/EntityTypeUtils.d.ts.map +1 -1
- package/dist/utils/functions/EntityTypeUtils.js +15 -4
- package/dist/utils/functions/EntityTypeUtils.js.map +1 -1
- package/dist/utils/functions/GridApiUtils.js.map +1 -1
- package/dist/utils/functions/QueryFilterUtils.js.map +1 -1
- package/dist/utils/functions/RealmUtils.d.ts +4 -0
- package/dist/utils/functions/RealmUtils.d.ts.map +1 -1
- package/dist/utils/functions/RealmUtils.js +9 -3
- package/dist/utils/functions/RealmUtils.js.map +1 -1
- package/dist/utils/functions/SanitizeHtmlUtils.js.map +1 -1
- package/dist/utils/functions/SanitizeHtmlUtils.test-utils.js.map +1 -1
- package/dist/utils/functions/SqlFunctions.js.map +1 -1
- package/dist/utils/functions/StringUtils.js.map +1 -1
- package/dist/utils/functions/deepLinkingUtils.js.map +1 -1
- package/dist/utils/functions/getDataFromFromStorage.js.map +1 -1
- package/dist/utils/functions/getEndpoint.js.map +1 -1
- package/dist/utils/functions/getUserData.js.map +1 -1
- package/dist/utils/functions/queryUtils.js.map +1 -1
- package/dist/utils/functions/testDownloadSpeed.js.map +1 -1
- package/dist/utils/hooks/useConfirmItems.js.map +1 -1
- package/dist/utils/hooks/useCookiePreferences.js.map +1 -1
- package/dist/utils/hooks/useCreateShortUrl.js.map +1 -1
- package/dist/utils/hooks/useDetectSSOCode.js.map +1 -1
- package/dist/utils/hooks/useDirectDownloadHandler.js.map +1 -1
- package/dist/utils/hooks/useGetGoalData.js.map +1 -1
- package/dist/utils/hooks/useGetInfoFromIds.js.map +1 -1
- package/dist/utils/hooks/useImageUrlUtils.js.map +1 -1
- package/dist/utils/hooks/useImmutableTableQuery/useImmutableTableQuery.js.map +1 -1
- package/dist/utils/hooks/useImmutableTableQuery/useTableQueryReducer.js.map +1 -1
- package/dist/utils/hooks/useIsBot.js.map +1 -1
- package/dist/utils/hooks/useListState.js.map +1 -1
- package/dist/utils/hooks/useLogin.d.ts.map +1 -1
- package/dist/utils/hooks/useLogin.js +53 -52
- package/dist/utils/hooks/useLogin.js.map +1 -1
- package/dist/utils/hooks/useMutuallyExclusiveState.js.map +1 -1
- package/dist/utils/hooks/useOverlay.js.map +1 -1
- package/dist/utils/hooks/usePreFetchResource.js.map +1 -1
- package/dist/utils/hooks/useQuerySearchParam.js.map +1 -1
- package/dist/utils/hooks/useScrollFadeTransition.js.map +1 -1
- package/dist/utils/hooks/useSet.js.map +1 -1
- package/dist/utils/hooks/useSourceAppConfigs.js.map +1 -1
- package/dist/utils/hooks/useTableImageUrl.js.map +1 -1
- package/dist/utils/hooks/useUploadFileEntity/useCreatePathsAndGetParentId.js.map +1 -1
- package/dist/utils/hooks/useUploadFileEntity/useLinkFileEntityToURL.js.map +1 -1
- package/dist/utils/hooks/useUploadFileEntity/usePrepareFileEntityUpload.js.map +1 -1
- package/dist/utils/hooks/useUploadFileEntity/useTrackFileUploads.js.map +1 -1
- package/dist/utils/hooks/useUploadFileEntity/useUploadFileEntities.js.map +1 -1
- package/dist/utils/hooks/useUploadFileEntity/useUploadFiles.js.map +1 -1
- package/dist/utils/hooks/useUploadFileEntity/willUploadsExceedStorageLimit.js.map +1 -1
- package/dist/utils/html/TargetEnum.js.map +1 -1
- package/dist/utils/jsonschema/SchemaAnnotationUtils.js.map +1 -1
- package/package.json +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SubmissionDirectoryList.js","names":[],"sources":["../../../src/components/ChallengeSubmission/SubmissionDirectoryList.tsx"],"sourcesContent":["import SynapseClient from '@/synapse-client'\nimport {\n invalidateAllQueriesForEntity,\n useGetEntities,\n useGetEntityChildren,\n} from '@/synapse-queries'\nimport { useSynapseContext } from '@/utils'\nimport { formatDate } from '@/utils/functions/DateFormatter'\nimport {\n BackendDestinationEnum,\n getEndpoint,\n} from '@/utils/functions/getEndpoint'\nimport { InfoTwoTone } from '@mui/icons-material'\nimport { Box, Button, Radio, Typography } from '@mui/material'\nimport { DataGrid, GridCellParams, GridColDef } from '@mui/x-data-grid'\nimport { EntityType } from '@sage-bionetworks/synapse-client'\nimport { SynapseClientError } from '@sage-bionetworks/synapse-client/util/SynapseClientError'\nimport {\n Direction,\n Entity,\n EntityChildrenRequest,\n EntityHeader,\n EntityLookupRequest,\n FILE_ENTITY_CONCRETE_TYPE_VALUE,\n FileEntity,\n FileUploadComplete,\n SortBy,\n UploadCallbackResp,\n} from '@sage-bionetworks/synapse-types'\nimport { useQueryClient } from '@tanstack/react-query'\nimport dayjs from 'dayjs'\nimport { useEffect, useMemo, useState } from 'react'\nimport { Link } from 'react-router'\nimport ConfirmationDialog from '../ConfirmationDialog'\nimport CopyToClipboardIcon from '../CopyToClipboardIcon'\nimport { ErrorBanner } from '../error/ErrorBanner'\nimport FileUpload from '../FileUpload'\nimport IconSvg from '../IconSvg'\nimport { EntityItem } from './ChallengeSubmission'\n\ntype SubmissionDirectoryRow = {\n id: string\n name: string\n modifiedOn: string\n}\n\ntype SubmissionDirectoryListProps = {\n pageSize: number\n challengeProjectId: string\n entityType: typeof EntityType.dockerrepo | typeof EntityType.file\n onItemSelected: (selected: EntityItem) => void\n}\n\ntype FileUploadAttempt = FileUploadComplete & {\n entityId?: string\n}\n\nfunction SubmissionDirectoryList({\n pageSize,\n challengeProjectId,\n entityType,\n onItemSelected,\n}: SubmissionDirectoryListProps) {\n const queryClient = useQueryClient()\n const { accessToken, keyFactory } = useSynapseContext()\n const [page, setPage] = useState<number>(0)\n const [selectedItem, setSelectedItem] = useState<EntityItem | undefined>()\n const [errorMessage, setErrorMessage] = useState<string>()\n const [canSubmit, setCanSubmit] = useState<boolean>()\n const [fetchedHeaders, setFetchedHeaders] = useState<EntityHeader[]>([])\n const [nextPageToken, setNextPageToken] = useState<string | undefined>()\n const [fetchNextPage, setFetchNextPage] = useState<boolean>(false)\n const [confirmOpen, setConfirmOpen] = useState<boolean>(false)\n const [uploadAttempt, setUploadAttempt] = useState<FileUploadAttempt>()\n\n const PER_PAGE = pageSize\n const HEADERS_PER_PAGE = 50\n const PROJECT_URL = `${getEndpoint(\n BackendDestinationEnum.PORTAL_ENDPOINT,\n )}Synapse:${challengeProjectId}`\n\n const request: EntityChildrenRequest = {\n parentId: challengeProjectId,\n nextPageToken: fetchNextPage ? nextPageToken : null,\n includeTypes: [entityType],\n includeTotalChildCount: true,\n sortBy: SortBy.MODIFIED_ON,\n sortDirection: Direction.DESC,\n }\n\n const { data: headerResults, refetch } = useGetEntityChildren(request, {\n enabled: !!challengeProjectId,\n throwOnError: true,\n })\n\n useEffect(() => {\n if (headerResults) {\n const newHeaders = [...fetchedHeaders]\n const headerPage = Math.floor(((page + 1) * PER_PAGE) / HEADERS_PER_PAGE)\n const start = headerPage * HEADERS_PER_PAGE\n newHeaders.splice(start, start + HEADERS_PER_PAGE, ...headerResults.page)\n setFetchedHeaders(newHeaders)\n setFetchNextPage(false)\n setNextPageToken(headerResults.nextPageToken)\n }\n // TODO: Temporary useEffect hook to remove onSuccess QueryOption for @tanstack/react-query v5\n // Refactor this component to remove this effect.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [headerResults])\n\n function getPageHeaders() {\n const pageStart = page * PER_PAGE\n const pageHeaders = fetchedHeaders.slice(pageStart, pageStart + PER_PAGE)\n return pageHeaders\n }\n\n function reset() {\n setErrorMessage(undefined)\n setCanSubmit(undefined)\n setFetchedHeaders([])\n setNextPageToken(undefined)\n setFetchNextPage(false)\n refetch()\n }\n\n useEffect(() => {\n reset()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [entityType, pageSize])\n\n const queries = useGetEntities(getPageHeaders())\n const entities = useMemo(\n () =>\n queries\n .filter(q => q.status === 'success')\n .map(q => q.data) as EntityItem[],\n [queries],\n )\n const areEntitiesLoading = queries.some(q => q.isLoading)\n\n const entityChangeHandler = async (value: string) => {\n setCanSubmit(false)\n const entity = entities.find(entity => entity?.id === value)\n if (entity) {\n setSelectedItem(entity)\n if (entityType === EntityType.dockerrepo) {\n let commits\n try {\n commits = await SynapseClient.getDockerTag(\n entity.id!,\n accessToken,\n 0,\n 1,\n )\n } catch (e) {\n return setErrorMessage(e.message)\n }\n if (commits.totalNumberOfResults === 0) {\n return setErrorMessage(\n 'No commits have been made to this repository. Please select a repository with at least one commit.',\n )\n }\n }\n setCanSubmit(true)\n setErrorMessage(undefined)\n }\n }\n\n const columns: GridColDef[] = [\n {\n field: 'radiobutton',\n headerName: '',\n width: 25,\n sortable: false,\n filterable: false,\n hideable: false,\n disableColumnMenu: true,\n renderCell: params => {\n return (\n <Radio\n value={params.id}\n checked={params.id === selectedItem?.id}\n onChange={event => {\n entityChangeHandler(event.target.value)\n }}\n />\n )\n },\n },\n {\n field: 'name',\n headerName:\n entityType === EntityType.dockerrepo\n ? 'Docker Repository'\n : 'File Name',\n flex: 1,\n filterable: false,\n hideable: false,\n disableColumnMenu: true,\n renderCell: (params: GridCellParams<Entity, SubmissionDirectoryRow>) => (\n <Link\n to={{\n pathname: `${getEndpoint(\n BackendDestinationEnum.PORTAL_ENDPOINT,\n )}Synapse:${params.row.id}`,\n }}\n target=\"_blank\"\n >\n {params.row.name}\n </Link>\n ),\n },\n {\n field: 'modifiedOn',\n headerName: 'Updated On',\n width: 100,\n filterable: false,\n hideable: false,\n disableColumnMenu: true,\n },\n {\n field: 'id',\n headerName: 'ID',\n width: 200,\n filterable: false,\n hideable: false,\n disableColumnMenu: true,\n },\n ]\n\n const getRows = (entities: EntityItem[]) => {\n const newRows: SubmissionDirectoryRow[] = []\n entities.forEach(entity => {\n newRows.push({\n id: entity.id!,\n name:\n entityType === EntityType.dockerrepo\n ? entity.repositoryName ?? entity.name\n : entity.name,\n modifiedOn: formatDate(dayjs(entity.modifiedOn), 'MM/DD/YY'),\n })\n })\n return newRows\n }\n\n const handlePageChange = (newPageNum: number) => {\n const lastIndexNeeded = Math.min(\n headerResults?.totalChildCount ?? 0,\n (newPageNum + 1) * PER_PAGE,\n )\n if (lastIndexNeeded > fetchedHeaders.length) {\n setFetchNextPage(true)\n }\n setPage(newPageNum)\n }\n\n const itemSelectedHandler = () => {\n onItemSelected(selectedItem!)\n }\n\n function createEntity(file: FileUploadAttempt) {\n // Create Entity\n if (!file) return\n const { fileHandleId, fileName } = file\n const newFileEntity: FileEntity = {\n parentId: challengeProjectId,\n name: fileName,\n concreteType: FILE_ENTITY_CONCRETE_TYPE_VALUE,\n dataFileHandleId: fileHandleId,\n }\n SynapseClient.createEntity(newFileEntity, accessToken)\n .then(() => {\n reset()\n })\n .catch((err: SynapseClientError) => {\n setErrorMessage(err.reason)\n })\n }\n\n async function updateEntity() {\n if (!uploadAttempt) return\n const { fileHandleId, entityId } = uploadAttempt\n if (!entityId)\n return setErrorMessage('Error: missing entityId. Please try again.')\n // Get the entity\n let entity: FileEntity\n try {\n entity = await SynapseClient.getEntity(accessToken, entityId)\n } catch (err) {\n return setErrorMessage(`The entity ${entityId} could not be retrieved.`)\n }\n\n const updateRequest: FileEntity = {\n id: entity.id,\n name: entity.name,\n dataFileHandleId: fileHandleId,\n concreteType: FILE_ENTITY_CONCRETE_TYPE_VALUE,\n parentId: entity.parentId,\n etag: entity.etag,\n modifiedOn: entity.modifiedOn,\n }\n\n try {\n const updatedEntity = await SynapseClient.updateEntity(\n updateRequest,\n accessToken,\n true,\n )\n await invalidateAllQueriesForEntity(\n queryClient,\n keyFactory,\n updatedEntity.id!,\n )\n queryClient.setQueryData(\n keyFactory.getEntityQueryKey(updatedEntity.id!),\n updatedEntity,\n )\n reset()\n } catch (err) {\n setErrorMessage(err.reason)\n }\n }\n\n const handleUpload = async (response: UploadCallbackResp) => {\n if (response.success && response.resp) {\n const { fileName } = response.resp\n\n // Lookup entity\n const entityLookupRequest: EntityLookupRequest = {\n entityName: fileName,\n parentId: challengeProjectId,\n }\n try {\n const entityId = await SynapseClient.lookupChildEntity(\n entityLookupRequest,\n accessToken,\n )\n // Entity exists, prompt user to update it\n if (entityId) {\n setUploadAttempt({ ...response.resp, entityId: entityId.id })\n setConfirmOpen(true)\n }\n } catch (err) {\n // An existing entity was not found for this file, create it\n setUploadAttempt(undefined)\n createEntity(response.resp)\n }\n } else if (!response.success && response.error) {\n setErrorMessage(response.error.reason as string)\n } else {\n setErrorMessage('An unknown error occurred. Please try again.')\n }\n }\n\n return (\n <Box>\n <Box\n sx={{\n display: 'flex',\n backgroundColor: '#FBFBFC',\n padding: '10px',\n justifyContent: 'space-between',\n }}\n >\n <Typography\n variant=\"h6\"\n sx={{ fontSize: '18px', lineHeight: '20px', fontWeight: 700 }}\n >\n Your Submission Directory\n </Typography>\n <Box sx={{ display: 'flex' }}>\n <Typography\n variant=\"body1\"\n sx={{ fontSize: '14px', color: '#71767F' }}\n >\n Project SynID:{' '}\n <Link to={{ pathname: PROJECT_URL }} target=\"_blank\">\n {challengeProjectId}\n </Link>\n </Typography>\n <CopyToClipboardIcon value={PROJECT_URL} sx={{ marginTop: '-4px' }} />\n </Box>\n </Box>\n <Box>\n <DataGrid\n loading={areEntitiesLoading}\n columns={columns}\n rows={getRows(entities)}\n rowCount={headerResults?.totalChildCount ?? 0}\n pagination\n paginationMode=\"server\"\n paginationModel={{ page, pageSize: PER_PAGE }}\n pageSizeOptions={[PER_PAGE]}\n onPaginationModelChange={({ page }) => {\n handlePageChange(page)\n }}\n density=\"compact\"\n autoHeight\n sx={{\n fontSize: '14px',\n border: 'none',\n height: '100%',\n '& .MuiDataGrid-columnHeader': {\n backgroundColor: '#F1F3F5',\n },\n '& .Mui-odd': {\n backgroundColor: '#FBFBFC',\n },\n '.MuiDataGrid-columnHeaderTitleContainer': {\n justifyContent: 'space-between',\n },\n '.radio': {\n display: 'flex',\n alignItems: 'center',\n height: '100%',\n },\n }}\n getRowClassName={params =>\n params.indexRelativeToCurrentPage % 2 === 0 ? 'Mui-even' : 'Mui-odd'\n }\n />\n </Box>\n {errorMessage && <ErrorBanner error={errorMessage}></ErrorBanner>}\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'space-between',\n }}\n >\n {entityType === EntityType.file && (\n <FileUpload\n label=\"Upload File\"\n buttonProps={{\n variant: 'outlined',\n endIcon: <IconSvg icon=\"upload\" />,\n sx: { lineHeight: 1 },\n }}\n onComplete={resp => {\n handleUpload(resp)\n }}\n />\n )}\n <Button\n color=\"primary\"\n variant=\"contained\"\n onClick={itemSelectedHandler}\n disabled={!canSubmit}\n >\n Submit Selection\n </Button>\n </Box>\n {entityType === EntityType.dockerrepo && (\n <Box\n sx={{\n mt: 4,\n display: 'flex',\n }}\n >\n <InfoTwoTone\n sx={{\n width: '16px',\n height: '16px',\n verticalAlign: 'text-bottom',\n }}\n />\n\n <Box\n sx={{\n ml: 2,\n }}\n >\n To learn more about how to create and submit the Docker containers\n using command line, see our{' '}\n <Link\n to=\"https://github.com/Sage-Bionetworks-Challenges/sample-model-templates#build-your-model\"\n target=\"_blank\"\n >\n Docker model submission guide\n </Link>\n .\n </Box>\n </Box>\n )}\n <ConfirmationDialog\n open={confirmOpen}\n title=\"File exists\"\n content={\n <Typography variant=\"body1\" sx={{ fontSize: '16px' }}>\n A file named "{uploadAttempt?.fileName}" (\n {uploadAttempt?.entityId}) already exists in this location. Do you\n want to update the existing file and create a new version?\n </Typography>\n }\n onCancel={() => setConfirmOpen(false)}\n onConfirm={() => {\n updateEntity()\n setConfirmOpen(false)\n }}\n />\n </Box>\n )\n}\n\nexport default SubmissionDirectoryList\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SubmissionDirectoryList.js","names":[],"sources":["../../../src/components/ChallengeSubmission/SubmissionDirectoryList.tsx"],"sourcesContent":["import SynapseClient from '@/synapse-client'\nimport {\n invalidateAllQueriesForEntity,\n useGetEntities,\n useGetEntityChildren,\n} from '@/synapse-queries'\nimport { useSynapseContext } from '@/utils'\nimport { formatDate } from '@/utils/functions/DateFormatter'\nimport {\n BackendDestinationEnum,\n getEndpoint,\n} from '@/utils/functions/getEndpoint'\nimport { NotesTwoTone } from '@mui/icons-material'\nimport { Box, Button, Radio, Typography } from '@mui/material'\nimport { DataGrid, GridCellParams, GridColDef } from '@mui/x-data-grid'\nimport { EntityType } from '@sage-bionetworks/synapse-client'\nimport { SynapseClientError } from '@sage-bionetworks/synapse-client/util/SynapseClientError'\nimport {\n Direction,\n Entity,\n EntityChildrenRequest,\n EntityHeader,\n EntityLookupRequest,\n FILE_ENTITY_CONCRETE_TYPE_VALUE,\n FileEntity,\n FileUploadComplete,\n SortBy,\n UploadCallbackResp,\n} from '@sage-bionetworks/synapse-types'\nimport { useQueryClient } from '@tanstack/react-query'\nimport dayjs from 'dayjs'\nimport { useEffect, useMemo, useState } from 'react'\nimport { Link } from 'react-router'\nimport ConfirmationDialog from '../ConfirmationDialog'\nimport CopyToClipboardIcon from '../CopyToClipboardIcon'\nimport { ErrorBanner } from '../error/ErrorBanner'\nimport FileUpload from '../FileUpload'\nimport IconSvg from '../IconSvg'\nimport { EntityItem } from './ChallengeSubmission'\n\ntype SubmissionDirectoryRow = {\n id: string\n name: string\n modifiedOn: string\n}\n\ntype SubmissionDirectoryListProps = {\n pageSize: number\n challengeProjectId: string\n entityType: typeof EntityType.dockerrepo | typeof EntityType.file\n onItemSelected: (selected: EntityItem) => void\n}\n\ntype FileUploadAttempt = FileUploadComplete & {\n entityId?: string\n}\n\nfunction SubmissionDirectoryList({\n pageSize,\n challengeProjectId,\n entityType,\n onItemSelected,\n}: SubmissionDirectoryListProps) {\n const queryClient = useQueryClient()\n const { accessToken, keyFactory } = useSynapseContext()\n const [page, setPage] = useState<number>(0)\n const [selectedItem, setSelectedItem] = useState<EntityItem | undefined>()\n const [errorMessage, setErrorMessage] = useState<string>()\n const [canSubmit, setCanSubmit] = useState<boolean>()\n const [fetchedHeaders, setFetchedHeaders] = useState<EntityHeader[]>([])\n const [nextPageToken, setNextPageToken] = useState<string | undefined>()\n const [fetchNextPage, setFetchNextPage] = useState<boolean>(false)\n const [confirmOpen, setConfirmOpen] = useState<boolean>(false)\n const [uploadAttempt, setUploadAttempt] = useState<FileUploadAttempt>()\n\n const PER_PAGE = pageSize\n const HEADERS_PER_PAGE = 50\n const PROJECT_URL = `${getEndpoint(\n BackendDestinationEnum.PORTAL_ENDPOINT,\n )}Synapse:${challengeProjectId}`\n\n const request: EntityChildrenRequest = {\n parentId: challengeProjectId,\n nextPageToken: fetchNextPage ? nextPageToken : null,\n includeTypes: [entityType],\n includeTotalChildCount: true,\n sortBy: SortBy.MODIFIED_ON,\n sortDirection: Direction.DESC,\n }\n\n const { data: headerResults, refetch } = useGetEntityChildren(request, {\n enabled: !!challengeProjectId,\n throwOnError: true,\n })\n\n useEffect(() => {\n if (headerResults) {\n const newHeaders = [...fetchedHeaders]\n const headerPage = Math.floor(((page + 1) * PER_PAGE) / HEADERS_PER_PAGE)\n const start = headerPage * HEADERS_PER_PAGE\n newHeaders.splice(start, start + HEADERS_PER_PAGE, ...headerResults.page)\n setFetchedHeaders(newHeaders)\n setFetchNextPage(false)\n setNextPageToken(headerResults.nextPageToken)\n }\n // TODO: Temporary useEffect hook to remove onSuccess QueryOption for @tanstack/react-query v5\n // Refactor this component to remove this effect.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [headerResults])\n\n function getPageHeaders() {\n const pageStart = page * PER_PAGE\n const pageHeaders = fetchedHeaders.slice(pageStart, pageStart + PER_PAGE)\n return pageHeaders\n }\n\n function reset() {\n setErrorMessage(undefined)\n setCanSubmit(undefined)\n setFetchedHeaders([])\n setNextPageToken(undefined)\n setFetchNextPage(false)\n refetch()\n }\n\n useEffect(() => {\n reset()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [entityType, pageSize])\n\n const queries = useGetEntities(getPageHeaders())\n const entities = useMemo(\n () =>\n queries\n .filter(q => q.status === 'success')\n .map(q => q.data) as EntityItem[],\n [queries],\n )\n const areEntitiesLoading = queries.some(q => q.isLoading)\n\n const entityChangeHandler = async (value: string) => {\n setCanSubmit(false)\n const entity = entities.find(entity => entity?.id === value)\n if (entity) {\n setSelectedItem(entity)\n if (entityType === EntityType.dockerrepo) {\n let commits\n try {\n commits = await SynapseClient.getDockerTag(\n entity.id!,\n accessToken,\n 0,\n 1,\n )\n } catch (e) {\n return setErrorMessage(e.message)\n }\n if (commits.totalNumberOfResults === 0) {\n return setErrorMessage(\n 'No commits have been made to this repository. Please select a repository with at least one commit.',\n )\n }\n }\n setCanSubmit(true)\n setErrorMessage(undefined)\n }\n }\n\n const columns: GridColDef[] = [\n {\n field: 'radiobutton',\n headerName: '',\n width: 25,\n sortable: false,\n filterable: false,\n hideable: false,\n disableColumnMenu: true,\n renderCell: params => {\n return (\n <Radio\n value={params.id}\n checked={params.id === selectedItem?.id}\n onChange={event => {\n entityChangeHandler(event.target.value)\n }}\n />\n )\n },\n },\n {\n field: 'name',\n headerName:\n entityType === EntityType.dockerrepo\n ? 'Docker Repository'\n : 'File Name',\n flex: 1,\n filterable: false,\n hideable: false,\n disableColumnMenu: true,\n renderCell: (params: GridCellParams<Entity, SubmissionDirectoryRow>) => (\n <Link\n to={{\n pathname: `${getEndpoint(\n BackendDestinationEnum.PORTAL_ENDPOINT,\n )}Synapse:${params.row.id}`,\n }}\n target=\"_blank\"\n >\n {params.row.name}\n </Link>\n ),\n },\n {\n field: 'modifiedOn',\n headerName: 'Updated On',\n width: 100,\n filterable: false,\n hideable: false,\n disableColumnMenu: true,\n },\n {\n field: 'id',\n headerName: 'ID',\n width: 200,\n filterable: false,\n hideable: false,\n disableColumnMenu: true,\n },\n ]\n\n const getRows = (entities: EntityItem[]) => {\n const newRows: SubmissionDirectoryRow[] = []\n entities.forEach(entity => {\n newRows.push({\n id: entity.id!,\n name:\n entityType === EntityType.dockerrepo\n ? entity.repositoryName ?? entity.name\n : entity.name,\n modifiedOn: formatDate(dayjs(entity.modifiedOn), 'MM/DD/YY'),\n })\n })\n return newRows\n }\n\n const handlePageChange = (newPageNum: number) => {\n const lastIndexNeeded = Math.min(\n headerResults?.totalChildCount ?? 0,\n (newPageNum + 1) * PER_PAGE,\n )\n if (lastIndexNeeded > fetchedHeaders.length) {\n setFetchNextPage(true)\n }\n setPage(newPageNum)\n }\n\n const itemSelectedHandler = () => {\n onItemSelected(selectedItem!)\n }\n\n function createEntity(file: FileUploadAttempt) {\n // Create Entity\n if (!file) return\n const { fileHandleId, fileName } = file\n const newFileEntity: FileEntity = {\n parentId: challengeProjectId,\n name: fileName,\n concreteType: FILE_ENTITY_CONCRETE_TYPE_VALUE,\n dataFileHandleId: fileHandleId,\n }\n SynapseClient.createEntity(newFileEntity, accessToken)\n .then(() => {\n reset()\n })\n .catch((err: SynapseClientError) => {\n setErrorMessage(err.reason)\n })\n }\n\n async function updateEntity() {\n if (!uploadAttempt) return\n const { fileHandleId, entityId } = uploadAttempt\n if (!entityId)\n return setErrorMessage('Error: missing entityId. Please try again.')\n // Get the entity\n let entity: FileEntity\n try {\n entity = await SynapseClient.getEntity(accessToken, entityId)\n } catch (err) {\n return setErrorMessage(`The entity ${entityId} could not be retrieved.`)\n }\n\n const updateRequest: FileEntity = {\n id: entity.id,\n name: entity.name,\n dataFileHandleId: fileHandleId,\n concreteType: FILE_ENTITY_CONCRETE_TYPE_VALUE,\n parentId: entity.parentId,\n etag: entity.etag,\n modifiedOn: entity.modifiedOn,\n }\n\n try {\n const updatedEntity = await SynapseClient.updateEntity(\n updateRequest,\n accessToken,\n true,\n )\n await invalidateAllQueriesForEntity(\n queryClient,\n keyFactory,\n updatedEntity.id!,\n )\n queryClient.setQueryData(\n keyFactory.getEntityQueryKey(updatedEntity.id!),\n updatedEntity,\n )\n reset()\n } catch (err) {\n setErrorMessage(err.reason)\n }\n }\n\n const handleUpload = async (response: UploadCallbackResp) => {\n if (response.success && response.resp) {\n const { fileName } = response.resp\n\n // Lookup entity\n const entityLookupRequest: EntityLookupRequest = {\n entityName: fileName,\n parentId: challengeProjectId,\n }\n try {\n const entityId = await SynapseClient.lookupChildEntity(\n entityLookupRequest,\n accessToken,\n )\n // Entity exists, prompt user to update it\n if (entityId) {\n setUploadAttempt({ ...response.resp, entityId: entityId.id })\n setConfirmOpen(true)\n }\n } catch (err) {\n // An existing entity was not found for this file, create it\n setUploadAttempt(undefined)\n createEntity(response.resp)\n }\n } else if (!response.success && response.error) {\n setErrorMessage(response.error.reason as string)\n } else {\n setErrorMessage('An unknown error occurred. Please try again.')\n }\n }\n\n return (\n <Box>\n <Box\n sx={{\n display: 'flex',\n backgroundColor: '#FBFBFC',\n padding: '10px',\n justifyContent: 'space-between',\n }}\n >\n <Typography\n variant=\"h6\"\n sx={{ fontSize: '18px', lineHeight: '20px', fontWeight: 700 }}\n >\n {entityType === EntityType.file\n ? 'Submit File'\n : 'Submit Docker Image'}\n </Typography>\n <Box sx={{ display: 'flex' }}>\n <Typography\n variant=\"body1\"\n sx={{ fontSize: '14px', color: '#71767F' }}\n >\n Your Project SynID:{' '}\n <Link to={{ pathname: PROJECT_URL }} target=\"_blank\">\n {challengeProjectId}\n </Link>\n </Typography>\n <CopyToClipboardIcon value={PROJECT_URL} sx={{ marginTop: '-4px' }} />\n </Box>\n </Box>\n <Box\n sx={{\n my: 3,\n display: 'flex',\n }}\n >\n <NotesTwoTone\n sx={{\n width: '16px',\n height: '16px',\n verticalAlign: 'text-bottom',\n }}\n />\n <Box\n sx={{\n ml: 1,\n }}\n >\n {entityType === EntityType.file && (\n <>\n Choose a prediction file from your submission directory below and\n click \"Submit Selection\" to pick an evaluation queue. If you need\n to add a new file, click \"Upload File\" first.\n </>\n )}\n {entityType === EntityType.dockerrepo && (\n <>\n Choose a Docker image from your submission directory below and\n click \"Submit Selection\" to pick an image version and evaluation\n queue. If you need to upload a new image to your project (\n <code>{challengeProjectId}</code>), see our{' '}\n <Link\n to=\"https://github.com/Sage-Bionetworks-Challenges/sample-model-templates#build-your-model\"\n target=\"_blank\"\n >\n Docker model submission guide\n </Link>{' '}\n for command-line instructions on how to build and upload.\n </>\n )}\n </Box>\n </Box>\n <Box>\n <DataGrid\n loading={areEntitiesLoading}\n columns={columns}\n rows={getRows(entities)}\n rowCount={headerResults?.totalChildCount ?? 0}\n pagination\n paginationMode=\"server\"\n paginationModel={{ page, pageSize: PER_PAGE }}\n pageSizeOptions={[PER_PAGE]}\n onPaginationModelChange={({ page }) => {\n handlePageChange(page)\n }}\n density=\"compact\"\n autoHeight\n sx={{\n fontSize: '14px',\n border: 'none',\n height: '100%',\n '& .MuiDataGrid-columnHeader': {\n backgroundColor: '#F1F3F5',\n },\n '& .Mui-odd': {\n backgroundColor: '#FBFBFC',\n },\n '.MuiDataGrid-columnHeaderTitleContainer': {\n justifyContent: 'space-between',\n },\n '.radio': {\n display: 'flex',\n alignItems: 'center',\n height: '100%',\n },\n }}\n getRowClassName={params =>\n params.indexRelativeToCurrentPage % 2 === 0 ? 'Mui-even' : 'Mui-odd'\n }\n />\n </Box>\n {errorMessage && <ErrorBanner error={errorMessage}></ErrorBanner>}\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'space-between',\n }}\n >\n {entityType === EntityType.file && (\n <FileUpload\n label=\"Upload File\"\n buttonProps={{\n variant: 'outlined',\n endIcon: <IconSvg icon=\"upload\" />,\n sx: { lineHeight: 1 },\n }}\n onComplete={resp => {\n handleUpload(resp)\n }}\n />\n )}\n <Button\n color=\"primary\"\n variant=\"contained\"\n onClick={itemSelectedHandler}\n disabled={!canSubmit}\n >\n Submit Selection\n </Button>\n </Box>\n <ConfirmationDialog\n open={confirmOpen}\n title=\"File exists\"\n content={\n <Typography variant=\"body1\" sx={{ fontSize: '16px' }}>\n A file named "{uploadAttempt?.fileName}" (\n {uploadAttempt?.entityId}) already exists in this location. Do you\n want to update the existing file and create a new version?\n </Typography>\n }\n onCancel={() => setConfirmOpen(false)}\n onConfirm={() => {\n updateEntity()\n setConfirmOpen(false)\n }}\n />\n </Box>\n )\n}\n\nexport default SubmissionDirectoryList\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChallengeTeamWizard.js","names":[],"sources":["../../../src/components/ChallengeTeamWizard/ChallengeTeamWizard.tsx"],"sourcesContent":["import {\n useAddMemberToTeam,\n useGetCurrentUserProfile,\n useGetEntityChallenge,\n useGetMembershipStatus,\n useGetUserSubmissionTeams,\n} from '@/synapse-queries'\nimport { useSynapseContext } from '@/utils'\nimport { Alert, Box, Button, Tooltip, Typography } from '@mui/material'\nimport { noop } from 'lodash-es'\nimport { useCallback, useMemo, useRef, useState } from 'react'\nimport { DialogBase } from '../DialogBase'\nimport { SignInPrompt, SynapseErrorBoundary } from '../error/ErrorBanner'\nimport { SynapseSpinner } from '../LoadingScreen/LoadingScreen'\nimport {\n CreateChallengeTeam,\n CreateChallengeTeamHandle,\n} from './CreateChallengeTeam'\nimport {\n MembershipRequestForm,\n MembershipRequestFormHandle,\n} from './MembershipRequestForm'\nimport {\n AcceptMembershipInvitationButton,\n OpenMembershipInvitation,\n} from './OpenMembershipInvitation'\nimport { RegistrationSuccessful } from './RegistrationSuccessful'\nimport { SelectChallengeTeam } from './SelectChallengeTeam'\n\nenum ChallengeTeamWizardStep {\n SELECT_YOUR_CHALLENGE_TEAM = 'SELECT_YOUR_CHALLENGE_TEAM',\n ACCEPT_INVITATION = 'ACCEPT_INVITATION',\n JOIN_REQUEST_FORM = 'JOIN_REQUEST_FORM',\n JOIN_REQUEST_SENT = 'JOIN_REQUEST_SENT',\n CREATE_NEW_TEAM = 'CREATE_NEW_TEAM',\n REGISTRATION_SUCCESSFUL = 'REGISTRATION_SUCCESSFUL',\n}\n\nfunction getStepDialogTitle(step: ChallengeTeamWizardStep) {\n switch (step) {\n case ChallengeTeamWizardStep.SELECT_YOUR_CHALLENGE_TEAM:\n return 'Select Your Challenge Team'\n case ChallengeTeamWizardStep.ACCEPT_INVITATION:\n return 'Invitation to Join Team'\n case ChallengeTeamWizardStep.JOIN_REQUEST_FORM:\n return 'Request Team Membership'\n case ChallengeTeamWizardStep.JOIN_REQUEST_SENT:\n return 'Request Sent'\n case ChallengeTeamWizardStep.CREATE_NEW_TEAM:\n return 'Create Team'\n case ChallengeTeamWizardStep.REGISTRATION_SUCCESSFUL:\n return 'Registration Successful!'\n }\n}\n\nexport type ChallengeTeamWizardProps = {\n projectId: string\n isShowingModal?: boolean\n onClose: () => void\n}\n\n/**\n * The ChallengeTeamWizard is used to guide a user through the process of joining or creating a team for a challenge.\n *\n * A required precondition is that the user is NOT on any registered submission team for the challenge.\n */\nfunction ChallengeTeamWizard(props: ChallengeTeamWizardProps) {\n const { projectId, isShowingModal = false, onClose } = props\n const { isAuthenticated } = useSynapseContext()\n\n const [step, setStep] = useState<ChallengeTeamWizardStep>(\n ChallengeTeamWizardStep.SELECT_YOUR_CHALLENGE_TEAM,\n )\n const [selectedTeamId, setSelectedTeamId] = useState<string | undefined>()\n\n // Tracks if the form to create a new team is valid, so the wizard can control the `disabled` status of the confirm button\n const [canCreateNewTeam, setCanCreateNewTeam] = useState(false)\n // true if the user has created a new team to register for the challenge\n const [hasCreatedNewTeam, setHasCreatedNewTeam] = useState<boolean>(false)\n\n const membershipRequestFormRef = useRef<MembershipRequestFormHandle>(null)\n const createTeamRef = useRef<CreateChallengeTeamHandle>(null)\n\n const { data: userProfile, isLoading: isLoadingUserProfile } =\n useGetCurrentUserProfile({\n enabled: isAuthenticated,\n })\n\n // Retrieve the challenge associated with the projectId passed through props\n const { data: challenge, isLoading: isLoadingChallenge } =\n useGetEntityChallenge(projectId)\n\n const {\n mutateAsync: addTeamMember,\n isPending: addMemberToTeamIsPending,\n error: addUserToTeamError,\n } = useAddMemberToTeam()\n\n // Determine whether the given user belongs to any submission teams\n const { data: userSubmissionTeams, error: userSubmissionTeamError } =\n useGetUserSubmissionTeams(challenge?.id!, 1, 0, {\n enabled: Boolean(isAuthenticated && challenge),\n })\n\n const isMemberOfSubmissionTeam =\n userSubmissionTeams && userSubmissionTeams.results.length > 0\n\n const {\n data: selectedTeamMembershipStatus,\n isLoading: selectedTeamMembershipStatusIsLoading,\n error: selectedTeamMembershipStatusError,\n } = useGetMembershipStatus(selectedTeamId!, String(userProfile?.ownerId), {\n enabled: isAuthenticated && !!selectedTeamId && !!userProfile,\n })\n\n const addUserToTeam = useCallback(async () => {\n if (!selectedTeamId || !userProfile) return\n await addTeamMember({\n teamId: selectedTeamId,\n userId: userProfile.ownerId,\n })\n setStep(ChallengeTeamWizardStep.REGISTRATION_SUCCESSFUL)\n }, [addTeamMember, setStep, selectedTeamId, userProfile])\n\n const hide = useCallback(() => {\n setHasCreatedNewTeam(false)\n setSelectedTeamId(undefined)\n onClose()\n }, [onClose])\n\n const isLoading = isLoadingUserProfile || isLoadingChallenge\n\n const backButton = useMemo(() => {\n switch (step) {\n case ChallengeTeamWizardStep.SELECT_YOUR_CHALLENGE_TEAM:\n case ChallengeTeamWizardStep.JOIN_REQUEST_SENT:\n case ChallengeTeamWizardStep.REGISTRATION_SUCCESSFUL:\n // Cannot go back from these steps\n return <></>\n case ChallengeTeamWizardStep.ACCEPT_INVITATION:\n case ChallengeTeamWizardStep.JOIN_REQUEST_FORM:\n case ChallengeTeamWizardStep.CREATE_NEW_TEAM:\n default:\n // All the other steps go back to team selection\n return (\n <Button\n variant={'outlined'}\n onClick={() => {\n setStep(ChallengeTeamWizardStep.SELECT_YOUR_CHALLENGE_TEAM)\n setSelectedTeamId(undefined)\n }}\n >\n Back\n </Button>\n )\n }\n }, [step])\n\n const closeButton = useMemo(() => {\n return (\n <Button\n variant={'contained'}\n onClick={() => {\n onClose()\n }}\n >\n Close\n </Button>\n )\n }, [onClose])\n\n // Determine modal content based on step.id\n const { actions = <></>, content = <></> } = useMemo(() => {\n if (!isAuthenticated) {\n return {\n content: (\n <Alert severity={'error'}>\n <SignInPrompt />\n </Alert>\n ),\n }\n }\n\n if (isMemberOfSubmissionTeam) {\n return {\n content: (\n <Alert severity={'error'}>\n <Typography>\n You are already a member of a registered submission team for this\n Challenge.\n </Typography>\n </Alert>\n ),\n }\n }\n\n switch (step) {\n case ChallengeTeamWizardStep.SELECT_YOUR_CHALLENGE_TEAM: {\n let buttonText = 'Join Team'\n let disableJoiningSelectedTeam = false\n let buttonOnClickBehavior: () => void = noop\n let buttonTooltip = ''\n if (\n selectedTeamMembershipStatus &&\n selectedTeamMembershipStatus.hasOpenInvitation\n ) {\n // The user has been invited to join the selected team\n buttonText = 'View Invitation to Join Team'\n buttonOnClickBehavior = () => {\n setStep(ChallengeTeamWizardStep.ACCEPT_INVITATION)\n }\n } else if (\n selectedTeamMembershipStatus &&\n selectedTeamMembershipStatus.hasOpenRequest\n ) {\n // User already has an open request to join the selected team, disable button to avoid request spamming\n buttonText = 'Join Request Pending'\n disableJoiningSelectedTeam = true\n buttonTooltip =\n 'You have already submitted a request to join this team.'\n } else if (\n selectedTeamMembershipStatus &&\n selectedTeamMembershipStatus.membershipApprovalRequired\n ) {\n // The user has to send a request to join the selected team\n buttonText = 'Request to Join Team'\n buttonOnClickBehavior = () => {\n setStep(ChallengeTeamWizardStep.JOIN_REQUEST_FORM)\n }\n } else if (\n selectedTeamMembershipStatus &&\n selectedTeamMembershipStatus.canJoin\n ) {\n // The user can freely join the selected team\n buttonText = 'Join Team'\n buttonOnClickBehavior = () => {\n void addUserToTeam()\n }\n }\n return {\n content: challenge && !isMemberOfSubmissionTeam && (\n <SelectChallengeTeam\n challengeId={challenge.id}\n onCreateTeam={() =>\n setStep(ChallengeTeamWizardStep.CREATE_NEW_TEAM)\n }\n selectedTeamId={selectedTeamId}\n onSelectTeam={teamId => setSelectedTeamId(teamId)}\n />\n ),\n actions: (\n <>\n {backButton}\n <Tooltip title={buttonTooltip}>\n {/* Wrap button in span to show tooltip when button is disabled */}\n <span>\n <Button\n onClick={buttonOnClickBehavior}\n startIcon={\n addMemberToTeamIsPending ? <SynapseSpinner /> : undefined\n }\n disabled={\n !selectedTeamId ||\n selectedTeamMembershipStatusIsLoading ||\n addMemberToTeamIsPending ||\n disableJoiningSelectedTeam\n }\n variant={'contained'}\n >\n {buttonText}\n </Button>\n </span>\n </Tooltip>\n </>\n ),\n }\n }\n case ChallengeTeamWizardStep.ACCEPT_INVITATION:\n return {\n content: <OpenMembershipInvitation teamId={selectedTeamId!} />,\n actions: (\n <>\n {backButton}\n <AcceptMembershipInvitationButton\n teamId={selectedTeamId!}\n onSuccess={() => {\n setStep(ChallengeTeamWizardStep.REGISTRATION_SUCCESSFUL)\n }}\n />\n </>\n ),\n }\n case ChallengeTeamWizardStep.JOIN_REQUEST_FORM:\n return {\n content: (\n <MembershipRequestForm\n ref={membershipRequestFormRef}\n teamId={selectedTeamId!}\n onRequestSubmitted={() => {\n setStep(ChallengeTeamWizardStep.JOIN_REQUEST_SENT)\n }}\n />\n ),\n actions: (\n <>\n {backButton}\n <Button\n variant={'contained'}\n onClick={() => {\n membershipRequestFormRef?.current?.submit()\n }}\n >\n Send Request\n </Button>\n </>\n ),\n }\n\n case ChallengeTeamWizardStep.JOIN_REQUEST_SENT:\n return {\n content: (\n <Typography variant=\"body1\" sx={{ lineHeight: '20px' }}>\n Team Manager(s) have received your request. Check your Synapse\n email address for status of your request.\n </Typography>\n ),\n actions: (\n <>\n {backButton}\n {closeButton}\n </>\n ),\n }\n case ChallengeTeamWizardStep.REGISTRATION_SUCCESSFUL:\n return {\n content: (\n <RegistrationSuccessful\n createdNewTeam={hasCreatedNewTeam}\n teamId={selectedTeamId}\n />\n ),\n actions: (\n <>\n {backButton}\n {closeButton}\n </>\n ),\n }\n case ChallengeTeamWizardStep.CREATE_NEW_TEAM: {\n return {\n content: (\n <CreateChallengeTeam\n ref={createTeamRef}\n challengeId={challenge?.id!}\n onCanSubmitChange={canSubmit => setCanCreateNewTeam(canSubmit)}\n onFinished={teamId => {\n setHasCreatedNewTeam(true)\n setSelectedTeamId(teamId)\n setStep(ChallengeTeamWizardStep.REGISTRATION_SUCCESSFUL)\n }}\n />\n ),\n actions: (\n <>\n {backButton}\n <Button\n variant={'contained'}\n disabled={!canCreateNewTeam}\n onClick={() => {\n createTeamRef?.current?.submit()\n }}\n >\n Create Team\n </Button>\n </>\n ),\n }\n }\n }\n }, [\n isAuthenticated,\n isMemberOfSubmissionTeam,\n step,\n selectedTeamId,\n backButton,\n closeButton,\n hasCreatedNewTeam,\n selectedTeamMembershipStatus,\n challenge,\n addMemberToTeamIsPending,\n selectedTeamMembershipStatusIsLoading,\n addUserToTeam,\n canCreateNewTeam,\n ])\n\n const errorMessage =\n addUserToTeamError?.message ||\n selectedTeamMembershipStatusError?.message ||\n userSubmissionTeamError?.message\n\n return (\n <DialogBase\n onCancel={hide}\n open={isShowingModal}\n actions={actions}\n title={getStepDialogTitle(step)}\n content={\n <SynapseErrorBoundary>\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'column',\n gap: 1,\n }}\n >\n {isLoading ? (\n <SynapseSpinner size={40} />\n ) : (\n <>\n {content}\n {errorMessage && (\n <Alert severity={'error'}>{errorMessage}</Alert>\n )}\n </>\n )}\n </Box>\n </SynapseErrorBoundary>\n }\n />\n )\n}\n\nexport default ChallengeTeamWizard\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ChallengeTeamWizard.js","names":[],"sources":["../../../src/components/ChallengeTeamWizard/ChallengeTeamWizard.tsx"],"sourcesContent":["import {\n useAddMemberToTeam,\n useGetCurrentUserProfile,\n useGetEntityChallenge,\n useGetMembershipStatus,\n useGetUserSubmissionTeams,\n} from '@/synapse-queries'\nimport { useSynapseContext } from '@/utils'\nimport { Alert, Box, Button, Tooltip, Typography } from '@mui/material'\nimport { noop } from 'lodash-es'\nimport { useCallback, useMemo, useRef, useState } from 'react'\nimport { DialogBase } from '../DialogBase'\nimport { SignInPrompt, SynapseErrorBoundary } from '../error/ErrorBanner'\nimport { SynapseSpinner } from '../LoadingScreen/LoadingScreen'\nimport {\n CreateChallengeTeam,\n CreateChallengeTeamHandle,\n} from './CreateChallengeTeam'\nimport {\n MembershipRequestForm,\n MembershipRequestFormHandle,\n} from './MembershipRequestForm'\nimport {\n AcceptMembershipInvitationButton,\n OpenMembershipInvitation,\n} from './OpenMembershipInvitation'\nimport { RegistrationSuccessful } from './RegistrationSuccessful'\nimport { SelectChallengeTeam } from './SelectChallengeTeam'\n\nenum ChallengeTeamWizardStep {\n SELECT_YOUR_CHALLENGE_TEAM = 'SELECT_YOUR_CHALLENGE_TEAM',\n ACCEPT_INVITATION = 'ACCEPT_INVITATION',\n JOIN_REQUEST_FORM = 'JOIN_REQUEST_FORM',\n JOIN_REQUEST_SENT = 'JOIN_REQUEST_SENT',\n CREATE_NEW_TEAM = 'CREATE_NEW_TEAM',\n REGISTRATION_SUCCESSFUL = 'REGISTRATION_SUCCESSFUL',\n}\n\nfunction getStepDialogTitle(step: ChallengeTeamWizardStep) {\n switch (step) {\n case ChallengeTeamWizardStep.SELECT_YOUR_CHALLENGE_TEAM:\n return 'Select Your Challenge Team'\n case ChallengeTeamWizardStep.ACCEPT_INVITATION:\n return 'Invitation to Join Team'\n case ChallengeTeamWizardStep.JOIN_REQUEST_FORM:\n return 'Request Team Membership'\n case ChallengeTeamWizardStep.JOIN_REQUEST_SENT:\n return 'Request Sent'\n case ChallengeTeamWizardStep.CREATE_NEW_TEAM:\n return 'Create Team'\n case ChallengeTeamWizardStep.REGISTRATION_SUCCESSFUL:\n return 'Registration Successful!'\n }\n}\n\nexport type ChallengeTeamWizardProps = {\n projectId: string\n isShowingModal?: boolean\n onClose: () => void\n}\n\n/**\n * The ChallengeTeamWizard is used to guide a user through the process of joining or creating a team for a challenge.\n *\n * A required precondition is that the user is NOT on any registered submission team for the challenge.\n */\nfunction ChallengeTeamWizard(props: ChallengeTeamWizardProps) {\n const { projectId, isShowingModal = false, onClose } = props\n const { isAuthenticated } = useSynapseContext()\n\n const [step, setStep] = useState<ChallengeTeamWizardStep>(\n ChallengeTeamWizardStep.SELECT_YOUR_CHALLENGE_TEAM,\n )\n const [selectedTeamId, setSelectedTeamId] = useState<string | undefined>()\n\n // Tracks if the form to create a new team is valid, so the wizard can control the `disabled` status of the confirm button\n const [canCreateNewTeam, setCanCreateNewTeam] = useState(false)\n // true if the user has created a new team to register for the challenge\n const [hasCreatedNewTeam, setHasCreatedNewTeam] = useState<boolean>(false)\n\n const membershipRequestFormRef = useRef<MembershipRequestFormHandle>(null)\n const createTeamRef = useRef<CreateChallengeTeamHandle>(null)\n\n const { data: userProfile, isLoading: isLoadingUserProfile } =\n useGetCurrentUserProfile({\n enabled: isAuthenticated,\n })\n\n // Retrieve the challenge associated with the projectId passed through props\n const { data: challenge, isLoading: isLoadingChallenge } =\n useGetEntityChallenge(projectId)\n\n const {\n mutateAsync: addTeamMember,\n isPending: addMemberToTeamIsPending,\n error: addUserToTeamError,\n } = useAddMemberToTeam()\n\n // Determine whether the given user belongs to any submission teams\n const { data: userSubmissionTeams, error: userSubmissionTeamError } =\n useGetUserSubmissionTeams(challenge?.id!, 1, 0, {\n enabled: Boolean(isAuthenticated && challenge),\n })\n\n const isMemberOfSubmissionTeam =\n userSubmissionTeams && userSubmissionTeams.results.length > 0\n\n const {\n data: selectedTeamMembershipStatus,\n isLoading: selectedTeamMembershipStatusIsLoading,\n error: selectedTeamMembershipStatusError,\n } = useGetMembershipStatus(selectedTeamId!, String(userProfile?.ownerId), {\n enabled: isAuthenticated && !!selectedTeamId && !!userProfile,\n })\n\n const addUserToTeam = useCallback(async () => {\n if (!selectedTeamId || !userProfile) return\n await addTeamMember({\n teamId: selectedTeamId,\n userId: userProfile.ownerId,\n })\n setStep(ChallengeTeamWizardStep.REGISTRATION_SUCCESSFUL)\n }, [addTeamMember, setStep, selectedTeamId, userProfile])\n\n const hide = useCallback(() => {\n setHasCreatedNewTeam(false)\n setSelectedTeamId(undefined)\n onClose()\n }, [onClose])\n\n const isLoading = isLoadingUserProfile || isLoadingChallenge\n\n const backButton = useMemo(() => {\n switch (step) {\n case ChallengeTeamWizardStep.SELECT_YOUR_CHALLENGE_TEAM:\n case ChallengeTeamWizardStep.JOIN_REQUEST_SENT:\n case ChallengeTeamWizardStep.REGISTRATION_SUCCESSFUL:\n // Cannot go back from these steps\n return <></>\n case ChallengeTeamWizardStep.ACCEPT_INVITATION:\n case ChallengeTeamWizardStep.JOIN_REQUEST_FORM:\n case ChallengeTeamWizardStep.CREATE_NEW_TEAM:\n default:\n // All the other steps go back to team selection\n return (\n <Button\n variant={'outlined'}\n onClick={() => {\n setStep(ChallengeTeamWizardStep.SELECT_YOUR_CHALLENGE_TEAM)\n setSelectedTeamId(undefined)\n }}\n >\n Back\n </Button>\n )\n }\n }, [step])\n\n const closeButton = useMemo(() => {\n return (\n <Button\n variant={'contained'}\n onClick={() => {\n onClose()\n }}\n >\n Close\n </Button>\n )\n }, [onClose])\n\n // Determine modal content based on step.id\n const { actions = <></>, content = <></> } = useMemo(() => {\n if (!isAuthenticated) {\n return {\n content: (\n <Alert severity={'error'}>\n <SignInPrompt />\n </Alert>\n ),\n }\n }\n\n if (isMemberOfSubmissionTeam) {\n return {\n content: (\n <Alert severity={'error'}>\n <Typography>\n You are already a member of a registered submission team for this\n Challenge.\n </Typography>\n </Alert>\n ),\n }\n }\n\n switch (step) {\n case ChallengeTeamWizardStep.SELECT_YOUR_CHALLENGE_TEAM: {\n let buttonText = 'Join Team'\n let disableJoiningSelectedTeam = false\n let buttonOnClickBehavior: () => void = noop\n let buttonTooltip = ''\n if (\n selectedTeamMembershipStatus &&\n selectedTeamMembershipStatus.hasOpenInvitation\n ) {\n // The user has been invited to join the selected team\n buttonText = 'View Invitation to Join Team'\n buttonOnClickBehavior = () => {\n setStep(ChallengeTeamWizardStep.ACCEPT_INVITATION)\n }\n } else if (\n selectedTeamMembershipStatus &&\n selectedTeamMembershipStatus.hasOpenRequest\n ) {\n // User already has an open request to join the selected team, disable button to avoid request spamming\n buttonText = 'Join Request Pending'\n disableJoiningSelectedTeam = true\n buttonTooltip =\n 'You have already submitted a request to join this team.'\n } else if (\n selectedTeamMembershipStatus &&\n selectedTeamMembershipStatus.membershipApprovalRequired\n ) {\n // The user has to send a request to join the selected team\n buttonText = 'Request to Join Team'\n buttonOnClickBehavior = () => {\n setStep(ChallengeTeamWizardStep.JOIN_REQUEST_FORM)\n }\n } else if (\n selectedTeamMembershipStatus &&\n selectedTeamMembershipStatus.canJoin\n ) {\n // The user can freely join the selected team\n buttonText = 'Join Team'\n buttonOnClickBehavior = () => {\n void addUserToTeam()\n }\n }\n return {\n content: challenge && !isMemberOfSubmissionTeam && (\n <SelectChallengeTeam\n challengeId={challenge.id}\n onCreateTeam={() =>\n setStep(ChallengeTeamWizardStep.CREATE_NEW_TEAM)\n }\n selectedTeamId={selectedTeamId}\n onSelectTeam={teamId => setSelectedTeamId(teamId)}\n />\n ),\n actions: (\n <>\n {backButton}\n <Tooltip title={buttonTooltip}>\n {/* Wrap button in span to show tooltip when button is disabled */}\n <span>\n <Button\n onClick={buttonOnClickBehavior}\n startIcon={\n addMemberToTeamIsPending ? <SynapseSpinner /> : undefined\n }\n disabled={\n !selectedTeamId ||\n selectedTeamMembershipStatusIsLoading ||\n addMemberToTeamIsPending ||\n disableJoiningSelectedTeam\n }\n variant={'contained'}\n >\n {buttonText}\n </Button>\n </span>\n </Tooltip>\n </>\n ),\n }\n }\n case ChallengeTeamWizardStep.ACCEPT_INVITATION:\n return {\n content: <OpenMembershipInvitation teamId={selectedTeamId!} />,\n actions: (\n <>\n {backButton}\n <AcceptMembershipInvitationButton\n teamId={selectedTeamId!}\n onSuccess={() => {\n setStep(ChallengeTeamWizardStep.REGISTRATION_SUCCESSFUL)\n }}\n />\n </>\n ),\n }\n case ChallengeTeamWizardStep.JOIN_REQUEST_FORM:\n return {\n content: (\n <MembershipRequestForm\n ref={membershipRequestFormRef}\n teamId={selectedTeamId!}\n onRequestSubmitted={() => {\n setStep(ChallengeTeamWizardStep.JOIN_REQUEST_SENT)\n }}\n />\n ),\n actions: (\n <>\n {backButton}\n <Button\n variant={'contained'}\n onClick={() => {\n membershipRequestFormRef?.current?.submit()\n }}\n >\n Send Request\n </Button>\n </>\n ),\n }\n\n case ChallengeTeamWizardStep.JOIN_REQUEST_SENT:\n return {\n content: (\n <Typography variant=\"body1\" sx={{ lineHeight: '20px' }}>\n Team Manager(s) have received your request. Check your Synapse\n email address for status of your request.\n </Typography>\n ),\n actions: (\n <>\n {backButton}\n {closeButton}\n </>\n ),\n }\n case ChallengeTeamWizardStep.REGISTRATION_SUCCESSFUL:\n return {\n content: (\n <RegistrationSuccessful\n createdNewTeam={hasCreatedNewTeam}\n teamId={selectedTeamId}\n />\n ),\n actions: (\n <>\n {backButton}\n {closeButton}\n </>\n ),\n }\n case ChallengeTeamWizardStep.CREATE_NEW_TEAM: {\n return {\n content: (\n <CreateChallengeTeam\n ref={createTeamRef}\n challengeId={challenge?.id!}\n onCanSubmitChange={canSubmit => setCanCreateNewTeam(canSubmit)}\n onFinished={teamId => {\n setHasCreatedNewTeam(true)\n setSelectedTeamId(teamId)\n setStep(ChallengeTeamWizardStep.REGISTRATION_SUCCESSFUL)\n }}\n />\n ),\n actions: (\n <>\n {backButton}\n <Button\n variant={'contained'}\n disabled={!canCreateNewTeam}\n onClick={() => {\n createTeamRef?.current?.submit()\n }}\n >\n Create Team\n </Button>\n </>\n ),\n }\n }\n }\n }, [\n isAuthenticated,\n isMemberOfSubmissionTeam,\n step,\n selectedTeamId,\n backButton,\n closeButton,\n hasCreatedNewTeam,\n selectedTeamMembershipStatus,\n challenge,\n addMemberToTeamIsPending,\n selectedTeamMembershipStatusIsLoading,\n addUserToTeam,\n canCreateNewTeam,\n ])\n\n const errorMessage =\n addUserToTeamError?.message ||\n selectedTeamMembershipStatusError?.message ||\n userSubmissionTeamError?.message\n\n return (\n <DialogBase\n onCancel={hide}\n open={isShowingModal}\n actions={actions}\n title={getStepDialogTitle(step)}\n content={\n <SynapseErrorBoundary>\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'column',\n gap: 1,\n }}\n >\n {isLoading ? (\n <SynapseSpinner size={40} />\n ) : (\n <>\n {content}\n {errorMessage && (\n <Alert severity={'error'}>{errorMessage}</Alert>\n )}\n </>\n )}\n </Box>\n </SynapseErrorBoundary>\n }\n />\n )\n}\n\nexport default ChallengeTeamWizard\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateChallengeTeam.js","names":[],"sources":["../../../src/components/ChallengeTeamWizard/CreateChallengeTeam.tsx"],"sourcesContent":["import {\n ForwardedRef,\n forwardRef,\n useEffect,\n useImperativeHandle,\n useMemo,\n useState,\n} from 'react'\nimport { Alert, Box, Typography } from '@mui/material'\nimport TextField from '../TextField'\nimport { CreateTeamRequest, Team } from '@sage-bionetworks/synapse-types'\nimport useCreateAndRegisterChallengeTeam from './useCreateAndRegisterChallengeTeam'\nimport { isEmpty, noop } from 'lodash-es'\nimport papaparseLib from 'papaparse'\n// papaparse is CJS-only; pull named values from the default export.\nconst { parse } = papaparseLib\n\nexport type CreateChallengeTeamProps = {\n challengeId: string\n onCanSubmitChange?: (canSubmit: boolean) => void\n onFinished?: (teamId: string) => void\n}\n\nconst INVITEE_LIMIT = 3\nexport const TOO_MANY_INVITEES_ERROR =\n 'Please limit the initial number of invited members to three. You may add additional members after the team has been created.'\n\nexport type CreateChallengeTeamHandle = {\n // Allow the parent component to trigger a submit of the form, so this may be embedded in an arbitrary modal.\n submit: () => void\n}\n\nexport const CreateChallengeTeam = forwardRef(function CreateChallengeTeam(\n props: CreateChallengeTeamProps,\n ref: ForwardedRef<CreateChallengeTeamHandle>,\n) {\n const { challengeId, onCanSubmitChange = noop, onFinished = noop } = props\n const [team, setTeam] = useState<CreateTeamRequest>({\n name: '',\n description: '',\n })\n const [invitationMessage, setInvitationMessage] = useState('')\n const [rawInvitees, setRawInvitees] = useState('')\n\n const handleTeamUpdate = (update: Partial<Team>) => {\n const updatedTeam: CreateTeamRequest = { ...team, ...update }\n setTeam(updatedTeam)\n }\n\n const { inviteesParseResult, parsedInvitees } = useMemo(() => {\n const inviteesParseResult = parse<string[]>(rawInvitees, {\n delimiter: ',',\n transform(value) {\n return value.trim()\n },\n })\n const parsedInvitees: string[] = inviteesParseResult.data[0] || []\n\n return { inviteesParseResult, parsedInvitees }\n }, [rawInvitees])\n\n const numberOfInvitees = parsedInvitees.length\n const tooManyInvitees = numberOfInvitees > INVITEE_LIMIT\n\n const formDataIsValid = Boolean(\n team && team.name && team.name.length > 1 && !tooManyInvitees,\n )\n\n useEffect(() => {\n onCanSubmitChange(formDataIsValid)\n }, [formDataIsValid, onCanSubmitChange])\n\n const {\n createAndRegisterTeam,\n isPending: mutationIsPending,\n errors,\n } = useCreateAndRegisterChallengeTeam()\n\n useImperativeHandle(\n ref,\n () => {\n return {\n submit() {\n if (!formDataIsValid) {\n console.warn(\n 'Attempted to submit when form data was not valid. Nothing will happen.',\n )\n return\n }\n createAndRegisterTeam(\n team,\n challengeId,\n parsedInvitees,\n invitationMessage,\n )\n .then(([newTeam]) => {\n onFinished(newTeam.id)\n })\n .catch(() => {\n // The hook will return errors, so no need to handle them here\n })\n },\n }\n },\n [\n formDataIsValid,\n parsedInvitees,\n createAndRegisterTeam,\n team,\n challengeId,\n invitationMessage,\n onFinished,\n ],\n )\n\n return (\n <Box>\n <Typography variant=\"body1\" sx={{ lineHeight: '20px' }}>\n Create a new team for this Challenge!\n </Typography>\n <TextField\n id=\"name\"\n label=\"Team Name\"\n value={team.name}\n fullWidth\n autoFocus\n required\n onChange={event => handleTeamUpdate({ name: event.target.value })}\n disabled={mutationIsPending}\n />\n <Box\n sx={{\n display: 'flex',\n }}\n >\n <TextField\n id=\"description\"\n label={\n <Box\n sx={{\n display: 'flex',\n gap: 2,\n }}\n >\n <Box>Team Description</Box>\n </Box>\n }\n value={team.description}\n fullWidth\n multiline\n rows={4}\n onChange={event =>\n handleTeamUpdate({ description: event.target.value })\n }\n disabled={mutationIsPending}\n />\n </Box>\n <Box\n sx={{\n display: 'flex',\n }}\n >\n <TextField\n id=\"message\"\n label={\n <Box\n sx={{\n display: 'flex',\n gap: 2,\n }}\n >\n <Box>Recruitment Message</Box>\n </Box>\n }\n value={invitationMessage}\n fullWidth\n multiline\n rows={4}\n onChange={event => setInvitationMessage(event.target.value)}\n disabled={mutationIsPending}\n />\n </Box>\n <TextField\n id=\"invitees\"\n label=\"Emails of Additional Members to Invite (max 3)\"\n placeholder=\"Enter emails separated by comma\"\n value={rawInvitees}\n fullWidth\n onChange={event => setRawInvitees(event.target.value)}\n disabled={mutationIsPending}\n />\n {(tooManyInvitees || !isEmpty(inviteesParseResult.errors) || errors) && (\n <Alert severity=\"error\">\n {tooManyInvitees && (\n <Typography variant={'body1'}>{TOO_MANY_INVITEES_ERROR}</Typography>\n )}\n {inviteesParseResult.errors.map((error, index) => (\n <Typography key={index} variant={'body1'}>\n {error.message}\n </Typography>\n ))}\n {errors &&\n errors.map(error => (\n <Typography key={error.reason} variant={'body1'}>\n {error.reason}\n </Typography>\n ))}\n </Alert>\n )}\n </Box>\n )\n})\n"],"mappings":";;;;;;;;AAeA,IAAM,EAAE,aAAU,GAQZ,IAAgB,GACT,IACX,gIAOW,IAAsB,EAAW,SAC5C,GACA,GACA;CACA,IAAM,EAAE,gBAAa,uBAAoB,GAAM,gBAAa,MAAS,GAC/D,CAAC,GAAM,KAAW,EAA4B;EAClD,MAAM;EACN,aAAa;EACd,CAAC,EACI,CAAC,GAAmB,KAAwB,EAAS,GAAG,EACxD,CAAC,GAAa,KAAkB,EAAS,GAAG,EAE5C,KAAoB,MAA0B;AAElD,
|
|
1
|
+
{"version":3,"file":"CreateChallengeTeam.js","names":[],"sources":["../../../src/components/ChallengeTeamWizard/CreateChallengeTeam.tsx"],"sourcesContent":["import {\n ForwardedRef,\n forwardRef,\n useEffect,\n useImperativeHandle,\n useMemo,\n useState,\n} from 'react'\nimport { Alert, Box, Typography } from '@mui/material'\nimport TextField from '../TextField'\nimport { CreateTeamRequest, Team } from '@sage-bionetworks/synapse-types'\nimport useCreateAndRegisterChallengeTeam from './useCreateAndRegisterChallengeTeam'\nimport { isEmpty, noop } from 'lodash-es'\nimport papaparseLib from 'papaparse'\n// papaparse is CJS-only; pull named values from the default export.\nconst { parse } = papaparseLib\n\nexport type CreateChallengeTeamProps = {\n challengeId: string\n onCanSubmitChange?: (canSubmit: boolean) => void\n onFinished?: (teamId: string) => void\n}\n\nconst INVITEE_LIMIT = 3\nexport const TOO_MANY_INVITEES_ERROR =\n 'Please limit the initial number of invited members to three. You may add additional members after the team has been created.'\n\nexport type CreateChallengeTeamHandle = {\n // Allow the parent component to trigger a submit of the form, so this may be embedded in an arbitrary modal.\n submit: () => void\n}\n\nexport const CreateChallengeTeam = forwardRef(function CreateChallengeTeam(\n props: CreateChallengeTeamProps,\n ref: ForwardedRef<CreateChallengeTeamHandle>,\n) {\n const { challengeId, onCanSubmitChange = noop, onFinished = noop } = props\n const [team, setTeam] = useState<CreateTeamRequest>({\n name: '',\n description: '',\n })\n const [invitationMessage, setInvitationMessage] = useState('')\n const [rawInvitees, setRawInvitees] = useState('')\n\n const handleTeamUpdate = (update: Partial<Team>) => {\n const updatedTeam: CreateTeamRequest = { ...team, ...update }\n setTeam(updatedTeam)\n }\n\n const { inviteesParseResult, parsedInvitees } = useMemo(() => {\n const inviteesParseResult = parse<string[]>(rawInvitees, {\n delimiter: ',',\n transform(value) {\n return value.trim()\n },\n })\n const parsedInvitees: string[] = inviteesParseResult.data[0] || []\n\n return { inviteesParseResult, parsedInvitees }\n }, [rawInvitees])\n\n const numberOfInvitees = parsedInvitees.length\n const tooManyInvitees = numberOfInvitees > INVITEE_LIMIT\n\n const formDataIsValid = Boolean(\n team && team.name && team.name.length > 1 && !tooManyInvitees,\n )\n\n useEffect(() => {\n onCanSubmitChange(formDataIsValid)\n }, [formDataIsValid, onCanSubmitChange])\n\n const {\n createAndRegisterTeam,\n isPending: mutationIsPending,\n errors,\n } = useCreateAndRegisterChallengeTeam()\n\n useImperativeHandle(\n ref,\n () => {\n return {\n submit() {\n if (!formDataIsValid) {\n console.warn(\n 'Attempted to submit when form data was not valid. Nothing will happen.',\n )\n return\n }\n createAndRegisterTeam(\n team,\n challengeId,\n parsedInvitees,\n invitationMessage,\n )\n .then(([newTeam]) => {\n onFinished(newTeam.id)\n })\n .catch(() => {\n // The hook will return errors, so no need to handle them here\n })\n },\n }\n },\n [\n formDataIsValid,\n parsedInvitees,\n createAndRegisterTeam,\n team,\n challengeId,\n invitationMessage,\n onFinished,\n ],\n )\n\n return (\n <Box>\n <Typography variant=\"body1\" sx={{ lineHeight: '20px' }}>\n Create a new team for this Challenge!\n </Typography>\n <TextField\n id=\"name\"\n label=\"Team Name\"\n value={team.name}\n fullWidth\n autoFocus\n required\n onChange={event => handleTeamUpdate({ name: event.target.value })}\n disabled={mutationIsPending}\n />\n <Box\n sx={{\n display: 'flex',\n }}\n >\n <TextField\n id=\"description\"\n label={\n <Box\n sx={{\n display: 'flex',\n gap: 2,\n }}\n >\n <Box>Team Description</Box>\n </Box>\n }\n value={team.description}\n fullWidth\n multiline\n rows={4}\n onChange={event =>\n handleTeamUpdate({ description: event.target.value })\n }\n disabled={mutationIsPending}\n />\n </Box>\n <Box\n sx={{\n display: 'flex',\n }}\n >\n <TextField\n id=\"message\"\n label={\n <Box\n sx={{\n display: 'flex',\n gap: 2,\n }}\n >\n <Box>Recruitment Message</Box>\n </Box>\n }\n value={invitationMessage}\n fullWidth\n multiline\n rows={4}\n onChange={event => setInvitationMessage(event.target.value)}\n disabled={mutationIsPending}\n />\n </Box>\n <TextField\n id=\"invitees\"\n label=\"Emails of Additional Members to Invite (max 3)\"\n placeholder=\"Enter emails separated by comma\"\n value={rawInvitees}\n fullWidth\n onChange={event => setRawInvitees(event.target.value)}\n disabled={mutationIsPending}\n />\n {(tooManyInvitees || !isEmpty(inviteesParseResult.errors) || errors) && (\n <Alert severity=\"error\">\n {tooManyInvitees && (\n <Typography variant={'body1'}>{TOO_MANY_INVITEES_ERROR}</Typography>\n )}\n {inviteesParseResult.errors.map((error, index) => (\n <Typography key={index} variant={'body1'}>\n {error.message}\n </Typography>\n ))}\n {errors &&\n errors.map(error => (\n <Typography key={error.reason} variant={'body1'}>\n {error.reason}\n </Typography>\n ))}\n </Alert>\n )}\n </Box>\n )\n})\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChangePassword.js","names":[],"sources":["../../../src/components/ChangePassword/ChangePassword.tsx"],"sourcesContent":["import { useGetCurrentUserProfile } from '@/synapse-queries'\nimport { useSynapseContext } from '@/utils'\nimport { validatePassword } from '@/utils/functions/StringUtils'\nimport { Alert, Button, Link, TextField } from '@mui/material'\nimport { FormEvent, useEffect, useState } from 'react'\nimport { Link as RouterLink, Navigate } from 'react-router'\nimport { displayToast } from '../ToastMessage'\nimport useChangePasswordFormState from './useChangePasswordFormState'\n\nexport const PASSWORD_CHANGED_SUCCESS_MESSAGE =\n 'Your password was successfully changed.'\n\nexport type ChangePasswordProps = {\n redirectToRoute?: string //optional target to send user after successfully changing the password\n hideReset2FA?: boolean\n}\n\nexport default function ChangePassword(props: ChangePasswordProps) {\n const { redirectToRoute, hideReset2FA = false } = props\n const [oldPassword, setOldPassword] = useState<string>('')\n const [newPassword, setNewPassword] = useState<string>('')\n const [newPasswordError, setNewPasswordError] = useState<string | undefined>(\n undefined,\n )\n const [confirmPassword, setConfirmPassword] = useState<string>('')\n const [userName, setUserName] = useState<string>('')\n const { isAuthenticated } = useSynapseContext()\n\n const { data: userProfile, isLoading: isLoadingUserProfile } =\n useGetCurrentUserProfile({\n enabled: isAuthenticated,\n })\n\n useEffect(() => {\n if (userProfile && userName == '') {\n setUserName(userProfile.userName ?? userProfile.emails![0]) // if username is not set, use the first email\n }\n }, [userName, userProfile, userProfile?.userName])\n\n const {\n promptForTwoFactorAuth,\n TwoFactorAuthPrompt,\n successfullyChangedPassword,\n isPending: changePasswordIsPending,\n handleChangePasswordWithCurrentPassword,\n error,\n } = useChangePasswordFormState({\n hideReset2FA,\n })\n\n const handleChangePassword = (clickEvent: FormEvent<HTMLElement>) => {\n clickEvent.preventDefault()\n if (newPassword !== confirmPassword) {\n displayToast('Passwords do not match.', 'danger')\n } else {\n handleChangePasswordWithCurrentPassword(\n userName,\n oldPassword,\n newPassword,\n )\n }\n }\n\n if (successfullyChangedPassword) {\n if (redirectToRoute) {\n displayToast(PASSWORD_CHANGED_SUCCESS_MESSAGE, 'success')\n return <Navigate to={redirectToRoute} />\n } else {\n return (\n <Alert severity={'success'}>{PASSWORD_CHANGED_SUCCESS_MESSAGE}</Alert>\n )\n }\n }\n\n return (\n <div>\n {promptForTwoFactorAuth ? (\n <TwoFactorAuthPrompt />\n ) : (\n <form\n onSubmit={e => {\n handleChangePassword(e)\n }}\n >\n {!isAuthenticated && (\n <TextField\n required\n fullWidth\n autoFocus\n autoComplete=\"username\"\n label=\"Username or Email Address\"\n id=\"username\"\n type=\"text\"\n value={userName}\n onChange={e => setUserName(e.target.value)}\n />\n )}\n <TextField\n fullWidth\n required\n margin={'normal'}\n type=\"password\"\n id=\"currentPassword\"\n label={'Current password'}\n onChange={e => setOldPassword(e.target.value)}\n value={oldPassword}\n />\n <TextField\n fullWidth\n required\n helperText={newPasswordError}\n margin={'normal'}\n type=\"password\"\n id=\"newPassword\"\n label={'New password'}\n onChange={e => {\n const error = validatePassword(e.target.value)\n setNewPasswordError(error)\n setNewPassword(e.target.value)\n }}\n value={newPassword}\n />\n <TextField\n fullWidth\n required\n margin={'normal'}\n type=\"password\"\n id=\"confirmPassword\"\n label={'Confirm password'}\n onChange={e => setConfirmPassword(e.target.value)}\n value={confirmPassword}\n />\n <div style={{ marginTop: '30px' }}>\n <Button\n sx={{ marginRight: '26px' }}\n disabled={\n !oldPassword ||\n !newPassword ||\n !confirmPassword ||\n !userName ||\n isLoadingUserProfile ||\n changePasswordIsPending\n }\n variant=\"contained\"\n type=\"submit\"\n >\n Change Password\n </Button>\n <Link\n component={RouterLink}\n to=\"/resetPassword\"\n sx={{ display: 'block', marginTop: '1em', marginLeft: '5px' }}\n >\n Forgot password?\n </Link>\n </div>\n </form>\n )}\n {error && (\n <Alert severity={'error'} sx={{ my: 2 }}>\n {error.reason}\n </Alert>\n )}\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;;;AASA,IAAa,IACX;AAOF,SAAwB,EAAe,GAA4B;CACjE,IAAM,EAAE,oBAAiB,kBAAe,OAAU,GAC5C,CAAC,GAAa,KAAkB,EAAiB,GAAG,EACpD,CAAC,GAAa,KAAkB,EAAiB,GAAG,EACpD,CAAC,GAAkB,KAAuB,EAC9C,KAAA,EACD,EACK,CAAC,GAAiB,KAAsB,EAAiB,GAAG,EAC5D,CAAC,GAAU,KAAe,EAAiB,GAAG,EAC9C,EAAE,uBAAoB,GAAmB,EAEzC,EAAE,MAAM,GAAa,WAAW,MACpC,EAAyB,EACvB,SAAS,GACV,CAAC;AAEJ,SAAgB;AACd,EAAI,KAAe,KAAY,MAC7B,EAAY,EAAY,YAAY,EAAY,OAAQ,GAAG;IAE5D;EAAC;EAAU;EAAa,GAAa;EAAS,CAAC;CAElD,IAAM,EACJ,2BACA,wBACA,gCACA,WAAW,GACX,4CACA,aACE,EAA2B,EAC7B,iBACD,CAAC,EAEI,KAAwB,MAAuC;AAEnE,EADA,EAAW,gBAAgB,EACvB,MAAgB,IAGlB,EACE,GACA,GACA,EACD,GAND,EAAa,2BAA2B,SAAS;;AAqBrD,QAXI,IACE,KACF,EAAa,GAAkC,UAAU,EAClD,kBAAC,GAAD,EAAU,IAAI,GAAmB,CAAA,IAGtC,kBAAC,GAAD;EAAO,UAAU;YAAY;EAAyC,CAAA,GAM1E,kBAAC,OAAD,EAAA,UAAA,CACG,IACC,kBAAC,GAAD,EAAuB,CAAA,GAEvB,kBAAC,QAAD;EACE,WAAU,MAAK;AACb,KAAqB,EAAE;;YAF3B;GAKG,CAAC,KACA,kBAAC,GAAD;IACE,UAAA;IACA,WAAA;IACA,WAAA;IACA,cAAa;IACb,OAAM;IACN,IAAG;IACH,MAAK;IACL,OAAO;IACP,WAAU,MAAK,EAAY,EAAE,OAAO,MAAM;IAC1C,CAAA;GAEJ,kBAAC,GAAD;IACE,WAAA;IACA,UAAA;IACA,QAAQ;IACR,MAAK;IACL,IAAG;IACH,OAAO;IACP,WAAU,MAAK,EAAe,EAAE,OAAO,MAAM;IAC7C,OAAO;IACP,CAAA;GACF,kBAAC,GAAD;IACE,WAAA;IACA,UAAA;IACA,YAAY;IACZ,QAAQ;IACR,MAAK;IACL,IAAG;IACH,OAAO;IACP,WAAU,MAAK;AAGb,KADA,EADc,EAAiB,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"ChangePassword.js","names":[],"sources":["../../../src/components/ChangePassword/ChangePassword.tsx"],"sourcesContent":["import { useGetCurrentUserProfile } from '@/synapse-queries'\nimport { useSynapseContext } from '@/utils'\nimport { validatePassword } from '@/utils/functions/StringUtils'\nimport { Alert, Button, Link, TextField } from '@mui/material'\nimport { FormEvent, useEffect, useState } from 'react'\nimport { Link as RouterLink, Navigate } from 'react-router'\nimport { displayToast } from '../ToastMessage'\nimport useChangePasswordFormState from './useChangePasswordFormState'\n\nexport const PASSWORD_CHANGED_SUCCESS_MESSAGE =\n 'Your password was successfully changed.'\n\nexport type ChangePasswordProps = {\n redirectToRoute?: string //optional target to send user after successfully changing the password\n hideReset2FA?: boolean\n}\n\nexport default function ChangePassword(props: ChangePasswordProps) {\n const { redirectToRoute, hideReset2FA = false } = props\n const [oldPassword, setOldPassword] = useState<string>('')\n const [newPassword, setNewPassword] = useState<string>('')\n const [newPasswordError, setNewPasswordError] = useState<string | undefined>(\n undefined,\n )\n const [confirmPassword, setConfirmPassword] = useState<string>('')\n const [userName, setUserName] = useState<string>('')\n const { isAuthenticated } = useSynapseContext()\n\n const { data: userProfile, isLoading: isLoadingUserProfile } =\n useGetCurrentUserProfile({\n enabled: isAuthenticated,\n })\n\n useEffect(() => {\n if (userProfile && userName == '') {\n setUserName(userProfile.userName ?? userProfile.emails![0]) // if username is not set, use the first email\n }\n }, [userName, userProfile, userProfile?.userName])\n\n const {\n promptForTwoFactorAuth,\n TwoFactorAuthPrompt,\n successfullyChangedPassword,\n isPending: changePasswordIsPending,\n handleChangePasswordWithCurrentPassword,\n error,\n } = useChangePasswordFormState({\n hideReset2FA,\n })\n\n const handleChangePassword = (clickEvent: FormEvent<HTMLElement>) => {\n clickEvent.preventDefault()\n if (newPassword !== confirmPassword) {\n displayToast('Passwords do not match.', 'danger')\n } else {\n handleChangePasswordWithCurrentPassword(\n userName,\n oldPassword,\n newPassword,\n )\n }\n }\n\n if (successfullyChangedPassword) {\n if (redirectToRoute) {\n displayToast(PASSWORD_CHANGED_SUCCESS_MESSAGE, 'success')\n return <Navigate to={redirectToRoute} />\n } else {\n return (\n <Alert severity={'success'}>{PASSWORD_CHANGED_SUCCESS_MESSAGE}</Alert>\n )\n }\n }\n\n return (\n <div>\n {promptForTwoFactorAuth ? (\n <TwoFactorAuthPrompt />\n ) : (\n <form\n onSubmit={e => {\n handleChangePassword(e)\n }}\n >\n {!isAuthenticated && (\n <TextField\n required\n fullWidth\n autoFocus\n autoComplete=\"username\"\n label=\"Username or Email Address\"\n id=\"username\"\n type=\"text\"\n value={userName}\n onChange={e => setUserName(e.target.value)}\n />\n )}\n <TextField\n fullWidth\n required\n margin={'normal'}\n type=\"password\"\n id=\"currentPassword\"\n label={'Current password'}\n onChange={e => setOldPassword(e.target.value)}\n value={oldPassword}\n />\n <TextField\n fullWidth\n required\n helperText={newPasswordError}\n margin={'normal'}\n type=\"password\"\n id=\"newPassword\"\n label={'New password'}\n onChange={e => {\n const error = validatePassword(e.target.value)\n setNewPasswordError(error)\n setNewPassword(e.target.value)\n }}\n value={newPassword}\n />\n <TextField\n fullWidth\n required\n margin={'normal'}\n type=\"password\"\n id=\"confirmPassword\"\n label={'Confirm password'}\n onChange={e => setConfirmPassword(e.target.value)}\n value={confirmPassword}\n />\n <div style={{ marginTop: '30px' }}>\n <Button\n sx={{ marginRight: '26px' }}\n disabled={\n !oldPassword ||\n !newPassword ||\n !confirmPassword ||\n !userName ||\n isLoadingUserProfile ||\n changePasswordIsPending\n }\n variant=\"contained\"\n type=\"submit\"\n >\n Change Password\n </Button>\n <Link\n component={RouterLink}\n to=\"/resetPassword\"\n sx={{ display: 'block', marginTop: '1em', marginLeft: '5px' }}\n >\n Forgot password?\n </Link>\n </div>\n </form>\n )}\n {error && (\n <Alert severity={'error'} sx={{ my: 2 }}>\n {error.reason}\n </Alert>\n )}\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;;;AASA,IAAa,IACX;AAOF,SAAwB,EAAe,GAA4B;CACjE,IAAM,EAAE,oBAAiB,kBAAe,OAAU,GAC5C,CAAC,GAAa,KAAkB,EAAiB,GAAG,EACpD,CAAC,GAAa,KAAkB,EAAiB,GAAG,EACpD,CAAC,GAAkB,KAAuB,EAC9C,KAAA,EACD,EACK,CAAC,GAAiB,KAAsB,EAAiB,GAAG,EAC5D,CAAC,GAAU,KAAe,EAAiB,GAAG,EAC9C,EAAE,uBAAoB,GAAmB,EAEzC,EAAE,MAAM,GAAa,WAAW,MACpC,EAAyB,EACvB,SAAS,GACV,CAAC;AAEJ,SAAgB;AACd,EAAI,KAAe,KAAY,MAC7B,EAAY,EAAY,YAAY,EAAY,OAAQ,GAAG;IAE5D;EAAC;EAAU;EAAa,GAAa;EAAS,CAAC;CAElD,IAAM,EACJ,2BACA,wBACA,gCACA,WAAW,GACX,4CACA,aACE,EAA2B,EAC7B,iBACD,CAAC,EAEI,KAAwB,MAAuC;AAEnE,EADA,EAAW,gBAAgB,EACvB,MAAgB,IAGlB,EACE,GACA,GACA,EACD,GAND,EAAa,2BAA2B,SAAS;;AAqBrD,QAXI,IACE,KACF,EAAa,GAAkC,UAAU,EAClD,kBAAC,GAAD,EAAU,IAAI,GAAmB,CAAA,IAGtC,kBAAC,GAAD;EAAO,UAAU;YAAY;EAAyC,CAAA,GAM1E,kBAAC,OAAD,EAAA,UAAA,CACG,IACC,kBAAC,GAAD,EAAuB,CAAA,GAEvB,kBAAC,QAAD;EACE,WAAU,MAAK;AACb,KAAqB,EAAE;;YAF3B;GAKG,CAAC,KACA,kBAAC,GAAD;IACE,UAAA;IACA,WAAA;IACA,WAAA;IACA,cAAa;IACb,OAAM;IACN,IAAG;IACH,MAAK;IACL,OAAO;IACP,WAAU,MAAK,EAAY,EAAE,OAAO,MAAM;IAC1C,CAAA;GAEJ,kBAAC,GAAD;IACE,WAAA;IACA,UAAA;IACA,QAAQ;IACR,MAAK;IACL,IAAG;IACH,OAAO;IACP,WAAU,MAAK,EAAe,EAAE,OAAO,MAAM;IAC7C,OAAO;IACP,CAAA;GACF,kBAAC,GAAD;IACE,WAAA;IACA,UAAA;IACA,YAAY;IACZ,QAAQ;IACR,MAAK;IACL,IAAG;IACH,OAAO;IACP,WAAU,MAAK;AAGb,KADA,EADc,EAAiB,EAAE,OAAO,MACpB,CAAM,EAC1B,EAAe,EAAE,OAAO,MAAM;;IAEhC,OAAO;IACP,CAAA;GACF,kBAAC,GAAD;IACE,WAAA;IACA,UAAA;IACA,QAAQ;IACR,MAAK;IACL,IAAG;IACH,OAAO;IACP,WAAU,MAAK,EAAmB,EAAE,OAAO,MAAM;IACjD,OAAO;IACP,CAAA;GACF,kBAAC,OAAD;IAAK,OAAO,EAAE,WAAW,QAAQ;cAAjC,CACE,kBAAC,GAAD;KACE,IAAI,EAAE,aAAa,QAAQ;KAC3B,UACE,CAAC,KACD,CAAC,KACD,CAAC,KACD,CAAC,KACD,KACA;KAEF,SAAQ;KACR,MAAK;eACN;KAEQ,CAAA,EACT,kBAAC,GAAD;KACE,WAAW;KACX,IAAG;KACH,IAAI;MAAE,SAAS;MAAS,WAAW;MAAO,YAAY;MAAO;eAC9D;KAEM,CAAA,CACH;;GACD;KAER,KACC,kBAAC,GAAD;EAAO,UAAU;EAAS,IAAI,EAAE,IAAI,GAAG;YACpC,EAAM;EACD,CAAA,CAEN,EAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChangePasswordWithToken.js","names":[],"sources":["../../../src/components/ChangePassword/ChangePasswordWithToken.tsx"],"sourcesContent":["import { validatePassword } from '@/utils/functions/StringUtils'\nimport { Alert, Button, TextField } from '@mui/material'\nimport { PasswordResetSignedToken } from '@sage-bionetworks/synapse-types'\nimport { FormEvent, useState } from 'react'\nimport { displayToast } from '../ToastMessage'\nimport useChangePasswordFormState from './useChangePasswordFormState'\n\ntype ChangePasswordWithTokenProps = {\n passwordChangeToken: PasswordResetSignedToken\n onSuccess: () => void\n}\n\nexport default function ChangePasswordWithToken(\n props: ChangePasswordWithTokenProps,\n) {\n const { passwordChangeToken, onSuccess } = props\n const [newPassword, setNewPassword] = useState<string>('')\n const [confirmPassword, setConfirmPassword] = useState<string>('')\n const [newPasswordError, setNewPasswordError] = useState<string | undefined>(\n undefined,\n )\n\n const {\n promptForTwoFactorAuth,\n TwoFactorAuthPrompt,\n isPending: changePasswordIsPending,\n handleChangePasswordWithResetToken,\n error,\n } = useChangePasswordFormState({\n onChangePasswordSuccess: () => {\n setNewPassword('')\n setConfirmPassword('')\n displayToast('Password successfully changed.', 'success')\n onSuccess()\n },\n })\n\n const handleChangePassword = (clickEvent: FormEvent<HTMLElement>) => {\n clickEvent.preventDefault()\n if (newPassword !== confirmPassword) {\n displayToast('Passwords do not match.', 'danger')\n } else {\n handleChangePasswordWithResetToken(newPassword, passwordChangeToken)\n }\n }\n\n return (\n <div>\n {promptForTwoFactorAuth ? (\n <TwoFactorAuthPrompt />\n ) : (\n <form\n onSubmit={e => {\n handleChangePassword(e)\n }}\n >\n <TextField\n fullWidth\n required\n helperText={newPasswordError}\n type=\"password\"\n id=\"newPassword\"\n name=\"newPassword\"\n label={'New password'}\n onChange={e => {\n const error = validatePassword(e.target.value)\n setNewPasswordError(error)\n setNewPassword(e.target.value)\n }}\n value={newPassword || ''}\n sx={{ mb: 2 }}\n />\n <TextField\n fullWidth\n required\n type=\"password\"\n id=\"confirmPassword\"\n name=\"confirmPassword\"\n label={'Confirm password'}\n onChange={e => setConfirmPassword(e.target.value)}\n value={confirmPassword || ''}\n sx={{ mb: 2 }}\n />\n <Button\n variant=\"contained\"\n type=\"submit\"\n fullWidth\n disabled={\n !newPassword || !confirmPassword || changePasswordIsPending\n }\n sx={{ mt: 3, py: 2 }}\n >\n Change Password\n </Button>\n </form>\n )}\n {error && (\n <Alert severity={'error'} sx={{ my: 2 }}>\n {error.reason}\n </Alert>\n )}\n </div>\n )\n}\n"],"mappings":";;;;;;;;AAYA,SAAwB,EACtB,GACA;CACA,IAAM,EAAE,wBAAqB,iBAAc,GACrC,CAAC,GAAa,KAAkB,EAAiB,GAAG,EACpD,CAAC,GAAiB,KAAsB,EAAiB,GAAG,EAC5D,CAAC,GAAkB,KAAuB,EAC9C,KAAA,EACD,EAEK,EACJ,2BACA,wBACA,WAAW,GACX,uCACA,aACE,EAA2B,EAC7B,+BAA+B;AAI7B,EAHA,EAAe,GAAG,EAClB,EAAmB,GAAG,EACtB,EAAa,kCAAkC,UAAU,EACzD,GAAW;IAEd,CAAC,EAEI,KAAwB,MAAuC;AAEnE,EADA,EAAW,gBAAgB,EACvB,MAAgB,IAGlB,EAAmC,GAAa,EAAoB,GAFpE,EAAa,2BAA2B,SAAS;;AAMrD,QACE,kBAAC,OAAD,EAAA,UAAA,CACG,IACC,kBAAC,GAAD,EAAuB,CAAA,GAEvB,kBAAC,QAAD;EACE,WAAU,MAAK;AACb,KAAqB,EAAE;;YAF3B;GAKE,kBAAC,GAAD;IACE,WAAA;IACA,UAAA;IACA,YAAY;IACZ,MAAK;IACL,IAAG;IACH,MAAK;IACL,OAAO;IACP,WAAU,MAAK;AAGb,KADA,EADc,EAAiB,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"ChangePasswordWithToken.js","names":[],"sources":["../../../src/components/ChangePassword/ChangePasswordWithToken.tsx"],"sourcesContent":["import { validatePassword } from '@/utils/functions/StringUtils'\nimport { Alert, Button, TextField } from '@mui/material'\nimport { PasswordResetSignedToken } from '@sage-bionetworks/synapse-types'\nimport { FormEvent, useState } from 'react'\nimport { displayToast } from '../ToastMessage'\nimport useChangePasswordFormState from './useChangePasswordFormState'\n\ntype ChangePasswordWithTokenProps = {\n passwordChangeToken: PasswordResetSignedToken\n onSuccess: () => void\n}\n\nexport default function ChangePasswordWithToken(\n props: ChangePasswordWithTokenProps,\n) {\n const { passwordChangeToken, onSuccess } = props\n const [newPassword, setNewPassword] = useState<string>('')\n const [confirmPassword, setConfirmPassword] = useState<string>('')\n const [newPasswordError, setNewPasswordError] = useState<string | undefined>(\n undefined,\n )\n\n const {\n promptForTwoFactorAuth,\n TwoFactorAuthPrompt,\n isPending: changePasswordIsPending,\n handleChangePasswordWithResetToken,\n error,\n } = useChangePasswordFormState({\n onChangePasswordSuccess: () => {\n setNewPassword('')\n setConfirmPassword('')\n displayToast('Password successfully changed.', 'success')\n onSuccess()\n },\n })\n\n const handleChangePassword = (clickEvent: FormEvent<HTMLElement>) => {\n clickEvent.preventDefault()\n if (newPassword !== confirmPassword) {\n displayToast('Passwords do not match.', 'danger')\n } else {\n handleChangePasswordWithResetToken(newPassword, passwordChangeToken)\n }\n }\n\n return (\n <div>\n {promptForTwoFactorAuth ? (\n <TwoFactorAuthPrompt />\n ) : (\n <form\n onSubmit={e => {\n handleChangePassword(e)\n }}\n >\n <TextField\n fullWidth\n required\n helperText={newPasswordError}\n type=\"password\"\n id=\"newPassword\"\n name=\"newPassword\"\n label={'New password'}\n onChange={e => {\n const error = validatePassword(e.target.value)\n setNewPasswordError(error)\n setNewPassword(e.target.value)\n }}\n value={newPassword || ''}\n sx={{ mb: 2 }}\n />\n <TextField\n fullWidth\n required\n type=\"password\"\n id=\"confirmPassword\"\n name=\"confirmPassword\"\n label={'Confirm password'}\n onChange={e => setConfirmPassword(e.target.value)}\n value={confirmPassword || ''}\n sx={{ mb: 2 }}\n />\n <Button\n variant=\"contained\"\n type=\"submit\"\n fullWidth\n disabled={\n !newPassword || !confirmPassword || changePasswordIsPending\n }\n sx={{ mt: 3, py: 2 }}\n >\n Change Password\n </Button>\n </form>\n )}\n {error && (\n <Alert severity={'error'} sx={{ my: 2 }}>\n {error.reason}\n </Alert>\n )}\n </div>\n )\n}\n"],"mappings":";;;;;;;;AAYA,SAAwB,EACtB,GACA;CACA,IAAM,EAAE,wBAAqB,iBAAc,GACrC,CAAC,GAAa,KAAkB,EAAiB,GAAG,EACpD,CAAC,GAAiB,KAAsB,EAAiB,GAAG,EAC5D,CAAC,GAAkB,KAAuB,EAC9C,KAAA,EACD,EAEK,EACJ,2BACA,wBACA,WAAW,GACX,uCACA,aACE,EAA2B,EAC7B,+BAA+B;AAI7B,EAHA,EAAe,GAAG,EAClB,EAAmB,GAAG,EACtB,EAAa,kCAAkC,UAAU,EACzD,GAAW;IAEd,CAAC,EAEI,KAAwB,MAAuC;AAEnE,EADA,EAAW,gBAAgB,EACvB,MAAgB,IAGlB,EAAmC,GAAa,EAAoB,GAFpE,EAAa,2BAA2B,SAAS;;AAMrD,QACE,kBAAC,OAAD,EAAA,UAAA,CACG,IACC,kBAAC,GAAD,EAAuB,CAAA,GAEvB,kBAAC,QAAD;EACE,WAAU,MAAK;AACb,KAAqB,EAAE;;YAF3B;GAKE,kBAAC,GAAD;IACE,WAAA;IACA,UAAA;IACA,YAAY;IACZ,MAAK;IACL,IAAG;IACH,MAAK;IACL,OAAO;IACP,WAAU,MAAK;AAGb,KADA,EADc,EAAiB,EAAE,OAAO,MACpB,CAAM,EAC1B,EAAe,EAAE,OAAO,MAAM;;IAEhC,OAAO,KAAe;IACtB,IAAI,EAAE,IAAI,GAAG;IACb,CAAA;GACF,kBAAC,GAAD;IACE,WAAA;IACA,UAAA;IACA,MAAK;IACL,IAAG;IACH,MAAK;IACL,OAAO;IACP,WAAU,MAAK,EAAmB,EAAE,OAAO,MAAM;IACjD,OAAO,KAAmB;IAC1B,IAAI,EAAE,IAAI,GAAG;IACb,CAAA;GACF,kBAAC,GAAD;IACE,SAAQ;IACR,MAAK;IACL,WAAA;IACA,UACE,CAAC,KAAe,CAAC,KAAmB;IAEtC,IAAI;KAAE,IAAI;KAAG,IAAI;KAAG;cACrB;IAEQ,CAAA;GACJ;KAER,KACC,kBAAC,GAAD;EAAO,UAAU;EAAS,IAAI,EAAE,IAAI,GAAG;YACpC,EAAM;EACD,CAAA,CAEN,EAAA,CAAA"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import e from "../../utils/appendFinalQueryParamKey.js";
|
|
2
2
|
import { useChangePassword as t } from "../../synapse-queries/auth/useChangePassword.js";
|
|
3
3
|
import { useOneSageURL as n } from "../../utils/hooks/useOneSageURL.js";
|
|
4
|
+
import "../Authentication/Constants.js";
|
|
4
5
|
import "../../utils/hooks/index.js";
|
|
5
6
|
import { useResetTwoFactorAuth as r } from "../../synapse-queries/auth/useTwoFactorEnrollment.js";
|
|
6
7
|
import "../../synapse-queries/index.js";
|
|
7
|
-
import "../Authentication/Constants.js";
|
|
8
8
|
import i from "../Authentication/OneTimePasswordForm.js";
|
|
9
9
|
import "../Authentication/index.js";
|
|
10
10
|
import { useCallback as a, useState as o } from "react";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useChangePasswordFormState.js","names":[],"sources":["../../../src/components/ChangePassword/useChangePasswordFormState.tsx"],"sourcesContent":["import { useChangePassword, useResetTwoFactorAuth } from '@/synapse-queries'\nimport appendFinalQueryParamKey from '@/utils/appendFinalQueryParamKey'\nimport { useOneSageURL } from '@/utils/hooks'\nimport { Alert, Typography } from '@mui/material'\nimport { TwoFactorAuthErrorResponse } from '@sage-bionetworks/synapse-client/generated/models/TwoFactorAuthErrorResponse'\nimport {\n ChangePasswordWithCurrentPassword,\n ChangePasswordWithToken as ChangePasswordWithTokenObject,\n ChangePasswordWithTwoFactorAuthToken,\n PasswordResetSignedToken,\n TwoFactorAuthOtpType,\n TwoFactorAuthResetRequest,\n} from '@sage-bionetworks/synapse-types'\nimport { useCallback, useState } from 'react'\nimport { ONE_TIME_PASSWORD_STEP, OneTimePasswordForm } from '../Authentication'\nimport {\n RECOVERY_CODE_GUIDANCE_TEXT_SHORT,\n TOTP_GUIDANCE_TEXT,\n} from '../Authentication/Constants'\n\nexport const TWO_FACTOR_AUTH_CHANGE_PASSWORD_PROMPT =\n 'Two-factor authentication is required to change your password. Your password has not yet been changed.'\n\nexport type UseChangePasswordFormStateOptions = {\n hideReset2FA?: boolean\n onChangePasswordSuccess?: () => void\n}\n\n/**\n * Hook that handles submitting a change password request and prompting the user for 2FA if necessary.\n * @param options\n */\nexport default function useChangePasswordFormState(\n options?: UseChangePasswordFormStateOptions,\n) {\n const defaultTwoFactorAuthResetUrl = useOneSageURL('/reset2FA')\n const twoFactorAuthResetUri = appendFinalQueryParamKey(\n defaultTwoFactorAuthResetUrl,\n 'twoFAResetToken',\n )\n\n // Store current and new password in state so that we can re-use it if 2FA is required\n const [currentPassword, setCurrentPassword] = useState<string>('')\n const [newPassword, setNewPassword] = useState<string>('')\n const [twoFactorAuthErrorResponse, setTwoFactorAuthErrorResponse] = useState<\n TwoFactorAuthErrorResponse | undefined\n >()\n const [otpStep, setOtpStep] =\n useState<ONE_TIME_PASSWORD_STEP>('VERIFICATION_CODE')\n const [successfullyChangedPassword, setSuccessfullyChangedPassword] =\n useState(false)\n const {\n mutate: changePassword,\n isPending,\n error,\n } = useChangePassword({\n onSuccess: maybeTwoFactorResponse => {\n if (maybeTwoFactorResponse) {\n // We store the 2FA Error Response in state because the `changePasswordResult` may change before we are done with the 2FA code,\n // e.g. if the user enters the wrong 2FA code\n setTwoFactorAuthErrorResponse(maybeTwoFactorResponse)\n } else {\n setSuccessfullyChangedPassword(true)\n setTwoFactorAuthErrorResponse(undefined)\n if (options?.onChangePasswordSuccess) {\n options.onChangePasswordSuccess()\n }\n }\n },\n })\n\n const handleChangePasswordWithCurrentPassword = useCallback(\n (username: string, currentPassword: string, newPassword: string) => {\n setCurrentPassword(currentPassword)\n setNewPassword(newPassword)\n const changeRequest: ChangePasswordWithCurrentPassword = {\n username,\n currentPassword,\n newPassword,\n concreteType:\n 'org.sagebionetworks.repo.model.auth.ChangePasswordWithCurrentPassword',\n }\n changePassword(changeRequest)\n },\n [changePassword],\n )\n\n const handleChangePasswordWithResetToken = useCallback(\n (newPassword: string, passwordChangeToken: PasswordResetSignedToken) => {\n setNewPassword(newPassword)\n const changeRequest: ChangePasswordWithTokenObject = {\n newPassword,\n concreteType:\n 'org.sagebionetworks.repo.model.auth.ChangePasswordWithToken',\n passwordChangeToken: passwordChangeToken,\n }\n changePassword(changeRequest)\n },\n [changePassword],\n )\n\n const handleChangePasswordWithOtp = useCallback(\n (newPassword: string, code: string, otpType: TwoFactorAuthOtpType) => {\n if (twoFactorAuthErrorResponse) {\n const changeRequest: ChangePasswordWithTwoFactorAuthToken = {\n newPassword,\n concreteType:\n 'org.sagebionetworks.repo.model.auth.ChangePasswordWithTwoFactorAuthToken',\n userId: twoFactorAuthErrorResponse.userId!,\n twoFaToken: twoFactorAuthErrorResponse.twoFaToken!,\n otpType: otpType,\n otpCode: code,\n }\n changePassword(changeRequest)\n }\n },\n [changePassword, twoFactorAuthErrorResponse],\n )\n const promptForTwoFactorAuth = Boolean(twoFactorAuthErrorResponse)\n const {\n mutate: resetTwoFactorAuth,\n isSuccess: twoFactorAuthResetIsSuccess,\n isPending: twoFactorAuthResetIsPending,\n } = useResetTwoFactorAuth()\n\n const beginTwoFactorAuthReset = useCallback(\n (twoFaResetEndpoint: string) => {\n if (twoFactorAuthErrorResponse) {\n const request: TwoFactorAuthResetRequest = {\n userId: twoFactorAuthErrorResponse.userId!,\n twoFaResetEndpoint: twoFaResetEndpoint,\n // When attempting to reset 2FA while resetting a password, the current password must be used to request 2FA reset\n password: currentPassword,\n }\n resetTwoFactorAuth(request)\n }\n },\n [currentPassword, resetTwoFactorAuth, twoFactorAuthErrorResponse],\n )\n\n const TwoFactorAuthPrompt = useCallback(() => {\n if (!promptForTwoFactorAuth) {\n return <></>\n }\n return (\n <>\n {otpStep === 'VERIFICATION_CODE' && (\n <Typography variant={'body1'} sx={{ my: 2 }} align={'center'}>\n {TOTP_GUIDANCE_TEXT}\n </Typography>\n )}\n {otpStep === 'RECOVERY_CODE' && (\n <Typography variant={'body1'} sx={{ my: 2 }} align={'center'}>\n {RECOVERY_CODE_GUIDANCE_TEXT_SHORT}\n </Typography>\n )}\n <OneTimePasswordForm\n step={otpStep}\n onClickUseTOTP={() => {\n setOtpStep('VERIFICATION_CODE')\n }}\n onClickUseBackupCode={() => {\n setOtpStep('RECOVERY_CODE')\n }}\n loginIsPending={isPending}\n onSubmit={(code, otpType) =>\n handleChangePasswordWithOtp(newPassword, code, otpType)\n }\n hideReset2FA={options?.hideReset2FA}\n onClickPromptReset2FA={() => {\n setOtpStep('DISABLE_2FA_PROMPT')\n }}\n onClickReset2FA={() => {\n beginTwoFactorAuthReset(twoFactorAuthResetUri)\n }}\n twoFactorAuthResetIsPending={twoFactorAuthResetIsPending}\n twoFactorAuthResetIsSuccess={twoFactorAuthResetIsSuccess}\n />\n {(otpStep === 'RECOVERY_CODE' || otpStep === 'VERIFICATION_CODE') && (\n <Alert severity={'info'} sx={{ my: 2 }}>\n {TWO_FACTOR_AUTH_CHANGE_PASSWORD_PROMPT}\n </Alert>\n )}\n {otpStep === 'DISABLE_2FA_PROMPT' && twoFactorAuthResetIsSuccess && (\n <Alert severity={'warning'} sx={{ my: 2 }}>\n <strong>Your password has not been changed.</strong> To disable\n two-factor authentication, you may be required to enter your current\n password after clicking the link sent to your email address.\n </Alert>\n )}\n </>\n )\n }, [\n beginTwoFactorAuthReset,\n handleChangePasswordWithOtp,\n isPending,\n newPassword,\n options?.hideReset2FA,\n otpStep,\n promptForTwoFactorAuth,\n twoFactorAuthResetIsPending,\n twoFactorAuthResetIsSuccess,\n twoFactorAuthResetUri,\n ])\n\n return {\n successfullyChangedPassword,\n isPending,\n error,\n promptForTwoFactorAuth,\n TwoFactorAuthPrompt: TwoFactorAuthPrompt,\n handleChangePasswordWithCurrentPassword,\n handleChangePasswordWithResetToken,\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAoBA,IAAa,IACX;AAWF,SAAwB,EACtB,GACA;CAEA,IAAM,IAAwB,EADO,EAAc,
|
|
1
|
+
{"version":3,"file":"useChangePasswordFormState.js","names":[],"sources":["../../../src/components/ChangePassword/useChangePasswordFormState.tsx"],"sourcesContent":["import { useChangePassword, useResetTwoFactorAuth } from '@/synapse-queries'\nimport appendFinalQueryParamKey from '@/utils/appendFinalQueryParamKey'\nimport { useOneSageURL } from '@/utils/hooks'\nimport { Alert, Typography } from '@mui/material'\nimport { TwoFactorAuthErrorResponse } from '@sage-bionetworks/synapse-client/generated/models/TwoFactorAuthErrorResponse'\nimport {\n ChangePasswordWithCurrentPassword,\n ChangePasswordWithToken as ChangePasswordWithTokenObject,\n ChangePasswordWithTwoFactorAuthToken,\n PasswordResetSignedToken,\n TwoFactorAuthOtpType,\n TwoFactorAuthResetRequest,\n} from '@sage-bionetworks/synapse-types'\nimport { useCallback, useState } from 'react'\nimport { ONE_TIME_PASSWORD_STEP, OneTimePasswordForm } from '../Authentication'\nimport {\n RECOVERY_CODE_GUIDANCE_TEXT_SHORT,\n TOTP_GUIDANCE_TEXT,\n} from '../Authentication/Constants'\n\nexport const TWO_FACTOR_AUTH_CHANGE_PASSWORD_PROMPT =\n 'Two-factor authentication is required to change your password. Your password has not yet been changed.'\n\nexport type UseChangePasswordFormStateOptions = {\n hideReset2FA?: boolean\n onChangePasswordSuccess?: () => void\n}\n\n/**\n * Hook that handles submitting a change password request and prompting the user for 2FA if necessary.\n * @param options\n */\nexport default function useChangePasswordFormState(\n options?: UseChangePasswordFormStateOptions,\n) {\n const defaultTwoFactorAuthResetUrl = useOneSageURL('/reset2FA')\n const twoFactorAuthResetUri = appendFinalQueryParamKey(\n defaultTwoFactorAuthResetUrl,\n 'twoFAResetToken',\n )\n\n // Store current and new password in state so that we can re-use it if 2FA is required\n const [currentPassword, setCurrentPassword] = useState<string>('')\n const [newPassword, setNewPassword] = useState<string>('')\n const [twoFactorAuthErrorResponse, setTwoFactorAuthErrorResponse] = useState<\n TwoFactorAuthErrorResponse | undefined\n >()\n const [otpStep, setOtpStep] =\n useState<ONE_TIME_PASSWORD_STEP>('VERIFICATION_CODE')\n const [successfullyChangedPassword, setSuccessfullyChangedPassword] =\n useState(false)\n const {\n mutate: changePassword,\n isPending,\n error,\n } = useChangePassword({\n onSuccess: maybeTwoFactorResponse => {\n if (maybeTwoFactorResponse) {\n // We store the 2FA Error Response in state because the `changePasswordResult` may change before we are done with the 2FA code,\n // e.g. if the user enters the wrong 2FA code\n setTwoFactorAuthErrorResponse(maybeTwoFactorResponse)\n } else {\n setSuccessfullyChangedPassword(true)\n setTwoFactorAuthErrorResponse(undefined)\n if (options?.onChangePasswordSuccess) {\n options.onChangePasswordSuccess()\n }\n }\n },\n })\n\n const handleChangePasswordWithCurrentPassword = useCallback(\n (username: string, currentPassword: string, newPassword: string) => {\n setCurrentPassword(currentPassword)\n setNewPassword(newPassword)\n const changeRequest: ChangePasswordWithCurrentPassword = {\n username,\n currentPassword,\n newPassword,\n concreteType:\n 'org.sagebionetworks.repo.model.auth.ChangePasswordWithCurrentPassword',\n }\n changePassword(changeRequest)\n },\n [changePassword],\n )\n\n const handleChangePasswordWithResetToken = useCallback(\n (newPassword: string, passwordChangeToken: PasswordResetSignedToken) => {\n setNewPassword(newPassword)\n const changeRequest: ChangePasswordWithTokenObject = {\n newPassword,\n concreteType:\n 'org.sagebionetworks.repo.model.auth.ChangePasswordWithToken',\n passwordChangeToken: passwordChangeToken,\n }\n changePassword(changeRequest)\n },\n [changePassword],\n )\n\n const handleChangePasswordWithOtp = useCallback(\n (newPassword: string, code: string, otpType: TwoFactorAuthOtpType) => {\n if (twoFactorAuthErrorResponse) {\n const changeRequest: ChangePasswordWithTwoFactorAuthToken = {\n newPassword,\n concreteType:\n 'org.sagebionetworks.repo.model.auth.ChangePasswordWithTwoFactorAuthToken',\n userId: twoFactorAuthErrorResponse.userId!,\n twoFaToken: twoFactorAuthErrorResponse.twoFaToken!,\n otpType: otpType,\n otpCode: code,\n }\n changePassword(changeRequest)\n }\n },\n [changePassword, twoFactorAuthErrorResponse],\n )\n const promptForTwoFactorAuth = Boolean(twoFactorAuthErrorResponse)\n const {\n mutate: resetTwoFactorAuth,\n isSuccess: twoFactorAuthResetIsSuccess,\n isPending: twoFactorAuthResetIsPending,\n } = useResetTwoFactorAuth()\n\n const beginTwoFactorAuthReset = useCallback(\n (twoFaResetEndpoint: string) => {\n if (twoFactorAuthErrorResponse) {\n const request: TwoFactorAuthResetRequest = {\n userId: twoFactorAuthErrorResponse.userId!,\n twoFaResetEndpoint: twoFaResetEndpoint,\n // When attempting to reset 2FA while resetting a password, the current password must be used to request 2FA reset\n password: currentPassword,\n }\n resetTwoFactorAuth(request)\n }\n },\n [currentPassword, resetTwoFactorAuth, twoFactorAuthErrorResponse],\n )\n\n const TwoFactorAuthPrompt = useCallback(() => {\n if (!promptForTwoFactorAuth) {\n return <></>\n }\n return (\n <>\n {otpStep === 'VERIFICATION_CODE' && (\n <Typography variant={'body1'} sx={{ my: 2 }} align={'center'}>\n {TOTP_GUIDANCE_TEXT}\n </Typography>\n )}\n {otpStep === 'RECOVERY_CODE' && (\n <Typography variant={'body1'} sx={{ my: 2 }} align={'center'}>\n {RECOVERY_CODE_GUIDANCE_TEXT_SHORT}\n </Typography>\n )}\n <OneTimePasswordForm\n step={otpStep}\n onClickUseTOTP={() => {\n setOtpStep('VERIFICATION_CODE')\n }}\n onClickUseBackupCode={() => {\n setOtpStep('RECOVERY_CODE')\n }}\n loginIsPending={isPending}\n onSubmit={(code, otpType) =>\n handleChangePasswordWithOtp(newPassword, code, otpType)\n }\n hideReset2FA={options?.hideReset2FA}\n onClickPromptReset2FA={() => {\n setOtpStep('DISABLE_2FA_PROMPT')\n }}\n onClickReset2FA={() => {\n beginTwoFactorAuthReset(twoFactorAuthResetUri)\n }}\n twoFactorAuthResetIsPending={twoFactorAuthResetIsPending}\n twoFactorAuthResetIsSuccess={twoFactorAuthResetIsSuccess}\n />\n {(otpStep === 'RECOVERY_CODE' || otpStep === 'VERIFICATION_CODE') && (\n <Alert severity={'info'} sx={{ my: 2 }}>\n {TWO_FACTOR_AUTH_CHANGE_PASSWORD_PROMPT}\n </Alert>\n )}\n {otpStep === 'DISABLE_2FA_PROMPT' && twoFactorAuthResetIsSuccess && (\n <Alert severity={'warning'} sx={{ my: 2 }}>\n <strong>Your password has not been changed.</strong> To disable\n two-factor authentication, you may be required to enter your current\n password after clicking the link sent to your email address.\n </Alert>\n )}\n </>\n )\n }, [\n beginTwoFactorAuthReset,\n handleChangePasswordWithOtp,\n isPending,\n newPassword,\n options?.hideReset2FA,\n otpStep,\n promptForTwoFactorAuth,\n twoFactorAuthResetIsPending,\n twoFactorAuthResetIsSuccess,\n twoFactorAuthResetUri,\n ])\n\n return {\n successfullyChangedPassword,\n isPending,\n error,\n promptForTwoFactorAuth,\n TwoFactorAuthPrompt: TwoFactorAuthPrompt,\n handleChangePasswordWithCurrentPassword,\n handleChangePasswordWithResetToken,\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAoBA,IAAa,IACX;AAWF,SAAwB,EACtB,GACA;CAEA,IAAM,IAAwB,EADO,EAAc,YAEjD,EACA,kBACD,EAGK,CAAC,GAAiB,KAAsB,EAAiB,GAAG,EAC5D,CAAC,GAAa,KAAkB,EAAiB,GAAG,EACpD,CAAC,GAA4B,KAAiC,GAEjE,EACG,CAAC,GAAS,KACd,EAAiC,oBAAoB,EACjD,CAAC,GAA6B,KAClC,EAAS,GAAM,EACX,EACJ,QAAQ,GACR,cACA,aACE,EAAkB,EACpB,YAAW,MAA0B;AACnC,EAAI,IAGF,EAA8B,EAAuB,IAErD,EAA+B,GAAK,EACpC,EAA8B,KAAA,EAAU,EACpC,GAAS,2BACX,EAAQ,yBAAyB;IAIxC,CAAC,EAEI,IAA0C,GAC7C,GAAkB,GAAyB,MAAwB;AAUlE,EATA,EAAmB,EAAgB,EACnC,EAAe,EAAY,EAQ3B,EAAe;GANb;GACA;GACA;GACA,cACE;GAEW,CAAc;IAE/B,CAAC,EAAe,CACjB,EAEK,IAAqC,GACxC,GAAqB,MAAkD;AAQtE,EAPA,EAAe,EAAY,EAO3B,EAAe;GALb;GACA,cACE;GACmB;GAER,CAAc;IAE/B,CAAC,EAAe,CACjB,EAEK,IAA8B,GACjC,GAAqB,GAAc,MAAkC;AACpE,EAAI,KAUF,EAAe;GARb;GACA,cACE;GACF,QAAQ,EAA2B;GACnC,YAAY,EAA2B;GAC9B;GACT,SAAS;GAEI,CAAc;IAGjC,CAAC,GAAgB,EAA2B,CAC7C,EACK,IAAyB,EAAQ,GACjC,EACJ,QAAQ,GACR,WAAW,GACX,WAAW,MACT,GAAuB,EAErB,IAA0B,GAC7B,MAA+B;AAC9B,EAAI,KAOF,EAAmB;GALjB,QAAQ,EAA2B;GACf;GAEpB,UAAU;GAEO,CAAQ;IAG/B;EAAC;EAAiB;EAAoB;EAA2B,CAClE;AAmED,QAAO;EACL;EACA;EACA;EACA;EACqB,qBAtEK,QACrB,IAIH,kBAAA,GAAA,EAAA,UAAA;GACG,MAAY,uBACX,kBAAC,GAAD;IAAY,SAAS;IAAS,IAAI,EAAE,IAAI,GAAG;IAAE,OAAO;;IAEvC,CAAA;GAEd,MAAY,mBACX,kBAAC,GAAD;IAAY,SAAS;IAAS,IAAI,EAAE,IAAI,GAAG;IAAE,OAAO;;IAEvC,CAAA;GAEf,kBAAC,GAAD;IACE,MAAM;IACN,sBAAsB;AACpB,OAAW,oBAAoB;;IAEjC,4BAA4B;AAC1B,OAAW,gBAAgB;;IAE7B,gBAAgB;IAChB,WAAW,GAAM,MACf,EAA4B,GAAa,GAAM,EAAQ;IAEzD,cAAc,GAAS;IACvB,6BAA6B;AAC3B,OAAW,qBAAqB;;IAElC,uBAAuB;AACrB,OAAwB,EAAsB;;IAEnB;IACA;IAC7B,CAAA;IACA,MAAY,mBAAmB,MAAY,wBAC3C,kBAAC,GAAD;IAAO,UAAU;IAAQ,IAAI,EAAE,IAAI,GAAG;;IAE9B,CAAA;GAET,MAAY,wBAAwB,KACnC,kBAAC,GAAD;IAAO,UAAU;IAAW,IAAI,EAAE,IAAI,GAAG;cAAzC,CACE,kBAAC,UAAD,EAAA,UAAQ,uCAA4C,CAAA,EAAA,gJAG9C;;GAET,EAAA,CAAA,GAhDI,kBAAA,GAAA,EAAK,CAAA,EAkDb;GACD;GACA;GACA;GACA;GACA,GAAS;GACT;GACA;GACA;GACA;GACA;GACD,CAOsB;EACrB;EACA;EACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CitationPopoverContent.js","names":[],"sources":["../../../src/components/CitationPopover/CitationPopoverContent.tsx"],"sourcesContent":["import {\n Alert,\n Box,\n Button,\n FormControl,\n MenuItem,\n Popover,\n Select,\n SelectChangeEvent,\n Stack,\n SxProps,\n Typography,\n PopoverProps,\n} from '@mui/material'\nimport React from 'react'\nimport { useCitation } from './useCitation'\nimport { createLinkAndDownload } from './CitationPopoverUtils'\nimport { KeyboardArrowDown } from '@mui/icons-material'\nimport CloseIcon from '@mui/icons-material/Close'\nimport { useState } from 'react'\nimport CopyToClipboardIcon from '../CopyToClipboardIcon'\nimport { CitationProps, CitationFormat } from './CitationTypes'\nimport MarkdownSynapse from '../Markdown/MarkdownSynapse'\n\nconst selectSx: SxProps = {\n width: '100%',\n '.MuiInputBase-root': {\n minHeight: '38px',\n borderRadius: 0,\n '&:before, &:after': {\n borderBottom: 'none !important',\n },\n },\n '& .MuiOutlinedInput-notchedOutline': {\n border: 0,\n },\n '&.MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline': {\n border: 'none',\n },\n '.MuiSelect-select': {\n display: 'flex',\n alignItems: 'center',\n },\n '.MuiInputBase-input': {\n padding: '7px 10px',\n },\n}\n\nexport type CitationPopoverProps = CitationProps &\n Pick<PopoverProps, 'anchorEl' | 'open' | 'id' | 'onClose'>\n\nexport const CitationPopoverContent = (\n props: CitationPopoverProps,\n): React.ReactNode => {\n const {\n doi,\n title,\n boilerplateText,\n defaultCitationFormat,\n onClose,\n anchorEl,\n open,\n id,\n } = props\n\n const [citationFormat, setCitationFormat] = useState<CitationFormat>(\n defaultCitationFormat || 'bibtex',\n )\n const {\n data: citation,\n isLoading,\n error,\n } = useCitation(doi || '', citationFormat, true)\n\n const handleDownload = (citation: string) => {\n if (!citation) {\n return\n }\n const extensionMap: Record<string, string> = {\n apa: 'ris',\n bibtex: 'bib',\n ieee: 'ris',\n nature: 'ris',\n science: 'ris',\n }\n const fileExtension = extensionMap[citationFormat] || 'txt'\n\n const blob = new Blob([citation], { type: 'text/plain' })\n const url = URL.createObjectURL(blob)\n\n createLinkAndDownload(title || 'citation', fileExtension, url)\n }\n\n const handleChange = (event: SelectChangeEvent<CitationFormat>) => {\n setCitationFormat(event.target.value as CitationFormat)\n }\n\n return (\n <Popover\n aria-label=\"Citation options\"\n role=\"dialog\"\n id={id}\n elevation={9}\n open={open}\n anchorEl={anchorEl}\n onClose={onClose}\n anchorOrigin={{\n vertical: 'bottom',\n horizontal: 'left',\n }}\n transformOrigin={{\n vertical: 'top',\n horizontal: 'left',\n }}\n slotProps={{\n paper: {\n square: true,\n sx: theme => ({\n width: '500px',\n position: 'relative',\n [theme.breakpoints.down('sm')]: {\n maxWidth: '100%',\n maxHeight: '100%',\n top: '0 !important',\n left: '0 !important',\n bottom: '0 !important',\n },\n }),\n },\n }}\n >\n <Stack\n sx={{\n gap: '20px',\n padding: '20px',\n }}\n >\n <Box sx={{ display: 'flex', alignItems: 'center' }}>\n <Typography\n sx={{ fontSize: '20px', fontWeight: 700, lineHeight: 'normal' }}\n >\n Cite As:\n </Typography>\n <CloseIcon\n sx={{\n cursor: 'pointer',\n display: { xs: 'block', sm: 'none' },\n marginLeft: 'auto',\n color: '#878E95',\n }}\n onClick={() => {\n onClose?.({}, 'escapeKeyDown')\n }}\n />\n </Box>\n {error && (\n <Alert severity={'error'} sx={{ my: 2 }} icon={false}>\n {error.message}\n </Alert>\n )}\n <Typography\n variant=\"smallText1\"\n component={'div'}\n sx={{\n lineHeight: 'normal',\n maxHeight: '300px',\n overflowY: 'scroll',\n wordWrap: 'break-word',\n }}\n >\n {boilerplateText && (\n <>\n <MarkdownSynapse markdown={boilerplateText} />\n <br />\n </>\n )}\n {isLoading ? (\n <Box sx={{ fontWeight: 700 }}>\n <br />\n Loading citation...\n </Box>\n ) : (\n citation\n )}\n </Typography>\n <Box\n sx={{\n display: 'flex',\n flexDirection: { xs: 'column', sm: 'row' },\n gap: { xs: '10px', sm: '8px' },\n width: '100%',\n maxHeight: '38px',\n }}\n >\n <Box sx={{ flex: 1 }}>\n <FormControl sx={selectSx}>\n <Select\n variant=\"standard\"\n sx={{\n svg: {\n color: '#878E95',\n width: '24px',\n height: '24px',\n right: '10px',\n },\n }}\n value={citationFormat}\n onChange={handleChange}\n IconComponent={KeyboardArrowDown}\n >\n <MenuItem value={'bibtex'}>bibtex</MenuItem>\n <MenuItem value={'apa'}>apa</MenuItem>\n <MenuItem value={'ieee'}>ieee</MenuItem>\n <MenuItem value={'nature'}>nature</MenuItem>\n <MenuItem value={'science'}>science</MenuItem>\n </Select>\n </FormControl>\n </Box>\n <Button\n onClick={() => handleDownload(citation || '')}\n variant=\"contained\"\n sx={{\n padding: '6px 16px',\n borderRadius: 0,\n }}\n >\n Download Citation\n </Button>\n <CopyToClipboardIcon\n value={citation || ''}\n sx={{\n borderRadius: 0,\n padding: '6px 16px',\n border: '1px solid',\n borderColor: 'primary.main',\n }}\n />\n </Box>\n </Stack>\n </Popover>\n )\n}\n\nexport default CitationPopoverContent\n"],"mappings":";;;;;;;;;;AAwBA,IAAM,IAAoB;CACxB,OAAO;CACP,sBAAsB;EACpB,WAAW;EACX,cAAc;EACd,qBAAqB,EACnB,cAAc,mBACf;EACF;CACD,sCAAsC,EACpC,QAAQ,GACT;CACD,wEAAwE,EACtE,QAAQ,QACT;CACD,qBAAqB;EACnB,SAAS;EACT,YAAY;EACb;CACD,uBAAuB,EACrB,SAAS,YACV;CACF,EAKY,KACX,MACoB;CACpB,IAAM,EACJ,QACA,UACA,oBACA,0BACA,YACA,aACA,SACA,UACE,GAEE,CAAC,GAAgB,KAAqB,EAC1C,KAAyB,SAC1B,EACK,EACJ,MAAM,GACN,cACA,aACE,EAAY,KAAO,IAAI,GAAgB,GAAK,EAE1C,KAAkB,MAAqB;AAC3C,MAAI,CAAC,EACH;EASF,IAAM,
|
|
1
|
+
{"version":3,"file":"CitationPopoverContent.js","names":[],"sources":["../../../src/components/CitationPopover/CitationPopoverContent.tsx"],"sourcesContent":["import {\n Alert,\n Box,\n Button,\n FormControl,\n MenuItem,\n Popover,\n Select,\n SelectChangeEvent,\n Stack,\n SxProps,\n Typography,\n PopoverProps,\n} from '@mui/material'\nimport React from 'react'\nimport { useCitation } from './useCitation'\nimport { createLinkAndDownload } from './CitationPopoverUtils'\nimport { KeyboardArrowDown } from '@mui/icons-material'\nimport CloseIcon from '@mui/icons-material/Close'\nimport { useState } from 'react'\nimport CopyToClipboardIcon from '../CopyToClipboardIcon'\nimport { CitationProps, CitationFormat } from './CitationTypes'\nimport MarkdownSynapse from '../Markdown/MarkdownSynapse'\n\nconst selectSx: SxProps = {\n width: '100%',\n '.MuiInputBase-root': {\n minHeight: '38px',\n borderRadius: 0,\n '&:before, &:after': {\n borderBottom: 'none !important',\n },\n },\n '& .MuiOutlinedInput-notchedOutline': {\n border: 0,\n },\n '&.MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline': {\n border: 'none',\n },\n '.MuiSelect-select': {\n display: 'flex',\n alignItems: 'center',\n },\n '.MuiInputBase-input': {\n padding: '7px 10px',\n },\n}\n\nexport type CitationPopoverProps = CitationProps &\n Pick<PopoverProps, 'anchorEl' | 'open' | 'id' | 'onClose'>\n\nexport const CitationPopoverContent = (\n props: CitationPopoverProps,\n): React.ReactNode => {\n const {\n doi,\n title,\n boilerplateText,\n defaultCitationFormat,\n onClose,\n anchorEl,\n open,\n id,\n } = props\n\n const [citationFormat, setCitationFormat] = useState<CitationFormat>(\n defaultCitationFormat || 'bibtex',\n )\n const {\n data: citation,\n isLoading,\n error,\n } = useCitation(doi || '', citationFormat, true)\n\n const handleDownload = (citation: string) => {\n if (!citation) {\n return\n }\n const extensionMap: Record<string, string> = {\n apa: 'ris',\n bibtex: 'bib',\n ieee: 'ris',\n nature: 'ris',\n science: 'ris',\n }\n const fileExtension = extensionMap[citationFormat] || 'txt'\n\n const blob = new Blob([citation], { type: 'text/plain' })\n const url = URL.createObjectURL(blob)\n\n createLinkAndDownload(title || 'citation', fileExtension, url)\n }\n\n const handleChange = (event: SelectChangeEvent<CitationFormat>) => {\n setCitationFormat(event.target.value as CitationFormat)\n }\n\n return (\n <Popover\n aria-label=\"Citation options\"\n role=\"dialog\"\n id={id}\n elevation={9}\n open={open}\n anchorEl={anchorEl}\n onClose={onClose}\n anchorOrigin={{\n vertical: 'bottom',\n horizontal: 'left',\n }}\n transformOrigin={{\n vertical: 'top',\n horizontal: 'left',\n }}\n slotProps={{\n paper: {\n square: true,\n sx: theme => ({\n width: '500px',\n position: 'relative',\n [theme.breakpoints.down('sm')]: {\n maxWidth: '100%',\n maxHeight: '100%',\n top: '0 !important',\n left: '0 !important',\n bottom: '0 !important',\n },\n }),\n },\n }}\n >\n <Stack\n sx={{\n gap: '20px',\n padding: '20px',\n }}\n >\n <Box sx={{ display: 'flex', alignItems: 'center' }}>\n <Typography\n sx={{ fontSize: '20px', fontWeight: 700, lineHeight: 'normal' }}\n >\n Cite As:\n </Typography>\n <CloseIcon\n sx={{\n cursor: 'pointer',\n display: { xs: 'block', sm: 'none' },\n marginLeft: 'auto',\n color: '#878E95',\n }}\n onClick={() => {\n onClose?.({}, 'escapeKeyDown')\n }}\n />\n </Box>\n {error && (\n <Alert severity={'error'} sx={{ my: 2 }} icon={false}>\n {error.message}\n </Alert>\n )}\n <Typography\n variant=\"smallText1\"\n component={'div'}\n sx={{\n lineHeight: 'normal',\n maxHeight: '300px',\n overflowY: 'scroll',\n wordWrap: 'break-word',\n }}\n >\n {boilerplateText && (\n <>\n <MarkdownSynapse markdown={boilerplateText} />\n <br />\n </>\n )}\n {isLoading ? (\n <Box sx={{ fontWeight: 700 }}>\n <br />\n Loading citation...\n </Box>\n ) : (\n citation\n )}\n </Typography>\n <Box\n sx={{\n display: 'flex',\n flexDirection: { xs: 'column', sm: 'row' },\n gap: { xs: '10px', sm: '8px' },\n width: '100%',\n maxHeight: '38px',\n }}\n >\n <Box sx={{ flex: 1 }}>\n <FormControl sx={selectSx}>\n <Select\n variant=\"standard\"\n sx={{\n svg: {\n color: '#878E95',\n width: '24px',\n height: '24px',\n right: '10px',\n },\n }}\n value={citationFormat}\n onChange={handleChange}\n IconComponent={KeyboardArrowDown}\n >\n <MenuItem value={'bibtex'}>bibtex</MenuItem>\n <MenuItem value={'apa'}>apa</MenuItem>\n <MenuItem value={'ieee'}>ieee</MenuItem>\n <MenuItem value={'nature'}>nature</MenuItem>\n <MenuItem value={'science'}>science</MenuItem>\n </Select>\n </FormControl>\n </Box>\n <Button\n onClick={() => handleDownload(citation || '')}\n variant=\"contained\"\n sx={{\n padding: '6px 16px',\n borderRadius: 0,\n }}\n >\n Download Citation\n </Button>\n <CopyToClipboardIcon\n value={citation || ''}\n sx={{\n borderRadius: 0,\n padding: '6px 16px',\n border: '1px solid',\n borderColor: 'primary.main',\n }}\n />\n </Box>\n </Stack>\n </Popover>\n )\n}\n\nexport default CitationPopoverContent\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ColumnFilter.js","names":[],"sources":["../../../src/components/ColumnFilter/ColumnFilter.tsx"],"sourcesContent":["import { UniqueFacetIdentifier } from '@/utils'\nimport {\n facetObjectMatchesDefinition,\n getCorrespondingSelectedFacet,\n} from '@/utils/functions/queryUtils'\nimport { Autocomplete, TextField } from '@mui/material'\nimport {\n FacetColumnResultValues,\n FacetColumnValuesRequest,\n} from '@sage-bionetworks/synapse-types'\nimport { SyntheticEvent } from 'react'\nimport { useQueryContext } from '../QueryContext/QueryContext'\nimport { useGetQueryMetadata } from '../QueryWrapper/useGetQueryMetadata'\n\nexport type FilterProps = {\n topLevelEnumeratedFacetToFilter: UniqueFacetIdentifier\n}\n\nfunction ColumnFilter(props: FilterProps) {\n const queryContext = useQueryContext()\n const {\n getCurrentQueryRequest,\n addValueToSelectedFacet,\n removeSelectedFacet,\n } = queryContext\n const { data: queryMetadata } = useGetQueryMetadata()\n const { topLevelEnumeratedFacetToFilter } = props\n\n const currentQuery = getCurrentQueryRequest()\n\n const activeFacet = (queryMetadata?.facets ?? []).find(facet =>\n facetObjectMatchesDefinition(facet, topLevelEnumeratedFacetToFilter),\n ) as FacetColumnResultValues | undefined\n\n // Map the facet values to format for MUI Autocomplete options\n const filterOptions = activeFacet?.facetValues.map(({ value }) => value) ?? []\n\n const selectedFacetFromQuery = getCorrespondingSelectedFacet(\n topLevelEnumeratedFacetToFilter,\n currentQuery.query.selectedFacets,\n ) as FacetColumnValuesRequest | undefined\n\n const selectedValues = selectedFacetFromQuery?.facetValues || []\n\n const onChange = (\n event: SyntheticEvent,\n values: string[], // New value for the selected options\n ) => {\n removeSelectedFacet(topLevelEnumeratedFacetToFilter)\n\n values.forEach(value =>\n addValueToSelectedFacet(topLevelEnumeratedFacetToFilter, value),\n )\n }\n\n return (\n <div>\n {filterOptions.length > 0 && (\n <Autocomplete\n multiple\n options={filterOptions}\n value={selectedValues}\n onChange={onChange}\n renderInput={params => (\n <TextField {...params} placeholder=\"Select Filter(s)\" />\n )}\n />\n )}\n </div>\n )\n}\n\nexport default ColumnFilter\n"],"mappings":";;;;;;AAkBA,SAAS,EAAa,GAAoB;CAExC,IAAM,EACJ,2BACA,4BACA,2BAJmB,
|
|
1
|
+
{"version":3,"file":"ColumnFilter.js","names":[],"sources":["../../../src/components/ColumnFilter/ColumnFilter.tsx"],"sourcesContent":["import { UniqueFacetIdentifier } from '@/utils'\nimport {\n facetObjectMatchesDefinition,\n getCorrespondingSelectedFacet,\n} from '@/utils/functions/queryUtils'\nimport { Autocomplete, TextField } from '@mui/material'\nimport {\n FacetColumnResultValues,\n FacetColumnValuesRequest,\n} from '@sage-bionetworks/synapse-types'\nimport { SyntheticEvent } from 'react'\nimport { useQueryContext } from '../QueryContext/QueryContext'\nimport { useGetQueryMetadata } from '../QueryWrapper/useGetQueryMetadata'\n\nexport type FilterProps = {\n topLevelEnumeratedFacetToFilter: UniqueFacetIdentifier\n}\n\nfunction ColumnFilter(props: FilterProps) {\n const queryContext = useQueryContext()\n const {\n getCurrentQueryRequest,\n addValueToSelectedFacet,\n removeSelectedFacet,\n } = queryContext\n const { data: queryMetadata } = useGetQueryMetadata()\n const { topLevelEnumeratedFacetToFilter } = props\n\n const currentQuery = getCurrentQueryRequest()\n\n const activeFacet = (queryMetadata?.facets ?? []).find(facet =>\n facetObjectMatchesDefinition(facet, topLevelEnumeratedFacetToFilter),\n ) as FacetColumnResultValues | undefined\n\n // Map the facet values to format for MUI Autocomplete options\n const filterOptions = activeFacet?.facetValues.map(({ value }) => value) ?? []\n\n const selectedFacetFromQuery = getCorrespondingSelectedFacet(\n topLevelEnumeratedFacetToFilter,\n currentQuery.query.selectedFacets,\n ) as FacetColumnValuesRequest | undefined\n\n const selectedValues = selectedFacetFromQuery?.facetValues || []\n\n const onChange = (\n event: SyntheticEvent,\n values: string[], // New value for the selected options\n ) => {\n removeSelectedFacet(topLevelEnumeratedFacetToFilter)\n\n values.forEach(value =>\n addValueToSelectedFacet(topLevelEnumeratedFacetToFilter, value),\n )\n }\n\n return (\n <div>\n {filterOptions.length > 0 && (\n <Autocomplete\n multiple\n options={filterOptions}\n value={selectedValues}\n onChange={onChange}\n renderInput={params => (\n <TextField {...params} placeholder=\"Select Filter(s)\" />\n )}\n />\n )}\n </div>\n )\n}\n\nexport default ColumnFilter\n"],"mappings":";;;;;;AAkBA,SAAS,EAAa,GAAoB;CAExC,IAAM,EACJ,2BACA,4BACA,2BAJmB,GAKjB,EACE,EAAE,MAAM,MAAkB,GAAqB,EAC/C,EAAE,uCAAoC,GAEtC,IAAe,GAAwB,EAOvC,KALe,GAAe,UAAU,EAAE,EAAE,MAAK,MACrD,EAA6B,GAAO,EAAgC,CAIhD,EAAa,YAAY,KAAK,EAAE,eAAY,EAAM,IAAI,EAAE,EAOxE,IALyB,EAC7B,GACA,EAAa,MAAM,eAGE,EAAwB,eAAe,EAAE;AAahE,QACE,kBAAC,OAAD,EAAA,UACG,EAAc,SAAS,KACtB,kBAAC,GAAD;EACE,UAAA;EACA,SAAS;EACT,OAAO;EACG,WAjBhB,GACA,MACG;AAGH,GAFA,EAAoB,EAAgC,EAEpD,EAAO,SAAQ,MACb,EAAwB,GAAiC,EAAM,CAChE;;EAWK,cAAa,MACX,kBAAC,GAAD;GAAW,GAAI;GAAQ,aAAY;GAAqB,CAAA;EAE1D,CAAA,EAEA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComponentCollapse.js","names":[],"sources":["../../src/components/ComponentCollapse.tsx"],"sourcesContent":["import { spreadSx } from '@/theme/spreadSx'\nimport {\n KeyboardArrowDownTwoTone,\n KeyboardArrowUpTwoTone,\n} from '@mui/icons-material'\nimport { Box, Collapse, SxProps } from '@mui/material'\nimport {\n KeyboardEvent,\n PropsWithChildren,\n ReactNode,\n useId,\n useState,\n} from 'react'\n\nexport type ComponentCollapseProps = PropsWithChildren<{\n component: ReactNode\n defaultVisible?: boolean // default to false (collapsed)\n componentContainerSx?: SxProps\n collapseBoxSx?: SxProps\n iconSx?: SxProps\n}>\n\n/**\n * Wrap any child components in a collapse, using a custom component as the trigger\n */\nexport default function ComponentCollapse({\n component,\n defaultVisible,\n componentContainerSx,\n collapseBoxSx,\n iconSx,\n children,\n}: ComponentCollapseProps) {\n const [show, setShow] = useState(defaultVisible)\n const collapseId = useId()\n const allIconSx: SxProps = {\n color: 'grey.700',\n marginBottom: '-5px !important',\n height: '18px',\n ...iconSx,\n }\n\n const componentContainerDefaultSx: SxProps = {\n display: 'flex',\n textAlign: 'left',\n justifyContent: 'space-between',\n backgroundColor: 'grey.200',\n padding: '15px',\n '&:hover': {\n cursor: 'pointer',\n },\n }\n const collapseBoxDefaultSx: SxProps = {\n backgroundColor: 'grey.100',\n padding: '25px',\n }\n\n return (\n <div className=\"MarkdownCollapse\">\n <Box\n component=\"button\"\n sx={spreadSx(componentContainerDefaultSx, componentContainerSx)}\n onClick={() => setShow(!show)}\n onKeyDown={(e: KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n setShow(!show)\n }\n }}\n aria-controls={collapseId}\n aria-expanded={show}\n >\n {component}\n {show ? (\n <KeyboardArrowUpTwoTone sx={allIconSx} />\n ) : (\n <KeyboardArrowDownTwoTone sx={allIconSx} />\n )}\n </Box>\n <Collapse in={show}>\n <Box sx={spreadSx(collapseBoxDefaultSx, collapseBoxSx)}>\n <div id={collapseId}>{children}</div>\n </Box>\n </Collapse>\n </div>\n )\n}\n"],"mappings":";;;;;;AAyBA,SAAwB,EAAkB,EACxC,cACA,mBACA,yBACA,kBACA,WACA,eACyB;CACzB,IAAM,CAAC,GAAM,KAAW,EAAS,EAAe,EAC1C,IAAa,GAAO,EACpB,IAAqB;EACzB,OAAO;EACP,cAAc;EACd,QAAQ;EACR,GAAG;EACJ;AAiBD,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,GAAD;GACE,WAAU;GACV,IAAI,
|
|
1
|
+
{"version":3,"file":"ComponentCollapse.js","names":[],"sources":["../../src/components/ComponentCollapse.tsx"],"sourcesContent":["import { spreadSx } from '@/theme/spreadSx'\nimport {\n KeyboardArrowDownTwoTone,\n KeyboardArrowUpTwoTone,\n} from '@mui/icons-material'\nimport { Box, Collapse, SxProps } from '@mui/material'\nimport {\n KeyboardEvent,\n PropsWithChildren,\n ReactNode,\n useId,\n useState,\n} from 'react'\n\nexport type ComponentCollapseProps = PropsWithChildren<{\n component: ReactNode\n defaultVisible?: boolean // default to false (collapsed)\n componentContainerSx?: SxProps\n collapseBoxSx?: SxProps\n iconSx?: SxProps\n}>\n\n/**\n * Wrap any child components in a collapse, using a custom component as the trigger\n */\nexport default function ComponentCollapse({\n component,\n defaultVisible,\n componentContainerSx,\n collapseBoxSx,\n iconSx,\n children,\n}: ComponentCollapseProps) {\n const [show, setShow] = useState(defaultVisible)\n const collapseId = useId()\n const allIconSx: SxProps = {\n color: 'grey.700',\n marginBottom: '-5px !important',\n height: '18px',\n ...iconSx,\n }\n\n const componentContainerDefaultSx: SxProps = {\n display: 'flex',\n textAlign: 'left',\n justifyContent: 'space-between',\n backgroundColor: 'grey.200',\n padding: '15px',\n '&:hover': {\n cursor: 'pointer',\n },\n }\n const collapseBoxDefaultSx: SxProps = {\n backgroundColor: 'grey.100',\n padding: '25px',\n }\n\n return (\n <div className=\"MarkdownCollapse\">\n <Box\n component=\"button\"\n sx={spreadSx(componentContainerDefaultSx, componentContainerSx)}\n onClick={() => setShow(!show)}\n onKeyDown={(e: KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n setShow(!show)\n }\n }}\n aria-controls={collapseId}\n aria-expanded={show}\n >\n {component}\n {show ? (\n <KeyboardArrowUpTwoTone sx={allIconSx} />\n ) : (\n <KeyboardArrowDownTwoTone sx={allIconSx} />\n )}\n </Box>\n <Collapse in={show}>\n <Box sx={spreadSx(collapseBoxDefaultSx, collapseBoxSx)}>\n <div id={collapseId}>{children}</div>\n </Box>\n </Collapse>\n </div>\n )\n}\n"],"mappings":";;;;;;AAyBA,SAAwB,EAAkB,EACxC,cACA,mBACA,yBACA,kBACA,WACA,eACyB;CACzB,IAAM,CAAC,GAAM,KAAW,EAAS,EAAe,EAC1C,IAAa,GAAO,EACpB,IAAqB;EACzB,OAAO;EACP,cAAc;EACd,QAAQ;EACR,GAAG;EACJ;AAiBD,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,GAAD;GACE,WAAU;GACV,IAAI,EAAS;IAlBjB,SAAS;IACT,WAAW;IACX,gBAAgB;IAChB,iBAAiB;IACjB,SAAS;IACT,WAAW,EACT,QAAQ,WACT;IAWgB,EAA6B,EAAqB;GAC/D,eAAe,EAAQ,CAAC,EAAK;GAC7B,YAAY,MAAqB;AAC/B,KAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,SACjC,EAAE,gBAAgB,EAClB,EAAQ,CAAC,EAAK;;GAGlB,iBAAe;GACf,iBAAe;aAXjB,CAaG,GAEC,EADD,IACE,IAEA,GAFD,EAAwB,IAAI,GAAa,CAEE,CAEzC;MACN,kBAAC,GAAD;GAAU,IAAI;aACZ,kBAAC,GAAD;IAAK,IAAI,EAAS;KA3BtB,iBAAiB;KACjB,SAAS;KA0Ba,EAAsB,EAAc;cACpD,kBAAC,OAAD;KAAK,IAAI;KAAa;KAAe,CAAA;IACjC,CAAA;GACG,CAAA,CACP"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CookiesNotification.js","names":[],"sources":["../../../src/components/CookiesNotification/CookiesNotification.tsx"],"sourcesContent":["import {\n allowAll,\n allowNone,\n CookiePreference,\n COOKIES_AGREEMENT_COOKIE_KEY,\n useCookiePreferences,\n} from '@/utils/hooks/useCookiePreferences'\nimport {\n PRIVACY_POLICY_LINK,\n URL_TERMS_CONDITIONS_AGREEMENT,\n CHILD_MINOR_ADDENDUM_LINK,\n} from '@/utils/SynapseConstants'\nimport React from 'react'\nimport { Link, Typography } from '@mui/material'\nimport { useEffect, useState } from 'react'\nimport UniversalCookies from 'universal-cookie'\nimport FullWidthAlert from '../FullWidthAlert'\nimport CookiePreferencesDialog from './CookiePreferencesDialog'\nimport styles from './CookiesNotification.module.scss'\n\nexport const alertConfig = {\n title: 'Our site uses cookies.',\n description: (\n <>\n <Typography variant=\"body1\">\n We use necessary cookies and store your data to ensure our websites\n function properly. With your consent, we would also like to use optional\n cookies to remember your preferences and improve our websites. Please\n read our <Link href={PRIVACY_POLICY_LINK}>Privacy Policy</Link> for\n details. By clicking “Allow All,” you agree to our use of cookies. You\n can adjust your cookie preferences anytime on the Settings page.\n </Typography>\n <Typography\n variant=\"smallText1\"\n sx={{ mt: '20px' }}\n className={styles.MinorAddendum}\n >\n Please read our{' '}\n <Link href={URL_TERMS_CONDITIONS_AGREEMENT}>Terms of Service</Link>{' '}\n before using our website. If you are between 13 and 18, you must submit\n a <Link href={CHILD_MINOR_ADDENDUM_LINK}>Child Minor Addendum</Link> for\n access.\n </Typography>\n </>\n ),\n primaryButtonText: 'ALLOW ALL',\n secondaryButtonText: 'Disable All',\n tertiaryButtonText: 'Customize',\n}\n\nexport type CookieNotificationProps = {\n onClose?: (cookiePrefs: CookiePreference) => void\n}\n\nconst CookiesNotification = (\n props: CookieNotificationProps,\n): React.ReactNode => {\n const { onClose } = props\n const [, setCookiePreferences] = useCookiePreferences()\n\n const [notificationDismissed, setNotificationDismissed] = useState(true)\n useEffect(() => {\n const cookies = new UniversalCookies()\n setNotificationDismissed(!!cookies.get(COOKIES_AGREEMENT_COOKIE_KEY))\n }, [])\n\n const [isCookiePrefsDialogVisible, setIsCookiePrefsDialogVisible] =\n useState(false)\n // show banner if they haven't clicked okay, otherwise show nothing\n return notificationDismissed ? (\n <></>\n ) : (\n <>\n <FullWidthAlert\n globalAlertSx={{ zIndex: 1500 }}\n variant=\"info\"\n title={alertConfig.title}\n description={alertConfig.description}\n primaryButtonConfig={{\n text: alertConfig.primaryButtonText,\n onClick: () => {\n setCookiePreferences(allowAll)\n setNotificationDismissed(true)\n if (onClose) {\n onClose(allowAll)\n }\n },\n }}\n secondaryButtonConfig={{\n text: alertConfig.secondaryButtonText,\n onClick: () => {\n setCookiePreferences(allowNone)\n setNotificationDismissed(true)\n if (onClose) {\n onClose(allowNone)\n }\n },\n }}\n tertiaryButtonConfig={{\n text: alertConfig.tertiaryButtonText,\n onClick: () => {\n setIsCookiePrefsDialogVisible(true)\n },\n }}\n isGlobal={true}\n />\n <CookiePreferencesDialog\n isOpen={isCookiePrefsDialogVisible}\n onSave={prefs => {\n setNotificationDismissed(true)\n setIsCookiePrefsDialogVisible(false)\n if (onClose) {\n onClose(prefs)\n }\n }}\n onHide={() => {\n setIsCookiePrefsDialogVisible(false)\n }}\n />\n </>\n )\n}\n\nexport default CookiesNotification\n"],"mappings":";;;;;;;;;;AAoBA,IAAa,IAAc;CACzB,OAAO;CACP,aACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;EAAY,SAAQ;YAApB;GAA4B;GAIjB,kBAAC,GAAD;IAAM,MAAM;cAAqB;IAAqB,CAAA;;GAGpD;KACb,kBAAC,GAAD;EACE,SAAQ;EACR,IAAI,EAAE,IAAI,QAAQ;EAClB,WAAW,EAAO;YAHpB;GAIC;GACiB;GAChB,kBAAC,GAAD;IAAM,MAAM;cAAgC;IAAuB,CAAA;GAAC;GAAI;GAEtE,kBAAC,GAAD;IAAM,MAAM;cAA2B;IAA2B,CAAA;;GAEzD;IACZ,EAAA,CAAA;CAEL,mBAAmB;CACnB,qBAAqB;CACrB,oBAAoB;CACrB,EAMK,KACJ,MACoB;CACpB,IAAM,EAAE,eAAY,GACd,GAAG,KAAwB,GAAsB,EAEjD,CAAC,GAAuB,KAA4B,EAAS,GAAK;AACxE,SAAgB;AAEd,IAAyB,CAAC,
|
|
1
|
+
{"version":3,"file":"CookiesNotification.js","names":[],"sources":["../../../src/components/CookiesNotification/CookiesNotification.tsx"],"sourcesContent":["import {\n allowAll,\n allowNone,\n CookiePreference,\n COOKIES_AGREEMENT_COOKIE_KEY,\n useCookiePreferences,\n} from '@/utils/hooks/useCookiePreferences'\nimport {\n PRIVACY_POLICY_LINK,\n URL_TERMS_CONDITIONS_AGREEMENT,\n CHILD_MINOR_ADDENDUM_LINK,\n} from '@/utils/SynapseConstants'\nimport React from 'react'\nimport { Link, Typography } from '@mui/material'\nimport { useEffect, useState } from 'react'\nimport UniversalCookies from 'universal-cookie'\nimport FullWidthAlert from '../FullWidthAlert'\nimport CookiePreferencesDialog from './CookiePreferencesDialog'\nimport styles from './CookiesNotification.module.scss'\n\nexport const alertConfig = {\n title: 'Our site uses cookies.',\n description: (\n <>\n <Typography variant=\"body1\">\n We use necessary cookies and store your data to ensure our websites\n function properly. With your consent, we would also like to use optional\n cookies to remember your preferences and improve our websites. Please\n read our <Link href={PRIVACY_POLICY_LINK}>Privacy Policy</Link> for\n details. By clicking “Allow All,” you agree to our use of cookies. You\n can adjust your cookie preferences anytime on the Settings page.\n </Typography>\n <Typography\n variant=\"smallText1\"\n sx={{ mt: '20px' }}\n className={styles.MinorAddendum}\n >\n Please read our{' '}\n <Link href={URL_TERMS_CONDITIONS_AGREEMENT}>Terms of Service</Link>{' '}\n before using our website. If you are between 13 and 18, you must submit\n a <Link href={CHILD_MINOR_ADDENDUM_LINK}>Child Minor Addendum</Link> for\n access.\n </Typography>\n </>\n ),\n primaryButtonText: 'ALLOW ALL',\n secondaryButtonText: 'Disable All',\n tertiaryButtonText: 'Customize',\n}\n\nexport type CookieNotificationProps = {\n onClose?: (cookiePrefs: CookiePreference) => void\n}\n\nconst CookiesNotification = (\n props: CookieNotificationProps,\n): React.ReactNode => {\n const { onClose } = props\n const [, setCookiePreferences] = useCookiePreferences()\n\n const [notificationDismissed, setNotificationDismissed] = useState(true)\n useEffect(() => {\n const cookies = new UniversalCookies()\n setNotificationDismissed(!!cookies.get(COOKIES_AGREEMENT_COOKIE_KEY))\n }, [])\n\n const [isCookiePrefsDialogVisible, setIsCookiePrefsDialogVisible] =\n useState(false)\n // show banner if they haven't clicked okay, otherwise show nothing\n return notificationDismissed ? (\n <></>\n ) : (\n <>\n <FullWidthAlert\n globalAlertSx={{ zIndex: 1500 }}\n variant=\"info\"\n title={alertConfig.title}\n description={alertConfig.description}\n primaryButtonConfig={{\n text: alertConfig.primaryButtonText,\n onClick: () => {\n setCookiePreferences(allowAll)\n setNotificationDismissed(true)\n if (onClose) {\n onClose(allowAll)\n }\n },\n }}\n secondaryButtonConfig={{\n text: alertConfig.secondaryButtonText,\n onClick: () => {\n setCookiePreferences(allowNone)\n setNotificationDismissed(true)\n if (onClose) {\n onClose(allowNone)\n }\n },\n }}\n tertiaryButtonConfig={{\n text: alertConfig.tertiaryButtonText,\n onClick: () => {\n setIsCookiePrefsDialogVisible(true)\n },\n }}\n isGlobal={true}\n />\n <CookiePreferencesDialog\n isOpen={isCookiePrefsDialogVisible}\n onSave={prefs => {\n setNotificationDismissed(true)\n setIsCookiePrefsDialogVisible(false)\n if (onClose) {\n onClose(prefs)\n }\n }}\n onHide={() => {\n setIsCookiePrefsDialogVisible(false)\n }}\n />\n </>\n )\n}\n\nexport default CookiesNotification\n"],"mappings":";;;;;;;;;;AAoBA,IAAa,IAAc;CACzB,OAAO;CACP,aACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;EAAY,SAAQ;YAApB;GAA4B;GAIjB,kBAAC,GAAD;IAAM,MAAM;cAAqB;IAAqB,CAAA;;GAGpD;KACb,kBAAC,GAAD;EACE,SAAQ;EACR,IAAI,EAAE,IAAI,QAAQ;EAClB,WAAW,EAAO;YAHpB;GAIC;GACiB;GAChB,kBAAC,GAAD;IAAM,MAAM;cAAgC;IAAuB,CAAA;GAAC;GAAI;GAEtE,kBAAC,GAAD;IAAM,MAAM;cAA2B;IAA2B,CAAA;;GAEzD;IACZ,EAAA,CAAA;CAEL,mBAAmB;CACnB,qBAAqB;CACrB,oBAAoB;CACrB,EAMK,KACJ,MACoB;CACpB,IAAM,EAAE,eAAY,GACd,GAAG,KAAwB,GAAsB,EAEjD,CAAC,GAAuB,KAA4B,EAAS,GAAK;AACxE,SAAgB;AAEd,IAAyB,CAAC,CAAC,IADP,GACO,CAAQ,IAAI,EAA6B,CAAC;IACpE,EAAE,CAAC;CAEN,IAAM,CAAC,GAA4B,KACjC,EAAS,GAAM;AAEjB,QAAO,IACL,kBAAA,GAAA,EAAK,CAAA,GAEL,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;EACE,eAAe,EAAE,QAAQ,MAAM;EAC/B,SAAQ;EACR,OAAO,EAAY;EACnB,aAAa,EAAY;EACzB,qBAAqB;GACnB,MAAM,EAAY;GAClB,eAAe;AAGb,IAFA,EAAqB,EAAS,EAC9B,EAAyB,GAAK,EAC1B,KACF,EAAQ,EAAS;;GAGtB;EACD,uBAAuB;GACrB,MAAM,EAAY;GAClB,eAAe;AAGb,IAFA,EAAqB,EAAU,EAC/B,EAAyB,GAAK,EAC1B,KACF,EAAQ,EAAU;;GAGvB;EACD,sBAAsB;GACpB,MAAM,EAAY;GAClB,eAAe;AACb,MAA8B,GAAK;;GAEtC;EACD,UAAU;EACV,CAAA,EACF,kBAAC,GAAD;EACE,QAAQ;EACR,SAAQ,MAAS;AAGf,GAFA,EAAyB,GAAK,EAC9B,EAA8B,GAAM,EAChC,KACF,EAAQ,EAAM;;EAGlB,cAAc;AACZ,KAA8B,GAAM;;EAEtC,CAAA,CACD,EAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateProjectModal.js","names":[],"sources":["../../../src/components/CreateProjectModal/CreateProjectModal.tsx"],"sourcesContent":["import SynapseClient from '@/synapse-client'\nimport { useGetRealmPrincipals } from '@/synapse-queries/realm/useRealmPrincipals'\nimport { SynapseClientError } from '@sage-bionetworks/synapse-client'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport { Alert, Stack } from '@mui/material'\nimport { ACCESS_TYPE } from '@sage-bionetworks/synapse-types'\nimport { KeyboardEvent, useState } from 'react'\nimport { useMutation } from '@tanstack/react-query'\nimport { ConfirmationDialog } from '../ConfirmationDialog/ConfirmationDialog'\nimport { displayToast } from '../ToastMessage/ToastMessage'\nimport TextField from '../TextField/TextField'\nimport {\n ProjectVisibility,\n ProjectVisibilityRadioGroup,\n} from './ProjectVisibilityRadioGroup'\n\nexport type CreateProjectModalProps = {\n isShowingModal?: boolean\n onClose: () => void\n gotoPlace?: (href: string) => void\n}\n\nexport function CreateProjectModal({\n isShowingModal = false,\n onClose,\n gotoPlace,\n}: CreateProjectModalProps) {\n const { accessToken } = useSynapseContext()\n const [projectName, setProjectName] = useState<string>('')\n const [description, setDescription] = useState<string>('')\n const [visibility, setVisibility] =\n useState<ProjectVisibility>('DISCOVERABLE')\n\n const { data: realmPrincipals } = useGetRealmPrincipals()\n const publicGroupId = realmPrincipals?.publicGroup\n const authenticatedUsersId = realmPrincipals?.authenticatedUsers\n\n const applyVisibilityAcl = async (projectId: string): Promise<void> => {\n if (visibility === 'PRIVATE') {\n return\n }\n try {\n const currentAcl = await SynapseClient.getEntityACL(\n projectId,\n accessToken,\n )\n\n const upsertAccessTypes = (\n entries: typeof currentAcl.resourceAccess,\n principalId: number,\n accessTypes: ACCESS_TYPE[],\n ): typeof currentAcl.resourceAccess => {\n const existing = entries.find(e => e.principalId === principalId)\n if (existing) {\n return entries.map(e =>\n e.principalId === principalId\n ? {\n ...e,\n accessType: [...new Set([...e.accessType, ...accessTypes])],\n }\n : e,\n )\n }\n return [...entries, { principalId, accessType: accessTypes }]\n }\n\n let newResourceAccess = [...currentAcl.resourceAccess]\n\n if (visibility === 'DISCOVERABLE') {\n if (publicGroupId) {\n newResourceAccess = upsertAccessTypes(\n newResourceAccess,\n Number(publicGroupId),\n [ACCESS_TYPE.READ],\n )\n }\n if (authenticatedUsersId) {\n newResourceAccess = upsertAccessTypes(\n newResourceAccess,\n Number(authenticatedUsersId),\n [ACCESS_TYPE.READ],\n )\n }\n } else if (visibility === 'PUBLIC') {\n if (publicGroupId) {\n newResourceAccess = upsertAccessTypes(\n newResourceAccess,\n Number(publicGroupId),\n [ACCESS_TYPE.READ],\n )\n }\n if (authenticatedUsersId) {\n newResourceAccess = upsertAccessTypes(\n newResourceAccess,\n Number(authenticatedUsersId),\n [ACCESS_TYPE.READ, ACCESS_TYPE.DOWNLOAD],\n )\n }\n }\n\n await SynapseClient.updateEntityACL(\n { ...currentAcl, resourceAccess: newResourceAccess },\n accessToken,\n )\n } catch (e) {\n const err = e as SynapseClientError\n throw new Error(\n `Project was created, but visibility could not be set: ${\n err.reason ?? err.message\n }`,\n )\n }\n }\n\n const createProjectMutation = useMutation({\n mutationFn: async () => {\n const newProject = await SynapseClient.createProject(\n projectName,\n description,\n accessToken,\n )\n let aclError: string | undefined\n try {\n await applyVisibilityAcl(newProject.id!)\n } catch (e) {\n aclError = (e as Error).message\n }\n return { newProject, aclError }\n },\n onError: error => {\n const synapseError = error as SynapseClientError\n displayToast(synapseError.reason ?? error.message, 'danger')\n },\n onSuccess: ({ newProject, aclError }) => {\n // Note - Do NOT call createProjectMutation.reset() here — in TanStack Query v5,\n // reset() inside onSuccess interrupts the rest of this callback.\n // Note 2 - displayToast is not shown in Storybook (with the window.location.href change), but works when\n // integrated in the Synapse.org app.\n if (aclError) {\n displayToast(aclError, 'danger')\n } else {\n displayToast('Project created', 'success')\n }\n setProjectName('')\n setDescription('')\n setVisibility('DISCOVERABLE')\n onClose()\n const href = `/Synapse:${newProject.id}`\n if (gotoPlace) {\n gotoPlace(href)\n } else {\n window.location.href = href\n }\n },\n })\n\n const hide = () => {\n setProjectName('')\n setDescription('')\n setVisibility('DISCOVERABLE')\n createProjectMutation.reset()\n onClose()\n }\n\n const dialogContent = (\n <Stack gap={2}>\n <TextField\n id=\"projectInput\"\n label=\"Project Name\"\n required\n helperText=\"Pick a unique title for your project\"\n value={projectName}\n fullWidth\n onChange={event => {\n setProjectName(event.target.value)\n }}\n inputProps={{\n onKeyDown: (event: KeyboardEvent<HTMLInputElement>) => {\n if (event.key === 'Enter') {\n if (projectName !== '') {\n createProjectMutation.mutate()\n }\n }\n },\n }}\n />\n <TextField\n id=\"descriptionInput\"\n label=\"Description\"\n helperText=\"(optional)\"\n placeholder=\"Brief description of this project\"\n multiline\n minRows={3}\n value={description}\n fullWidth\n maxCharacterCount={350}\n onChange={event => {\n setDescription(event.target.value)\n }}\n />\n <ProjectVisibilityRadioGroup\n value={visibility}\n onChange={setVisibility}\n />\n <Alert severity=\"warning\">\n You can update project visibility at any time in Project Tools, or\n manage access at a more granular level for individual files and folders.\n </Alert>\n </Stack>\n )\n\n return (\n <>\n <ConfirmationDialog\n open={isShowingModal}\n title=\"Create a new Project\"\n content={dialogContent}\n confirmButtonProps={{\n children: 'Save',\n disabled: createProjectMutation.isPending,\n loading: createProjectMutation.isPending,\n }}\n onConfirm={() => {\n createProjectMutation.mutate()\n }}\n onCancel={hide}\n maxWidth=\"sm\"\n dense\n />\n </>\n )\n}\n"],"mappings":";;;;;;;;;;;;;AAsBA,SAAgB,EAAmB,EACjC,oBAAiB,IACjB,YACA,gBAC0B;CAC1B,IAAM,EAAE,mBAAgB,GAAmB,EACrC,CAAC,GAAa,KAAkB,EAAiB,GAAG,EACpD,CAAC,GAAa,KAAkB,EAAiB,GAAG,EACpD,CAAC,GAAY,KACjB,EAA4B,eAAe,EAEvC,EAAE,MAAM,MAAoB,GAAuB,EACnD,IAAgB,GAAiB,aACjC,IAAuB,GAAiB,oBAExC,IAAqB,OAAO,MAAqC;AACjE,YAAe,UAGnB,KAAI;GACF,IAAM,IAAa,MAAM,EAAc,aACrC,GACA,EACD,EAEK,KACJ,GACA,GACA,MAEiB,EAAQ,MAAK,MAAK,EAAE,gBAAgB,
|
|
1
|
+
{"version":3,"file":"CreateProjectModal.js","names":[],"sources":["../../../src/components/CreateProjectModal/CreateProjectModal.tsx"],"sourcesContent":["import SynapseClient from '@/synapse-client'\nimport { useGetRealmPrincipals } from '@/synapse-queries/realm/useRealmPrincipals'\nimport { SynapseClientError } from '@sage-bionetworks/synapse-client'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport { Alert, Stack } from '@mui/material'\nimport { ACCESS_TYPE } from '@sage-bionetworks/synapse-types'\nimport { KeyboardEvent, useState } from 'react'\nimport { useMutation } from '@tanstack/react-query'\nimport { ConfirmationDialog } from '../ConfirmationDialog/ConfirmationDialog'\nimport { displayToast } from '../ToastMessage/ToastMessage'\nimport TextField from '../TextField/TextField'\nimport {\n ProjectVisibility,\n ProjectVisibilityRadioGroup,\n} from './ProjectVisibilityRadioGroup'\n\nexport type CreateProjectModalProps = {\n isShowingModal?: boolean\n onClose: () => void\n gotoPlace?: (href: string) => void\n}\n\nexport function CreateProjectModal({\n isShowingModal = false,\n onClose,\n gotoPlace,\n}: CreateProjectModalProps) {\n const { accessToken } = useSynapseContext()\n const [projectName, setProjectName] = useState<string>('')\n const [description, setDescription] = useState<string>('')\n const [visibility, setVisibility] =\n useState<ProjectVisibility>('DISCOVERABLE')\n\n const { data: realmPrincipals } = useGetRealmPrincipals()\n const publicGroupId = realmPrincipals?.publicGroup\n const authenticatedUsersId = realmPrincipals?.authenticatedUsers\n\n const applyVisibilityAcl = async (projectId: string): Promise<void> => {\n if (visibility === 'PRIVATE') {\n return\n }\n try {\n const currentAcl = await SynapseClient.getEntityACL(\n projectId,\n accessToken,\n )\n\n const upsertAccessTypes = (\n entries: typeof currentAcl.resourceAccess,\n principalId: number,\n accessTypes: ACCESS_TYPE[],\n ): typeof currentAcl.resourceAccess => {\n const existing = entries.find(e => e.principalId === principalId)\n if (existing) {\n return entries.map(e =>\n e.principalId === principalId\n ? {\n ...e,\n accessType: [...new Set([...e.accessType, ...accessTypes])],\n }\n : e,\n )\n }\n return [...entries, { principalId, accessType: accessTypes }]\n }\n\n let newResourceAccess = [...currentAcl.resourceAccess]\n\n if (visibility === 'DISCOVERABLE') {\n if (publicGroupId) {\n newResourceAccess = upsertAccessTypes(\n newResourceAccess,\n Number(publicGroupId),\n [ACCESS_TYPE.READ],\n )\n }\n if (authenticatedUsersId) {\n newResourceAccess = upsertAccessTypes(\n newResourceAccess,\n Number(authenticatedUsersId),\n [ACCESS_TYPE.READ],\n )\n }\n } else if (visibility === 'PUBLIC') {\n if (publicGroupId) {\n newResourceAccess = upsertAccessTypes(\n newResourceAccess,\n Number(publicGroupId),\n [ACCESS_TYPE.READ],\n )\n }\n if (authenticatedUsersId) {\n newResourceAccess = upsertAccessTypes(\n newResourceAccess,\n Number(authenticatedUsersId),\n [ACCESS_TYPE.READ, ACCESS_TYPE.DOWNLOAD],\n )\n }\n }\n\n await SynapseClient.updateEntityACL(\n { ...currentAcl, resourceAccess: newResourceAccess },\n accessToken,\n )\n } catch (e) {\n const err = e as SynapseClientError\n throw new Error(\n `Project was created, but visibility could not be set: ${\n err.reason ?? err.message\n }`,\n )\n }\n }\n\n const createProjectMutation = useMutation({\n mutationFn: async () => {\n const newProject = await SynapseClient.createProject(\n projectName,\n description,\n accessToken,\n )\n let aclError: string | undefined\n try {\n await applyVisibilityAcl(newProject.id!)\n } catch (e) {\n aclError = (e as Error).message\n }\n return { newProject, aclError }\n },\n onError: error => {\n const synapseError = error as SynapseClientError\n displayToast(synapseError.reason ?? error.message, 'danger')\n },\n onSuccess: ({ newProject, aclError }) => {\n // Note - Do NOT call createProjectMutation.reset() here — in TanStack Query v5,\n // reset() inside onSuccess interrupts the rest of this callback.\n // Note 2 - displayToast is not shown in Storybook (with the window.location.href change), but works when\n // integrated in the Synapse.org app.\n if (aclError) {\n displayToast(aclError, 'danger')\n } else {\n displayToast('Project created', 'success')\n }\n setProjectName('')\n setDescription('')\n setVisibility('DISCOVERABLE')\n onClose()\n const href = `/Synapse:${newProject.id}`\n if (gotoPlace) {\n gotoPlace(href)\n } else {\n window.location.href = href\n }\n },\n })\n\n const hide = () => {\n setProjectName('')\n setDescription('')\n setVisibility('DISCOVERABLE')\n createProjectMutation.reset()\n onClose()\n }\n\n const dialogContent = (\n <Stack gap={2}>\n <TextField\n id=\"projectInput\"\n label=\"Project Name\"\n required\n helperText=\"Pick a unique title for your project\"\n value={projectName}\n fullWidth\n onChange={event => {\n setProjectName(event.target.value)\n }}\n inputProps={{\n onKeyDown: (event: KeyboardEvent<HTMLInputElement>) => {\n if (event.key === 'Enter') {\n if (projectName !== '') {\n createProjectMutation.mutate()\n }\n }\n },\n }}\n />\n <TextField\n id=\"descriptionInput\"\n label=\"Description\"\n helperText=\"(optional)\"\n placeholder=\"Brief description of this project\"\n multiline\n minRows={3}\n value={description}\n fullWidth\n maxCharacterCount={350}\n onChange={event => {\n setDescription(event.target.value)\n }}\n />\n <ProjectVisibilityRadioGroup\n value={visibility}\n onChange={setVisibility}\n />\n <Alert severity=\"warning\">\n You can update project visibility at any time in Project Tools, or\n manage access at a more granular level for individual files and folders.\n </Alert>\n </Stack>\n )\n\n return (\n <>\n <ConfirmationDialog\n open={isShowingModal}\n title=\"Create a new Project\"\n content={dialogContent}\n confirmButtonProps={{\n children: 'Save',\n disabled: createProjectMutation.isPending,\n loading: createProjectMutation.isPending,\n }}\n onConfirm={() => {\n createProjectMutation.mutate()\n }}\n onCancel={hide}\n maxWidth=\"sm\"\n dense\n />\n </>\n )\n}\n"],"mappings":"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"}
|