synapse-react-client 4.0.9 → 4.0.10
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/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.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 +113 -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.js.map +1 -1
- 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/json-rx/JsonRx.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/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.js.map +1 -1
- 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.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/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.js.map +1 -1
- package/dist/components/Forum/DiscussionSearchResult.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/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/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.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.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.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/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.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/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/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 +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateOrUpdateDoiModal.js","names":[],"sources":["../../../src/components/doi/CreateOrUpdateDoiModal.tsx"],"sourcesContent":["import ConfirmCloseWithoutSavingDialog from '@/components/Dialog/ConfirmCloseWithoutSavingDialog'\nimport { DialogBase } from '@/components/DialogBase'\nimport { doiFormSchema, doiFormUiSchema } from '@/components/doi/DoiFormSchemas'\nimport { PrivateEntityDoiWarning } from '@/components/doi/PrivateEntityDoiWarning'\nimport { JsonSchemaForm } from '@/components/JsonSchemaForm/JsonSchemaForm'\nimport { MarkdownPopover } from '@/components/Markdown/MarkdownPopover'\nimport { StyledFormControl } from '@/components/styled/StyledFormControl'\nimport { displayToast } from '@/components/ToastMessage/ToastMessage'\nimport { useCreateOrUpdateDOI, useGetDOI } from '@/synapse-queries/doi/useDOI'\nimport { useGetVersions } from '@/synapse-queries/entity/useEntity'\nimport { useGetEntityBundle } from '@/synapse-queries/entity/useEntityBundle'\nimport { useGetPortal } from '@/synapse-queries/portal/usePortal'\nimport { useGetRealmPrincipals } from '@/synapse-queries/realm/useRealmPrincipals'\nimport { useGetCurrentUserProfile } from '@/synapse-queries/user/useUserBundle'\nimport { useGlobalIsEditingContext } from '@/utils/context/GlobalIsEditingContext'\nimport { isEntityPublic } from '@/utils/functions/AccessControlListUtils'\nimport {\n entityTypeToFriendlyName,\n isDataset,\n isTable,\n isVersionableEntity,\n} from '@/utils/functions/EntityTypeUtils'\nimport {\n BackendDestinationEnum,\n getEndpoint,\n} from '@/utils/functions/getEndpoint'\nimport { DATA_CATALOG_PATH_SEGMENT } from '@/utils/SynapseConstants'\nimport { HelpTwoTone } from '@mui/icons-material'\nimport {\n Alert,\n Button,\n InputLabel,\n Link,\n MenuItem,\n Select,\n TextField,\n Typography,\n} from '@mui/material'\nimport RJSF from '@rjsf/core'\nimport {\n DoiObjectType,\n DoiResourceTypeGeneral,\n DoiResourceTypeResourceTypeGeneralEnum,\n EntityType,\n V2Doi,\n} from '@sage-bionetworks/synapse-client'\nimport { isEmpty } from 'lodash-es'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport { SynapseSpinner } from '../LoadingScreen/LoadingScreen'\n\ntype CreateOrUpdateDoiModalStep = 'warning' | 'form'\n\nexport type CreateOrUpdateDoiModalProps = {\n /** Whether the dialog is open */\n open: boolean\n /** Callback to call when the dialog is closed */\n onClose: () => void\n /** The type of object */\n objectType: DoiObjectType\n /** The ID of the object */\n objectId: string\n /** The optional version number of the object used to populate the form. */\n defaultVersionNumber?: number\n /** If minting a DOI for a portal, the ID of the portal object in Synapse */\n portalId?: string\n}\n\ntype DoiFormData = {\n titles?: string[]\n creators?: string[]\n resourceTypeGeneral?: DoiResourceTypeResourceTypeGeneralEnum\n publicationYear?: number\n}\n\nfunction getSuggestedResourceTypeGeneral(\n type: EntityType,\n): DoiResourceTypeGeneral {\n if (type === EntityType.project || type === EntityType.folder) {\n return DoiResourceTypeGeneral.Collection\n } else {\n return DoiResourceTypeGeneral.Dataset\n }\n}\n\nfunction convertDoiToFormData(doi: V2Doi): DoiFormData {\n return {\n titles: (doi.titles || []).map(title => title.title!),\n creators: (doi.creators || []).map(creator => creator.creatorName!),\n resourceTypeGeneral: doi.resourceType?.resourceTypeGeneral,\n publicationYear: doi.publicationYear,\n }\n}\n\n/**\n * Returns true if the DOI has fields that are not exposed in the UI, so we can let the user know that any changes\n * may be destructive to hidden fields.\n */\nfunction getWasModifiedViaAPI(doi: V2Doi) {\n if (doi.creators?.some(creator => !isEmpty(creator.nameIdentifiers))) {\n return true\n }\n return false\n}\n\nfunction convertFormDataToDoi(formData: DoiFormData): V2Doi {\n return {\n titles: formData.titles?.map(title => ({ title })) || [],\n creators:\n formData.creators?.map(creator => ({ creatorName: creator })) || [],\n resourceType: {\n resourceTypeGeneral: formData.resourceTypeGeneral,\n },\n publicationYear: formData.publicationYear,\n }\n}\n\nexport function CreateOrUpdateDoiModal(props: CreateOrUpdateDoiModalProps) {\n const {\n open,\n onClose,\n objectType,\n objectId,\n defaultVersionNumber,\n portalId,\n } = props\n\n const [showConfirmCloseModal, setShowConfirmCloseDialog] = useState(false)\n const [currentStep, setCurrentStep] =\n useState<CreateOrUpdateDoiModalStep | null>(null)\n const hasSetInitialStepForThisSession = useRef(false)\n const { isEditing, setIsEditing } = useGlobalIsEditingContext()\n useEffect(() => {\n setIsEditing(open)\n\n return () => {\n setIsEditing(false)\n }\n }, [open, setIsEditing])\n\n function handleClose() {\n if (isEditing) {\n setShowConfirmCloseDialog(true)\n } else {\n onClose()\n }\n }\n\n const [selectedVersionNumber, setSelectedVersionNumber] =\n useState(defaultVersionNumber)\n\n const { data: portal } = useGetPortal(portalId!, {\n enabled: Boolean(portalId),\n })\n\n const [formData, setFormData] = useState<DoiFormData>({\n titles: [''],\n creators: [''],\n })\n const { data: currentUser, isLoading: isLoadingCurrentUser } =\n useGetCurrentUserProfile()\n const { data: entityBundle, isLoading: isLoadingEntity } = useGetEntityBundle(\n objectId,\n selectedVersionNumber,\n {\n includeEntity: true,\n includeBenefactorACL: true,\n },\n {\n enabled: objectType === DoiObjectType.ENTITY,\n staleTime: Infinity,\n throwOnError: true,\n },\n )\n const { data: realmPrincipals, isLoading: isLoadingRealmPrincipals } =\n useGetRealmPrincipals()\n const { data: doi, isLoading: isLoadingDoi } = useGetDOI(\n {\n id: objectId,\n version: selectedVersionNumber,\n type: objectType,\n portalId: portalId,\n },\n {\n staleTime: Infinity,\n throwOnError: true,\n },\n )\n\n const shouldShowWarning = useMemo(() => {\n return (\n open &&\n doi === null && // Creating new DOI\n entityBundle?.benefactorAcl &&\n realmPrincipals &&\n !isEntityPublic(\n entityBundle.benefactorAcl.resourceAccess,\n realmPrincipals,\n )\n )\n }, [open, doi, entityBundle, realmPrincipals])\n\n useEffect(() => {\n if (\n open &&\n !hasSetInitialStepForThisSession.current &&\n doi !== undefined && // Wait for DOI query to resolve before determining step\n shouldShowWarning !== undefined\n ) {\n const newStep = shouldShowWarning ? 'warning' : 'form'\n setCurrentStep(newStep)\n hasSetInitialStepForThisSession.current = true\n } else if (!open) {\n setCurrentStep(null)\n hasSetInitialStepForThisSession.current = false\n }\n }, [shouldShowWarning, open, doi])\n\n const doiCanBeAppliedToVersion =\n objectType === DoiObjectType.ENTITY &&\n entityBundle?.entity &&\n isVersionableEntity(entityBundle.entity)\n\n const { data: entityVersions } = useGetVersions(\n objectId,\n undefined,\n undefined,\n {\n enabled: doiCanBeAppliedToVersion,\n },\n )\n const formRef = useRef<RJSF>(null)\n\n const entityType = entityBundle?.entityType ?? EntityType.file\n const entityTypeDisplay = entityTypeToFriendlyName(entityType)\n let versionHelpMarkdown = `A DOI can be associated with a specific version of this ${entityTypeDisplay}.\n \n Versioned DOIs will link to the specified version of the ${entityTypeDisplay}.\n \n A DOI without a version will always link to the newest version of this ${entityTypeDisplay},\n so the data that someone retrieves using the DOI may change over time.`\n if (entityBundle?.entity && isTable(entityBundle.entity)) {\n const tableVersionCopy = isDataset(entityBundle.entity)\n ? 'version'\n : 'snapshot'\n versionHelpMarkdown += `\\n\\nTo create a DOI that will always link to the current set of data in the ${entityTypeDisplay},\n create a new ${tableVersionCopy} and mint a DOI for that ${tableVersionCopy}.`\n }\n\n const {\n mutate: createOrUpdateDoi,\n isPending: updateIsPending,\n error: updateDoiError,\n } = useCreateOrUpdateDOI({\n onSuccess: () => {\n displayToast('The DOI was successfully updated.', 'success')\n onClose()\n },\n })\n\n const isLoading =\n updateIsPending ||\n isLoadingCurrentUser ||\n isLoadingEntity ||\n isLoadingDoi ||\n isLoadingRealmPrincipals\n\n const wasModifiedViaAPI = Boolean(doi && getWasModifiedViaAPI(doi))\n\n useEffect(() => {\n if (doi) {\n setFormData(convertDoiToFormData(doi))\n }\n // If there is no DOI, then pre-fill the form.\n if (currentUser && entityBundle?.entity && doi === null) {\n const newFormData = {\n titles: [entityBundle.entity.name],\n creators: new Array<string>(),\n resourceTypeGeneral: getSuggestedResourceTypeGeneral(\n entityBundle.entityType,\n ),\n publicationYear: new Date().getFullYear(),\n } satisfies DoiFormData\n if (currentUser.lastName && currentUser.firstName) {\n newFormData.creators.push(\n `${currentUser.lastName}, ${currentUser.firstName}`,\n )\n }\n setFormData(newFormData)\n }\n }, [currentUser, doi, entityBundle])\n\n function onSave() {\n if (formRef.current && formRef.current.validateForm()) {\n const requestDoi: V2Doi = convertFormDataToDoi(formData)\n requestDoi.objectType = objectType\n requestDoi.objectId = objectId\n requestDoi.objectVersion = selectedVersionNumber\n requestDoi.etag = doi?.etag\n requestDoi.portalId = portalId\n createOrUpdateDoi({\n doi: requestDoi,\n concreteType: 'org.sagebionetworks.repo.model.doi.v2.DoiRequest',\n })\n }\n }\n\n const dialogContent = (\n <>\n <Typography variant={'body1'} gutterBottom>\n Minting a DOI allows you to credit contributors and makes it easy to\n cite your work.\n </Typography>\n <Typography variant={'body1'} gutterBottom sx={{ mb: 2 }}>\n Note that while the DOI and its associated metadata will be publicly\n visible outside of Synapse, your data will still adhere to its existing\n access conditions. If your data is private, it will remain restricted,\n but the DOI will still be listed. Resources with DOIs may be added to\n the{' '}\n <Link\n href={`${getEndpoint(\n BackendDestinationEnum.PORTAL_ENDPOINT,\n )}${DATA_CATALOG_PATH_SEGMENT}`}\n target=\"_blank\"\n rel=\"noopener\"\n >\n Synapse Data Catalog\n </Link>\n .\n </Typography>\n {portalId && (\n <TextField\n label={'Publisher'}\n fullWidth\n value={portal?.name || ''}\n disabled\n />\n )}\n {doiCanBeAppliedToVersion && (\n <StyledFormControl className=\"limit-type\" fullWidth sx={{ my: 2 }}>\n <InputLabel\n htmlFor=\"doi-version-select\"\n sx={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n width: '100%',\n }}\n >\n <span>Version</span>\n <MarkdownPopover\n contentProps={{ markdown: versionHelpMarkdown }}\n maxWidth=\"350px\"\n >\n <HelpTwoTone className={`HelpButton`} />\n </MarkdownPopover>\n </InputLabel>\n <Select\n id=\"doi-version-select\"\n value={selectedVersionNumber ?? -1}\n onChange={e => {\n if (e.target.value === -1) {\n setSelectedVersionNumber(undefined)\n } else {\n setSelectedVersionNumber(e.target.value)\n }\n }}\n >\n <MenuItem value={-1}>No version</MenuItem>\n {entityVersions &&\n entityVersions.results.map(version => (\n <MenuItem\n key={version.versionNumber}\n value={version.versionNumber}\n >\n Version {version.versionNumber}\n {/* display the version label if it exists & is different from the number itself */}\n {version.versionLabel &&\n version.versionLabel !== String(version.versionNumber)\n ? ` / ${version.versionLabel}`\n : ''}\n </MenuItem>\n ))}\n </Select>\n </StyledFormControl>\n )}\n <div className=\"JsonSchemaFormContainer\">\n <JsonSchemaForm\n formRef={formRef}\n disabled={isLoading || wasModifiedViaAPI}\n schema={doiFormSchema}\n formData={formData}\n onChange={e => {\n setFormData(e.formData)\n }}\n uiSchema={doiFormUiSchema}\n showErrorList={false}\n />\n </div>\n {doi && (\n <Alert severity={'warning'}>\n <Typography variant={'body1'}>\n A DOI has already been created. Updating the DOI information will\n cause old information to be lost!\n </Typography>\n </Alert>\n )}\n {wasModifiedViaAPI && (\n <Alert severity={'warning'} sx={{ my: 1 }}>\n <Typography variant={'body1'}>\n The metadata for this DOI was modified using a programmatic client,\n so data may be hidden from this view. Any changes may result in\n metadata being lost.\n </Typography>\n </Alert>\n )}\n {updateDoiError && (\n <Alert severity={'error'} sx={{ mt: 1 }}>\n <Typography variant={'body1'}>{updateDoiError.message}</Typography>\n </Alert>\n )}\n </>\n )\n\n const dialogActions = (\n <>\n <Button variant=\"outlined\" disabled={isLoading} onClick={handleClose}>\n Cancel\n </Button>\n <Button\n variant=\"contained\"\n disabled={isLoading}\n onClick={\n currentStep === 'warning'\n ? () => setCurrentStep('form')\n : e => {\n // SWC-7055 - The default action may trigger `beforeunload` and erroneously warn the user about leaving the page.\n e.preventDefault()\n onSave()\n }\n }\n >\n {currentStep === 'warning' ? 'Continue' : 'Save'}\n </Button>\n </>\n )\n\n return (\n <>\n <ConfirmCloseWithoutSavingDialog\n open={showConfirmCloseModal}\n onCancel={() => {\n setShowConfirmCloseDialog(false)\n }}\n onConfirm={() => {\n setShowConfirmCloseDialog(false)\n onClose()\n }}\n />\n <DialogBase\n open={open}\n onCancel={handleClose}\n title={\n currentStep === 'warning'\n ? 'This page is private'\n : 'Create or Update a DOI'\n }\n content={\n !currentStep ? (\n <SynapseSpinner />\n ) : (\n <>\n {currentStep === 'warning' && <PrivateEntityDoiWarning />}\n {currentStep === 'form' && dialogContent}\n </>\n )\n }\n actions={dialogActions}\n />\n </>\n )\n}\n\nexport default CreateOrUpdateDoiModal\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CreateOrUpdateDoiModal.js","names":[],"sources":["../../../src/components/doi/CreateOrUpdateDoiModal.tsx"],"sourcesContent":["import ConfirmCloseWithoutSavingDialog from '@/components/Dialog/ConfirmCloseWithoutSavingDialog'\nimport { DialogBase } from '@/components/DialogBase'\nimport { doiFormSchema, doiFormUiSchema } from '@/components/doi/DoiFormSchemas'\nimport { PrivateEntityDoiWarning } from '@/components/doi/PrivateEntityDoiWarning'\nimport { JsonSchemaForm } from '@/components/JsonSchemaForm/JsonSchemaForm'\nimport { MarkdownPopover } from '@/components/Markdown/MarkdownPopover'\nimport { StyledFormControl } from '@/components/styled/StyledFormControl'\nimport { displayToast } from '@/components/ToastMessage/ToastMessage'\nimport { useCreateOrUpdateDOI, useGetDOI } from '@/synapse-queries/doi/useDOI'\nimport { useGetVersions } from '@/synapse-queries/entity/useEntity'\nimport { useGetEntityBundle } from '@/synapse-queries/entity/useEntityBundle'\nimport { useGetPortal } from '@/synapse-queries/portal/usePortal'\nimport { useGetRealmPrincipals } from '@/synapse-queries/realm/useRealmPrincipals'\nimport { useGetCurrentUserProfile } from '@/synapse-queries/user/useUserBundle'\nimport { useGlobalIsEditingContext } from '@/utils/context/GlobalIsEditingContext'\nimport { isEntityPublic } from '@/utils/functions/AccessControlListUtils'\nimport {\n entityTypeToFriendlyName,\n isDataset,\n isTable,\n isVersionableEntity,\n} from '@/utils/functions/EntityTypeUtils'\nimport {\n BackendDestinationEnum,\n getEndpoint,\n} from '@/utils/functions/getEndpoint'\nimport { DATA_CATALOG_PATH_SEGMENT } from '@/utils/SynapseConstants'\nimport { HelpTwoTone } from '@mui/icons-material'\nimport {\n Alert,\n Button,\n InputLabel,\n Link,\n MenuItem,\n Select,\n TextField,\n Typography,\n} from '@mui/material'\nimport RJSF from '@rjsf/core'\nimport {\n DoiObjectType,\n DoiResourceTypeGeneral,\n DoiResourceTypeResourceTypeGeneralEnum,\n EntityType,\n V2Doi,\n} from '@sage-bionetworks/synapse-client'\nimport { isEmpty } from 'lodash-es'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport { SynapseSpinner } from '../LoadingScreen/LoadingScreen'\n\ntype CreateOrUpdateDoiModalStep = 'warning' | 'form'\n\nexport type CreateOrUpdateDoiModalProps = {\n /** Whether the dialog is open */\n open: boolean\n /** Callback to call when the dialog is closed */\n onClose: () => void\n /** The type of object */\n objectType: DoiObjectType\n /** The ID of the object */\n objectId: string\n /** The optional version number of the object used to populate the form. */\n defaultVersionNumber?: number\n /** If minting a DOI for a portal, the ID of the portal object in Synapse */\n portalId?: string\n}\n\ntype DoiFormData = {\n titles?: string[]\n creators?: string[]\n resourceTypeGeneral?: DoiResourceTypeResourceTypeGeneralEnum\n publicationYear?: number\n}\n\nfunction getSuggestedResourceTypeGeneral(\n type: EntityType,\n): DoiResourceTypeGeneral {\n if (type === EntityType.project || type === EntityType.folder) {\n return DoiResourceTypeGeneral.Collection\n } else {\n return DoiResourceTypeGeneral.Dataset\n }\n}\n\nfunction convertDoiToFormData(doi: V2Doi): DoiFormData {\n return {\n titles: (doi.titles || []).map(title => title.title!),\n creators: (doi.creators || []).map(creator => creator.creatorName!),\n resourceTypeGeneral: doi.resourceType?.resourceTypeGeneral,\n publicationYear: doi.publicationYear,\n }\n}\n\n/**\n * Returns true if the DOI has fields that are not exposed in the UI, so we can let the user know that any changes\n * may be destructive to hidden fields.\n */\nfunction getWasModifiedViaAPI(doi: V2Doi) {\n if (doi.creators?.some(creator => !isEmpty(creator.nameIdentifiers))) {\n return true\n }\n return false\n}\n\nfunction convertFormDataToDoi(formData: DoiFormData): V2Doi {\n return {\n titles: formData.titles?.map(title => ({ title })) || [],\n creators:\n formData.creators?.map(creator => ({ creatorName: creator })) || [],\n resourceType: {\n resourceTypeGeneral: formData.resourceTypeGeneral,\n },\n publicationYear: formData.publicationYear,\n }\n}\n\nexport function CreateOrUpdateDoiModal(props: CreateOrUpdateDoiModalProps) {\n const {\n open,\n onClose,\n objectType,\n objectId,\n defaultVersionNumber,\n portalId,\n } = props\n\n const [showConfirmCloseModal, setShowConfirmCloseDialog] = useState(false)\n const [currentStep, setCurrentStep] =\n useState<CreateOrUpdateDoiModalStep | null>(null)\n const hasSetInitialStepForThisSession = useRef(false)\n const { isEditing, setIsEditing } = useGlobalIsEditingContext()\n useEffect(() => {\n setIsEditing(open)\n\n return () => {\n setIsEditing(false)\n }\n }, [open, setIsEditing])\n\n function handleClose() {\n if (isEditing) {\n setShowConfirmCloseDialog(true)\n } else {\n onClose()\n }\n }\n\n const [selectedVersionNumber, setSelectedVersionNumber] =\n useState(defaultVersionNumber)\n\n const { data: portal } = useGetPortal(portalId!, {\n enabled: Boolean(portalId),\n })\n\n const [formData, setFormData] = useState<DoiFormData>({\n titles: [''],\n creators: [''],\n })\n const { data: currentUser, isLoading: isLoadingCurrentUser } =\n useGetCurrentUserProfile()\n const { data: entityBundle, isLoading: isLoadingEntity } = useGetEntityBundle(\n objectId,\n selectedVersionNumber,\n {\n includeEntity: true,\n includeBenefactorACL: true,\n },\n {\n enabled: objectType === DoiObjectType.ENTITY,\n staleTime: Infinity,\n throwOnError: true,\n },\n )\n const { data: realmPrincipals, isLoading: isLoadingRealmPrincipals } =\n useGetRealmPrincipals()\n const { data: doi, isLoading: isLoadingDoi } = useGetDOI(\n {\n id: objectId,\n version: selectedVersionNumber,\n type: objectType,\n portalId: portalId,\n },\n {\n staleTime: Infinity,\n throwOnError: true,\n },\n )\n\n const shouldShowWarning = useMemo(() => {\n return (\n open &&\n doi === null && // Creating new DOI\n entityBundle?.benefactorAcl &&\n realmPrincipals &&\n !isEntityPublic(\n entityBundle.benefactorAcl.resourceAccess,\n realmPrincipals,\n )\n )\n }, [open, doi, entityBundle, realmPrincipals])\n\n useEffect(() => {\n if (\n open &&\n !hasSetInitialStepForThisSession.current &&\n doi !== undefined && // Wait for DOI query to resolve before determining step\n shouldShowWarning !== undefined\n ) {\n const newStep = shouldShowWarning ? 'warning' : 'form'\n setCurrentStep(newStep)\n hasSetInitialStepForThisSession.current = true\n } else if (!open) {\n setCurrentStep(null)\n hasSetInitialStepForThisSession.current = false\n }\n }, [shouldShowWarning, open, doi])\n\n const doiCanBeAppliedToVersion =\n objectType === DoiObjectType.ENTITY &&\n entityBundle?.entity &&\n isVersionableEntity(entityBundle.entity)\n\n const { data: entityVersions } = useGetVersions(\n objectId,\n undefined,\n undefined,\n {\n enabled: doiCanBeAppliedToVersion,\n },\n )\n const formRef = useRef<RJSF>(null)\n\n const entityType = entityBundle?.entityType ?? EntityType.file\n const entityTypeDisplay = entityTypeToFriendlyName(entityType)\n let versionHelpMarkdown = `A DOI can be associated with a specific version of this ${entityTypeDisplay}.\n \n Versioned DOIs will link to the specified version of the ${entityTypeDisplay}.\n \n A DOI without a version will always link to the newest version of this ${entityTypeDisplay},\n so the data that someone retrieves using the DOI may change over time.`\n if (entityBundle?.entity && isTable(entityBundle.entity)) {\n const tableVersionCopy = isDataset(entityBundle.entity)\n ? 'version'\n : 'snapshot'\n versionHelpMarkdown += `\\n\\nTo create a DOI that will always link to the current set of data in the ${entityTypeDisplay},\n create a new ${tableVersionCopy} and mint a DOI for that ${tableVersionCopy}.`\n }\n\n const {\n mutate: createOrUpdateDoi,\n isPending: updateIsPending,\n error: updateDoiError,\n } = useCreateOrUpdateDOI({\n onSuccess: () => {\n displayToast('The DOI was successfully updated.', 'success')\n onClose()\n },\n })\n\n const isLoading =\n updateIsPending ||\n isLoadingCurrentUser ||\n isLoadingEntity ||\n isLoadingDoi ||\n isLoadingRealmPrincipals\n\n const wasModifiedViaAPI = Boolean(doi && getWasModifiedViaAPI(doi))\n\n useEffect(() => {\n if (doi) {\n setFormData(convertDoiToFormData(doi))\n }\n // If there is no DOI, then pre-fill the form.\n if (currentUser && entityBundle?.entity && doi === null) {\n const newFormData = {\n titles: [entityBundle.entity.name],\n creators: new Array<string>(),\n resourceTypeGeneral: getSuggestedResourceTypeGeneral(\n entityBundle.entityType,\n ),\n publicationYear: new Date().getFullYear(),\n } satisfies DoiFormData\n if (currentUser.lastName && currentUser.firstName) {\n newFormData.creators.push(\n `${currentUser.lastName}, ${currentUser.firstName}`,\n )\n }\n setFormData(newFormData)\n }\n }, [currentUser, doi, entityBundle])\n\n function onSave() {\n if (formRef.current && formRef.current.validateForm()) {\n const requestDoi: V2Doi = convertFormDataToDoi(formData)\n requestDoi.objectType = objectType\n requestDoi.objectId = objectId\n requestDoi.objectVersion = selectedVersionNumber\n requestDoi.etag = doi?.etag\n requestDoi.portalId = portalId\n createOrUpdateDoi({\n doi: requestDoi,\n concreteType: 'org.sagebionetworks.repo.model.doi.v2.DoiRequest',\n })\n }\n }\n\n const dialogContent = (\n <>\n <Typography variant={'body1'} gutterBottom>\n Minting a DOI allows you to credit contributors and makes it easy to\n cite your work.\n </Typography>\n <Typography variant={'body1'} gutterBottom sx={{ mb: 2 }}>\n Note that while the DOI and its associated metadata will be publicly\n visible outside of Synapse, your data will still adhere to its existing\n access conditions. If your data is private, it will remain restricted,\n but the DOI will still be listed. Resources with DOIs may be added to\n the{' '}\n <Link\n href={`${getEndpoint(\n BackendDestinationEnum.PORTAL_ENDPOINT,\n )}${DATA_CATALOG_PATH_SEGMENT}`}\n target=\"_blank\"\n rel=\"noopener\"\n >\n Synapse Data Catalog\n </Link>\n .\n </Typography>\n {portalId && (\n <TextField\n label={'Publisher'}\n fullWidth\n value={portal?.name || ''}\n disabled\n />\n )}\n {doiCanBeAppliedToVersion && (\n <StyledFormControl className=\"limit-type\" fullWidth sx={{ my: 2 }}>\n <InputLabel\n htmlFor=\"doi-version-select\"\n sx={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n width: '100%',\n }}\n >\n <span>Version</span>\n <MarkdownPopover\n contentProps={{ markdown: versionHelpMarkdown }}\n maxWidth=\"350px\"\n >\n <HelpTwoTone className={`HelpButton`} />\n </MarkdownPopover>\n </InputLabel>\n <Select\n id=\"doi-version-select\"\n value={selectedVersionNumber ?? -1}\n onChange={e => {\n if (e.target.value === -1) {\n setSelectedVersionNumber(undefined)\n } else {\n setSelectedVersionNumber(e.target.value)\n }\n }}\n >\n <MenuItem value={-1}>No version</MenuItem>\n {entityVersions &&\n entityVersions.results.map(version => (\n <MenuItem\n key={version.versionNumber}\n value={version.versionNumber}\n >\n Version {version.versionNumber}\n {/* display the version label if it exists & is different from the number itself */}\n {version.versionLabel &&\n version.versionLabel !== String(version.versionNumber)\n ? ` / ${version.versionLabel}`\n : ''}\n </MenuItem>\n ))}\n </Select>\n </StyledFormControl>\n )}\n <div className=\"JsonSchemaFormContainer\">\n <JsonSchemaForm\n formRef={formRef}\n disabled={isLoading || wasModifiedViaAPI}\n schema={doiFormSchema}\n formData={formData}\n onChange={e => {\n setFormData(e.formData)\n }}\n uiSchema={doiFormUiSchema}\n showErrorList={false}\n />\n </div>\n {doi && (\n <Alert severity={'warning'}>\n <Typography variant={'body1'}>\n A DOI has already been created. Updating the DOI information will\n cause old information to be lost!\n </Typography>\n </Alert>\n )}\n {wasModifiedViaAPI && (\n <Alert severity={'warning'} sx={{ my: 1 }}>\n <Typography variant={'body1'}>\n The metadata for this DOI was modified using a programmatic client,\n so data may be hidden from this view. Any changes may result in\n metadata being lost.\n </Typography>\n </Alert>\n )}\n {updateDoiError && (\n <Alert severity={'error'} sx={{ mt: 1 }}>\n <Typography variant={'body1'}>{updateDoiError.message}</Typography>\n </Alert>\n )}\n </>\n )\n\n const dialogActions = (\n <>\n <Button variant=\"outlined\" disabled={isLoading} onClick={handleClose}>\n Cancel\n </Button>\n <Button\n variant=\"contained\"\n disabled={isLoading}\n onClick={\n currentStep === 'warning'\n ? () => setCurrentStep('form')\n : e => {\n // SWC-7055 - The default action may trigger `beforeunload` and erroneously warn the user about leaving the page.\n e.preventDefault()\n onSave()\n }\n }\n >\n {currentStep === 'warning' ? 'Continue' : 'Save'}\n </Button>\n </>\n )\n\n return (\n <>\n <ConfirmCloseWithoutSavingDialog\n open={showConfirmCloseModal}\n onCancel={() => {\n setShowConfirmCloseDialog(false)\n }}\n onConfirm={() => {\n setShowConfirmCloseDialog(false)\n onClose()\n }}\n />\n <DialogBase\n open={open}\n onCancel={handleClose}\n title={\n currentStep === 'warning'\n ? 'This page is private'\n : 'Create or Update a DOI'\n }\n content={\n !currentStep ? (\n <SynapseSpinner />\n ) : (\n <>\n {currentStep === 'warning' && <PrivateEntityDoiWarning />}\n {currentStep === 'form' && dialogContent}\n </>\n )\n }\n actions={dialogActions}\n />\n </>\n )\n}\n\nexport default CreateOrUpdateDoiModal\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreatedByModifiedBy.js","names":[],"sources":["../../../../src/components/entity/page/CreatedByModifiedBy.tsx"],"sourcesContent":["import ConditionalWrapper from '@/components/utils/ConditionalWrapper'\nimport {\n useGetEntity,\n useGetQueryResultBundleWithAsyncStatus,\n} from '@/synapse-queries'\nimport { formatDate } from '@/utils/functions/DateFormatter'\nimport {\n convertToEntityType,\n entityTypeToFriendlyName,\n isDataset,\n isTable,\n} from '@/utils/functions/EntityTypeUtils'\nimport { BUNDLE_MASK_LAST_UPDATED_ON } from '@/utils/SynapseConstants'\nimport { InfoTwoTone } from '@mui/icons-material'\nimport {\n Box,\n Breadcrumbs,\n Skeleton,\n SxProps,\n Tooltip,\n Typography,\n useMediaQuery,\n useTheme,\n} from '@mui/material'\nimport dayjs from 'dayjs'\nimport { UserBadge } from '../../UserCard/UserBadge'\n\nexport type CreatedByModifiedByProps = {\n entityId: string\n versionNumber?: number\n}\n\nfunction Separator() {\n const theme = useTheme()\n const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm'))\n if (isSmallScreen) {\n return null\n }\n return (\n <Typography variant={'breadcrumb1'} sx={{ color: 'grey.700' }}>\n /\n </Typography>\n )\n}\n\nexport function CreatedByModifiedBy(props: CreatedByModifiedByProps) {\n const { entityId, versionNumber } = props\n const entityIdWithVersion = `${entityId}${\n versionNumber ? `.${versionNumber}` : ''\n }`\n\n const { data: entity } = useGetEntity(entityId, versionNumber)\n\n const { data: tableQueryResult } = useGetQueryResultBundleWithAsyncStatus(\n {\n entityId,\n query: {\n sql: `SELECT * FROM ${entityIdWithVersion} LIMIT 0`,\n },\n partMask: BUNDLE_MASK_LAST_UPDATED_ON,\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n },\n { enabled: !!(entity && isTable(entity)) },\n )\n\n const tableLastRebuilt = tableQueryResult?.responseBody?.lastUpdatedOn\n const friendlyName = entity\n ? entityTypeToFriendlyName(convertToEntityType(entity.concreteType))\n : ''\n\n const datasetCreatedByTooltipText =\n 'This is the user who created this Dataset. ' +\n 'This may not be the same person who generated the files in this Dataset, or who originally uploaded these files to Synapse.'\n\n const tableModifiedOnTooltipText = (\n <>\n <p>\n This is when the configuration of this {friendlyName} was last changed.\n </p>\n <p>Configuration changes may be triggered by (for example):</p>\n <ul>\n <li>Editing the name of the {friendlyName}</li>\n <li>Updating the schema used by the {friendlyName}</li>\n </ul>\n <p>\n This does NOT reflect changes to the data displayed in the the{' '}\n {friendlyName}.\n </p>\n </>\n )\n /*\n If the tooltip text is a string, MUI automatically applies it to aria-label which is more accessible and testable.\n Since this tooltip text is a ReactNode, let's manually create a short string to use for the aria-label.\n */\n const tableModifiedOnAccessibleLabel = `This is when the configuration of this ${friendlyName} was last changed.`\n\n const tableLastUpdatedTooltipText =\n `When data changes, the ${friendlyName} is rebuilt to reflect those changes. ` +\n `This is the last time changes were made to the data.`\n\n const createdByTooltipId = `${entityIdWithVersion}-createdByTooltip`\n const modifiedByTooltipId = `${entityIdWithVersion}-modifiedByTooltip`\n const lastUpdatedTooltipId = `${entityIdWithVersion}-lastUpdatedTooltip`\n\n const iconSx: SxProps = {\n width: '16px',\n height: '16px',\n ml: '4px',\n verticalAlign: 'text-bottom',\n }\n\n return (\n <Box\n sx={theme => ({\n bgcolor: 'grey.100',\n py: '10px',\n [theme.breakpoints.down('sm')]: {\n p: '24px 40px',\n },\n })}\n >\n <Breadcrumbs\n separator={<Separator />}\n sx={theme => ({\n '& .MuiBreadcrumbs-ol': {\n justifyContent: 'center',\n [theme.breakpoints.down('sm')]: {\n gap: '4px',\n },\n },\n })}\n >\n <ConditionalWrapper condition={!entity} wrapper={Skeleton}>\n <Typography\n sx={{ color: 'grey.700' }}\n variant={'breadcrumb1'}\n aria-describedby={createdByTooltipId}\n >\n {friendlyName} created by <UserBadge userId={entity?.createdBy} />{' '}\n on {formatDate(dayjs(entity?.createdOn))}\n {entity && isDataset(entity) && (\n <Tooltip\n id={createdByTooltipId}\n title={datasetCreatedByTooltipText}\n >\n <InfoTwoTone sx={iconSx} />\n </Tooltip>\n )}\n </Typography>\n </ConditionalWrapper>\n <ConditionalWrapper condition={!entity} wrapper={Skeleton}>\n <Typography\n sx={{ color: 'grey.700' }}\n variant={'breadcrumb1'}\n aria-describedby={modifiedByTooltipId}\n >\n {entity && isTable(entity) ? 'Configuration' : friendlyName} last\n modified by <UserBadge userId={entity?.modifiedBy} /> on{' '}\n {formatDate(dayjs(entity?.modifiedOn))}\n {entity && isTable(entity) && (\n <Tooltip\n id={modifiedByTooltipId}\n title={tableModifiedOnTooltipText}\n aria-label={tableModifiedOnAccessibleLabel}\n >\n <InfoTwoTone sx={iconSx} />\n </Tooltip>\n )}\n </Typography>\n </ConditionalWrapper>\n {tableLastRebuilt && (\n <Typography\n sx={{ color: 'grey.700' }}\n variant={'breadcrumb1'}\n aria-describedby={lastUpdatedTooltipId}\n >\n {friendlyName} last rebuilt on {formatDate(dayjs(tableLastRebuilt))}\n <Tooltip\n title={tableLastUpdatedTooltipText}\n id={lastUpdatedTooltipId}\n >\n <InfoTwoTone sx={iconSx} />\n </Tooltip>\n </Typography>\n )}\n </Breadcrumbs>\n </Box>\n )\n}\n\nexport default CreatedByModifiedBy\n"],"mappings":";;;;;;;;;;;;;AAgCA,SAAS,IAAY;AAMnB,QAJsB,EADR,
|
|
1
|
+
{"version":3,"file":"CreatedByModifiedBy.js","names":[],"sources":["../../../../src/components/entity/page/CreatedByModifiedBy.tsx"],"sourcesContent":["import ConditionalWrapper from '@/components/utils/ConditionalWrapper'\nimport {\n useGetEntity,\n useGetQueryResultBundleWithAsyncStatus,\n} from '@/synapse-queries'\nimport { formatDate } from '@/utils/functions/DateFormatter'\nimport {\n convertToEntityType,\n entityTypeToFriendlyName,\n isDataset,\n isTable,\n} from '@/utils/functions/EntityTypeUtils'\nimport { BUNDLE_MASK_LAST_UPDATED_ON } from '@/utils/SynapseConstants'\nimport { InfoTwoTone } from '@mui/icons-material'\nimport {\n Box,\n Breadcrumbs,\n Skeleton,\n SxProps,\n Tooltip,\n Typography,\n useMediaQuery,\n useTheme,\n} from '@mui/material'\nimport dayjs from 'dayjs'\nimport { UserBadge } from '../../UserCard/UserBadge'\n\nexport type CreatedByModifiedByProps = {\n entityId: string\n versionNumber?: number\n}\n\nfunction Separator() {\n const theme = useTheme()\n const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm'))\n if (isSmallScreen) {\n return null\n }\n return (\n <Typography variant={'breadcrumb1'} sx={{ color: 'grey.700' }}>\n /\n </Typography>\n )\n}\n\nexport function CreatedByModifiedBy(props: CreatedByModifiedByProps) {\n const { entityId, versionNumber } = props\n const entityIdWithVersion = `${entityId}${\n versionNumber ? `.${versionNumber}` : ''\n }`\n\n const { data: entity } = useGetEntity(entityId, versionNumber)\n\n const { data: tableQueryResult } = useGetQueryResultBundleWithAsyncStatus(\n {\n entityId,\n query: {\n sql: `SELECT * FROM ${entityIdWithVersion} LIMIT 0`,\n },\n partMask: BUNDLE_MASK_LAST_UPDATED_ON,\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n },\n { enabled: !!(entity && isTable(entity)) },\n )\n\n const tableLastRebuilt = tableQueryResult?.responseBody?.lastUpdatedOn\n const friendlyName = entity\n ? entityTypeToFriendlyName(convertToEntityType(entity.concreteType))\n : ''\n\n const datasetCreatedByTooltipText =\n 'This is the user who created this Dataset. ' +\n 'This may not be the same person who generated the files in this Dataset, or who originally uploaded these files to Synapse.'\n\n const tableModifiedOnTooltipText = (\n <>\n <p>\n This is when the configuration of this {friendlyName} was last changed.\n </p>\n <p>Configuration changes may be triggered by (for example):</p>\n <ul>\n <li>Editing the name of the {friendlyName}</li>\n <li>Updating the schema used by the {friendlyName}</li>\n </ul>\n <p>\n This does NOT reflect changes to the data displayed in the the{' '}\n {friendlyName}.\n </p>\n </>\n )\n /*\n If the tooltip text is a string, MUI automatically applies it to aria-label which is more accessible and testable.\n Since this tooltip text is a ReactNode, let's manually create a short string to use for the aria-label.\n */\n const tableModifiedOnAccessibleLabel = `This is when the configuration of this ${friendlyName} was last changed.`\n\n const tableLastUpdatedTooltipText =\n `When data changes, the ${friendlyName} is rebuilt to reflect those changes. ` +\n `This is the last time changes were made to the data.`\n\n const createdByTooltipId = `${entityIdWithVersion}-createdByTooltip`\n const modifiedByTooltipId = `${entityIdWithVersion}-modifiedByTooltip`\n const lastUpdatedTooltipId = `${entityIdWithVersion}-lastUpdatedTooltip`\n\n const iconSx: SxProps = {\n width: '16px',\n height: '16px',\n ml: '4px',\n verticalAlign: 'text-bottom',\n }\n\n return (\n <Box\n sx={theme => ({\n bgcolor: 'grey.100',\n py: '10px',\n [theme.breakpoints.down('sm')]: {\n p: '24px 40px',\n },\n })}\n >\n <Breadcrumbs\n separator={<Separator />}\n sx={theme => ({\n '& .MuiBreadcrumbs-ol': {\n justifyContent: 'center',\n [theme.breakpoints.down('sm')]: {\n gap: '4px',\n },\n },\n })}\n >\n <ConditionalWrapper condition={!entity} wrapper={Skeleton}>\n <Typography\n sx={{ color: 'grey.700' }}\n variant={'breadcrumb1'}\n aria-describedby={createdByTooltipId}\n >\n {friendlyName} created by <UserBadge userId={entity?.createdBy} />{' '}\n on {formatDate(dayjs(entity?.createdOn))}\n {entity && isDataset(entity) && (\n <Tooltip\n id={createdByTooltipId}\n title={datasetCreatedByTooltipText}\n >\n <InfoTwoTone sx={iconSx} />\n </Tooltip>\n )}\n </Typography>\n </ConditionalWrapper>\n <ConditionalWrapper condition={!entity} wrapper={Skeleton}>\n <Typography\n sx={{ color: 'grey.700' }}\n variant={'breadcrumb1'}\n aria-describedby={modifiedByTooltipId}\n >\n {entity && isTable(entity) ? 'Configuration' : friendlyName} last\n modified by <UserBadge userId={entity?.modifiedBy} /> on{' '}\n {formatDate(dayjs(entity?.modifiedOn))}\n {entity && isTable(entity) && (\n <Tooltip\n id={modifiedByTooltipId}\n title={tableModifiedOnTooltipText}\n aria-label={tableModifiedOnAccessibleLabel}\n >\n <InfoTwoTone sx={iconSx} />\n </Tooltip>\n )}\n </Typography>\n </ConditionalWrapper>\n {tableLastRebuilt && (\n <Typography\n sx={{ color: 'grey.700' }}\n variant={'breadcrumb1'}\n aria-describedby={lastUpdatedTooltipId}\n >\n {friendlyName} last rebuilt on {formatDate(dayjs(tableLastRebuilt))}\n <Tooltip\n title={tableLastUpdatedTooltipText}\n id={lastUpdatedTooltipId}\n >\n <InfoTwoTone sx={iconSx} />\n </Tooltip>\n </Typography>\n )}\n </Breadcrumbs>\n </Box>\n )\n}\n\nexport default CreatedByModifiedBy\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityActionMenu.js","names":[],"sources":["../../../../../src/components/entity/page/action_menu/EntityActionMenu.tsx"],"sourcesContent":["import { SxProps } from '@mui/material'\nimport { ComplexMenu } from '../../../menu/ComplexMenu'\nimport IconSvg, { IconName } from '../../../IconSvg/IconSvg'\nimport { DropdownMenuItem, DropdownMenuProps } from '../../../menu/DropdownMenu'\nimport { IconSvgButtonProps } from '../../../IconSvgButton'\nimport { MouseEvent } from 'react'\n\n// Represents the two types of dropdown menus that will be displayed on the entity page\ntype EntityActionMenuDropdownMenuType = 'DOWNLOAD' | 'PRIMARY'\n\ntype EntityActionMenuDropdownMenuConfiguration = {\n visible: boolean\n tooltipText?: string\n disabled?: boolean\n}\n\nexport type ActionConfiguration = {\n visible: boolean\n text: string\n disabled?: boolean\n tooltipText?: string\n onClick?: (e: MouseEvent) => void\n href?: string\n}\n\nexport type ActionConfigurationMap = Record<string, ActionConfiguration>\n\nexport type MenuConfigurationMap = Record<\n EntityActionMenuDropdownMenuType,\n EntityActionMenuDropdownMenuConfiguration\n>\n\nexport type ActionViewProps = {\n action: string\n icon?: IconName\n textSx?: SxProps\n iconSx?: SxProps\n}\n\nexport type EntityActionMenuLayout = {\n buttonActions: ActionViewProps[]\n downloadMenuActions: ActionViewProps[][]\n primaryMenuActions: ActionViewProps[][]\n primaryMenuText: string\n primaryMenuEndIcon: IconName\n menuButtonSx?: SxProps\n}\n\nexport type EntityActionMenuProps = {\n /* Maps a unique action string to a dynamic configuration for that particular action */\n actionConfiguration: ActionConfigurationMap\n /* Maps each dropdown menu to a dynamic configuration for that particular menu */\n menuConfiguration: MenuConfigurationMap\n /* Defines the layout of the actions. Typically depends on just the entity type and area. */\n layout: EntityActionMenuLayout\n}\n\n/*\n * All visible actions should be specified in the layout, but this is not guaranteed at compile time.\n * Find all visible actions in the action configuration that are not in the layout.\n */\nfunction getUnmappedActions(\n actionConfiguration: ActionConfigurationMap,\n layout: EntityActionMenuLayout,\n): ActionConfigurationMap {\n return Object.fromEntries(\n Object.entries(actionConfiguration).filter(([action, config]) => {\n // We don't care about actions that are not configured or should not be visible\n if (!config || !config.visible) {\n return false\n }\n\n const allLayoutActions: ActionViewProps[] = [\n ...layout.buttonActions,\n ...layout.primaryMenuActions.flat(),\n ...layout.downloadMenuActions.flat(),\n ]\n // Action is unmapped if it's visible and the layout doesn't have it\n return !allLayoutActions.some(\n layoutAction => layoutAction.action === action,\n )\n }),\n )\n}\n\n/**\n * Given a group of dropdown menu items and an action configuration,\n * return a list of dropdown menu items with non-visible and non-configured actions removed.\n * @param group\n * @param actionConfiguration\n */\nfunction mapAndFilterItemsInMenuGroup(\n group: ActionViewProps[],\n actionConfiguration: ActionConfigurationMap,\n): DropdownMenuItem[] {\n return group.reduce(\n (itemAcc: DropdownMenuItem[], actionViewProps: ActionViewProps) => {\n const configForAction = actionConfiguration[actionViewProps.action]\n // Only show the item if it's configured + visible\n if (configForAction && configForAction.visible) {\n itemAcc.push({\n text: configForAction.text ?? actionViewProps.action,\n onClick: configForAction.onClick,\n href: configForAction.href,\n tooltipText: configForAction.tooltipText,\n disabled: configForAction.disabled,\n icon: actionViewProps.icon,\n textSx: actionViewProps.textSx,\n iconSx: actionViewProps.iconSx,\n })\n }\n return itemAcc\n },\n [],\n )\n}\n\n/**\n * Given a list of groups of dropdown menu actions, returns a list of dropdown menu item\n * groups where non-visible actions have been removed, and groups with no visible actions\n * have been removed.\n * @param menuActions\n * @param actionConfiguration\n */\nfunction mapAndFilterMenuGroups(\n menuActions: ActionViewProps[][],\n actionConfiguration: ActionConfigurationMap,\n): DropdownMenuItem[][] {\n return menuActions.reduce(\n (groupAcc: DropdownMenuItem[][], group: ActionViewProps[]) => {\n const itemGroup = mapAndFilterItemsInMenuGroup(group, actionConfiguration)\n // Only show the group if it contains visible items\n if (itemGroup.length > 0) {\n groupAcc.push(itemGroup)\n }\n return groupAcc\n },\n [],\n )\n}\n\n/**\n * The EntityActionMenu renders a menu that displays the actions that can be invoked on an Entity page.\n */\nexport default function EntityActionMenu(props: EntityActionMenuProps) {\n const { actionConfiguration, menuConfiguration, layout } = props\n\n /*\n * All actions should be specified in the layout, but this is not guaranteed at compile time.\n * Find all visible actions in the action configuration that are not in the layout.\n */\n const unmappedActions = getUnmappedActions(actionConfiguration, layout)\n // Warn if unmapped actions were found and push them on to the layout.\n if (Object.entries(unmappedActions).length > 0) {\n console.warn(\n 'Actions are visible but have not been configured in the layout:',\n Object.entries(unmappedActions).map(entry => entry[0]),\n )\n // Modify the layout: put the unmapped actions in their own group at the top of the menu\n layout.primaryMenuActions.unshift(\n Object.entries(unmappedActions).map(\n (entry): ActionViewProps => ({\n action: entry[0],\n }),\n ),\n )\n }\n\n // Map button actions to an IconButtonConfiguration and omit non-visible actions\n const iconButtonConfigs: IconSvgButtonProps[] = layout.buttonActions.reduce(\n (acc: IconSvgButtonProps[], buttonViewProps: ActionViewProps) => {\n const configForAction = actionConfiguration[buttonViewProps.action]\n if (configForAction && configForAction.visible) {\n let onClick = configForAction.onClick\n if (onClick == null && !configForAction.href) {\n console.warn(`No handler registered for ${buttonViewProps.action}`)\n onClick = () => {\n console.warn(`No handler registered for ${buttonViewProps.action}`)\n }\n }\n acc.push({\n icon: buttonViewProps.icon as IconName,\n onClick: onClick,\n tooltipText: configForAction.text,\n disabled: configForAction.disabled,\n href: configForAction.href,\n })\n }\n return acc\n },\n [],\n )\n\n const downloadMenuConfig: DropdownMenuProps = {\n dropdownButtonText: 'Download Options',\n convertSingleItemToButton: true,\n renderMenuIfNoItems: false,\n buttonTooltip: menuConfiguration.DOWNLOAD.tooltipText,\n buttonProps: {\n disabled: menuConfiguration.DOWNLOAD.disabled,\n endIcon: <IconSvg icon={'download'} wrap={false} />,\n },\n items: mapAndFilterMenuGroups(\n layout.downloadMenuActions,\n actionConfiguration,\n ),\n }\n\n const primaryMenuConfig: DropdownMenuProps = {\n dropdownButtonText: layout.primaryMenuText,\n convertSingleItemToButton: true,\n renderMenuIfNoItems: false,\n buttonProps: {\n endIcon: <IconSvg icon={layout.primaryMenuEndIcon} wrap={false} />,\n },\n items: mapAndFilterMenuGroups(\n layout.primaryMenuActions,\n actionConfiguration,\n ),\n }\n\n return (\n <ComplexMenu\n iconButtons={iconButtonConfigs}\n dropdownMenus={[downloadMenuConfig, primaryMenuConfig]}\n />\n )\n}\n\nexport const EXPORTED_FOR_UNIT_TESTING = {\n getUnmappedActions,\n mapAndFilterItemsInMenuGroup,\n mapAndFilterMenuGroups,\n}\n"],"mappings":";;;;AA6DA,SAAS,EACP,GACA,GACwB;AACxB,QAAO,OAAO,YACZ,OAAO,QAAQ,EAAoB,CAAC,QAAQ,CAAC,GAAQ,OAE/C,CAAC,KAAU,CAAC,EAAO,UACd,KASF,
|
|
1
|
+
{"version":3,"file":"EntityActionMenu.js","names":[],"sources":["../../../../../src/components/entity/page/action_menu/EntityActionMenu.tsx"],"sourcesContent":["import { SxProps } from '@mui/material'\nimport { ComplexMenu } from '../../../menu/ComplexMenu'\nimport IconSvg, { IconName } from '../../../IconSvg/IconSvg'\nimport { DropdownMenuItem, DropdownMenuProps } from '../../../menu/DropdownMenu'\nimport { IconSvgButtonProps } from '../../../IconSvgButton'\nimport { MouseEvent } from 'react'\n\n// Represents the two types of dropdown menus that will be displayed on the entity page\ntype EntityActionMenuDropdownMenuType = 'DOWNLOAD' | 'PRIMARY'\n\ntype EntityActionMenuDropdownMenuConfiguration = {\n visible: boolean\n tooltipText?: string\n disabled?: boolean\n}\n\nexport type ActionConfiguration = {\n visible: boolean\n text: string\n disabled?: boolean\n tooltipText?: string\n onClick?: (e: MouseEvent) => void\n href?: string\n}\n\nexport type ActionConfigurationMap = Record<string, ActionConfiguration>\n\nexport type MenuConfigurationMap = Record<\n EntityActionMenuDropdownMenuType,\n EntityActionMenuDropdownMenuConfiguration\n>\n\nexport type ActionViewProps = {\n action: string\n icon?: IconName\n textSx?: SxProps\n iconSx?: SxProps\n}\n\nexport type EntityActionMenuLayout = {\n buttonActions: ActionViewProps[]\n downloadMenuActions: ActionViewProps[][]\n primaryMenuActions: ActionViewProps[][]\n primaryMenuText: string\n primaryMenuEndIcon: IconName\n menuButtonSx?: SxProps\n}\n\nexport type EntityActionMenuProps = {\n /* Maps a unique action string to a dynamic configuration for that particular action */\n actionConfiguration: ActionConfigurationMap\n /* Maps each dropdown menu to a dynamic configuration for that particular menu */\n menuConfiguration: MenuConfigurationMap\n /* Defines the layout of the actions. Typically depends on just the entity type and area. */\n layout: EntityActionMenuLayout\n}\n\n/*\n * All visible actions should be specified in the layout, but this is not guaranteed at compile time.\n * Find all visible actions in the action configuration that are not in the layout.\n */\nfunction getUnmappedActions(\n actionConfiguration: ActionConfigurationMap,\n layout: EntityActionMenuLayout,\n): ActionConfigurationMap {\n return Object.fromEntries(\n Object.entries(actionConfiguration).filter(([action, config]) => {\n // We don't care about actions that are not configured or should not be visible\n if (!config || !config.visible) {\n return false\n }\n\n const allLayoutActions: ActionViewProps[] = [\n ...layout.buttonActions,\n ...layout.primaryMenuActions.flat(),\n ...layout.downloadMenuActions.flat(),\n ]\n // Action is unmapped if it's visible and the layout doesn't have it\n return !allLayoutActions.some(\n layoutAction => layoutAction.action === action,\n )\n }),\n )\n}\n\n/**\n * Given a group of dropdown menu items and an action configuration,\n * return a list of dropdown menu items with non-visible and non-configured actions removed.\n * @param group\n * @param actionConfiguration\n */\nfunction mapAndFilterItemsInMenuGroup(\n group: ActionViewProps[],\n actionConfiguration: ActionConfigurationMap,\n): DropdownMenuItem[] {\n return group.reduce(\n (itemAcc: DropdownMenuItem[], actionViewProps: ActionViewProps) => {\n const configForAction = actionConfiguration[actionViewProps.action]\n // Only show the item if it's configured + visible\n if (configForAction && configForAction.visible) {\n itemAcc.push({\n text: configForAction.text ?? actionViewProps.action,\n onClick: configForAction.onClick,\n href: configForAction.href,\n tooltipText: configForAction.tooltipText,\n disabled: configForAction.disabled,\n icon: actionViewProps.icon,\n textSx: actionViewProps.textSx,\n iconSx: actionViewProps.iconSx,\n })\n }\n return itemAcc\n },\n [],\n )\n}\n\n/**\n * Given a list of groups of dropdown menu actions, returns a list of dropdown menu item\n * groups where non-visible actions have been removed, and groups with no visible actions\n * have been removed.\n * @param menuActions\n * @param actionConfiguration\n */\nfunction mapAndFilterMenuGroups(\n menuActions: ActionViewProps[][],\n actionConfiguration: ActionConfigurationMap,\n): DropdownMenuItem[][] {\n return menuActions.reduce(\n (groupAcc: DropdownMenuItem[][], group: ActionViewProps[]) => {\n const itemGroup = mapAndFilterItemsInMenuGroup(group, actionConfiguration)\n // Only show the group if it contains visible items\n if (itemGroup.length > 0) {\n groupAcc.push(itemGroup)\n }\n return groupAcc\n },\n [],\n )\n}\n\n/**\n * The EntityActionMenu renders a menu that displays the actions that can be invoked on an Entity page.\n */\nexport default function EntityActionMenu(props: EntityActionMenuProps) {\n const { actionConfiguration, menuConfiguration, layout } = props\n\n /*\n * All actions should be specified in the layout, but this is not guaranteed at compile time.\n * Find all visible actions in the action configuration that are not in the layout.\n */\n const unmappedActions = getUnmappedActions(actionConfiguration, layout)\n // Warn if unmapped actions were found and push them on to the layout.\n if (Object.entries(unmappedActions).length > 0) {\n console.warn(\n 'Actions are visible but have not been configured in the layout:',\n Object.entries(unmappedActions).map(entry => entry[0]),\n )\n // Modify the layout: put the unmapped actions in their own group at the top of the menu\n layout.primaryMenuActions.unshift(\n Object.entries(unmappedActions).map(\n (entry): ActionViewProps => ({\n action: entry[0],\n }),\n ),\n )\n }\n\n // Map button actions to an IconButtonConfiguration and omit non-visible actions\n const iconButtonConfigs: IconSvgButtonProps[] = layout.buttonActions.reduce(\n (acc: IconSvgButtonProps[], buttonViewProps: ActionViewProps) => {\n const configForAction = actionConfiguration[buttonViewProps.action]\n if (configForAction && configForAction.visible) {\n let onClick = configForAction.onClick\n if (onClick == null && !configForAction.href) {\n console.warn(`No handler registered for ${buttonViewProps.action}`)\n onClick = () => {\n console.warn(`No handler registered for ${buttonViewProps.action}`)\n }\n }\n acc.push({\n icon: buttonViewProps.icon as IconName,\n onClick: onClick,\n tooltipText: configForAction.text,\n disabled: configForAction.disabled,\n href: configForAction.href,\n })\n }\n return acc\n },\n [],\n )\n\n const downloadMenuConfig: DropdownMenuProps = {\n dropdownButtonText: 'Download Options',\n convertSingleItemToButton: true,\n renderMenuIfNoItems: false,\n buttonTooltip: menuConfiguration.DOWNLOAD.tooltipText,\n buttonProps: {\n disabled: menuConfiguration.DOWNLOAD.disabled,\n endIcon: <IconSvg icon={'download'} wrap={false} />,\n },\n items: mapAndFilterMenuGroups(\n layout.downloadMenuActions,\n actionConfiguration,\n ),\n }\n\n const primaryMenuConfig: DropdownMenuProps = {\n dropdownButtonText: layout.primaryMenuText,\n convertSingleItemToButton: true,\n renderMenuIfNoItems: false,\n buttonProps: {\n endIcon: <IconSvg icon={layout.primaryMenuEndIcon} wrap={false} />,\n },\n items: mapAndFilterMenuGroups(\n layout.primaryMenuActions,\n actionConfiguration,\n ),\n }\n\n return (\n <ComplexMenu\n iconButtons={iconButtonConfigs}\n dropdownMenus={[downloadMenuConfig, primaryMenuConfig]}\n />\n )\n}\n\nexport const EXPORTED_FOR_UNIT_TESTING = {\n getUnmappedActions,\n mapAndFilterItemsInMenuGroup,\n mapAndFilterMenuGroups,\n}\n"],"mappings":";;;;AA6DA,SAAS,EACP,GACA,GACwB;AACxB,QAAO,OAAO,YACZ,OAAO,QAAQ,EAAoB,CAAC,QAAQ,CAAC,GAAQ,OAE/C,CAAC,KAAU,CAAC,EAAO,UACd,KASF,CAAC;EALN,GAAG,EAAO;EACV,GAAG,EAAO,mBAAmB,MAAM;EACnC,GAAG,EAAO,oBAAoB,MAAM;EAG9B,CAAiB,MACvB,MAAgB,EAAa,WAAW,EACzC,CACD,CACH;;AASH,SAAS,EACP,GACA,GACoB;AACpB,QAAO,EAAM,QACV,GAA6B,MAAqC;EACjE,IAAM,IAAkB,EAAoB,EAAgB;AAc5D,SAZI,KAAmB,EAAgB,WACrC,EAAQ,KAAK;GACX,MAAM,EAAgB,QAAQ,EAAgB;GAC9C,SAAS,EAAgB;GACzB,MAAM,EAAgB;GACtB,aAAa,EAAgB;GAC7B,UAAU,EAAgB;GAC1B,MAAM,EAAgB;GACtB,QAAQ,EAAgB;GACxB,QAAQ,EAAgB;GACzB,CAAC,EAEG;IAET,EAAE,CACH;;AAUH,SAAS,EACP,GACA,GACsB;AACtB,QAAO,EAAY,QAChB,GAAgC,MAA6B;EAC5D,IAAM,IAAY,EAA6B,GAAO,EAAoB;AAK1E,SAHI,EAAU,SAAS,KACrB,EAAS,KAAK,EAAU,EAEnB;IAET,EAAE,CACH;;AAMH,SAAwB,EAAiB,GAA8B;CACrE,IAAM,EAAE,wBAAqB,sBAAmB,cAAW,GAMrD,IAAkB,EAAmB,GAAqB,EAAO;AAsEvE,QApEI,OAAO,QAAQ,EAAgB,CAAC,SAAS,MAC3C,QAAQ,KACN,mEACA,OAAO,QAAQ,EAAgB,CAAC,KAAI,MAAS,EAAM,GAAG,CACvD,EAED,EAAO,mBAAmB,QACxB,OAAO,QAAQ,EAAgB,CAAC,KAC7B,OAA4B,EAC3B,QAAQ,EAAM,IACf,EACF,CACF,GAyDD,kBAAC,GAAD;EACE,aAtD4C,EAAO,cAAc,QAClE,GAA2B,MAAqC;GAC/D,IAAM,IAAkB,EAAoB,EAAgB;AAC5D,OAAI,KAAmB,EAAgB,SAAS;IAC9C,IAAI,IAAU,EAAgB;AAO9B,IANI,KAAW,QAAQ,CAAC,EAAgB,SACtC,QAAQ,KAAK,6BAA6B,EAAgB,SAAS,EACnE,UAAgB;AACd,aAAQ,KAAK,6BAA6B,EAAgB,SAAS;QAGvE,EAAI,KAAK;KACP,MAAM,EAAgB;KACb;KACT,aAAa,EAAgB;KAC7B,UAAU,EAAgB;KAC1B,MAAM,EAAgB;KACvB,CAAC;;AAEJ,UAAO;KAET,EAAE,CAiCa;EACb,eAAe,CAAC;GA9BlB,oBAAoB;GACpB,2BAA2B;GAC3B,qBAAqB;GACrB,eAAe,EAAkB,SAAS;GAC1C,aAAa;IACX,UAAU,EAAkB,SAAS;IACrC,SAAS,kBAAC,GAAD;KAAS,MAAM;KAAY,MAAM;KAAS,CAAA;IACpD;GACD,OAAO,EACL,EAAO,qBACP,EACD;GAmBiB,EAAoB;GAftC,oBAAoB,EAAO;GAC3B,2BAA2B;GAC3B,qBAAqB;GACrB,aAAa,EACX,SAAS,kBAAC,GAAD;IAAS,MAAM,EAAO;IAAoB,MAAM;IAAS,CAAA,EACnE;GACD,OAAO,EACL,EAAO,oBACP,EACD;GAMqC,CAAkB;EACtD,CAAA;;AAIN,IAAa,IAA4B;CACvC;CACA;CACA;CACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDataCiteUsage.js","names":[],"sources":["../../../../../src/components/entity/page/title_bar/useDataCiteUsage.ts"],"sourcesContent":["import { useMemo } from 'react'\nimport { skipToken, useQuery, UseQueryOptions } from '@tanstack/react-query'\n\ntype RestUsage = {\n citationCount: number\n citations: CitingWork[]\n}\n\nexport type CitingWork = {\n id: string // DOI in bare form (e.g., 10.1234/abcd)\n doi: string\n title?: string\n publisher?: string\n publicationYear?: number\n containerTitle?: string\n}\n\nexport const maxCitationCount = 500\n\nexport const getDataCiteUsageQueryKey = (doi?: string) =>\n ['datacite-usage', doi] as const\n\nfunction toBareDoi(idOrUrl: string): string {\n return idOrUrl.replace(/^https?:\\/\\/(dx\\.)?doi\\.org\\//i, '')\n}\n\nasync function fetchCitationsViaGraphQL(signal: AbortSignal, doi: string) {\n const body = JSON.stringify({\n query: `\n query($id: ID!) {\n work(id: $id) {\n citations(first: ${maxCitationCount}) {\n nodes {\n id\n titles { title }\n publisher { name }\n publicationYear\n \n # publication (container) info\n container {\n title\n }\n }\n }\n }\n }\n `,\n variables: { id: `https://doi.org/${doi}` },\n })\n\n const r = await fetch('https://api.datacite.org/graphql', {\n method: 'POST',\n signal,\n headers: { 'content-type': 'application/json', accept: 'application/json' },\n body,\n })\n if (!r.ok) throw new Error(`DataCite GraphQL ${r.status}`)\n const json = await r.json()\n const nodes = json?.data?.work?.citations?.nodes ?? []\n return nodes.map((n: any) => {\n const bare = toBareDoi(n?.id ?? '')\n const title =\n Array.isArray(n?.titles) && n.titles.length\n ? n.titles[0]?.title.replaceAll('?', '') // many extended characters are returned as '?'s from DataCite\n : // for example, see https://commons.datacite.org/doi.org/10.1101%2F205807\n undefined\n const publisher = n?.publisher?.name ?? undefined\n const publicationYear = n?.publicationYear ?? undefined\n const containerTitle = n?.container?.title ?? undefined\n\n return {\n id: bare,\n doi: bare,\n title,\n publisher,\n publicationYear,\n containerTitle,\n } as CitingWork\n })\n}\n\nasync function fetchDataCiteUsage(\n signal: AbortSignal,\n doi: string,\n): Promise<RestUsage> {\n const citations: CitingWork[] = await fetchCitationsViaGraphQL(signal, doi)\n if (!citations) {\n throw new Error('No citations found')\n }\n return {\n citationCount: citations.length ?? 0,\n citations,\n }\n}\n\nexport function useDataCiteUsage(\n doi?: string,\n options?: Omit<UseQueryOptions<RestUsage, Error>, 'queryKey' | 'queryFn'>,\n) {\n const key = useMemo(() => getDataCiteUsageQueryKey(doi), [doi])\n return useQuery({\n ...options,\n queryKey: key,\n queryFn: doi\n ? ({ signal }) => {\n return fetchDataCiteUsage(signal, doi)\n }\n : skipToken,\n })\n}\n"],"mappings":";;;AAiBA,IAAa,IAAmB,KAEnB,KAA4B,MACvC,CAAC,kBAAkB,EAAI;AAEzB,SAAS,EAAU,GAAyB;AAC1C,QAAO,EAAQ,QAAQ,kCAAkC,GAAG;;AAG9D,eAAe,EAAyB,GAAqB,GAAa;CACxE,IAAM,IAAO,KAAK,UAAU;EAC1B,OAAO;EAmBP,WAAW,EAAE,IAAI,mBAAmB,KAAO;EAC5C,CAAC,EAEI,IAAI,MAAM,MAAM,oCAAoC;EACxD,QAAQ;EACR;EACA,SAAS;GAAE,gBAAgB;GAAoB,QAAQ;GAAoB;EAC3E;EACD,CAAC;AACF,KAAI,CAAC,EAAE,GAAI,OAAU,MAAM,oBAAoB,EAAE,SAAS;AAG1D,
|
|
1
|
+
{"version":3,"file":"useDataCiteUsage.js","names":[],"sources":["../../../../../src/components/entity/page/title_bar/useDataCiteUsage.ts"],"sourcesContent":["import { useMemo } from 'react'\nimport { skipToken, useQuery, UseQueryOptions } from '@tanstack/react-query'\n\ntype RestUsage = {\n citationCount: number\n citations: CitingWork[]\n}\n\nexport type CitingWork = {\n id: string // DOI in bare form (e.g., 10.1234/abcd)\n doi: string\n title?: string\n publisher?: string\n publicationYear?: number\n containerTitle?: string\n}\n\nexport const maxCitationCount = 500\n\nexport const getDataCiteUsageQueryKey = (doi?: string) =>\n ['datacite-usage', doi] as const\n\nfunction toBareDoi(idOrUrl: string): string {\n return idOrUrl.replace(/^https?:\\/\\/(dx\\.)?doi\\.org\\//i, '')\n}\n\nasync function fetchCitationsViaGraphQL(signal: AbortSignal, doi: string) {\n const body = JSON.stringify({\n query: `\n query($id: ID!) {\n work(id: $id) {\n citations(first: ${maxCitationCount}) {\n nodes {\n id\n titles { title }\n publisher { name }\n publicationYear\n \n # publication (container) info\n container {\n title\n }\n }\n }\n }\n }\n `,\n variables: { id: `https://doi.org/${doi}` },\n })\n\n const r = await fetch('https://api.datacite.org/graphql', {\n method: 'POST',\n signal,\n headers: { 'content-type': 'application/json', accept: 'application/json' },\n body,\n })\n if (!r.ok) throw new Error(`DataCite GraphQL ${r.status}`)\n const json = await r.json()\n const nodes = json?.data?.work?.citations?.nodes ?? []\n return nodes.map((n: any) => {\n const bare = toBareDoi(n?.id ?? '')\n const title =\n Array.isArray(n?.titles) && n.titles.length\n ? n.titles[0]?.title.replaceAll('?', '') // many extended characters are returned as '?'s from DataCite\n : // for example, see https://commons.datacite.org/doi.org/10.1101%2F205807\n undefined\n const publisher = n?.publisher?.name ?? undefined\n const publicationYear = n?.publicationYear ?? undefined\n const containerTitle = n?.container?.title ?? undefined\n\n return {\n id: bare,\n doi: bare,\n title,\n publisher,\n publicationYear,\n containerTitle,\n } as CitingWork\n })\n}\n\nasync function fetchDataCiteUsage(\n signal: AbortSignal,\n doi: string,\n): Promise<RestUsage> {\n const citations: CitingWork[] = await fetchCitationsViaGraphQL(signal, doi)\n if (!citations) {\n throw new Error('No citations found')\n }\n return {\n citationCount: citations.length ?? 0,\n citations,\n }\n}\n\nexport function useDataCiteUsage(\n doi?: string,\n options?: Omit<UseQueryOptions<RestUsage, Error>, 'queryKey' | 'queryFn'>,\n) {\n const key = useMemo(() => getDataCiteUsageQueryKey(doi), [doi])\n return useQuery({\n ...options,\n queryKey: key,\n queryFn: doi\n ? ({ signal }) => {\n return fetchDataCiteUsage(signal, doi)\n }\n : skipToken,\n })\n}\n"],"mappings":";;;AAiBA,IAAa,IAAmB,KAEnB,KAA4B,MACvC,CAAC,kBAAkB,EAAI;AAEzB,SAAS,EAAU,GAAyB;AAC1C,QAAO,EAAQ,QAAQ,kCAAkC,GAAG;;AAG9D,eAAe,EAAyB,GAAqB,GAAa;CACxE,IAAM,IAAO,KAAK,UAAU;EAC1B,OAAO;EAmBP,WAAW,EAAE,IAAI,mBAAmB,KAAO;EAC5C,CAAC,EAEI,IAAI,MAAM,MAAM,oCAAoC;EACxD,QAAQ;EACR;EACA,SAAS;GAAE,gBAAgB;GAAoB,QAAQ;GAAoB;EAC3E;EACD,CAAC;AACF,KAAI,CAAC,EAAE,GAAI,OAAU,MAAM,oBAAoB,EAAE,SAAS;AAG1D,UADc,MADK,EAAE,MAAM,GACP,MAAM,MAAM,WAAW,SAAS,EAAE,EACzC,KAAK,MAAW;EAC3B,IAAM,IAAO,EAAU,GAAG,MAAM,GAAG;AAUnC,SAAO;GACL,IAAI;GACJ,KAAK;GACL,OAXA,MAAM,QAAQ,GAAG,OAAO,IAAI,EAAE,OAAO,SACjC,EAAE,OAAO,IAAI,MAAM,WAAW,KAAK,GAAG,GAEtC,KAAA;GASJ,WARgB,GAAG,WAAW,QAAQ,KAAA;GAStC,iBARsB,GAAG,mBAAmB,KAAA;GAS5C,gBARqB,GAAG,WAAW,SAAS,KAAA;GAS7C;GACD;;AAGJ,eAAe,EACb,GACA,GACoB;CACpB,IAAM,IAA0B,MAAM,EAAyB,GAAQ,EAAI;AAC3E,KAAI,CAAC,EACH,OAAU,MAAM,qBAAqB;AAEvC,QAAO;EACL,eAAe,EAAU,UAAU;EACnC;EACD;;AAGH,SAAgB,EACd,GACA,GACA;CACA,IAAM,IAAM,QAAc,EAAyB,EAAI,EAAE,CAAC,EAAI,CAAC;AAC/D,QAAO,EAAS;EACd,GAAG;EACH,UAAU;EACV,SAAS,KACJ,EAAE,gBACM,EAAmB,GAAQ,EAAI,GAExC;EACL,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useGetMentions.js","names":[],"sources":["../../../../../src/components/entity/page/title_bar/useGetMentions.ts"],"sourcesContent":["import { useMemo } from 'react'\nimport { skipToken, useQuery, UseQueryOptions } from '@tanstack/react-query'\nimport {\n COLUMN_SINGLE_VALUE_QUERY_FILTER_CONCRETE_TYPE_VALUE,\n ColumnSingleValueFilterOperator,\n Query,\n} from '@sage-bionetworks/synapse-types'\nimport { useGetQueryResultBundleWithAsyncStatus } from '@/synapse-queries'\nimport { BUNDLE_MASK_QUERY_RESULTS } from '@/utils/SynapseConstants'\nimport { CitingWork } from './useDataCiteUsage'\n\nconst MENTIONS_SYNAPSE_TABLE_ID = 'syn66047339'\n\nexport type EuropePMCAuthor = {\n fullName?: string\n firstName?: string\n lastName?: string\n}\n\nexport type EuropePMCAuthorList = {\n author?: EuropePMCAuthor[]\n}\n\nexport type EuropePMCResult = {\n id?: string\n pmid?: string\n pmcid?: string\n doi?: string\n title?: string\n journalTitle?: string\n pubYear?: string\n authorList?: EuropePMCAuthorList\n}\n\nexport type EuropePMCResponse = {\n resultList: {\n result: EuropePMCResult[]\n }\n}\n\nexport const getMentionsQueryKey = (entityId: string) =>\n ['europepmc', entityId] as const\n\nexport async function fetchMetadataForPMCIDs(\n signal: AbortSignal,\n pmcids: string[],\n): Promise<CitingWork[]> {\n if (pmcids.length === 0) return []\n const query = pmcids.map(id => `PMCID:${id}`).join(' OR ')\n\n const url = new URL('https://www.ebi.ac.uk/europepmc/webservices/rest/search')\n url.searchParams.set('query', query)\n url.searchParams.set('format', 'json')\n url.searchParams.set('pageSize', String(pmcids.length))\n\n const resp = await fetch(url.toString(), {\n headers: { Accept: 'application/json' },\n signal,\n })\n if (!resp.ok)\n throw new Error(`Europe PMC error ${resp.status}: ${await resp.text()}`)\n\n const json = (await resp.json()) as EuropePMCResponse\n return mapEuropePMCResponseToCitingWorks(json)\n}\n\nexport function mapEuropePMCResponseToCitingWorks(\n json: EuropePMCResponse,\n): CitingWork[] {\n return json.resultList.result.map(\n r =>\n ({\n id: r.pmcid,\n title: r.title ?? '(Untitled)',\n doi: r.doi,\n publisher: r.journalTitle,\n publicationYear: r.pubYear ? Number(r.pubYear) : undefined,\n // authors: r.authorList?.author?.map((a: EuropePMCAuthor) => a.fullName ?? `${a.firstName ?? \"\"} ${a.lastName ?? \"\"}`.trim()) ?? [],\n } as CitingWork),\n )\n}\n\nexport function useGetMentions(\n entityId: string,\n options?: Omit<UseQueryOptions<CitingWork[], Error>, 'queryKey' | 'queryFn'>,\n) {\n const query: Query = {\n sql: `select pmcid from ${MENTIONS_SYNAPSE_TABLE_ID}`,\n additionalFilters: [\n {\n concreteType: COLUMN_SINGLE_VALUE_QUERY_FILTER_CONCRETE_TYPE_VALUE,\n columnName: 'synid',\n operator: ColumnSingleValueFilterOperator.EQUAL,\n values: [entityId],\n },\n ],\n }\n\n const { data } = useGetQueryResultBundleWithAsyncStatus({\n entityId: entityId,\n query,\n partMask: BUNDLE_MASK_QUERY_RESULTS,\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n })\n\n const rows = data?.responseBody?.queryResult?.queryResults?.rows\n const pcmids = rows\n ?.map(row => {\n const pmcid = row.values[0]\n // remove \"pmc:\" prefix if present\n return pmcid?.toString().replace(/^pmc:/i, '')\n })\n .filter(pmcid => pmcid != null) as string[]\n const key = useMemo(() => getMentionsQueryKey(entityId), [entityId])\n return useQuery({\n ...options,\n queryKey: key,\n queryFn: pcmids\n ? ({ signal }) => {\n return fetchMetadataForPMCIDs(signal, pcmids)\n }\n : skipToken,\n })\n}\n"],"mappings":";;;;;;;AAWA,IAAM,IAA4B,eA6BrB,KAAuB,MAClC,CAAC,aAAa,EAAS;AAEzB,eAAsB,EACpB,GACA,GACuB;AACvB,KAAI,EAAO,WAAW,EAAG,QAAO,EAAE;CAClC,IAAM,IAAQ,EAAO,KAAI,MAAM,SAAS,IAAK,CAAC,KAAK,OAAO,EAEpD,IAAM,IAAI,IAAI,0DAA0D;AAG9E,CAFA,EAAI,aAAa,IAAI,SAAS,EAAM,EACpC,EAAI,aAAa,IAAI,UAAU,OAAO,EACtC,EAAI,aAAa,IAAI,YAAY,OAAO,EAAO,OAAO,CAAC;CAEvD,IAAM,IAAO,MAAM,MAAM,EAAI,UAAU,EAAE;EACvC,SAAS,EAAE,QAAQ,oBAAoB;EACvC;EACD,CAAC;AACF,KAAI,CAAC,EAAK,GACR,OAAU,MAAM,oBAAoB,EAAK,OAAO,IAAI,MAAM,EAAK,MAAM,GAAG;AAG1E,QAAO,
|
|
1
|
+
{"version":3,"file":"useGetMentions.js","names":[],"sources":["../../../../../src/components/entity/page/title_bar/useGetMentions.ts"],"sourcesContent":["import { useMemo } from 'react'\nimport { skipToken, useQuery, UseQueryOptions } from '@tanstack/react-query'\nimport {\n COLUMN_SINGLE_VALUE_QUERY_FILTER_CONCRETE_TYPE_VALUE,\n ColumnSingleValueFilterOperator,\n Query,\n} from '@sage-bionetworks/synapse-types'\nimport { useGetQueryResultBundleWithAsyncStatus } from '@/synapse-queries'\nimport { BUNDLE_MASK_QUERY_RESULTS } from '@/utils/SynapseConstants'\nimport { CitingWork } from './useDataCiteUsage'\n\nconst MENTIONS_SYNAPSE_TABLE_ID = 'syn66047339'\n\nexport type EuropePMCAuthor = {\n fullName?: string\n firstName?: string\n lastName?: string\n}\n\nexport type EuropePMCAuthorList = {\n author?: EuropePMCAuthor[]\n}\n\nexport type EuropePMCResult = {\n id?: string\n pmid?: string\n pmcid?: string\n doi?: string\n title?: string\n journalTitle?: string\n pubYear?: string\n authorList?: EuropePMCAuthorList\n}\n\nexport type EuropePMCResponse = {\n resultList: {\n result: EuropePMCResult[]\n }\n}\n\nexport const getMentionsQueryKey = (entityId: string) =>\n ['europepmc', entityId] as const\n\nexport async function fetchMetadataForPMCIDs(\n signal: AbortSignal,\n pmcids: string[],\n): Promise<CitingWork[]> {\n if (pmcids.length === 0) return []\n const query = pmcids.map(id => `PMCID:${id}`).join(' OR ')\n\n const url = new URL('https://www.ebi.ac.uk/europepmc/webservices/rest/search')\n url.searchParams.set('query', query)\n url.searchParams.set('format', 'json')\n url.searchParams.set('pageSize', String(pmcids.length))\n\n const resp = await fetch(url.toString(), {\n headers: { Accept: 'application/json' },\n signal,\n })\n if (!resp.ok)\n throw new Error(`Europe PMC error ${resp.status}: ${await resp.text()}`)\n\n const json = (await resp.json()) as EuropePMCResponse\n return mapEuropePMCResponseToCitingWorks(json)\n}\n\nexport function mapEuropePMCResponseToCitingWorks(\n json: EuropePMCResponse,\n): CitingWork[] {\n return json.resultList.result.map(\n r =>\n ({\n id: r.pmcid,\n title: r.title ?? '(Untitled)',\n doi: r.doi,\n publisher: r.journalTitle,\n publicationYear: r.pubYear ? Number(r.pubYear) : undefined,\n // authors: r.authorList?.author?.map((a: EuropePMCAuthor) => a.fullName ?? `${a.firstName ?? \"\"} ${a.lastName ?? \"\"}`.trim()) ?? [],\n } as CitingWork),\n )\n}\n\nexport function useGetMentions(\n entityId: string,\n options?: Omit<UseQueryOptions<CitingWork[], Error>, 'queryKey' | 'queryFn'>,\n) {\n const query: Query = {\n sql: `select pmcid from ${MENTIONS_SYNAPSE_TABLE_ID}`,\n additionalFilters: [\n {\n concreteType: COLUMN_SINGLE_VALUE_QUERY_FILTER_CONCRETE_TYPE_VALUE,\n columnName: 'synid',\n operator: ColumnSingleValueFilterOperator.EQUAL,\n values: [entityId],\n },\n ],\n }\n\n const { data } = useGetQueryResultBundleWithAsyncStatus({\n entityId: entityId,\n query,\n partMask: BUNDLE_MASK_QUERY_RESULTS,\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n })\n\n const rows = data?.responseBody?.queryResult?.queryResults?.rows\n const pcmids = rows\n ?.map(row => {\n const pmcid = row.values[0]\n // remove \"pmc:\" prefix if present\n return pmcid?.toString().replace(/^pmc:/i, '')\n })\n .filter(pmcid => pmcid != null) as string[]\n const key = useMemo(() => getMentionsQueryKey(entityId), [entityId])\n return useQuery({\n ...options,\n queryKey: key,\n queryFn: pcmids\n ? ({ signal }) => {\n return fetchMetadataForPMCIDs(signal, pcmids)\n }\n : skipToken,\n })\n}\n"],"mappings":";;;;;;;AAWA,IAAM,IAA4B,eA6BrB,KAAuB,MAClC,CAAC,aAAa,EAAS;AAEzB,eAAsB,EACpB,GACA,GACuB;AACvB,KAAI,EAAO,WAAW,EAAG,QAAO,EAAE;CAClC,IAAM,IAAQ,EAAO,KAAI,MAAM,SAAS,IAAK,CAAC,KAAK,OAAO,EAEpD,IAAM,IAAI,IAAI,0DAA0D;AAG9E,CAFA,EAAI,aAAa,IAAI,SAAS,EAAM,EACpC,EAAI,aAAa,IAAI,UAAU,OAAO,EACtC,EAAI,aAAa,IAAI,YAAY,OAAO,EAAO,OAAO,CAAC;CAEvD,IAAM,IAAO,MAAM,MAAM,EAAI,UAAU,EAAE;EACvC,SAAS,EAAE,QAAQ,oBAAoB;EACvC;EACD,CAAC;AACF,KAAI,CAAC,EAAK,GACR,OAAU,MAAM,oBAAoB,EAAK,OAAO,IAAI,MAAM,EAAK,MAAM,GAAG;AAG1E,QAAO,EAAkC,MADrB,EAAK,MAAM,CACe;;AAGhD,SAAgB,EACd,GACc;AACd,QAAO,EAAK,WAAW,OAAO,KAC5B,OACG;EACC,IAAI,EAAE;EACN,OAAO,EAAE,SAAS;EAClB,KAAK,EAAE;EACP,WAAW,EAAE;EACb,iBAAiB,EAAE,UAAU,OAAO,EAAE,QAAQ,GAAG,KAAA;EAElD,EACJ;;AAGH,SAAgB,EACd,GACA,GACA;CAaA,IAAM,EAAE,YAAS,EAAuC;EAC5C;EACV,OAAA;GAbA,KAAK,qBAAqB;GAC1B,mBAAmB,CACjB;IACE,cAAc;IACd,YAAY;IACZ,UAAU,EAAgC;IAC1C,QAAQ,CAAC,EAAS;IACnB,CACF;GAKD;EACA,UAAA;EACA,cAAc;EACf,CAAC,EAGI,KADO,GAAM,cAAc,aAAa,cAAc,OAExD,KAAI,MACU,EAAI,OAAO,IAEX,UAAU,CAAC,QAAQ,UAAU,GAAG,CAC9C,CACD,QAAO,MAAS,KAAS,KAAK,EAC3B,IAAM,QAAc,EAAoB,EAAS,EAAE,CAAC,EAAS,CAAC;AACpE,QAAO,EAAS;EACd,GAAG;EACH,UAAU;EACV,SAAS,KACJ,EAAE,gBACM,EAAuB,GAAQ,EAAO,GAE/C;EACL,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ErrorPage.js","names":[],"sources":["../../../src/components/error/ErrorPage.tsx"],"sourcesContent":["import { ReactComponent as MaintenanceSvg } from '@/assets/icons/error_page/maintenance.svg'\nimport { ReactComponent as NoAccessSvg } from '@/assets/icons/error_page/no-access.svg'\nimport { ReactComponent as UnavailableSvg } from '@/assets/icons/error_page/unavailable.svg'\nimport { useSynapseContext } from '@/utils'\nimport { Box, Link, Typography } from '@mui/material'\nimport { useCallback, useMemo, useState } from 'react'\nimport SynapseObjectDOIInfo from './SynapseObjectDOIInfo'\nimport SendMessageToEntityOwnerDialog from './SendMessageToEntityOwnerDialog'\nimport { DoiObjectType } from '@sage-bionetworks/synapse-client/generated/models/DoiObjectType'\n\nexport type ErrorPageProps = {\n type: SynapseErrorType\n message?: string // custom message to report\n /** @deprecated use `id` and objectType: DoiObjectType.ENTITY */\n entityId?: string\n /** @deprecated use `version` and objectType: DoiObjectType.ENTITY */\n entityVersion?: number\n\n /** The ID of the object that was attempted to be retrieved, which may be used to show a 'tombstone' */\n id?: string\n /** The version of the object that was attempted to be retrieved, which may be used to show a 'tombstone' */\n version?: number\n /** The type of the object that was attempted to be retrieved, which may be used to show a 'tombstone' */\n objectType?: DoiObjectType\n /** If on a portal that may mint DOIs, this portal ID may be used to find a DOI to show a 'tombstone' */\n portalId?: string\n\n gotoPlace: (href: string) => void\n}\n\nexport const SYNAPSE_DOWN_TITLE = 'Synapse is down for maintenance.'\nexport const ACCESS_DENIED_TITLE = 'You don’t have permission to view this.'\nexport const NOT_FOUND_TITLE = 'This page isn’t available.'\nexport const LOG_IN_LINK_TEXT = 'Log in to Synapse'\nexport const CONTACT_US_LINK_TEXT = 'Contact us for more information'\nexport const CONTACT_ADMIN_LINK_TEXT = 'Contact the Administrator'\nexport const ACCESS_DENIED_ANONYMOUS_MESSAGE =\n 'Try logging in. If you still see this message after logging in, you have not been granted access to view this resource.'\nexport const ACCESS_DENIED_MESSAGE =\n 'This account has not been granted access to view this resource.'\nexport const NOT_FOUND_MESSAGE =\n 'The link you followed may be broken, or the page may have been removed.'\nexport const ACCESS_DENIED_ANONYMOUS_ACTION_DESCRIPTION =\n 'A Synapse account is free, and lets you view public resources.'\nexport const ACCESS_DENIED_CONTACT_ADMIN_ACTION_DESCRIPTION =\n 'Write a message to the owner of the resource asking for permission to view.'\n\nexport enum SynapseErrorType {\n DOWN = 'DOWN',\n ACCESS_DENIED = 'ACCESS_DENIED',\n NOT_FOUND = 'NOT_FOUND',\n}\n\nconst getImage = (type: SynapseErrorType) => {\n switch (type) {\n case SynapseErrorType.DOWN:\n return (\n <MaintenanceSvg\n role=\"img\"\n aria-label=\"Synapse is Down image\"\n title={SynapseErrorType.DOWN}\n />\n )\n case SynapseErrorType.ACCESS_DENIED:\n return (\n <NoAccessSvg\n role=\"img\"\n aria-label=\"Access denied image\"\n title={SynapseErrorType.ACCESS_DENIED}\n />\n )\n case SynapseErrorType.NOT_FOUND:\n return (\n <UnavailableSvg\n role=\"img\"\n aria-label=\"Resource not found image\"\n title={SynapseErrorType.NOT_FOUND}\n />\n )\n default:\n return <></>\n }\n}\nconst getTitle = (type: SynapseErrorType) => {\n switch (type) {\n case SynapseErrorType.DOWN:\n return SYNAPSE_DOWN_TITLE\n case SynapseErrorType.ACCESS_DENIED:\n return ACCESS_DENIED_TITLE\n case SynapseErrorType.NOT_FOUND:\n return NOT_FOUND_TITLE\n default:\n return ''\n }\n}\n\ntype ErrorPageAction = {\n linkText: string\n onClick: () => void\n description: string\n}\n\nfunction ErrorPage(props: ErrorPageProps) {\n const {\n type,\n entityId = '',\n entityVersion,\n message,\n gotoPlace,\n id,\n version,\n objectType,\n portalId,\n } = props\n const [isSendMessageToAdminDialogOpen, setSendMessageToAdminDialogOpen] =\n useState<boolean>(false)\n const { isAuthenticated } = useSynapseContext()\n const image = useMemo(() => getImage(type), [type])\n const title = useMemo(() => getTitle(type), [type])\n\n const messages = useMemo(() => {\n const msgs: string[] = []\n switch (type) {\n case SynapseErrorType.ACCESS_DENIED:\n if (!isAuthenticated) {\n msgs.push(ACCESS_DENIED_ANONYMOUS_MESSAGE)\n } else {\n msgs.push(ACCESS_DENIED_MESSAGE)\n }\n break\n case SynapseErrorType.NOT_FOUND:\n msgs.push(NOT_FOUND_MESSAGE)\n break\n }\n if (message) {\n msgs.push(message)\n }\n return msgs\n }, [type, isAuthenticated, message])\n\n const actions = useMemo(() => {\n const acts: ErrorPageAction[] = []\n if (type === SynapseErrorType.ACCESS_DENIED) {\n if (!isAuthenticated) {\n acts.push({\n linkText: LOG_IN_LINK_TEXT,\n onClick: () => gotoPlace('/LoginPlace:0'),\n description: ACCESS_DENIED_ANONYMOUS_ACTION_DESCRIPTION,\n })\n } else if (entityId) {\n acts.push({\n linkText: CONTACT_US_LINK_TEXT,\n onClick: () =>\n window.open(\n 'https://sagebionetworks.jira.com/servicedesk/customer/portals',\n '_blank',\n ),\n description: '',\n })\n // SWC-7073: Remove ability to send a message to the admins until we have a better option for the majority of the cases (service desk, contact emails, ...)\n // acts.push({\n // linkText: CONTACT_ADMIN_LINK_TEXT,\n // onClick: () => setSendMessageToAdminDialogOpen(true),\n // description: ACCESS_DENIED_CONTACT_ADMIN_ACTION_DESCRIPTION,\n // })\n }\n }\n return acts\n }, [type, isAuthenticated, entityId, gotoPlace])\n\n const handleCloseDialog = useCallback(\n () => setSendMessageToAdminDialogOpen(false),\n [],\n )\n return (\n <>\n <Box\n sx={{\n display: { xs: 'flex', lg: 'grid' },\n columnGap: '80px',\n flexDirection: { xs: 'column', lg: undefined },\n gridTemplateColumns: { lg: '40% 60%' },\n }}\n >\n <Box\n sx={{\n justifySelf: 'end',\n alignSelf: 'center',\n '& svg': {\n height: '360px',\n maxWidth: '300px',\n },\n pt: '50px',\n pb: '50px',\n }}\n >\n {image}\n </Box>\n <Box\n sx={{\n justifySelf: 'start',\n alignSelf: 'center',\n display: 'flex',\n flexDirection: 'column',\n gap: '20px',\n m: { xs: '15px', lg: undefined },\n mr: { lg: '100px' },\n }}\n >\n <Typography\n sx={{ fontSize: '30px', fontWeight: 700, lineHeight: '36px' }}\n >\n {title}\n </Typography>\n {messages.map(message => {\n return (\n <Typography variant=\"body1\" key={message}>\n {message}\n </Typography>\n )\n })}\n {actions.map(action => {\n const { onClick, linkText, description } = action\n return (\n <Box key={linkText}>\n <Link sx={{ fontSize: '16px' }} onClick={onClick}>\n {linkText}\n </Link>\n <Typography variant=\"body1\">{description}</Typography>\n </Box>\n )\n })}\n {entityId && (\n <SynapseObjectDOIInfo\n id={entityId}\n version={entityVersion}\n type={DoiObjectType.ENTITY}\n />\n )}\n {id && objectType && (\n <SynapseObjectDOIInfo\n id={id}\n version={version}\n type={objectType}\n portalId={portalId}\n />\n )}\n </Box>\n </Box>\n {entityId && (\n <SendMessageToEntityOwnerDialog\n isOpen={isSendMessageToAdminDialogOpen}\n onHide={handleCloseDialog}\n entityId={entityId}\n />\n )}\n </>\n )\n}\n\nexport default ErrorPage\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ErrorPage.js","names":[],"sources":["../../../src/components/error/ErrorPage.tsx"],"sourcesContent":["import { ReactComponent as MaintenanceSvg } from '@/assets/icons/error_page/maintenance.svg'\nimport { ReactComponent as NoAccessSvg } from '@/assets/icons/error_page/no-access.svg'\nimport { ReactComponent as UnavailableSvg } from '@/assets/icons/error_page/unavailable.svg'\nimport { useSynapseContext } from '@/utils'\nimport { Box, Link, Typography } from '@mui/material'\nimport { useCallback, useMemo, useState } from 'react'\nimport SynapseObjectDOIInfo from './SynapseObjectDOIInfo'\nimport SendMessageToEntityOwnerDialog from './SendMessageToEntityOwnerDialog'\nimport { DoiObjectType } from '@sage-bionetworks/synapse-client/generated/models/DoiObjectType'\n\nexport type ErrorPageProps = {\n type: SynapseErrorType\n message?: string // custom message to report\n /** @deprecated use `id` and objectType: DoiObjectType.ENTITY */\n entityId?: string\n /** @deprecated use `version` and objectType: DoiObjectType.ENTITY */\n entityVersion?: number\n\n /** The ID of the object that was attempted to be retrieved, which may be used to show a 'tombstone' */\n id?: string\n /** The version of the object that was attempted to be retrieved, which may be used to show a 'tombstone' */\n version?: number\n /** The type of the object that was attempted to be retrieved, which may be used to show a 'tombstone' */\n objectType?: DoiObjectType\n /** If on a portal that may mint DOIs, this portal ID may be used to find a DOI to show a 'tombstone' */\n portalId?: string\n\n gotoPlace: (href: string) => void\n}\n\nexport const SYNAPSE_DOWN_TITLE = 'Synapse is down for maintenance.'\nexport const ACCESS_DENIED_TITLE = 'You don’t have permission to view this.'\nexport const NOT_FOUND_TITLE = 'This page isn’t available.'\nexport const LOG_IN_LINK_TEXT = 'Log in to Synapse'\nexport const CONTACT_US_LINK_TEXT = 'Contact us for more information'\nexport const CONTACT_ADMIN_LINK_TEXT = 'Contact the Administrator'\nexport const ACCESS_DENIED_ANONYMOUS_MESSAGE =\n 'Try logging in. If you still see this message after logging in, you have not been granted access to view this resource.'\nexport const ACCESS_DENIED_MESSAGE =\n 'This account has not been granted access to view this resource.'\nexport const NOT_FOUND_MESSAGE =\n 'The link you followed may be broken, or the page may have been removed.'\nexport const ACCESS_DENIED_ANONYMOUS_ACTION_DESCRIPTION =\n 'A Synapse account is free, and lets you view public resources.'\nexport const ACCESS_DENIED_CONTACT_ADMIN_ACTION_DESCRIPTION =\n 'Write a message to the owner of the resource asking for permission to view.'\n\nexport enum SynapseErrorType {\n DOWN = 'DOWN',\n ACCESS_DENIED = 'ACCESS_DENIED',\n NOT_FOUND = 'NOT_FOUND',\n}\n\nconst getImage = (type: SynapseErrorType) => {\n switch (type) {\n case SynapseErrorType.DOWN:\n return (\n <MaintenanceSvg\n role=\"img\"\n aria-label=\"Synapse is Down image\"\n title={SynapseErrorType.DOWN}\n />\n )\n case SynapseErrorType.ACCESS_DENIED:\n return (\n <NoAccessSvg\n role=\"img\"\n aria-label=\"Access denied image\"\n title={SynapseErrorType.ACCESS_DENIED}\n />\n )\n case SynapseErrorType.NOT_FOUND:\n return (\n <UnavailableSvg\n role=\"img\"\n aria-label=\"Resource not found image\"\n title={SynapseErrorType.NOT_FOUND}\n />\n )\n default:\n return <></>\n }\n}\nconst getTitle = (type: SynapseErrorType) => {\n switch (type) {\n case SynapseErrorType.DOWN:\n return SYNAPSE_DOWN_TITLE\n case SynapseErrorType.ACCESS_DENIED:\n return ACCESS_DENIED_TITLE\n case SynapseErrorType.NOT_FOUND:\n return NOT_FOUND_TITLE\n default:\n return ''\n }\n}\n\ntype ErrorPageAction = {\n linkText: string\n onClick: () => void\n description: string\n}\n\nfunction ErrorPage(props: ErrorPageProps) {\n const {\n type,\n entityId = '',\n entityVersion,\n message,\n gotoPlace,\n id,\n version,\n objectType,\n portalId,\n } = props\n const [isSendMessageToAdminDialogOpen, setSendMessageToAdminDialogOpen] =\n useState<boolean>(false)\n const { isAuthenticated } = useSynapseContext()\n const image = useMemo(() => getImage(type), [type])\n const title = useMemo(() => getTitle(type), [type])\n\n const messages = useMemo(() => {\n const msgs: string[] = []\n switch (type) {\n case SynapseErrorType.ACCESS_DENIED:\n if (!isAuthenticated) {\n msgs.push(ACCESS_DENIED_ANONYMOUS_MESSAGE)\n } else {\n msgs.push(ACCESS_DENIED_MESSAGE)\n }\n break\n case SynapseErrorType.NOT_FOUND:\n msgs.push(NOT_FOUND_MESSAGE)\n break\n }\n if (message) {\n msgs.push(message)\n }\n return msgs\n }, [type, isAuthenticated, message])\n\n const actions = useMemo(() => {\n const acts: ErrorPageAction[] = []\n if (type === SynapseErrorType.ACCESS_DENIED) {\n if (!isAuthenticated) {\n acts.push({\n linkText: LOG_IN_LINK_TEXT,\n onClick: () => gotoPlace('/LoginPlace:0'),\n description: ACCESS_DENIED_ANONYMOUS_ACTION_DESCRIPTION,\n })\n } else if (entityId) {\n acts.push({\n linkText: CONTACT_US_LINK_TEXT,\n onClick: () =>\n window.open(\n 'https://sagebionetworks.jira.com/servicedesk/customer/portals',\n '_blank',\n ),\n description: '',\n })\n // SWC-7073: Remove ability to send a message to the admins until we have a better option for the majority of the cases (service desk, contact emails, ...)\n // acts.push({\n // linkText: CONTACT_ADMIN_LINK_TEXT,\n // onClick: () => setSendMessageToAdminDialogOpen(true),\n // description: ACCESS_DENIED_CONTACT_ADMIN_ACTION_DESCRIPTION,\n // })\n }\n }\n return acts\n }, [type, isAuthenticated, entityId, gotoPlace])\n\n const handleCloseDialog = useCallback(\n () => setSendMessageToAdminDialogOpen(false),\n [],\n )\n return (\n <>\n <Box\n sx={{\n display: { xs: 'flex', lg: 'grid' },\n columnGap: '80px',\n flexDirection: { xs: 'column', lg: undefined },\n gridTemplateColumns: { lg: '40% 60%' },\n }}\n >\n <Box\n sx={{\n justifySelf: 'end',\n alignSelf: 'center',\n '& svg': {\n height: '360px',\n maxWidth: '300px',\n },\n pt: '50px',\n pb: '50px',\n }}\n >\n {image}\n </Box>\n <Box\n sx={{\n justifySelf: 'start',\n alignSelf: 'center',\n display: 'flex',\n flexDirection: 'column',\n gap: '20px',\n m: { xs: '15px', lg: undefined },\n mr: { lg: '100px' },\n }}\n >\n <Typography\n sx={{ fontSize: '30px', fontWeight: 700, lineHeight: '36px' }}\n >\n {title}\n </Typography>\n {messages.map(message => {\n return (\n <Typography variant=\"body1\" key={message}>\n {message}\n </Typography>\n )\n })}\n {actions.map(action => {\n const { onClick, linkText, description } = action\n return (\n <Box key={linkText}>\n <Link sx={{ fontSize: '16px' }} onClick={onClick}>\n {linkText}\n </Link>\n <Typography variant=\"body1\">{description}</Typography>\n </Box>\n )\n })}\n {entityId && (\n <SynapseObjectDOIInfo\n id={entityId}\n version={entityVersion}\n type={DoiObjectType.ENTITY}\n />\n )}\n {id && objectType && (\n <SynapseObjectDOIInfo\n id={id}\n version={version}\n type={objectType}\n portalId={portalId}\n />\n )}\n </Box>\n </Box>\n {entityId && (\n <SendMessageToEntityOwnerDialog\n isOpen={isSendMessageToAdminDialogOpen}\n onHide={handleCloseDialog}\n entityId={entityId}\n />\n )}\n </>\n )\n}\n\nexport default ErrorPage\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FavoritesPage.js","names":[],"sources":["../../../src/components/favorites/FavoritesPage.tsx"],"sourcesContent":["import NoSearchResults from '@/assets/icons/NoSearchResults'\nimport { useGetFavorites } from '@/synapse-queries/user/useFavorites'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport {\n convertToEntityType,\n entityTypeToFriendlyName,\n} from '@/utils/functions/EntityTypeUtils'\nimport { PRODUCTION_ENDPOINT_CONFIG } from '@/utils/functions/getEndpoint'\nimport { InputAdornment, Stack, TextField } from '@mui/material'\nimport { EntityHeader } from '@sage-bionetworks/synapse-types'\nimport {\n createColumnHelper,\n getCoreRowModel,\n getFacetedRowModel,\n getFacetedUniqueValues,\n getFilteredRowModel,\n getSortedRowModel,\n useReactTable,\n} from '@tanstack/react-table'\nimport { useEffect, useMemo, useState } from 'react'\nimport { EntityTypeIcon } from '../EntityIcon'\nimport { ErrorBanner } from '../error/ErrorBanner'\nimport IconSvg from '../IconSvg/IconSvg'\nimport { SynapseSpinner } from '../LoadingScreen/LoadingScreen'\nimport ColumnHeader from '../TanStackTable/ColumnHeader'\nimport StyledTanStackTable from '../TanStackTable/StyledTanStackTable'\nimport FavoriteButton from './FavoriteButton'\n\n// Local types used for client-side sorting\nexport type SortField = 'name' | 'type'\nexport type SortDirection = 'ASC' | 'DESC'\nexport type Sort = {\n field: SortField\n direction: SortDirection\n}\n\nconst columnHelper = createColumnHelper<EntityHeader>()\n\nconst columns = [\n columnHelper.display({\n id: 'removeFavorite',\n cell: ctx => <FavoriteButton entityId={ctx.row.original.id} />,\n size: 60,\n enableResizing: false,\n meta: {\n textAlign: 'center',\n },\n }),\n columnHelper.accessor('name', {\n cell: ctx => (\n <a\n rel=\"noopener noreferrer\"\n href={`${PRODUCTION_ENDPOINT_CONFIG.PORTAL}Synapse:${ctx.row.original.id}`}\n >\n {ctx.row.original.name}\n </a>\n ),\n enableGlobalFilter: true,\n header: props => <ColumnHeader {...props} title={'Name'} />,\n size: 400,\n enableColumnFilter: false,\n sortingFn: 'alphanumeric',\n enableSorting: true,\n }),\n columnHelper.accessor('type', {\n cell: ctx => {\n const entityType = convertToEntityType(ctx.row.original.type)\n return (\n <>\n <EntityTypeIcon type={entityType} style={{ marginRight: '5px' }} />\n {entityTypeToFriendlyName(entityType)}\n </>\n )\n },\n header: props => <ColumnHeader {...props} title={'Type'} />,\n size: 160,\n enableGlobalFilter: false,\n sortingFn: 'alphanumeric',\n filterFn: 'arrIncludes',\n meta: {\n enableMultipleSelect: true,\n filterVariant: 'enumeration',\n getDisplayText: value =>\n entityTypeToFriendlyName(convertToEntityType(value)),\n },\n enableSorting: true,\n }),\n]\n\nexport default function FavoritesPage() {\n const { isAuthenticated } = useSynapseContext()\n const [searchText, setSearchText] = useState<string>('')\n const [error, setError] = useState<Error>()\n const { data, isLoading, isError, error: newError } = useGetFavorites()\n\n const favorites = useMemo(() => data ?? [], [data])\n\n const favoritesTable = useReactTable<EntityHeader>({\n data: favorites,\n columns: columns,\n getCoreRowModel: getCoreRowModel(),\n getFilteredRowModel: getFilteredRowModel(),\n getSortedRowModel: getSortedRowModel(),\n getFacetedRowModel: getFacetedRowModel(),\n getFacetedUniqueValues: getFacetedUniqueValues(),\n globalFilterFn: 'includesString',\n state: {\n globalFilter: searchText,\n },\n columnResizeMode: 'onChange',\n })\n\n useEffect(() => {\n if (isError && newError) {\n setError(newError)\n }\n }, [isError, newError])\n\n useEffect(() => {\n if (!isAuthenticated) {\n setError(new Error('Please sign in to access your favorites.'))\n } else {\n setError(undefined)\n }\n }, [isAuthenticated])\n\n if (error) {\n return <ErrorBanner error={error} />\n }\n\n const hasFavoritesMatchingQuery = favoritesTable.getRowModel().rows.length > 0\n\n return (\n <div className=\"FavoritesPage\">\n <TextField\n type=\"search\"\n placeholder=\"Favorite Name\"\n value={searchText}\n onChange={event => {\n setSearchText(event.target.value)\n }}\n fullWidth\n sx={{ mb: 4, maxWidth: '800px' }}\n slotProps={{\n input: {\n startAdornment: (\n <InputAdornment position=\"start\">\n <IconSvg icon=\"search\" wrap={false} />\n </InputAdornment>\n ),\n },\n }}\n />\n <StyledTanStackTable table={favoritesTable} fullWidth={false} />\n {!hasFavoritesMatchingQuery && !isLoading && (\n <Stack\n sx={{\n my: 2,\n gap: 1,\n textAlign: 'center',\n }}\n >\n <NoSearchResults height={'150px'} />\n {data?.length == 0 ? (\n <p>You currently have no favorites</p>\n ) : (\n <p>No matching favorites found</p>\n )}\n </Stack>\n )}\n\n {isLoading && (\n <div className=\"placeholder\">\n <SynapseSpinner size={30} />\n </div>\n )}\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAoCA,IAAM,IAAe,GAAkC,EAEjD,IAAU;CACd,EAAa,QAAQ;EACnB,IAAI;EACJ,OAAM,MAAO,kBAAC,GAAD,EAAgB,UAAU,EAAI,IAAI,SAAS,IAAM,CAAA;EAC9D,MAAM;EACN,gBAAgB;EAChB,MAAM,EACJ,WAAW,UACZ;EACF,CAAC;CACF,EAAa,SAAS,QAAQ;EAC5B,OAAM,MACJ,kBAAC,KAAD;GACE,KAAI;GACJ,MAAM,GAAG,EAA2B,OAAO,UAAU,EAAI,IAAI,SAAS;aAErE,EAAI,IAAI,SAAS;GAChB,CAAA;EAEN,oBAAoB;EACpB,SAAQ,MAAS,kBAAC,GAAD;GAAc,GAAI;GAAO,OAAO;GAAU,CAAA;EAC3D,MAAM;EACN,oBAAoB;EACpB,WAAW;EACX,eAAe;EAChB,CAAC;CACF,EAAa,SAAS,QAAQ;EAC5B,OAAM,MAAO;GACX,IAAM,IAAa,EAAoB,EAAI,IAAI,SAAS,KAAK;AAC7D,UACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;IAAgB,MAAM;IAAY,OAAO,EAAE,aAAa,OAAO;IAAI,CAAA,EAClE,EAAyB,EAAW,CACpC,EAAA,CAAA;;EAGP,SAAQ,MAAS,kBAAC,GAAD;GAAc,GAAI;GAAO,OAAO;GAAU,CAAA;EAC3D,MAAM;EACN,oBAAoB;EACpB,WAAW;EACX,UAAU;EACV,MAAM;GACJ,sBAAsB;GACtB,eAAe;GACf,iBAAgB,MACd,EAAyB,EAAoB,EAAM,CAAC;GACvD;EACD,eAAe;EAChB,CAAC;CACH;AAED,SAAwB,IAAgB;CACtC,IAAM,EAAE,uBAAoB,GAAmB,EACzC,CAAC,GAAY,KAAiB,EAAiB,GAAG,EAClD,CAAC,GAAO,KAAY,GAAiB,EACrC,EAAE,SAAM,cAAW,YAAS,OAAO,MAAa,GAAiB,EAIjE,IAAiB,EAA4B;EACjD,MAHgB,QAAc,KAAQ,EAAE,EAAE,CAAC,EAAK,
|
|
1
|
+
{"version":3,"file":"FavoritesPage.js","names":[],"sources":["../../../src/components/favorites/FavoritesPage.tsx"],"sourcesContent":["import NoSearchResults from '@/assets/icons/NoSearchResults'\nimport { useGetFavorites } from '@/synapse-queries/user/useFavorites'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport {\n convertToEntityType,\n entityTypeToFriendlyName,\n} from '@/utils/functions/EntityTypeUtils'\nimport { PRODUCTION_ENDPOINT_CONFIG } from '@/utils/functions/getEndpoint'\nimport { InputAdornment, Stack, TextField } from '@mui/material'\nimport { EntityHeader } from '@sage-bionetworks/synapse-types'\nimport {\n createColumnHelper,\n getCoreRowModel,\n getFacetedRowModel,\n getFacetedUniqueValues,\n getFilteredRowModel,\n getSortedRowModel,\n useReactTable,\n} from '@tanstack/react-table'\nimport { useEffect, useMemo, useState } from 'react'\nimport { EntityTypeIcon } from '../EntityIcon'\nimport { ErrorBanner } from '../error/ErrorBanner'\nimport IconSvg from '../IconSvg/IconSvg'\nimport { SynapseSpinner } from '../LoadingScreen/LoadingScreen'\nimport ColumnHeader from '../TanStackTable/ColumnHeader'\nimport StyledTanStackTable from '../TanStackTable/StyledTanStackTable'\nimport FavoriteButton from './FavoriteButton'\n\n// Local types used for client-side sorting\nexport type SortField = 'name' | 'type'\nexport type SortDirection = 'ASC' | 'DESC'\nexport type Sort = {\n field: SortField\n direction: SortDirection\n}\n\nconst columnHelper = createColumnHelper<EntityHeader>()\n\nconst columns = [\n columnHelper.display({\n id: 'removeFavorite',\n cell: ctx => <FavoriteButton entityId={ctx.row.original.id} />,\n size: 60,\n enableResizing: false,\n meta: {\n textAlign: 'center',\n },\n }),\n columnHelper.accessor('name', {\n cell: ctx => (\n <a\n rel=\"noopener noreferrer\"\n href={`${PRODUCTION_ENDPOINT_CONFIG.PORTAL}Synapse:${ctx.row.original.id}`}\n >\n {ctx.row.original.name}\n </a>\n ),\n enableGlobalFilter: true,\n header: props => <ColumnHeader {...props} title={'Name'} />,\n size: 400,\n enableColumnFilter: false,\n sortingFn: 'alphanumeric',\n enableSorting: true,\n }),\n columnHelper.accessor('type', {\n cell: ctx => {\n const entityType = convertToEntityType(ctx.row.original.type)\n return (\n <>\n <EntityTypeIcon type={entityType} style={{ marginRight: '5px' }} />\n {entityTypeToFriendlyName(entityType)}\n </>\n )\n },\n header: props => <ColumnHeader {...props} title={'Type'} />,\n size: 160,\n enableGlobalFilter: false,\n sortingFn: 'alphanumeric',\n filterFn: 'arrIncludes',\n meta: {\n enableMultipleSelect: true,\n filterVariant: 'enumeration',\n getDisplayText: value =>\n entityTypeToFriendlyName(convertToEntityType(value)),\n },\n enableSorting: true,\n }),\n]\n\nexport default function FavoritesPage() {\n const { isAuthenticated } = useSynapseContext()\n const [searchText, setSearchText] = useState<string>('')\n const [error, setError] = useState<Error>()\n const { data, isLoading, isError, error: newError } = useGetFavorites()\n\n const favorites = useMemo(() => data ?? [], [data])\n\n const favoritesTable = useReactTable<EntityHeader>({\n data: favorites,\n columns: columns,\n getCoreRowModel: getCoreRowModel(),\n getFilteredRowModel: getFilteredRowModel(),\n getSortedRowModel: getSortedRowModel(),\n getFacetedRowModel: getFacetedRowModel(),\n getFacetedUniqueValues: getFacetedUniqueValues(),\n globalFilterFn: 'includesString',\n state: {\n globalFilter: searchText,\n },\n columnResizeMode: 'onChange',\n })\n\n useEffect(() => {\n if (isError && newError) {\n setError(newError)\n }\n }, [isError, newError])\n\n useEffect(() => {\n if (!isAuthenticated) {\n setError(new Error('Please sign in to access your favorites.'))\n } else {\n setError(undefined)\n }\n }, [isAuthenticated])\n\n if (error) {\n return <ErrorBanner error={error} />\n }\n\n const hasFavoritesMatchingQuery = favoritesTable.getRowModel().rows.length > 0\n\n return (\n <div className=\"FavoritesPage\">\n <TextField\n type=\"search\"\n placeholder=\"Favorite Name\"\n value={searchText}\n onChange={event => {\n setSearchText(event.target.value)\n }}\n fullWidth\n sx={{ mb: 4, maxWidth: '800px' }}\n slotProps={{\n input: {\n startAdornment: (\n <InputAdornment position=\"start\">\n <IconSvg icon=\"search\" wrap={false} />\n </InputAdornment>\n ),\n },\n }}\n />\n <StyledTanStackTable table={favoritesTable} fullWidth={false} />\n {!hasFavoritesMatchingQuery && !isLoading && (\n <Stack\n sx={{\n my: 2,\n gap: 1,\n textAlign: 'center',\n }}\n >\n <NoSearchResults height={'150px'} />\n {data?.length == 0 ? (\n <p>You currently have no favorites</p>\n ) : (\n <p>No matching favorites found</p>\n )}\n </Stack>\n )}\n\n {isLoading && (\n <div className=\"placeholder\">\n <SynapseSpinner size={30} />\n </div>\n )}\n </div>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BasicFileHandleUpload.js","names":[],"sources":["../../../../src/components/file/upload/BasicFileHandleUpload.tsx"],"sourcesContent":["import MultiFileUploadProgress from '@/components/file/upload/MultiFileUploadProgress'\nimport UploadFilePanel from '@/components/file/upload/UploadFilePanel'\nimport {\n UploaderState,\n useUploadFiles,\n} from '@/utils/hooks/useUploadFileEntity/useUploadFiles'\nimport { noop } from 'lodash-es'\nimport { ForwardedRef, forwardRef, useEffect, useImperativeHandle } from 'react'\n\nexport type BasicFileHandleUploadProps = {\n /**\n * Whether to allow uploading multiple files.\n * Currently, only single file upload is supported by this UI component.\n */\n allowMultipleUpload: false\n /**\n * Whether to disable \"drag-and-drop to upload\" functionality.\n * Currently, drag-and-drop cannot be enabled.\n */\n disableDragAndDrop: true\n /** Callback that is invoked when the state of the uploader changes */\n onStateChange?: (state: UploaderState) => void\n /** Callback that is invoked when component is ready to upload */\n onUploadReady?: () => void\n /** Callback that is invoked when an individual upload is complete */\n onFileUploadComplete?: (fileHandleIds: string) => void\n}\n\nexport type FileUploadHandle = {\n /** Programmatically add files to the upload (e.g. on drag & drop) */\n handleUploads: (fileList: ArrayLike<File>) => void\n}\n\n/**\n * BasicFileHandleUpload is a component that supports uploading a file to the default Synapse S3 bucket and creating a\n * file handle, which can only be accessed the system itself and the user uploading the file.\n */\nexport const BasicFileHandleUpload = forwardRef(function FileHandleUpload(\n props: BasicFileHandleUploadProps,\n ref: ForwardedRef<FileUploadHandle>,\n) {\n const {\n allowMultipleUpload,\n onStateChange = noop,\n onUploadReady = noop,\n onFileUploadComplete = noop,\n } = props\n\n const { startUpload, state, uploadProgress } = useUploadFiles({\n onUploadComplete: (_, fileHandleId) => {\n onFileUploadComplete(fileHandleId)\n return Promise.resolve()\n },\n })\n\n useEffect(() => {\n onStateChange(state)\n }, [state, onStateChange])\n\n useEffect(() => {\n onUploadReady()\n }, [onUploadReady])\n\n function uploadFileList(fileList: ArrayLike<File>) {\n const args = Array.from(fileList).map(file => {\n return {\n file,\n }\n })\n startUpload(...args)\n }\n\n useImperativeHandle(ref, () => ({\n handleUploads: uploadFileList,\n }))\n\n return (\n <div>\n <UploadFilePanel\n onUploadFileList={uploadFileList}\n allowMultipleFiles={allowMultipleUpload}\n disableDragAndDrop={true}\n />\n <MultiFileUploadProgress\n uploaderState={state}\n uploadProgress={uploadProgress}\n />\n </div>\n )\n})\n"],"mappings":";;;;;;;AAqCA,IAAa,IAAwB,EAAW,SAC9C,GACA,GACA;CACA,IAAM,EACJ,wBACA,mBAAgB,GAChB,mBAAgB,GAChB,0BAAuB,MACrB,GAEE,EAAE,gBAAa,UAAO,sBAAmB,EAAe,EAC5D,mBAAmB,GAAG,OACpB,EAAqB,EAAa,EAC3B,QAAQ,SAAS,GAE3B,CAAC;AAMF,CAJA,QAAgB;AACd,IAAc,EAAM;IACnB,CAAC,GAAO,EAAc,CAAC,EAE1B,QAAgB;AACd,KAAe;IACd,CAAC,EAAc,CAAC;CAEnB,SAAS,EAAe,GAA2B;AAMjD,IAAY,GALC,MAAM,KAAK,EAAS,CAAC,KAAI,OAC7B,EACL,SACD,
|
|
1
|
+
{"version":3,"file":"BasicFileHandleUpload.js","names":[],"sources":["../../../../src/components/file/upload/BasicFileHandleUpload.tsx"],"sourcesContent":["import MultiFileUploadProgress from '@/components/file/upload/MultiFileUploadProgress'\nimport UploadFilePanel from '@/components/file/upload/UploadFilePanel'\nimport {\n UploaderState,\n useUploadFiles,\n} from '@/utils/hooks/useUploadFileEntity/useUploadFiles'\nimport { noop } from 'lodash-es'\nimport { ForwardedRef, forwardRef, useEffect, useImperativeHandle } from 'react'\n\nexport type BasicFileHandleUploadProps = {\n /**\n * Whether to allow uploading multiple files.\n * Currently, only single file upload is supported by this UI component.\n */\n allowMultipleUpload: false\n /**\n * Whether to disable \"drag-and-drop to upload\" functionality.\n * Currently, drag-and-drop cannot be enabled.\n */\n disableDragAndDrop: true\n /** Callback that is invoked when the state of the uploader changes */\n onStateChange?: (state: UploaderState) => void\n /** Callback that is invoked when component is ready to upload */\n onUploadReady?: () => void\n /** Callback that is invoked when an individual upload is complete */\n onFileUploadComplete?: (fileHandleIds: string) => void\n}\n\nexport type FileUploadHandle = {\n /** Programmatically add files to the upload (e.g. on drag & drop) */\n handleUploads: (fileList: ArrayLike<File>) => void\n}\n\n/**\n * BasicFileHandleUpload is a component that supports uploading a file to the default Synapse S3 bucket and creating a\n * file handle, which can only be accessed the system itself and the user uploading the file.\n */\nexport const BasicFileHandleUpload = forwardRef(function FileHandleUpload(\n props: BasicFileHandleUploadProps,\n ref: ForwardedRef<FileUploadHandle>,\n) {\n const {\n allowMultipleUpload,\n onStateChange = noop,\n onUploadReady = noop,\n onFileUploadComplete = noop,\n } = props\n\n const { startUpload, state, uploadProgress } = useUploadFiles({\n onUploadComplete: (_, fileHandleId) => {\n onFileUploadComplete(fileHandleId)\n return Promise.resolve()\n },\n })\n\n useEffect(() => {\n onStateChange(state)\n }, [state, onStateChange])\n\n useEffect(() => {\n onUploadReady()\n }, [onUploadReady])\n\n function uploadFileList(fileList: ArrayLike<File>) {\n const args = Array.from(fileList).map(file => {\n return {\n file,\n }\n })\n startUpload(...args)\n }\n\n useImperativeHandle(ref, () => ({\n handleUploads: uploadFileList,\n }))\n\n return (\n <div>\n <UploadFilePanel\n onUploadFileList={uploadFileList}\n allowMultipleFiles={allowMultipleUpload}\n disableDragAndDrop={true}\n />\n <MultiFileUploadProgress\n uploaderState={state}\n uploadProgress={uploadProgress}\n />\n </div>\n )\n})\n"],"mappings":";;;;;;;AAqCA,IAAa,IAAwB,EAAW,SAC9C,GACA,GACA;CACA,IAAM,EACJ,wBACA,mBAAgB,GAChB,mBAAgB,GAChB,0BAAuB,MACrB,GAEE,EAAE,gBAAa,UAAO,sBAAmB,EAAe,EAC5D,mBAAmB,GAAG,OACpB,EAAqB,EAAa,EAC3B,QAAQ,SAAS,GAE3B,CAAC;AAMF,CAJA,QAAgB;AACd,IAAc,EAAM;IACnB,CAAC,GAAO,EAAc,CAAC,EAE1B,QAAgB;AACd,KAAe;IACd,CAAC,EAAc,CAAC;CAEnB,SAAS,EAAe,GAA2B;AAMjD,IAAY,GALC,MAAM,KAAK,EAAS,CAAC,KAAI,OAC7B,EACL,SACD,EAEY,CAAK;;AAOtB,QAJA,EAAoB,UAAY,EAC9B,eAAe,GAChB,EAAE,EAGD,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,GAAD;EACE,kBAAkB;EAClB,oBAAoB;EACpB,oBAAoB;EACpB,CAAA,EACF,kBAAC,GAAD;EACE,eAAe;EACC;EAChB,CAAA,CACE,EAAA,CAAA;EAER"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type SWCHeaderProps = {
|
|
2
|
+
title: React.ReactNode;
|
|
3
|
+
description?: React.ReactNode;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* Header that uses CSS class names defined in SWC to match styling of SWC pages.
|
|
7
|
+
*/
|
|
8
|
+
export default function SWCHeader(props: SWCHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
//# sourceMappingURL=SWCHeader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SWCHeader.d.ts","sourceRoot":"","sources":["../../../src/components/layout/SWCHeader.tsx"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC9B,CAAA;AAED;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,KAAK,EAAE,cAAc,2CAQtD"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as e, jsxs as t } from "react/jsx-runtime";
|
|
2
|
+
//#region src/components/layout/SWCHeader.tsx
|
|
3
|
+
function n(n) {
|
|
4
|
+
let { title: r, description: i } = n;
|
|
5
|
+
return /* @__PURE__ */ t("div", {
|
|
6
|
+
className: "pageHeader",
|
|
7
|
+
children: [/* @__PURE__ */ e("h3", {
|
|
8
|
+
className: "pageHeaderTitle",
|
|
9
|
+
children: r
|
|
10
|
+
}), i && /* @__PURE__ */ e("div", {
|
|
11
|
+
className: "description",
|
|
12
|
+
children: i
|
|
13
|
+
})]
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { n as default };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=SWCHeader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SWCHeader.js","names":[],"sources":["../../../src/components/layout/SWCHeader.tsx"],"sourcesContent":["export type SWCHeaderProps = {\n title: React.ReactNode\n description?: React.ReactNode\n}\n\n/**\n * Header that uses CSS class names defined in SWC to match styling of SWC pages.\n */\nexport default function SWCHeader(props: SWCHeaderProps) {\n const { title, description } = props\n return (\n <div className={'pageHeader'}>\n <h3 className={'pageHeaderTitle'}>{title}</h3>\n {description && <div className=\"description\">{description}</div>}\n </div>\n )\n}\n"],"mappings":";;AAQA,SAAwB,EAAU,GAAuB;CACvD,IAAM,EAAE,UAAO,mBAAgB;AAC/B,QACE,kBAAC,OAAD;EAAK,WAAW;YAAhB,CACE,kBAAC,MAAD;GAAI,WAAW;aAAoB;GAAW,CAAA,EAC7C,KAAe,kBAAC,OAAD;GAAK,WAAU;aAAe;GAAkB,CAAA,CAC5D"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SWCHeaderProps } from './SWCHeader';
|
|
2
|
+
/**
|
|
3
|
+
* Page layout that uses CSS class names defined in SWC to match styling of SWC pages. This should not be used outside of SWC.
|
|
4
|
+
*/
|
|
5
|
+
export default function SWCPageLayout(props: {
|
|
6
|
+
header: SWCHeaderProps;
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
//# sourceMappingURL=SWCPageLayout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SWCPageLayout.d.ts","sourceRoot":"","sources":["../../../src/components/layout/SWCPageLayout.tsx"],"names":[],"mappings":"AAAA,OAAkB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAEvD;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,KAAK,EAAE;IAC3C,MAAM,EAAE,cAAc,CAAA;IACtB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B,2CASA"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import e from "./SWCHeader.js";
|
|
2
|
+
import { Fragment as t, jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
3
|
+
//#region src/components/layout/SWCPageLayout.tsx
|
|
4
|
+
function i(i) {
|
|
5
|
+
let { header: a, children: o } = i;
|
|
6
|
+
return /* @__PURE__ */ r(t, { children: [/* @__PURE__ */ n(e, { ...a }), /* @__PURE__ */ n("div", {
|
|
7
|
+
className: "pageLayout",
|
|
8
|
+
children: o
|
|
9
|
+
})] });
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { i as default };
|
|
13
|
+
|
|
14
|
+
//# sourceMappingURL=SWCPageLayout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SWCPageLayout.js","names":[],"sources":["../../../src/components/layout/SWCPageLayout.tsx"],"sourcesContent":["import SWCHeader, { SWCHeaderProps } from './SWCHeader'\n\n/**\n * Page layout that uses CSS class names defined in SWC to match styling of SWC pages. This should not be used outside of SWC.\n */\nexport default function SWCPageLayout(props: {\n header: SWCHeaderProps\n children: React.ReactNode\n}) {\n const { header, children } = props\n\n return (\n <>\n <SWCHeader {...header} />\n <div className=\"pageLayout\">{children}</div>\n </>\n )\n}\n"],"mappings":";;;AAKA,SAAwB,EAAc,GAGnC;CACD,IAAM,EAAE,WAAQ,gBAAa;AAE7B,QACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD,EAAW,GAAI,GAAU,CAAA,EACzB,kBAAC,OAAD;EAAK,WAAU;EAAc;EAAe,CAAA,CAC3C,EAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComplexMenu.js","names":[],"sources":["../../../src/components/menu/ComplexMenu.tsx"],"sourcesContent":["import { Box, Button, Typography, useMediaQuery, useTheme } from '@mui/material'\nimport { DropdownMenu, DropdownMenuProps } from './DropdownMenu'\nimport { IconSvgButton, IconSvgButtonProps } from '../IconSvgButton'\nimport IconSvg from '../IconSvg'\n\nexport type ComplexMenuProps = {\n /*\n * Configuration for IconButtons. Each entry corresponds to one button.\n * See the IconButtonConfiguration type for more info.\n */\n iconButtons?: IconSvgButtonProps[]\n /*\n * Configuration for DropdownMenus. Each entry corresponds to one dropdown menu button, which\n * itself can contain multiple groups of items.\n * See the DropdownMenuProps type for more info.\n */\n dropdownMenus?: DropdownMenuProps[]\n}\n\n/**\n * The ComplexMenu component allows you to create a generic menu with\n * icon buttons and multiple dropdown menus that contain groups of items.\n */\nexport function ComplexMenu(props: ComplexMenuProps) {\n const { iconButtons = [], dropdownMenus = [] } = props\n const theme = useTheme()\n const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm'))\n\n return (\n <Box\n sx={theme => ({\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n [theme.breakpoints.down('sm')]: {\n flexDirection: 'column',\n paddingTop: '10px',\n },\n })}\n >\n {iconButtons.map(iconButton =>\n isSmallScreen && iconButton.tooltipText ? (\n <Box\n sx={{\n width: '100%',\n textAlign: 'center',\n }}\n >\n <Button\n variant=\"text\"\n startIcon={\n <IconSvg\n key={iconButton.tooltipText}\n icon={iconButton.icon}\n wrap={false}\n fontSize={'inherit'}\n />\n }\n onClick={iconButton.onClick}\n sx={{\n padding: '6px 12px',\n minWidth: 'unset',\n }}\n >\n <Typography variant=\"buttonLink\">\n {iconButton.tooltipText}\n </Typography>\n </Button>\n </Box>\n ) : (\n <IconSvgButton key={iconButton.tooltipText} {...iconButton} />\n ),\n )}\n {dropdownMenus.map(\n (menuProps, index) =>\n menuProps.items &&\n menuProps.items.length > 0 && (\n <Box\n sx={theme => ({\n [theme.breakpoints.down('sm')]: {\n width: '100%',\n '.MuiButton-root': { width: '100%' },\n },\n })}\n >\n <DropdownMenu key={index} {...menuProps} />\n </Box>\n ),\n )}\n </Box>\n )\n}\n"],"mappings":";;;;;;AAuBA,SAAgB,EAAY,GAAyB;CACnD,IAAM,EAAE,iBAAc,EAAE,EAAE,mBAAgB,EAAE,KAAK,GAE3C,IAAgB,EADR,
|
|
1
|
+
{"version":3,"file":"ComplexMenu.js","names":[],"sources":["../../../src/components/menu/ComplexMenu.tsx"],"sourcesContent":["import { Box, Button, Typography, useMediaQuery, useTheme } from '@mui/material'\nimport { DropdownMenu, DropdownMenuProps } from './DropdownMenu'\nimport { IconSvgButton, IconSvgButtonProps } from '../IconSvgButton'\nimport IconSvg from '../IconSvg'\n\nexport type ComplexMenuProps = {\n /*\n * Configuration for IconButtons. Each entry corresponds to one button.\n * See the IconButtonConfiguration type for more info.\n */\n iconButtons?: IconSvgButtonProps[]\n /*\n * Configuration for DropdownMenus. Each entry corresponds to one dropdown menu button, which\n * itself can contain multiple groups of items.\n * See the DropdownMenuProps type for more info.\n */\n dropdownMenus?: DropdownMenuProps[]\n}\n\n/**\n * The ComplexMenu component allows you to create a generic menu with\n * icon buttons and multiple dropdown menus that contain groups of items.\n */\nexport function ComplexMenu(props: ComplexMenuProps) {\n const { iconButtons = [], dropdownMenus = [] } = props\n const theme = useTheme()\n const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm'))\n\n return (\n <Box\n sx={theme => ({\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n [theme.breakpoints.down('sm')]: {\n flexDirection: 'column',\n paddingTop: '10px',\n },\n })}\n >\n {iconButtons.map(iconButton =>\n isSmallScreen && iconButton.tooltipText ? (\n <Box\n sx={{\n width: '100%',\n textAlign: 'center',\n }}\n >\n <Button\n variant=\"text\"\n startIcon={\n <IconSvg\n key={iconButton.tooltipText}\n icon={iconButton.icon}\n wrap={false}\n fontSize={'inherit'}\n />\n }\n onClick={iconButton.onClick}\n sx={{\n padding: '6px 12px',\n minWidth: 'unset',\n }}\n >\n <Typography variant=\"buttonLink\">\n {iconButton.tooltipText}\n </Typography>\n </Button>\n </Box>\n ) : (\n <IconSvgButton key={iconButton.tooltipText} {...iconButton} />\n ),\n )}\n {dropdownMenus.map(\n (menuProps, index) =>\n menuProps.items &&\n menuProps.items.length > 0 && (\n <Box\n sx={theme => ({\n [theme.breakpoints.down('sm')]: {\n width: '100%',\n '.MuiButton-root': { width: '100%' },\n },\n })}\n >\n <DropdownMenu key={index} {...menuProps} />\n </Box>\n ),\n )}\n </Box>\n )\n}\n"],"mappings":";;;;;;AAuBA,SAAgB,EAAY,GAAyB;CACnD,IAAM,EAAE,iBAAc,EAAE,EAAE,mBAAgB,EAAE,KAAK,GAE3C,IAAgB,EADR,GACsB,CAAM,YAAY,KAAK,KAAK,CAAC;AAEjE,QACE,kBAAC,GAAD;EACE,KAAI,OAAU;GACZ,SAAS;GACT,YAAY;GACZ,KAAK;IACJ,EAAM,YAAY,KAAK,KAAK,GAAG;IAC9B,eAAe;IACf,YAAY;IACb;GACF;YATH,CAWG,EAAY,KAAI,MACf,KAAiB,EAAW,cAC1B,kBAAC,GAAD;GACE,IAAI;IACF,OAAO;IACP,WAAW;IACZ;aAED,kBAAC,GAAD;IACE,SAAQ;IACR,WACE,kBAAC,GAAD;KAEE,MAAM,EAAW;KACjB,MAAM;KACN,UAAU;KACV,EAJK,EAAW,YAIhB;IAEJ,SAAS,EAAW;IACpB,IAAI;KACF,SAAS;KACT,UAAU;KACX;cAED,kBAAC,GAAD;KAAY,SAAQ;eACjB,EAAW;KACD,CAAA;IACN,CAAA;GACL,CAAA,GAEN,kBAAC,GAAD,EAA4C,GAAI,GAAc,EAA1C,EAAW,YAA+B,CAEjE,EACA,EAAc,KACZ,GAAW,MACV,EAAU,SACV,EAAU,MAAM,SAAS,KACvB,kBAAC,GAAD;GACE,KAAI,OAAU,GACX,EAAM,YAAY,KAAK,KAAK,GAAG;IAC9B,OAAO;IACP,mBAAmB,EAAE,OAAO,QAAQ;IACrC,EACF;aAED,kBAAC,GAAD,EAA0B,GAAI,GAAa,EAAxB,EAAwB;GACvC,CAAA,CAEX,CACG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChipContainer.js","names":[],"sources":["../../../../src/components/row_renderers/utils/ChipContainer.tsx"],"sourcesContent":["import React from 'react'\ntype ChipContainerProps = {\n chips: any[]\n}\n\nconst ChipContainer = ({ chips }: ChipContainerProps): React.ReactNode => {\n const chipsFormatted = chips.map((el, index) => {\n if (!el) {\n return false\n }\n return <span key={index}> {el}</span>\n })\n return <>{chipsFormatted}</>\n}\nexport default ChipContainer\n"],"mappings":";;;AAKA,IAAM,KAAiB,EAAE,eAOhB,kBAAA,GAAA,EAAA,UANgB,EAAM,KAAK,GAAI,MAC/B,IAGE,kBAAC,QAAD,EAAA,UAAA,CAAkB,KAAE,EAAU,EAAA,EAAnB,EAAmB,GAF5B,
|
|
1
|
+
{"version":3,"file":"ChipContainer.js","names":[],"sources":["../../../../src/components/row_renderers/utils/ChipContainer.tsx"],"sourcesContent":["import React from 'react'\ntype ChipContainerProps = {\n chips: any[]\n}\n\nconst ChipContainer = ({ chips }: ChipContainerProps): React.ReactNode => {\n const chipsFormatted = chips.map((el, index) => {\n if (!el) {\n return false\n }\n return <span key={index}> {el}</span>\n })\n return <>{chipsFormatted}</>\n}\nexport default ChipContainer\n"],"mappings":";;;AAKA,IAAM,KAAiB,EAAE,eAOhB,kBAAA,GAAA,EAAA,UANgB,EAAM,KAAK,GAAI,MAC/B,IAGE,kBAAC,QAAD,EAAA,UAAA,CAAkB,KAAE,EAAU,EAAA,EAAnB,EAAmB,GAF5B,GAID,EAAkB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StyledPopover.js","names":[],"sources":["../../../src/components/styled/StyledPopover.tsx"],"sourcesContent":["import LightTooltip from '@/components/styled/LightTooltip'\nimport { spreadSx } from '@/theme/spreadSx'\nimport {\n Box,\n Button,\n ButtonProps,\n SxProps,\n tooltipClasses,\n TooltipProps,\n} from '@mui/material'\nimport { atom, useAtom } from 'jotai'\nimport { PropsWithChildren, ReactNode, useId } from 'react'\n\nexport type StyledPopoverProps = PropsWithChildren<{\n popoverContent: React.ReactNode\n sx?: TooltipProps['sx']\n placement?: TooltipProps['placement']\n showCloseButton?: boolean\n actionButton?: {\n content: ReactNode\n color?: ButtonProps['color']\n variant?: ButtonProps['variant']\n onClick: () => void\n closePopoverOnClick?: boolean\n }\n maxWidth?: string\n minWidth?: string\n containerSx?: SxProps\n}>\n\nconst buttonBoxSx: SxProps = {\n mt: 2,\n display: 'flex',\n justifyContent: 'space-between',\n flexDirection: 'row-reverse',\n '> button': {\n flexGrow: 1,\n maxWidth: '45%',\n },\n}\n\n// Register a global atom to track which popover is open, to ensure only one is shown at any given time\nconst openMarkdownPopoverAtom = atom<string | null>(null)\n\nexport function StyledPopover({\n children,\n popoverContent,\n placement = 'bottom-start',\n showCloseButton = true,\n actionButton,\n sx,\n maxWidth = '500px',\n minWidth = '300px',\n containerSx,\n}: StyledPopoverProps) {\n const id = useId()\n const [openMarkdownPopoverId, setOpenMarkdownPopoverId] = useAtom(\n openMarkdownPopoverAtom,\n )\n\n const show = openMarkdownPopoverId === id\n\n const content = (\n <Box sx={{ padding: '20px' }}>\n {popoverContent}\n <Box sx={buttonBoxSx}>\n {actionButton && (\n <Button\n color={actionButton.color || 'primary'}\n variant={actionButton.variant || 'contained'}\n onClick={() => {\n actionButton.onClick()\n if (actionButton.closePopoverOnClick) {\n setOpenMarkdownPopoverId(null)\n }\n }}\n >\n {actionButton.content}\n </Button>\n )}\n {showCloseButton && (\n <Button\n variant=\"outlined\"\n onClick={() => setOpenMarkdownPopoverId(null)}\n >\n Close\n </Button>\n )}\n </Box>\n </Box>\n )\n\n return (\n <LightTooltip\n title={content}\n placement={placement}\n open={show}\n sx={spreadSx(sx, {\n [`& .${tooltipClasses.tooltip}`]: {\n maxWidth: { maxWidth },\n minWidth: { minWidth },\n },\n })}\n >\n <Box\n role=\"button\"\n className={'PopoverContainer'}\n onClick={e => {\n // Prevent the default action of the click event -- for example, if this is in a `label` tag for a checkbox,\n // prevent the click from toggling the checkbox value\n e.preventDefault()\n // Prevent the click from propagating to the parent container\n e.stopPropagation()\n setOpenMarkdownPopoverId(currentId => (currentId == id ? null : id))\n }}\n sx={{ display: 'inline-block', cursor: 'pointer', ...containerSx }}\n >\n {children}\n </Box>\n </LightTooltip>\n )\n}\n"],"mappings":";;;;;;;AA8BA,IAAM,IAAuB;CAC3B,IAAI;CACJ,SAAS;CACT,gBAAgB;CAChB,eAAe;CACf,YAAY;EACV,UAAU;EACV,UAAU;EACX;CACF,EAGK,IAA0B,EAAoB,KAAK;AAEzD,SAAgB,EAAc,EAC5B,aACA,mBACA,eAAY,gBACZ,qBAAkB,IAClB,iBACA,OACA,cAAW,SACX,cAAW,SACX,kBACqB;CACrB,IAAM,IAAK,GAAO,EACZ,CAAC,GAAuB,KAA4B,EACxD,EACD,EAEK,IAAO,MAA0B;AAgCvC,QACE,kBAAC,GAAD;EACE,OA/BF,kBAAC,GAAD;GAAK,IAAI,EAAE,SAAS,QAAQ;aAA5B,CACG,GACD,kBAAC,GAAD;IAAK,IAAI;cAAT,CACG,KACC,kBAAC,GAAD;KACE,OAAO,EAAa,SAAS;KAC7B,SAAS,EAAa,WAAW;KACjC,eAAe;AAEb,MADA,EAAa,SAAS,EAClB,EAAa,uBACf,EAAyB,KAAK;;eAIjC,EAAa;KACP,CAAA,EAEV,KACC,kBAAC,GAAD;KACE,SAAQ;KACR,eAAe,EAAyB,KAAK;eAC9C;KAEQ,CAAA,CAEP;MACF
|
|
1
|
+
{"version":3,"file":"StyledPopover.js","names":[],"sources":["../../../src/components/styled/StyledPopover.tsx"],"sourcesContent":["import LightTooltip from '@/components/styled/LightTooltip'\nimport { spreadSx } from '@/theme/spreadSx'\nimport {\n Box,\n Button,\n ButtonProps,\n SxProps,\n tooltipClasses,\n TooltipProps,\n} from '@mui/material'\nimport { atom, useAtom } from 'jotai'\nimport { PropsWithChildren, ReactNode, useId } from 'react'\n\nexport type StyledPopoverProps = PropsWithChildren<{\n popoverContent: React.ReactNode\n sx?: TooltipProps['sx']\n placement?: TooltipProps['placement']\n showCloseButton?: boolean\n actionButton?: {\n content: ReactNode\n color?: ButtonProps['color']\n variant?: ButtonProps['variant']\n onClick: () => void\n closePopoverOnClick?: boolean\n }\n maxWidth?: string\n minWidth?: string\n containerSx?: SxProps\n}>\n\nconst buttonBoxSx: SxProps = {\n mt: 2,\n display: 'flex',\n justifyContent: 'space-between',\n flexDirection: 'row-reverse',\n '> button': {\n flexGrow: 1,\n maxWidth: '45%',\n },\n}\n\n// Register a global atom to track which popover is open, to ensure only one is shown at any given time\nconst openMarkdownPopoverAtom = atom<string | null>(null)\n\nexport function StyledPopover({\n children,\n popoverContent,\n placement = 'bottom-start',\n showCloseButton = true,\n actionButton,\n sx,\n maxWidth = '500px',\n minWidth = '300px',\n containerSx,\n}: StyledPopoverProps) {\n const id = useId()\n const [openMarkdownPopoverId, setOpenMarkdownPopoverId] = useAtom(\n openMarkdownPopoverAtom,\n )\n\n const show = openMarkdownPopoverId === id\n\n const content = (\n <Box sx={{ padding: '20px' }}>\n {popoverContent}\n <Box sx={buttonBoxSx}>\n {actionButton && (\n <Button\n color={actionButton.color || 'primary'}\n variant={actionButton.variant || 'contained'}\n onClick={() => {\n actionButton.onClick()\n if (actionButton.closePopoverOnClick) {\n setOpenMarkdownPopoverId(null)\n }\n }}\n >\n {actionButton.content}\n </Button>\n )}\n {showCloseButton && (\n <Button\n variant=\"outlined\"\n onClick={() => setOpenMarkdownPopoverId(null)}\n >\n Close\n </Button>\n )}\n </Box>\n </Box>\n )\n\n return (\n <LightTooltip\n title={content}\n placement={placement}\n open={show}\n sx={spreadSx(sx, {\n [`& .${tooltipClasses.tooltip}`]: {\n maxWidth: { maxWidth },\n minWidth: { minWidth },\n },\n })}\n >\n <Box\n role=\"button\"\n className={'PopoverContainer'}\n onClick={e => {\n // Prevent the default action of the click event -- for example, if this is in a `label` tag for a checkbox,\n // prevent the click from toggling the checkbox value\n e.preventDefault()\n // Prevent the click from propagating to the parent container\n e.stopPropagation()\n setOpenMarkdownPopoverId(currentId => (currentId == id ? null : id))\n }}\n sx={{ display: 'inline-block', cursor: 'pointer', ...containerSx }}\n >\n {children}\n </Box>\n </LightTooltip>\n )\n}\n"],"mappings":";;;;;;;AA8BA,IAAM,IAAuB;CAC3B,IAAI;CACJ,SAAS;CACT,gBAAgB;CAChB,eAAe;CACf,YAAY;EACV,UAAU;EACV,UAAU;EACX;CACF,EAGK,IAA0B,EAAoB,KAAK;AAEzD,SAAgB,EAAc,EAC5B,aACA,mBACA,eAAY,gBACZ,qBAAkB,IAClB,iBACA,OACA,cAAW,SACX,cAAW,SACX,kBACqB;CACrB,IAAM,IAAK,GAAO,EACZ,CAAC,GAAuB,KAA4B,EACxD,EACD,EAEK,IAAO,MAA0B;AAgCvC,QACE,kBAAC,GAAD;EACE,OA/BF,kBAAC,GAAD;GAAK,IAAI,EAAE,SAAS,QAAQ;aAA5B,CACG,GACD,kBAAC,GAAD;IAAK,IAAI;cAAT,CACG,KACC,kBAAC,GAAD;KACE,OAAO,EAAa,SAAS;KAC7B,SAAS,EAAa,WAAW;KACjC,eAAe;AAEb,MADA,EAAa,SAAS,EAClB,EAAa,uBACf,EAAyB,KAAK;;eAIjC,EAAa;KACP,CAAA,EAEV,KACC,kBAAC,GAAD;KACE,SAAQ;KACR,eAAe,EAAyB,KAAK;eAC9C;KAEQ,CAAA,CAEP;MACF;IAKG;EACI;EACX,MAAM;EACN,IAAI,EAAS,GAAI,GACd,MAAM,EAAe,YAAY;GAChC,UAAU,EAAE,aAAU;GACtB,UAAU,EAAE,aAAU;GACvB,EACF,CAAC;YAEF,kBAAC,GAAD;GACE,MAAK;GACL,WAAW;GACX,UAAS,MAAK;AAMZ,IAHA,EAAE,gBAAgB,EAElB,EAAE,iBAAiB,EACnB,GAAyB,MAAc,KAAa,IAAK,OAAO,EAAI;;GAEtE,IAAI;IAAE,SAAS;IAAgB,QAAQ;IAAW,GAAG;IAAa;GAEjE;GACG,CAAA;EACO,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CsvPreview.js","names":[],"sources":["../../../../src/components/table/CsvPreview/CsvPreview.tsx"],"sourcesContent":["import { ErrorBanner } from '@/components/index'\nimport ColumnHeader from '@/components/TanStackTable/ColumnHeader'\nimport StyledTanStackTable from '@/components/TanStackTable/StyledTanStackTable'\nimport { useGetCsvPreview } from '@/synapse-queries/table/useGetCsvPreview'\nimport Typography from '@mui/material/Typography'\nimport {\n ColumnModel,\n CsvTableDescriptor,\n TableRow,\n UploadToTablePreviewResult,\n} from '@sage-bionetworks/synapse-client'\nimport {\n createColumnHelper,\n getCoreRowModel,\n useReactTable,\n} from '@tanstack/react-table'\nimport noop from 'lodash-es/noop'\nimport { useEffect, useMemo } from 'react'\n\nexport type CsvPreviewProps = {\n fileHandleId: string\n csvTableDescriptor: CsvTableDescriptor\n onCsvPreviewDataChange?: (data: UploadToTablePreviewResult) => void\n onIsLoadingChange?: (isLoading: boolean) => void\n}\n\n/**\n * Given a file handle ID and CSV Table Descriptor, fetches and displays a preview of the CSV file as it would be parsed into a table.\n */\nexport default function CsvPreview(props: CsvPreviewProps) {\n const {\n fileHandleId,\n csvTableDescriptor,\n onCsvPreviewDataChange = noop,\n onIsLoadingChange = noop,\n } = props\n\n const {\n data: csvPreviewData,\n isLoading,\n error,\n } = useGetCsvPreview({\n concreteType:\n 'org.sagebionetworks.repo.model.table.UploadToTablePreviewRequest',\n uploadFileHandleId: fileHandleId,\n csvTableDescriptor,\n })\n\n useEffect(() => {\n if (csvPreviewData) {\n onCsvPreviewDataChange(csvPreviewData)\n }\n }, [csvPreviewData, onCsvPreviewDataChange])\n\n useEffect(() => {\n onIsLoadingChange(isLoading)\n }, [isLoading, onIsLoadingChange])\n\n const tableData = useMemo(\n () => csvPreviewData?.sampleRows ?? [],\n [csvPreviewData?.sampleRows],\n )\n\n const columns = useMemo(\n () => getPreviewColumns(csvPreviewData?.suggestedColumns ?? []),\n [csvPreviewData?.suggestedColumns],\n )\n\n const table = useReactTable({\n getCoreRowModel: getCoreRowModel(),\n data: tableData,\n columns: columns,\n })\n\n if (error) {\n return <ErrorBanner error={error} />\n }\n\n return (\n <>\n {isLoading && <div>Loading preview...</div>}\n {!isLoading && csvPreviewData && table && (\n <>\n <Typography variant={'body1'}>\n Scanned {csvPreviewData?.rowsScanned?.toLocaleString()} rows to\n generate preview:\n </Typography>\n <StyledTanStackTable table={table} />\n </>\n )}\n </>\n )\n}\n\nfunction getPreviewColumns(columnModels: ColumnModel[]) {\n const columnHelper = createColumnHelper<TableRow>()\n return columnModels.map((columnModel, index) => {\n return columnHelper.accessor(tr => tr.values![index], {\n id: `column-${index}`,\n header: props => (\n <ColumnHeader\n {...props}\n title={`${columnModel.name}
|
|
1
|
+
{"version":3,"file":"CsvPreview.js","names":[],"sources":["../../../../src/components/table/CsvPreview/CsvPreview.tsx"],"sourcesContent":["import { ErrorBanner } from '@/components/index'\nimport ColumnHeader from '@/components/TanStackTable/ColumnHeader'\nimport StyledTanStackTable from '@/components/TanStackTable/StyledTanStackTable'\nimport { useGetCsvPreview } from '@/synapse-queries/table/useGetCsvPreview'\nimport Typography from '@mui/material/Typography'\nimport {\n ColumnModel,\n CsvTableDescriptor,\n TableRow,\n UploadToTablePreviewResult,\n} from '@sage-bionetworks/synapse-client'\nimport {\n createColumnHelper,\n getCoreRowModel,\n useReactTable,\n} from '@tanstack/react-table'\nimport noop from 'lodash-es/noop'\nimport { useEffect, useMemo } from 'react'\n\nexport type CsvPreviewProps = {\n fileHandleId: string\n csvTableDescriptor: CsvTableDescriptor\n onCsvPreviewDataChange?: (data: UploadToTablePreviewResult) => void\n onIsLoadingChange?: (isLoading: boolean) => void\n}\n\n/**\n * Given a file handle ID and CSV Table Descriptor, fetches and displays a preview of the CSV file as it would be parsed into a table.\n */\nexport default function CsvPreview(props: CsvPreviewProps) {\n const {\n fileHandleId,\n csvTableDescriptor,\n onCsvPreviewDataChange = noop,\n onIsLoadingChange = noop,\n } = props\n\n const {\n data: csvPreviewData,\n isLoading,\n error,\n } = useGetCsvPreview({\n concreteType:\n 'org.sagebionetworks.repo.model.table.UploadToTablePreviewRequest',\n uploadFileHandleId: fileHandleId,\n csvTableDescriptor,\n })\n\n useEffect(() => {\n if (csvPreviewData) {\n onCsvPreviewDataChange(csvPreviewData)\n }\n }, [csvPreviewData, onCsvPreviewDataChange])\n\n useEffect(() => {\n onIsLoadingChange(isLoading)\n }, [isLoading, onIsLoadingChange])\n\n const tableData = useMemo(\n () => csvPreviewData?.sampleRows ?? [],\n [csvPreviewData?.sampleRows],\n )\n\n const columns = useMemo(\n () => getPreviewColumns(csvPreviewData?.suggestedColumns ?? []),\n [csvPreviewData?.suggestedColumns],\n )\n\n const table = useReactTable({\n getCoreRowModel: getCoreRowModel(),\n data: tableData,\n columns: columns,\n })\n\n if (error) {\n return <ErrorBanner error={error} />\n }\n\n return (\n <>\n {isLoading && <div>Loading preview...</div>}\n {!isLoading && csvPreviewData && table && (\n <>\n <Typography variant={'body1'}>\n Scanned {csvPreviewData?.rowsScanned?.toLocaleString()} rows to\n generate preview:\n </Typography>\n <StyledTanStackTable table={table} />\n </>\n )}\n </>\n )\n}\n\nfunction getPreviewColumns(columnModels: ColumnModel[]) {\n const columnHelper = createColumnHelper<TableRow>()\n return columnModels.map((columnModel, index) => {\n return columnHelper.accessor(tr => tr.values![index], {\n id: `column-${index}`,\n header: props => (\n <ColumnHeader\n {...props}\n wrap={true}\n title={`${columnModel.name}\\n(${columnModel.columnType})`}\n />\n ),\n enableColumnFilter: false,\n enableSorting: false,\n })\n })\n}\n"],"mappings":";;;;;;;;;;;AA6BA,SAAwB,EAAW,GAAwB;CACzD,IAAM,EACJ,iBACA,uBACA,4BAAyB,GACzB,uBAAoB,MAClB,GAEE,EACJ,MAAM,GACN,cACA,aACE,EAAiB;EACnB,cACE;EACF,oBAAoB;EACpB;EACD,CAAC;AAQF,CANA,QAAgB;AACd,EAAI,KACF,EAAuB,EAAe;IAEvC,CAAC,GAAgB,EAAuB,CAAC,EAE5C,QAAgB;AACd,IAAkB,EAAU;IAC3B,CAAC,GAAW,EAAkB,CAAC;CAElC,IAAM,IAAY,QACV,GAAgB,cAAc,EAAE,EACtC,CAAC,GAAgB,WAAW,CAC7B,EAEK,IAAU,QACR,EAAkB,GAAgB,oBAAoB,EAAE,CAAC,EAC/D,CAAC,GAAgB,iBAAiB,CACnC,EAEK,IAAQ,EAAc;EAC1B,iBAAiB,GAAiB;EAClC,MAAM;EACG;EACV,CAAC;AAMF,QAJI,IACK,kBAAC,GAAD,EAAoB,UAAS,CAAA,GAIpC,kBAAA,GAAA,EAAA,UAAA,CACG,KAAa,kBAAC,OAAD,EAAA,UAAK,sBAAwB,CAAA,EAC1C,CAAC,KAAa,KAAkB,KAC/B,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;EAAY,SAAS;YAArB;GAA8B;GACnB,GAAgB,aAAa,gBAAgB;GAAC;GAE5C;KACb,kBAAC,GAAD,EAA4B,UAAS,CAAA,CACpC,EAAA,CAAA,CAEJ,EAAA,CAAA;;AAIP,SAAS,EAAkB,GAA6B;CACtD,IAAM,IAAe,GAA8B;AACnD,QAAO,EAAa,KAAK,GAAa,MAC7B,EAAa,UAAS,MAAM,EAAG,OAAQ,IAAQ;EACpD,IAAI,UAAU;EACd,SAAQ,MACN,kBAAC,GAAD;GACE,GAAI;GACJ,MAAM;GACN,OAAO,GAAG,EAAY,KAAK,KAAK,EAAY,WAAW;GACvD,CAAA;EAEJ,oBAAoB;EACpB,eAAe;EAChB,CAAC,CACF"}
|