synapse-react-client 4.0.17 → 4.0.19
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/README.md +5 -3
- package/dist/SWC.index.d.ts +2 -0
- package/dist/SWC.index.d.ts.map +1 -1
- package/dist/SWC.index.js +3 -1
- package/dist/SWC.index.js.map +1 -1
- package/dist/assets/homepage/BlinkingLiveIcon.d.ts +1 -1
- package/dist/components/AccessRequirementAclEditor/AccessRequirementAclEditor.d.ts.map +1 -1
- package/dist/components/AccessRequirementAclEditor/AccessRequirementAclEditor.js.map +1 -1
- package/dist/components/AccessRequirementList/AccessRequirementList.js.map +1 -1
- package/dist/components/AccessRequirementList/RequirementItem/CertificationRequirement.js.map +1 -1
- package/dist/components/AccessRequirementList/RequirementItem/SelfSignAccessRequirementItem.js.map +1 -1
- package/dist/components/AccessRequirementList/RequirementItem/UnmanagedACTAccessRequirementItem.js.map +1 -1
- package/dist/components/AccessRequirementList/RequirementItem/ValidationRequirement.js.map +1 -1
- package/dist/components/AccessTokenPage/CreateAccessTokenModal.d.ts.map +1 -1
- package/dist/components/AccessTokenPage/CreateAccessTokenModal.js +56 -54
- package/dist/components/AccessTokenPage/CreateAccessTokenModal.js.map +1 -1
- package/dist/components/Authentication/PasswordField.d.ts +1 -1
- package/dist/components/Authentication/PasswordField.d.ts.map +1 -1
- package/dist/components/Authentication/PasswordField.js.map +1 -1
- package/dist/components/Authentication/TwoFactorEnrollmentForm.d.ts.map +1 -1
- package/dist/components/Authentication/TwoFactorEnrollmentForm.js +1 -2
- package/dist/components/Authentication/TwoFactorEnrollmentForm.js.map +1 -1
- package/dist/components/Authentication/UsernamePasswordForm.d.ts.map +1 -1
- package/dist/components/Authentication/UsernamePasswordForm.js +32 -29
- package/dist/components/Authentication/UsernamePasswordForm.js.map +1 -1
- package/dist/components/CardContainer/CardLink.d.ts +2 -2
- package/dist/components/CardContainer/CardLink.d.ts.map +1 -1
- package/dist/components/CardDeck/CardDeckCardProps.d.ts.map +1 -1
- package/dist/components/ChallengeSubmission/SubmissionDirectoryList.js.map +1 -1
- package/dist/components/ChallengeTeamWizard/CreateChallengeTeam.d.ts.map +1 -1
- package/dist/components/ChallengeTeamWizard/CreateChallengeTeam.js +106 -103
- package/dist/components/ChallengeTeamWizard/CreateChallengeTeam.js.map +1 -1
- package/dist/components/ChallengeTeamWizard/MembershipRequestForm.d.ts.map +1 -1
- package/dist/components/ChallengeTeamWizard/MembershipRequestForm.js.map +1 -1
- package/dist/components/ChallengeTeamWizard/useCreateAndRegisterChallengeTeam.d.ts.map +1 -1
- package/dist/components/ChallengeTeamWizard/useCreateAndRegisterChallengeTeam.js.map +1 -1
- package/dist/components/CreateProjectModal/CreateProjectModal.d.ts.map +1 -1
- package/dist/components/CreateProjectModal/CreateProjectModal.js +4 -4
- package/dist/components/CreateProjectModal/CreateProjectModal.js.map +1 -1
- package/dist/components/CreateTableViewWizard/TableNameForm.js +6 -6
- package/dist/components/CreateTableViewWizard/TableNameForm.js.map +1 -1
- package/dist/components/CrispChat/CrispChat.js +4 -4
- package/dist/components/CrispChat/CrispChat.js.map +1 -1
- package/dist/components/DataExplorer/DataExplorer.css +1 -0
- package/dist/components/DataExplorer/DataExplorer.d.ts +13 -0
- package/dist/components/DataExplorer/DataExplorer.d.ts.map +1 -0
- package/dist/components/DataExplorer/DataExplorer.js +119 -0
- package/dist/components/DataExplorer/DataExplorer.js.map +1 -0
- package/dist/components/DataExplorer/DataExplorer.module.js +22 -0
- package/dist/components/DataExplorer/DataExplorer.module.js.map +1 -0
- package/dist/components/DataExplorer/DataExplorer.module.scss +156 -0
- package/dist/components/DataGrid/columns/AutocompleteColumn.d.ts.map +1 -1
- package/dist/components/DataGrid/columns/AutocompleteColumn.js +106 -102
- package/dist/components/DataGrid/columns/AutocompleteColumn.js.map +1 -1
- package/dist/components/DataGrid/columns/AutocompleteMultipleEnumColumn.d.ts.map +1 -1
- package/dist/components/DataGrid/columns/AutocompleteMultipleEnumColumn.js +97 -89
- package/dist/components/DataGrid/columns/AutocompleteMultipleEnumColumn.js.map +1 -1
- package/dist/components/DataGrid/columns/useGridAutocompleteState.d.ts +19 -8
- package/dist/components/DataGrid/columns/useGridAutocompleteState.d.ts.map +1 -1
- package/dist/components/DataGrid/columns/useGridAutocompleteState.js +64 -43
- package/dist/components/DataGrid/columns/useGridAutocompleteState.js.map +1 -1
- package/dist/components/DataGrid/components/UploadCsvToGridDialog.d.ts.map +1 -1
- package/dist/components/DataGrid/components/UploadCsvToGridDialog.js +9 -9
- package/dist/components/DataGrid/components/UploadCsvToGridDialog.js.map +1 -1
- package/dist/components/DataGrid/hooks/useGetSchemaForGrid.d.ts.map +1 -1
- package/dist/components/DataGrid/hooks/useGetSchemaForGrid.js +8 -1
- package/dist/components/DataGrid/hooks/useGetSchemaForGrid.js.map +1 -1
- package/dist/components/DataGrid/utils/json-rx/JsonRxResponseComplete.js.map +1 -1
- package/dist/components/DownloadCart/RequestDownloadCard.js +14 -14
- package/dist/components/DownloadCart/RequestDownloadCard.js.map +1 -1
- package/dist/components/EntityAclEditor/EntityAclEditor.d.ts.map +1 -1
- package/dist/components/EntityAclEditor/EntityAclEditor.js.map +1 -1
- package/dist/components/EntityBadgeIcons/EntityBadgeIcons.d.ts.map +1 -1
- package/dist/components/EntityBadgeIcons/EntityBadgeIcons.js.map +1 -1
- package/dist/components/EntityCitation/EntityCitationUtils.js.map +1 -1
- package/dist/components/EntityDownloadConfirmation/EntityDownloadConfirmation.js.map +1 -1
- package/dist/components/EntityFinder/EntityFinder.js.map +1 -1
- package/dist/components/EntityFinder/EntityIdTextField.d.ts +17 -0
- package/dist/components/EntityFinder/EntityIdTextField.d.ts.map +1 -0
- package/dist/components/EntityFinder/EntityIdTextField.js +35 -0
- package/dist/components/EntityFinder/EntityIdTextField.js.map +1 -0
- package/dist/components/Evaluation/round_limits/EvaluationRoundLimitOptions.d.ts.map +1 -1
- package/dist/components/Evaluation/round_limits/EvaluationRoundLimitOptions.js +22 -16
- package/dist/components/Evaluation/round_limits/EvaluationRoundLimitOptions.js.map +1 -1
- package/dist/components/FeaturedDataTabs/FacetPlotsCardGrid.js.map +1 -1
- package/dist/components/Forum/ForumThreadEditor.js.map +1 -1
- package/dist/components/FullWidthAlert/FullWidthAlert.d.ts.map +1 -1
- package/dist/components/FullWidthAlert/FullWidthAlert.js.map +1 -1
- package/dist/components/GenericCard/PortalDOI/PortalDOIUtils.d.ts.map +1 -1
- package/dist/components/GenericCard/PortalDOI/PortalDOIUtils.js.map +1 -1
- package/dist/components/Markdown/widget/MarkdownSynapsePlot.js.map +1 -1
- package/dist/components/OAuthClientAclEditor/OAuthClientAclEditor.d.ts.map +1 -1
- package/dist/components/OAuthClientAclEditor/OAuthClientAclEditor.js.map +1 -1
- package/dist/components/PortalAclEditor/PortalAclEditor.d.ts.map +1 -1
- package/dist/components/PortalAclEditor/PortalAclEditor.js.map +1 -1
- package/dist/components/PortalHomePageHeader/PortalHomePageHeader.d.ts +1 -1
- package/dist/components/PortalHomePageHeader/PortalHomePageHeader.d.ts.map +1 -1
- package/dist/components/PortalHomePageHeader/PortalHomePageHeader.js +1 -1
- package/dist/components/PortalHomePageHeader/PortalHomePageHeader.js.map +1 -1
- package/dist/components/PortalList/CreatePortalModal.d.ts.map +1 -1
- package/dist/components/PortalList/CreatePortalModal.js +34 -33
- package/dist/components/PortalList/CreatePortalModal.js.map +1 -1
- package/dist/components/QueryVisualizationWrapper/QueryVisualizationWrapper.d.ts.map +1 -1
- package/dist/components/QueryVisualizationWrapper/QueryVisualizationWrapper.js +67 -65
- package/dist/components/QueryVisualizationWrapper/QueryVisualizationWrapper.js.map +1 -1
- package/dist/components/QueryWrapperPlotNav/QueryWrapperPlotNav.d.ts +1 -1
- package/dist/components/QueryWrapperPlotNav/QueryWrapperPlotNav.d.ts.map +1 -1
- package/dist/components/QueryWrapperPlotNav/QueryWrapperPlotNav.js +1 -0
- package/dist/components/QueryWrapperPlotNav/QueryWrapperPlotNav.js.map +1 -1
- package/dist/components/QueryWrapperPlotNav/RowSetView.d.ts.map +1 -1
- package/dist/components/QueryWrapperPlotNav/RowSetView.js.map +1 -1
- package/dist/components/Resources/Resources.Desktop.js.map +1 -1
- package/dist/components/SearchQueryWrapper/SearchQueryUseQueryOptions.js.map +1 -1
- package/dist/components/SearchQueryWrapperPlotNav/SearchQueryWrapperPlotNav.d.ts +1 -1
- package/dist/components/SearchQueryWrapperPlotNav/SearchQueryWrapperPlotNav.d.ts.map +1 -1
- package/dist/components/SearchQueryWrapperPlotNav/SearchQueryWrapperPlotNav.js +1 -0
- package/dist/components/SearchQueryWrapperPlotNav/SearchQueryWrapperPlotNav.js.map +1 -1
- package/dist/components/SetAccessRequirementCommonFields/SetAccessRequirementCommonFields.d.ts.map +1 -1
- package/dist/components/SetAccessRequirementCommonFields/SetAccessRequirementCommonFields.js.map +1 -1
- package/dist/components/SetBasicAccessRequirementFields/SetBasicAccessRequirementFields.d.ts.map +1 -1
- package/dist/components/SetBasicAccessRequirementFields/SetBasicAccessRequirementFields.js.map +1 -1
- package/dist/components/SetManagedAccessRequirementFields/SetManagedAccessRequirementFields.d.ts.map +1 -1
- package/dist/components/SetManagedAccessRequirementFields/SetManagedAccessRequirementFields.js.map +1 -1
- package/dist/components/StandaloneQueryWrapper/StandaloneQueryWrapper.d.ts +1 -1
- package/dist/components/StandaloneQueryWrapper/StandaloneQueryWrapper.d.ts.map +1 -1
- package/dist/components/StandaloneQueryWrapper/StandaloneQueryWrapper.js.map +1 -1
- package/dist/components/SynapseChat/SynapseChatInteraction.js.map +1 -1
- package/dist/components/SynapsePortalBanners/SynapsePortalBanners.d.ts.map +1 -1
- package/dist/components/SynapsePortalBanners/SynapsePortalBanners.js +1 -1
- package/dist/components/SynapsePortalBanners/SynapsePortalBanners.js.map +1 -1
- package/dist/components/SynapseTable/SearchV2.js.map +1 -1
- package/dist/components/SynapseTable/SynapseTable.js.map +1 -1
- package/dist/components/SynapseTable/SynapseTableUtils.d.ts.map +1 -1
- package/dist/components/SynapseTable/SynapseTableUtils.js.map +1 -1
- package/dist/components/SynapseTable/datasets/DatasetItemsEditor.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/ColumnModelForm.js +9 -9
- package/dist/components/TableColumnSchemaEditor/ColumnModelForm.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/ColumnModelFormFields/MultiValueField.js +4 -4
- package/dist/components/TableColumnSchemaEditor/TableColumnSchemaForm.d.ts.map +1 -1
- package/dist/components/TableColumnSchemaEditor/TableColumnSchemaForm.js +25 -25
- package/dist/components/TableColumnSchemaEditor/TableColumnSchemaForm.js.map +1 -1
- package/dist/components/TanStackTable/TanStackTableUtils.js.map +1 -1
- package/dist/components/TextField/TextField.css +1 -1
- package/dist/components/TextField/TextField.d.ts +14 -3
- package/dist/components/TextField/TextField.d.ts.map +1 -1
- package/dist/components/TextField/TextField.js +41 -43
- package/dist/components/TextField/TextField.js.map +1 -1
- package/dist/components/TextField/TextField.module.js +3 -4
- package/dist/components/TextField/TextField.module.js.map +1 -1
- package/dist/components/TextField/TextField.module.scss +18 -10
- package/dist/components/TimelinePlot/TimelinePlotSpeciesSelector.d.ts.map +1 -1
- package/dist/components/TimelinePlot/TimelinePlotSpeciesSelector.js +20 -16
- package/dist/components/TimelinePlot/TimelinePlotSpeciesSelector.js.map +1 -1
- package/dist/components/UserCardList/UserCardList.d.ts.map +1 -1
- package/dist/components/UserCardList/UserCardList.js.map +1 -1
- package/dist/components/UserCardList/UserCardListGroups/UserCardListGroups.Desktop.js.map +1 -1
- package/dist/components/UserOrTeamBadge/useUserOrTeam.js.map +1 -1
- package/dist/components/UserSearchBox/UserSearchBox.d.ts.map +1 -1
- package/dist/components/UserSearchBox/UserSearchBox.js.map +1 -1
- package/dist/components/WikiMarkdownEditorButton/WikiMarkdownEditorButton.js.map +1 -1
- package/dist/components/dataaccess/SubmissionPage/SubmissionPage.js.map +1 -1
- package/dist/components/doi/CreateOrUpdateDoiModal.js +13 -13
- package/dist/components/doi/CreateOrUpdateDoiModal.js.map +1 -1
- package/dist/components/entity/page/title_bar/TitleBarProperties.js +23 -23
- package/dist/components/entity/page/title_bar/TitleBarProperties.js.map +1 -1
- package/dist/components/entity/page/title_bar/useGetMentions.js.map +1 -1
- package/dist/components/index.js +17 -17
- package/dist/components/styled/StyledFormControl.d.ts +15 -0
- package/dist/components/styled/StyledFormControl.d.ts.map +1 -1
- package/dist/components/styled/StyledFormControl.js +1 -0
- package/dist/components/styled/StyledFormControl.js.map +1 -1
- package/dist/components/styled/index.js +3 -3
- package/dist/components/table/CsvPreview/CreateTableFromCsvDialog.d.ts +18 -0
- package/dist/components/table/CsvPreview/CreateTableFromCsvDialog.d.ts.map +1 -0
- package/dist/components/table/CsvPreview/CreateTableFromCsvDialog.js +116 -0
- package/dist/components/table/CsvPreview/CreateTableFromCsvDialog.js.map +1 -0
- package/dist/components/table/CsvPreview/CsvPreviewDialog.d.ts +5 -5
- package/dist/components/table/CsvPreview/CsvPreviewDialog.d.ts.map +1 -1
- package/dist/components/table/CsvPreview/CsvPreviewDialog.js +27 -76
- package/dist/components/table/CsvPreview/CsvPreviewDialog.js.map +1 -1
- package/dist/components/table/CsvPreview/CsvPreviewWithOptions.d.ts +19 -0
- package/dist/components/table/CsvPreview/CsvPreviewWithOptions.d.ts.map +1 -0
- package/dist/components/table/CsvPreview/CsvPreviewWithOptions.js +41 -0
- package/dist/components/table/CsvPreview/CsvPreviewWithOptions.js.map +1 -0
- package/dist/components/table/CsvPreview/CsvUploadPreviewContent.d.ts +12 -0
- package/dist/components/table/CsvPreview/CsvUploadPreviewContent.d.ts.map +1 -0
- package/dist/components/table/CsvPreview/CsvUploadPreviewContent.js +25 -0
- package/dist/components/table/CsvPreview/CsvUploadPreviewContent.js.map +1 -0
- package/dist/components/table/CsvPreview/UpdateTableWithCsvDialog.d.ts +18 -0
- package/dist/components/table/CsvPreview/UpdateTableWithCsvDialog.d.ts.map +1 -0
- package/dist/components/table/CsvPreview/UpdateTableWithCsvDialog.js +55 -0
- package/dist/components/table/CsvPreview/UpdateTableWithCsvDialog.js.map +1 -0
- package/dist/components/table/CsvPreview/useCreateTableFromCsv.d.ts +19 -0
- package/dist/components/table/CsvPreview/useCreateTableFromCsv.d.ts.map +1 -0
- package/dist/components/table/CsvPreview/useCreateTableFromCsv.js +35 -0
- package/dist/components/table/CsvPreview/useCreateTableFromCsv.js.map +1 -0
- package/dist/components/table/CsvPreview/useCsvUploadPreview.d.ts +22 -0
- package/dist/components/table/CsvPreview/useCsvUploadPreview.d.ts.map +1 -0
- package/dist/components/table/CsvPreview/useCsvUploadPreview.js +32 -0
- package/dist/components/table/CsvPreview/useCsvUploadPreview.js.map +1 -0
- package/dist/components/table/CsvPreview/useUploadCsvToExistingTable.d.ts +14 -0
- package/dist/components/table/CsvPreview/useUploadCsvToExistingTable.d.ts.map +1 -0
- package/dist/components/table/CsvPreview/useUploadCsvToExistingTable.js +23 -0
- package/dist/components/table/CsvPreview/useUploadCsvToExistingTable.js.map +1 -0
- package/dist/components/utils/ConditionalWrapper.d.ts.map +1 -1
- package/dist/components/utils/ConditionalWrapper.js.map +1 -1
- package/dist/components/widgets/ElementWithTooltip.js.map +1 -1
- package/dist/components/widgets/facet-nav/FacetNavPanel.d.ts.map +1 -1
- package/dist/components/widgets/facet-nav/FacetNavPanel.js +69 -62
- package/dist/components/widgets/facet-nav/FacetNavPanel.js.map +1 -1
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilter.d.ts +1 -0
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilter.d.ts.map +1 -1
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilter.js +27 -26
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilter.js.map +1 -1
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterDropdown.d.ts +1 -0
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterDropdown.d.ts.map +1 -1
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterDropdown.js +2 -1
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterDropdown.js.map +1 -1
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterUI.d.ts +1 -0
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterUI.d.ts.map +1 -1
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterUI.js +44 -43
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilterUI.js.map +1 -1
- package/dist/features/entity/metadata-task/components/CreateOrUpdateCurationTaskDialog.d.ts +13 -0
- package/dist/features/entity/metadata-task/components/CreateOrUpdateCurationTaskDialog.d.ts.map +1 -0
- package/dist/features/entity/metadata-task/components/CreateOrUpdateCurationTaskDialog.js +398 -0
- package/dist/features/entity/metadata-task/components/CreateOrUpdateCurationTaskDialog.js.map +1 -0
- package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.d.ts.map +1 -1
- package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.js +49 -19
- package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.js.map +1 -1
- package/dist/features/entity/metadata-task/components/MetadataTasksPage.d.ts.map +1 -1
- package/dist/features/entity/metadata-task/components/MetadataTasksPage.js +49 -25
- package/dist/features/entity/metadata-task/components/MetadataTasksPage.js.map +1 -1
- package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask.d.ts +0 -1
- package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask.d.ts.map +1 -1
- package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask.js +20 -22
- package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask.js.map +1 -1
- package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.d.ts.map +1 -1
- package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.js +25 -27
- package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.js.map +1 -1
- package/dist/features/entity/metadata-task/utils/constants.d.ts +29 -0
- package/dist/features/entity/metadata-task/utils/constants.d.ts.map +1 -1
- package/dist/features/entity/metadata-task/utils/constants.js +2 -2
- package/dist/features/entity/metadata-task/utils/constants.js.map +1 -1
- package/dist/index.js +17 -17
- package/dist/mockServiceWorker.js +6 -8
- package/dist/mocks/curation/mockCurationTask.d.ts +2 -2
- package/dist/mocks/curation/mockCurationTask.d.ts.map +1 -1
- package/dist/mocks/curation/mockCurationTask.js +9 -5
- package/dist/mocks/curation/mockCurationTask.js.map +1 -1
- package/dist/mocks/msw/handlers/featureFlagHandlers.d.ts +1 -1
- package/dist/mocks/msw/handlers/featureFlagHandlers.d.ts.map +1 -1
- package/dist/mocks/msw/handlers/featureFlagHandlers.js +1 -1
- package/dist/mocks/msw/handlers/featureFlagHandlers.js.map +1 -1
- package/dist/style/components/_cards.scss +0 -3
- package/dist/style/components/_data-grid-extra.scss +2 -2
- package/dist/style/components/_login.scss +6 -2
- package/dist/style/main.css +1 -1
- package/dist/synapse-client/SynapseClient.d.ts +2 -1
- package/dist/synapse-client/SynapseClient.d.ts.map +1 -1
- package/dist/synapse-client/SynapseClient.js.map +1 -1
- package/dist/synapse-queries/QueryFilterUtils.js.map +1 -1
- package/dist/synapse-queries/curation/task/useCurationTask.d.ts +1 -0
- package/dist/synapse-queries/curation/task/useCurationTask.d.ts.map +1 -1
- package/dist/synapse-queries/curation/task/useCurationTask.js +16 -6
- package/dist/synapse-queries/curation/task/useCurationTask.js.map +1 -1
- package/dist/synapse-queries/dataaccess/useAccessRequirements.d.ts.map +1 -1
- package/dist/synapse-queries/dataaccess/useAccessRequirements.js.map +1 -1
- package/dist/synapse-queries/entity/useGetQueryResultBundle.js.map +1 -1
- package/dist/synapse-queries/featureflags/useGetFeatureFlag.d.ts +1 -1
- package/dist/synapse-queries/featureflags/useGetFeatureFlag.d.ts.map +1 -1
- package/dist/synapse-queries/featureflags/useGetFeatureFlag.js.map +1 -1
- package/dist/synapse-queries/file/useFiles.d.ts.map +1 -1
- package/dist/synapse-queries/file/useFiles.js.map +1 -1
- package/dist/synapse-queries/termsOfService/useTermsOfService.d.ts.map +1 -1
- package/dist/synapse-queries/termsOfService/useTermsOfService.js.map +1 -1
- package/dist/synapse-queries/user/useGetUserChallenges.d.ts.map +1 -1
- package/dist/synapse-queries/user/useGetUserChallenges.js.map +1 -1
- package/dist/testutils/ReactQueryMockUtils.js.map +1 -1
- package/dist/theme/palette/Palettes.d.ts +2 -2
- package/dist/theme/palette/Palettes.d.ts.map +1 -1
- package/dist/theme/palette/Palettes.js +2 -2
- package/dist/theme/palette/Palettes.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types/ThemeTypes.d.ts +5 -6
- package/dist/utils/AppUtils/session/SynapseSessionManager.d.ts.map +1 -1
- package/dist/utils/AppUtils/session/SynapseSessionManager.js.map +1 -1
- package/dist/utils/featureflag/FeatureFlags.d.ts +13 -0
- package/dist/utils/featureflag/FeatureFlags.d.ts.map +1 -0
- package/dist/utils/featureflag/FeatureFlags.js +8 -0
- package/dist/utils/featureflag/FeatureFlags.js.map +1 -0
- package/dist/utils/functions/SanitizeHtmlUtils.js.map +1 -1
- package/dist/utils/functions/queryUtils.js.map +1 -1
- package/dist/utils/hooks/useGetInfoFromIds.d.ts.map +1 -1
- package/dist/utils/hooks/useGetInfoFromIds.js.map +1 -1
- package/dist/utils/slots/SlotUtils.d.ts.map +1 -1
- package/dist/utils/slots/SlotUtils.js.map +1 -1
- package/package.json +5 -6
|
@@ -23,7 +23,7 @@ function u({ entityId: u, dataCatalogEntityId: d = "syn61609402", sourceAppConfi
|
|
|
23
23
|
},
|
|
24
24
|
partMask: 1,
|
|
25
25
|
concreteType: "org.sagebionetworks.repo.model.table.QueryBundleRequest"
|
|
26
|
-
}, { enabled: !!p }), _ = g?.responseBody?.queryResult?.queryResults, v = !!_ && _?.rows.length > 0, y = _?.rows.map((e) => e.values[0]), b = y && y.length > 0, x = e(f, b ? [{
|
|
26
|
+
}, { enabled: !!p }), _ = g?.responseBody?.queryResult?.queryResults, v = !!_ && _?.rows.length > 0, y = _?.rows.map((e) => e.values[0]).filter((e) => !!e), b = y && y.length > 0, x = e(f, b ? [{
|
|
27
27
|
concreteType: "org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter",
|
|
28
28
|
columnName: "appId",
|
|
29
29
|
operator: c.EQUAL,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SynapsePortalBanners.js","names":[],"sources":["../../../src/components/SynapsePortalBanners/SynapsePortalBanners.tsx"],"sourcesContent":["import {\n useGetEntityPath,\n useGetQueryResultBundleWithAsyncStatus,\n} from '@/synapse-queries'\nimport { useSourceAppConfigs } from '@/utils/hooks'\nimport { BUNDLE_MASK_QUERY_RESULTS } from '@/utils/SynapseConstants'\nimport { ChevronRightTwoTone } from '@mui/icons-material'\nimport { Box, Typography } from '@mui/material'\nimport {\n ColumnSingleValueQueryFilter,\n ColumnSingleValueFilterOperator,\n} from '@sage-bionetworks/synapse-types'\n\nexport type SynapsePortalBannersProps = {\n entityId: string\n dataCatalogEntityId?: string\n sourceAppConfigTableID?: string\n}\n\n/**\n *\n * @param props\n */\nexport default function SynapsePortalBanners({\n entityId,\n dataCatalogEntityId = 'syn61609402',\n sourceAppConfigTableID = 'syn45291362',\n}: SynapsePortalBannersProps) {\n const { data: entityPathData } = useGetEntityPath(entityId)\n // get all EntityHeader ids in the entity path data in a string array\n // Note: we remove the first item from entityPathData.path as it is always the root Synapse folder which we don't want to include\n const entityIdValues: string[] = entityPathData\n ? entityPathData.path.map(header => header.id).slice(1)\n : [entityId]\n\n const dataCatalogAdditionalFilters: ColumnSingleValueQueryFilter[] =\n entityIdValues\n ? [\n {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n columnName: 'id',\n operator: ColumnSingleValueFilterOperator.IN,\n values: entityIdValues,\n },\n ]\n : []\n const { data: dataCatalogData } = useGetQueryResultBundleWithAsyncStatus(\n {\n entityId: dataCatalogEntityId,\n query: {\n sql: `SELECT appId, link FROM ${dataCatalogEntityId}`,\n additionalFilters: dataCatalogAdditionalFilters,\n },\n partMask: BUNDLE_MASK_QUERY_RESULTS,\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n },\n {\n enabled: !!entityPathData,\n },\n )\n\n const rowSet = dataCatalogData?.responseBody?.queryResult?.queryResults\n const hasPortalBanners = !!rowSet && rowSet?.rows.length > 0\n\n const appIds = rowSet?.rows.map(row => row.values[0]) as string[]\n const hasAppIds = appIds && appIds.length > 0\n\n const sourceAppConfigFilters: ColumnSingleValueQueryFilter[] = hasAppIds\n ? [\n {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n columnName: 'appId',\n operator: ColumnSingleValueFilterOperator.EQUAL,\n values: appIds,\n },\n ]\n : []\n const sourceAppConfigs = useSourceAppConfigs(\n sourceAppConfigTableID,\n sourceAppConfigFilters,\n )\n const hasSourceAppConfigs = !!sourceAppConfigs && sourceAppConfigs.length > 0\n\n if (!hasAppIds || !hasPortalBanners || !hasSourceAppConfigs) {\n return <></>\n }\n\n // we have source app configs associated to this entity, let's render the banners\n return (\n <Box\n sx={{\n display: 'flex',\n flexWrap: 'wrap',\n gap: '20px',\n width: '100%',\n alignItems: 'center',\n }}\n >\n {sourceAppConfigs.map((appConfig, index) => {\n const dataCatalogRow = rowSet.rows.find(row => {\n return row.values[0] === appConfig.appId\n })\n const link = dataCatalogRow?.values[1] || appConfig.appURL\n return (\n <Box\n key={index}\n component=\"a\"\n href={link}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n flex={1}\n sx={{\n display: 'flex',\n flexWrap: 'nowrap',\n padding: '16px',\n justifyContent: 'space-between',\n border: '1px solid #ccc',\n borderRadius: '8px',\n backgroundColor: '#f9f9f9',\n textDecoration: 'none',\n pointer: 'cursor',\n '&:hover': {\n textDecoration: 'none !important',\n },\n width: '100%',\n alignItems: 'center',\n mt: '10px',\n mb: '10px',\n }}\n >\n <Box\n flex={1}\n sx={{\n display: 'flex',\n flexWrap: 'wrap',\n justifyContent: 'space-between',\n gap: '10px',\n }}\n >\n <Box\n sx={{\n '> *': {\n height: '60px',\n },\n }}\n >\n {appConfig?.logo}\n </Box>\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n mr: '10px',\n }}\n >\n <Typography variant=\"body1\" sx={{ fontWeight: 700 }}>\n This resource is part of a Portal\n </Typography>\n <Typography variant=\"body1\">\n {' '}\n Access it on the {appConfig.friendlyName}\n </Typography>\n </Box>\n </Box>\n <ChevronRightTwoTone />\n </Box>\n )\n })}\n </Box>\n )\n}\n"],"mappings":";;;;;;;;;;;AAuBA,SAAwB,EAAqB,EAC3C,aACA,yBAAsB,eACtB,4BAAyB,iBACG;CAC5B,IAAM,EAAE,MAAM,MAAmB,EAAiB,EAAS,EAGrD,IAA2B,IAC7B,EAAe,KAAK,KAAI,MAAU,EAAO,GAAG,CAAC,MAAM,EAAE,GACrD,CAAC,EAAS,EAER,IACJ,IACI,CACE;EACE,cACE;EACF,YAAY;EACZ,UAAU,EAAgC;EAC1C,QAAQ;EACT,CACF,GACD,EAAE,EACF,EAAE,MAAM,MAAoB,EAChC;EACE,UAAU;EACV,OAAO;GACL,KAAK,2BAA2B;GAChC,mBAAmB;GACpB;EACD,UAAA;EACA,cAAc;EACf,EACD,EACE,SAAS,CAAC,CAAC,GACZ,CACF,EAEK,IAAS,GAAiB,cAAc,aAAa,cACrD,IAAmB,CAAC,CAAC,KAAU,GAAQ,KAAK,SAAS,GAErD,IAAS,GAAQ,
|
|
1
|
+
{"version":3,"file":"SynapsePortalBanners.js","names":[],"sources":["../../../src/components/SynapsePortalBanners/SynapsePortalBanners.tsx"],"sourcesContent":["import {\n useGetEntityPath,\n useGetQueryResultBundleWithAsyncStatus,\n} from '@/synapse-queries'\nimport { useSourceAppConfigs } from '@/utils/hooks'\nimport { BUNDLE_MASK_QUERY_RESULTS } from '@/utils/SynapseConstants'\nimport { ChevronRightTwoTone } from '@mui/icons-material'\nimport { Box, Typography } from '@mui/material'\nimport {\n ColumnSingleValueQueryFilter,\n ColumnSingleValueFilterOperator,\n} from '@sage-bionetworks/synapse-types'\n\nexport type SynapsePortalBannersProps = {\n entityId: string\n dataCatalogEntityId?: string\n sourceAppConfigTableID?: string\n}\n\n/**\n *\n * @param props\n */\nexport default function SynapsePortalBanners({\n entityId,\n dataCatalogEntityId = 'syn61609402',\n sourceAppConfigTableID = 'syn45291362',\n}: SynapsePortalBannersProps) {\n const { data: entityPathData } = useGetEntityPath(entityId)\n // get all EntityHeader ids in the entity path data in a string array\n // Note: we remove the first item from entityPathData.path as it is always the root Synapse folder which we don't want to include\n const entityIdValues: string[] = entityPathData\n ? entityPathData.path.map(header => header.id).slice(1)\n : [entityId]\n\n const dataCatalogAdditionalFilters: ColumnSingleValueQueryFilter[] =\n entityIdValues\n ? [\n {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n columnName: 'id',\n operator: ColumnSingleValueFilterOperator.IN,\n values: entityIdValues,\n },\n ]\n : []\n const { data: dataCatalogData } = useGetQueryResultBundleWithAsyncStatus(\n {\n entityId: dataCatalogEntityId,\n query: {\n sql: `SELECT appId, link FROM ${dataCatalogEntityId}`,\n additionalFilters: dataCatalogAdditionalFilters,\n },\n partMask: BUNDLE_MASK_QUERY_RESULTS,\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n },\n {\n enabled: !!entityPathData,\n },\n )\n\n const rowSet = dataCatalogData?.responseBody?.queryResult?.queryResults\n const hasPortalBanners = !!rowSet && rowSet?.rows.length > 0\n\n const appIds = rowSet?.rows\n .map(row => row.values[0])\n .filter((v): v is string => !!v) as string[]\n const hasAppIds = appIds && appIds.length > 0\n\n const sourceAppConfigFilters: ColumnSingleValueQueryFilter[] = hasAppIds\n ? [\n {\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n columnName: 'appId',\n operator: ColumnSingleValueFilterOperator.EQUAL,\n values: appIds,\n },\n ]\n : []\n const sourceAppConfigs = useSourceAppConfigs(\n sourceAppConfigTableID,\n sourceAppConfigFilters,\n )\n const hasSourceAppConfigs = !!sourceAppConfigs && sourceAppConfigs.length > 0\n\n if (!hasAppIds || !hasPortalBanners || !hasSourceAppConfigs) {\n return <></>\n }\n\n // we have source app configs associated to this entity, let's render the banners\n return (\n <Box\n sx={{\n display: 'flex',\n flexWrap: 'wrap',\n gap: '20px',\n width: '100%',\n alignItems: 'center',\n }}\n >\n {sourceAppConfigs.map((appConfig, index) => {\n const dataCatalogRow = rowSet.rows.find(row => {\n return row.values[0] === appConfig.appId\n })\n\n const link = dataCatalogRow?.values[1] || appConfig.appURL\n return (\n <Box\n key={index}\n component=\"a\"\n href={link}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n flex={1}\n sx={{\n display: 'flex',\n flexWrap: 'nowrap',\n padding: '16px',\n justifyContent: 'space-between',\n border: '1px solid #ccc',\n borderRadius: '8px',\n backgroundColor: '#f9f9f9',\n textDecoration: 'none',\n pointer: 'cursor',\n '&:hover': {\n textDecoration: 'none !important',\n },\n width: '100%',\n alignItems: 'center',\n mt: '10px',\n mb: '10px',\n }}\n >\n <Box\n flex={1}\n sx={{\n display: 'flex',\n flexWrap: 'wrap',\n justifyContent: 'space-between',\n gap: '10px',\n }}\n >\n <Box\n sx={{\n '> *': {\n height: '60px',\n },\n }}\n >\n {appConfig?.logo}\n </Box>\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n mr: '10px',\n }}\n >\n <Typography variant=\"body1\" sx={{ fontWeight: 700 }}>\n This resource is part of a Portal\n </Typography>\n <Typography variant=\"body1\">\n {' '}\n Access it on the {appConfig.friendlyName}\n </Typography>\n </Box>\n </Box>\n <ChevronRightTwoTone />\n </Box>\n )\n })}\n </Box>\n )\n}\n"],"mappings":";;;;;;;;;;;AAuBA,SAAwB,EAAqB,EAC3C,aACA,yBAAsB,eACtB,4BAAyB,iBACG;CAC5B,IAAM,EAAE,MAAM,MAAmB,EAAiB,EAAS,EAGrD,IAA2B,IAC7B,EAAe,KAAK,KAAI,MAAU,EAAO,GAAG,CAAC,MAAM,EAAE,GACrD,CAAC,EAAS,EAER,IACJ,IACI,CACE;EACE,cACE;EACF,YAAY;EACZ,UAAU,EAAgC;EAC1C,QAAQ;EACT,CACF,GACD,EAAE,EACF,EAAE,MAAM,MAAoB,EAChC;EACE,UAAU;EACV,OAAO;GACL,KAAK,2BAA2B;GAChC,mBAAmB;GACpB;EACD,UAAA;EACA,cAAc;EACf,EACD,EACE,SAAS,CAAC,CAAC,GACZ,CACF,EAEK,IAAS,GAAiB,cAAc,aAAa,cACrD,IAAmB,CAAC,CAAC,KAAU,GAAQ,KAAK,SAAS,GAErD,IAAS,GAAQ,KACpB,KAAI,MAAO,EAAI,OAAO,GAAG,CACzB,QAAQ,MAAmB,CAAC,CAAC,EAAE,EAC5B,IAAY,KAAU,EAAO,SAAS,GAatC,IAAmB,EACvB,GAZ6D,IAC3D,CACE;EACE,cACE;EACF,YAAY;EACZ,UAAU,EAAgC;EAC1C,QAAQ;EACT,CACF,GACD,EAAE,CAIL,EACK,IAAsB,CAAC,CAAC,KAAoB,EAAiB,SAAS;AAO5E,QALI,CAAC,KAAa,CAAC,KAAoB,CAAC,IAC/B,kBAAA,GAAA,EAAK,CAAA,GAKZ,kBAAC,GAAD;EACE,IAAI;GACF,SAAS;GACT,UAAU;GACV,KAAK;GACL,OAAO;GACP,YAAY;GACb;YAEA,EAAiB,KAAK,GAAW,MAO9B,kBAAC,GAAD;GAEE,WAAU;GACV,MATmB,EAAO,KAAK,MAAK,MAC/B,EAAI,OAAO,OAAO,EAAU,MAGxB,EAAgB,OAAO,MAAM,EAAU;GAMhD,QAAO;GACP,KAAI;GACJ,MAAM;GACN,IAAI;IACF,SAAS;IACT,UAAU;IACV,SAAS;IACT,gBAAgB;IAChB,QAAQ;IACR,cAAc;IACd,iBAAiB;IACjB,gBAAgB;IAChB,SAAS;IACT,WAAW,EACT,gBAAgB,mBACjB;IACD,OAAO;IACP,YAAY;IACZ,IAAI;IACJ,IAAI;IACL;aAxBH,CA0BE,kBAAC,GAAD;IACE,MAAM;IACN,IAAI;KACF,SAAS;KACT,UAAU;KACV,gBAAgB;KAChB,KAAK;KACN;cAPH,CASE,kBAAC,GAAD;KACE,IAAI,EACF,OAAO,EACL,QAAQ,QACT,EACF;eAEA,GAAW;KACR,CAAA,EACN,kBAAC,GAAD;KACE,IAAI;MACF,SAAS;MACT,eAAe;MACf,gBAAgB;MAChB,IAAI;MACL;eANH,CAQE,kBAAC,GAAD;MAAY,SAAQ;MAAQ,IAAI,EAAE,YAAY,KAAK;gBAAE;MAExC,CAAA,EACb,kBAAC,GAAD;MAAY,SAAQ;gBAApB;OACG;OAAI;OACa,EAAU;OACjB;QACT;OACF;OACN,kBAAC,GAAD,EAAuB,CAAA,CACnB;KA7DC,EA6DD,CAER;EACE,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SearchV2.js","names":[],"sources":["../../../src/components/SynapseTable/SearchV2.tsx"],"sourcesContent":["import {\n isColumnMultiValueFunctionQueryFilter,\n isColumnSingleValueQueryFilter,\n LockedColumn,\n} from '@/utils'\nimport { Collapse } from '@mui/material'\nimport {\n ColumnModel,\n ColumnMultiValueFunction,\n ColumnMultiValueFunctionQueryFilter,\n ColumnSingleValueFilterOperator,\n ColumnSingleValueQueryFilter,\n ColumnTypeEnum,\n QueryFilter,\n} from '@sage-bionetworks/synapse-types'\nimport {\n Component,\n createRef,\n FormEvent,\n RefObject,\n SyntheticEvent,\n} from 'react'\nimport { CSSTransition } from 'react-transition-group'\nimport IconSvg from '../IconSvg/IconSvg'\nimport { QueryContextType } from '../QueryContext'\nimport { QueryVisualizationContextType } from '../QueryVisualizationWrapper'\nimport { useGetQueryMetadata } from '../QueryWrapper/useGetQueryMetadata'\nimport { ReadonlyDeep } from 'type-fest'\n\ntype SearchState = {\n show: boolean\n /* \n When the component is revealed in queryplotnav we want to focus on the input field and reveal the dropdown\n there is an issue where the method handleClickOutsideForm will override the state from componentDidUpdate\n so we track when componentDidUpdate just fired so that `show` is not overriden on the click event which\n triggers componentDidUpdate \n */\n didUpdateRanLast: boolean\n searchText: string\n columnName: string\n}\n\nexport type SearchableColumnsV2 = string[]\n\nexport type SearchV2Props = {\n queryContext: QueryContextType\n queryVisualizationContext: QueryVisualizationContextType\n isQueryWrapperMenuChild?: boolean\n defaultColumn?: string\n searchable?: SearchableColumnsV2\n lockedColumn?: LockedColumn\n /**\n * PLFM-8897, PORTALS-3534: Full-Text Search configuration.\n * For Tables that have FTS enabled...\n * If specified, use the specified mode and distance (if BOOLEAN mode). Otherwise default to NATURAL_LANGUAGE mode.\n */\n ftsConfig?: ReadonlyDeep<FTSConfig>\n}\n\nexport type TextMatchesMode = 'NATURAL_LANGUAGE' | 'BOOLEAN'\nexport type FTSConfig = {\n textMatchesMode: TextMatchesMode\n distance?: number // In BOOLEAN mode, this operator tests whether two or more words all start within a specified distance from each other, measured in words.\n searchHelpURL?: string\n /**\n * Optional function to provide autocomplete suggestions for the search bar.\n * When provided, the search input will show a dropdown of suggestions as the user types.\n * @param searchText - The current text in the search input\n * @returns A promise resolving to an array of suggestion strings\n */\n getSuggestions?: (searchText: string) => Promise<string[]>\n /**\n * Override the minimum number of characters required before a search is executed.\n * Defaults to 3 (see PLFM-7011).\n */\n minSearchQueryLength?: number\n /**\n * When true, submitting a new search term replaces any existing TextMatchesQueryFilter\n * in additionalFilters rather than appending a new one.\n * Defaults to false (existing behaviour: filters accumulate).\n */\n replaceExistingFilter?: boolean\n}\n\ntype InternalSearchProps = SearchV2Props & {\n columnModels: ColumnModel[] | undefined\n}\n\nclass _Search extends Component<InternalSearchProps, SearchState> {\n public searchFormRef: RefObject<HTMLFormElement | null>\n public radioFormRef: RefObject<HTMLFormElement | null>\n\n constructor(props: InternalSearchProps) {\n super(props)\n this.state = {\n show: false,\n didUpdateRanLast: false,\n searchText: '',\n columnName: this.props.defaultColumn ?? '',\n }\n this.searchFormRef = createRef()\n this.radioFormRef = createRef()\n }\n\n componentDidMount() {\n // @ts-expect-error\n document.addEventListener('click', this.handleClickOutsideForm)\n }\n\n componentDidUpdate(prevProps: InternalSearchProps) {\n if (\n !prevProps.queryVisualizationContext?.showSearchBar &&\n this.props.queryVisualizationContext?.showSearchBar\n ) {\n this.setState({\n show: true,\n didUpdateRanLast: true,\n })\n this.searchFormRef?.current?.querySelector('input')?.focus()\n }\n }\n\n componentWillUnmount() {\n // @ts-expect-error\n document.removeEventListener('click', this.handleClickOutsideForm)\n }\n\n handleClickOutsideForm = (event: SyntheticEvent) => {\n if (\n // @ts-expect-error\n !this.searchFormRef.current?.contains(event?.target) &&\n // @ts-expect-error\n !this.radioFormRef.current?.contains(event?.target)\n ) {\n if (this.state.didUpdateRanLast) {\n this.setState({\n didUpdateRanLast: false,\n })\n } else {\n this.setState({\n show: false,\n })\n }\n }\n }\n\n public search = (event: SyntheticEvent<HTMLFormElement>) => {\n // form completion by default causes the page to reload, so we prevent that\n event.preventDefault()\n const { searchText } = this.state\n let { columnName } = this.state\n const { searchable, lockedColumn } = this.props\n if (columnName === '') {\n if (searchable) {\n // If searchable column names are defined in the config, grab the first one (that is not locked)\n columnName = searchable.filter(\n colName => colName !== lockedColumn?.columnName,\n )[0]\n } else {\n // Otherwise, get the first column model that can be searched.\n // And for study details page: if lockedColumn is defined, remove it from the search\n const searchableColumnModels = this.props.columnModels\n ?.filter(el => el.name !== lockedColumn?.columnName)\n .filter(el => this.isSupportedColumn(el))\n columnName = searchableColumnModels?.[0].name ?? ''\n }\n }\n this.setState({\n show: false,\n })\n const { executeQueryRequest, getCurrentQueryRequest } =\n this.props.queryContext\n\n const lastQueryRequestDeepClone = getCurrentQueryRequest()\n\n const { additionalFilters = [] } = lastQueryRequestDeepClone.query\n\n const indexOfColumn = additionalFilters.findIndex((el: QueryFilter) => {\n if (\n isColumnSingleValueQueryFilter(el) ||\n (isColumnMultiValueFunctionQueryFilter(el) &&\n el.columnName === columnName)\n ) {\n return true\n }\n return false\n })\n if (indexOfColumn === -1) {\n // get the column model to figure out what kind of filter we should apply.\n const columnModel: ColumnModel | undefined =\n this.props.columnModels?.filter(el => el.name === columnName)[0]\n if (columnModel?.columnType.endsWith('_LIST')) {\n const columnMultiValueQueryFilter: ColumnMultiValueFunctionQueryFilter =\n {\n columnName,\n function: ColumnMultiValueFunction.HAS_LIKE,\n _function: ColumnMultiValueFunction.HAS_LIKE,\n values: [`%${searchText}%`],\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnMultiValueFunctionQueryFilter',\n }\n additionalFilters.push(columnMultiValueQueryFilter)\n } else {\n if (columnModel?.columnType == ColumnTypeEnum.ENTITYID) {\n const columnSingleValueQueryFilter: ColumnSingleValueQueryFilter = {\n columnName,\n operator: ColumnSingleValueFilterOperator.EQUAL,\n values: [`${searchText.toLowerCase().replace('syn', '')}`],\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n }\n additionalFilters.push(columnSingleValueQueryFilter)\n } else {\n const columnSingleValueQueryFilter: ColumnSingleValueQueryFilter = {\n columnName,\n operator: ColumnSingleValueFilterOperator.LIKE,\n values: [`%${searchText}%`],\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n }\n additionalFilters.push(columnSingleValueQueryFilter)\n }\n }\n } else {\n ;(\n additionalFilters[indexOfColumn] as\n | ColumnSingleValueQueryFilter\n | ColumnMultiValueFunctionQueryFilter\n ).values.push(`%${searchText}%`)\n }\n lastQueryRequestDeepClone.query.additionalFilters = additionalFilters\n executeQueryRequest(lastQueryRequestDeepClone)\n }\n\n public handleChange = (event: FormEvent<HTMLInputElement>) => {\n this.setState({\n searchText: event.currentTarget.value,\n })\n }\n\n public isSupportedColumn = (columnModel?: ColumnModel) => {\n switch (columnModel?.columnType) {\n case ColumnTypeEnum.FILEHANDLEID:\n case ColumnTypeEnum.DATE:\n case ColumnTypeEnum.DATE_LIST:\n case ColumnTypeEnum.USERID:\n // case ColumnTypeEnum.ENTITYID: //PORTALS-2995: users may want to search on Synapse ID\n return false\n default:\n return true\n }\n }\n\n public isSupportedColumnAndInProps = (columnModel?: ColumnModel) => {\n if (this.isSupportedColumn(columnModel)) {\n // return true if the searchable array contains this column name\n const { searchable } = this.props\n return searchable?.some(e => e === columnModel?.name)\n }\n return false\n }\n\n render() {\n const {\n searchable,\n lockedColumn,\n columnModels,\n queryVisualizationContext: { showSearchBar, getColumnDisplayName },\n } = this.props\n const { searchText, show, columnName } = this.state\n let searchColumns: string[] = []\n\n // searchable specifies the order of the columns to search\n if (searchable) {\n searchColumns = searchable\n .map(el => columnModels?.find(model => model.name === el))\n .filter(this.isSupportedColumnAndInProps)\n .map(el => el!.name)\n } else if (columnModels) {\n searchColumns = columnModels\n ?.filter(this.isSupportedColumn)\n .map(el => el.name)\n }\n\n // For study details page: if lockedColumn is defined, remove it from the radio dropdown\n if (searchColumns.length && lockedColumn?.columnName) {\n searchColumns = searchColumns.filter(\n el => el !== lockedColumn?.columnName,\n )\n }\n return (\n <div className={`QueryWrapperSearchInput`}>\n <Collapse in={showSearchBar}>\n <form\n className=\"QueryWrapperSearchInput__searchbar\"\n onSubmit={this.search}\n onClick={() => {\n this.setState({ show: true })\n }}\n ref={this.searchFormRef}\n >\n <span className=\"QueryWrapperSearchInput__searchbar__searchicon\">\n <IconSvg icon=\"search\" />\n </span>\n <input\n onChange={this.handleChange}\n onClick={() => {\n this.setState({\n show: true,\n })\n }}\n placeholder=\"Enter Search Terms\"\n value={searchText}\n type=\"text\"\n />\n {this.state.searchText.length > 0 && (\n <button\n className=\"QueryWrapperSearchInput__searchbar__clearbutton\"\n type=\"button\"\n onClick={() => {\n this.setState({\n searchText: '',\n })\n }}\n >\n <IconSvg icon=\"close\" />\n </button>\n )}\n </form>\n </Collapse>\n <div className=\"QueryWrapperSearchInput__dropdown_pos\">\n <CSSTransition\n nodeRef={this.radioFormRef}\n in={show}\n classNames=\"QueryWrapperSearchInput__animate_dropdown\"\n timeout={{ enter: 0, exit: 300 }}\n >\n <form\n ref={this.radioFormRef}\n className=\"QueryWrapperSearchInput__column-select QueryWrapperSearchInput__animate_height\"\n >\n <p className=\"deemphasized\">\n <i> Search In Field: </i>\n </p>\n {searchColumns.map((name, index) => {\n const displayName = getColumnDisplayName(name)\n const isSelected =\n (columnName === '' && index === 0) || columnName === name\n return (\n <div className=\"radio\" key={`search-field-${name}-${index}`}>\n <label>\n <span>\n <input\n id={name}\n type=\"radio\"\n value={name}\n checked={isSelected}\n onClick={() => {\n this.searchFormRef?.current\n ?.querySelector('input')\n ?.focus()\n this.setState({\n columnName: name,\n })\n }}\n />\n <span>{displayName}</span>\n </span>\n </label>\n </div>\n )\n })}\n </form>\n </CSSTransition>\n </div>\n </div>\n )\n }\n}\n\nexport default function Search(props: SearchV2Props) {\n const { data: queryMetadata } = useGetQueryMetadata()\n return <_Search {...props} columnModels={queryMetadata?.columnModels} />\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SearchV2.js","names":[],"sources":["../../../src/components/SynapseTable/SearchV2.tsx"],"sourcesContent":["import {\n isColumnMultiValueFunctionQueryFilter,\n isColumnSingleValueQueryFilter,\n LockedColumn,\n} from '@/utils'\nimport { Collapse } from '@mui/material'\nimport {\n ColumnModel,\n ColumnMultiValueFunction,\n ColumnMultiValueFunctionQueryFilter,\n ColumnSingleValueFilterOperator,\n ColumnSingleValueQueryFilter,\n ColumnTypeEnum,\n QueryFilter,\n} from '@sage-bionetworks/synapse-types'\nimport {\n Component,\n createRef,\n FormEvent,\n RefObject,\n SyntheticEvent,\n} from 'react'\nimport { CSSTransition } from 'react-transition-group'\nimport IconSvg from '../IconSvg/IconSvg'\nimport { QueryContextType } from '../QueryContext'\nimport { QueryVisualizationContextType } from '../QueryVisualizationWrapper'\nimport { useGetQueryMetadata } from '../QueryWrapper/useGetQueryMetadata'\nimport { ReadonlyDeep } from 'type-fest'\n\ntype SearchState = {\n show: boolean\n /*\n When the component is revealed in queryplotnav we want to focus on the input field and reveal the dropdown\n there is an issue where the method handleClickOutsideForm will override the state from componentDidUpdate\n so we track when componentDidUpdate just fired so that `show` is not overriden on the click event which\n triggers componentDidUpdate \n */\n didUpdateRanLast: boolean\n searchText: string\n columnName: string\n}\n\nexport type SearchableColumnsV2 = string[]\n\nexport type SearchV2Props = {\n queryContext: QueryContextType\n queryVisualizationContext: QueryVisualizationContextType\n isQueryWrapperMenuChild?: boolean\n defaultColumn?: string\n searchable?: SearchableColumnsV2\n lockedColumn?: LockedColumn\n /**\n * PLFM-8897, PORTALS-3534: Full-Text Search configuration.\n * For Tables that have FTS enabled...\n * If specified, use the specified mode and distance (if BOOLEAN mode). Otherwise default to NATURAL_LANGUAGE mode.\n */\n ftsConfig?: ReadonlyDeep<FTSConfig>\n}\n\nexport type TextMatchesMode = 'NATURAL_LANGUAGE' | 'BOOLEAN'\nexport type FTSConfig = {\n textMatchesMode: TextMatchesMode\n distance?: number // In BOOLEAN mode, this operator tests whether two or more words all start within a specified distance from each other, measured in words.\n searchHelpURL?: string\n /**\n * Optional function to provide autocomplete suggestions for the search bar.\n * When provided, the search input will show a dropdown of suggestions as the user types.\n * @param searchText - The current text in the search input\n * @returns A promise resolving to an array of suggestion strings\n */\n getSuggestions?: (searchText: string) => Promise<string[]>\n /**\n * Override the minimum number of characters required before a search is executed.\n * Defaults to 3 (see PLFM-7011).\n */\n minSearchQueryLength?: number\n /**\n * When true, submitting a new search term replaces any existing TextMatchesQueryFilter\n * in additionalFilters rather than appending a new one.\n * Defaults to false (existing behaviour: filters accumulate).\n */\n replaceExistingFilter?: boolean\n}\n\ntype InternalSearchProps = SearchV2Props & {\n columnModels: ColumnModel[] | undefined\n}\n\nclass _Search extends Component<InternalSearchProps, SearchState> {\n public searchFormRef: RefObject<HTMLFormElement | null>\n public radioFormRef: RefObject<HTMLFormElement | null>\n\n constructor(props: InternalSearchProps) {\n super(props)\n this.state = {\n show: false,\n didUpdateRanLast: false,\n searchText: '',\n columnName: this.props.defaultColumn ?? '',\n }\n this.searchFormRef = createRef()\n this.radioFormRef = createRef()\n }\n\n componentDidMount() {\n // @ts-expect-error\n document.addEventListener('click', this.handleClickOutsideForm)\n }\n\n componentDidUpdate(prevProps: InternalSearchProps) {\n if (\n !prevProps.queryVisualizationContext?.showSearchBar &&\n this.props.queryVisualizationContext?.showSearchBar\n ) {\n this.setState({\n show: true,\n didUpdateRanLast: true,\n })\n this.searchFormRef?.current?.querySelector('input')?.focus()\n }\n }\n\n componentWillUnmount() {\n // @ts-expect-error\n document.removeEventListener('click', this.handleClickOutsideForm)\n }\n\n handleClickOutsideForm = (event: SyntheticEvent) => {\n if (\n // @ts-expect-error\n !this.searchFormRef.current?.contains(event?.target) &&\n // @ts-expect-error\n !this.radioFormRef.current?.contains(event?.target)\n ) {\n if (this.state.didUpdateRanLast) {\n this.setState({\n didUpdateRanLast: false,\n })\n } else {\n this.setState({\n show: false,\n })\n }\n }\n }\n\n public search = (event: SyntheticEvent<HTMLFormElement>) => {\n // form completion by default causes the page to reload, so we prevent that\n event.preventDefault()\n const { searchText } = this.state\n let { columnName } = this.state\n const { searchable, lockedColumn } = this.props\n if (columnName === '') {\n if (searchable) {\n // If searchable column names are defined in the config, grab the first one (that is not locked)\n columnName = searchable.filter(\n colName => colName !== lockedColumn?.columnName,\n )[0]\n } else {\n // Otherwise, get the first column model that can be searched.\n // And for study details page: if lockedColumn is defined, remove it from the search\n const searchableColumnModels = this.props.columnModels\n ?.filter(el => el.name !== lockedColumn?.columnName)\n .filter(el => this.isSupportedColumn(el))\n columnName = searchableColumnModels?.[0].name ?? ''\n }\n }\n this.setState({\n show: false,\n })\n const { executeQueryRequest, getCurrentQueryRequest } =\n this.props.queryContext\n\n const lastQueryRequestDeepClone = getCurrentQueryRequest()\n\n const { additionalFilters = [] } = lastQueryRequestDeepClone.query\n\n const indexOfColumn = additionalFilters.findIndex((el: QueryFilter) => {\n if (\n isColumnSingleValueQueryFilter(el) ||\n (isColumnMultiValueFunctionQueryFilter(el) &&\n el.columnName === columnName)\n ) {\n return true\n }\n return false\n })\n if (indexOfColumn === -1) {\n // get the column model to figure out what kind of filter we should apply.\n const columnModel: ColumnModel | undefined =\n this.props.columnModels?.filter(el => el.name === columnName)[0]\n if (columnModel?.columnType.endsWith('_LIST')) {\n const columnMultiValueQueryFilter: ColumnMultiValueFunctionQueryFilter =\n {\n columnName,\n function: ColumnMultiValueFunction.HAS_LIKE,\n _function: ColumnMultiValueFunction.HAS_LIKE,\n values: [`%${searchText}%`],\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnMultiValueFunctionQueryFilter',\n }\n additionalFilters.push(columnMultiValueQueryFilter)\n } else {\n if (columnModel?.columnType == ColumnTypeEnum.ENTITYID) {\n const columnSingleValueQueryFilter: ColumnSingleValueQueryFilter = {\n columnName,\n operator: ColumnSingleValueFilterOperator.EQUAL,\n values: [`${searchText.toLowerCase().replace('syn', '')}`],\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n }\n additionalFilters.push(columnSingleValueQueryFilter)\n } else {\n const columnSingleValueQueryFilter: ColumnSingleValueQueryFilter = {\n columnName,\n operator: ColumnSingleValueFilterOperator.LIKE,\n values: [`%${searchText}%`],\n concreteType:\n 'org.sagebionetworks.repo.model.table.ColumnSingleValueQueryFilter',\n }\n additionalFilters.push(columnSingleValueQueryFilter)\n }\n }\n } else {\n ;(\n additionalFilters[indexOfColumn] as\n | ColumnSingleValueQueryFilter\n | ColumnMultiValueFunctionQueryFilter\n ).values.push(`%${searchText}%`)\n }\n lastQueryRequestDeepClone.query.additionalFilters = additionalFilters\n executeQueryRequest(lastQueryRequestDeepClone)\n }\n\n public handleChange = (event: FormEvent<HTMLInputElement>) => {\n this.setState({\n searchText: event.currentTarget.value,\n })\n }\n\n public isSupportedColumn = (columnModel?: ColumnModel) => {\n switch (columnModel?.columnType) {\n case ColumnTypeEnum.FILEHANDLEID:\n case ColumnTypeEnum.DATE:\n case ColumnTypeEnum.DATE_LIST:\n case ColumnTypeEnum.USERID:\n // case ColumnTypeEnum.ENTITYID: //PORTALS-2995: users may want to search on Synapse ID\n return false\n default:\n return true\n }\n }\n\n public isSupportedColumnAndInProps = (columnModel?: ColumnModel) => {\n if (this.isSupportedColumn(columnModel)) {\n // return true if the searchable array contains this column name\n const { searchable } = this.props\n return searchable?.some(e => e === columnModel?.name)\n }\n return false\n }\n\n render() {\n const {\n searchable,\n lockedColumn,\n columnModels,\n queryVisualizationContext: { showSearchBar, getColumnDisplayName },\n } = this.props\n const { searchText, show, columnName } = this.state\n let searchColumns: string[] = []\n\n // searchable specifies the order of the columns to search\n if (searchable) {\n searchColumns = searchable\n .map(el => columnModels?.find(model => model.name === el))\n .filter(this.isSupportedColumnAndInProps)\n .map(el => el!.name)\n } else if (columnModels) {\n searchColumns = columnModels\n ?.filter(this.isSupportedColumn)\n .map(el => el.name)\n }\n\n // For study details page: if lockedColumn is defined, remove it from the radio dropdown\n if (searchColumns.length && lockedColumn?.columnName) {\n searchColumns = searchColumns.filter(\n el => el !== lockedColumn?.columnName,\n )\n }\n return (\n <div className={`QueryWrapperSearchInput`}>\n <Collapse in={showSearchBar}>\n <form\n className=\"QueryWrapperSearchInput__searchbar\"\n onSubmit={this.search}\n onClick={() => {\n this.setState({ show: true })\n }}\n ref={this.searchFormRef}\n >\n <span className=\"QueryWrapperSearchInput__searchbar__searchicon\">\n <IconSvg icon=\"search\" />\n </span>\n <input\n onChange={this.handleChange}\n onClick={() => {\n this.setState({\n show: true,\n })\n }}\n placeholder=\"Enter Search Terms\"\n value={searchText}\n type=\"text\"\n />\n {this.state.searchText.length > 0 && (\n <button\n className=\"QueryWrapperSearchInput__searchbar__clearbutton\"\n type=\"button\"\n onClick={() => {\n this.setState({\n searchText: '',\n })\n }}\n >\n <IconSvg icon=\"close\" />\n </button>\n )}\n </form>\n </Collapse>\n <div className=\"QueryWrapperSearchInput__dropdown_pos\">\n <CSSTransition\n nodeRef={this.radioFormRef}\n in={show}\n classNames=\"QueryWrapperSearchInput__animate_dropdown\"\n timeout={{ enter: 0, exit: 300 }}\n >\n <form\n ref={this.radioFormRef}\n className=\"QueryWrapperSearchInput__column-select QueryWrapperSearchInput__animate_height\"\n >\n <p className=\"deemphasized\">\n <i> Search In Field: </i>\n </p>\n {searchColumns.map((name, index) => {\n const displayName = getColumnDisplayName(name)\n const isSelected =\n (columnName === '' && index === 0) || columnName === name\n return (\n <div className=\"radio\" key={`search-field-${name}-${index}`}>\n <label>\n <span>\n <input\n id={name}\n type=\"radio\"\n value={name}\n checked={isSelected}\n onClick={() => {\n this.searchFormRef?.current\n ?.querySelector('input')\n ?.focus()\n this.setState({\n columnName: name,\n })\n }}\n />\n <span>{displayName}</span>\n </span>\n </label>\n </div>\n )\n })}\n </form>\n </CSSTransition>\n </div>\n </div>\n )\n }\n}\n\nexport default function Search(props: SearchV2Props) {\n const { data: queryMetadata } = useGetQueryMetadata()\n return <_Search {...props} columnModels={queryMetadata?.columnModels} />\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SynapseTable.js","names":[],"sources":["../../../src/components/SynapseTable/SynapseTable.tsx"],"sourcesContent":["import { useGetEntity } from '@/synapse-queries'\nimport { useSynapseContext } from '@/utils'\nimport {\n ColumnTypeEnum,\n Row,\n RowSet,\n Table,\n} from '@sage-bionetworks/synapse-types'\nimport {\n Cell,\n ColumnDef,\n createColumnHelper,\n getCoreRowModel,\n useReactTable,\n VisibilityState,\n} from '@tanstack/react-table'\nimport { useAtomValue } from 'jotai'\nimport { useMemo, useState } from 'react'\nimport { LabelLinkConfig } from '../CardContainerLogic'\nimport ModalDownload from '../ModalDownload/ModalDownload'\nimport { useQueryContext } from '../QueryContext'\nimport { useQueryVisualizationContext } from '../QueryVisualizationWrapper'\nimport { isRowSelectionVisibleAtom } from '../QueryWrapper/TableRowSelectionState'\nimport StyledTanStackTable from '../TanStackTable/StyledTanStackTable'\nimport { SynapseTableContext } from './SynapseTableContext'\nimport {\n accessColumn,\n addToDownloadListColumn,\n directDownloadColumn,\n rowSelectionColumn,\n TableDataCell,\n TableDataColumnHeader,\n} from './SynapseTableRenderers'\nimport {\n isEntityViewOrDatasetOrCollection,\n isFileViewOrDataset,\n isSortableColumn,\n} from './SynapseTableUtils'\nimport { usePrefetchResourcesInTable } from './usePrefetchTableData'\nimport { useTableSort } from './useTableSort'\n\nconst DEFAULT_CUSTOM_COLUMNS: ColumnDef<Row, any>[] = []\n\n/**\n * Returns the minimum column width (in px) for a Synapse table column\n * based on its type and name.\n */\nexport function getColumnMinSize(\n columnName: string,\n columnType: ColumnTypeEnum,\n): number {\n const nameLower = columnName.toLowerCase()\n if (nameLower.includes('name') || nameLower.includes('description')) {\n return 250\n }\n switch (columnType) {\n case ColumnTypeEnum.ENTITYID:\n case ColumnTypeEnum.ENTITYID_LIST:\n case ColumnTypeEnum.USERID:\n case ColumnTypeEnum.USERID_LIST:\n case ColumnTypeEnum.FILEHANDLEID:\n case ColumnTypeEnum.EVALUATIONID:\n case ColumnTypeEnum.SUBMISSIONID:\n return 180\n case ColumnTypeEnum.DATE:\n case ColumnTypeEnum.DATE_LIST:\n return 120\n case ColumnTypeEnum.STRING:\n case ColumnTypeEnum.STRING_LIST:\n return 100\n default:\n return 60\n }\n}\n\nexport type SynapseTableConfiguration = Pick<\n SynapseTableProps,\n | 'showAccessColumn'\n | 'showExternalAccessIcon'\n | 'showAccessColumnHeader'\n | 'showDownloadColumn'\n | 'hideDownload'\n | 'showDirectDownloadColumn'\n | 'hideAddToDownloadListColumn'\n | 'columnLinks'\n | 'customColumns'\n>\n\nexport type SynapseTableProps = {\n /** The row data shown in the table. */\n rowSet: RowSet\n /** Whether a new page of data is being loaded */\n isLoadingNewPage: boolean\n /** Custom columns to render in the table */\n customColumns?: ColumnDef<Row, any>[]\n /** If true and entity is a view or dataset, renders a column that represents if the caller has permission to download the entity represented by the row */\n showAccessColumn?: boolean\n /**\n * If true, the component will show enhanced UI for the case where\n * - the entity is a FileEntity, AND\n * - the caller has permission to fetch the dataFileHandle, AND\n * - the dataFileHandle is an instance of ExternalFileHandleInterface (i.e. the file is not controlled by Synapse)\n * Note that this requires an additional API call that cannot be batched, so it should be avoided in bulk contexts if possible.\n * @default false\n */\n showExternalAccessIcon?: boolean\n showAccessColumnHeader?: boolean\n /** @deprecated use showDirectDownloadColumn */\n showDownloadColumn?: boolean\n /** @deprecated use hideAddToDownloadListColumn */\n hideDownload?: boolean\n /** If true and entity is a file view or dataset, renders a column that allows the logged-in user to directly download the file, if they have permission */\n showDirectDownloadColumn?: boolean\n /** If true, the add to download list column will be hidden */\n hideAddToDownloadListColumn?: boolean\n /** Configuration to override cell renderers with e.g. a link to a portals detail page */\n columnLinks?: LabelLinkConfig\n}\n\nconst columnHelper = createColumnHelper<Row>()\n\nexport function SynapseTable(props: SynapseTableProps) {\n const { showDownloadColumn, hideDownload } = props\n const {\n rowSet,\n isLoadingNewPage,\n customColumns = DEFAULT_CUSTOM_COLUMNS,\n showAccessColumn,\n showExternalAccessIcon,\n showAccessColumnHeader,\n showDirectDownloadColumn = showDownloadColumn,\n hideAddToDownloadListColumn = hideDownload,\n columnLinks,\n } = props\n const {\n entityId,\n versionNumber,\n getCurrentQueryRequest,\n fileIdColumnName,\n fileVersionColumnName,\n } = useQueryContext()\n const queryRequest = useMemo(\n () => getCurrentQueryRequest(),\n [getCurrentQueryRequest],\n )\n\n const selectColumns = rowSet.headers\n\n const { data: entity } = useGetEntity<Table>(entityId, versionNumber)\n\n const { columnsToShowInTable, NoContentPlaceholder } =\n useQueryVisualizationContext()\n const synapseTableContext = useMemo(\n () => ({\n columnLinks,\n showExternalAccessIcon,\n }),\n [columnLinks, showExternalAccessIcon],\n )\n const { isAuthenticated } = useSynapseContext()\n\n const [isExportTableDownloadOpen, setIsExportTableDownloadOpen] =\n useState(false)\n\n const { sort, setSort } = useTableSort()\n const isRowSelectionVisible = useAtomValue(isRowSelectionVisibleAtom)\n\n const isShowingAccessColumn: boolean = Boolean(\n showAccessColumn &&\n entity &&\n ((isEntityViewOrDatasetOrCollection(entity) && allRowsHaveId(rowSet)) ||\n fileIdColumnName),\n )\n const rowsAreDownloadable =\n entity &&\n isAuthenticated &&\n ((isFileViewOrDataset(entity) && allRowsHaveId(rowSet)) || fileIdColumnName)\n\n const isShowingDirectDownloadColumn = Boolean(\n rowsAreDownloadable && showDirectDownloadColumn,\n )\n\n const isShowingAddToV2DownloadListColumn: boolean = Boolean(\n rowsAreDownloadable &&\n !hideAddToDownloadListColumn &&\n !isRowSelectionVisible,\n )\n const rowEntityIDColumnIndex = fileIdColumnName\n ? rowSet.headers.findIndex(col => col.name == fileIdColumnName)\n : undefined\n const rowEntityVersionColumnIndex = fileVersionColumnName\n ? rowSet.headers.findIndex(col => col.name == fileVersionColumnName)\n : undefined\n\n const columns = useMemo(\n () => [\n ...customColumns,\n rowSelectionColumn,\n addToDownloadListColumn,\n directDownloadColumn,\n {\n ...accessColumn,\n header: showAccessColumn && showAccessColumnHeader ? 'Access' : '',\n },\n ...(selectColumns.map((selectColumn, index) => {\n return columnHelper.accessor(row => row.values[index], {\n id: selectColumn.name,\n enableSorting: isSortableColumn(selectColumn.columnType),\n enableResizing: true,\n minSize: getColumnMinSize(\n selectColumn.name,\n selectColumn.columnType as ColumnTypeEnum,\n ),\n header: TableDataColumnHeader,\n cell: TableDataCell,\n })\n }) ?? []),\n ],\n [customColumns, selectColumns, showAccessColumn, showAccessColumnHeader],\n )\n\n const prependColumnVisibility: VisibilityState = useMemo(\n () => ({\n [rowSelectionColumn.id as string]: isRowSelectionVisible,\n [addToDownloadListColumn.id as string]:\n isShowingAddToV2DownloadListColumn,\n [directDownloadColumn.id as string]: isShowingDirectDownloadColumn,\n [accessColumn.id as string]: isShowingAccessColumn,\n }),\n [\n isRowSelectionVisible,\n isShowingAccessColumn,\n isShowingAddToV2DownloadListColumn,\n isShowingDirectDownloadColumn,\n ],\n )\n\n // Transform our `columnsToShowInTable` to @tanstack/react-table's `VisibilityState`\n const columnVisibility: VisibilityState = useMemo(\n () =>\n selectColumns.reduce((prev: VisibilityState, curr) => {\n return {\n ...prev,\n [curr.name]: columnsToShowInTable.includes(curr.name),\n }\n }, prependColumnVisibility),\n [columnsToShowInTable, selectColumns, prependColumnVisibility],\n )\n\n const { dataHasBeenPrefetched } = usePrefetchResourcesInTable(rowSet)\n const renderTableDataPlaceholder = isLoadingNewPage || !dataHasBeenPrefetched\n\n const table = useReactTable({\n data: rowSet.rows,\n columns,\n defaultColumn: { minSize: 60 },\n getCoreRowModel: getCoreRowModel(),\n manualSorting: true,\n manualFiltering: true,\n onSortingChange: setSort,\n enableMultiSort: true,\n columnResizeMode: 'onChange',\n state: {\n sorting: sort,\n columnVisibility: columnVisibility,\n },\n meta: {\n rowSet,\n // make the rowEntityIDColumnIndex available to all cell renderers\n rowEntityIDColumnIndex,\n rowEntityVersionColumnIndex,\n renderPlaceholderData: renderTableDataPlaceholder,\n getWrapInExpandableTd: (cell: Cell<Row, unknown>) => {\n const selectColumn = selectColumns.find(\n cm => cm.name === cell.column.id,\n )\n return Boolean(\n selectColumn &&\n /* JSON handles its own overflow*/\n selectColumn.columnType !== ColumnTypeEnum.JSON,\n )\n },\n },\n })\n\n /**\n * Display the view\n */\n if (!rowSet) {\n return <></>\n }\n const hasResults = (rowSet.rows?.length ?? 0) > 0\n // Show the No Results UI if the current page has no rows, and this is the first page of data (offset === 0 or null/undefined).\n if (\n !hasResults &&\n (queryRequest.query.offset === 0 || queryRequest.query.offset == null)\n ) {\n return <NoContentPlaceholder />\n }\n\n return (\n <SynapseTableContext.Provider value={synapseTableContext}>\n <div>\n {isExportTableDownloadOpen && (\n <ModalDownload\n onClose={() => {\n setIsExportTableDownloadOpen(false)\n }}\n queryBundleRequest={queryRequest}\n />\n )}\n <StyledTanStackTable\n styledTableContainerProps={{\n className: 'SynapseTable',\n ['data-testid']: 'SynapseTable',\n density: 'default',\n }}\n table={table}\n fullWidth={false}\n autoColumnSizing={true}\n />\n </div>\n </SynapseTableContext.Provider>\n )\n}\n\n/**\n * If this is a view/dataset and rows have an ID, then rows represent individual objects in Synapse.\n * Presence of row IDs also indicates that the query is also necessarily not summary data, e.g. the query does\n * not include an operation like GROUP BY, DISTINCT, etc., that would cause rows to not map 1:1 to Synapse Entities\n */\nfunction allRowsHaveId(rowSet: RowSet): boolean {\n return Boolean(rowSet.rows?.every(row => !!row.rowId))\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SynapseTable.js","names":[],"sources":["../../../src/components/SynapseTable/SynapseTable.tsx"],"sourcesContent":["import { useGetEntity } from '@/synapse-queries'\nimport { useSynapseContext } from '@/utils'\nimport {\n ColumnTypeEnum,\n Row,\n RowSet,\n Table,\n} from '@sage-bionetworks/synapse-types'\nimport {\n Cell,\n ColumnDef,\n createColumnHelper,\n getCoreRowModel,\n useReactTable,\n VisibilityState,\n} from '@tanstack/react-table'\nimport { useAtomValue } from 'jotai'\nimport { useMemo, useState } from 'react'\nimport { LabelLinkConfig } from '../CardContainerLogic'\nimport ModalDownload from '../ModalDownload/ModalDownload'\nimport { useQueryContext } from '../QueryContext'\nimport { useQueryVisualizationContext } from '../QueryVisualizationWrapper'\nimport { isRowSelectionVisibleAtom } from '../QueryWrapper/TableRowSelectionState'\nimport StyledTanStackTable from '../TanStackTable/StyledTanStackTable'\nimport { SynapseTableContext } from './SynapseTableContext'\nimport {\n accessColumn,\n addToDownloadListColumn,\n directDownloadColumn,\n rowSelectionColumn,\n TableDataCell,\n TableDataColumnHeader,\n} from './SynapseTableRenderers'\nimport {\n isEntityViewOrDatasetOrCollection,\n isFileViewOrDataset,\n isSortableColumn,\n} from './SynapseTableUtils'\nimport { usePrefetchResourcesInTable } from './usePrefetchTableData'\nimport { useTableSort } from './useTableSort'\n\nconst DEFAULT_CUSTOM_COLUMNS: ColumnDef<Row, any>[] = []\n\n/**\n * Returns the minimum column width (in px) for a Synapse table column\n * based on its type and name.\n */\nexport function getColumnMinSize(\n columnName: string,\n columnType: ColumnTypeEnum,\n): number {\n const nameLower = columnName.toLowerCase()\n if (nameLower.includes('name') || nameLower.includes('description')) {\n return 250\n }\n switch (columnType) {\n case ColumnTypeEnum.ENTITYID:\n case ColumnTypeEnum.ENTITYID_LIST:\n case ColumnTypeEnum.USERID:\n case ColumnTypeEnum.USERID_LIST:\n case ColumnTypeEnum.FILEHANDLEID:\n case ColumnTypeEnum.EVALUATIONID:\n case ColumnTypeEnum.SUBMISSIONID:\n return 180\n case ColumnTypeEnum.DATE:\n case ColumnTypeEnum.DATE_LIST:\n return 120\n case ColumnTypeEnum.STRING:\n case ColumnTypeEnum.STRING_LIST:\n return 100\n default:\n return 60\n }\n}\n\nexport type SynapseTableConfiguration = Pick<\n SynapseTableProps,\n | 'showAccessColumn'\n | 'showExternalAccessIcon'\n | 'showAccessColumnHeader'\n | 'showDownloadColumn'\n | 'hideDownload'\n | 'showDirectDownloadColumn'\n | 'hideAddToDownloadListColumn'\n | 'columnLinks'\n | 'customColumns'\n>\n\nexport type SynapseTableProps = {\n /** The row data shown in the table. */\n rowSet: RowSet\n /** Whether a new page of data is being loaded */\n isLoadingNewPage: boolean\n /** Custom columns to render in the table */\n customColumns?: ColumnDef<Row, any>[]\n /** If true and entity is a view or dataset, renders a column that represents if the caller has permission to download the entity represented by the row */\n showAccessColumn?: boolean\n /**\n * If true, the component will show enhanced UI for the case where\n * - the entity is a FileEntity, AND\n * - the caller has permission to fetch the dataFileHandle, AND\n * - the dataFileHandle is an instance of ExternalFileHandleInterface (i.e. the file is not controlled by Synapse)\n * Note that this requires an additional API call that cannot be batched, so it should be avoided in bulk contexts if possible.\n * @default false\n */\n showExternalAccessIcon?: boolean\n showAccessColumnHeader?: boolean\n /** @deprecated use showDirectDownloadColumn */\n showDownloadColumn?: boolean\n /** @deprecated use hideAddToDownloadListColumn */\n hideDownload?: boolean\n /** If true and entity is a file view or dataset, renders a column that allows the logged-in user to directly download the file, if they have permission */\n showDirectDownloadColumn?: boolean\n /** If true, the add to download list column will be hidden */\n hideAddToDownloadListColumn?: boolean\n /** Configuration to override cell renderers with e.g. a link to a portals detail page */\n columnLinks?: LabelLinkConfig\n}\n\nconst columnHelper = createColumnHelper<Row>()\n\nexport function SynapseTable(props: SynapseTableProps) {\n const { showDownloadColumn, hideDownload } = props\n const {\n rowSet,\n isLoadingNewPage,\n customColumns = DEFAULT_CUSTOM_COLUMNS,\n showAccessColumn,\n showExternalAccessIcon,\n showAccessColumnHeader,\n showDirectDownloadColumn = showDownloadColumn,\n hideAddToDownloadListColumn = hideDownload,\n columnLinks,\n } = props\n const {\n entityId,\n versionNumber,\n getCurrentQueryRequest,\n fileIdColumnName,\n fileVersionColumnName,\n } = useQueryContext()\n const queryRequest = useMemo(\n () => getCurrentQueryRequest(),\n [getCurrentQueryRequest],\n )\n\n const selectColumns = rowSet.headers\n\n const { data: entity } = useGetEntity<Table>(entityId, versionNumber)\n\n const { columnsToShowInTable, NoContentPlaceholder } =\n useQueryVisualizationContext()\n const synapseTableContext = useMemo(\n () => ({\n columnLinks,\n showExternalAccessIcon,\n }),\n [columnLinks, showExternalAccessIcon],\n )\n const { isAuthenticated } = useSynapseContext()\n\n const [isExportTableDownloadOpen, setIsExportTableDownloadOpen] =\n useState(false)\n\n const { sort, setSort } = useTableSort()\n const isRowSelectionVisible = useAtomValue(isRowSelectionVisibleAtom)\n\n const isShowingAccessColumn: boolean = Boolean(\n showAccessColumn &&\n entity &&\n ((isEntityViewOrDatasetOrCollection(entity) && allRowsHaveId(rowSet)) ||\n fileIdColumnName),\n )\n const rowsAreDownloadable =\n entity &&\n isAuthenticated &&\n ((isFileViewOrDataset(entity) && allRowsHaveId(rowSet)) || fileIdColumnName)\n\n const isShowingDirectDownloadColumn = Boolean(\n rowsAreDownloadable && showDirectDownloadColumn,\n )\n\n const isShowingAddToV2DownloadListColumn: boolean = Boolean(\n rowsAreDownloadable &&\n !hideAddToDownloadListColumn &&\n !isRowSelectionVisible,\n )\n const rowEntityIDColumnIndex = fileIdColumnName\n ? rowSet.headers.findIndex(col => col.name == fileIdColumnName)\n : undefined\n const rowEntityVersionColumnIndex = fileVersionColumnName\n ? rowSet.headers.findIndex(col => col.name == fileVersionColumnName)\n : undefined\n\n const columns = useMemo(\n () => [\n ...customColumns,\n rowSelectionColumn,\n addToDownloadListColumn,\n directDownloadColumn,\n {\n ...accessColumn,\n header: showAccessColumn && showAccessColumnHeader ? 'Access' : '',\n },\n ...(selectColumns.map((selectColumn, index) => {\n return columnHelper.accessor(row => row.values[index], {\n id: selectColumn.name,\n enableSorting: isSortableColumn(selectColumn.columnType),\n enableResizing: true,\n minSize: getColumnMinSize(\n selectColumn.name,\n selectColumn.columnType as ColumnTypeEnum,\n ),\n header: TableDataColumnHeader,\n cell: TableDataCell,\n })\n }) ?? []),\n ],\n [customColumns, selectColumns, showAccessColumn, showAccessColumnHeader],\n )\n\n const prependColumnVisibility: VisibilityState = useMemo(\n () => ({\n [rowSelectionColumn.id as string]: isRowSelectionVisible,\n [addToDownloadListColumn.id as string]:\n isShowingAddToV2DownloadListColumn,\n [directDownloadColumn.id as string]: isShowingDirectDownloadColumn,\n [accessColumn.id as string]: isShowingAccessColumn,\n }),\n [\n isRowSelectionVisible,\n isShowingAccessColumn,\n isShowingAddToV2DownloadListColumn,\n isShowingDirectDownloadColumn,\n ],\n )\n\n // Transform our `columnsToShowInTable` to @tanstack/react-table's `VisibilityState`\n const columnVisibility: VisibilityState = useMemo(\n () =>\n selectColumns.reduce((prev: VisibilityState, curr) => {\n return {\n ...prev,\n [curr.name]: columnsToShowInTable.includes(curr.name),\n }\n }, prependColumnVisibility),\n [columnsToShowInTable, selectColumns, prependColumnVisibility],\n )\n\n const { dataHasBeenPrefetched } = usePrefetchResourcesInTable(rowSet)\n const renderTableDataPlaceholder = isLoadingNewPage || !dataHasBeenPrefetched\n\n const table = useReactTable({\n data: rowSet.rows,\n columns,\n defaultColumn: { minSize: 60 },\n getCoreRowModel: getCoreRowModel(),\n manualSorting: true,\n manualFiltering: true,\n onSortingChange: setSort,\n enableMultiSort: true,\n columnResizeMode: 'onChange',\n state: {\n sorting: sort,\n columnVisibility: columnVisibility,\n },\n meta: {\n rowSet,\n // make the rowEntityIDColumnIndex available to all cell renderers\n rowEntityIDColumnIndex,\n rowEntityVersionColumnIndex,\n renderPlaceholderData: renderTableDataPlaceholder,\n getWrapInExpandableTd: (cell: Cell<Row, unknown>) => {\n const selectColumn = selectColumns.find(\n cm => cm.name === cell.column.id,\n )\n return Boolean(\n selectColumn &&\n /* JSON handles its own overflow*/\n selectColumn.columnType !== ColumnTypeEnum.JSON,\n )\n },\n },\n })\n\n /**\n * Display the view\n */\n if (!rowSet) {\n return <></>\n }\n const hasResults = (rowSet.rows?.length ?? 0) > 0\n // Show the No Results UI if the current page has no rows, and this is the first page of data (offset === 0 or null/undefined).\n if (\n !hasResults &&\n (queryRequest.query.offset === 0 || queryRequest.query.offset == null)\n ) {\n return <NoContentPlaceholder />\n }\n\n return (\n <SynapseTableContext.Provider value={synapseTableContext}>\n <div>\n {isExportTableDownloadOpen && (\n <ModalDownload\n onClose={() => {\n setIsExportTableDownloadOpen(false)\n }}\n queryBundleRequest={queryRequest}\n />\n )}\n <StyledTanStackTable\n styledTableContainerProps={{\n className: 'SynapseTable',\n ['data-testid']: 'SynapseTable',\n density: 'default',\n }}\n table={table}\n fullWidth={false}\n autoColumnSizing={true}\n />\n </div>\n </SynapseTableContext.Provider>\n )\n}\n\n/**\n * If this is a view/dataset and rows have an ID, then rows represent individual objects in Synapse.\n * Presence of row IDs also indicates that the query is also necessarily not summary data, e.g. the query does\n * not include an operation like GROUP BY, DISTINCT, etc., that would cause rows to not map 1:1 to Synapse Entities\n */\nfunction allRowsHaveId(rowSet: RowSet): boolean {\n return Boolean(rowSet.rows?.every(row => !!row.rowId))\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SynapseTableUtils.d.ts","sourceRoot":"","sources":["../../../src/components/SynapseTable/SynapseTableUtils.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,WAAW,EACX,UAAU,EAEV,MAAM,EACN,YAAY,EACZ,iBAAiB,EACjB,KAAK,EACL,eAAe,EACf,WAAW,EACZ,MAAM,iCAAiC,CAAA;AAExC,eAAO,MAAM,yCAAyC,mEACY,CAAA;AAElE,eAAO,MAAM,wBAAwB,GACnC,MAAM,iBAAiB,GAAG,SAAS,EACnC,GAAG,aAAa,UAAU,EAAE,aAS7B,CAAA;AAED,eAAO,MAAM,iBAAiB,GAC5B,MAAM,iBAAiB,EACvB,eAAe,MAAM,CACnB,MAAM,EACN,YAAY,GAAG,OAAO,CAAC,eAAe,GAAG,WAAW,CAAC,CACtD,EACD,SAAS,MAAM,EAAE,gBAiBlB,CAAA;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,CAAC,EAAE,KAAK,uBAKjD;AAED,eAAO,MAAM,oBAAoB,GAC/B,eAAe,WAAW,EAAE,KAC3B,MAAM,GAAG,SAkBX,CAAA;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,WA4BlD;AAED,wBAAgB,oBAAoB,CAClC,MAAM,CAAC,EAAE,KAAK,EACd,YAAY,CAAC,EAAE,WAAW,EAAE,GAC3B,MAAM,EAAE,GAAG,SAAS,CAUtB;AAED,wBAAgB,iCAAiC,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"SynapseTableUtils.d.ts","sourceRoot":"","sources":["../../../src/components/SynapseTable/SynapseTableUtils.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,WAAW,EACX,UAAU,EAEV,MAAM,EACN,YAAY,EACZ,iBAAiB,EACjB,KAAK,EACL,eAAe,EACf,WAAW,EACZ,MAAM,iCAAiC,CAAA;AAExC,eAAO,MAAM,yCAAyC,mEACY,CAAA;AAElE,eAAO,MAAM,wBAAwB,GACnC,MAAM,iBAAiB,GAAG,SAAS,EACnC,GAAG,aAAa,UAAU,EAAE,aAS7B,CAAA;AAED,eAAO,MAAM,iBAAiB,GAC5B,MAAM,iBAAiB,EACvB,eAAe,MAAM,CACnB,MAAM,EACN,YAAY,GAAG,OAAO,CAAC,eAAe,GAAG,WAAW,CAAC,CACtD,EACD,SAAS,MAAM,EAAE,gBAiBlB,CAAA;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,CAAC,EAAE,KAAK,uBAKjD;AAED,eAAO,MAAM,oBAAoB,GAC/B,eAAe,WAAW,EAAE,KAC3B,MAAM,GAAG,SAkBX,CAAA;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,WA4BlD;AAED,wBAAgB,oBAAoB,CAClC,MAAM,CAAC,EAAE,KAAK,EACd,YAAY,CAAC,EAAE,WAAW,EAAE,GAC3B,MAAM,EAAE,GAAG,SAAS,CAUtB;AAED,wBAAgB,iCAAiC,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAKzE;AAED,wBAAgB,cAAc,CAC5B,OAAO,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,EAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAQ/B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SynapseTableUtils.js","names":[],"sources":["../../../src/components/SynapseTable/SynapseTableUtils.ts"],"sourcesContent":["import {\n hasFilesInView,\n isDataset,\n isDatasetCollection,\n isEntityView,\n} from '@/utils/functions/EntityTypeUtils'\nimport {\n ColumnModel,\n ColumnType,\n ColumnTypeEnum,\n Entity,\n EntityHeader,\n QueryResultBundle,\n Table,\n UserGroupHeader,\n UserProfile,\n} from '@sage-bionetworks/synapse-types'\n\nexport const SEND_TO_ANALYSIS_PLATFORM_SIGN_IN_MESSAGE =\n 'You must be signed in to send results to an analysis platform.'\n\nexport const getColumnIndicesWithType = (\n data: QueryResultBundle | undefined,\n ...columnTypes: ColumnType[]\n) => {\n const columnsOfTypeEntity: number[] = []\n data?.selectColumns?.forEach((el, index) => {\n if (columnTypes.includes(el.columnType)) {\n columnsOfTypeEntity.push(index)\n }\n })\n return columnsOfTypeEntity\n}\n\nexport const getUniqueEntities = (\n data: QueryResultBundle,\n mapIdToHeader: Record<\n string,\n EntityHeader | Partial<UserGroupHeader & UserProfile>\n >,\n indices: number[],\n) => {\n const distinctEntities = new Set<string>()\n data.queryResult?.queryResults.rows.forEach(row => {\n row.values.forEach((el: string | null, colIndex: number) => {\n // make sure this is a column of type entity and that we haven't retrieved this entity's information prior\n if (\n el != null &&\n indices.includes(colIndex) &&\n !Object.prototype.hasOwnProperty.call(mapIdToHeader, el) &&\n el\n ) {\n distinctEntities.add(el)\n }\n })\n })\n return distinctEntities\n}\n\n/**\n * i.e. the view may have FileEntities in it\n *\n * PORTALS-2010: Enhance change made for PORTALS-1973. File specific action will only be shown for rows that represent FileEntities.\n */\nexport function isFileViewOrDataset(entity?: Table) {\n return (\n entity &&\n ((isEntityView(entity) && hasFilesInView(entity)) || isDataset(entity))\n )\n}\n\nexport const getFileColumnModelId = (\n columnModels?: ColumnModel[],\n): string | undefined => {\n if (!columnModels) {\n return undefined\n }\n const entityIdColumnModels: ColumnModel[] | undefined = columnModels?.filter(\n el => el.columnType === ColumnTypeEnum.ENTITYID,\n )\n // if there's a single ENTITYID type column, return that column id\n if (entityIdColumnModels?.length === 1) {\n return entityIdColumnModels[0].id\n }\n // otherwise, if there's an 'id' column, return that column id\n const idColumnModel = entityIdColumnModels?.filter(el => el.name === 'id')\n if (idColumnModel.length === 1) {\n return idColumnModel[0].id\n }\n // else the file ID column was not found\n return undefined\n}\n\nexport function isSortableColumn(column: ColumnType) {\n switch (column) {\n case ColumnTypeEnum.STRING:\n case ColumnTypeEnum.DOUBLE:\n case ColumnTypeEnum.BOOLEAN:\n case ColumnTypeEnum.INTEGER:\n case ColumnTypeEnum.DATE:\n case ColumnTypeEnum.LINK:\n case ColumnTypeEnum.MEDIUMTEXT:\n case ColumnTypeEnum.LARGETEXT:\n return true\n case ColumnTypeEnum.USERID:\n case ColumnTypeEnum.ENTITYID:\n case ColumnTypeEnum.FILEHANDLEID:\n case ColumnTypeEnum.STRING_LIST:\n case ColumnTypeEnum.INTEGER_LIST:\n case ColumnTypeEnum.BOOLEAN_LIST:\n case ColumnTypeEnum.DATE_LIST:\n case ColumnTypeEnum.USERID_LIST:\n case ColumnTypeEnum.ENTITYID_LIST:\n case ColumnTypeEnum.EVALUATIONID:\n case ColumnTypeEnum.SUBMISSIONID:\n case ColumnTypeEnum.JSON:\n return false\n default:\n console.warn(`Unhandled column type: ${column}`)\n return false\n }\n}\n\nexport function getDefaultPrimaryKey(\n entity?: Table,\n columnModels?: ColumnModel[],\n): string[] | undefined {\n if (\n isFileViewOrDataset(entity) &&\n columnModels?.find(cm => cm.name === 'id')\n ) {\n // If the primary key isn't specified via props, and this is a file view/dataset, we can safely use the 'id' column as primary key, if it is present\n // Note: Synapse tables don't have an internal concept of a primary key\n return ['id']\n }\n return undefined\n}\n\nexport function isEntityViewOrDatasetOrCollection(entity: Entity): boolean {\n return Boolean(\n entity &&\n
|
|
1
|
+
{"version":3,"file":"SynapseTableUtils.js","names":[],"sources":["../../../src/components/SynapseTable/SynapseTableUtils.ts"],"sourcesContent":["import {\n hasFilesInView,\n isDataset,\n isDatasetCollection,\n isEntityView,\n} from '@/utils/functions/EntityTypeUtils'\nimport {\n ColumnModel,\n ColumnType,\n ColumnTypeEnum,\n Entity,\n EntityHeader,\n QueryResultBundle,\n Table,\n UserGroupHeader,\n UserProfile,\n} from '@sage-bionetworks/synapse-types'\n\nexport const SEND_TO_ANALYSIS_PLATFORM_SIGN_IN_MESSAGE =\n 'You must be signed in to send results to an analysis platform.'\n\nexport const getColumnIndicesWithType = (\n data: QueryResultBundle | undefined,\n ...columnTypes: ColumnType[]\n) => {\n const columnsOfTypeEntity: number[] = []\n data?.selectColumns?.forEach((el, index) => {\n if (columnTypes.includes(el.columnType)) {\n columnsOfTypeEntity.push(index)\n }\n })\n return columnsOfTypeEntity\n}\n\nexport const getUniqueEntities = (\n data: QueryResultBundle,\n mapIdToHeader: Record<\n string,\n EntityHeader | Partial<UserGroupHeader & UserProfile>\n >,\n indices: number[],\n) => {\n const distinctEntities = new Set<string>()\n data.queryResult?.queryResults.rows.forEach(row => {\n row.values.forEach((el: string | null, colIndex: number) => {\n // make sure this is a column of type entity and that we haven't retrieved this entity's information prior\n if (\n el != null &&\n indices.includes(colIndex) &&\n !Object.prototype.hasOwnProperty.call(mapIdToHeader, el) &&\n el\n ) {\n distinctEntities.add(el)\n }\n })\n })\n return distinctEntities\n}\n\n/**\n * i.e. the view may have FileEntities in it\n *\n * PORTALS-2010: Enhance change made for PORTALS-1973. File specific action will only be shown for rows that represent FileEntities.\n */\nexport function isFileViewOrDataset(entity?: Table) {\n return (\n entity &&\n ((isEntityView(entity) && hasFilesInView(entity)) || isDataset(entity))\n )\n}\n\nexport const getFileColumnModelId = (\n columnModels?: ColumnModel[],\n): string | undefined => {\n if (!columnModels) {\n return undefined\n }\n const entityIdColumnModels: ColumnModel[] | undefined = columnModels?.filter(\n el => el.columnType === ColumnTypeEnum.ENTITYID,\n )\n // if there's a single ENTITYID type column, return that column id\n if (entityIdColumnModels?.length === 1) {\n return entityIdColumnModels[0].id\n }\n // otherwise, if there's an 'id' column, return that column id\n const idColumnModel = entityIdColumnModels?.filter(el => el.name === 'id')\n if (idColumnModel.length === 1) {\n return idColumnModel[0].id\n }\n // else the file ID column was not found\n return undefined\n}\n\nexport function isSortableColumn(column: ColumnType) {\n switch (column) {\n case ColumnTypeEnum.STRING:\n case ColumnTypeEnum.DOUBLE:\n case ColumnTypeEnum.BOOLEAN:\n case ColumnTypeEnum.INTEGER:\n case ColumnTypeEnum.DATE:\n case ColumnTypeEnum.LINK:\n case ColumnTypeEnum.MEDIUMTEXT:\n case ColumnTypeEnum.LARGETEXT:\n return true\n case ColumnTypeEnum.USERID:\n case ColumnTypeEnum.ENTITYID:\n case ColumnTypeEnum.FILEHANDLEID:\n case ColumnTypeEnum.STRING_LIST:\n case ColumnTypeEnum.INTEGER_LIST:\n case ColumnTypeEnum.BOOLEAN_LIST:\n case ColumnTypeEnum.DATE_LIST:\n case ColumnTypeEnum.USERID_LIST:\n case ColumnTypeEnum.ENTITYID_LIST:\n case ColumnTypeEnum.EVALUATIONID:\n case ColumnTypeEnum.SUBMISSIONID:\n case ColumnTypeEnum.JSON:\n return false\n default:\n console.warn(`Unhandled column type: ${column}`)\n return false\n }\n}\n\nexport function getDefaultPrimaryKey(\n entity?: Table,\n columnModels?: ColumnModel[],\n): string[] | undefined {\n if (\n isFileViewOrDataset(entity) &&\n columnModels?.find(cm => cm.name === 'id')\n ) {\n // If the primary key isn't specified via props, and this is a file view/dataset, we can safely use the 'id' column as primary key, if it is present\n // Note: Synapse tables don't have an internal concept of a primary key\n return ['id']\n }\n return undefined\n}\n\nexport function isEntityViewOrDatasetOrCollection(entity: Entity): boolean {\n return Boolean(\n entity &&\n (isEntityView(entity) || isDataset(entity) || isDatasetCollection(entity)),\n )\n}\n\nexport function mapRowToRecord(\n rowData: (string | null)[],\n schema: Record<string, number>,\n): Record<string, string | null> {\n return Object.entries(schema).reduce<Record<string, string | null>>(\n (acc, [columnName, columnIndex]) => {\n acc[columnName] = rowData[columnIndex]\n return acc\n },\n {},\n )\n}\n"],"mappings":";;;AAkBA,IAAa,IACX,kEAEW,KACX,GACA,GAAG,MACA;CACH,IAAM,IAAgC,EAAE;AAMxC,QALA,GAAM,eAAe,SAAS,GAAI,MAAU;AAC1C,EAAI,EAAY,SAAS,EAAG,WAAW,IACrC,EAAoB,KAAK,EAAM;GAEjC,EACK;GAGI,KACX,GACA,GAIA,MACG;CACH,IAAM,oBAAmB,IAAI,KAAa;AAc1C,QAbA,EAAK,aAAa,aAAa,KAAK,SAAQ,MAAO;AACjD,IAAI,OAAO,SAAS,GAAmB,MAAqB;AAE1D,GACE,KAAM,QACN,EAAQ,SAAS,EAAS,IAC1B,CAAC,OAAO,UAAU,eAAe,KAAK,GAAe,EAAG,IACxD,KAEA,EAAiB,IAAI,EAAG;IAE1B;GACF,EACK;;AAQT,SAAgB,EAAoB,GAAgB;AAClD,QACE,MACE,EAAa,EAAO,IAAI,EAAe,EAAO,IAAK,EAAU,EAAO;;AAI1E,IAAa,KACX,MACuB;AACvB,KAAI,CAAC,EACH;CAEF,IAAM,IAAkD,GAAc,QACpE,MAAM,EAAG,eAAe,EAAe,SACxC;AAED,KAAI,GAAsB,WAAW,EACnC,QAAO,EAAqB,GAAG;CAGjC,IAAM,IAAgB,GAAsB,QAAO,MAAM,EAAG,SAAS,KAAK;AAC1E,KAAI,EAAc,WAAW,EAC3B,QAAO,EAAc,GAAG;;AAM5B,SAAgB,EAAiB,GAAoB;AACnD,SAAQ,GAAR;EACE,KAAK,EAAe;EACpB,KAAK,EAAe;EACpB,KAAK,EAAe;EACpB,KAAK,EAAe;EACpB,KAAK,EAAe;EACpB,KAAK,EAAe;EACpB,KAAK,EAAe;EACpB,KAAK,EAAe,UAClB,QAAO;EACT,KAAK,EAAe;EACpB,KAAK,EAAe;EACpB,KAAK,EAAe;EACpB,KAAK,EAAe;EACpB,KAAK,EAAe;EACpB,KAAK,EAAe;EACpB,KAAK,EAAe;EACpB,KAAK,EAAe;EACpB,KAAK,EAAe;EACpB,KAAK,EAAe;EACpB,KAAK,EAAe;EACpB,KAAK,EAAe,KAClB,QAAO;EACT,QAEE,QADA,QAAQ,KAAK,0BAA0B,IAAS,EACzC;;;AAIb,SAAgB,EACd,GACA,GACsB;AACtB,KACE,EAAoB,EAAO,IAC3B,GAAc,MAAK,MAAM,EAAG,SAAS,KAAK,CAI1C,QAAO,CAAC,KAAK;;AAKjB,SAAgB,EAAkC,GAAyB;AACzE,QAAO,GACL,MACC,EAAa,EAAO,IAAI,EAAU,EAAO,IAAI,EAAoB,EAAO;;AAI7E,SAAgB,EACd,GACA,GAC+B;AAC/B,QAAO,OAAO,QAAQ,EAAO,CAAC,QAC3B,GAAK,CAAC,GAAY,QACjB,EAAI,KAAc,EAAQ,IACnB,IAET,EAAE,CACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DatasetItemsEditor.js","names":[],"sources":["../../../../src/components/SynapseTable/datasets/DatasetItemsEditor.tsx"],"sourcesContent":["import React from 'react'\nimport WideButton from '@/components/styled/WideButton'\nimport { datasetItemToReference } from '@/components/SynapseTable/datasets/DatasetEditorUtils'\nimport {\n useGetEntity,\n useGetEntityPath,\n useUpdateEntity,\n} from '@/synapse-queries'\nimport { RequiredProperties } from '@/utils'\nimport {\n convertToEntityType,\n entityTypeToFriendlyName,\n isDataset,\n isDatasetCollection,\n} from '@/utils/functions/EntityTypeUtils'\nimport { useSet } from '@/utils/hooks'\nimport AddCircleTwoToneIcon from '@mui/icons-material/AddCircleTwoTone'\nimport {\n Alert,\n Button,\n Checkbox,\n Skeleton,\n Tooltip,\n Typography,\n} from '@mui/material'\nimport { EntityType } from '@sage-bionetworks/synapse-client'\nimport {\n EntityRef,\n EntityRefCollectionView,\n Reference,\n} from '@sage-bionetworks/synapse-types'\nimport {\n createColumnHelper,\n getCoreRowModel,\n Table,\n useReactTable,\n} from '@tanstack/react-table'\nimport { useVirtualizer } from '@tanstack/react-virtual'\nimport { isEqual, upperFirst } from 'lodash-es'\nimport pluralize from 'pluralize'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport { CreatedOnCell } from '../../EntityFinder/details/view/table/CreatedOnCell'\nimport { EntityBadgeIconsCell } from '../../EntityFinder/details/view/table/EntityBadgeIconsCell'\nimport { EntityNameCell } from '../../EntityFinder/details/view/table/EntityNameCell'\nimport { ModifiedByCell } from '../../EntityFinder/details/view/table/ModifiedByCell'\nimport { ModifiedOnCell } from '../../EntityFinder/details/view/table/ModifiedOnCell'\nimport { ParentProjectCell } from '../../EntityFinder/details/view/table/ParentProjectCell'\nimport { EntityFinderModal } from '../../EntityFinder/EntityFinderModal'\nimport { FinderScope } from '../../EntityFinder/tree/EntityTree'\nimport { VersionSelectionType } from '../../EntityFinder/VersionSelectionType'\nimport { BlockingLoader } from '../../LoadingScreen/LoadingScreen'\nimport { SkeletonTable } from '../../Skeleton'\nimport WarningDialog from '../../SynapseForm/WarningDialog'\nimport ColumnHeader from '../../TanStackTable/ColumnHeader'\nimport StyledVirtualTanStackTable from '../../TanStackTable/StyledVirtualTanStackTable'\nimport { displayToast } from '../../ToastMessage'\nimport { DatasetEditorCheckboxCell } from './DatasetEditorCheckboxCell'\nimport { DatasetEditorVersionCell } from './DatasetEditorVersionCell'\nimport { EntityFetchErrorCell } from './EntityFetchErrorCell'\n\nexport type DatasetItemsEditorTableData = EntityRef & {\n isSelected: boolean\n setSelected: (value: boolean) => void\n}\n\nenum DatasetItemsEditorColumn {\n ERROR_STATE = 'errorState',\n SELECTED = 'isSelected',\n NAME = 'name',\n ENTITY_ID = 'entityId',\n BADGES = 'badges',\n VERSION = 'version',\n CREATED_ON = 'createdOn',\n MODIFIED_ON = 'modifieddOn',\n MODIFIED_BY = 'modifiedBy',\n PROJECT = 'project',\n}\n\nconst columnHelper = createColumnHelper<DatasetItemsEditorTableData>()\nfunction getColumns(\n opts: SelectAllCheckboxRendererProps & {\n changeVersionOnItem: (entityId: string, newVersion: number) => void\n },\n) {\n const {\n datasetToUpdate,\n selectedIds,\n clearSelectedIds,\n addSelectedId,\n allItemsAreSelected,\n changeVersionOnItem,\n } = opts\n return [\n columnHelper.display({\n id: DatasetItemsEditorColumn.ERROR_STATE,\n minSize: 35,\n maxSize: 35,\n size: 35,\n enableResizing: false,\n header: () => null,\n cell: EntityFetchErrorCell,\n }),\n columnHelper.display({\n id: DatasetItemsEditorColumn.SELECTED,\n minSize: 40,\n maxSize: 40,\n size: 40,\n enableResizing: false,\n header: () => (\n <SelectAllCheckboxRenderer\n datasetToUpdate={datasetToUpdate}\n selectedIds={selectedIds}\n clearSelectedIds={clearSelectedIds}\n addSelectedId={addSelectedId}\n allItemsAreSelected={allItemsAreSelected}\n />\n ),\n cell: DatasetEditorCheckboxCell,\n }),\n columnHelper.display({\n id: DatasetItemsEditorColumn.NAME,\n minSize: 50,\n size: 300,\n header: props => <ColumnHeader {...props} title={'Name'} />,\n cell: EntityNameCell,\n }),\n columnHelper.accessor(DatasetItemsEditorColumn.ENTITY_ID, {\n minSize: 50,\n size: 130,\n header: props => <ColumnHeader {...props} title={'ID'} />,\n enableColumnFilter: false,\n }),\n columnHelper.display({\n id: DatasetItemsEditorColumn.BADGES,\n minSize: 80,\n size: 80,\n enableResizing: true,\n cell: EntityBadgeIconsCell,\n }),\n columnHelper.display({\n id: DatasetItemsEditorColumn.VERSION,\n minSize: 150,\n size: 150,\n header: props => <ColumnHeader {...props} title={'Version'} />,\n cell: props => (\n <DatasetEditorVersionCell\n {...props}\n toggleSelection={datasetItem => {\n changeVersionOnItem(datasetItem.entityId, datasetItem.versionNumber)\n }}\n />\n ),\n }),\n columnHelper.display({\n id: DatasetItemsEditorColumn.CREATED_ON,\n header: props => <ColumnHeader {...props} title={'Created On'} />,\n size: 220,\n minSize: 170,\n cell: CreatedOnCell,\n }),\n columnHelper.display({\n id: DatasetItemsEditorColumn.MODIFIED_ON,\n header: props => <ColumnHeader {...props} title={'Modified On'} />,\n size: 220,\n minSize: 170,\n cell: ModifiedOnCell,\n }),\n columnHelper.display({\n id: DatasetItemsEditorColumn.MODIFIED_BY,\n header: props => <ColumnHeader {...props} title={'Modified By'} />,\n size: 250,\n enableResizing: true,\n cell: ModifiedByCell,\n }),\n columnHelper.display({\n id: DatasetItemsEditorColumn.PROJECT,\n header: props => <ColumnHeader {...props} title={'Size'} />,\n size: 300,\n cell: ParentProjectCell,\n }),\n ]\n}\n\nfunction getSelectableTypes(entity: EntityRefCollectionView) {\n if (isDataset(entity)) {\n return [EntityType.file]\n } else if (isDatasetCollection(entity)) {\n return [EntityType.dataset]\n } else {\n console.error(\n 'Cannot determine selectable types for entity type: ' +\n entity.concreteType,\n )\n return []\n }\n}\n\nexport function getCopy(entity?: EntityRefCollectionView) {\n const displayName = entity\n ? entityTypeToFriendlyName(convertToEntityType(entity.concreteType))\n : 'Collection'\n let itemName = 'Item'\n let currentVersionName = 'Current Version'\n if (entity && isDataset(entity)) {\n itemName = entityTypeToFriendlyName(EntityType.file)\n currentVersionName = 'Draft'\n } else if (entity && isDatasetCollection(entity)) {\n itemName = entityTypeToFriendlyName(EntityType.dataset)\n }\n\n const entityFinderPopover =\n entity && isDataset(entity)\n ? `Use the left pane to browse projects and folders. Select ${pluralize(\n itemName,\n )} from the right pane to add to this ${displayName}. ${upperFirst(\n pluralize(itemName),\n )} in a ${displayName} can be added from multiple folders. You can also use Search to find and select ${pluralize(\n itemName,\n )}.`\n : `Use the left pane to browse projects. Select ${pluralize(\n itemName,\n )} from the right pane to add to this ${displayName}. ${upperFirst(\n pluralize(itemName),\n )} in a ${displayName} can be added from multiple projects. You can also use Search to find and select ${pluralize(\n itemName,\n )}.`\n\n return {\n ADD_ITEMS: `Add ${pluralize(itemName)}`,\n ADD_ITEMS_TO: `Add ${pluralize(itemName)} to ${displayName}`,\n REMOVE_ITEMS: `Remove ${pluralize(itemName)}`,\n NO_ITEMS_IN_THIS_DATASET: `No ${pluralize(\n itemName,\n )} in this ${displayName}`,\n SAVE_TO_CONTINUE: `Save the ${displayName} to continue`,\n CREATE_VERSION_TO_FREEZE: `Create a Version of this ${displayName} to freeze it in its current state`,\n ENTITY_SAVED: `${displayName} Saved`,\n SAVE_CHANGES: `Save changes to ${currentVersionName}`,\n ENTITY_FINDER_POPOVER: entityFinderPopover,\n ENTITY_FINDER_PROMPT: `Find ${pluralize(\n itemName,\n )} to add to the ${displayName}.`,\n PRECONDITION_FAILED_MESSAGE: `Re-retrieve the ${displayName} to get the latest changes. Your current changes will be lost.`,\n PRECONDITION_FAILED_TITLE: `${displayName} updated since last fetched`,\n PRECONDITION_FAILED_ACTION: `Retrieve ${displayName}`,\n NO_CHANGES_MADE: `You have not made any changes to the ${displayName}.`,\n }\n}\n\nfunction getDataSetDifference(\n oldDataSet: EntityRef[],\n changedItems: EntityRef[],\n) {\n const unchangedItems = oldDataSet.filter(\n oldItem =>\n !changedItems.find(newItem => newItem.entityId === oldItem.entityId),\n )\n const deletedItems = [...unchangedItems]\n const { updatedItems, newItems } = changedItems.reduce(\n (results, result) => {\n const oldItem = oldDataSet.find(old => old.entityId === result.entityId)\n if (oldItem) {\n if (result.versionNumber !== oldItem.versionNumber) {\n results['updatedItems'].push(result)\n } else {\n unchangedItems.push(result)\n }\n } else {\n results['newItems'].push(result)\n }\n return results\n },\n { updatedItems: [], newItems: [] } as {\n updatedItems: EntityRef[]\n newItems: EntityRef[]\n },\n )\n\n return { unchangedItems, updatedItems, newItems, deletedItems }\n}\n\nfunction getDatasetChangedToastMessageTitle(\n previousDatasetToUpdate?: RequiredProperties<\n EntityRefCollectionView,\n 'items'\n >,\n datasetToUpdate?: RequiredProperties<EntityRefCollectionView, 'items'>,\n) {\n const { updatedItems, newItems, deletedItems } = getDataSetDifference(\n previousDatasetToUpdate?.items ?? [],\n datasetToUpdate?.items!,\n )\n let toastTitle = ''\n\n // \"X items(s) deleted\"\n if (deletedItems.length > 0) {\n toastTitle += `${deletedItems.length} Item${\n deletedItems.length === 1 ? '' : 's'\n } removed`\n } else {\n // \"Y item(s) added\"\n toastTitle += `${newItems.length} Item${\n newItems.length === 1 ? '' : 's'\n } added`\n\n // \"and Z item(s) updated\", only shown if there are updated items\n if (updatedItems.length > 0) {\n toastTitle += ` and ${updatedItems.length} Item${\n updatedItems.length === 1 ? '' : 's'\n } updated`\n }\n }\n return toastTitle\n}\n\nexport type DatasetItemsEditorProps = {\n /* The synId of the EntityRefCollectionView to modify */\n entityId: string\n /** Callback invoked when the editor changes state to contain un/saved changes. */\n onUnsavedChangesChange?: (hasUnsavedChanges: boolean) => void\n onSave?: () => void\n onClose?: () => void\n}\n\nconst ROW_HEIGHT = 48\n\ntype SelectAllCheckboxRendererProps = {\n datasetToUpdate: RequiredProperties<EntityRefCollectionView, 'items'>\n selectedIds: Omit<Set<string>, 'add' | 'delete' | 'clear'>\n addSelectedId: (...items: string[]) => void\n clearSelectedIds: () => void\n allItemsAreSelected: boolean\n}\n\nconst SelectAllCheckboxRenderer = (\n props: SelectAllCheckboxRendererProps,\n): React.ReactNode => {\n const {\n datasetToUpdate,\n clearSelectedIds,\n allItemsAreSelected,\n addSelectedId,\n } = props\n const isChecked = allItemsAreSelected\n\n return (\n <Checkbox\n inputProps={{ 'aria-label': 'Select All' }}\n checked={isChecked}\n disabled={datasetToUpdate.items.length === 0}\n onChange={() => {\n if (isChecked) {\n clearSelectedIds()\n } else {\n addSelectedId(...datasetToUpdate.items.map(item => item.entityId))\n }\n }}\n />\n )\n}\n\nfunction NoItemsPlaceholder(props: {\n titleCopy: string\n buttonCopy: string\n onButtonClick: () => void\n}) {\n const { titleCopy, buttonCopy, onButtonClick } = props\n return (\n <div className=\"NoItemsPlaceholder\">\n <Typography variant={'headline3'}>{titleCopy}</Typography>\n <WideButton\n variant=\"contained\"\n color=\"primary\"\n onClick={onButtonClick}\n startIcon={<AddCircleTwoToneIcon />}\n sx={{ mt: 2 }}\n >\n {buttonCopy}\n </WideButton>\n </div>\n )\n}\n\nexport function DatasetItemsEditor(props: DatasetItemsEditorProps) {\n const { entityId, onSave, onClose, onUnsavedChangesChange } = props\n const [showEntityFinder, setShowEntityFinder] = useState<boolean>(false)\n const [showWarningDialog, setShowWarningDialog] = useState<boolean>(false)\n\n // The current 'client state' of dataset that the user is currently editing. Updates to this state are not saved until the user clicks 'Save'.\n const [datasetToUpdate, setDatasetToUpdate] =\n useState<RequiredProperties<EntityRefCollectionView, 'items'>>()\n\n // The previous value of the datasetToUpdate variable. This is used to calculate a summary of bulk actions since the last update to the unsaved dataset state.\n const [previousDatasetToUpdate, setPreviousDatasetToUpdate] =\n useState<RequiredProperties<EntityRefCollectionView, 'items'>>()\n\n // Stores the `close` function that will be used to hide the last toast that prompted the user to save\n const [onCloseLastSavePromptToast, setOnCloseLastSavePromptToast] = useState<\n { close: () => void } | undefined\n >()\n\n const { data: datasetOnServer, refetch: refetchDataset } = useGetEntity<\n RequiredProperties<EntityRefCollectionView, 'items'>\n >(entityId, undefined, {\n staleTime: Infinity,\n })\n\n const hasChangedSinceLastSave = Boolean(\n datasetOnServer &&\n datasetToUpdate &&\n !isEqual(datasetOnServer, datasetToUpdate),\n )\n\n const {\n ADD_ITEMS,\n ADD_ITEMS_TO,\n REMOVE_ITEMS,\n NO_ITEMS_IN_THIS_DATASET,\n SAVE_TO_CONTINUE,\n CREATE_VERSION_TO_FREEZE,\n ENTITY_SAVED,\n SAVE_CHANGES,\n PRECONDITION_FAILED_TITLE,\n PRECONDITION_FAILED_MESSAGE,\n PRECONDITION_FAILED_ACTION,\n ENTITY_FINDER_POPOVER,\n ENTITY_FINDER_PROMPT,\n NO_CHANGES_MADE,\n } = useMemo(() => getCopy(datasetOnServer), [datasetOnServer])\n\n useEffect(() => {\n if (datasetOnServer) {\n // SWC-5876: Dataset Items may be undefined. This has the same inherent meaning as the empty list, so we'll just change it to save us some null checks.\n if (datasetOnServer.items == null) {\n datasetOnServer.items = []\n }\n setDatasetToUpdate(datasetOnServer)\n }\n }, [datasetOnServer])\n\n const {\n set: selectedIds,\n add: addSelectedId,\n remove: removeSelectedId,\n clear: clearSelectedIds,\n } = useSet<string>()\n const allItemsAreSelected = Boolean(\n datasetToUpdate && datasetToUpdate.items.length === selectedIds.size,\n )\n\n useEffect(() => {\n if (datasetToUpdate && datasetOnServer && onUnsavedChangesChange) {\n onUnsavedChangesChange(hasChangedSinceLastSave)\n }\n }, [\n datasetOnServer,\n datasetToUpdate,\n hasChangedSinceLastSave,\n onUnsavedChangesChange,\n ])\n\n // We get the project ID to show the \"Current Project\" context in the Entity Finder.\n const { data: path } = useGetEntityPath(entityId)\n const projectId = path?.path[1]?.id\n\n const { mutate, isPending: updateIsPending } =\n useUpdateEntity<EntityRefCollectionView>({\n onMutate: () => {\n // Close existing toast that prompted the user to save\n if (onCloseLastSavePromptToast) {\n onCloseLastSavePromptToast.close()\n setOnCloseLastSavePromptToast(undefined)\n }\n },\n onSuccess: () => {\n // The query should automatically be invalidated, but just in case\n void refetchDataset()\n\n if (onSave) {\n onSave()\n } else {\n // If onSave isn't specified, push a generic toast message.\n displayToast(CREATE_VERSION_TO_FREEZE, 'success', {\n title: ENTITY_SAVED,\n })\n }\n },\n onError: error => {\n if (error.status === 412) {\n displayToast(PRECONDITION_FAILED_MESSAGE, 'warning', {\n title: PRECONDITION_FAILED_TITLE,\n primaryButtonConfig: {\n text: PRECONDITION_FAILED_ACTION,\n onClick: () => {\n void refetchDataset()\n },\n },\n })\n } else {\n displayToast(error.reason, 'danger', {\n title: 'An Error Occurred',\n })\n }\n },\n })\n\n useEffect(() => {\n // When changes are made (but not saved) to the datasetToUpdate, show a notification that summarizes the change and prompts the user to save\n if (\n previousDatasetToUpdate &&\n datasetToUpdate &&\n !isEqual(previousDatasetToUpdate.items, datasetToUpdate.items) &&\n !updateIsPending\n ) {\n const toastMessageTitle = getDatasetChangedToastMessageTitle(\n previousDatasetToUpdate,\n datasetToUpdate,\n )\n // Replace existing toast that prompts the user to save before showing the new one\n if (onCloseLastSavePromptToast) {\n onCloseLastSavePromptToast.close()\n }\n const onCloseToast = displayToast(SAVE_TO_CONTINUE, 'info', {\n title: toastMessageTitle,\n primaryButtonConfig: {\n text: SAVE_CHANGES,\n onClick: () => mutate(datasetToUpdate),\n },\n })\n setOnCloseLastSavePromptToast({ close: onCloseToast })\n }\n setPreviousDatasetToUpdate(datasetToUpdate)\n // Only run when datasetToUpdate changes\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [datasetToUpdate])\n\n const tableData = useMemo(\n () =>\n datasetToUpdate?.items.map(\n (item: EntityRef): DatasetItemsEditorTableData => {\n return {\n ...item,\n isSelected: selectedIds.has(item.entityId),\n setSelected: (value: boolean) => {\n return value\n ? addSelectedId(item.entityId)\n : removeSelectedId(item.entityId)\n },\n }\n },\n ) ?? [],\n [addSelectedId, datasetToUpdate?.items, removeSelectedId, selectedIds],\n )\n\n function addItemsToDataset(itemsToAdd: Reference[]) {\n setDatasetToUpdate(datasetToUpdate => {\n if (datasetToUpdate) {\n const refToDatasetItem = itemsToAdd.map(item => ({\n entityId: item.targetId,\n versionNumber: item.targetVersionNumber!,\n }))\n const { unchangedItems, updatedItems, newItems } = getDataSetDifference(\n datasetToUpdate.items,\n refToDatasetItem,\n )\n\n if (updatedItems.length == 0 && newItems.length == 0) {\n // No items were added or updated, so don't update the state variable.\n return datasetToUpdate\n }\n\n const items = [...unchangedItems, ...updatedItems, ...newItems]\n\n return {\n ...datasetToUpdate,\n items: items,\n }\n } else {\n console.warn(\n 'Cannot add items to the Collection because it is undefined. The Collection may not have been fetched yet.',\n )\n return datasetToUpdate\n }\n })\n clearSelectedIds()\n }\n\n function removeSelectedItemsFromDataset() {\n setDatasetToUpdate(dataset => ({\n ...dataset!,\n items: dataset!.items.filter(\n datasetItem => !selectedIds.has(datasetItem.entityId),\n ),\n }))\n clearSelectedIds()\n }\n\n function changeVersionOnItem(entityId: string, newVersion: number) {\n setDatasetToUpdate(dataset => ({\n ...dataset!,\n items: dataset!.items.map(datasetItem =>\n datasetItem.entityId === entityId\n ? { entityId: entityId, versionNumber: newVersion }\n : datasetItem,\n ),\n }))\n }\n\n const selectableTypes: EntityType[] | undefined = useMemo(() => {\n if (datasetOnServer) {\n return getSelectableTypes(datasetOnServer)\n } else {\n return undefined\n }\n }, [datasetOnServer])\n\n const columns = useMemo(() => {\n if (!datasetToUpdate) {\n return []\n }\n return getColumns({\n datasetToUpdate,\n selectedIds,\n clearSelectedIds,\n addSelectedId,\n allItemsAreSelected,\n changeVersionOnItem,\n })\n }, [\n addSelectedId,\n allItemsAreSelected,\n clearSelectedIds,\n datasetToUpdate,\n selectedIds,\n ])\n\n const table: Table<DatasetItemsEditorTableData> =\n useReactTable<DatasetItemsEditorTableData>({\n data: tableData,\n columns,\n getCoreRowModel: getCoreRowModel(),\n columnResizeMode: 'onChange',\n // There are no backend sort controls. The server only provides ID/version, and a dataset could be up to 10k items,\n // so client side sorting is non-trivial. We may consider fetching all entity headers upon user request.\n enableSorting: false,\n })\n\n const tableContainerRef = useRef<HTMLDivElement>(null)\n\n const rowVirtualizer = useVirtualizer({\n count: tableData?.length ?? 0,\n estimateSize: () => ROW_HEIGHT, // estimate row height for accurate scrollbar dragging\n getScrollElement: () => tableContainerRef.current,\n // measure dynamic row height, except in firefox because it measures table border height incorrectly\n measureElement:\n typeof window !== 'undefined' &&\n navigator.userAgent.indexOf('Firefox') === -1\n ? element => element?.getBoundingClientRect().height\n : undefined,\n overscan: 5,\n })\n\n const datasetItemsAsEntityFinderRef = useMemo(\n () => datasetToUpdate?.items.map(datasetItemToReference),\n [datasetToUpdate],\n )\n\n return (\n <div className=\"DatasetEditor\">\n <EntityFinderModal\n initialSelected={datasetItemsAsEntityFinderRef}\n configuration={{\n projectId: projectId,\n selectMultiple: true,\n initialScope: FinderScope.CURRENT_PROJECT,\n initialContainer: projectId ?? null,\n selectableTypes: selectableTypes,\n versionSelection: VersionSelectionType.REQUIRED,\n }}\n titleHelpPopoverProps={{\n markdownText: ENTITY_FINDER_POPOVER,\n helpUrl: 'https://help.synapse.org/docs/Datasets.2611281979.html',\n placement: 'right',\n }}\n promptCopy={ENTITY_FINDER_PROMPT}\n show={showEntityFinder}\n title={ADD_ITEMS_TO}\n confirmButtonCopy={'Apply changes'}\n onConfirm={items => {\n addItemsToDataset(items)\n setShowEntityFinder(false)\n }}\n onCancel={() => setShowEntityFinder(false)}\n />\n <WarningDialog\n title=\"Unsaved Changes\"\n content=\"Any unsaved changes will be lost. Are you sure you want to close the editor?\"\n confirmButtonText=\"Close Editor\"\n onConfirm={() => {\n if (onClose) {\n setShowWarningDialog(false)\n if (onUnsavedChangesChange) {\n onUnsavedChangesChange(false)\n }\n onClose()\n }\n }}\n open={showWarningDialog}\n onConfirmCallbackArgs={[]}\n onCancel={() => setShowWarningDialog(false)}\n />\n\n <div className=\"DatasetEditorTopBottomPanel\">\n <BlockingLoader show={updateIsPending} />\n <div className=\"ItemCount\">\n {datasetToUpdate ? (\n <Typography variant=\"headline3\">\n {datasetToUpdate.items.length === 0\n ? 'No'\n : datasetToUpdate.items.length.toLocaleString()}{' '}\n File\n {datasetToUpdate.items.length !== 1 && 's'}\n </Typography>\n ) : (\n <Skeleton variant=\"rectangular\" width={200} />\n )}\n </div>\n\n <Button\n variant=\"contained\"\n color=\"primary\"\n disabled={datasetToUpdate == null}\n onClick={() => setShowEntityFinder(true)}\n >\n {ADD_ITEMS}\n </Button>\n <Button\n disabled={selectedIds.size === 0}\n variant=\"outlined\"\n color=\"primary\"\n onClick={removeSelectedItemsFromDataset}\n >\n {REMOVE_ITEMS}\n </Button>\n </div>\n <div className=\"DatasetEditorTableContainer\">\n {datasetToUpdate && datasetToUpdate.items.length === 0 && (\n <NoItemsPlaceholder\n titleCopy={NO_ITEMS_IN_THIS_DATASET}\n buttonCopy={ADD_ITEMS}\n onButtonClick={() => setShowEntityFinder(true)}\n />\n )}\n {datasetToUpdate && datasetToUpdate.items.length > 0 && (\n <StyledVirtualTanStackTable<DatasetItemsEditorTableData>\n styledTableContainerProps={{\n className: 'DatasetEditorTable',\n ref: tableContainerRef,\n height: '350px',\n }}\n table={table}\n rowVirtualizer={rowVirtualizer}\n slotProps={{\n Tr: {\n className: `DatasetEditorRow`,\n style: {\n height: `${ROW_HEIGHT}px`,\n maxHeight: `${ROW_HEIGHT}px`,\n },\n },\n }}\n />\n )}\n {!datasetToUpdate && (\n <SkeletonTable\n className=\"DatasetItemsEditorSkeleton\"\n numRows={8}\n numCols={6}\n rowHeight={`${ROW_HEIGHT}px`}\n />\n )}\n </div>\n <div className=\"DatasetEditorTopBottomPanel\">\n {hasChangedSinceLastSave && (\n <Alert severity=\"warning\">You have unsaved changes</Alert>\n )}\n <Button\n variant=\"outlined\"\n color=\"primary\"\n onClick={() => {\n if (hasChangedSinceLastSave) {\n setShowWarningDialog(true)\n } else if (onClose) {\n onClose()\n }\n }}\n >\n Cancel\n </Button>\n\n <Tooltip title={!hasChangedSinceLastSave && NO_CHANGES_MADE}>\n <div>\n <Button\n disabled={!datasetToUpdate || !hasChangedSinceLastSave}\n variant=\"contained\"\n color=\"primary\"\n onClick={() => mutate(datasetToUpdate!)}\n >\n Save\n </Button>\n </div>\n </Tooltip>\n </div>\n </div>\n )\n}\n\nexport default DatasetItemsEditor\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DatasetItemsEditor.js","names":[],"sources":["../../../../src/components/SynapseTable/datasets/DatasetItemsEditor.tsx"],"sourcesContent":["import React from 'react'\nimport WideButton from '@/components/styled/WideButton'\nimport { datasetItemToReference } from '@/components/SynapseTable/datasets/DatasetEditorUtils'\nimport {\n useGetEntity,\n useGetEntityPath,\n useUpdateEntity,\n} from '@/synapse-queries'\nimport { RequiredProperties } from '@/utils'\nimport {\n convertToEntityType,\n entityTypeToFriendlyName,\n isDataset,\n isDatasetCollection,\n} from '@/utils/functions/EntityTypeUtils'\nimport { useSet } from '@/utils/hooks'\nimport AddCircleTwoToneIcon from '@mui/icons-material/AddCircleTwoTone'\nimport {\n Alert,\n Button,\n Checkbox,\n Skeleton,\n Tooltip,\n Typography,\n} from '@mui/material'\nimport { EntityType } from '@sage-bionetworks/synapse-client'\nimport {\n EntityRef,\n EntityRefCollectionView,\n Reference,\n} from '@sage-bionetworks/synapse-types'\nimport {\n createColumnHelper,\n getCoreRowModel,\n Table,\n useReactTable,\n} from '@tanstack/react-table'\nimport { useVirtualizer } from '@tanstack/react-virtual'\nimport { isEqual, upperFirst } from 'lodash-es'\nimport pluralize from 'pluralize'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport { CreatedOnCell } from '../../EntityFinder/details/view/table/CreatedOnCell'\nimport { EntityBadgeIconsCell } from '../../EntityFinder/details/view/table/EntityBadgeIconsCell'\nimport { EntityNameCell } from '../../EntityFinder/details/view/table/EntityNameCell'\nimport { ModifiedByCell } from '../../EntityFinder/details/view/table/ModifiedByCell'\nimport { ModifiedOnCell } from '../../EntityFinder/details/view/table/ModifiedOnCell'\nimport { ParentProjectCell } from '../../EntityFinder/details/view/table/ParentProjectCell'\nimport { EntityFinderModal } from '../../EntityFinder/EntityFinderModal'\nimport { FinderScope } from '../../EntityFinder/tree/EntityTree'\nimport { VersionSelectionType } from '../../EntityFinder/VersionSelectionType'\nimport { BlockingLoader } from '../../LoadingScreen/LoadingScreen'\nimport { SkeletonTable } from '../../Skeleton'\nimport WarningDialog from '../../SynapseForm/WarningDialog'\nimport ColumnHeader from '../../TanStackTable/ColumnHeader'\nimport StyledVirtualTanStackTable from '../../TanStackTable/StyledVirtualTanStackTable'\nimport { displayToast } from '../../ToastMessage'\nimport { DatasetEditorCheckboxCell } from './DatasetEditorCheckboxCell'\nimport { DatasetEditorVersionCell } from './DatasetEditorVersionCell'\nimport { EntityFetchErrorCell } from './EntityFetchErrorCell'\n\nexport type DatasetItemsEditorTableData = EntityRef & {\n isSelected: boolean\n setSelected: (value: boolean) => void\n}\n\nenum DatasetItemsEditorColumn {\n ERROR_STATE = 'errorState',\n SELECTED = 'isSelected',\n NAME = 'name',\n ENTITY_ID = 'entityId',\n BADGES = 'badges',\n VERSION = 'version',\n CREATED_ON = 'createdOn',\n MODIFIED_ON = 'modifieddOn',\n MODIFIED_BY = 'modifiedBy',\n PROJECT = 'project',\n}\n\nconst columnHelper = createColumnHelper<DatasetItemsEditorTableData>()\nfunction getColumns(\n opts: SelectAllCheckboxRendererProps & {\n changeVersionOnItem: (entityId: string, newVersion: number) => void\n },\n) {\n const {\n datasetToUpdate,\n selectedIds,\n clearSelectedIds,\n addSelectedId,\n allItemsAreSelected,\n changeVersionOnItem,\n } = opts\n return [\n columnHelper.display({\n id: DatasetItemsEditorColumn.ERROR_STATE,\n minSize: 35,\n maxSize: 35,\n size: 35,\n enableResizing: false,\n header: () => null,\n cell: EntityFetchErrorCell,\n }),\n columnHelper.display({\n id: DatasetItemsEditorColumn.SELECTED,\n minSize: 40,\n maxSize: 40,\n size: 40,\n enableResizing: false,\n header: () => (\n <SelectAllCheckboxRenderer\n datasetToUpdate={datasetToUpdate}\n selectedIds={selectedIds}\n clearSelectedIds={clearSelectedIds}\n addSelectedId={addSelectedId}\n allItemsAreSelected={allItemsAreSelected}\n />\n ),\n cell: DatasetEditorCheckboxCell,\n }),\n columnHelper.display({\n id: DatasetItemsEditorColumn.NAME,\n minSize: 50,\n size: 300,\n header: props => <ColumnHeader {...props} title={'Name'} />,\n cell: EntityNameCell,\n }),\n columnHelper.accessor(DatasetItemsEditorColumn.ENTITY_ID, {\n minSize: 50,\n size: 130,\n header: props => <ColumnHeader {...props} title={'ID'} />,\n enableColumnFilter: false,\n }),\n columnHelper.display({\n id: DatasetItemsEditorColumn.BADGES,\n minSize: 80,\n size: 80,\n enableResizing: true,\n cell: EntityBadgeIconsCell,\n }),\n columnHelper.display({\n id: DatasetItemsEditorColumn.VERSION,\n minSize: 150,\n size: 150,\n header: props => <ColumnHeader {...props} title={'Version'} />,\n cell: props => (\n <DatasetEditorVersionCell\n {...props}\n toggleSelection={datasetItem => {\n changeVersionOnItem(datasetItem.entityId, datasetItem.versionNumber)\n }}\n />\n ),\n }),\n columnHelper.display({\n id: DatasetItemsEditorColumn.CREATED_ON,\n header: props => <ColumnHeader {...props} title={'Created On'} />,\n size: 220,\n minSize: 170,\n cell: CreatedOnCell,\n }),\n columnHelper.display({\n id: DatasetItemsEditorColumn.MODIFIED_ON,\n header: props => <ColumnHeader {...props} title={'Modified On'} />,\n size: 220,\n minSize: 170,\n cell: ModifiedOnCell,\n }),\n columnHelper.display({\n id: DatasetItemsEditorColumn.MODIFIED_BY,\n header: props => <ColumnHeader {...props} title={'Modified By'} />,\n size: 250,\n enableResizing: true,\n cell: ModifiedByCell,\n }),\n columnHelper.display({\n id: DatasetItemsEditorColumn.PROJECT,\n header: props => <ColumnHeader {...props} title={'Size'} />,\n size: 300,\n cell: ParentProjectCell,\n }),\n ]\n}\n\nfunction getSelectableTypes(entity: EntityRefCollectionView) {\n if (isDataset(entity)) {\n return [EntityType.file]\n } else if (isDatasetCollection(entity)) {\n return [EntityType.dataset]\n } else {\n console.error(\n 'Cannot determine selectable types for entity type: ' +\n entity.concreteType,\n )\n return []\n }\n}\n\nexport function getCopy(entity?: EntityRefCollectionView) {\n const displayName = entity\n ? entityTypeToFriendlyName(convertToEntityType(entity.concreteType))\n : 'Collection'\n let itemName = 'Item'\n let currentVersionName = 'Current Version'\n if (entity && isDataset(entity)) {\n itemName = entityTypeToFriendlyName(EntityType.file)\n currentVersionName = 'Draft'\n } else if (entity && isDatasetCollection(entity)) {\n itemName = entityTypeToFriendlyName(EntityType.dataset)\n }\n\n const entityFinderPopover =\n entity && isDataset(entity)\n ? `Use the left pane to browse projects and folders. Select ${pluralize(\n itemName,\n )} from the right pane to add to this ${displayName}. ${upperFirst(\n pluralize(itemName),\n )} in a ${displayName} can be added from multiple folders. You can also use Search to find and select ${pluralize(\n itemName,\n )}.`\n : `Use the left pane to browse projects. Select ${pluralize(\n itemName,\n )} from the right pane to add to this ${displayName}. ${upperFirst(\n pluralize(itemName),\n )} in a ${displayName} can be added from multiple projects. You can also use Search to find and select ${pluralize(\n itemName,\n )}.`\n\n return {\n ADD_ITEMS: `Add ${pluralize(itemName)}`,\n ADD_ITEMS_TO: `Add ${pluralize(itemName)} to ${displayName}`,\n REMOVE_ITEMS: `Remove ${pluralize(itemName)}`,\n NO_ITEMS_IN_THIS_DATASET: `No ${pluralize(\n itemName,\n )} in this ${displayName}`,\n SAVE_TO_CONTINUE: `Save the ${displayName} to continue`,\n CREATE_VERSION_TO_FREEZE: `Create a Version of this ${displayName} to freeze it in its current state`,\n ENTITY_SAVED: `${displayName} Saved`,\n SAVE_CHANGES: `Save changes to ${currentVersionName}`,\n ENTITY_FINDER_POPOVER: entityFinderPopover,\n ENTITY_FINDER_PROMPT: `Find ${pluralize(\n itemName,\n )} to add to the ${displayName}.`,\n PRECONDITION_FAILED_MESSAGE: `Re-retrieve the ${displayName} to get the latest changes. Your current changes will be lost.`,\n PRECONDITION_FAILED_TITLE: `${displayName} updated since last fetched`,\n PRECONDITION_FAILED_ACTION: `Retrieve ${displayName}`,\n NO_CHANGES_MADE: `You have not made any changes to the ${displayName}.`,\n }\n}\n\nfunction getDataSetDifference(\n oldDataSet: EntityRef[],\n changedItems: EntityRef[],\n) {\n const unchangedItems = oldDataSet.filter(\n oldItem =>\n !changedItems.find(newItem => newItem.entityId === oldItem.entityId),\n )\n const deletedItems = [...unchangedItems]\n const { updatedItems, newItems } = changedItems.reduce(\n (results, result) => {\n const oldItem = oldDataSet.find(old => old.entityId === result.entityId)\n if (oldItem) {\n if (result.versionNumber !== oldItem.versionNumber) {\n results['updatedItems'].push(result)\n } else {\n unchangedItems.push(result)\n }\n } else {\n results['newItems'].push(result)\n }\n return results\n },\n { updatedItems: [], newItems: [] } as {\n updatedItems: EntityRef[]\n newItems: EntityRef[]\n },\n )\n\n return { unchangedItems, updatedItems, newItems, deletedItems }\n}\n\nfunction getDatasetChangedToastMessageTitle(\n previousDatasetToUpdate?: RequiredProperties<\n EntityRefCollectionView,\n 'items'\n >,\n datasetToUpdate?: RequiredProperties<EntityRefCollectionView, 'items'>,\n) {\n const { updatedItems, newItems, deletedItems } = getDataSetDifference(\n previousDatasetToUpdate?.items ?? [],\n datasetToUpdate?.items!,\n )\n let toastTitle = ''\n\n // \"X items(s) deleted\"\n if (deletedItems.length > 0) {\n toastTitle += `${deletedItems.length} Item${\n deletedItems.length === 1 ? '' : 's'\n } removed`\n } else {\n // \"Y item(s) added\"\n toastTitle += `${newItems.length} Item${\n newItems.length === 1 ? '' : 's'\n } added`\n\n // \"and Z item(s) updated\", only shown if there are updated items\n if (updatedItems.length > 0) {\n toastTitle += ` and ${updatedItems.length} Item${\n updatedItems.length === 1 ? '' : 's'\n } updated`\n }\n }\n return toastTitle\n}\n\nexport type DatasetItemsEditorProps = {\n /* The synId of the EntityRefCollectionView to modify */\n entityId: string\n /** Callback invoked when the editor changes state to contain un/saved changes. */\n onUnsavedChangesChange?: (hasUnsavedChanges: boolean) => void\n onSave?: () => void\n onClose?: () => void\n}\n\nconst ROW_HEIGHT = 48\n\ntype SelectAllCheckboxRendererProps = {\n datasetToUpdate: RequiredProperties<EntityRefCollectionView, 'items'>\n selectedIds: Omit<Set<string>, 'add' | 'delete' | 'clear'>\n addSelectedId: (...items: string[]) => void\n clearSelectedIds: () => void\n allItemsAreSelected: boolean\n}\n\nconst SelectAllCheckboxRenderer = (\n props: SelectAllCheckboxRendererProps,\n): React.ReactNode => {\n const {\n datasetToUpdate,\n clearSelectedIds,\n allItemsAreSelected,\n addSelectedId,\n } = props\n const isChecked = allItemsAreSelected\n\n return (\n <Checkbox\n inputProps={{ 'aria-label': 'Select All' }}\n checked={isChecked}\n disabled={datasetToUpdate.items.length === 0}\n onChange={() => {\n if (isChecked) {\n clearSelectedIds()\n } else {\n addSelectedId(...datasetToUpdate.items.map(item => item.entityId))\n }\n }}\n />\n )\n}\n\nfunction NoItemsPlaceholder(props: {\n titleCopy: string\n buttonCopy: string\n onButtonClick: () => void\n}) {\n const { titleCopy, buttonCopy, onButtonClick } = props\n return (\n <div className=\"NoItemsPlaceholder\">\n <Typography variant={'headline3'}>{titleCopy}</Typography>\n <WideButton\n variant=\"contained\"\n color=\"primary\"\n onClick={onButtonClick}\n startIcon={<AddCircleTwoToneIcon />}\n sx={{ mt: 2 }}\n >\n {buttonCopy}\n </WideButton>\n </div>\n )\n}\n\nexport function DatasetItemsEditor(props: DatasetItemsEditorProps) {\n const { entityId, onSave, onClose, onUnsavedChangesChange } = props\n const [showEntityFinder, setShowEntityFinder] = useState<boolean>(false)\n const [showWarningDialog, setShowWarningDialog] = useState<boolean>(false)\n\n // The current 'client state' of dataset that the user is currently editing. Updates to this state are not saved until the user clicks 'Save'.\n const [datasetToUpdate, setDatasetToUpdate] =\n useState<RequiredProperties<EntityRefCollectionView, 'items'>>()\n\n // The previous value of the datasetToUpdate variable. This is used to calculate a summary of bulk actions since the last update to the unsaved dataset state.\n const [previousDatasetToUpdate, setPreviousDatasetToUpdate] =\n useState<RequiredProperties<EntityRefCollectionView, 'items'>>()\n\n // Stores the `close` function that will be used to hide the last toast that prompted the user to save\n const [onCloseLastSavePromptToast, setOnCloseLastSavePromptToast] = useState<\n { close: () => void } | undefined\n >()\n\n const { data: datasetOnServer, refetch: refetchDataset } = useGetEntity<\n RequiredProperties<EntityRefCollectionView, 'items'>\n >(entityId, undefined, {\n staleTime: Infinity,\n })\n\n const hasChangedSinceLastSave = Boolean(\n datasetOnServer &&\n datasetToUpdate &&\n !isEqual(datasetOnServer, datasetToUpdate),\n )\n\n const {\n ADD_ITEMS,\n ADD_ITEMS_TO,\n REMOVE_ITEMS,\n NO_ITEMS_IN_THIS_DATASET,\n SAVE_TO_CONTINUE,\n CREATE_VERSION_TO_FREEZE,\n ENTITY_SAVED,\n SAVE_CHANGES,\n PRECONDITION_FAILED_TITLE,\n PRECONDITION_FAILED_MESSAGE,\n PRECONDITION_FAILED_ACTION,\n ENTITY_FINDER_POPOVER,\n ENTITY_FINDER_PROMPT,\n NO_CHANGES_MADE,\n } = useMemo(() => getCopy(datasetOnServer), [datasetOnServer])\n\n useEffect(() => {\n if (datasetOnServer) {\n // SWC-5876: Dataset Items may be undefined. This has the same inherent meaning as the empty list, so we'll just change it to save us some null checks.\n if (datasetOnServer.items == null) {\n datasetOnServer.items = []\n }\n setDatasetToUpdate(datasetOnServer)\n }\n }, [datasetOnServer])\n\n const {\n set: selectedIds,\n add: addSelectedId,\n remove: removeSelectedId,\n clear: clearSelectedIds,\n } = useSet<string>()\n const allItemsAreSelected = Boolean(\n datasetToUpdate && datasetToUpdate.items.length === selectedIds.size,\n )\n\n useEffect(() => {\n if (datasetToUpdate && datasetOnServer && onUnsavedChangesChange) {\n onUnsavedChangesChange(hasChangedSinceLastSave)\n }\n }, [\n datasetOnServer,\n datasetToUpdate,\n hasChangedSinceLastSave,\n onUnsavedChangesChange,\n ])\n\n // We get the project ID to show the \"Current Project\" context in the Entity Finder.\n const { data: path } = useGetEntityPath(entityId)\n const projectId = path?.path[1]?.id\n\n const { mutate, isPending: updateIsPending } =\n useUpdateEntity<EntityRefCollectionView>({\n onMutate: () => {\n // Close existing toast that prompted the user to save\n if (onCloseLastSavePromptToast) {\n onCloseLastSavePromptToast.close()\n setOnCloseLastSavePromptToast(undefined)\n }\n },\n onSuccess: () => {\n // The query should automatically be invalidated, but just in case\n void refetchDataset()\n\n if (onSave) {\n onSave()\n } else {\n // If onSave isn't specified, push a generic toast message.\n displayToast(CREATE_VERSION_TO_FREEZE, 'success', {\n title: ENTITY_SAVED,\n })\n }\n },\n onError: error => {\n if (error.status === 412) {\n displayToast(PRECONDITION_FAILED_MESSAGE, 'warning', {\n title: PRECONDITION_FAILED_TITLE,\n primaryButtonConfig: {\n text: PRECONDITION_FAILED_ACTION,\n onClick: () => {\n void refetchDataset()\n },\n },\n })\n } else {\n displayToast(error.reason, 'danger', {\n title: 'An Error Occurred',\n })\n }\n },\n })\n\n useEffect(() => {\n // When changes are made (but not saved) to the datasetToUpdate, show a notification that summarizes the change and prompts the user to save\n if (\n previousDatasetToUpdate &&\n datasetToUpdate &&\n !isEqual(previousDatasetToUpdate.items, datasetToUpdate.items) &&\n !updateIsPending\n ) {\n const toastMessageTitle = getDatasetChangedToastMessageTitle(\n previousDatasetToUpdate,\n datasetToUpdate,\n )\n // Replace existing toast that prompts the user to save before showing the new one\n if (onCloseLastSavePromptToast) {\n onCloseLastSavePromptToast.close()\n }\n const onCloseToast = displayToast(SAVE_TO_CONTINUE, 'info', {\n title: toastMessageTitle,\n primaryButtonConfig: {\n text: SAVE_CHANGES,\n onClick: () => mutate(datasetToUpdate),\n },\n })\n setOnCloseLastSavePromptToast({ close: onCloseToast })\n }\n setPreviousDatasetToUpdate(datasetToUpdate)\n // Only run when datasetToUpdate changes\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [datasetToUpdate])\n\n const tableData = useMemo(\n () =>\n datasetToUpdate?.items.map(\n (item: EntityRef): DatasetItemsEditorTableData => {\n return {\n ...item,\n isSelected: selectedIds.has(item.entityId),\n setSelected: (value: boolean) => {\n return value\n ? addSelectedId(item.entityId)\n : removeSelectedId(item.entityId)\n },\n }\n },\n ) ?? [],\n [addSelectedId, datasetToUpdate?.items, removeSelectedId, selectedIds],\n )\n\n function addItemsToDataset(itemsToAdd: Reference[]) {\n setDatasetToUpdate(datasetToUpdate => {\n if (datasetToUpdate) {\n const refToDatasetItem = itemsToAdd.map(item => ({\n entityId: item.targetId,\n versionNumber: item.targetVersionNumber!,\n }))\n const { unchangedItems, updatedItems, newItems } = getDataSetDifference(\n datasetToUpdate.items,\n refToDatasetItem,\n )\n\n if (updatedItems.length == 0 && newItems.length == 0) {\n // No items were added or updated, so don't update the state variable.\n return datasetToUpdate\n }\n\n const items = [...unchangedItems, ...updatedItems, ...newItems]\n\n return {\n ...datasetToUpdate,\n items: items,\n }\n } else {\n console.warn(\n 'Cannot add items to the Collection because it is undefined. The Collection may not have been fetched yet.',\n )\n return datasetToUpdate\n }\n })\n clearSelectedIds()\n }\n\n function removeSelectedItemsFromDataset() {\n setDatasetToUpdate(dataset => ({\n ...dataset!,\n items: dataset!.items.filter(\n datasetItem => !selectedIds.has(datasetItem.entityId),\n ),\n }))\n clearSelectedIds()\n }\n\n function changeVersionOnItem(entityId: string, newVersion: number) {\n setDatasetToUpdate(dataset => ({\n ...dataset!,\n items: dataset!.items.map(datasetItem =>\n datasetItem.entityId === entityId\n ? { entityId: entityId, versionNumber: newVersion }\n : datasetItem,\n ),\n }))\n }\n\n const selectableTypes: EntityType[] | undefined = useMemo(() => {\n if (datasetOnServer) {\n return getSelectableTypes(datasetOnServer)\n } else {\n return undefined\n }\n }, [datasetOnServer])\n\n const columns = useMemo(() => {\n if (!datasetToUpdate) {\n return []\n }\n return getColumns({\n datasetToUpdate,\n selectedIds,\n clearSelectedIds,\n addSelectedId,\n allItemsAreSelected,\n changeVersionOnItem,\n })\n }, [\n addSelectedId,\n allItemsAreSelected,\n clearSelectedIds,\n datasetToUpdate,\n selectedIds,\n ])\n\n const table: Table<DatasetItemsEditorTableData> =\n useReactTable<DatasetItemsEditorTableData>({\n data: tableData,\n columns,\n getCoreRowModel: getCoreRowModel(),\n columnResizeMode: 'onChange',\n // There are no backend sort controls. The server only provides ID/version, and a dataset could be up to 10k items,\n // so client side sorting is non-trivial. We may consider fetching all entity headers upon user request.\n enableSorting: false,\n })\n\n const tableContainerRef = useRef<HTMLDivElement>(null)\n\n const rowVirtualizer = useVirtualizer({\n count: tableData?.length ?? 0,\n estimateSize: () => ROW_HEIGHT, // estimate row height for accurate scrollbar dragging\n getScrollElement: () => tableContainerRef.current,\n // measure dynamic row height, except in firefox because it measures table border height incorrectly\n measureElement:\n typeof window !== 'undefined' &&\n navigator.userAgent.indexOf('Firefox') === -1\n ? element => element?.getBoundingClientRect().height\n : undefined,\n overscan: 5,\n })\n\n const datasetItemsAsEntityFinderRef = useMemo(\n () => datasetToUpdate?.items.map(datasetItemToReference),\n [datasetToUpdate],\n )\n\n return (\n <div className=\"DatasetEditor\">\n <EntityFinderModal\n initialSelected={datasetItemsAsEntityFinderRef}\n configuration={{\n projectId: projectId,\n selectMultiple: true,\n initialScope: FinderScope.CURRENT_PROJECT,\n initialContainer: projectId ?? null,\n selectableTypes: selectableTypes,\n versionSelection: VersionSelectionType.REQUIRED,\n }}\n titleHelpPopoverProps={{\n markdownText: ENTITY_FINDER_POPOVER,\n helpUrl: 'https://help.synapse.org/docs/Datasets.2611281979.html',\n placement: 'right',\n }}\n promptCopy={ENTITY_FINDER_PROMPT}\n show={showEntityFinder}\n title={ADD_ITEMS_TO}\n confirmButtonCopy={'Apply changes'}\n onConfirm={items => {\n addItemsToDataset(items)\n setShowEntityFinder(false)\n }}\n onCancel={() => setShowEntityFinder(false)}\n />\n <WarningDialog\n title=\"Unsaved Changes\"\n content=\"Any unsaved changes will be lost. Are you sure you want to close the editor?\"\n confirmButtonText=\"Close Editor\"\n onConfirm={() => {\n if (onClose) {\n setShowWarningDialog(false)\n if (onUnsavedChangesChange) {\n onUnsavedChangesChange(false)\n }\n onClose()\n }\n }}\n open={showWarningDialog}\n onConfirmCallbackArgs={[]}\n onCancel={() => setShowWarningDialog(false)}\n />\n\n <div className=\"DatasetEditorTopBottomPanel\">\n <BlockingLoader show={updateIsPending} />\n <div className=\"ItemCount\">\n {datasetToUpdate ? (\n <Typography variant=\"headline3\">\n {datasetToUpdate.items.length === 0\n ? 'No'\n : datasetToUpdate.items.length.toLocaleString()}{' '}\n File\n {datasetToUpdate.items.length !== 1 && 's'}\n </Typography>\n ) : (\n <Skeleton variant=\"rectangular\" width={200} />\n )}\n </div>\n\n <Button\n variant=\"contained\"\n color=\"primary\"\n disabled={datasetToUpdate == null}\n onClick={() => setShowEntityFinder(true)}\n >\n {ADD_ITEMS}\n </Button>\n <Button\n disabled={selectedIds.size === 0}\n variant=\"outlined\"\n color=\"primary\"\n onClick={removeSelectedItemsFromDataset}\n >\n {REMOVE_ITEMS}\n </Button>\n </div>\n <div className=\"DatasetEditorTableContainer\">\n {datasetToUpdate && datasetToUpdate.items.length === 0 && (\n <NoItemsPlaceholder\n titleCopy={NO_ITEMS_IN_THIS_DATASET}\n buttonCopy={ADD_ITEMS}\n onButtonClick={() => setShowEntityFinder(true)}\n />\n )}\n {datasetToUpdate && datasetToUpdate.items.length > 0 && (\n <StyledVirtualTanStackTable<DatasetItemsEditorTableData>\n styledTableContainerProps={{\n className: 'DatasetEditorTable',\n ref: tableContainerRef,\n height: '350px',\n }}\n table={table}\n rowVirtualizer={rowVirtualizer}\n slotProps={{\n Tr: {\n className: `DatasetEditorRow`,\n style: {\n height: `${ROW_HEIGHT}px`,\n maxHeight: `${ROW_HEIGHT}px`,\n },\n },\n }}\n />\n )}\n {!datasetToUpdate && (\n <SkeletonTable\n className=\"DatasetItemsEditorSkeleton\"\n numRows={8}\n numCols={6}\n rowHeight={`${ROW_HEIGHT}px`}\n />\n )}\n </div>\n <div className=\"DatasetEditorTopBottomPanel\">\n {hasChangedSinceLastSave && (\n <Alert severity=\"warning\">You have unsaved changes</Alert>\n )}\n <Button\n variant=\"outlined\"\n color=\"primary\"\n onClick={() => {\n if (hasChangedSinceLastSave) {\n setShowWarningDialog(true)\n } else if (onClose) {\n onClose()\n }\n }}\n >\n Cancel\n </Button>\n\n <Tooltip title={!hasChangedSinceLastSave && NO_CHANGES_MADE}>\n <div>\n <Button\n disabled={!datasetToUpdate || !hasChangedSinceLastSave}\n variant=\"contained\"\n color=\"primary\"\n onClick={() => mutate(datasetToUpdate!)}\n >\n Save\n </Button>\n </div>\n </Tooltip>\n </div>\n </div>\n )\n}\n\nexport default DatasetItemsEditor\n"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { convertToConcreteEntityType as e } from "../../utils/functions/EntityTypeUtils.js";
|
|
2
2
|
import { canHaveDefault as t, canHaveMaxListLength as n, canHaveRestrictedValues as ee, canHaveSize as r, configureFacetsForType as te, getAllowedColumnTypes as i, getColumnTypeFriendlyName as a, getFacetTypeFriendlyName as o, getMaxSizeForType as s } from "./TableColumnSchemaEditorUtils.js";
|
|
3
|
-
import
|
|
4
|
-
import l from "./ColumnModelFormFields/
|
|
5
|
-
import u from "./ColumnModelFormFields/
|
|
6
|
-
import {
|
|
3
|
+
import c from "./ColumnModelFormFields/MultiValueField.js";
|
|
4
|
+
import l from "./ColumnModelFormFields/DefaultValueField.js";
|
|
5
|
+
import { FieldWithRecommendedMinimum as u } from "./ColumnModelFormFields/FieldWithRecommendedMinimum.js";
|
|
6
|
+
import { tableColumnSchemaFormDataAtom as d } from "./TableColumnSchemaFormReducer.js";
|
|
7
7
|
import { HIERARCHY_VERTICAL_LINE_COMPONENT as f } from "./TableColumnSchemaForm.js";
|
|
8
8
|
import { useMemo as p } from "react";
|
|
9
9
|
import { isArray as m, isEmpty as h, isEqual as g } from "lodash-es";
|
|
@@ -38,7 +38,7 @@ function I(e) {
|
|
|
38
38
|
}
|
|
39
39
|
var L = !0;
|
|
40
40
|
function R(R) {
|
|
41
|
-
let { columnModelIndex: z, jsonSubColumnIndex: B, entityType: V, isDefaultColumn: H, disabled: U = !1, validationErrors: W = null, defaultAnnotationModel: G, originalColumnModel: K } = R, q = B != null, J = A(
|
|
41
|
+
let { columnModelIndex: z, jsonSubColumnIndex: B, entityType: V, isDefaultColumn: H, disabled: U = !1, validationErrors: W = null, defaultAnnotationModel: G, originalColumnModel: K } = R, q = B != null, J = A(d), Y = O.includes(e(V)), X = k(p(() => ne(d, (e) => q ? e[z].jsonSubColumns[B] : e[z], g), [
|
|
42
42
|
z,
|
|
43
43
|
q,
|
|
44
44
|
B
|
|
@@ -144,7 +144,7 @@ function R(R) {
|
|
|
144
144
|
}),
|
|
145
145
|
/* @__PURE__ */ E(_, {
|
|
146
146
|
sx: { my: H ? "auto" : void 0 },
|
|
147
|
-
children: H ? X.maximumSize ?? "" : /* @__PURE__ */ E(
|
|
147
|
+
children: H ? X.maximumSize ?? "" : /* @__PURE__ */ E(u, {
|
|
148
148
|
value: X.maximumSize ?? "",
|
|
149
149
|
originalValue: K?.maximumSize,
|
|
150
150
|
recommendedValue: G?.maximumSize,
|
|
@@ -177,7 +177,7 @@ function R(R) {
|
|
|
177
177
|
}),
|
|
178
178
|
/* @__PURE__ */ E(_, {
|
|
179
179
|
sx: { my: H ? "auto" : void 0 },
|
|
180
|
-
children: H ? X.maximumListLength ?? "" : /* @__PURE__ */ E(
|
|
180
|
+
children: H ? X.maximumListLength ?? "" : /* @__PURE__ */ E(u, {
|
|
181
181
|
value: X.maximumListLength ?? "",
|
|
182
182
|
originalValue: K?.maximumListLength,
|
|
183
183
|
recommendedValue: G?.maximumListLength,
|
|
@@ -206,7 +206,7 @@ function R(R) {
|
|
|
206
206
|
}),
|
|
207
207
|
/* @__PURE__ */ E(_, {
|
|
208
208
|
sx: { my: H ? "auto" : void 0 },
|
|
209
|
-
children: H ? P(X?.defaultValue, X.columnType) : /* @__PURE__ */ E(
|
|
209
|
+
children: H ? P(X?.defaultValue, X.columnType) : /* @__PURE__ */ E(l, {
|
|
210
210
|
TextFieldProps: {
|
|
211
211
|
InputProps: {
|
|
212
212
|
disableInjectingGlobalStyles: L,
|
|
@@ -240,7 +240,7 @@ function R(R) {
|
|
|
240
240
|
disabled: U || !t(X.columnType, Y, q)
|
|
241
241
|
})
|
|
242
242
|
}),
|
|
243
|
-
/* @__PURE__ */ E(_, { children: /* @__PURE__ */ E(
|
|
243
|
+
/* @__PURE__ */ E(_, { children: /* @__PURE__ */ E(c, {
|
|
244
244
|
value: X?.enumValues,
|
|
245
245
|
onChange: (e) => {
|
|
246
246
|
J({
|