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":"FeaturedResearch.js","names":[],"sources":["../../../src/components/FeaturedResearch/FeaturedResearch.tsx"],"sourcesContent":["import React from 'react'\nimport useGetQueryResultBundle from '@/synapse-queries/entity/useGetQueryResultBundle'\nimport { formatDate } from '@/utils/functions/DateFormatter'\nimport { getFieldIndex } from '@/utils/functions/queryUtils'\nimport { parseEntityIdFromSqlStatement } from '@/utils/functions/SqlFunctions'\nimport { useImageUrl } from '@/utils/hooks/useImageUrlUtils'\nimport * as SynapseConstants from '@/utils/SynapseConstants'\nimport {\n Box,\n CardMedia,\n Fade,\n Link,\n Skeleton,\n Stack,\n Typography,\n} from '@mui/material'\nimport { QueryBundleRequest, Row } from '@sage-bionetworks/synapse-types'\nimport dayjs from 'dayjs'\nimport { useInView } from 'react-intersection-observer'\nimport PortalSectionHeader from '../PortalSectionHeader'\n\nconst transitionTimeoutMs = 400\n\nexport type FeaturedResearchProps = {\n sql: string\n}\n\nexport type FeaturedResearchCardProps = {\n research: Row\n entityId: string\n isLoading: boolean\n publicationDateColIndex: number\n titleColIndex: number\n descriptionColIndex: number\n linkColIndex: number\n imageColIndex: number\n}\n\nconst FeaturedResearchCard = ({\n research,\n entityId,\n publicationDateColIndex,\n titleColIndex,\n linkColIndex,\n imageColIndex,\n isLoading,\n}: FeaturedResearchCardProps): React.ReactNode => {\n const fileId = research.values[imageColIndex] ?? ''\n const url = useImageUrl(fileId ?? '', entityId)\n if (isLoading) {\n return <Skeleton variant=\"rectangular\" height={142} width=\"100%\" />\n }\n return (\n <Box\n sx={{\n display: 'flex',\n gap: '30px',\n borderBottom: '1px solid',\n padding: '24px 0',\n borderColor: 'grey.300',\n flexDirection: {\n xs: 'column',\n sm: 'row',\n },\n }}\n >\n <Stack\n useFlexGap\n sx={{\n gap: '10px',\n }}\n >\n <Typography\n variant=\"headline2\"\n sx={{\n color: 'gray.1000',\n fontSize: '21px',\n }}\n >\n <Link\n href={research.values[linkColIndex] ?? ''}\n target=\"_blank\"\n sx={{\n color: 'grey.1000',\n textDecoration: 'none',\n '&:hover': {\n textDecoration: 'none',\n },\n }}\n >\n {research.values[titleColIndex]}\n </Link>\n </Typography>\n <Typography\n sx={{\n lineHeight: 'normal',\n color: 'grey.600',\n }}\n >\n {research.values[publicationDateColIndex] &&\n formatDate(\n dayjs(Number(research.values[publicationDateColIndex])),\n 'MMMM, YYYY',\n )}\n </Typography>\n </Stack>\n <CardMedia\n component=\"img\"\n image={url}\n aria-hidden=\"true\"\n sx={{\n flexShrink: 0,\n width: '140px',\n height: '93.8px',\n borderRadius: '6px',\n objectFit: 'cover',\n marginLeft: { xs: 'initial', sm: 'auto' },\n }}\n />\n </Box>\n )\n}\n\nconst FeaturedResearchTopCard = ({\n research,\n entityId,\n titleColIndex,\n descriptionColIndex,\n linkColIndex,\n imageColIndex,\n isLoading,\n}: FeaturedResearchCardProps): React.ReactNode => {\n const [ref, inView] = useInView({ threshold: 0.3, triggerOnce: true })\n const fileId = research.values[imageColIndex] ?? ''\n const url = useImageUrl(fileId || '', entityId)\n if (isLoading) {\n return (\n <Skeleton\n variant=\"rectangular\"\n width=\"100%\"\n sx={{\n height: { xs: '250px', sm: '500px', md: '600px', lg: '800px' },\n }}\n />\n )\n }\n return (\n <Box ref={ref}>\n <Fade in={inView} timeout={transitionTimeoutMs}>\n <CardMedia\n component=\"img\"\n image={url}\n aria-hidden=\"true\"\n sx={{\n objectFit: 'cover',\n borderRadius: '10px',\n marginBottom: '30px',\n }}\n />\n </Fade>\n <Stack\n useFlexGap\n sx={{\n gap: '16px',\n }}\n >\n <Typography\n variant=\"headline2\"\n sx={{ color: 'grey.1000', fontSize: { xs: '24px', md: '36px' } }}\n >\n <Link\n href={research.values[linkColIndex] ?? ''}\n target=\"_blank\"\n sx={{\n color: 'grey.1000',\n textDecoration: 'none',\n '&:hover': {\n textDecoration: 'none',\n },\n }}\n >\n {research.values[titleColIndex]}\n </Link>\n </Typography>\n <Typography\n sx={{\n fontSize: '18px',\n lineHeight: '22.4px',\n }}\n >\n {research.values[descriptionColIndex] ?? ''}\n </Typography>\n <Link href={research.values[linkColIndex] ?? ''} target={'_blank'}>\n Read more\n </Link>\n </Stack>\n </Box>\n )\n}\n\nfunction FeaturedResearch(props: FeaturedResearchProps) {\n const { sql } = props\n\n const entityId = parseEntityIdFromSqlStatement(sql)\n\n const queryBundleRequest: QueryBundleRequest = {\n partMask:\n SynapseConstants.BUNDLE_MASK_QUERY_SELECT_COLUMNS |\n SynapseConstants.BUNDLE_MASK_QUERY_RESULTS,\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n entityId,\n query: {\n sql,\n },\n }\n const { data: queryResultBundle, isLoading } =\n useGetQueryResultBundle(queryBundleRequest)\n\n const dataRows = queryResultBundle?.queryResult!.queryResults.rows ?? []\n\n enum ExpectedColumns {\n TITLE = 'title',\n DESCRIPTION = 'description',\n PUBLICATION_DATE = 'publicationDate',\n IMAGE = 'image',\n LINK = 'link',\n }\n\n const titleColIndex = getFieldIndex(ExpectedColumns.TITLE, queryResultBundle)\n const descriptionColIndex = getFieldIndex(\n ExpectedColumns.DESCRIPTION,\n queryResultBundle,\n )\n const publicationDateColIndex = getFieldIndex(\n ExpectedColumns.PUBLICATION_DATE,\n queryResultBundle,\n )\n const imageColIndex = getFieldIndex(ExpectedColumns.IMAGE, queryResultBundle)\n const linkColIndex = getFieldIndex(ExpectedColumns.LINK, queryResultBundle)\n\n const topCard = dataRows[0]\n const remainingCards = dataRows.slice(1)\n\n const featuredResearchHeader = (\n <PortalSectionHeader\n title=\"Featured Research\"\n sx={{\n h2: { fontSize: '24px', paddingBottom: 0, width: '100%' },\n }}\n />\n )\n\n return (\n <Box\n sx={{\n display: 'grid',\n gridTemplateColumns: { xs: '1fr', md: '1fr 1fr' },\n gap: { xs: '30px', md: '40px' },\n padding: { xs: '40px', lg: '80px' },\n }}\n >\n <Box sx={{ display: { md: 'none' } }}>{featuredResearchHeader}</Box>\n <Box>\n {topCard && (\n <FeaturedResearchTopCard\n entityId={entityId}\n research={topCard}\n titleColIndex={titleColIndex}\n isLoading={isLoading}\n descriptionColIndex={descriptionColIndex}\n publicationDateColIndex={publicationDateColIndex}\n imageColIndex={imageColIndex}\n linkColIndex={linkColIndex}\n />\n )}\n </Box>\n <Stack>\n <Box sx={{ display: { xs: 'none', md: 'block' } }}>\n {featuredResearchHeader}\n </Box>\n <Stack\n sx={{\n gap: '16px',\n }}\n >\n {remainingCards.map((research, index) => (\n <FeaturedResearchCard\n entityId={entityId}\n research={research}\n key={index}\n isLoading={isLoading}\n titleColIndex={titleColIndex}\n descriptionColIndex={descriptionColIndex}\n publicationDateColIndex={publicationDateColIndex}\n imageColIndex={imageColIndex}\n linkColIndex={linkColIndex}\n />\n ))}\n </Stack>\n </Stack>\n </Box>\n )\n}\n\nexport default FeaturedResearch\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FeaturedResearch.js","names":[],"sources":["../../../src/components/FeaturedResearch/FeaturedResearch.tsx"],"sourcesContent":["import React from 'react'\nimport useGetQueryResultBundle from '@/synapse-queries/entity/useGetQueryResultBundle'\nimport { formatDate } from '@/utils/functions/DateFormatter'\nimport { getFieldIndex } from '@/utils/functions/queryUtils'\nimport { parseEntityIdFromSqlStatement } from '@/utils/functions/SqlFunctions'\nimport { useImageUrl } from '@/utils/hooks/useImageUrlUtils'\nimport * as SynapseConstants from '@/utils/SynapseConstants'\nimport {\n Box,\n CardMedia,\n Fade,\n Link,\n Skeleton,\n Stack,\n Typography,\n} from '@mui/material'\nimport { QueryBundleRequest, Row } from '@sage-bionetworks/synapse-types'\nimport dayjs from 'dayjs'\nimport { useInView } from 'react-intersection-observer'\nimport PortalSectionHeader from '../PortalSectionHeader'\n\nconst transitionTimeoutMs = 400\n\nexport type FeaturedResearchProps = {\n sql: string\n}\n\nexport type FeaturedResearchCardProps = {\n research: Row\n entityId: string\n isLoading: boolean\n publicationDateColIndex: number\n titleColIndex: number\n descriptionColIndex: number\n linkColIndex: number\n imageColIndex: number\n}\n\nconst FeaturedResearchCard = ({\n research,\n entityId,\n publicationDateColIndex,\n titleColIndex,\n linkColIndex,\n imageColIndex,\n isLoading,\n}: FeaturedResearchCardProps): React.ReactNode => {\n const fileId = research.values[imageColIndex] ?? ''\n const url = useImageUrl(fileId ?? '', entityId)\n if (isLoading) {\n return <Skeleton variant=\"rectangular\" height={142} width=\"100%\" />\n }\n return (\n <Box\n sx={{\n display: 'flex',\n gap: '30px',\n borderBottom: '1px solid',\n padding: '24px 0',\n borderColor: 'grey.300',\n flexDirection: {\n xs: 'column',\n sm: 'row',\n },\n }}\n >\n <Stack\n useFlexGap\n sx={{\n gap: '10px',\n }}\n >\n <Typography\n variant=\"headline2\"\n sx={{\n color: 'gray.1000',\n fontSize: '21px',\n }}\n >\n <Link\n href={research.values[linkColIndex] ?? ''}\n target=\"_blank\"\n sx={{\n color: 'grey.1000',\n textDecoration: 'none',\n '&:hover': {\n textDecoration: 'none',\n },\n }}\n >\n {research.values[titleColIndex]}\n </Link>\n </Typography>\n <Typography\n sx={{\n lineHeight: 'normal',\n color: 'grey.600',\n }}\n >\n {research.values[publicationDateColIndex] &&\n formatDate(\n dayjs(Number(research.values[publicationDateColIndex])),\n 'MMMM, YYYY',\n )}\n </Typography>\n </Stack>\n <CardMedia\n component=\"img\"\n image={url}\n aria-hidden=\"true\"\n sx={{\n flexShrink: 0,\n width: '140px',\n height: '93.8px',\n borderRadius: '6px',\n objectFit: 'cover',\n marginLeft: { xs: 'initial', sm: 'auto' },\n }}\n />\n </Box>\n )\n}\n\nconst FeaturedResearchTopCard = ({\n research,\n entityId,\n titleColIndex,\n descriptionColIndex,\n linkColIndex,\n imageColIndex,\n isLoading,\n}: FeaturedResearchCardProps): React.ReactNode => {\n const [ref, inView] = useInView({ threshold: 0.3, triggerOnce: true })\n const fileId = research.values[imageColIndex] ?? ''\n const url = useImageUrl(fileId || '', entityId)\n if (isLoading) {\n return (\n <Skeleton\n variant=\"rectangular\"\n width=\"100%\"\n sx={{\n height: { xs: '250px', sm: '500px', md: '600px', lg: '800px' },\n }}\n />\n )\n }\n return (\n <Box ref={ref}>\n <Fade in={inView} timeout={transitionTimeoutMs}>\n <CardMedia\n component=\"img\"\n image={url}\n aria-hidden=\"true\"\n sx={{\n objectFit: 'cover',\n borderRadius: '10px',\n marginBottom: '30px',\n }}\n />\n </Fade>\n <Stack\n useFlexGap\n sx={{\n gap: '16px',\n }}\n >\n <Typography\n variant=\"headline2\"\n sx={{ color: 'grey.1000', fontSize: { xs: '24px', md: '36px' } }}\n >\n <Link\n href={research.values[linkColIndex] ?? ''}\n target=\"_blank\"\n sx={{\n color: 'grey.1000',\n textDecoration: 'none',\n '&:hover': {\n textDecoration: 'none',\n },\n }}\n >\n {research.values[titleColIndex]}\n </Link>\n </Typography>\n <Typography\n sx={{\n fontSize: '18px',\n lineHeight: '22.4px',\n }}\n >\n {research.values[descriptionColIndex] ?? ''}\n </Typography>\n <Link href={research.values[linkColIndex] ?? ''} target={'_blank'}>\n Read more\n </Link>\n </Stack>\n </Box>\n )\n}\n\nfunction FeaturedResearch(props: FeaturedResearchProps) {\n const { sql } = props\n\n const entityId = parseEntityIdFromSqlStatement(sql)\n\n const queryBundleRequest: QueryBundleRequest = {\n partMask:\n SynapseConstants.BUNDLE_MASK_QUERY_SELECT_COLUMNS |\n SynapseConstants.BUNDLE_MASK_QUERY_RESULTS,\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n entityId,\n query: {\n sql,\n },\n }\n const { data: queryResultBundle, isLoading } =\n useGetQueryResultBundle(queryBundleRequest)\n\n const dataRows = queryResultBundle?.queryResult!.queryResults.rows ?? []\n\n enum ExpectedColumns {\n TITLE = 'title',\n DESCRIPTION = 'description',\n PUBLICATION_DATE = 'publicationDate',\n IMAGE = 'image',\n LINK = 'link',\n }\n\n const titleColIndex = getFieldIndex(ExpectedColumns.TITLE, queryResultBundle)\n const descriptionColIndex = getFieldIndex(\n ExpectedColumns.DESCRIPTION,\n queryResultBundle,\n )\n const publicationDateColIndex = getFieldIndex(\n ExpectedColumns.PUBLICATION_DATE,\n queryResultBundle,\n )\n const imageColIndex = getFieldIndex(ExpectedColumns.IMAGE, queryResultBundle)\n const linkColIndex = getFieldIndex(ExpectedColumns.LINK, queryResultBundle)\n\n const topCard = dataRows[0]\n const remainingCards = dataRows.slice(1)\n\n const featuredResearchHeader = (\n <PortalSectionHeader\n title=\"Featured Research\"\n sx={{\n h2: { fontSize: '24px', paddingBottom: 0, width: '100%' },\n }}\n />\n )\n\n return (\n <Box\n sx={{\n display: 'grid',\n gridTemplateColumns: { xs: '1fr', md: '1fr 1fr' },\n gap: { xs: '30px', md: '40px' },\n padding: { xs: '40px', lg: '80px' },\n }}\n >\n <Box sx={{ display: { md: 'none' } }}>{featuredResearchHeader}</Box>\n <Box>\n {topCard && (\n <FeaturedResearchTopCard\n entityId={entityId}\n research={topCard}\n titleColIndex={titleColIndex}\n isLoading={isLoading}\n descriptionColIndex={descriptionColIndex}\n publicationDateColIndex={publicationDateColIndex}\n imageColIndex={imageColIndex}\n linkColIndex={linkColIndex}\n />\n )}\n </Box>\n <Stack>\n <Box sx={{ display: { xs: 'none', md: 'block' } }}>\n {featuredResearchHeader}\n </Box>\n <Stack\n sx={{\n gap: '16px',\n }}\n >\n {remainingCards.map((research, index) => (\n <FeaturedResearchCard\n entityId={entityId}\n research={research}\n key={index}\n isLoading={isLoading}\n titleColIndex={titleColIndex}\n descriptionColIndex={descriptionColIndex}\n publicationDateColIndex={publicationDateColIndex}\n imageColIndex={imageColIndex}\n linkColIndex={linkColIndex}\n />\n ))}\n </Stack>\n </Stack>\n </Box>\n )\n}\n\nexport default FeaturedResearch\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FeaturedToolsList.js","names":[],"sources":["../../../src/components/FeaturedToolsList/FeaturedToolsList.tsx"],"sourcesContent":["import useGetQueryResultBundle from '@/synapse-queries/entity/useGetQueryResultBundle'\nimport { SynapseConstants } from '@/utils'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport { getFieldIndex } from '@/utils/functions/queryUtils'\nimport { QueryBundleRequest } from '@sage-bionetworks/synapse-types'\nimport { useEffect, useState } from 'react'\nimport { ErrorBanner } from '../error/ErrorBanner'\nimport { FeaturedToolCard } from './FeaturedToolCard'\n\nexport type FeaturedToolsListProps = {\n entityId: string\n idColumnName: string\n nameColumnName: string\n descriptionColumnName: string\n typeColumnName: string\n dateColumnName?: string\n filterClause: string\n} & ( // for the link, either the toolDetailPageURL or the toolURLColumnName must be set\n | {\n toolDetailPageURL: string\n toolURLColumnName?: never\n }\n | {\n toolDetailPageURL?: never\n toolURLColumnName: string\n }\n)\n\ntype ToolData = {\n id: string\n name: string\n description: string\n type: string\n date?: string\n url?: string //set if URL is in toolURLColumnName, dynamic if pointing to a detail page\n}\n\n/**\n * Display a set of FeaturedToolCards (driven by a Table/View). Driven by the following annotations/column names:\n * 'id', 'name', 'type', and 'description'.\n */\nexport function FeaturedToolsList({\n entityId,\n toolDetailPageURL,\n toolURLColumnName,\n idColumnName = 'id',\n nameColumnName = 'name',\n descriptionColumnName = 'description',\n typeColumnName = 'type',\n dateColumnName,\n filterClause,\n}: FeaturedToolsListProps) {\n const sql = `SELECT * FROM ${entityId} ${filterClause} LIMIT 3`\n const queryBundleRequest: QueryBundleRequest = {\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n entityId,\n partMask:\n SynapseConstants.BUNDLE_MASK_QUERY_SELECT_COLUMNS |\n SynapseConstants.BUNDLE_MASK_QUERY_RESULTS,\n query: {\n sql,\n },\n }\n\n const { accessToken } = useSynapseContext()\n const [tools, setTools] = useState<ToolData[]>([])\n const [error, setError] = useState<Error>()\n const { data: queryResultBundle, error: queryError } =\n useGetQueryResultBundle(queryBundleRequest)\n\n useEffect(() => {\n const getData = () => {\n try {\n const idIndex = getFieldIndex(idColumnName, queryResultBundle)\n const nameColumnIndex = getFieldIndex(nameColumnName, queryResultBundle)\n const typeColumnIndex = getFieldIndex(typeColumnName, queryResultBundle)\n const descriptionColumnIndex = getFieldIndex(\n descriptionColumnName,\n queryResultBundle,\n )\n const dateColumnIndex = getFieldIndex(dateColumnName, queryResultBundle)\n const toolURLColumnIndex = getFieldIndex(\n toolURLColumnName,\n queryResultBundle,\n )\n const tools: ToolData[] =\n queryResultBundle?.queryResult!.queryResults.rows.map(row => {\n if (row.values.some(value => value === null)) {\n console.warn('Row has null value(s)')\n }\n // Cast to string, assuming there are no null values\n const values = row.values as string[]\n return {\n name: values[nameColumnIndex],\n description: values[descriptionColumnIndex],\n type: values[typeColumnIndex],\n id: values[idIndex],\n date: dateColumnName ? values[dateColumnIndex] : undefined,\n url: toolURLColumnName ? values[toolURLColumnIndex] : undefined,\n }\n }) ?? []\n if (queryError) {\n throw queryError\n }\n if (tools.length === 0) {\n // wait for data to load\n return\n }\n\n setTools(tools)\n } catch (error) {\n console.error(error)\n setError(error)\n }\n }\n getData()\n }, [\n entityId,\n accessToken,\n queryResultBundle,\n queryError,\n idColumnName,\n nameColumnName,\n typeColumnName,\n descriptionColumnName,\n dateColumnName,\n ])\n return error ? (\n <ErrorBanner error={error}></ErrorBanner>\n ) : (\n <div className=\"FeaturedToolList\">\n {tools.map(tool => {\n return (\n <FeaturedToolCard\n key={tool.id}\n name={tool.name}\n type={tool.type}\n description={tool.description}\n id={tool.id}\n date={tool.date}\n toolDetailPageURL={toolDetailPageURL}\n url={tool.url}\n />\n )\n })}\n </div>\n )\n}\n\nexport default FeaturedToolsList\n"],"mappings":";;;;;;;;;;AAyCA,SAAgB,EAAkB,EAChC,aACA,sBACA,sBACA,kBAAe,MACf,oBAAiB,QACjB,2BAAwB,eACxB,oBAAiB,QACjB,mBACA,mBACyB;CAEzB,IAAM,IAAyC;EAC7C,cAAc;EACd;EACA,UACE;EAEF,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"FeaturedToolsList.js","names":[],"sources":["../../../src/components/FeaturedToolsList/FeaturedToolsList.tsx"],"sourcesContent":["import useGetQueryResultBundle from '@/synapse-queries/entity/useGetQueryResultBundle'\nimport { SynapseConstants } from '@/utils'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport { getFieldIndex } from '@/utils/functions/queryUtils'\nimport { QueryBundleRequest } from '@sage-bionetworks/synapse-types'\nimport { useEffect, useState } from 'react'\nimport { ErrorBanner } from '../error/ErrorBanner'\nimport { FeaturedToolCard } from './FeaturedToolCard'\n\nexport type FeaturedToolsListProps = {\n entityId: string\n idColumnName: string\n nameColumnName: string\n descriptionColumnName: string\n typeColumnName: string\n dateColumnName?: string\n filterClause: string\n} & ( // for the link, either the toolDetailPageURL or the toolURLColumnName must be set\n | {\n toolDetailPageURL: string\n toolURLColumnName?: never\n }\n | {\n toolDetailPageURL?: never\n toolURLColumnName: string\n }\n)\n\ntype ToolData = {\n id: string\n name: string\n description: string\n type: string\n date?: string\n url?: string //set if URL is in toolURLColumnName, dynamic if pointing to a detail page\n}\n\n/**\n * Display a set of FeaturedToolCards (driven by a Table/View). Driven by the following annotations/column names:\n * 'id', 'name', 'type', and 'description'.\n */\nexport function FeaturedToolsList({\n entityId,\n toolDetailPageURL,\n toolURLColumnName,\n idColumnName = 'id',\n nameColumnName = 'name',\n descriptionColumnName = 'description',\n typeColumnName = 'type',\n dateColumnName,\n filterClause,\n}: FeaturedToolsListProps) {\n const sql = `SELECT * FROM ${entityId} ${filterClause} LIMIT 3`\n const queryBundleRequest: QueryBundleRequest = {\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n entityId,\n partMask:\n SynapseConstants.BUNDLE_MASK_QUERY_SELECT_COLUMNS |\n SynapseConstants.BUNDLE_MASK_QUERY_RESULTS,\n query: {\n sql,\n },\n }\n\n const { accessToken } = useSynapseContext()\n const [tools, setTools] = useState<ToolData[]>([])\n const [error, setError] = useState<Error>()\n const { data: queryResultBundle, error: queryError } =\n useGetQueryResultBundle(queryBundleRequest)\n\n useEffect(() => {\n const getData = () => {\n try {\n const idIndex = getFieldIndex(idColumnName, queryResultBundle)\n const nameColumnIndex = getFieldIndex(nameColumnName, queryResultBundle)\n const typeColumnIndex = getFieldIndex(typeColumnName, queryResultBundle)\n const descriptionColumnIndex = getFieldIndex(\n descriptionColumnName,\n queryResultBundle,\n )\n const dateColumnIndex = getFieldIndex(dateColumnName, queryResultBundle)\n const toolURLColumnIndex = getFieldIndex(\n toolURLColumnName,\n queryResultBundle,\n )\n const tools: ToolData[] =\n queryResultBundle?.queryResult!.queryResults.rows.map(row => {\n if (row.values.some(value => value === null)) {\n console.warn('Row has null value(s)')\n }\n // Cast to string, assuming there are no null values\n const values = row.values as string[]\n return {\n name: values[nameColumnIndex],\n description: values[descriptionColumnIndex],\n type: values[typeColumnIndex],\n id: values[idIndex],\n date: dateColumnName ? values[dateColumnIndex] : undefined,\n url: toolURLColumnName ? values[toolURLColumnIndex] : undefined,\n }\n }) ?? []\n if (queryError) {\n throw queryError\n }\n if (tools.length === 0) {\n // wait for data to load\n return\n }\n\n setTools(tools)\n } catch (error) {\n console.error(error)\n setError(error)\n }\n }\n getData()\n }, [\n entityId,\n accessToken,\n queryResultBundle,\n queryError,\n idColumnName,\n nameColumnName,\n typeColumnName,\n descriptionColumnName,\n dateColumnName,\n ])\n return error ? (\n <ErrorBanner error={error}></ErrorBanner>\n ) : (\n <div className=\"FeaturedToolList\">\n {tools.map(tool => {\n return (\n <FeaturedToolCard\n key={tool.id}\n name={tool.name}\n type={tool.type}\n description={tool.description}\n id={tool.id}\n date={tool.date}\n toolDetailPageURL={toolDetailPageURL}\n url={tool.url}\n />\n )\n })}\n </div>\n )\n}\n\nexport default FeaturedToolsList\n"],"mappings":";;;;;;;;;;AAyCA,SAAgB,EAAkB,EAChC,aACA,sBACA,sBACA,kBAAe,MACf,oBAAiB,QACjB,2BAAwB,eACxB,oBAAiB,QACjB,mBACA,mBACyB;CAEzB,IAAM,IAAyC;EAC7C,cAAc;EACd;EACA,UACE;EAEF,OAAO,EACL,sBARyB,EAAS,GAAG,EAAa,WASnD;EACF,EAEK,EAAE,mBAAgB,GAAmB,EACrC,CAAC,GAAO,KAAY,EAAqB,EAAE,CAAC,EAC5C,CAAC,GAAO,KAAY,GAAiB,EACrC,EAAE,MAAM,GAAmB,OAAO,MACtC,EAAwB,EAAmB;AA2D7C,QAzDA,QAAgB;AA6Cd,SA5CsB;AACpB,OAAI;IACF,IAAM,IAAU,EAAc,GAAc,EAAkB,EACxD,IAAkB,EAAc,GAAgB,EAAkB,EAClE,IAAkB,EAAc,GAAgB,EAAkB,EAClE,IAAyB,EAC7B,GACA,EACD,EACK,IAAkB,EAAc,GAAgB,EAAkB,EAClE,IAAqB,EACzB,GACA,EACD,EACK,IACJ,GAAmB,YAAa,aAAa,KAAK,KAAI,MAAO;AAC3D,KAAI,EAAI,OAAO,MAAK,MAAS,MAAU,KAAK,IAC1C,QAAQ,KAAK,wBAAwB;KAGvC,IAAM,IAAS,EAAI;AACnB,YAAO;MACL,MAAM,EAAO;MACb,aAAa,EAAO;MACpB,MAAM,EAAO;MACb,IAAI,EAAO;MACX,MAAM,IAAiB,EAAO,KAAmB,KAAA;MACjD,KAAK,IAAoB,EAAO,KAAsB,KAAA;MACvD;MACD,IAAI,EAAE;AACV,QAAI,EACF,OAAM;AAER,QAAI,EAAM,WAAW,EAEnB;AAGF,MAAS,EAAM;YACR,GAAO;AAEd,IADA,QAAQ,MAAM,EAAM,EACpB,EAAS,EAAM;;MAGV;IACR;EACD;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,EACK,IACL,kBAAC,GAAD,EAAoB,UAAqB,CAAA,GAEzC,kBAAC,OAAD;EAAK,WAAU;YACZ,EAAM,KAAI,MAEP,kBAAC,GAAD;GAEE,MAAM,EAAK;GACX,MAAM,EAAK;GACX,aAAa,EAAK;GAClB,IAAI,EAAK;GACT,MAAM,EAAK;GACQ;GACnB,KAAK,EAAK;GACV,EARK,EAAK,GAQV,CAEJ;EACE,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileHandleContentRenderer.js","names":[],"sources":["../../../src/components/FilePreview/FileHandleContentRenderer.tsx"],"sourcesContent":["import { useGetPresignedUrlContent } from '@/synapse-queries/file/useFiles'\nimport { MB } from '@/utils/SynapseConstants'\nimport {\n BatchFileRequest,\n FileHandle,\n FileHandleAssociation,\n} from '@sage-bionetworks/synapse-types'\nimport { SynapseSpinner } from '../LoadingScreen/LoadingScreen'\nimport HtmlPreview from './HtmlPreview/HtmlPreview'\nimport PdfPreview from './PdfPreview'\nimport { PreviewRendererType } from './PreviewRendererType'\n\nconst MAX_FILE_SIZE = 30 * MB\n\nexport type FileHandleContentRendererProps = {\n /** The file handle whose contents should be downloaded and rendered */\n fileHandle: FileHandle\n /** The association between the file handle and an object which will give the user permission to access the file data */\n fileHandleAssociation: FileHandleAssociation\n /** Informs how to render the file data */\n previewType: PreviewRendererType\n}\n\n/**\n * Fetches the content for and renders the contents of a file handle.\n * @param props\n * @returns\n */\nexport default function FileHandleContentRenderer(\n props: FileHandleContentRendererProps,\n) {\n const { fileHandle, fileHandleAssociation, previewType } = props\n\n const batchFileRequest: BatchFileRequest = {\n requestedFiles: [fileHandleAssociation],\n includePreSignedURLs: true,\n includeFileHandles: false,\n includePreviewPreSignedURLs: false,\n }\n\n const { data: content, isLoading } = useGetPresignedUrlContent(\n fileHandle,\n batchFileRequest,\n MAX_FILE_SIZE,\n { throwOnError: true },\n )\n\n if (isLoading) {\n return <SynapseSpinner />\n }\n if (previewType === PreviewRendererType.HTML) {\n return (\n <HtmlPreview rawHtml={content!} createdByUserId={fileHandle.createdBy} />\n )\n } else if (previewType === PreviewRendererType.PDF) {\n return (\n <PdfPreview\n fileHandle={fileHandle}\n fileHandleAssociation={fileHandleAssociation}\n />\n )\n } else {\n if (previewType !== PreviewRendererType.NONE) {\n console.warn(\n `Rendering a preview of type ${previewType} is not supported in Portals`,\n )\n }\n return <></>\n }\n}\n"],"mappings":";;;;;;;;AAYA,IAAM,IAAgB,KAAK;AAgB3B,SAAwB,EACtB,GACA;CACA,IAAM,EAAE,eAAY,0BAAuB,mBAAgB,GASrD,EAAE,MAAM,GAAS,iBAAc,EACnC,
|
|
1
|
+
{"version":3,"file":"FileHandleContentRenderer.js","names":[],"sources":["../../../src/components/FilePreview/FileHandleContentRenderer.tsx"],"sourcesContent":["import { useGetPresignedUrlContent } from '@/synapse-queries/file/useFiles'\nimport { MB } from '@/utils/SynapseConstants'\nimport {\n BatchFileRequest,\n FileHandle,\n FileHandleAssociation,\n} from '@sage-bionetworks/synapse-types'\nimport { SynapseSpinner } from '../LoadingScreen/LoadingScreen'\nimport HtmlPreview from './HtmlPreview/HtmlPreview'\nimport PdfPreview from './PdfPreview'\nimport { PreviewRendererType } from './PreviewRendererType'\n\nconst MAX_FILE_SIZE = 30 * MB\n\nexport type FileHandleContentRendererProps = {\n /** The file handle whose contents should be downloaded and rendered */\n fileHandle: FileHandle\n /** The association between the file handle and an object which will give the user permission to access the file data */\n fileHandleAssociation: FileHandleAssociation\n /** Informs how to render the file data */\n previewType: PreviewRendererType\n}\n\n/**\n * Fetches the content for and renders the contents of a file handle.\n * @param props\n * @returns\n */\nexport default function FileHandleContentRenderer(\n props: FileHandleContentRendererProps,\n) {\n const { fileHandle, fileHandleAssociation, previewType } = props\n\n const batchFileRequest: BatchFileRequest = {\n requestedFiles: [fileHandleAssociation],\n includePreSignedURLs: true,\n includeFileHandles: false,\n includePreviewPreSignedURLs: false,\n }\n\n const { data: content, isLoading } = useGetPresignedUrlContent(\n fileHandle,\n batchFileRequest,\n MAX_FILE_SIZE,\n { throwOnError: true },\n )\n\n if (isLoading) {\n return <SynapseSpinner />\n }\n if (previewType === PreviewRendererType.HTML) {\n return (\n <HtmlPreview rawHtml={content!} createdByUserId={fileHandle.createdBy} />\n )\n } else if (previewType === PreviewRendererType.PDF) {\n return (\n <PdfPreview\n fileHandle={fileHandle}\n fileHandleAssociation={fileHandleAssociation}\n />\n )\n } else {\n if (previewType !== PreviewRendererType.NONE) {\n console.warn(\n `Rendering a preview of type ${previewType} is not supported in Portals`,\n )\n }\n return <></>\n }\n}\n"],"mappings":";;;;;;;;AAYA,IAAM,IAAgB,KAAK;AAgB3B,SAAwB,EACtB,GACA;CACA,IAAM,EAAE,eAAY,0BAAuB,mBAAgB,GASrD,EAAE,MAAM,GAAS,iBAAc,EACnC,GACA;EARA,gBAAgB,CAAC,EAAsB;EACvC,sBAAsB;EACtB,oBAAoB;EACpB,6BAA6B;EAK7B,EACA,GACA,EAAE,cAAc,IAAM,CACvB;AAsBC,QApBE,IACK,kBAAC,GAAD,EAAkB,CAAA,GAEvB,MAAgB,EAAoB,OAEpC,kBAAC,GAAD;EAAa,SAAS;EAAU,iBAAiB,EAAW;EAAa,CAAA,GAElE,MAAgB,EAAoB,MAE3C,kBAAC,GAAD;EACc;EACW;EACvB,CAAA,IAGA,MAAgB,EAAoB,QACtC,QAAQ,KACN,+BAA+B,EAAY,8BAC5C,EAEI,kBAAA,GAAA,EAAK,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HtmlPreview.js","names":[],"sources":["../../../../src/components/FilePreview/HtmlPreview/HtmlPreview.tsx"],"sourcesContent":["import { useGetIsUserMemberOfTeam } from '@/synapse-queries/team/useTeamMembers'\nimport { sanitize } from '@/utils/functions/SanitizeHtmlUtils'\nimport { TRUSTED_HTML_USERS_TEAM_ID } from '@/utils/SynapseConstants'\nimport { Alert } from '@mui/material'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport { SynapseSpinner } from '../../LoadingScreen/LoadingScreen'\n\n/**\n * @param options\n * @returns HTML that is cleaned if it is not trusted. undefined if `isLoading` is true.\n */\nfunction useCleanHtml(options: {\n rawHtml: string\n isLoading: boolean\n isTrusted: boolean\n}): string | undefined {\n const { rawHtml, isLoading, isTrusted } = options\n return useMemo(() => {\n if (isLoading) {\n return undefined\n }\n if (isTrusted) {\n return rawHtml\n } else {\n return sanitize(rawHtml)\n }\n }, [isLoading, isTrusted, rawHtml])\n}\n\nexport type HtmlPreviewProps = {\n createdByUserId: string\n rawHtml: string\n}\n\n/**\n * Renders raw HTML. Uses file handle data to determine if the content should be sanitized.\n * @param props\n * @returns\n */\nexport default function HtmlPreview(props: HtmlPreviewProps) {\n const { createdByUserId, rawHtml } = props\n const frameEl = useRef(null)\n const [frameHeight, setFrameHeight] = useState(100)\n\n const { data: teamMembership, isLoading } = useGetIsUserMemberOfTeam(\n TRUSTED_HTML_USERS_TEAM_ID,\n createdByUserId,\n )\n const updateHeight = () => {\n if (frameEl?.current && frameEl?.current['contentWindow']) {\n let newHeightPx: number =\n frameEl.current['contentWindow']['document']['body']['scrollHeight']\n if (newHeightPx < 450) {\n newHeightPx = 450\n }\n if (!frameHeight || Math.abs(newHeightPx - frameHeight) > 70) {\n setFrameHeight(newHeightPx + 50)\n }\n }\n }\n useEffect(() => {\n setInterval(() => {\n updateHeight()\n }, 500)\n }, [rawHtml])\n const htmlIsCreatedByTrustedUser = !!teamMembership\n\n const cleanHtml = useCleanHtml({\n rawHtml,\n isLoading,\n isTrusted: htmlIsCreatedByTrustedUser,\n })\n\n if (isLoading) {\n return <SynapseSpinner />\n }\n\n return (\n <>\n {rawHtml !== cleanHtml && (\n <Alert severity=\"info\" sx={{ marginBottom: '20px' }}>\n Limited rendering only.\n </Alert>\n )}\n <iframe\n ref={frameEl}\n srcDoc={cleanHtml}\n height={`${frameHeight}px`}\n style={{ border: 0, width: '100%' }}\n />\n </>\n )\n}\n\nexport const EXPORTED_FOR_UNIT_TESTING = {\n useCleanHtml,\n}\n"],"mappings":";;;;;;;;AAWA,SAAS,EAAa,GAIC;CACrB,IAAM,EAAE,YAAS,cAAW,iBAAc;AAC1C,QAAO,QAAc;AACf,SAMF,QAHE,IACK,IAEA,EAAS,EAAQ;IAEzB;EAAC;EAAW;EAAW;EAAQ,CAAC;;AAarC,SAAwB,EAAY,GAAyB;CAC3D,IAAM,EAAE,oBAAiB,eAAY,GAC/B,IAAU,EAAO,KAAK,EACtB,CAAC,GAAa,KAAkB,EAAS,IAAI,EAE7C,EAAE,MAAM,GAAgB,iBAAc,EAC1C,GACA,EACD,EACK,UAAqB;AACzB,MAAI,GAAS,WAAW,GAAS,QAAQ,eAAkB;GACzD,IAAI,IACF,EAAQ,QAAQ,cAAiB,SAAY,KAAQ;AAIvD,GAHI,IAAc,QAChB,IAAc,OAEZ,CAAC,KAAe,KAAK,IAAI,IAAc,EAAY,GAAG,OACxD,EAAe,IAAc,GAAG;;;AAItC,SAAgB;AACd,oBAAkB;AAChB,MAAc;KACb,IAAI;IACN,CAAC,EAAQ,CAAC;CAGb,IAAM,IAAY,EAAa;EAC7B;EACA;EACA,
|
|
1
|
+
{"version":3,"file":"HtmlPreview.js","names":[],"sources":["../../../../src/components/FilePreview/HtmlPreview/HtmlPreview.tsx"],"sourcesContent":["import { useGetIsUserMemberOfTeam } from '@/synapse-queries/team/useTeamMembers'\nimport { sanitize } from '@/utils/functions/SanitizeHtmlUtils'\nimport { TRUSTED_HTML_USERS_TEAM_ID } from '@/utils/SynapseConstants'\nimport { Alert } from '@mui/material'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport { SynapseSpinner } from '../../LoadingScreen/LoadingScreen'\n\n/**\n * @param options\n * @returns HTML that is cleaned if it is not trusted. undefined if `isLoading` is true.\n */\nfunction useCleanHtml(options: {\n rawHtml: string\n isLoading: boolean\n isTrusted: boolean\n}): string | undefined {\n const { rawHtml, isLoading, isTrusted } = options\n return useMemo(() => {\n if (isLoading) {\n return undefined\n }\n if (isTrusted) {\n return rawHtml\n } else {\n return sanitize(rawHtml)\n }\n }, [isLoading, isTrusted, rawHtml])\n}\n\nexport type HtmlPreviewProps = {\n createdByUserId: string\n rawHtml: string\n}\n\n/**\n * Renders raw HTML. Uses file handle data to determine if the content should be sanitized.\n * @param props\n * @returns\n */\nexport default function HtmlPreview(props: HtmlPreviewProps) {\n const { createdByUserId, rawHtml } = props\n const frameEl = useRef(null)\n const [frameHeight, setFrameHeight] = useState(100)\n\n const { data: teamMembership, isLoading } = useGetIsUserMemberOfTeam(\n TRUSTED_HTML_USERS_TEAM_ID,\n createdByUserId,\n )\n const updateHeight = () => {\n if (frameEl?.current && frameEl?.current['contentWindow']) {\n let newHeightPx: number =\n frameEl.current['contentWindow']['document']['body']['scrollHeight']\n if (newHeightPx < 450) {\n newHeightPx = 450\n }\n if (!frameHeight || Math.abs(newHeightPx - frameHeight) > 70) {\n setFrameHeight(newHeightPx + 50)\n }\n }\n }\n useEffect(() => {\n setInterval(() => {\n updateHeight()\n }, 500)\n }, [rawHtml])\n const htmlIsCreatedByTrustedUser = !!teamMembership\n\n const cleanHtml = useCleanHtml({\n rawHtml,\n isLoading,\n isTrusted: htmlIsCreatedByTrustedUser,\n })\n\n if (isLoading) {\n return <SynapseSpinner />\n }\n\n return (\n <>\n {rawHtml !== cleanHtml && (\n <Alert severity=\"info\" sx={{ marginBottom: '20px' }}>\n Limited rendering only.\n </Alert>\n )}\n <iframe\n ref={frameEl}\n srcDoc={cleanHtml}\n height={`${frameHeight}px`}\n style={{ border: 0, width: '100%' }}\n />\n </>\n )\n}\n\nexport const EXPORTED_FOR_UNIT_TESTING = {\n useCleanHtml,\n}\n"],"mappings":";;;;;;;;AAWA,SAAS,EAAa,GAIC;CACrB,IAAM,EAAE,YAAS,cAAW,iBAAc;AAC1C,QAAO,QAAc;AACf,SAMF,QAHE,IACK,IAEA,EAAS,EAAQ;IAEzB;EAAC;EAAW;EAAW;EAAQ,CAAC;;AAarC,SAAwB,EAAY,GAAyB;CAC3D,IAAM,EAAE,oBAAiB,eAAY,GAC/B,IAAU,EAAO,KAAK,EACtB,CAAC,GAAa,KAAkB,EAAS,IAAI,EAE7C,EAAE,MAAM,GAAgB,iBAAc,EAC1C,GACA,EACD,EACK,UAAqB;AACzB,MAAI,GAAS,WAAW,GAAS,QAAQ,eAAkB;GACzD,IAAI,IACF,EAAQ,QAAQ,cAAiB,SAAY,KAAQ;AAIvD,GAHI,IAAc,QAChB,IAAc,OAEZ,CAAC,KAAe,KAAK,IAAI,IAAc,EAAY,GAAG,OACxD,EAAe,IAAc,GAAG;;;AAItC,SAAgB;AACd,oBAAkB;AAChB,MAAc;KACb,IAAI;IACN,CAAC,EAAQ,CAAC;CAGb,IAAM,IAAY,EAAa;EAC7B;EACA;EACA,WAAW,CALuB,CAAC;EAMpC,CAAC;AAMF,QAJI,IACK,kBAAC,GAAD,EAAkB,CAAA,GAIzB,kBAAA,GAAA,EAAA,UAAA,CACG,MAAY,KACX,kBAAC,GAAD;EAAO,UAAS;EAAO,IAAI,EAAE,cAAc,QAAQ;YAAE;EAE7C,CAAA,EAEV,kBAAC,UAAD;EACE,KAAK;EACL,QAAQ;EACR,QAAQ,GAAG,EAAY;EACvB,OAAO;GAAE,QAAQ;GAAG,OAAO;GAAQ;EACnC,CAAA,CACD,EAAA,CAAA;;AAIP,IAAa,IAA4B,EACvC,iBACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PreviewRendererType.js","names":[],"sources":["../../../src/components/FilePreview/PreviewRendererType.ts"],"sourcesContent":["// Note: The PreviewRendererType is copied from SWC's PreviewWidget.PreviewFileType\n// Not all of these are supported by SRC, but we do need to support all of them for preview widget feature parity\n\n/**\n * Types of files that can be previewed. The PreviewFileType of a file handle can be determined based on its MIME type.\n * Each value corresponds to a particular renderer.\n */\nexport enum PreviewRendererType {\n PLAINTEXT = 'PLAINTEXT',\n CODE = 'CODE',\n ZIP = 'ZIP',\n CSV = 'CSV',\n IMAGE = 'IMAGE',\n NONE = 'NONE',\n TAB = 'TAB',\n HTML = 'HTML',\n PDF = 'PDF',\n IPYNB = 'IPYNB',\n VIDEO = 'VIDEO',\n MARKDOWN = 'MARKDOWN',\n TIFF = 'TIFF',\n}\n"],"mappings":";AAOA,IAAY,IAAL,yBAAA,GAAA;QACL,EAAA,
|
|
1
|
+
{"version":3,"file":"PreviewRendererType.js","names":[],"sources":["../../../src/components/FilePreview/PreviewRendererType.ts"],"sourcesContent":["// Note: The PreviewRendererType is copied from SWC's PreviewWidget.PreviewFileType\n// Not all of these are supported by SRC, but we do need to support all of them for preview widget feature parity\n\n/**\n * Types of files that can be previewed. The PreviewFileType of a file handle can be determined based on its MIME type.\n * Each value corresponds to a particular renderer.\n */\nexport enum PreviewRendererType {\n PLAINTEXT = 'PLAINTEXT',\n CODE = 'CODE',\n ZIP = 'ZIP',\n CSV = 'CSV',\n IMAGE = 'IMAGE',\n NONE = 'NONE',\n TAB = 'TAB',\n HTML = 'HTML',\n PDF = 'PDF',\n IPYNB = 'IPYNB',\n VIDEO = 'VIDEO',\n MARKDOWN = 'MARKDOWN',\n TIFF = 'TIFF',\n}\n"],"mappings":";AAOA,IAAY,IAAL,yBAAA,GAAA;QACL,EAAA,YAAY,aACZ,EAAA,OAAO,QACP,EAAA,MAAM,OACN,EAAA,MAAM,OACN,EAAA,QAAQ,SACR,EAAA,OAAO,QACP,EAAA,MAAM,OACN,EAAA,OAAO,QACP,EAAA,MAAM,OACN,EAAA,QAAQ,SACR,EAAA,QAAQ,SACR,EAAA,WAAW,YACX,EAAA,OAAO;KACR"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DiscussionReply.js","names":[],"sources":["../../../src/components/Forum/DiscussionReply.tsx"],"sourcesContent":["import { useGetCurrentUserProfile, useGetEntityBundle } from '@/synapse-queries'\nimport { useDeleteReply, useGetReply } from '@/synapse-queries/forum/useReply'\nimport { formatDate } from '@/utils/functions/DateFormatter'\nimport {\n DiscussionReplyBundle,\n ObjectType,\n} from '@sage-bionetworks/synapse-types'\nimport dayjs from 'dayjs'\nimport { useState, useRef, useEffect } from 'react'\nimport IconSvg from '../IconSvg/IconSvg'\nimport MarkdownSynapse from '../Markdown/MarkdownSynapse'\nimport { SkeletonTable } from '../Skeleton/SkeletonTable'\nimport WarningDialog from '../SynapseForm/WarningDialog'\nimport { displayToast } from '../ToastMessage/ToastMessage'\nimport { UserBadge } from '../UserCard/UserBadge'\nimport { ForumThreadEditor } from './ForumThreadEditor'\nimport { Box } from '@mui/material'\nimport { copyStringToClipboard } from '@/utils/functions/StringUtils'\nimport { REPLY_ID_PARAM_KEY } from './DiscussionConstants'\n\nexport type DiscussionReplyProps = {\n reply: DiscussionReplyBundle\n isReplyAuthorModerator?: boolean\n onClickLink?: () => void\n}\n\nconst handleCopyLink = (id: string) => {\n const baseUrl = `${window.location.origin}${window.location.pathname}`\n const url = `${baseUrl}?${REPLY_ID_PARAM_KEY}=${id}`\n copyStringToClipboard(url).then(() =>\n displayToast('Reply link copied to clipboard', 'info'),\n )\n}\n\nexport function DiscussionReply(props: DiscussionReplyProps) {\n const { reply, isReplyAuthorModerator = false } = props\n const [showReplyModal, setShowReplyModal] = useState(false)\n const [showDeleteModal, setShowDeleteModal] = useState(false)\n const { data: currentUserProfile } = useGetCurrentUserProfile()\n const { data: entityBundle } = useGetEntityBundle(reply.projectId)\n const { data: message, isLoading } = useGetReply(reply)\n const replyRef = useRef<HTMLDivElement>(null)\n\n const { mutate: deleteReply } = useDeleteReply({\n onSuccess: () => {\n setShowDeleteModal(false)\n displayToast('A reply has been deleted.', 'info')\n },\n })\n\n const isCurrentUserAuthor = reply.createdBy == currentUserProfile?.ownerId\n\n useEffect(() => {\n const params = new URLSearchParams(window.location.search)\n const replyId = params.get(REPLY_ID_PARAM_KEY)\n let timerId: ReturnType<typeof setTimeout>\n if (replyId === reply.id && replyRef.current) {\n replyRef.current.style.transition = 'background-color 1s ease'\n replyRef.current.style.backgroundColor = '#fbf4e0'\n replyRef.current.style.borderColor = '#f4dda3'\n timerId = setTimeout(() => {\n if (replyRef.current) {\n replyRef.current.style.backgroundColor = '#f9f9f9'\n replyRef.current.style.borderColor = '#ccc'\n }\n }, 2000)\n }\n return () => {\n if (timerId) {\n clearTimeout(timerId)\n }\n }\n }, [reply.id])\n\n return (\n <div\n className=\"reply-container\"\n id={`reply._${reply.id}`}\n ref={replyRef}\n role={'article'}\n >\n {isLoading ? (\n <SkeletonTable numCols={1} numRows={4} />\n ) : (\n <>\n {message && (\n <>\n <div>\n <UserBadge\n userId={reply.createdBy}\n withAvatar={true}\n avatarSize=\"MEDIUM\"\n showCardOnHover={true}\n showModeratorBadge={isReplyAuthorModerator}\n />\n <div className=\"message-body\">\n <MarkdownSynapse\n markdown={message}\n objectType={ObjectType.REPLY}\n />\n <span>\n posted {formatDate(dayjs(reply.createdOn), 'M/D/YYYY')}\n {reply.isEdited ? <i>{' (Edited)'}</i> : null}\n </span>\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'flex-end',\n marginTop: { xs: '8px', sm: 0 },\n float: { sm: 'right' },\n }}\n >\n <button onClick={() => handleCopyLink(reply.id)}>\n <IconSvg icon=\"link\" label={'Copy link to this reply'} />\n </button>\n {isCurrentUserAuthor && (\n <button onClick={() => setShowReplyModal(true)}>\n <IconSvg icon=\"edit\" label={'Edit reply'} />\n </button>\n )}\n {entityBundle?.permissions.canModerate && (\n <button onClick={() => setShowDeleteModal(true)}>\n <IconSvg icon=\"delete\" label={'Delete reply'} />\n </button>\n )}\n </Box>\n </div>\n </div>\n <ForumThreadEditor\n isReply={true}\n initialText={message}\n onClose={() => setShowReplyModal(false)}\n id={reply.id}\n isDialog={true}\n openDialog={showReplyModal}\n />\n <WarningDialog\n open={showDeleteModal}\n title=\"Confirm Deletion\"\n content=\"Are you sure you want to delete this reply?\"\n onCancel={() => {\n setShowDeleteModal(false)\n }}\n onConfirm={() =>\n deleteReply({\n forumId: reply.forumId,\n threadId: reply.threadId,\n replyId: reply.id,\n })\n }\n confirmButtonColor=\"error\"\n confirmButtonText=\"Delete\"\n />\n </>\n )}\n </>\n )}\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA0BA,IAAM,KAAkB,MAAe;AAGrC,
|
|
1
|
+
{"version":3,"file":"DiscussionReply.js","names":[],"sources":["../../../src/components/Forum/DiscussionReply.tsx"],"sourcesContent":["import { useGetCurrentUserProfile, useGetEntityBundle } from '@/synapse-queries'\nimport { useDeleteReply, useGetReply } from '@/synapse-queries/forum/useReply'\nimport { formatDate } from '@/utils/functions/DateFormatter'\nimport {\n DiscussionReplyBundle,\n ObjectType,\n} from '@sage-bionetworks/synapse-types'\nimport dayjs from 'dayjs'\nimport { useState, useRef, useEffect } from 'react'\nimport IconSvg from '../IconSvg/IconSvg'\nimport MarkdownSynapse from '../Markdown/MarkdownSynapse'\nimport { SkeletonTable } from '../Skeleton/SkeletonTable'\nimport WarningDialog from '../SynapseForm/WarningDialog'\nimport { displayToast } from '../ToastMessage/ToastMessage'\nimport { UserBadge } from '../UserCard/UserBadge'\nimport { ForumThreadEditor } from './ForumThreadEditor'\nimport { Box } from '@mui/material'\nimport { copyStringToClipboard } from '@/utils/functions/StringUtils'\nimport { REPLY_ID_PARAM_KEY } from './DiscussionConstants'\n\nexport type DiscussionReplyProps = {\n reply: DiscussionReplyBundle\n isReplyAuthorModerator?: boolean\n onClickLink?: () => void\n}\n\nconst handleCopyLink = (id: string) => {\n const baseUrl = `${window.location.origin}${window.location.pathname}`\n const url = `${baseUrl}?${REPLY_ID_PARAM_KEY}=${id}`\n copyStringToClipboard(url).then(() =>\n displayToast('Reply link copied to clipboard', 'info'),\n )\n}\n\nexport function DiscussionReply(props: DiscussionReplyProps) {\n const { reply, isReplyAuthorModerator = false } = props\n const [showReplyModal, setShowReplyModal] = useState(false)\n const [showDeleteModal, setShowDeleteModal] = useState(false)\n const { data: currentUserProfile } = useGetCurrentUserProfile()\n const { data: entityBundle } = useGetEntityBundle(reply.projectId)\n const { data: message, isLoading } = useGetReply(reply)\n const replyRef = useRef<HTMLDivElement>(null)\n\n const { mutate: deleteReply } = useDeleteReply({\n onSuccess: () => {\n setShowDeleteModal(false)\n displayToast('A reply has been deleted.', 'info')\n },\n })\n\n const isCurrentUserAuthor = reply.createdBy == currentUserProfile?.ownerId\n\n useEffect(() => {\n const params = new URLSearchParams(window.location.search)\n const replyId = params.get(REPLY_ID_PARAM_KEY)\n let timerId: ReturnType<typeof setTimeout>\n if (replyId === reply.id && replyRef.current) {\n replyRef.current.style.transition = 'background-color 1s ease'\n replyRef.current.style.backgroundColor = '#fbf4e0'\n replyRef.current.style.borderColor = '#f4dda3'\n timerId = setTimeout(() => {\n if (replyRef.current) {\n replyRef.current.style.backgroundColor = '#f9f9f9'\n replyRef.current.style.borderColor = '#ccc'\n }\n }, 2000)\n }\n return () => {\n if (timerId) {\n clearTimeout(timerId)\n }\n }\n }, [reply.id])\n\n return (\n <div\n className=\"reply-container\"\n id={`reply._${reply.id}`}\n ref={replyRef}\n role={'article'}\n >\n {isLoading ? (\n <SkeletonTable numCols={1} numRows={4} />\n ) : (\n <>\n {message && (\n <>\n <div>\n <UserBadge\n userId={reply.createdBy}\n withAvatar={true}\n avatarSize=\"MEDIUM\"\n showCardOnHover={true}\n showModeratorBadge={isReplyAuthorModerator}\n />\n <div className=\"message-body\">\n <MarkdownSynapse\n markdown={message}\n objectType={ObjectType.REPLY}\n />\n <span>\n posted {formatDate(dayjs(reply.createdOn), 'M/D/YYYY')}\n {reply.isEdited ? <i>{' (Edited)'}</i> : null}\n </span>\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'flex-end',\n marginTop: { xs: '8px', sm: 0 },\n float: { sm: 'right' },\n }}\n >\n <button onClick={() => handleCopyLink(reply.id)}>\n <IconSvg icon=\"link\" label={'Copy link to this reply'} />\n </button>\n {isCurrentUserAuthor && (\n <button onClick={() => setShowReplyModal(true)}>\n <IconSvg icon=\"edit\" label={'Edit reply'} />\n </button>\n )}\n {entityBundle?.permissions.canModerate && (\n <button onClick={() => setShowDeleteModal(true)}>\n <IconSvg icon=\"delete\" label={'Delete reply'} />\n </button>\n )}\n </Box>\n </div>\n </div>\n <ForumThreadEditor\n isReply={true}\n initialText={message}\n onClose={() => setShowReplyModal(false)}\n id={reply.id}\n isDialog={true}\n openDialog={showReplyModal}\n />\n <WarningDialog\n open={showDeleteModal}\n title=\"Confirm Deletion\"\n content=\"Are you sure you want to delete this reply?\"\n onCancel={() => {\n setShowDeleteModal(false)\n }}\n onConfirm={() =>\n deleteReply({\n forumId: reply.forumId,\n threadId: reply.threadId,\n replyId: reply.id,\n })\n }\n confirmButtonColor=\"error\"\n confirmButtonText=\"Delete\"\n />\n </>\n )}\n </>\n )}\n </div>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DiscussionSearchResult.js","names":[],"sources":["../../../src/components/Forum/DiscussionSearchResult.tsx"],"sourcesContent":["import {\n getReply,\n getReplyMessageUrl,\n getThread,\n getThreadMessageUrl,\n getUserProfileById,\n} from '@/synapse-client/SynapseClient'\nimport React from 'react'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport { formatDate } from '@/utils/functions/DateFormatter'\nimport { PRODUCTION_ENDPOINT_CONFIG } from '@/utils/functions/getEndpoint'\nimport { Box, Skeleton, Typography } from '@mui/material'\nimport {\n DiscussionReplyBundle,\n DiscussionThreadBundle,\n UserProfile,\n} from '@sage-bionetworks/synapse-types'\nimport dayjs from 'dayjs'\nimport { useEffect, useState } from 'react'\nimport IconSvg from '../IconSvg/IconSvg'\nimport { SkeletonParagraph } from '../Skeleton/SkeletonParagraph'\nimport { UserBadge } from '../UserCard/UserBadge'\n\nexport const getMessage = async (url: string): Promise<string> => {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n Accept: '*/*',\n 'Access-Control-Request-Headers': 'authorization',\n 'Content-Type': 'text/plain; charset=utf-8',\n },\n })\n return response.text()\n}\n\nexport type DiscussionSearchResultProps = {\n threadId: string\n replyId?: string\n}\n\nconst DiscussionSearchResult = (\n props: DiscussionSearchResultProps,\n): React.ReactNode => {\n const { threadId, replyId } = props\n const { accessToken } = useSynapseContext()\n const [threadBundle, setThreadBundle] = useState<DiscussionThreadBundle>()\n const [messageUrl, setMessageUrl] = useState<string>('')\n const [replyBundle, setReplyBundle] = useState<DiscussionReplyBundle>()\n const [replyAuthor, setReplyAuthor] = useState<UserProfile>()\n const [isLoading, setIsLoading] = useState(false)\n\n useEffect(() => {\n const getThreadOrReply = async () => {\n let newMessageUrl\n setIsLoading(true)\n const thread = await getThread(threadId, accessToken)\n if (replyId) {\n const reply = await getReply(replyId, accessToken)\n newMessageUrl = await getReplyMessageUrl(reply.messageKey, accessToken)\n setReplyAuthor(await getUserProfileById(reply.createdBy))\n setReplyBundle(reply)\n } else {\n setReplyAuthor(await getUserProfileById(thread.createdBy))\n newMessageUrl = await getThreadMessageUrl(\n thread.messageKey,\n accessToken,\n )\n }\n setMessageUrl(await getMessage(newMessageUrl.messageUrl))\n setThreadBundle(thread)\n setIsLoading(false)\n }\n getThreadOrReply()\n }, [accessToken, replyId, threadId])\n\n const getUrl = (threadId: string, projectId: string, replyId?: string) => {\n let url = `${PRODUCTION_ENDPOINT_CONFIG.PORTAL}Synapse:${projectId}/discussion/threadId=${threadId}`\n if (replyId) {\n url += `&replyId=${replyId}`\n }\n return url\n }\n\n return (\n <div className=\"search-result-container\">\n <Box\n sx={{\n display: 'grid',\n gridTemplateColumns: '40px auto',\n }}\n >\n <div>\n {isLoading ? (\n <Skeleton variant=\"circular\" width=\"30px\" height={'30px'} />\n ) : replyId ? (\n <IconSvg icon=\"replyTwoTone\" />\n ) : (\n <IconSvg icon=\"chatTwoTone\" />\n )}\n </div>\n <div>\n {isLoading ? (\n <SkeletonParagraph numRows={4} />\n ) : (\n <>\n <Typography variant=\"headline3\" gutterBottom>\n <a\n className=\"link\"\n href={getUrl(\n threadBundle?.id!,\n threadBundle?.projectId!,\n replyBundle?.id,\n )}\n >\n {threadBundle?.title}\n </a>\n </Typography>\n <div className=\"truncated\">\n <Typography variant=\"body1\" gutterBottom>\n {messageUrl}\n </Typography>\n </div>\n <div className=\"search-result-footer\">\n {replyId ? 'Reply' : 'Thread'} by{' '}\n {<UserBadge userId={replyAuthor?.ownerId} />}{' '}\n {formatDate(dayjs(replyBundle?.createdOn))}\n </div>\n </>\n )}\n </div>\n </Box>\n </div>\n )\n}\n\nexport default DiscussionSearchResult\n"],"mappings":";;;;;;;;;;;;AAuBA,IAAa,IAAa,OAAO,
|
|
1
|
+
{"version":3,"file":"DiscussionSearchResult.js","names":[],"sources":["../../../src/components/Forum/DiscussionSearchResult.tsx"],"sourcesContent":["import {\n getReply,\n getReplyMessageUrl,\n getThread,\n getThreadMessageUrl,\n getUserProfileById,\n} from '@/synapse-client/SynapseClient'\nimport React from 'react'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport { formatDate } from '@/utils/functions/DateFormatter'\nimport { PRODUCTION_ENDPOINT_CONFIG } from '@/utils/functions/getEndpoint'\nimport { Box, Skeleton, Typography } from '@mui/material'\nimport {\n DiscussionReplyBundle,\n DiscussionThreadBundle,\n UserProfile,\n} from '@sage-bionetworks/synapse-types'\nimport dayjs from 'dayjs'\nimport { useEffect, useState } from 'react'\nimport IconSvg from '../IconSvg/IconSvg'\nimport { SkeletonParagraph } from '../Skeleton/SkeletonParagraph'\nimport { UserBadge } from '../UserCard/UserBadge'\n\nexport const getMessage = async (url: string): Promise<string> => {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n Accept: '*/*',\n 'Access-Control-Request-Headers': 'authorization',\n 'Content-Type': 'text/plain; charset=utf-8',\n },\n })\n return response.text()\n}\n\nexport type DiscussionSearchResultProps = {\n threadId: string\n replyId?: string\n}\n\nconst DiscussionSearchResult = (\n props: DiscussionSearchResultProps,\n): React.ReactNode => {\n const { threadId, replyId } = props\n const { accessToken } = useSynapseContext()\n const [threadBundle, setThreadBundle] = useState<DiscussionThreadBundle>()\n const [messageUrl, setMessageUrl] = useState<string>('')\n const [replyBundle, setReplyBundle] = useState<DiscussionReplyBundle>()\n const [replyAuthor, setReplyAuthor] = useState<UserProfile>()\n const [isLoading, setIsLoading] = useState(false)\n\n useEffect(() => {\n const getThreadOrReply = async () => {\n let newMessageUrl\n setIsLoading(true)\n const thread = await getThread(threadId, accessToken)\n if (replyId) {\n const reply = await getReply(replyId, accessToken)\n newMessageUrl = await getReplyMessageUrl(reply.messageKey, accessToken)\n setReplyAuthor(await getUserProfileById(reply.createdBy))\n setReplyBundle(reply)\n } else {\n setReplyAuthor(await getUserProfileById(thread.createdBy))\n newMessageUrl = await getThreadMessageUrl(\n thread.messageKey,\n accessToken,\n )\n }\n setMessageUrl(await getMessage(newMessageUrl.messageUrl))\n setThreadBundle(thread)\n setIsLoading(false)\n }\n getThreadOrReply()\n }, [accessToken, replyId, threadId])\n\n const getUrl = (threadId: string, projectId: string, replyId?: string) => {\n let url = `${PRODUCTION_ENDPOINT_CONFIG.PORTAL}Synapse:${projectId}/discussion/threadId=${threadId}`\n if (replyId) {\n url += `&replyId=${replyId}`\n }\n return url\n }\n\n return (\n <div className=\"search-result-container\">\n <Box\n sx={{\n display: 'grid',\n gridTemplateColumns: '40px auto',\n }}\n >\n <div>\n {isLoading ? (\n <Skeleton variant=\"circular\" width=\"30px\" height={'30px'} />\n ) : replyId ? (\n <IconSvg icon=\"replyTwoTone\" />\n ) : (\n <IconSvg icon=\"chatTwoTone\" />\n )}\n </div>\n <div>\n {isLoading ? (\n <SkeletonParagraph numRows={4} />\n ) : (\n <>\n <Typography variant=\"headline3\" gutterBottom>\n <a\n className=\"link\"\n href={getUrl(\n threadBundle?.id!,\n threadBundle?.projectId!,\n replyBundle?.id,\n )}\n >\n {threadBundle?.title}\n </a>\n </Typography>\n <div className=\"truncated\">\n <Typography variant=\"body1\" gutterBottom>\n {messageUrl}\n </Typography>\n </div>\n <div className=\"search-result-footer\">\n {replyId ? 'Reply' : 'Thread'} by{' '}\n {<UserBadge userId={replyAuthor?.ownerId} />}{' '}\n {formatDate(dayjs(replyBundle?.createdOn))}\n </div>\n </>\n )}\n </div>\n </Box>\n </div>\n )\n}\n\nexport default DiscussionSearchResult\n"],"mappings":";;;;;;;;;;;;AAuBA,IAAa,IAAa,OAAO,OASxB,MARgB,MAAM,GAAK;CAChC,QAAQ;CACR,SAAS;EACP,QAAQ;EACR,kCAAkC;EAClC,gBAAgB;EACjB;CACF,CAAC,EACc,MAAM,EAQlB,KACJ,MACoB;CACpB,IAAM,EAAE,aAAU,eAAY,GACxB,EAAE,mBAAgB,GAAmB,EACrC,CAAC,GAAc,KAAmB,GAAkC,EACpE,CAAC,GAAY,KAAiB,EAAiB,GAAG,EAClD,CAAC,GAAa,KAAkB,GAAiC,EACjE,CAAC,GAAa,KAAkB,GAAuB,EACvD,CAAC,GAAW,KAAgB,EAAS,GAAM;AAkCjD,QAhCA,QAAgB;AAqBd,eApBqC;GACnC,IAAI;AACJ,KAAa,GAAK;GAClB,IAAM,IAAS,MAAM,EAAU,GAAU,EAAY;AACrD,OAAI,GAAS;IACX,IAAM,IAAQ,MAAM,EAAS,GAAS,EAAY;AAGlD,IAFA,IAAgB,MAAM,EAAmB,EAAM,YAAY,EAAY,EACvE,EAAe,MAAM,EAAmB,EAAM,UAAU,CAAC,EACzD,EAAe,EAAM;SAGrB,CADA,EAAe,MAAM,EAAmB,EAAO,UAAU,CAAC,EAC1D,IAAgB,MAAM,EACpB,EAAO,YACP,EACD;AAIH,GAFA,EAAc,MAAM,EAAW,EAAc,WAAW,CAAC,EACzD,EAAgB,EAAO,EACvB,EAAa,GAAM;MAEH;IACjB;EAAC;EAAa;EAAS;EAAS,CAAC,EAWlC,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GACE,IAAI;IACF,SAAS;IACT,qBAAqB;IACtB;aAJH,CAME,kBAAC,OAAD,EAAA,UACG,IACC,kBAAC,GAAD;IAAU,SAAQ;IAAW,OAAM;IAAO,QAAQ;IAAU,CAAA,GAC1D,IACF,kBAAC,GAAD,EAAS,MAAK,gBAAiB,CAAA,GAE/B,kBAAC,GAAD,EAAS,MAAK,eAAgB,CAAA,EAE5B,CAAA,EACN,kBAAC,OAAD,EAAA,UACG,IACC,kBAAC,GAAD,EAAmB,SAAS,GAAK,CAAA,GAEjC,kBAAA,GAAA,EAAA,UAAA;IACE,kBAAC,GAAD;KAAY,SAAQ;KAAY,cAAA;eAC9B,kBAAC,KAAD;MACE,WAAU;MACV,QAjCA,GAAkB,GAAmB,MAAqB;OACxE,IAAI,IAAM,GAAG,EAA2B,OAAO,UAAU,EAAU,uBAAuB;AAI1F,cAHI,MACF,KAAO,YAAY,MAEd;SA6BS,GAAc,IACd,GAAc,WACd,GAAa,GACd;gBAEA,GAAc;MACb,CAAA;KACO,CAAA;IACb,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD;MAAY,SAAQ;MAAQ,cAAA;gBACzB;MACU,CAAA;KACT,CAAA;IACN,kBAAC,OAAD;KAAK,WAAU;eAAf;MACG,IAAU,UAAU;MAAS;MAAI;MACjC,kBAAC,GAAD,EAAW,QAAQ,GAAa,SAAW,CAAA;MAAE;MAC7C,EAAW,EAAM,GAAa,UAAU,CAAC;MACtC;;IACL,EAAA,CAAA,EAED,CAAA,CACF;;EACF,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ForumTable.js","names":[],"sources":["../../../src/components/Forum/ForumTable.tsx"],"sourcesContent":["import InfiniteTableLayout from '@/components/layout/InfiniteTableLayout'\nimport { useGetForumThreadsInfinite } from '@/synapse-queries/forum/useForum'\nimport { AVATAR } from '@/utils/SynapseConstants'\nimport { Link } from '@mui/material'\nimport {\n DiscussionFilter,\n DiscussionThreadBundle,\n DiscussionThreadOrder,\n} from '@sage-bionetworks/synapse-types'\nimport {\n ColumnDef,\n createColumnHelper,\n getCoreRowModel,\n SortingState,\n Table,\n useReactTable,\n} from '@tanstack/react-table'\nimport dayjs from 'dayjs'\nimport isEmpty from 'lodash-es/isEmpty'\nimport { useMemo, useState } from 'react'\nimport IconSvg from '../IconSvg/IconSvg'\nimport ColumnHeader from '../TanStackTable/ColumnHeader'\nimport StyledTanStackTable from '../TanStackTable/StyledTanStackTable'\nimport { UserBadge } from '../UserCard/UserBadge'\nimport UserCard from '../UserCard/UserCard'\n\nexport type ForumTableProps = {\n forumId: string\n limit: number\n onClickLink: (threadId: string) => void\n filter: DiscussionFilter\n}\n\nconst columnHelper = createColumnHelper<DiscussionThreadBundle>()\n\nfunction getColumns(\n onClickLink: (threadId: string) => void,\n): ColumnDef<DiscussionThreadBundle, any>[] {\n return [\n columnHelper.accessor('title', {\n header: props => <ColumnHeader {...props} title={'Topic'} />,\n cell: ({ row }) => (\n <Link onClick={() => onClickLink(row.original.id)}>\n {row.original.isPinned ? <IconSvg icon=\"pushpin\" /> : <></>}\n {row.original.title}\n </Link>\n ),\n enableSorting: true,\n size: 250,\n }),\n columnHelper.accessor('createdBy', {\n header: props => <ColumnHeader {...props} title={'Author'} />,\n cell: ({ getValue }) => <UserBadge userId={getValue()} />,\n enableSorting: false,\n size: 60,\n }),\n columnHelper.accessor('activeAuthors', {\n header: props => <ColumnHeader {...props} title={'Active Users'} />,\n cell: ({ getValue }) =>\n getValue().map((userId: string) => (\n <div key={userId} className=\"avatarContainer\">\n <UserCard\n showCardOnHover={true}\n className=\"ActiveUsers\"\n size={AVATAR}\n avatarSize={'MEDIUM'}\n ownerId={userId}\n />\n </div>\n )),\n enableSorting: false,\n }),\n columnHelper.accessor('numberOfReplies', {\n header: props => <ColumnHeader {...props} title={'Replies'} />,\n cell: ({ getValue }) => getValue().toLocaleString(),\n enableSorting: true,\n minSize: 10,\n size: 20,\n }),\n columnHelper.accessor('numberOfViews', {\n header: props => <ColumnHeader {...props} title={'Views'} />,\n cell: ({ getValue }) => getValue().toLocaleString(),\n enableSorting: true,\n minSize: 10,\n size: 20,\n }),\n columnHelper.accessor('lastActivity', {\n header: props => <ColumnHeader {...props} title={'Activity'} />,\n cell: ({ getValue }) => dayjs(getValue()).format('L'),\n enableSorting: true,\n size: 30,\n }),\n ]\n}\n\nexport function ForumTable({\n forumId,\n limit,\n filter,\n onClickLink,\n}: ForumTableProps) {\n const [tableSortState, setTableSortState] = useState<SortingState>([\n {\n desc: true,\n id: 'lastActivity',\n },\n ])\n\n const discussionThreadOrder = useMemo(() => {\n if (!isEmpty(tableSortState)) {\n if (tableSortState[0].id == 'lastActivity') {\n return DiscussionThreadOrder.PINNED_AND_LAST_ACTIVITY\n } else if (tableSortState[0].id == 'numberOfReplies') {\n return DiscussionThreadOrder.NUMBER_OF_REPLIES\n } else if (tableSortState[0].id == 'title') {\n return DiscussionThreadOrder.THREAD_TITLE\n } else if (tableSortState[0].id == 'numberOfViews') {\n return DiscussionThreadOrder.NUMBER_OF_VIEWS\n }\n }\n return DiscussionThreadOrder.PINNED_AND_LAST_ACTIVITY\n }, [tableSortState])\n\n const { data, isLoading, hasNextPage, fetchNextPage, isFetchingNextPage } =\n useGetForumThreadsInfinite(\n forumId,\n limit,\n discussionThreadOrder,\n !tableSortState[0]?.desc,\n filter,\n )\n\n const threads = useMemo(\n () => data?.pages.flatMap(page => page.results) ?? [],\n [data],\n )\n\n const columns = useMemo(() => getColumns(onClickLink), [onClickLink])\n\n const table: Table<DiscussionThreadBundle> =\n useReactTable<DiscussionThreadBundle>({\n data: threads,\n columns: columns,\n state: {\n sorting: tableSortState,\n },\n onSortingChange: setTableSortState,\n getRowId: row => row.id,\n getCoreRowModel: getCoreRowModel(),\n columnResizeMode: 'onChange',\n manualSorting: true,\n enableMultiSort: false,\n enableFilters: false,\n })\n\n const hasNoResults = !isLoading && table.getRowModel().rows.length === 0\n\n return (\n <div className=\"ForumTable\">\n <InfiniteTableLayout\n table={\n <StyledTanStackTable\n table={table}\n styledTableContainerProps={{ sx: { my: 2, maxHeight: '250px' } }}\n />\n }\n isLoading={isLoading}\n isEmpty={hasNoResults}\n hasNextPage={hasNextPage}\n onFetchNextPageClicked={() => {\n void fetchNextPage()\n }}\n isFetchingNextPage={isFetchingNextPage}\n />\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAiCA,IAAM,IAAe,GAA4C;AAEjE,SAAS,EACP,GAC0C;AAC1C,QAAO;EACL,EAAa,SAAS,SAAS;GAC7B,SAAQ,MAAS,kBAAC,GAAD;IAAc,GAAI;IAAO,OAAO;IAAW,CAAA;GAC5D,OAAO,EAAE,aACP,kBAAC,GAAD;IAAM,eAAe,EAAY,EAAI,SAAS,GAAG;cAAjD,CACG,EAAI,SAAS,WAAW,kBAAC,GAAD,EAAS,MAAK,WAAY,CAAA,GAAG,kBAAA,GAAA,EAAK,CAAA,EAC1D,EAAI,SAAS,MACT;;GAET,eAAe;GACf,MAAM;GACP,CAAC;EACF,EAAa,SAAS,aAAa;GACjC,SAAQ,MAAS,kBAAC,GAAD;IAAc,GAAI;IAAO,OAAO;IAAY,CAAA;GAC7D,OAAO,EAAE,kBAAe,kBAAC,GAAD,EAAW,QAAQ,GAAU,EAAI,CAAA;GACzD,eAAe;GACf,MAAM;GACP,CAAC;EACF,EAAa,SAAS,iBAAiB;GACrC,SAAQ,MAAS,kBAAC,GAAD;IAAc,GAAI;IAAO,OAAO;IAAkB,CAAA;GACnE,OAAO,EAAE,kBACP,GAAU,CAAC,KAAK,MACd,kBAAC,OAAD;IAAkB,WAAU;cAC1B,kBAAC,GAAD;KACE,iBAAiB;KACjB,WAAU;KACV,MAAM;KACN,YAAY;KACZ,SAAS;KACT,CAAA;IACE,EARI,EAQJ,CACN;GACJ,eAAe;GAChB,CAAC;EACF,EAAa,SAAS,mBAAmB;GACvC,SAAQ,MAAS,kBAAC,GAAD;IAAc,GAAI;IAAO,OAAO;IAAa,CAAA;GAC9D,OAAO,EAAE,kBAAe,GAAU,CAAC,gBAAgB;GACnD,eAAe;GACf,SAAS;GACT,MAAM;GACP,CAAC;EACF,EAAa,SAAS,iBAAiB;GACrC,SAAQ,MAAS,kBAAC,GAAD;IAAc,GAAI;IAAO,OAAO;IAAW,CAAA;GAC5D,OAAO,EAAE,kBAAe,GAAU,CAAC,gBAAgB;GACnD,eAAe;GACf,SAAS;GACT,MAAM;GACP,CAAC;EACF,EAAa,SAAS,gBAAgB;GACpC,SAAQ,MAAS,kBAAC,GAAD;IAAc,GAAI;IAAO,OAAO;IAAc,CAAA;GAC/D,OAAO,EAAE,kBAAe,EAAM,GAAU,CAAC,CAAC,OAAO,IAAI;GACrD,eAAe;GACf,MAAM;GACP,CAAC;EACH;;AAGH,SAAgB,EAAW,EACzB,YACA,UACA,WACA,kBACkB;CAClB,IAAM,CAAC,GAAgB,KAAqB,EAAuB,CACjE;EACE,MAAM;EACN,IAAI;EACL,CACF,CAAC,EAiBI,EAAE,SAAM,cAAW,gBAAa,kBAAe,0BACnD,EACE,GACA,GAlB0B,QAAc;AAC1C,MAAI,CAAC,EAAQ,EAAe,EAC1B;OAAI,EAAe,GAAG,MAAM,eAC1B,QAAO,EAAsB;OACpB,EAAe,GAAG,MAAM,kBACjC,QAAO,EAAsB;OACpB,EAAe,GAAG,MAAM,QACjC,QAAO,EAAsB;OACpB,EAAe,GAAG,MAAM,gBACjC,QAAO,EAAsB;;AAGjC,SAAO,EAAsB;IAC5B,CAAC,EAAe,
|
|
1
|
+
{"version":3,"file":"ForumTable.js","names":[],"sources":["../../../src/components/Forum/ForumTable.tsx"],"sourcesContent":["import InfiniteTableLayout from '@/components/layout/InfiniteTableLayout'\nimport { useGetForumThreadsInfinite } from '@/synapse-queries/forum/useForum'\nimport { AVATAR } from '@/utils/SynapseConstants'\nimport { Link } from '@mui/material'\nimport {\n DiscussionFilter,\n DiscussionThreadBundle,\n DiscussionThreadOrder,\n} from '@sage-bionetworks/synapse-types'\nimport {\n ColumnDef,\n createColumnHelper,\n getCoreRowModel,\n SortingState,\n Table,\n useReactTable,\n} from '@tanstack/react-table'\nimport dayjs from 'dayjs'\nimport isEmpty from 'lodash-es/isEmpty'\nimport { useMemo, useState } from 'react'\nimport IconSvg from '../IconSvg/IconSvg'\nimport ColumnHeader from '../TanStackTable/ColumnHeader'\nimport StyledTanStackTable from '../TanStackTable/StyledTanStackTable'\nimport { UserBadge } from '../UserCard/UserBadge'\nimport UserCard from '../UserCard/UserCard'\n\nexport type ForumTableProps = {\n forumId: string\n limit: number\n onClickLink: (threadId: string) => void\n filter: DiscussionFilter\n}\n\nconst columnHelper = createColumnHelper<DiscussionThreadBundle>()\n\nfunction getColumns(\n onClickLink: (threadId: string) => void,\n): ColumnDef<DiscussionThreadBundle, any>[] {\n return [\n columnHelper.accessor('title', {\n header: props => <ColumnHeader {...props} title={'Topic'} />,\n cell: ({ row }) => (\n <Link onClick={() => onClickLink(row.original.id)}>\n {row.original.isPinned ? <IconSvg icon=\"pushpin\" /> : <></>}\n {row.original.title}\n </Link>\n ),\n enableSorting: true,\n size: 250,\n }),\n columnHelper.accessor('createdBy', {\n header: props => <ColumnHeader {...props} title={'Author'} />,\n cell: ({ getValue }) => <UserBadge userId={getValue()} />,\n enableSorting: false,\n size: 60,\n }),\n columnHelper.accessor('activeAuthors', {\n header: props => <ColumnHeader {...props} title={'Active Users'} />,\n cell: ({ getValue }) =>\n getValue().map((userId: string) => (\n <div key={userId} className=\"avatarContainer\">\n <UserCard\n showCardOnHover={true}\n className=\"ActiveUsers\"\n size={AVATAR}\n avatarSize={'MEDIUM'}\n ownerId={userId}\n />\n </div>\n )),\n enableSorting: false,\n }),\n columnHelper.accessor('numberOfReplies', {\n header: props => <ColumnHeader {...props} title={'Replies'} />,\n cell: ({ getValue }) => getValue().toLocaleString(),\n enableSorting: true,\n minSize: 10,\n size: 20,\n }),\n columnHelper.accessor('numberOfViews', {\n header: props => <ColumnHeader {...props} title={'Views'} />,\n cell: ({ getValue }) => getValue().toLocaleString(),\n enableSorting: true,\n minSize: 10,\n size: 20,\n }),\n columnHelper.accessor('lastActivity', {\n header: props => <ColumnHeader {...props} title={'Activity'} />,\n cell: ({ getValue }) => dayjs(getValue()).format('L'),\n enableSorting: true,\n size: 30,\n }),\n ]\n}\n\nexport function ForumTable({\n forumId,\n limit,\n filter,\n onClickLink,\n}: ForumTableProps) {\n const [tableSortState, setTableSortState] = useState<SortingState>([\n {\n desc: true,\n id: 'lastActivity',\n },\n ])\n\n const discussionThreadOrder = useMemo(() => {\n if (!isEmpty(tableSortState)) {\n if (tableSortState[0].id == 'lastActivity') {\n return DiscussionThreadOrder.PINNED_AND_LAST_ACTIVITY\n } else if (tableSortState[0].id == 'numberOfReplies') {\n return DiscussionThreadOrder.NUMBER_OF_REPLIES\n } else if (tableSortState[0].id == 'title') {\n return DiscussionThreadOrder.THREAD_TITLE\n } else if (tableSortState[0].id == 'numberOfViews') {\n return DiscussionThreadOrder.NUMBER_OF_VIEWS\n }\n }\n return DiscussionThreadOrder.PINNED_AND_LAST_ACTIVITY\n }, [tableSortState])\n\n const { data, isLoading, hasNextPage, fetchNextPage, isFetchingNextPage } =\n useGetForumThreadsInfinite(\n forumId,\n limit,\n discussionThreadOrder,\n !tableSortState[0]?.desc,\n filter,\n )\n\n const threads = useMemo(\n () => data?.pages.flatMap(page => page.results) ?? [],\n [data],\n )\n\n const columns = useMemo(() => getColumns(onClickLink), [onClickLink])\n\n const table: Table<DiscussionThreadBundle> =\n useReactTable<DiscussionThreadBundle>({\n data: threads,\n columns: columns,\n state: {\n sorting: tableSortState,\n },\n onSortingChange: setTableSortState,\n getRowId: row => row.id,\n getCoreRowModel: getCoreRowModel(),\n columnResizeMode: 'onChange',\n manualSorting: true,\n enableMultiSort: false,\n enableFilters: false,\n })\n\n const hasNoResults = !isLoading && table.getRowModel().rows.length === 0\n\n return (\n <div className=\"ForumTable\">\n <InfiniteTableLayout\n table={\n <StyledTanStackTable\n table={table}\n styledTableContainerProps={{ sx: { my: 2, maxHeight: '250px' } }}\n />\n }\n isLoading={isLoading}\n isEmpty={hasNoResults}\n hasNextPage={hasNextPage}\n onFetchNextPageClicked={() => {\n void fetchNextPage()\n }}\n isFetchingNextPage={isFetchingNextPage}\n />\n </div>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ForumThreadEditor.js","names":[],"sources":["../../../src/components/Forum/ForumThreadEditor.tsx"],"sourcesContent":["import { usePostReply, usePutReply } from '@/synapse-queries/forum/useReply'\nimport {\n useCreateThread,\n useUpdateThreadMessage,\n useUpdateThreadTitle,\n} from '@/synapse-queries/forum/useThread'\nimport { Box, TextField } from '@mui/material'\nimport { CreateDiscussionThread } from '@sage-bionetworks/synapse-types'\nimport { useState } from 'react'\nimport {\n ConfirmationButtons,\n ConfirmationDialog,\n} from '../ConfirmationDialog/ConfirmationDialog'\nimport { MarkdownEditor } from '../Markdown/MarkdownEditor'\n\nexport type ForumThreadEditorProps = {\n initialTitle?: string\n initialText?: string\n id: string\n onClose: () => void\n isReply: boolean\n} & (\n | { isDialog: false; openDialog?: never }\n | { isDialog: true; openDialog: boolean }\n)\n\nexport function ForumThreadEditor(props: ForumThreadEditorProps) {\n const {\n initialText,\n initialTitle,\n id,\n onClose,\n isReply,\n isDialog,\n openDialog,\n } = props\n\n const [title, setTitle] = useState<string>(initialTitle ?? '')\n const [text, setText] = useState<string>(initialText ?? '')\n const { mutate: updateTitle, isPending: titleUpdateIsPending } =\n useUpdateThreadTitle({\n onSuccess: () => onClose(),\n })\n const { mutate: updateMessage, isPending: messageUpdateIsPending } =\n useUpdateThreadMessage({\n onSuccess: () => onClose(),\n })\n const { mutate: createThread, isPending: createThreadIsPending } =\n useCreateThread({\n onSuccess: () => onClose(),\n })\n const { mutate: createReply, isPending: createReplyIsPending } = usePostReply(\n {\n onSuccess: () => onClose(),\n },\n )\n const { mutate: updateReply, isPending: updateReplyIsPending } = usePutReply({\n onSuccess: () => onClose(),\n })\n\n const updateIsPending =\n messageUpdateIsPending ||\n createReplyIsPending ||\n createThreadIsPending ||\n titleUpdateIsPending ||\n updateReplyIsPending\n\n const isExistingThread = !isReply && initialTitle\n\n const onSave = (text: string, title: string) => {\n if (isReply) {\n if (initialText) {\n // updating reply\n updateReply({\n replyId: id,\n messageMarkdown: text,\n })\n } else {\n // posting reply\n createReply({\n threadId: id,\n messageMarkdown: text,\n })\n }\n } else {\n if (isExistingThread) {\n // updating thread\n updateTitle({\n title: title,\n threadId: id,\n })\n updateMessage({\n messageMarkdown: text,\n threadId: id,\n })\n } else {\n // posting thread\n const request: CreateDiscussionThread = {\n forumId: id,\n title: title,\n messageMarkdown: text,\n }\n createThread(request)\n }\n }\n }\n\n const editorContent = (\n <div>\n {!isReply && (\n <TextField\n fullWidth\n sx={{ my: 1 }}\n placeholder=\"Title\"\n value={title}\n onChange={e => setTitle(e.target.value)}\n />\n )}\n <MarkdownEditor\n placeholder={'Write a reply...'}\n text={text}\n setText={setText}\n />\n </div>\n )\n\n const confirmButtonText = updateIsPending ? 'Saving' : 'Post'\n\n return (\n <>\n {isDialog ? (\n <ConfirmationDialog\n maxWidth=\"md\"\n open={openDialog}\n onCancel={onClose}\n title={\n isReply\n ? 'Edit Reply'\n : isExistingThread\n ? 'Edit Thread'\n : 'New Thread'\n }\n content={editorContent}\n onConfirm={() => onSave(text, title)}\n confirmButtonProps={{ children: confirmButtonText }}\n />\n ) : (\n <>\n {editorContent}\n <Box\n sx={{ display: 'flex', justifyContent: 'flex-end', gap: 1, my: 1 }}\n >\n <ConfirmationButtons\n onCancel={onClose}\n onConfirm={() => onSave(text, title)}\n confirmButtonProps={{ children: confirmButtonText }}\n />\n </Box>\n </>\n )}\n </>\n )\n}\n"],"mappings":";;;;;;;;AA0BA,SAAgB,EAAkB,GAA+B;CAC/D,IAAM,EACJ,gBACA,iBACA,OACA,YACA,YACA,aACA,kBACE,GAEE,CAAC,GAAO,KAAY,EAAiB,KAAgB,GAAG,EACxD,CAAC,GAAM,KAAW,EAAiB,KAAe,GAAG,EACrD,EAAE,QAAQ,GAAa,WAAW,MACtC,EAAqB,EACnB,iBAAiB,GAAS,EAC3B,CAAC,EACE,EAAE,QAAQ,GAAe,WAAW,MACxC,EAAuB,EACrB,iBAAiB,GAAS,EAC3B,CAAC,EACE,EAAE,QAAQ,GAAc,WAAW,MACvC,EAAgB,EACd,iBAAiB,GAAS,EAC3B,CAAC,EACE,EAAE,QAAQ,GAAa,WAAW,MAAyB,EAC/D,EACE,iBAAiB,GAAS,EAC3B,CACF,EACK,EAAE,QAAQ,GAAa,WAAW,MAAyB,EAAY,EAC3E,iBAAiB,GAAS,EAC3B,CAAC,EAEI,IACJ,KACA,KACA,KACA,KACA,GAEI,IAAmB,CAAC,KAAW,GAE/B,KAAU,GAAc,MAAkB;AAC9C,EAAI,IACE,IAEF,EAAY;GACV,SAAS;GACT,iBAAiB;GAClB,CAAC,GAGF,EAAY;GACV,UAAU;GACV,iBAAiB;GAClB,CAAC,GAGA,KAEF,EAAY;GACH;GACP,UAAU;GACX,CAAC,EACF,EAAc;GACZ,iBAAiB;GACjB,UAAU;GACX,CAAC,IAQF,
|
|
1
|
+
{"version":3,"file":"ForumThreadEditor.js","names":[],"sources":["../../../src/components/Forum/ForumThreadEditor.tsx"],"sourcesContent":["import { usePostReply, usePutReply } from '@/synapse-queries/forum/useReply'\nimport {\n useCreateThread,\n useUpdateThreadMessage,\n useUpdateThreadTitle,\n} from '@/synapse-queries/forum/useThread'\nimport { Box, TextField } from '@mui/material'\nimport { CreateDiscussionThread } from '@sage-bionetworks/synapse-types'\nimport { useState } from 'react'\nimport {\n ConfirmationButtons,\n ConfirmationDialog,\n} from '../ConfirmationDialog/ConfirmationDialog'\nimport { MarkdownEditor } from '../Markdown/MarkdownEditor'\n\nexport type ForumThreadEditorProps = {\n initialTitle?: string\n initialText?: string\n id: string\n onClose: () => void\n isReply: boolean\n} & (\n | { isDialog: false; openDialog?: never }\n | { isDialog: true; openDialog: boolean }\n)\n\nexport function ForumThreadEditor(props: ForumThreadEditorProps) {\n const {\n initialText,\n initialTitle,\n id,\n onClose,\n isReply,\n isDialog,\n openDialog,\n } = props\n\n const [title, setTitle] = useState<string>(initialTitle ?? '')\n const [text, setText] = useState<string>(initialText ?? '')\n const { mutate: updateTitle, isPending: titleUpdateIsPending } =\n useUpdateThreadTitle({\n onSuccess: () => onClose(),\n })\n const { mutate: updateMessage, isPending: messageUpdateIsPending } =\n useUpdateThreadMessage({\n onSuccess: () => onClose(),\n })\n const { mutate: createThread, isPending: createThreadIsPending } =\n useCreateThread({\n onSuccess: () => onClose(),\n })\n const { mutate: createReply, isPending: createReplyIsPending } = usePostReply(\n {\n onSuccess: () => onClose(),\n },\n )\n const { mutate: updateReply, isPending: updateReplyIsPending } = usePutReply({\n onSuccess: () => onClose(),\n })\n\n const updateIsPending =\n messageUpdateIsPending ||\n createReplyIsPending ||\n createThreadIsPending ||\n titleUpdateIsPending ||\n updateReplyIsPending\n\n const isExistingThread = !isReply && initialTitle\n\n const onSave = (text: string, title: string) => {\n if (isReply) {\n if (initialText) {\n // updating reply\n updateReply({\n replyId: id,\n messageMarkdown: text,\n })\n } else {\n // posting reply\n createReply({\n threadId: id,\n messageMarkdown: text,\n })\n }\n } else {\n if (isExistingThread) {\n // updating thread\n updateTitle({\n title: title,\n threadId: id,\n })\n updateMessage({\n messageMarkdown: text,\n threadId: id,\n })\n } else {\n // posting thread\n const request: CreateDiscussionThread = {\n forumId: id,\n title: title,\n messageMarkdown: text,\n }\n createThread(request)\n }\n }\n }\n\n const editorContent = (\n <div>\n {!isReply && (\n <TextField\n fullWidth\n sx={{ my: 1 }}\n placeholder=\"Title\"\n value={title}\n onChange={e => setTitle(e.target.value)}\n />\n )}\n <MarkdownEditor\n placeholder={'Write a reply...'}\n text={text}\n setText={setText}\n />\n </div>\n )\n\n const confirmButtonText = updateIsPending ? 'Saving' : 'Post'\n\n return (\n <>\n {isDialog ? (\n <ConfirmationDialog\n maxWidth=\"md\"\n open={openDialog}\n onCancel={onClose}\n title={\n isReply\n ? 'Edit Reply'\n : isExistingThread\n ? 'Edit Thread'\n : 'New Thread'\n }\n content={editorContent}\n onConfirm={() => onSave(text, title)}\n confirmButtonProps={{ children: confirmButtonText }}\n />\n ) : (\n <>\n {editorContent}\n <Box\n sx={{ display: 'flex', justifyContent: 'flex-end', gap: 1, my: 1 }}\n >\n <ConfirmationButtons\n onCancel={onClose}\n onConfirm={() => onSave(text, title)}\n confirmButtonProps={{ children: confirmButtonText }}\n />\n </Box>\n </>\n )}\n </>\n )\n}\n"],"mappings":";;;;;;;;AA0BA,SAAgB,EAAkB,GAA+B;CAC/D,IAAM,EACJ,gBACA,iBACA,OACA,YACA,YACA,aACA,kBACE,GAEE,CAAC,GAAO,KAAY,EAAiB,KAAgB,GAAG,EACxD,CAAC,GAAM,KAAW,EAAiB,KAAe,GAAG,EACrD,EAAE,QAAQ,GAAa,WAAW,MACtC,EAAqB,EACnB,iBAAiB,GAAS,EAC3B,CAAC,EACE,EAAE,QAAQ,GAAe,WAAW,MACxC,EAAuB,EACrB,iBAAiB,GAAS,EAC3B,CAAC,EACE,EAAE,QAAQ,GAAc,WAAW,MACvC,EAAgB,EACd,iBAAiB,GAAS,EAC3B,CAAC,EACE,EAAE,QAAQ,GAAa,WAAW,MAAyB,EAC/D,EACE,iBAAiB,GAAS,EAC3B,CACF,EACK,EAAE,QAAQ,GAAa,WAAW,MAAyB,EAAY,EAC3E,iBAAiB,GAAS,EAC3B,CAAC,EAEI,IACJ,KACA,KACA,KACA,KACA,GAEI,IAAmB,CAAC,KAAW,GAE/B,KAAU,GAAc,MAAkB;AAC9C,EAAI,IACE,IAEF,EAAY;GACV,SAAS;GACT,iBAAiB;GAClB,CAAC,GAGF,EAAY;GACV,UAAU;GACV,iBAAiB;GAClB,CAAC,GAGA,KAEF,EAAY;GACH;GACP,UAAU;GACX,CAAC,EACF,EAAc;GACZ,iBAAiB;GACjB,UAAU;GACX,CAAC,IAQF,EAAa;GAJX,SAAS;GACF;GACP,iBAAiB;GAEN,CAAQ;IAKrB,IACJ,kBAAC,OAAD,EAAA,UAAA,CACG,CAAC,KACA,kBAAC,GAAD;EACE,WAAA;EACA,IAAI,EAAE,IAAI,GAAG;EACb,aAAY;EACZ,OAAO;EACP,WAAU,MAAK,EAAS,EAAE,OAAO,MAAM;EACvC,CAAA,EAEJ,kBAAC,GAAD;EACE,aAAa;EACP;EACG;EACT,CAAA,CACE,EAAA,CAAA,EAGF,IAAoB,IAAkB,WAAW;AAEvD,QACE,kBAAA,GAAA,EAAA,UACG,IACC,kBAAC,GAAD;EACE,UAAS;EACT,MAAM;EACN,UAAU;EACV,OACE,IACI,eACA,IACA,gBACA;EAEN,SAAS;EACT,iBAAiB,EAAO,GAAM,EAAM;EACpC,oBAAoB,EAAE,UAAU,GAAmB;EACnD,CAAA,GAEF,kBAAA,GAAA,EAAA,UAAA,CACG,GACD,kBAAC,GAAD;EACE,IAAI;GAAE,SAAS;GAAQ,gBAAgB;GAAY,KAAK;GAAG,IAAI;GAAG;YAElE,kBAAC,GAAD;GACE,UAAU;GACV,iBAAiB,EAAO,GAAM,EAAM;GACpC,oBAAoB,EAAE,UAAU,GAAmB;GACnD,CAAA;EACE,CAAA,CACL,EAAA,CAAA,EAEJ,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FullTextSearchUtils.js","names":[],"sources":["../../../src/components/FullTextSearch/FullTextSearchUtils.ts"],"sourcesContent":["import { SYNAPSE_ENTITY_ID_REGEX } from '@/utils/functions/RegularExpressions'\nimport {\n ColumnModel,\n ColumnSingleValueFilterOperator,\n ColumnSingleValueQueryFilter,\n QueryBundleRequest,\n TextMatchesQueryFilter,\n} from '@sage-bionetworks/synapse-types'\nimport { getFileColumnModelId } from '../SynapseTable/SynapseTableUtils'\nimport { FTSConfig } from '../SynapseTable/SearchV2'\nimport { getWordCount } from '../TextField/TextFieldWithWordLimit'\n\n/**\n * Expects a search expression of the form: \"searchText\" @3\n * In this example, this function will return the following string via a regex: searchText\n */\nexport function getSearchTextFromBooleanModeSearchExpression(\n searchExpression: string,\n) {\n /**\n * ^\"(.+?)\": Matches the opening double quote and lazily captures any characters until the next quote.\n * \\s*@\\d+$: Matches optional whitespace, the @ symbol, and one or more digits at the end.\n */\n const match = searchExpression.match(/^\"(.+?)\"\\s*@\\d+$/)\n if (match) {\n return match[1]\n } else {\n return ''\n }\n}\n\n// Convert the user-provided searchText into a search expression given the current FTS configuration.\n// If configured to search using BOOLEAN mode, search expression will wrap the search text in double quotes and include the distance.\nexport function getTextMatchesQueryFilter(\n searchText: string,\n ftsConfig: FTSConfig = {\n textMatchesMode: 'NATURAL_LANGUAGE',\n },\n) {\n const { textMatchesMode, distance = 0 } = ftsConfig\n let searchExpression = searchText\n if (textMatchesMode == 'BOOLEAN') {\n //split by non-word character and ignore empty strings\n const searchTextWordLength = getWordCount(searchText)\n const distanceToUse = Math.max(distance, searchTextWordLength)\n searchExpression = `\"${searchText.replaceAll('\"', '')}\" @${distanceToUse}`\n }\n const textMatchesQueryFilter: TextMatchesQueryFilter = {\n concreteType: 'org.sagebionetworks.repo.model.table.TextMatchesQueryFilter',\n searchExpression,\n searchMode: ftsConfig.textMatchesMode,\n }\n return textMatchesQueryFilter\n}\n\nexport function updateQueryUsingSearchTerm(\n queryBundleRequest: QueryBundleRequest,\n columnModels: ColumnModel[] | undefined,\n searchText: string,\n ftsConfig?: FTSConfig,\n): QueryBundleRequest {\n const { additionalFilters = [] } = queryBundleRequest.query\n const synIdColumnModelId = getFileColumnModelId(columnModels)\n const isSynapseID = searchText.match(SYNAPSE_ENTITY_ID_REGEX)\n if (isSynapseID && synIdColumnModelId) {\n const idColumnModel = columnModels?.filter(\n el => el.id === synIdColumnModelId,\n )\n const singleValueQueryFilter: ColumnSingleValueQueryFilter = {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n columnName: idColumnModel![0].name,\n operator: ColumnSingleValueFilterOperator.IN,\n values: [searchText],\n }\n // Replace the active filter on the column, if one exists\n const matchingFilter = additionalFilters.find(\n filter =>\n filter.concreteType == singleValueQueryFilter.concreteType &&\n filter.columnName == singleValueQueryFilter.columnName,\n ) as ColumnSingleValueQueryFilter\n if (matchingFilter) {\n if (!matchingFilter.values.includes(searchText)) {\n matchingFilter.values.push(searchText)\n }\n return queryBundleRequest\n }\n additionalFilters.push(singleValueQueryFilter)\n } else {\n const textMatchesQueryFilter = getTextMatchesQueryFilter(\n searchText,\n ftsConfig,\n )\n // PORTALS-2093: does this additional filter already exist?\n const found = additionalFilters.find(\n filter =>\n filter.concreteType == textMatchesQueryFilter.concreteType &&\n filter.searchExpression == textMatchesQueryFilter.searchExpression,\n )\n if (found) {\n return queryBundleRequest\n }\n additionalFilters.push(textMatchesQueryFilter)\n }\n queryBundleRequest.query.additionalFilters = additionalFilters\n return queryBundleRequest\n}\n"],"mappings":";;;;;AAgBA,SAAgB,EACd,GACA;CAKA,IAAM,IAAQ,EAAiB,MAAM,mBAAmB;AAItD,QAHE,IACK,EAAM,KAEN;;AAMX,SAAgB,EACd,GACA,IAAuB,EACrB,iBAAiB,oBAClB,EACD;CACA,IAAM,EAAE,oBAAiB,cAAW,MAAM,GACtC,IAAmB;AACvB,KAAI,KAAmB,WAAW;EAEhC,IAAM,IAAuB,EAAa,EAAW,EAC/C,IAAgB,KAAK,IAAI,GAAU,EAAqB;AAC9D,MAAmB,IAAI,EAAW,WAAW,MAAK,GAAG,CAAC,KAAK;;AAO7D,
|
|
1
|
+
{"version":3,"file":"FullTextSearchUtils.js","names":[],"sources":["../../../src/components/FullTextSearch/FullTextSearchUtils.ts"],"sourcesContent":["import { SYNAPSE_ENTITY_ID_REGEX } from '@/utils/functions/RegularExpressions'\nimport {\n ColumnModel,\n ColumnSingleValueFilterOperator,\n ColumnSingleValueQueryFilter,\n QueryBundleRequest,\n TextMatchesQueryFilter,\n} from '@sage-bionetworks/synapse-types'\nimport { getFileColumnModelId } from '../SynapseTable/SynapseTableUtils'\nimport { FTSConfig } from '../SynapseTable/SearchV2'\nimport { getWordCount } from '../TextField/TextFieldWithWordLimit'\n\n/**\n * Expects a search expression of the form: \"searchText\" @3\n * In this example, this function will return the following string via a regex: searchText\n */\nexport function getSearchTextFromBooleanModeSearchExpression(\n searchExpression: string,\n) {\n /**\n * ^\"(.+?)\": Matches the opening double quote and lazily captures any characters until the next quote.\n * \\s*@\\d+$: Matches optional whitespace, the @ symbol, and one or more digits at the end.\n */\n const match = searchExpression.match(/^\"(.+?)\"\\s*@\\d+$/)\n if (match) {\n return match[1]\n } else {\n return ''\n }\n}\n\n// Convert the user-provided searchText into a search expression given the current FTS configuration.\n// If configured to search using BOOLEAN mode, search expression will wrap the search text in double quotes and include the distance.\nexport function getTextMatchesQueryFilter(\n searchText: string,\n ftsConfig: FTSConfig = {\n textMatchesMode: 'NATURAL_LANGUAGE',\n },\n) {\n const { textMatchesMode, distance = 0 } = ftsConfig\n let searchExpression = searchText\n if (textMatchesMode == 'BOOLEAN') {\n //split by non-word character and ignore empty strings\n const searchTextWordLength = getWordCount(searchText)\n const distanceToUse = Math.max(distance, searchTextWordLength)\n searchExpression = `\"${searchText.replaceAll('\"', '')}\" @${distanceToUse}`\n }\n const textMatchesQueryFilter: TextMatchesQueryFilter = {\n concreteType: 'org.sagebionetworks.repo.model.table.TextMatchesQueryFilter',\n searchExpression,\n searchMode: ftsConfig.textMatchesMode,\n }\n return textMatchesQueryFilter\n}\n\nexport function updateQueryUsingSearchTerm(\n queryBundleRequest: QueryBundleRequest,\n columnModels: ColumnModel[] | undefined,\n searchText: string,\n ftsConfig?: FTSConfig,\n): QueryBundleRequest {\n const { additionalFilters = [] } = queryBundleRequest.query\n const synIdColumnModelId = getFileColumnModelId(columnModels)\n const isSynapseID = searchText.match(SYNAPSE_ENTITY_ID_REGEX)\n if (isSynapseID && synIdColumnModelId) {\n const idColumnModel = columnModels?.filter(\n el => el.id === synIdColumnModelId,\n )\n const singleValueQueryFilter: ColumnSingleValueQueryFilter = {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n columnName: idColumnModel![0].name,\n operator: ColumnSingleValueFilterOperator.IN,\n values: [searchText],\n }\n // Replace the active filter on the column, if one exists\n const matchingFilter = additionalFilters.find(\n filter =>\n filter.concreteType == singleValueQueryFilter.concreteType &&\n filter.columnName == singleValueQueryFilter.columnName,\n ) as ColumnSingleValueQueryFilter\n if (matchingFilter) {\n if (!matchingFilter.values.includes(searchText)) {\n matchingFilter.values.push(searchText)\n }\n return queryBundleRequest\n }\n additionalFilters.push(singleValueQueryFilter)\n } else {\n const textMatchesQueryFilter = getTextMatchesQueryFilter(\n searchText,\n ftsConfig,\n )\n // PORTALS-2093: does this additional filter already exist?\n const found = additionalFilters.find(\n filter =>\n filter.concreteType == textMatchesQueryFilter.concreteType &&\n filter.searchExpression == textMatchesQueryFilter.searchExpression,\n )\n if (found) {\n return queryBundleRequest\n }\n additionalFilters.push(textMatchesQueryFilter)\n }\n queryBundleRequest.query.additionalFilters = additionalFilters\n return queryBundleRequest\n}\n"],"mappings":";;;;;AAgBA,SAAgB,EACd,GACA;CAKA,IAAM,IAAQ,EAAiB,MAAM,mBAAmB;AAItD,QAHE,IACK,EAAM,KAEN;;AAMX,SAAgB,EACd,GACA,IAAuB,EACrB,iBAAiB,oBAClB,EACD;CACA,IAAM,EAAE,oBAAiB,cAAW,MAAM,GACtC,IAAmB;AACvB,KAAI,KAAmB,WAAW;EAEhC,IAAM,IAAuB,EAAa,EAAW,EAC/C,IAAgB,KAAK,IAAI,GAAU,EAAqB;AAC9D,MAAmB,IAAI,EAAW,WAAW,MAAK,GAAG,CAAC,KAAK;;AAO7D,QAAO;EAJL,cAAc;EACd;EACA,YAAY,EAAU;EAEjB;;AAGT,SAAgB,EACd,GACA,GACA,GACA,GACoB;CACpB,IAAM,EAAE,uBAAoB,EAAE,KAAK,EAAmB,OAChD,IAAqB,EAAqB,EAAa;AAE7D,KADoB,EAAW,MAAM,EACjC,IAAe,GAAoB;EAIrC,IAAM,IAAuD;GAC3D,cACE;GACF,aANoB,GAAc,QAClC,MAAM,EAAG,OAAO,EACjB,EAI4B,GAAG;GAC9B,UAAU,EAAgC;GAC1C,QAAQ,CAAC,EAAW;GACrB,EAEK,IAAiB,EAAkB,MACvC,MACE,EAAO,gBAAgB,EAAuB,gBAC9C,EAAO,cAAc,EAAuB,WAC/C;AACD,MAAI,EAIF,QAHK,EAAe,OAAO,SAAS,EAAW,IAC7C,EAAe,OAAO,KAAK,EAAW,EAEjC;AAET,IAAkB,KAAK,EAAuB;QACzC;EACL,IAAM,IAAyB,EAC7B,GACA,EACD;AAOD,MALc,EAAkB,MAC9B,MACE,EAAO,gBAAgB,EAAuB,gBAC9C,EAAO,oBAAoB,EAAuB,iBAElD,CACF,QAAO;AAET,IAAkB,KAAK,EAAuB;;AAGhD,QADA,EAAmB,MAAM,oBAAoB,GACtC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GenericCard.d.ts","sourceRoot":"","sources":["../../../src/components/GenericCard/GenericCard.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,6CAA6C,CAAA;AAEvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAA;AACvE,OAAO,KAAoC,MAAM,OAAO,CAAA;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AACzD,OAAmB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAG7D,OAAO,EAAE,4BAA4B,EAAE,MAAM,oDAAoD,CAAA;AAIjG,kHAAkH;AAClH,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,KAAK,CAAC,SAAS,CAAA;IACrB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,0FAA0F;IAC1F,IAAI,EAAE,MAAM,CAAA;IACZ,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAA;IACb,mEAAmE;IACnE,sBAAsB,CAAC,EAAE;QACvB,IAAI,EAAE,MAAM,CAAA;QACZ,MAAM,EAAE,MAAM,CAAA;KACf,CAAA;IACD,6FAA6F;IAC7F,kCAAkC,CAAC,EAAE;QACnC,sEAAsE;QACtE,qBAAqB,EAAE,qBAAqB,CAAA;QAC5C,gDAAgD;QAChD,gBAAgB,EAAE,OAAO,CAAA;KAC1B,CAAA;IACD,uDAAuD;IACvD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,iDAAiD;IACjD,WAAW,EAAE,MAAM,CAAA;IACnB,mEAAmE;IACnE,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,qEAAqE;IACrE,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IACrC,8DAA8D;IAC9D,cAAc,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAChC,qEAAqE;IACrE,cAAc,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAChC,uDAAuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,gEAAgE;IAChE,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IACrC;wBACoB;IACpB,0BAA0B,CAAC,EAAE,OAAO,CAAA;IACpC;;OAEG;IACH,IAAI,EAAE,KAAK,CAAC,SAAS,CAAA;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,SAAS,EAAE,CAAA;IACpB;;OAEG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B;;OAEG;IACH,aAAa,CAAC,EAAE,aAAa,GAAG,aAAa,EAAE,CAAA;IAC/C;;OAEG;IACH,gBAAgB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAClC;;OAEG;IACH,uBAAuB,CAAC,EAAE,4BAA4B,CAAA;IACtD;;OAEG;IACH,iBAAiB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACnC;;OAEG;IACH,qBAAqB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvC;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB,CAAA;AAID;;GAEG;AACH,eAAO,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"GenericCard.d.ts","sourceRoot":"","sources":["../../../src/components/GenericCard/GenericCard.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,6CAA6C,CAAA;AAEvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAA;AACvE,OAAO,KAAoC,MAAM,OAAO,CAAA;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AACzD,OAAmB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAG7D,OAAO,EAAE,4BAA4B,EAAE,MAAM,oDAAoD,CAAA;AAIjG,kHAAkH;AAClH,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,KAAK,CAAC,SAAS,CAAA;IACrB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,0FAA0F;IAC1F,IAAI,EAAE,MAAM,CAAA;IACZ,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAA;IACb,mEAAmE;IACnE,sBAAsB,CAAC,EAAE;QACvB,IAAI,EAAE,MAAM,CAAA;QACZ,MAAM,EAAE,MAAM,CAAA;KACf,CAAA;IACD,6FAA6F;IAC7F,kCAAkC,CAAC,EAAE;QACnC,sEAAsE;QACtE,qBAAqB,EAAE,qBAAqB,CAAA;QAC5C,gDAAgD;QAChD,gBAAgB,EAAE,OAAO,CAAA;KAC1B,CAAA;IACD,uDAAuD;IACvD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,iDAAiD;IACjD,WAAW,EAAE,MAAM,CAAA;IACnB,mEAAmE;IACnE,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,qEAAqE;IACrE,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IACrC,8DAA8D;IAC9D,cAAc,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAChC,qEAAqE;IACrE,cAAc,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAChC,uDAAuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,gEAAgE;IAChE,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IACrC;wBACoB;IACpB,0BAA0B,CAAC,EAAE,OAAO,CAAA;IACpC;;OAEG;IACH,IAAI,EAAE,KAAK,CAAC,SAAS,CAAA;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,SAAS,EAAE,CAAA;IACpB;;OAEG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B;;OAEG;IACH,aAAa,CAAC,EAAE,aAAa,GAAG,aAAa,EAAE,CAAA;IAC/C;;OAEG;IACH,gBAAgB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAClC;;OAEG;IACH,uBAAuB,CAAC,EAAE,4BAA4B,CAAA;IACtD;;OAEG;IACH,iBAAiB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACnC;;OAEG;IACH,qBAAqB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvC;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB,CAAA;AAID;;GAEG;AACH,eAAO,MAAM,WAAW,yFA8KtB,CAAA;AAEF,eAAe,WAAW,CAAA"}
|
|
@@ -2,16 +2,16 @@ import e from "../row_renderers/utils/CardFooter.js";
|
|
|
2
2
|
import "../row_renderers/utils/index.js";
|
|
3
3
|
import { SmartLink as t } from "../SmartLink/SmartLink.js";
|
|
4
4
|
import { GenericCardTitle as n } from "./GenericCardTitle.js";
|
|
5
|
-
import {
|
|
6
|
-
import i from "
|
|
7
|
-
import
|
|
5
|
+
import { FileHandleLink as r } from "../widgets/FileHandleLink.js";
|
|
6
|
+
import { CollapsibleDescription as i } from "./CollapsibleDescription.js";
|
|
7
|
+
import a from "../HeaderCard.js";
|
|
8
8
|
import { forwardRef as o } from "react";
|
|
9
9
|
import { Box as s, Stack as c } from "@mui/material";
|
|
10
10
|
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
11
11
|
//#region src/components/GenericCard/GenericCard.tsx
|
|
12
12
|
var d = [], f = o(function(o, f) {
|
|
13
13
|
let { icon: p, type: m, title: h, titleLinkConfiguration: g, titleAsFileHandleLinkConfiguration: _, subtitle: v, description: y, descriptionSubTitle: b = "", descriptionConfig: x, cardTopContent: S, cardTopButtons: C, isHeader: w = !1, headerCardVariant: T, useStylesForDisplayedImage: E = !1, labels: D = d, secondaryLabelLimit: O, ctaLinkConfig: k, renderedIconList: A, sustainabilityScorecard: j, cardTypeAdornment: M, titleAreaRightContent: N, charCountCutoff: P } = o, F = D.length > 0;
|
|
14
|
-
return w ? /* @__PURE__ */ l(
|
|
14
|
+
return w ? /* @__PURE__ */ l(a, {
|
|
15
15
|
ref: f,
|
|
16
16
|
headerCardVariant: T,
|
|
17
17
|
descriptionConfig: x,
|
|
@@ -29,7 +29,12 @@ var d = [], f = o(function(o, f) {
|
|
|
29
29
|
secondaryLabelLimit: O,
|
|
30
30
|
cardTopButtons: C,
|
|
31
31
|
cardTopContent: S,
|
|
32
|
-
sustainabilityScorecard: j
|
|
32
|
+
sustainabilityScorecard: j,
|
|
33
|
+
renderedIconList: A,
|
|
34
|
+
cardTypeAdornment: M,
|
|
35
|
+
titleAsFileHandleLinkConfiguration: _,
|
|
36
|
+
titleAreaRightContent: N,
|
|
37
|
+
descriptionSubTitle: b
|
|
33
38
|
}) : /* @__PURE__ */ u("div", {
|
|
34
39
|
style: {
|
|
35
40
|
marginTop: w ? "0px" : void 0,
|
|
@@ -81,7 +86,7 @@ var d = [], f = o(function(o, f) {
|
|
|
81
86
|
title: h,
|
|
82
87
|
href: g?.href,
|
|
83
88
|
target: g?.target
|
|
84
|
-
}), _ && /* @__PURE__ */ l(
|
|
89
|
+
}), _ && /* @__PURE__ */ l(r, {
|
|
85
90
|
fileHandleAssociation: _.fileHandleAssociation,
|
|
86
91
|
showDownloadIcon: _.showDownloadIcon,
|
|
87
92
|
displayValue: h
|
|
@@ -91,7 +96,7 @@ var d = [], f = o(function(o, f) {
|
|
|
91
96
|
className: "SRC-author",
|
|
92
97
|
children: v
|
|
93
98
|
}),
|
|
94
|
-
/* @__PURE__ */ l(
|
|
99
|
+
/* @__PURE__ */ l(i, {
|
|
95
100
|
description: y,
|
|
96
101
|
descriptionSubTitle: b,
|
|
97
102
|
descriptionConfig: x
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GenericCard.js","names":[],"sources":["../../../src/components/GenericCard/GenericCard.tsx"],"sourcesContent":["import { GenericCardTitle } from '@/components/GenericCard/GenericCardTitle'\nimport { CardLabel } from '@/components/row_renderers/utils/CardFooter'\nimport { Box, Stack } from '@mui/material'\nimport { FileHandleAssociation } from '@sage-bionetworks/synapse-types'\nimport React, { CSSProperties, forwardRef } from 'react'\nimport { DescriptionConfig } from '../CardContainerLogic'\nimport HeaderCard, { HeaderCardVariant } from '../HeaderCard'\nimport { CardFooter } from '../row_renderers/utils'\nimport { SmartLink } from '../SmartLink/SmartLink'\nimport { SustainabilityScorecardProps } from '../SustainabilityScorecard/SustainabilityScorecard'\nimport { FileHandleLink } from '../widgets/FileHandleLink'\nimport { CollapsibleDescription } from './CollapsibleDescription'\n\n/** Resolved CTA link configuration with actual href values (as opposed to CTACardLink which uses column names) */\nexport type CTALinkConfig = {\n text: React.ReactNode\n href?: string\n target?: string\n}\n\nexport type GenericCardProps = {\n /** String representing the 'type' of object. This is displayed as a label on the card. */\n type: string\n /** The title displayed on the card. */\n title: string\n /** Optionally provide href/target if the title should be a link */\n titleLinkConfiguration?: {\n href: string\n target: string\n }\n /** Optionally provide configuration if the title should be a link to a Synapse FileHandle */\n titleAsFileHandleLinkConfiguration?: {\n /** The FileHandleAssociation used to get access to the file handle */\n fileHandleAssociation: FileHandleAssociation\n /** Whether a 'download' icon should be shown */\n showDownloadIcon: boolean\n }\n /** An optional subtitle to be displayed on the card */\n subtitle?: string\n /** An description to be displayed on the card */\n description: string\n /** An optional description subtitle to be displayed on the card */\n descriptionSubTitle?: string\n /** Configuration for altering the display of the description prop */\n descriptionConfig?: DescriptionConfig\n /** Optional slot for adding content to the top of the card */\n cardTopContent?: React.ReactNode\n /** Optional slot for adding action buttons to the top of the card */\n cardTopButtons?: React.ReactNode\n /** If true, a HeaderCard component will be rendered */\n isHeader?: boolean\n /** The variant of HeaderCard to render if `isHeader` is true */\n headerCardVariant?: HeaderCardVariant\n /** Set to true if the icon is an arbitrary image. The card styles will be updated to accommodate the image\n * @default false */\n useStylesForDisplayedImage?: boolean\n /**\n * The rendered icon on the card\n */\n icon: React.ReactNode\n /**\n * The card labels to be displayed in the footer of the card\n */\n labels?: CardLabel[]\n /**\n * The initial number of labels to display in the footer of the card\n */\n secondaryLabelLimit?: number\n /**\n * Optional configuration for displaying CTA button(s) on the card. Accepts a single config or an array.\n */\n ctaLinkConfig?: CTALinkConfig | CTALinkConfig[]\n /**\n * The rendered icon list on the card\n */\n renderedIconList?: React.ReactNode\n /**\n * Optional sustainability scorecard to be displayed on the header card\n */\n sustainabilityScorecard?: SustainabilityScorecardProps\n /**\n * Optional ReactNode to be rendered next to the card type\n */\n cardTypeAdornment?: React.ReactNode\n /**\n * Optional content to render to the right of the title/subtitle/description area.\n */\n titleAreaRightContent?: React.ReactNode\n /**\n * Character count threshold for truncating description\n * @default 400\n */\n charCountCutoff?: number\n}\n\nconst EMPTY_CARD_LABEL_ARRAY: CardLabel[] = []\n\n/**\n * Generic portal card UI component with a predefined layout\n */\nexport const GenericCard = forwardRef(function GenericCard(\n props: GenericCardProps,\n ref: React.Ref<HTMLDivElement>,\n) {\n const {\n icon,\n type,\n title,\n titleLinkConfiguration,\n titleAsFileHandleLinkConfiguration,\n subtitle,\n description,\n descriptionSubTitle = '',\n descriptionConfig,\n cardTopContent,\n cardTopButtons,\n isHeader = false,\n headerCardVariant,\n useStylesForDisplayedImage = false,\n labels = EMPTY_CARD_LABEL_ARRAY,\n secondaryLabelLimit,\n ctaLinkConfig,\n renderedIconList,\n sustainabilityScorecard,\n cardTypeAdornment,\n titleAreaRightContent,\n charCountCutoff,\n } = props\n\n const showFooter = labels.length > 0\n\n const style: CSSProperties = {\n // undefined, take default value from class\n marginTop: isHeader ? '0px' : undefined,\n marginBottom: isHeader ? '0px' : undefined,\n paddingBottom:\n showFooter || useStylesForDisplayedImage ? undefined : '15px',\n }\n\n if (isHeader) {\n return (\n <HeaderCard\n ref={ref}\n headerCardVariant={headerCardVariant}\n descriptionConfig={descriptionConfig}\n charCountCutoff={charCountCutoff}\n title={title}\n subTitle={subtitle}\n description={description}\n type={type}\n icon={icon}\n values={labels}\n href={titleLinkConfiguration?.href}\n target={titleLinkConfiguration?.target}\n ctaLinkConfig={ctaLinkConfig}\n isAlignToLeftNav={true}\n secondaryLabelLimit={secondaryLabelLimit}\n cardTopButtons={cardTopButtons}\n cardTopContent={cardTopContent}\n sustainabilityScorecard={sustainabilityScorecard}\n />\n )\n }\n\n return (\n <div style={style} ref={ref} className={'SRC-portalCard'}>\n <div className={'SRC-portalCardMain'}>\n {icon}\n <div className=\"SRC-cardContent\">\n {cardTopButtons && (\n <Box\n sx={{\n position: 'absolute',\n right: '24px',\n display: 'flex',\n float: 'right',\n flexDirection: 'row',\n gap: '10px',\n }}\n >\n {cardTopButtons}\n </Box>\n )}\n <Stack\n sx={{\n flexDirection: 'row',\n alignItems: 'center',\n gap: '10px',\n }}\n >\n <div className=\"SRC-type\">{type}</div>\n {cardTypeAdornment}\n </Stack>\n {renderedIconList}\n <Box className=\"SRC-cardTitleArea\">\n <Box sx={{ flex: 1, minWidth: 0 }}>\n <div>\n <h3\n className=\"SRC-boldText SRC-blackText\"\n style={{ margin: 'none' }}\n >\n {!titleAsFileHandleLinkConfiguration && (\n <GenericCardTitle\n title={title}\n href={titleLinkConfiguration?.href}\n target={titleLinkConfiguration?.target}\n />\n )}\n {titleAsFileHandleLinkConfiguration && (\n <FileHandleLink\n fileHandleAssociation={\n titleAsFileHandleLinkConfiguration.fileHandleAssociation\n }\n showDownloadIcon={\n titleAsFileHandleLinkConfiguration.showDownloadIcon\n }\n displayValue={title}\n />\n )}\n </h3>\n </div>\n {subtitle && <div className=\"SRC-author\">{subtitle}</div>}\n <CollapsibleDescription\n description={description}\n descriptionSubTitle={descriptionSubTitle}\n descriptionConfig={descriptionConfig}\n />\n {ctaLinkConfig && (\n <Box\n sx={{ mt: '20px', display: 'flex', gap: 2, flexWrap: 'wrap' }}\n >\n {(Array.isArray(ctaLinkConfig)\n ? ctaLinkConfig\n : [ctaLinkConfig]\n ).map(\n (config, index) =>\n config.text &&\n config.href && (\n <SmartLink\n key={index}\n href={config.href}\n target={config.target}\n >\n {config.text}\n </SmartLink>\n ),\n )}\n </Box>\n )}\n </Box>\n {titleAreaRightContent && (\n <div className=\"SRC-cardTitleAreaDetails\">\n {titleAreaRightContent}\n </div>\n )}\n </Box>\n </div>\n </div>\n {showFooter && (\n <CardFooter\n isHeader={false}\n secondaryLabelLimit={secondaryLabelLimit}\n values={labels}\n className={useStylesForDisplayedImage ? undefined : 'hasIcon'}\n cardTopContent={cardTopContent}\n />\n )}\n </div>\n )\n})\n\nexport default GenericCard\n"],"mappings":";;;;;;;;;;;AA+FA,IAAM,IAAsC,EAAE,EAKjC,IAAc,EAAW,SACpC,GACA,GACA;CACA,IAAM,EACJ,SACA,SACA,UACA,2BACA,uCACA,aACA,gBACA,yBAAsB,IACtB,sBACA,mBACA,mBACA,cAAW,IACX,sBACA,gCAA6B,IAC7B,YAAS,GACT,wBACA,kBACA,qBACA,4BACA,sBACA,0BACA,uBACE,GAEE,IAAa,EAAO,SAAS;AAmCnC,QAzBI,IAEA,kBAAC,GAAD;EACO;EACc;EACA;EACF;EACV;EACP,UAAU;EACG;EACP;EACA;EACN,QAAQ;EACR,MAAM,GAAwB;EAC9B,QAAQ,GAAwB;EACjB;EACf,kBAAkB;EACG;EACL;EACA;EACS;EACzB,CAAA,GAKJ,kBAAC,OAAD;EAAY,OAlCe;GAE3B,WAAW,IAAW,QAAQ,KAAA;GAC9B,cAAc,IAAW,QAAQ,KAAA;GACjC,eACE,KAAc,IAA6B,KAAA,IAAY;GAC1D;EA4ByB;EAAK,WAAW;YAAxC,CACE,kBAAC,OAAD;GAAK,WAAW;aAAhB,CACG,GACD,kBAAC,OAAD;IAAK,WAAU;cAAf;KACG,KACC,kBAAC,GAAD;MACE,IAAI;OACF,UAAU;OACV,OAAO;OACP,SAAS;OACT,OAAO;OACP,eAAe;OACf,KAAK;OACN;gBAEA;MACG,CAAA;KAER,kBAAC,GAAD;MACE,IAAI;OACF,eAAe;OACf,YAAY;OACZ,KAAK;OACN;gBALH,CAOE,kBAAC,OAAD;OAAK,WAAU;iBAAY;OAAW,CAAA,EACrC,EACK;;KACP;KACD,kBAAC,GAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD;OAAK,IAAI;QAAE,MAAM;QAAG,UAAU;QAAG;iBAAjC;QACE,kBAAC,OAAD,EAAA,UACE,kBAAC,MAAD;SACE,WAAU;SACV,OAAO,EAAE,QAAQ,QAAQ;mBAF3B,CAIG,CAAC,KACA,kBAAC,GAAD;UACS;UACP,MAAM,GAAwB;UAC9B,QAAQ,GAAwB;UAChC,CAAA,EAEH,KACC,kBAAC,GAAD;UACE,uBACE,EAAmC;UAErC,kBACE,EAAmC;UAErC,cAAc;UACd,CAAA,CAED;YACD,CAAA;QACL,KAAY,kBAAC,OAAD;SAAK,WAAU;mBAAc;SAAe,CAAA;QACzD,kBAAC,GAAD;SACe;SACQ;SACF;SACnB,CAAA;QACD,KACC,kBAAC,GAAD;SACE,IAAI;UAAE,IAAI;UAAQ,SAAS;UAAQ,KAAK;UAAG,UAAU;UAAQ;oBAE3D,MAAM,QAAQ,EAAc,GAC1B,IACA,CAAC,EAAc,EACjB,KACC,GAAQ,MACP,EAAO,QACP,EAAO,QACL,kBAAC,GAAD;UAEE,MAAM,EAAO;UACb,QAAQ,EAAO;oBAEd,EAAO;UACE,EALL,EAKK,CAEjB;SACG,CAAA;QAEJ;UACL,KACC,kBAAC,OAAD;OAAK,WAAU;iBACZ;OACG,CAAA,CAEJ;;KACF;MACF;MACL,KACC,kBAAC,GAAD;GACE,UAAU;GACW;GACrB,QAAQ;GACR,WAAW,IAA6B,KAAA,IAAY;GACpC;GAChB,CAAA,CAEA;;EAER"}
|
|
1
|
+
{"version":3,"file":"GenericCard.js","names":[],"sources":["../../../src/components/GenericCard/GenericCard.tsx"],"sourcesContent":["import { GenericCardTitle } from '@/components/GenericCard/GenericCardTitle'\nimport { CardLabel } from '@/components/row_renderers/utils/CardFooter'\nimport { Box, Stack } from '@mui/material'\nimport { FileHandleAssociation } from '@sage-bionetworks/synapse-types'\nimport React, { CSSProperties, forwardRef } from 'react'\nimport { DescriptionConfig } from '../CardContainerLogic'\nimport HeaderCard, { HeaderCardVariant } from '../HeaderCard'\nimport { CardFooter } from '../row_renderers/utils'\nimport { SmartLink } from '../SmartLink/SmartLink'\nimport { SustainabilityScorecardProps } from '../SustainabilityScorecard/SustainabilityScorecard'\nimport { FileHandleLink } from '../widgets/FileHandleLink'\nimport { CollapsibleDescription } from './CollapsibleDescription'\n\n/** Resolved CTA link configuration with actual href values (as opposed to CTACardLink which uses column names) */\nexport type CTALinkConfig = {\n text: React.ReactNode\n href?: string\n target?: string\n}\n\nexport type GenericCardProps = {\n /** String representing the 'type' of object. This is displayed as a label on the card. */\n type: string\n /** The title displayed on the card. */\n title: string\n /** Optionally provide href/target if the title should be a link */\n titleLinkConfiguration?: {\n href: string\n target: string\n }\n /** Optionally provide configuration if the title should be a link to a Synapse FileHandle */\n titleAsFileHandleLinkConfiguration?: {\n /** The FileHandleAssociation used to get access to the file handle */\n fileHandleAssociation: FileHandleAssociation\n /** Whether a 'download' icon should be shown */\n showDownloadIcon: boolean\n }\n /** An optional subtitle to be displayed on the card */\n subtitle?: string\n /** An description to be displayed on the card */\n description: string\n /** An optional description subtitle to be displayed on the card */\n descriptionSubTitle?: string\n /** Configuration for altering the display of the description prop */\n descriptionConfig?: DescriptionConfig\n /** Optional slot for adding content to the top of the card */\n cardTopContent?: React.ReactNode\n /** Optional slot for adding action buttons to the top of the card */\n cardTopButtons?: React.ReactNode\n /** If true, a HeaderCard component will be rendered */\n isHeader?: boolean\n /** The variant of HeaderCard to render if `isHeader` is true */\n headerCardVariant?: HeaderCardVariant\n /** Set to true if the icon is an arbitrary image. The card styles will be updated to accommodate the image\n * @default false */\n useStylesForDisplayedImage?: boolean\n /**\n * The rendered icon on the card\n */\n icon: React.ReactNode\n /**\n * The card labels to be displayed in the footer of the card\n */\n labels?: CardLabel[]\n /**\n * The initial number of labels to display in the footer of the card\n */\n secondaryLabelLimit?: number\n /**\n * Optional configuration for displaying CTA button(s) on the card. Accepts a single config or an array.\n */\n ctaLinkConfig?: CTALinkConfig | CTALinkConfig[]\n /**\n * The rendered icon list on the card\n */\n renderedIconList?: React.ReactNode\n /**\n * Optional sustainability scorecard to be displayed on the header card\n */\n sustainabilityScorecard?: SustainabilityScorecardProps\n /**\n * Optional ReactNode to be rendered next to the card type\n */\n cardTypeAdornment?: React.ReactNode\n /**\n * Optional content to render to the right of the title/subtitle/description area.\n */\n titleAreaRightContent?: React.ReactNode\n /**\n * Character count threshold for truncating description\n * @default 400\n */\n charCountCutoff?: number\n}\n\nconst EMPTY_CARD_LABEL_ARRAY: CardLabel[] = []\n\n/**\n * Generic portal card UI component with a predefined layout\n */\nexport const GenericCard = forwardRef(function GenericCard(\n props: GenericCardProps,\n ref: React.Ref<HTMLDivElement>,\n) {\n const {\n icon,\n type,\n title,\n titleLinkConfiguration,\n titleAsFileHandleLinkConfiguration,\n subtitle,\n description,\n descriptionSubTitle = '',\n descriptionConfig,\n cardTopContent,\n cardTopButtons,\n isHeader = false,\n headerCardVariant,\n useStylesForDisplayedImage = false,\n labels = EMPTY_CARD_LABEL_ARRAY,\n secondaryLabelLimit,\n ctaLinkConfig,\n renderedIconList,\n sustainabilityScorecard,\n cardTypeAdornment,\n titleAreaRightContent,\n charCountCutoff,\n } = props\n\n const showFooter = labels.length > 0\n\n const style: CSSProperties = {\n // undefined, take default value from class\n marginTop: isHeader ? '0px' : undefined,\n marginBottom: isHeader ? '0px' : undefined,\n paddingBottom:\n showFooter || useStylesForDisplayedImage ? undefined : '15px',\n }\n\n if (isHeader) {\n return (\n <HeaderCard\n ref={ref}\n headerCardVariant={headerCardVariant}\n descriptionConfig={descriptionConfig}\n charCountCutoff={charCountCutoff}\n title={title}\n subTitle={subtitle}\n description={description}\n type={type}\n icon={icon}\n values={labels}\n href={titleLinkConfiguration?.href}\n target={titleLinkConfiguration?.target}\n ctaLinkConfig={ctaLinkConfig}\n isAlignToLeftNav={true}\n secondaryLabelLimit={secondaryLabelLimit}\n cardTopButtons={cardTopButtons}\n cardTopContent={cardTopContent}\n sustainabilityScorecard={sustainabilityScorecard}\n renderedIconList={renderedIconList}\n cardTypeAdornment={cardTypeAdornment}\n titleAsFileHandleLinkConfiguration={titleAsFileHandleLinkConfiguration}\n titleAreaRightContent={titleAreaRightContent}\n descriptionSubTitle={descriptionSubTitle}\n />\n )\n }\n\n return (\n <div style={style} ref={ref} className={'SRC-portalCard'}>\n <div className={'SRC-portalCardMain'}>\n {icon}\n <div className=\"SRC-cardContent\">\n {cardTopButtons && (\n <Box\n sx={{\n position: 'absolute',\n right: '24px',\n display: 'flex',\n float: 'right',\n flexDirection: 'row',\n gap: '10px',\n }}\n >\n {cardTopButtons}\n </Box>\n )}\n <Stack\n sx={{\n flexDirection: 'row',\n alignItems: 'center',\n gap: '10px',\n }}\n >\n <div className=\"SRC-type\">{type}</div>\n {cardTypeAdornment}\n </Stack>\n {renderedIconList}\n <Box className=\"SRC-cardTitleArea\">\n <Box sx={{ flex: 1, minWidth: 0 }}>\n <div>\n <h3\n className=\"SRC-boldText SRC-blackText\"\n style={{ margin: 'none' }}\n >\n {!titleAsFileHandleLinkConfiguration && (\n <GenericCardTitle\n title={title}\n href={titleLinkConfiguration?.href}\n target={titleLinkConfiguration?.target}\n />\n )}\n {titleAsFileHandleLinkConfiguration && (\n <FileHandleLink\n fileHandleAssociation={\n titleAsFileHandleLinkConfiguration.fileHandleAssociation\n }\n showDownloadIcon={\n titleAsFileHandleLinkConfiguration.showDownloadIcon\n }\n displayValue={title}\n />\n )}\n </h3>\n </div>\n {subtitle && <div className=\"SRC-author\">{subtitle}</div>}\n <CollapsibleDescription\n description={description}\n descriptionSubTitle={descriptionSubTitle}\n descriptionConfig={descriptionConfig}\n />\n {ctaLinkConfig && (\n <Box\n sx={{ mt: '20px', display: 'flex', gap: 2, flexWrap: 'wrap' }}\n >\n {(Array.isArray(ctaLinkConfig)\n ? ctaLinkConfig\n : [ctaLinkConfig]\n ).map(\n (config, index) =>\n config.text &&\n config.href && (\n <SmartLink\n key={index}\n href={config.href}\n target={config.target}\n >\n {config.text}\n </SmartLink>\n ),\n )}\n </Box>\n )}\n </Box>\n {titleAreaRightContent && (\n <div className=\"SRC-cardTitleAreaDetails\">\n {titleAreaRightContent}\n </div>\n )}\n </Box>\n </div>\n </div>\n {showFooter && (\n <CardFooter\n isHeader={false}\n secondaryLabelLimit={secondaryLabelLimit}\n values={labels}\n className={useStylesForDisplayedImage ? undefined : 'hasIcon'}\n cardTopContent={cardTopContent}\n />\n )}\n </div>\n )\n})\n\nexport default GenericCard\n"],"mappings":";;;;;;;;;;;AA+FA,IAAM,IAAsC,EAAE,EAKjC,IAAc,EAAW,SACpC,GACA,GACA;CACA,IAAM,EACJ,SACA,SACA,UACA,2BACA,uCACA,aACA,gBACA,yBAAsB,IACtB,sBACA,mBACA,mBACA,cAAW,IACX,sBACA,gCAA6B,IAC7B,YAAS,GACT,wBACA,kBACA,qBACA,4BACA,sBACA,0BACA,uBACE,GAEE,IAAa,EAAO,SAAS;AAwCnC,QA9BI,IAEA,kBAAC,GAAD;EACO;EACc;EACA;EACF;EACV;EACP,UAAU;EACG;EACP;EACA;EACN,QAAQ;EACR,MAAM,GAAwB;EAC9B,QAAQ,GAAwB;EACjB;EACf,kBAAkB;EACG;EACL;EACA;EACS;EACP;EACC;EACiB;EACb;EACF;EACrB,CAAA,GAKJ,kBAAC,OAAD;EAAY;GArCZ,WAAW,IAAW,QAAQ,KAAA;GAC9B,cAAc,IAAW,QAAQ,KAAA;GACjC,eACE,KAAc,IAA6B,KAAA,IAAY;GAkC7C;EAAY;EAAK,WAAW;YAAxC,CACE,kBAAC,OAAD;GAAK,WAAW;aAAhB,CACG,GACD,kBAAC,OAAD;IAAK,WAAU;cAAf;KACG,KACC,kBAAC,GAAD;MACE,IAAI;OACF,UAAU;OACV,OAAO;OACP,SAAS;OACT,OAAO;OACP,eAAe;OACf,KAAK;OACN;gBAEA;MACG,CAAA;KAER,kBAAC,GAAD;MACE,IAAI;OACF,eAAe;OACf,YAAY;OACZ,KAAK;OACN;gBALH,CAOE,kBAAC,OAAD;OAAK,WAAU;iBAAY;OAAW,CAAA,EACrC,EACK;;KACP;KACD,kBAAC,GAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD;OAAK,IAAI;QAAE,MAAM;QAAG,UAAU;QAAG;iBAAjC;QACE,kBAAC,OAAD,EAAA,UACE,kBAAC,MAAD;SACE,WAAU;SACV,OAAO,EAAE,QAAQ,QAAQ;mBAF3B,CAIG,CAAC,KACA,kBAAC,GAAD;UACS;UACP,MAAM,GAAwB;UAC9B,QAAQ,GAAwB;UAChC,CAAA,EAEH,KACC,kBAAC,GAAD;UACE,uBACE,EAAmC;UAErC,kBACE,EAAmC;UAErC,cAAc;UACd,CAAA,CAED;YACD,CAAA;QACL,KAAY,kBAAC,OAAD;SAAK,WAAU;mBAAc;SAAe,CAAA;QACzD,kBAAC,GAAD;SACe;SACQ;SACF;SACnB,CAAA;QACD,KACC,kBAAC,GAAD;SACE,IAAI;UAAE,IAAI;UAAQ,SAAS;UAAQ,KAAK;UAAG,UAAU;UAAQ;oBAE3D,MAAM,QAAQ,EAAc,GAC1B,IACA,CAAC,EAAc,EACjB,KACC,GAAQ,MACP,EAAO,QACP,EAAO,QACL,kBAAC,GAAD;UAEE,MAAM,EAAO;UACb,QAAQ,EAAO;oBAEd,EAAO;UACE,EALL,EAKK,CAEjB;SACG,CAAA;QAEJ;UACL,KACC,kBAAC,OAAD;OAAK,WAAU;iBACZ;OACG,CAAA,CAEJ;;KACF;MACF;MACL,KACC,kBAAC,GAAD;GACE,UAAU;GACW;GACrB,QAAQ;GACR,WAAW,IAA6B,KAAA,IAAY;GACpC;GAChB,CAAA,CAEA;;EAER"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Linkify.js","names":[],"sources":["../../../src/components/GenericCard/Linkify.tsx"],"sourcesContent":["import { PRODUCTION_ENDPOINT_CONFIG } from '@/utils/functions/getEndpoint'\nimport { Link } from '@mui/material'\nimport { TargetEnum } from '@/utils/html/TargetEnum'\nimport { bioregistryRules } from './BioregistryRules'\n\nexport type LinkifyProps = {\n text?: string\n className?: string\n}\n\nexport type LinkifyRule = {\n regex: RegExp\n onMatch: (value: string) => string\n}\n\n// PORTALS-3600: No longer match synapse IDs that are not preceded by a space or the start of the string\n// (?:(?<=\\s)|^): non-capturing group that matches either:\n// (?<=\\s) — a positive lookbehind for a whitespace character (ensures there's a space before), or\n// ^ — the start of the string\nconst synapseIdRule: LinkifyRule = {\n regex: /((?:(?<=\\s)|^)syn\\d+)/,\n onMatch: value => `${PRODUCTION_ENDPOINT_CONFIG.PORTAL}Synapse:${value}`,\n}\n\nconst httpRule: LinkifyRule = {\n regex: /(http:\\/\\/[^ \",]+)/,\n onMatch: value => value,\n}\nconst httpsRule: LinkifyRule = {\n regex: /(https:\\/\\/[^ \",]+)/,\n onMatch: value => value,\n}\nconst ftpRule: LinkifyRule = {\n regex: /(ftp:\\/\\/[^ \",]+)/,\n onMatch: value => value,\n}\n\nconst pubMedRule: LinkifyRule = {\n regex: /(PMID:\\d+)/,\n onMatch: value => {\n const id = value.slice('PMID:'.length)\n return `https://pubmed.ncbi.nlm.nih.gov/${id}`\n },\n}\nconst mutationIdRule: LinkifyRule = {\n regex: /(MGI:\\d+)/,\n onMatch: value => `https://www.informatics.jax.org/allele/${value}`,\n}\nconst sciCrunchResolverRule: LinkifyRule = {\n regex:\n /(AB_\\d+)|(Addgene_\\d+)|(CVCL_[a-zA-Z0-9]+)|(MMRRC_\\d+-.{3})|(IMSR_JAX:\\d+)/,\n onMatch: value => `https://scicrunch.org/resolver/${value}`,\n}\nconst clinVarVCVRule: LinkifyRule = {\n regex: /(ClinVar:VCV\\d+)/,\n onMatch: value => {\n const id = value.slice('ClinVar:'.length)\n return `https://www.ncbi.nlm.nih.gov/clinvar/variation/${id}`\n },\n}\nconst clinVarRCVRule: LinkifyRule = {\n regex: /(ClinVar:RCV\\d+)/,\n onMatch: value => {\n const id = value.slice('ClinVar:'.length)\n return `https://www.ncbi.nlm.nih.gov/clinvar/${id}`\n },\n}\n\nconst arXivRule: LinkifyRule = {\n regex: /(arXiv:[a-zA-Z0-9.]+)/,\n onMatch: value => {\n const id = value.slice('arXiv:'.length)\n return `https://arxiv.org/abs/${id}`\n },\n}\n\nconst rridRule: LinkifyRule = {\n regex: /(rrid:[a-zA-Z]+.+)/,\n onMatch: value => {\n return `https://bioregistry.io/${value}`\n },\n}\n\nconst rules: LinkifyRule[] = [\n httpRule,\n httpsRule,\n ftpRule,\n synapseIdRule,\n rridRule,\n pubMedRule,\n sciCrunchResolverRule,\n mutationIdRule,\n clinVarVCVRule,\n clinVarRCVRule,\n arXivRule,\n ...bioregistryRules,\n]\nconst allRegexes = rules.map(r => r.regex.source).join('|')\nconst splitter = new RegExp(allRegexes, 'g')\n\nfunction Linkify({ text, className }: LinkifyProps) {\n if (text == null) {\n return <></>\n }\n // Split the string using the joined regular expressions so we can add links to identifiers within free text\n const parts = text.split(splitter)\n return (\n <>\n {parts.map((part, index) => {\n const match = rules.find(r => r.regex.test(part))\n if (match) {\n return (\n <Link\n href={match.onMatch(part)}\n key={index}\n target={TargetEnum.NEW_WINDOW}\n rel=\"noopener noreferrer\"\n className={className}\n >\n {part}\n </Link>\n )\n }\n // else\n return part\n })}\n </>\n )\n}\n\nexport default Linkify\n"],"mappings":";;;;;;AAmFA,IAAM,IAAuB;
|
|
1
|
+
{"version":3,"file":"Linkify.js","names":[],"sources":["../../../src/components/GenericCard/Linkify.tsx"],"sourcesContent":["import { PRODUCTION_ENDPOINT_CONFIG } from '@/utils/functions/getEndpoint'\nimport { Link } from '@mui/material'\nimport { TargetEnum } from '@/utils/html/TargetEnum'\nimport { bioregistryRules } from './BioregistryRules'\n\nexport type LinkifyProps = {\n text?: string\n className?: string\n}\n\nexport type LinkifyRule = {\n regex: RegExp\n onMatch: (value: string) => string\n}\n\n// PORTALS-3600: No longer match synapse IDs that are not preceded by a space or the start of the string\n// (?:(?<=\\s)|^): non-capturing group that matches either:\n// (?<=\\s) — a positive lookbehind for a whitespace character (ensures there's a space before), or\n// ^ — the start of the string\nconst synapseIdRule: LinkifyRule = {\n regex: /((?:(?<=\\s)|^)syn\\d+)/,\n onMatch: value => `${PRODUCTION_ENDPOINT_CONFIG.PORTAL}Synapse:${value}`,\n}\n\nconst httpRule: LinkifyRule = {\n regex: /(http:\\/\\/[^ \",]+)/,\n onMatch: value => value,\n}\nconst httpsRule: LinkifyRule = {\n regex: /(https:\\/\\/[^ \",]+)/,\n onMatch: value => value,\n}\nconst ftpRule: LinkifyRule = {\n regex: /(ftp:\\/\\/[^ \",]+)/,\n onMatch: value => value,\n}\n\nconst pubMedRule: LinkifyRule = {\n regex: /(PMID:\\d+)/,\n onMatch: value => {\n const id = value.slice('PMID:'.length)\n return `https://pubmed.ncbi.nlm.nih.gov/${id}`\n },\n}\nconst mutationIdRule: LinkifyRule = {\n regex: /(MGI:\\d+)/,\n onMatch: value => `https://www.informatics.jax.org/allele/${value}`,\n}\nconst sciCrunchResolverRule: LinkifyRule = {\n regex:\n /(AB_\\d+)|(Addgene_\\d+)|(CVCL_[a-zA-Z0-9]+)|(MMRRC_\\d+-.{3})|(IMSR_JAX:\\d+)/,\n onMatch: value => `https://scicrunch.org/resolver/${value}`,\n}\nconst clinVarVCVRule: LinkifyRule = {\n regex: /(ClinVar:VCV\\d+)/,\n onMatch: value => {\n const id = value.slice('ClinVar:'.length)\n return `https://www.ncbi.nlm.nih.gov/clinvar/variation/${id}`\n },\n}\nconst clinVarRCVRule: LinkifyRule = {\n regex: /(ClinVar:RCV\\d+)/,\n onMatch: value => {\n const id = value.slice('ClinVar:'.length)\n return `https://www.ncbi.nlm.nih.gov/clinvar/${id}`\n },\n}\n\nconst arXivRule: LinkifyRule = {\n regex: /(arXiv:[a-zA-Z0-9.]+)/,\n onMatch: value => {\n const id = value.slice('arXiv:'.length)\n return `https://arxiv.org/abs/${id}`\n },\n}\n\nconst rridRule: LinkifyRule = {\n regex: /(rrid:[a-zA-Z]+.+)/,\n onMatch: value => {\n return `https://bioregistry.io/${value}`\n },\n}\n\nconst rules: LinkifyRule[] = [\n httpRule,\n httpsRule,\n ftpRule,\n synapseIdRule,\n rridRule,\n pubMedRule,\n sciCrunchResolverRule,\n mutationIdRule,\n clinVarVCVRule,\n clinVarRCVRule,\n arXivRule,\n ...bioregistryRules,\n]\nconst allRegexes = rules.map(r => r.regex.source).join('|')\nconst splitter = new RegExp(allRegexes, 'g')\n\nfunction Linkify({ text, className }: LinkifyProps) {\n if (text == null) {\n return <></>\n }\n // Split the string using the joined regular expressions so we can add links to identifiers within free text\n const parts = text.split(splitter)\n return (\n <>\n {parts.map((part, index) => {\n const match = rules.find(r => r.regex.test(part))\n if (match) {\n return (\n <Link\n href={match.onMatch(part)}\n key={index}\n target={TargetEnum.NEW_WINDOW}\n rel=\"noopener noreferrer\"\n className={className}\n >\n {part}\n </Link>\n )\n }\n // else\n return part\n })}\n </>\n )\n}\n\nexport default Linkify\n"],"mappings":";;;;;;AAmFA,IAAM,IAAuB;CAC3B;EA3DA,OAAO;EACP,UAAS,MAAS;EA0DlB;CACA;EAxDA,OAAO;EACP,UAAS,MAAS;EAuDlB;CACA;EArDA,OAAO;EACP,UAAS,MAAS;EAoDlB;CACA;EAnEA,OAAO;EACP,UAAS,MAAS,GAAG,EAA2B,OAAO,UAAU;EAkEjE;CACA;EAXA,OAAO;EACP,UAAS,MACA,0BAA0B;EASnC;CACA;EAnDA,OAAO;EACP,UAAS,MAEA,mCADI,EAAM,MAAM,EACmB;EAgD5C;CACA;EAzCA,OACE;EACF,UAAS,MAAS,kCAAkC;EAuCpD;CACA;EA9CA,OAAO;EACP,UAAS,MAAS,0CAA0C;EA6C5D;CACA;EAtCA,OAAO;EACP,UAAS,MAEA,kDADI,EAAM,MAAM,EACkC;EAmC3D;CACA;EAhCA,OAAO;EACP,UAAS,MAEA,wCADI,EAAM,MAAM,EACwB;EA6BjD;CACA;EAzBA,OAAO;EACP,UAAS,MAEA,yBADI,EAAM,MAAM,EACS;EAsBlC;CACA,GAAG;CACJ,EACK,IAAa,EAAM,KAAI,MAAK,EAAE,MAAM,OAAO,CAAC,KAAK,IAAI,EACrD,IAAW,IAAI,OAAO,GAAY,IAAI;AAE5C,SAAS,EAAQ,EAAE,SAAM,gBAA2B;AAMlD,QALI,KAAQ,OACH,kBAAA,GAAA,EAAK,CAAA,GAKZ,kBAAA,GAAA,EAAA,UAFY,EAAK,MAAM,EAGpB,CAAM,KAAK,GAAM,MAAU;EAC1B,IAAM,IAAQ,EAAM,MAAK,MAAK,EAAE,MAAM,KAAK,EAAK,CAAC;AAejD,SAdI,IAEA,kBAAC,GAAD;GACE,MAAM,EAAM,QAAQ,EAAK;GAEzB,QAAQ,EAAW;GACnB,KAAI;GACO;aAEV;GACI,EANA,EAMA,GAIJ;GACP,EACD,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SynapseCardLabel.js","names":[],"sources":["../../../src/components/GenericCard/SynapseCardLabel.tsx"],"sourcesContent":["import { CardLink } from '@/components/CardContainer/CardLink'\nimport { getValueOrMultiValue } from '@/components/GenericCard/CardUtils'\nimport { formatDate } from '@/utils/functions/DateFormatter'\nimport { getColumnIndex } from '@/utils/functions/index'\nimport { TargetEnum } from '@/utils/html/TargetEnum'\nimport { Tooltip } from '@mui/material'\nimport {\n ColumnModel,\n ColumnTypeEnum,\n Row,\n SelectColumn,\n} from '@sage-bionetworks/synapse-types'\nimport dayjs from 'dayjs'\nimport { isEmpty } from 'lodash-es'\nimport { CSSProperties, Fragment, ReactNode } from 'react'\nimport {\n ColumnIconConfigs,\n ColumnSpecifiedLink,\n MarkdownLink,\n} from '../CardContainerLogic'\nimport {\n EntityImage,\n MapValueToReactComponentConfig,\n} from '../CardContainerLogic/CardContainerLogic'\nimport { EntityLink } from '../EntityLink'\nimport MarkdownSynapse from '../Markdown/MarkdownSynapse'\nimport { SmartLink } from '../SmartLink/SmartLink'\nimport { UserBadge } from '../UserCard/UserBadge'\nimport { EntityColumnImage } from '../widgets/EntityColumnImage'\nimport { LabelMaybeWithIcon } from './LabelMaybeWithIcon'\nimport Linkify from './Linkify'\n\ntype SynapseCardLabelProps = {\n value: string\n columnName: string\n labelLink:\n | CardLink\n | MarkdownLink\n | ColumnSpecifiedLink\n | EntityImage\n | MapValueToReactComponentConfig\n | undefined\n selectColumns: SelectColumn[] | undefined\n columnModels: ColumnModel[] | undefined\n isHeader: boolean\n className?: string\n rowData: Row['values']\n rowId?: string\n columnIconOptions?: ColumnIconConfigs\n}\nexport function SynapseCardLabel(props: SynapseCardLabelProps) {\n const {\n value,\n columnName,\n labelLink,\n selectColumns,\n columnModels,\n isHeader,\n className,\n rowData,\n rowId,\n columnIconOptions,\n } = props\n\n if (!value) {\n return <p>{value}</p>\n }\n const { strList, str, selectColumn } = getValueOrMultiValue({\n columnName,\n value,\n selectColumns,\n columnModels,\n })\n\n const columnModelType = selectColumn?.columnType\n const iconConfig = columnIconOptions?.columns?.[columnName]\n // \\u00a0 is a nbsp;\n const separator = ',\\u00a0\\u00a0'\n\n if (!str) {\n // the array came back empty\n return <p>{str}</p>\n }\n\n let newClassName = className\n const style: CSSProperties = {}\n if (isHeader) {\n newClassName = className?.concat(' ', 'SRC-lightLink')\n }\n // PORTALS-1913: special rendering for user ID lists\n if (columnModelType === ColumnTypeEnum.USERID_LIST && strList) {\n return (\n <p>\n {strList.map((val: string, index: number) => {\n return (\n <Fragment key={val}>\n <UserBadge userId={val} className={newClassName} />\n {index < strList.length - 1 && separator}\n </Fragment>\n )\n })}\n </p>\n )\n }\n if (columnModelType === ColumnTypeEnum.USERID && str) {\n return <UserBadge userId={str} className={newClassName} />\n }\n\n if (columnModelType === ColumnTypeEnum.ENTITYID_LIST && strList) {\n return (\n <p>\n {strList.map((entityId: string, index: number) => {\n return (\n <Fragment key={entityId}>\n <EntityLink entity={entityId} className={newClassName} />\n {index < strList.length - 1 && separator}\n </Fragment>\n )\n })}\n </p>\n )\n }\n\n if (columnModelType === ColumnTypeEnum.ENTITYID && str && !labelLink) {\n return <EntityLink entity={str} className={newClassName} />\n }\n\n // NFINT-906\n if (columnModelType === ColumnTypeEnum.DATE && str) {\n return <p>{formatDate(dayjs(Number(str)))}</p>\n }\n\n if (!labelLink) {\n if (strList) {\n return (\n <>\n {strList.map((el, index) => (\n <Fragment key={el}>\n <LabelMaybeWithIcon value={el} iconConfig={iconConfig}>\n <Linkify text={el} className={newClassName} />\n </LabelMaybeWithIcon>\n {index < strList.length - 1 && separator}\n </Fragment>\n ))}\n </>\n )\n }\n return (\n <LabelMaybeWithIcon value={str} iconConfig={iconConfig}>\n <Linkify text={str} className={newClassName} />\n </LabelMaybeWithIcon>\n )\n }\n\n if ('resolveEntityName' in labelLink && labelLink.resolveEntityName && str) {\n const { baseURL, URLColumnName } = labelLink\n const href = `/${baseURL}?${URLColumnName}=${str}`\n return <EntityLink entity={str} link={href} showIcon={false} />\n }\n\n let labelContent: ReactNode\n\n if (\n 'isMapValueToReactNodeConfig' in labelLink &&\n labelLink.isMapValueToReactNodeConfig\n ) {\n const { Component } = labelLink\n labelContent = (\n <Component value={strList || str} selectColumn={selectColumn!} />\n )\n } else if ('isMarkdown' in labelLink && labelLink.isMarkdown) {\n if (strList) {\n labelContent = (\n <p>\n {strList.map((el, index) => {\n return (\n <Fragment key={el}>\n <MarkdownSynapse key={el} renderInline={true} markdown={el} />\n {index < strList.length - 1 && separator}\n </Fragment>\n )\n })}\n </p>\n )\n } else {\n labelContent = <MarkdownSynapse renderInline={true} markdown={value} />\n }\n } else if ('isEntityImage' in labelLink && labelLink.isEntityImage) {\n if (strList) {\n labelContent = (\n <p>\n {strList.map((el, index) => {\n return (\n <Fragment key={el}>\n <EntityColumnImage entityId={el} />\n {index < strList.length - 1 && separator}\n </Fragment>\n )\n })}\n </p>\n )\n } else {\n labelContent = <EntityColumnImage entityId={value} />\n }\n } else {\n const split = strList ? strList : str.split(',')\n let linkTarget: TargetEnum | undefined = undefined\n if ('target' in labelLink) {\n linkTarget = labelLink.target!\n }\n if ('linkColumnName' in labelLink) {\n const linkIndex = getColumnIndex(\n labelLink.linkColumnName,\n selectColumns,\n columnModels,\n )\n if (linkIndex == null) {\n console.warn(\n `Could not determine column index of ${labelLink.linkColumnName}`,\n )\n labelContent = <>{value}</>\n } else {\n const href = rowData[linkIndex]\n\n if (isEmpty(href)) {\n labelContent = <>{value}</>\n } else {\n labelContent = (\n <p>\n {split.map((el, index) => {\n return (\n <Fragment key={el}>\n <SmartLink\n href={href ?? ''}\n target={linkTarget ?? TargetEnum.NEW_WINDOW}\n key={el}\n className={newClassName}\n style={style}\n >\n {el}\n </SmartLink>\n {index < split.length - 1 && (\n <span style={{ marginRight: 4 }}>, </span>\n )}\n </Fragment>\n )\n })}\n </p>\n )\n }\n }\n } else {\n labelContent = (\n <p>\n {split.map((el, index) => {\n const cardLink = labelLink as CardLink\n const elOrRowId = cardLink.overrideValueWithRowID ? rowId : el\n let href = ''\n if ('baseURL' in cardLink) {\n const {\n baseURL,\n URLColumnName,\n wrapValueWithParens,\n urlParamStyle = 'query-param',\n } = cardLink\n const value = wrapValueWithParens ? `(${elOrRowId})` : elOrRowId\n if (urlParamStyle === 'path-segment') {\n href = `/${baseURL}/${encodeURIComponent(String(value))}`\n } else {\n href = `/${baseURL}?${URLColumnName}=${value}`\n }\n } else if ('overrideLinkURLColumnName' in cardLink) {\n const overrideHrefIndex = getColumnIndex(\n cardLink.overrideLinkURLColumnName,\n selectColumns,\n columnModels,\n )\n if (overrideHrefIndex) {\n const overrideHrefData = rowData[overrideHrefIndex]\n if (overrideHrefData) {\n if (cardLink.overrideLinkURLColumnTransform) {\n href =\n cardLink.overrideLinkURLColumnTransform(overrideHrefData)\n } else {\n href = overrideHrefData\n }\n }\n }\n }\n\n return (\n <Fragment key={el}>\n <SmartLink\n href={href}\n key={el}\n className={newClassName}\n style={style}\n target={linkTarget ?? TargetEnum.CURRENT_WINDOW}\n >\n {el}\n </SmartLink>\n {index < split.length - 1 && (\n <span style={{ marginRight: 4 }}>, </span>\n )}\n </Fragment>\n )\n })}\n </p>\n )\n }\n }\n\n if ('tooltipText' in labelLink && labelLink.tooltipText) {\n // wrap in a tooltip\n return (\n <Tooltip title={labelLink.tooltipText} enterNextDelay={300}>\n <span>{labelContent}</span>\n </Tooltip>\n )\n } else {\n return labelContent\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SynapseCardLabel.js","names":[],"sources":["../../../src/components/GenericCard/SynapseCardLabel.tsx"],"sourcesContent":["import { CardLink } from '@/components/CardContainer/CardLink'\nimport { getValueOrMultiValue } from '@/components/GenericCard/CardUtils'\nimport { formatDate } from '@/utils/functions/DateFormatter'\nimport { getColumnIndex } from '@/utils/functions/index'\nimport { TargetEnum } from '@/utils/html/TargetEnum'\nimport { Tooltip } from '@mui/material'\nimport {\n ColumnModel,\n ColumnTypeEnum,\n Row,\n SelectColumn,\n} from '@sage-bionetworks/synapse-types'\nimport dayjs from 'dayjs'\nimport { isEmpty } from 'lodash-es'\nimport { CSSProperties, Fragment, ReactNode } from 'react'\nimport {\n ColumnIconConfigs,\n ColumnSpecifiedLink,\n MarkdownLink,\n} from '../CardContainerLogic'\nimport {\n EntityImage,\n MapValueToReactComponentConfig,\n} from '../CardContainerLogic/CardContainerLogic'\nimport { EntityLink } from '../EntityLink'\nimport MarkdownSynapse from '../Markdown/MarkdownSynapse'\nimport { SmartLink } from '../SmartLink/SmartLink'\nimport { UserBadge } from '../UserCard/UserBadge'\nimport { EntityColumnImage } from '../widgets/EntityColumnImage'\nimport { LabelMaybeWithIcon } from './LabelMaybeWithIcon'\nimport Linkify from './Linkify'\n\ntype SynapseCardLabelProps = {\n value: string\n columnName: string\n labelLink:\n | CardLink\n | MarkdownLink\n | ColumnSpecifiedLink\n | EntityImage\n | MapValueToReactComponentConfig\n | undefined\n selectColumns: SelectColumn[] | undefined\n columnModels: ColumnModel[] | undefined\n isHeader: boolean\n className?: string\n rowData: Row['values']\n rowId?: string\n columnIconOptions?: ColumnIconConfigs\n}\nexport function SynapseCardLabel(props: SynapseCardLabelProps) {\n const {\n value,\n columnName,\n labelLink,\n selectColumns,\n columnModels,\n isHeader,\n className,\n rowData,\n rowId,\n columnIconOptions,\n } = props\n\n if (!value) {\n return <p>{value}</p>\n }\n const { strList, str, selectColumn } = getValueOrMultiValue({\n columnName,\n value,\n selectColumns,\n columnModels,\n })\n\n const columnModelType = selectColumn?.columnType\n const iconConfig = columnIconOptions?.columns?.[columnName]\n // \\u00a0 is a nbsp;\n const separator = ',\\u00a0\\u00a0'\n\n if (!str) {\n // the array came back empty\n return <p>{str}</p>\n }\n\n let newClassName = className\n const style: CSSProperties = {}\n if (isHeader) {\n newClassName = className?.concat(' ', 'SRC-lightLink')\n }\n // PORTALS-1913: special rendering for user ID lists\n if (columnModelType === ColumnTypeEnum.USERID_LIST && strList) {\n return (\n <p>\n {strList.map((val: string, index: number) => {\n return (\n <Fragment key={val}>\n <UserBadge userId={val} className={newClassName} />\n {index < strList.length - 1 && separator}\n </Fragment>\n )\n })}\n </p>\n )\n }\n if (columnModelType === ColumnTypeEnum.USERID && str) {\n return <UserBadge userId={str} className={newClassName} />\n }\n\n if (columnModelType === ColumnTypeEnum.ENTITYID_LIST && strList) {\n return (\n <p>\n {strList.map((entityId: string, index: number) => {\n return (\n <Fragment key={entityId}>\n <EntityLink entity={entityId} className={newClassName} />\n {index < strList.length - 1 && separator}\n </Fragment>\n )\n })}\n </p>\n )\n }\n\n if (columnModelType === ColumnTypeEnum.ENTITYID && str && !labelLink) {\n return <EntityLink entity={str} className={newClassName} />\n }\n\n // NFINT-906\n if (columnModelType === ColumnTypeEnum.DATE && str) {\n return <p>{formatDate(dayjs(Number(str)))}</p>\n }\n\n if (!labelLink) {\n if (strList) {\n return (\n <>\n {strList.map((el, index) => (\n <Fragment key={el}>\n <LabelMaybeWithIcon value={el} iconConfig={iconConfig}>\n <Linkify text={el} className={newClassName} />\n </LabelMaybeWithIcon>\n {index < strList.length - 1 && separator}\n </Fragment>\n ))}\n </>\n )\n }\n return (\n <LabelMaybeWithIcon value={str} iconConfig={iconConfig}>\n <Linkify text={str} className={newClassName} />\n </LabelMaybeWithIcon>\n )\n }\n\n if ('resolveEntityName' in labelLink && labelLink.resolveEntityName && str) {\n const { baseURL, URLColumnName } = labelLink\n const href = `/${baseURL}?${URLColumnName}=${str}`\n return <EntityLink entity={str} link={href} showIcon={false} />\n }\n\n let labelContent: ReactNode\n\n if (\n 'isMapValueToReactNodeConfig' in labelLink &&\n labelLink.isMapValueToReactNodeConfig\n ) {\n const { Component } = labelLink\n labelContent = (\n <Component value={strList || str} selectColumn={selectColumn!} />\n )\n } else if ('isMarkdown' in labelLink && labelLink.isMarkdown) {\n if (strList) {\n labelContent = (\n <p>\n {strList.map((el, index) => {\n return (\n <Fragment key={el}>\n <MarkdownSynapse key={el} renderInline={true} markdown={el} />\n {index < strList.length - 1 && separator}\n </Fragment>\n )\n })}\n </p>\n )\n } else {\n labelContent = <MarkdownSynapse renderInline={true} markdown={value} />\n }\n } else if ('isEntityImage' in labelLink && labelLink.isEntityImage) {\n if (strList) {\n labelContent = (\n <p>\n {strList.map((el, index) => {\n return (\n <Fragment key={el}>\n <EntityColumnImage entityId={el} />\n {index < strList.length - 1 && separator}\n </Fragment>\n )\n })}\n </p>\n )\n } else {\n labelContent = <EntityColumnImage entityId={value} />\n }\n } else {\n const split = strList ? strList : str.split(',')\n let linkTarget: TargetEnum | undefined = undefined\n if ('target' in labelLink) {\n linkTarget = labelLink.target!\n }\n if ('linkColumnName' in labelLink) {\n const linkIndex = getColumnIndex(\n labelLink.linkColumnName,\n selectColumns,\n columnModels,\n )\n if (linkIndex == null) {\n console.warn(\n `Could not determine column index of ${labelLink.linkColumnName}`,\n )\n labelContent = <>{value}</>\n } else {\n const href = rowData[linkIndex]\n\n if (isEmpty(href)) {\n labelContent = <>{value}</>\n } else {\n labelContent = (\n <p>\n {split.map((el, index) => {\n return (\n <Fragment key={el}>\n <SmartLink\n href={href ?? ''}\n target={linkTarget ?? TargetEnum.NEW_WINDOW}\n key={el}\n className={newClassName}\n style={style}\n >\n {el}\n </SmartLink>\n {index < split.length - 1 && (\n <span style={{ marginRight: 4 }}>, </span>\n )}\n </Fragment>\n )\n })}\n </p>\n )\n }\n }\n } else {\n labelContent = (\n <p>\n {split.map((el, index) => {\n const cardLink = labelLink as CardLink\n const elOrRowId = cardLink.overrideValueWithRowID ? rowId : el\n let href = ''\n if ('baseURL' in cardLink) {\n const {\n baseURL,\n URLColumnName,\n wrapValueWithParens,\n urlParamStyle = 'query-param',\n } = cardLink\n const value = wrapValueWithParens ? `(${elOrRowId})` : elOrRowId\n if (urlParamStyle === 'path-segment') {\n href = `/${baseURL}/${encodeURIComponent(String(value))}`\n } else {\n href = `/${baseURL}?${URLColumnName}=${value}`\n }\n } else if ('overrideLinkURLColumnName' in cardLink) {\n const overrideHrefIndex = getColumnIndex(\n cardLink.overrideLinkURLColumnName,\n selectColumns,\n columnModels,\n )\n if (overrideHrefIndex) {\n const overrideHrefData = rowData[overrideHrefIndex]\n if (overrideHrefData) {\n if (cardLink.overrideLinkURLColumnTransform) {\n href =\n cardLink.overrideLinkURLColumnTransform(overrideHrefData)\n } else {\n href = overrideHrefData\n }\n }\n }\n }\n\n return (\n <Fragment key={el}>\n <SmartLink\n href={href}\n key={el}\n className={newClassName}\n style={style}\n target={linkTarget ?? TargetEnum.CURRENT_WINDOW}\n >\n {el}\n </SmartLink>\n {index < split.length - 1 && (\n <span style={{ marginRight: 4 }}>, </span>\n )}\n </Fragment>\n )\n })}\n </p>\n )\n }\n }\n\n if ('tooltipText' in labelLink && labelLink.tooltipText) {\n // wrap in a tooltip\n return (\n <Tooltip title={labelLink.tooltipText} enterNextDelay={300}>\n <span>{labelContent}</span>\n </Tooltip>\n )\n } else {\n return labelContent\n }\n}\n"],"mappings":"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"}
|