synapse-react-client 4.0.9 → 4.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/SWC.index.d.ts +1 -0
- package/dist/SWC.index.d.ts.map +1 -1
- package/dist/SWC.index.js +2 -1
- package/dist/SWC.index.js.map +1 -1
- package/dist/aridhia-queries/aridhiaTokenExchange.js.map +1 -1
- package/dist/aridhia-queries/useGetAridhiaRequests.js.map +1 -1
- package/dist/assets/icons/TasksIcon.d.ts.map +1 -1
- package/dist/assets/icons/TasksIcon.js +6 -10
- package/dist/assets/icons/TasksIcon.js.map +1 -1
- package/dist/components/AccessRequirementAclEditor/AccessRequirementAclEditor.d.ts.map +1 -1
- package/dist/components/AccessRequirementAclEditor/AccessRequirementAclEditor.js +69 -63
- package/dist/components/AccessRequirementAclEditor/AccessRequirementAclEditor.js.map +1 -1
- package/dist/components/AccessRequirementList/AccessApprovalCheckMark.js.map +1 -1
- package/dist/components/AccessRequirementList/AccessRequirementList.js.map +1 -1
- package/dist/components/AccessRequirementList/AccessRequirementListUtils.js.map +1 -1
- package/dist/components/AccessRequirementList/ManagedACTAccessRequirementRequestFlow/DataAccessRequestAccessorsEditor.js.map +1 -1
- package/dist/components/AccessRequirementList/RequirementItem/SelfSignAccessRequirementItem.js.map +1 -1
- package/dist/components/AccessRequirementRelatedProjectsList/AccessRequirementRelatedProjectsList.js.map +1 -1
- package/dist/components/AccessTokenPage/AccessTokenCard/AccessTokenCard.js.map +1 -1
- package/dist/components/AcknowledgementsPage/StudyAcknowledgements.js.map +1 -1
- package/dist/components/AclEditor/PermissionLevelMenu.js.map +1 -1
- package/dist/components/AclEditor/ResourceAccessAndUserGroupHeader.js.map +1 -1
- package/dist/components/AclEditor/useSortResourceAccessList.js.map +1 -1
- package/dist/components/AclEditor/useUpdateAcl.js.map +1 -1
- package/dist/components/Aridhia/AridhiaAccessStatus.js.map +1 -1
- package/dist/components/Authentication/AuthenticationMethodSelection.d.ts.map +1 -1
- package/dist/components/Authentication/AuthenticationMethodSelection.js +38 -37
- package/dist/components/Authentication/AuthenticationMethodSelection.js.map +1 -1
- package/dist/components/Authentication/Constants.d.ts +1 -0
- package/dist/components/Authentication/Constants.d.ts.map +1 -1
- package/dist/components/Authentication/Constants.js +2 -2
- package/dist/components/Authentication/Constants.js.map +1 -1
- package/dist/components/Authentication/LastLoginInfo.js.map +1 -1
- package/dist/components/Authentication/RecoveryCodeForm.js.map +1 -1
- package/dist/components/Authentication/RecoveryCodeGrid.js.map +1 -1
- package/dist/components/Authentication/RegenerateBackupCodesWarning.js.map +1 -1
- package/dist/components/Authentication/Reset2FAWarning.js.map +1 -1
- package/dist/components/Authentication/StandaloneLoginForm.js +1 -1
- package/dist/components/Authentication/TwoFactorBackupCodes.js.map +1 -1
- package/dist/components/Authentication/TwoFactorEnrollmentForm.d.ts.map +1 -1
- package/dist/components/Authentication/TwoFactorEnrollmentForm.js +2 -1
- package/dist/components/Authentication/TwoFactorEnrollmentForm.js.map +1 -1
- package/dist/components/BasePortalCard/ColorfulPortalCardWithChips/ColorfulPortalCardWithChips.js.map +1 -1
- package/dist/components/CardContainer/CardContainer.js.map +1 -1
- package/dist/components/CardDeck/CardDeck.Mobile.js.map +1 -1
- package/dist/components/CardDeck/TableQueryCardDeck.js.map +1 -1
- package/dist/components/CertificationQuiz/CertificationQuiz.js.map +1 -1
- package/dist/components/ChallengeDataDownload/ChallengeDataDownload.js.map +1 -1
- package/dist/components/ChallengeSubmission/ChallengeSubmission.js.map +1 -1
- package/dist/components/ChallengeSubmission/ChallengeSubmissionStepper.js.map +1 -1
- package/dist/components/ChallengeSubmission/EvaluationQueueCurrentRoundInfo.js.map +1 -1
- package/dist/components/ChallengeSubmission/EvaluationQueueList.js.map +1 -1
- package/dist/components/ChallengeSubmission/SubmissionDirectoryList.js.map +1 -1
- package/dist/components/ChallengeTeamWizard/ChallengeTeamWizard.js.map +1 -1
- package/dist/components/ChallengeTeamWizard/CreateChallengeTeam.js.map +1 -1
- package/dist/components/ChangePassword/ChangePassword.js.map +1 -1
- package/dist/components/ChangePassword/ChangePasswordWithToken.js.map +1 -1
- package/dist/components/ChangePassword/useChangePasswordFormState.js +1 -1
- package/dist/components/ChangePassword/useChangePasswordFormState.js.map +1 -1
- package/dist/components/CitationPopover/CitationPopoverContent.js.map +1 -1
- package/dist/components/ColumnFilter/ColumnFilter.js.map +1 -1
- package/dist/components/ComponentCollapse.js.map +1 -1
- package/dist/components/CookiesNotification/CookiesNotification.js.map +1 -1
- package/dist/components/CreateProjectModal/CreateProjectModal.js.map +1 -1
- package/dist/components/CreateTableViewWizard/CreateTableViewWizardUtils.js.map +1 -1
- package/dist/components/DataGrid/DataGrid.d.ts +0 -1
- package/dist/components/DataGrid/DataGrid.d.ts.map +1 -1
- package/dist/components/DataGrid/DataGrid.js +72 -72
- package/dist/components/DataGrid/DataGrid.js.map +1 -1
- package/dist/components/DataGrid/DataGridWebSocket.d.ts +4 -0
- package/dist/components/DataGrid/DataGridWebSocket.d.ts.map +1 -1
- package/dist/components/DataGrid/DataGridWebSocket.js +9 -8
- package/dist/components/DataGrid/DataGridWebSocket.js.map +1 -1
- package/dist/components/DataGrid/SynapseGrid.d.ts.map +1 -1
- package/dist/components/DataGrid/SynapseGrid.js +326 -268
- package/dist/components/DataGrid/SynapseGrid.js.map +1 -1
- package/dist/components/DataGrid/columns/AutocompleteColumn.d.ts +2 -0
- package/dist/components/DataGrid/columns/AutocompleteColumn.d.ts.map +1 -1
- package/dist/components/DataGrid/columns/AutocompleteColumn.js +113 -67
- package/dist/components/DataGrid/columns/AutocompleteColumn.js.map +1 -1
- package/dist/components/DataGrid/columns/AutocompleteMultipleEnumColumn.d.ts +2 -1
- package/dist/components/DataGrid/columns/AutocompleteMultipleEnumColumn.d.ts.map +1 -1
- package/dist/components/DataGrid/columns/AutocompleteMultipleEnumColumn.js +126 -122
- package/dist/components/DataGrid/columns/AutocompleteMultipleEnumColumn.js.map +1 -1
- package/dist/components/DataGrid/columns/useGridAutocompleteState.d.ts +58 -0
- package/dist/components/DataGrid/columns/useGridAutocompleteState.d.ts.map +1 -0
- package/dist/components/DataGrid/columns/useGridAutocompleteState.js +52 -0
- package/dist/components/DataGrid/columns/useGridAutocompleteState.js.map +1 -0
- package/dist/components/DataGrid/components/ValidationAlert.d.ts +5 -2
- package/dist/components/DataGrid/components/ValidationAlert.d.ts.map +1 -1
- package/dist/components/DataGrid/components/ValidationAlert.js +429 -24
- package/dist/components/DataGrid/components/ValidationAlert.js.map +1 -1
- package/dist/components/DataGrid/hooks/useColumnResizeHandles.js.map +1 -1
- package/dist/components/DataGrid/hooks/useGetSchemaForGrid.js.map +1 -1
- package/dist/components/DataGrid/hooks/useGridUndoRedo.js.map +1 -1
- package/dist/components/DataGrid/hooks/useStack.js.map +1 -1
- package/dist/components/DataGrid/useCRDTModelView.js.map +1 -1
- package/dist/components/DataGrid/useDataGridWebsocket.d.ts +7 -0
- package/dist/components/DataGrid/useDataGridWebsocket.d.ts.map +1 -1
- package/dist/components/DataGrid/useDataGridWebsocket.js +16 -2
- package/dist/components/DataGrid/useDataGridWebsocket.js.map +1 -1
- package/dist/components/DataGrid/useInitializeGridConnection.js.map +1 -1
- package/dist/components/DataGrid/useMergeGridWithRecordSet.js.map +1 -1
- package/dist/components/DataGrid/useMergeGridWithSource.js.map +1 -1
- package/dist/components/DataGrid/useMergeGridWithTable.js.map +1 -1
- package/dist/components/DataGrid/utils/DataGridUtils.js.map +1 -1
- package/dist/components/DataGrid/utils/applyModelChange.js.map +1 -1
- package/dist/components/DataGrid/utils/columnFactory.js.map +1 -1
- package/dist/components/DataGrid/utils/computeReplicaSelectionModel.js.map +1 -1
- package/dist/components/DataGrid/utils/extractColumnValidationMessages.js.map +1 -1
- package/dist/components/DataGrid/utils/getCellClassName.d.ts.map +1 -1
- package/dist/components/DataGrid/utils/getCellClassName.js +8 -8
- package/dist/components/DataGrid/utils/getCellClassName.js.map +1 -1
- package/dist/components/DataGrid/utils/json-rx/JsonRx.js.map +1 -1
- package/dist/components/DataGrid/utils/modelRowsToGrid.js.map +1 -1
- package/dist/components/DataGrid/utils/parseFreeTextUsingJsonSchemaType.js.map +1 -1
- package/dist/components/DataGrid/utils/splitPatch.js.map +1 -1
- package/dist/components/DateTimePicker/DateTimePicker.js.map +1 -1
- package/dist/components/DirectDownload/DirectDownload.js.map +1 -1
- package/dist/components/DirectDownloadButton.js.map +1 -1
- package/dist/components/DownloadCart/CreatePackageV2.js.map +1 -1
- package/dist/components/DownloadCart/DownloadIneligibleForPackagingFilesFromListButton.js.map +1 -1
- package/dist/components/DownloadCart/DownloadListActionsRequired.js.map +1 -1
- package/dist/components/DownloadCart/DownloadListTable.js.map +1 -1
- package/dist/components/DownloadCart/fileNameUtils.js.map +1 -1
- package/dist/components/DraggableDialog/DraggableDialog.js.map +1 -1
- package/dist/components/DynamicForm/DynamicFormModal.js.map +1 -1
- package/dist/components/Ecosystem/TableQueryEcosystem.js.map +1 -1
- package/dist/components/EntityAclEditor/EntityAclEditor.d.ts.map +1 -1
- package/dist/components/EntityAclEditor/EntityAclEditor.js +103 -103
- package/dist/components/EntityAclEditor/EntityAclEditor.js.map +1 -1
- package/dist/components/EntityAclEditor/useNotifyNewACLUsers.js.map +1 -1
- package/dist/components/EntityBadgeIcons/EntityBadgeIcons.js.map +1 -1
- package/dist/components/EntityCitation/EntityCitation.js.map +1 -1
- package/dist/components/EntityDownloadButton/EntityDownloadButton.js.map +1 -1
- package/dist/components/EntityDownloadConfirmation/EntityDownloadConfirmation.d.ts.map +1 -1
- package/dist/components/EntityDownloadConfirmation/EntityDownloadConfirmation.js +36 -30
- package/dist/components/EntityDownloadConfirmation/EntityDownloadConfirmation.js.map +1 -1
- package/dist/components/EntityFinder/EntityFinder.js.map +1 -1
- package/dist/components/EntityFinder/VersionSelectionType.js.map +1 -1
- package/dist/components/EntityFinder/details/configurations/EntityChildrenDetails.js.map +1 -1
- package/dist/components/EntityFinder/details/configurations/FavoritesDetails.js.map +1 -1
- package/dist/components/EntityFinder/details/configurations/ProjectListDetails.js.map +1 -1
- package/dist/components/EntityFinder/details/view/DetailsView.js.map +1 -1
- package/dist/components/EntityFinder/tree/EntityTree.js.map +1 -1
- package/dist/components/EntityFinder/tree/VirtualizedTree.js.map +1 -1
- package/dist/components/EntityFinder/useEntitySelection.js.map +1 -1
- package/dist/components/EntityForm/EntityForm.js.map +1 -1
- package/dist/components/EntityHeaderTable/EntityHeaderTable.js.map +1 -1
- package/dist/components/EntityHeaderTable/Filter.js.map +1 -1
- package/dist/components/EntityHeaderTable/useEntityHeaderTableState.js.map +1 -1
- package/dist/components/EntitySubjectsSelector/EntitySubjectsSelector.js.map +1 -1
- package/dist/components/EntityTreeTable/components/IdColumnHeader.js.map +1 -1
- package/dist/components/EntityTreeTable/hooks/useEntityTreeState.js.map +1 -1
- package/dist/components/EntityTreeTable/hooks/useTableColumns.js.map +1 -1
- package/dist/components/EntityTreeTable/hooks/useTableData.js.map +1 -1
- package/dist/components/EntityTreeTable/hooks/useTreeOperationsWithDirectFetch.js.map +1 -1
- package/dist/components/EntityUpload/EntityUpload.js.map +1 -1
- package/dist/components/ExperimentalMode/ExperimentalMode.js.map +1 -1
- package/dist/components/ExternalFileHandleLink/ExternalFileHandleLink.js.map +1 -1
- package/dist/components/FeaturedDataTabs/FacetPlotsCard.js.map +1 -1
- package/dist/components/FeaturedDataTabs/QueryPerFacetPlotsCard.js.map +1 -1
- package/dist/components/FeaturedDataTabs/SingleQueryFacetPlotsCards.js.map +1 -1
- package/dist/components/FeaturedResearch/FeaturedResearch.js.map +1 -1
- package/dist/components/FeaturedToolsList/FeaturedToolsList.js.map +1 -1
- package/dist/components/FilePreview/FileHandleContentRenderer.js.map +1 -1
- package/dist/components/FilePreview/HtmlPreview/HtmlPreview.js.map +1 -1
- package/dist/components/FilePreview/PreviewRendererType.js.map +1 -1
- package/dist/components/Forum/DiscussionReply.js.map +1 -1
- package/dist/components/Forum/DiscussionSearchResult.js.map +1 -1
- package/dist/components/Forum/ForumTable.js.map +1 -1
- package/dist/components/Forum/ForumThreadEditor.js.map +1 -1
- package/dist/components/FullTextSearch/FullTextSearchUtils.js.map +1 -1
- package/dist/components/GenericCard/GenericCard.d.ts.map +1 -1
- package/dist/components/GenericCard/GenericCard.js +12 -7
- package/dist/components/GenericCard/GenericCard.js.map +1 -1
- package/dist/components/GenericCard/Linkify.js.map +1 -1
- package/dist/components/GenericCard/SynapseCardLabel.js.map +1 -1
- package/dist/components/GenericCard/TableRowGenericCard.js +105 -105
- package/dist/components/GenericCard/TableRowGenericCard.js.map +1 -1
- package/dist/components/Goals/Goals.Mobile.js.map +1 -1
- package/dist/components/Goals/Goals.js.map +1 -1
- package/dist/components/GoalsV2/GoalsV2.Mobile.js.map +1 -1
- package/dist/components/GoalsV2/GoalsV2.js.map +1 -1
- package/dist/components/GoalsV3/GoalsV3.Mobile.js.map +1 -1
- package/dist/components/GoalsV3/GoalsV3.js.map +1 -1
- package/dist/components/GoogleMap/SynapseUserMarker.js.map +1 -1
- package/dist/components/HasAccess/AccessIcon.js.map +1 -1
- package/dist/components/HasAccess/useHasAccess.js.map +1 -1
- package/dist/components/HeaderCard/HeaderCardV2.js.map +1 -1
- package/dist/components/HeaderCard.d.ts +6 -1
- package/dist/components/HeaderCard.d.ts.map +1 -1
- package/dist/components/HeaderCard.js +107 -76
- package/dist/components/HeaderCard.js.map +1 -1
- package/dist/components/HexGrid/HexGrid.js.map +1 -1
- package/dist/components/IconList.js.map +1 -1
- package/dist/components/ImageCardGridWithLinks/ImageCardGridWithLinks.js.map +1 -1
- package/dist/components/ImageFromSynapseTable.js.map +1 -1
- package/dist/components/JSONArrayEditor/useParseCsv.js.map +1 -1
- package/dist/components/JsonSchemaForm/templates/ArrayFieldDescriptionTemplate.js.map +1 -1
- package/dist/components/JsonSchemaForm/templates/ArrayFieldItemTemplate.js.map +1 -1
- package/dist/components/JsonSchemaForm/templates/BaseInputTemplate.js.map +1 -1
- package/dist/components/JsonSchemaForm/templates/FieldTemplate.js.map +1 -1
- package/dist/components/JsonSchemaForm/templates/RJSFInputLabel.js.map +1 -1
- package/dist/components/Markdown/MarkdownGithub.js.map +1 -1
- package/dist/components/Markdown/MarkdownSynapse.js.map +1 -1
- package/dist/components/Markdown/MarkdownUtils.js.map +1 -1
- package/dist/components/Markdown/SynapseWikiContext.js.map +1 -1
- package/dist/components/Markdown/UserMentionModal.js.map +1 -1
- package/dist/components/Markdown/widget/MarkdownProvenanceGraph.js.map +1 -1
- package/dist/components/MissingQueryResultsWarning/MissingQueryResultsWarning.js.map +1 -1
- package/dist/components/ModalDownload/ModalDownload.js.map +1 -1
- package/dist/components/OAuthClientAclEditor/OAuthClientAclEditor.d.ts.map +1 -1
- package/dist/components/OAuthClientAclEditor/OAuthClientAclEditor.js +45 -39
- package/dist/components/OAuthClientAclEditor/OAuthClientAclEditor.js.map +1 -1
- package/dist/components/OAuthClientManagement/OAuthManagement.js.map +1 -1
- package/dist/components/PageProgress/PageProgress.js.map +1 -1
- package/dist/components/Plot/DotPlot.js.map +1 -1
- package/dist/components/Plot/Plot.js.map +1 -1
- package/dist/components/Plot/SynapsePlot.js.map +1 -1
- package/dist/components/Plot/ThemesPlot.js.map +1 -1
- package/dist/components/Plot/UpsetPlot.js.map +1 -1
- package/dist/components/PortalAclEditor/PortalAclEditor.d.ts.map +1 -1
- package/dist/components/PortalAclEditor/PortalAclEditor.js +43 -41
- package/dist/components/PortalAclEditor/PortalAclEditor.js.map +1 -1
- package/dist/components/PortalFeaturedPartners/PortalFeaturedPartners.js.map +1 -1
- package/dist/components/PortalList/CreatePortalModal.js.map +1 -1
- package/dist/components/ProgrammaticInstructionsModal/ProgrammaticInstructionsModal.js.map +1 -1
- package/dist/components/ProgrammaticTableDownload/ProgrammaticTableDownload.js.map +1 -1
- package/dist/components/Programs/Programs.Mobile.js.map +1 -1
- package/dist/components/Programs/Programs.js.map +1 -1
- package/dist/components/ProvenanceGraph/ProvenanceExternalIcon.js.map +1 -1
- package/dist/components/ProvenanceGraph/ProvenanceGraph.js.map +1 -1
- package/dist/components/ProvenanceGraph/ProvenanceGraphUtils.js.map +1 -1
- package/dist/components/ProvenanceGraph/ProvenanceUtils.js.map +1 -1
- package/dist/components/QueryCount/QueryCount.js.map +1 -1
- package/dist/components/QueryCountButton/QueryCountButton.js.map +1 -1
- package/dist/components/QueryVisualizationWrapper/QueryVisualizationWrapper.js.map +1 -1
- package/dist/components/QueryWrapper/QueryWrapper.js.map +1 -1
- package/dist/components/QueryWrapper/TableQueryUseQueryOptions.js.map +1 -1
- package/dist/components/QueryWrapper/TableRowSelectionState.js.map +1 -1
- package/dist/components/QueryWrapper/generateEncodedPathAndQueryForSelectedFacetURL.js.map +1 -1
- package/dist/components/QueryWrapper/useGetQueryMetadata.js.map +1 -1
- package/dist/components/QueryWrapperErrorBoundary.js.map +1 -1
- package/dist/components/QueryWrapperPlotNav/QueryWrapperPlotNav.js.map +1 -1
- package/dist/components/QueryWrapperPlotNav/UseRowSet.js.map +1 -1
- package/dist/components/RecentPublicationsGrid/RecentPublicationsGrid.js.map +1 -1
- package/dist/components/ReleaseCard/ReleaseCardUtils.js.map +1 -1
- package/dist/components/ResizableContainer/hooks/useResizable.js.map +1 -1
- package/dist/components/Resources/Resources.Mobile.js.map +1 -1
- package/dist/components/Resources/Resources.js.map +1 -1
- package/dist/components/RowDataTable/RowDataTableWithQuery.js.map +1 -1
- package/dist/components/SageResourcesPopover/SageResourcesPopover.js.map +1 -1
- package/dist/components/SchemaDrivenAnnotationEditor/AnnotationEditorUtils.js.map +1 -1
- package/dist/components/SetAccessRequirementCommonFields/SetAccessRequirementCommonFields.js.map +1 -1
- package/dist/components/SetManagedAccessRequirementFields/SetManagedAccessRequirementFields.js.map +1 -1
- package/dist/components/SmartLink/SmartButton.js.map +1 -1
- package/dist/components/SmartLink/SmartLink.js.map +1 -1
- package/dist/components/SourceAppImage.js.map +1 -1
- package/dist/components/StandaloneQueryWrapper/StandaloneQueryWrapper.js.map +1 -1
- package/dist/components/StatisticsPlot.js.map +1 -1
- package/dist/components/StorybookComponentWrapper.js.map +1 -1
- package/dist/components/SubsectionRowRenderer/SubsectionRowRenderer.js.map +1 -1
- package/dist/components/SustainabilityScorecard/SustainabilityScorecard.js.map +1 -1
- package/dist/components/SynapseChat/GridAgentChat.js.map +1 -1
- package/dist/components/SynapseChat/SynapseChatInteraction.js.map +1 -1
- package/dist/components/SynapseChat/SynapseChatMessage.js.map +1 -1
- package/dist/components/SynapseChat/extractMessageFromTraceEvent.js.map +1 -1
- package/dist/components/SynapseForm/StepsSideNav.js.map +1 -1
- package/dist/components/SynapseForm/SummaryTable.js.map +1 -1
- package/dist/components/SynapseForm/SynapseForm.js +4 -2
- package/dist/components/SynapseForm/SynapseForm.js.map +1 -1
- package/dist/components/SynapseForm/SynapseFormWrapper.js.map +1 -1
- package/dist/components/SynapseHomepageV2/SynapseByTheNumbersItem.js.map +1 -1
- package/dist/components/SynapseHomepageV2/SynapseFeatureItem.js.map +1 -1
- package/dist/components/SynapseHomepageV2/SynapseHomepageChatSearch.js.map +1 -1
- package/dist/components/SynapseHomepageV2/SynapseHomepageSearch.js.map +1 -1
- package/dist/components/SynapseHomepageV2/SynapseInActionItem.js.map +1 -1
- package/dist/components/SynapseHomepageV2/SynapsePlans.js.map +1 -1
- package/dist/components/SynapseHomepageV2/SynapseTrendingProjects.js.map +1 -1
- package/dist/components/SynapseNavDrawer/SynapseNavDrawer.d.ts +8 -7
- package/dist/components/SynapseNavDrawer/SynapseNavDrawer.d.ts.map +1 -1
- package/dist/components/SynapseNavDrawer/SynapseNavDrawer.js +173 -164
- package/dist/components/SynapseNavDrawer/SynapseNavDrawer.js.map +1 -1
- package/dist/components/SynapsePortalBanners/SynapsePortalBanners.js.map +1 -1
- package/dist/components/SynapseSearchPageResults/SearchFacetPanel/SearchFacetPanel.js.map +1 -1
- package/dist/components/SynapseSearchPageResults/SearchFacetPanel/SearchFacetPanelUtils.js.map +1 -1
- package/dist/components/SynapseSearchPageResults/SynapseSearchPageResults.js.map +1 -1
- package/dist/components/SynapseTable/EntityIDColumnCopyIcon.js.map +1 -1
- package/dist/components/SynapseTable/NoContentPlaceholderType.js.map +1 -1
- package/dist/components/SynapseTable/RowSelection/RowSelectionControls.js.map +1 -1
- package/dist/components/SynapseTable/SynapseTableCell/SynapseTableCell.js.map +1 -1
- package/dist/components/SynapseTable/SynapseTableRenderers.js.map +1 -1
- package/dist/components/SynapseTable/datasets/DatasetItemsEditor.js.map +1 -1
- package/dist/components/SynapseTable/table-top/ColumnSelection.js.map +1 -1
- package/dist/components/SynapseTable/table-top/DownloadOptions.js.map +1 -1
- package/dist/components/SynapseTable/usePrefetchTableData.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/ColumnModelForm.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/ColumnModelFormFields/DefaultValueField.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/ImportTableColumnsButton.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/TableColumnSchemaEditorUtils.d.ts +1 -1
- package/dist/components/TableColumnSchemaEditor/TableColumnSchemaEditorUtils.d.ts.map +1 -1
- package/dist/components/TableColumnSchemaEditor/TableColumnSchemaEditorUtils.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/TableColumnSchemaForm.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/TableColumnSchemaFormReducer.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/Validators/ColumnModelValidator.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/Validators/DatetimeSchema.js.map +1 -1
- package/dist/components/TanStackTable/ColumnHeader.d.ts +1 -0
- package/dist/components/TanStackTable/ColumnHeader.d.ts.map +1 -1
- package/dist/components/TanStackTable/ColumnHeader.js +8 -8
- package/dist/components/TanStackTable/ColumnHeader.js.map +1 -1
- package/dist/components/TanStackTable/ColumnHeaderEnumFilter.js.map +1 -1
- package/dist/components/TanStackTable/TableBody.js.map +1 -1
- package/dist/components/TeamSubjectsSelector/TeamSubjectsSelector.js.map +1 -1
- package/dist/components/TextField/TextField.js.map +1 -1
- package/dist/components/TimelinePlot/TimelinePhase.js.map +1 -1
- package/dist/components/TimelinePlot/TimelinePlot.js.map +1 -1
- package/dist/components/TimelinePlot/TimelinePlotSpeciesSelector.js.map +1 -1
- package/dist/components/UserCard/Avatar.js.map +1 -1
- package/dist/components/UserCardList/UserCardList.js.map +1 -1
- package/dist/components/UserCardList/UserCardListGroups/UserCardListGroups.Mobile.js.map +1 -1
- package/dist/components/UserCardList/UserCardListRotate.js.map +1 -1
- package/dist/components/UserOrTeamBadge/useUserOrTeam.js.map +1 -1
- package/dist/components/UserProfileLinks/UserProjects.js.map +1 -1
- package/dist/components/UserSearchBox/UserSearchBox.js.map +1 -1
- package/dist/components/Webhook/WebhookDashboard.js.map +1 -1
- package/dist/components/WikiMarkdownEditor/WikiMarkdownEditor.js.map +1 -1
- package/dist/components/WikiMarkdownEditorButton/WikiMarkdownEditorButton.js.map +1 -1
- package/dist/components/dataaccess/AccessApprovalsTable.js.map +1 -1
- package/dist/components/dataaccess/AccessRequestSubmissionTable.js.map +1 -1
- package/dist/components/dataaccess/SubmissionPage/SubmissionPage.js.map +1 -1
- package/dist/components/dataaccess/UseAccessRequirementTable.js.map +1 -1
- package/dist/components/dataaccess/UserAccessRequestHistory/UserAccessRequestHistoryTable.js.map +1 -1
- package/dist/components/doi/CreateOrUpdateDoiModal.js.map +1 -1
- package/dist/components/entity/page/CreatedByModifiedBy.js.map +1 -1
- package/dist/components/entity/page/action_menu/EntityActionMenu.js.map +1 -1
- package/dist/components/entity/page/title_bar/useDataCiteUsage.js.map +1 -1
- package/dist/components/entity/page/title_bar/useGetMentions.js.map +1 -1
- package/dist/components/error/ErrorPage.js.map +1 -1
- package/dist/components/favorites/FavoritesPage.js.map +1 -1
- package/dist/components/file/upload/BasicFileHandleUpload.js.map +1 -1
- package/dist/components/layout/SWCHeader.d.ts +9 -0
- package/dist/components/layout/SWCHeader.d.ts.map +1 -0
- package/dist/components/layout/SWCHeader.js +19 -0
- package/dist/components/layout/SWCHeader.js.map +1 -0
- package/dist/components/layout/SWCPageLayout.d.ts +9 -0
- package/dist/components/layout/SWCPageLayout.d.ts.map +1 -0
- package/dist/components/layout/SWCPageLayout.js +14 -0
- package/dist/components/layout/SWCPageLayout.js.map +1 -0
- package/dist/components/menu/ComplexMenu.js.map +1 -1
- package/dist/components/row_renderers/utils/ChipContainer.js.map +1 -1
- package/dist/components/styled/StyledPopover.js.map +1 -1
- package/dist/components/table/CsvPreview/CsvPreview.js +2 -1
- package/dist/components/table/CsvPreview/CsvPreview.js.map +1 -1
- package/dist/components/table/CsvPreview/CsvPreviewDialog.js.map +1 -1
- package/dist/components/trash/TrashCanList.js.map +1 -1
- package/dist/components/widgets/FileHandleLink.js.map +1 -1
- package/dist/components/widgets/RangeSlider/RangeSlider.js.map +1 -1
- package/dist/components/widgets/SynapseVideo.js.map +1 -1
- package/dist/components/widgets/facet-nav/FacetNavPanel.js.map +1 -1
- package/dist/components/widgets/facet-nav/PlotsContainer.js.map +1 -1
- package/dist/components/widgets/facet-nav/SelectionCriteriaPills.js.map +1 -1
- package/dist/components/widgets/facet-nav/useFacetPlots.js.map +1 -1
- package/dist/components/widgets/query-filter/CombinedRangeFacetFilter.js.map +1 -1
- package/dist/components/widgets/query-filter/EnumFacetFilter/EnumFacetFilter.js.map +1 -1
- package/dist/components/widgets/query-filter/FacetFilterControls.js.map +1 -1
- package/dist/components/widgets/query-filter/RangeFacetFilter.js.map +1 -1
- package/dist/components/widgets/query-filter/RangeFacetFilterUI.js.map +1 -1
- package/dist/features/curator/GridPage/components/GridPageTitle.d.ts.map +1 -1
- package/dist/features/curator/GridPage/components/GridPageTitle.js +23 -30
- package/dist/features/curator/GridPage/components/GridPageTitle.js.map +1 -1
- package/dist/features/curator/dashboard/CuratorDashboard.d.ts +2 -0
- package/dist/features/curator/dashboard/CuratorDashboard.d.ts.map +1 -0
- package/dist/features/curator/dashboard/CuratorDashboard.js +45 -0
- package/dist/features/curator/dashboard/CuratorDashboard.js.map +1 -0
- package/dist/features/curator/dashboard/components/CurationTaskCard.css +1 -0
- package/dist/features/curator/dashboard/components/CurationTaskCard.d.ts +9 -0
- package/dist/features/curator/dashboard/components/CurationTaskCard.d.ts.map +1 -0
- package/dist/features/curator/dashboard/components/CurationTaskCard.js +106 -0
- package/dist/features/curator/dashboard/components/CurationTaskCard.js.map +1 -0
- package/dist/features/curator/dashboard/components/CurationTaskCard.module.js +12 -0
- package/dist/features/curator/dashboard/components/CurationTaskCard.module.js.map +1 -0
- package/dist/features/curator/dashboard/components/CurationTaskCard.module.scss +52 -0
- package/dist/features/curator/dashboard/components/NextStepButton.css +1 -0
- package/dist/features/curator/dashboard/components/NextStepButton.d.ts +14 -0
- package/dist/features/curator/dashboard/components/NextStepButton.d.ts.map +1 -0
- package/dist/features/curator/dashboard/components/NextStepButton.js +35 -0
- package/dist/features/curator/dashboard/components/NextStepButton.js.map +1 -0
- package/dist/features/curator/dashboard/components/NextStepButton.module.js +11 -0
- package/dist/features/curator/dashboard/components/NextStepButton.module.js.map +1 -0
- package/dist/features/curator/dashboard/components/NextStepButton.module.scss +57 -0
- package/dist/features/curator/dashboard/components/UserOrTeamChip.css +1 -1
- package/dist/features/curator/dashboard/components/UserOrTeamChip.module.js +1 -1
- package/dist/features/curator/dashboard/components/UserOrTeamChip.module.js.map +1 -1
- package/dist/features/curator/dashboard/components/UserOrTeamChip.module.scss +5 -5
- package/dist/features/curator/dashboard/components/shared.css +1 -0
- package/dist/features/curator/dashboard/components/shared.module.js +5 -0
- package/dist/features/curator/dashboard/components/shared.module.js.map +1 -0
- package/dist/features/curator/dashboard/components/shared.module.scss +8 -0
- package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.d.ts +0 -2
- package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.d.ts.map +1 -1
- package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.js +16 -34
- package/dist/features/entity/metadata-task/components/MetadataTaskTableActionCell.js.map +1 -1
- package/dist/features/entity/metadata-task/components/MetadataTasksTableAssigneeCell.js.map +1 -1
- package/dist/features/entity/metadata-task/hooks/useGetOrCreateGridSessionForSource.js.map +1 -1
- package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask.js.map +1 -1
- package/dist/features/entity/metadata-task/hooks/useGridSessionForCurationTask_legacy.js.map +1 -1
- package/dist/features/entity/metadata-task/hooks/useMetadataTaskTable.js +1 -1
- package/dist/features/entity/metadata-task/hooks/useMetadataTaskTable.js.map +1 -1
- package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.d.ts +10 -0
- package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.d.ts.map +1 -0
- package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.js +37 -0
- package/dist/features/entity/metadata-task/hooks/useOpenCuratorButton.js.map +1 -0
- package/dist/features/entity/metadata-task/utils/constants.d.ts +5 -0
- package/dist/features/entity/metadata-task/utils/constants.d.ts.map +1 -0
- package/dist/features/entity/metadata-task/utils/constants.js +6 -0
- package/dist/features/entity/metadata-task/utils/constants.js.map +1 -0
- package/dist/mocks/challenge/mockChallenge.js.map +1 -1
- package/dist/mocks/entity/mockDataset.js.map +1 -1
- package/dist/mocks/entity/mockDatasetCollection.js.map +1 -1
- package/dist/mocks/entity/mockFileEntity.js.map +1 -1
- package/dist/mocks/entity/mockFileView.js.map +1 -1
- package/dist/mocks/entity/mockGeneratedEntityData.js.map +1 -1
- package/dist/mocks/entity/mockProject.js.map +1 -1
- package/dist/mocks/entity/mockProjectView.js.map +1 -1
- package/dist/mocks/entity/mockRootEntity.js.map +1 -1
- package/dist/mocks/entity/mockTableEntity.js.map +1 -1
- package/dist/mocks/mockWiki.js.map +1 -1
- package/dist/mocks/msw/handlers/asyncJobHandlers.js.map +1 -1
- package/dist/mocks/msw/handlers/challengeHandlers.js.map +1 -1
- package/dist/mocks/msw/handlers/changePasswordHandlers.js.map +1 -1
- package/dist/mocks/msw/handlers/discussionHandlers.js.map +1 -1
- package/dist/mocks/msw/handlers/entityHandlers.js.map +1 -1
- package/dist/mocks/msw/handlers/fileHandlers.js.map +1 -1
- package/dist/mocks/msw/handlers/gridHandlers.js.map +1 -1
- package/dist/mocks/msw/handlers/personalAccessTokenHandlers.js.map +1 -1
- package/dist/mocks/msw/handlers/subscriptionHandlers.js.map +1 -1
- package/dist/mocks/msw/handlers/teamHandlers.js.map +1 -1
- package/dist/mocks/msw/handlers/userProfileHandlers.js.map +1 -1
- package/dist/mocks/msw/handlers/wikiHandlers.js.map +1 -1
- package/dist/mocks/provenance/mockActivity.js.map +1 -1
- package/dist/mocks/query/mockReleaseCardsTableQueryResultBundle.js.map +1 -1
- package/dist/ror-client/index.js.map +1 -1
- package/dist/style/components/_cards.scss +4 -0
- package/dist/style/components/_data-grid-extra.css +1 -1
- package/dist/style/components/_data-grid-extra.scss +2 -0
- package/dist/style/main.css +1 -1
- package/dist/synapse-client/HttpClient.js.map +1 -1
- package/dist/synapse-client/SynapseClient.js.map +1 -1
- package/dist/synapse-queries/QueryMatching.test-utils.js.map +1 -1
- package/dist/synapse-queries/auth/useTwoFactorEnrollment.js.map +1 -1
- package/dist/synapse-queries/curation/task/useCurationTask.d.ts +1 -1
- package/dist/synapse-queries/curation/task/useCurationTask.d.ts.map +1 -1
- package/dist/synapse-queries/curation/task/useCurationTask.js +1 -1
- package/dist/synapse-queries/curation/task/useCurationTask.js.map +1 -1
- package/dist/synapse-queries/dataaccess/useRestrictionInformation.js.map +1 -1
- package/dist/synapse-queries/doi/useDOI.js.map +1 -1
- package/dist/synapse-queries/download/useDownloadList.js.map +1 -1
- package/dist/synapse-queries/entity/useEntity.js.map +1 -1
- package/dist/synapse-queries/entity/useEntityBundle.js.map +1 -1
- package/dist/synapse-queries/entity/useExportTableQueryToAnalysisPlatform.js.map +1 -1
- package/dist/synapse-queries/entity/useExportToTerra.js.map +1 -1
- package/dist/synapse-queries/entity/useGetQueryResultBundle.js.map +1 -1
- package/dist/synapse-queries/entity/useSchema.js.map +1 -1
- package/dist/synapse-queries/file/UploadToS3.js.map +1 -1
- package/dist/synapse-queries/file/useDirectUploadToS3.js.map +1 -1
- package/dist/synapse-queries/file/useFiles.js.map +1 -1
- package/dist/synapse-queries/forum/useReply.js.map +1 -1
- package/dist/synapse-queries/forum/useThread.js.map +1 -1
- package/dist/synapse-queries/grid/useEstablishWebsocketConnection.d.ts +2 -0
- package/dist/synapse-queries/grid/useEstablishWebsocketConnection.d.ts.map +1 -1
- package/dist/synapse-queries/grid/useEstablishWebsocketConnection.js.map +1 -1
- package/dist/synapse-queries/grid/useExportGrid.js.map +1 -1
- package/dist/synapse-queries/grid/useGridSession.js.map +1 -1
- package/dist/synapse-queries/grid/useImportCsvIntoGrid.js.map +1 -1
- package/dist/synapse-queries/subscription/useSubscription.js.map +1 -1
- package/dist/synapse-queries/table/useGetCsvPreview.js.map +1 -1
- package/dist/synapse-queries/table/useTableUpdateTransaction.js.map +1 -1
- package/dist/synapse-queries/team/useTeamMembers.js.map +1 -1
- package/dist/synapse-queries/user/useGetUserChallenges.js.map +1 -1
- package/dist/synapse-queries/user/useUserBundle.js.map +1 -1
- package/dist/synapse-queries/user/useUserGroupHeader.js.map +1 -1
- package/dist/testutils/ReactQueryMockUtils.js.map +1 -1
- package/dist/theme/ThemeProvider.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utils/AppUtils/session/SynapseSessionManager.js.map +1 -1
- package/dist/utils/AppUtils/session/useSessionManager.js.map +1 -1
- package/dist/utils/PermissionLevelToAccessType.js.map +1 -1
- package/dist/utils/challenge/evaluation/EvaluationUtils.js.map +1 -1
- package/dist/utils/context/SynapseContext.js.map +1 -1
- package/dist/utils/functions/AccessControlListUtils.d.ts +4 -0
- package/dist/utils/functions/AccessControlListUtils.d.ts.map +1 -1
- package/dist/utils/functions/AccessControlListUtils.js +12 -1
- package/dist/utils/functions/AccessControlListUtils.js.map +1 -1
- package/dist/utils/functions/GridApiUtils.js.map +1 -1
- package/dist/utils/functions/QueryFilterUtils.js.map +1 -1
- package/dist/utils/functions/RealmUtils.d.ts +4 -0
- package/dist/utils/functions/RealmUtils.d.ts.map +1 -1
- package/dist/utils/functions/RealmUtils.js +9 -3
- package/dist/utils/functions/RealmUtils.js.map +1 -1
- package/dist/utils/functions/SanitizeHtmlUtils.js.map +1 -1
- package/dist/utils/functions/SanitizeHtmlUtils.test-utils.js.map +1 -1
- package/dist/utils/functions/SqlFunctions.js.map +1 -1
- package/dist/utils/functions/StringUtils.js.map +1 -1
- package/dist/utils/functions/deepLinkingUtils.js.map +1 -1
- package/dist/utils/functions/getDataFromFromStorage.js.map +1 -1
- package/dist/utils/functions/getEndpoint.js.map +1 -1
- package/dist/utils/functions/getUserData.js.map +1 -1
- package/dist/utils/functions/queryUtils.js.map +1 -1
- package/dist/utils/functions/testDownloadSpeed.js.map +1 -1
- package/dist/utils/hooks/useConfirmItems.js.map +1 -1
- package/dist/utils/hooks/useCookiePreferences.js.map +1 -1
- package/dist/utils/hooks/useCreateShortUrl.js.map +1 -1
- package/dist/utils/hooks/useDetectSSOCode.js.map +1 -1
- package/dist/utils/hooks/useDirectDownloadHandler.js.map +1 -1
- package/dist/utils/hooks/useGetGoalData.js.map +1 -1
- package/dist/utils/hooks/useGetInfoFromIds.js.map +1 -1
- package/dist/utils/hooks/useImageUrlUtils.js.map +1 -1
- package/dist/utils/hooks/useImmutableTableQuery/useImmutableTableQuery.js.map +1 -1
- package/dist/utils/hooks/useImmutableTableQuery/useTableQueryReducer.js.map +1 -1
- package/dist/utils/hooks/useIsBot.js.map +1 -1
- package/dist/utils/hooks/useListState.js.map +1 -1
- package/dist/utils/hooks/useLogin.d.ts.map +1 -1
- package/dist/utils/hooks/useLogin.js +53 -52
- package/dist/utils/hooks/useLogin.js.map +1 -1
- package/dist/utils/hooks/useMutuallyExclusiveState.js.map +1 -1
- package/dist/utils/hooks/useOverlay.js.map +1 -1
- package/dist/utils/hooks/usePreFetchResource.js.map +1 -1
- package/dist/utils/hooks/useQuerySearchParam.js.map +1 -1
- package/dist/utils/hooks/useScrollFadeTransition.js.map +1 -1
- package/dist/utils/hooks/useSet.js.map +1 -1
- package/dist/utils/hooks/useSourceAppConfigs.js.map +1 -1
- package/dist/utils/hooks/useTableImageUrl.js.map +1 -1
- package/dist/utils/hooks/useUploadFileEntity/useCreatePathsAndGetParentId.js.map +1 -1
- package/dist/utils/hooks/useUploadFileEntity/useLinkFileEntityToURL.js.map +1 -1
- package/dist/utils/hooks/useUploadFileEntity/usePrepareFileEntityUpload.js.map +1 -1
- package/dist/utils/hooks/useUploadFileEntity/useTrackFileUploads.js.map +1 -1
- package/dist/utils/hooks/useUploadFileEntity/useUploadFileEntities.js.map +1 -1
- package/dist/utils/hooks/useUploadFileEntity/useUploadFiles.js.map +1 -1
- package/dist/utils/hooks/useUploadFileEntity/willUploadsExceedStorageLimit.js.map +1 -1
- package/dist/utils/html/TargetEnum.js.map +1 -1
- package/dist/utils/jsonschema/SchemaAnnotationUtils.js.map +1 -1
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"computeReplicaSelectionModel.js","names":["CrdtId","GridModel","ReplicaSelectionModel","ArrApi","SelectionWithId","computeReplicaSelectionModel","selection","model","replicaSelectionModel","modelSnapshot","api","getSnapshot","isSelectAll","rows","min","row","max","rowSelectAll","rowsArr","arr","rowSelection","getCrdtIdsForArrayRange","columnOrder","col","columnSelectAll","columnOrderArr","columnSelection","arrSnapshot","length","array","crdtIds","i","findChunkResult","node","findChunk","chunk","offset","push","rep","id","sid","seq","time","console","warn"],"sources":["../../../../src/components/DataGrid/utils/computeReplicaSelectionModel.ts"],"sourcesContent":["import {\n CrdtId,\n GridModel,\n ReplicaSelectionModel,\n} from '@/components/DataGrid/DataGridTypes'\nimport { ArrApi } from 'json-joy'\nimport { SelectionWithId } from '@sage-bionetworks/react-datasheet-grid'\n\n/**\n * Compute the ReplicaSelectionModel that should be attached to the grid model\n * @param selection the selection provided by react-datasheet-grid\n * @param model the current Data Grid CRDT Model\n */\nexport default function computeReplicaSelectionModel(\n selection: SelectionWithId,\n model: GridModel,\n): ReplicaSelectionModel {\n const replicaSelectionModel: ReplicaSelectionModel = {}\n const modelSnapshot = model.api.getSnapshot()\n if (isSelectAll(modelSnapshot.rows, selection.min.row, selection.max.row)) {\n replicaSelectionModel.rowSelectAll = true\n } else {\n // Get the arr element CrdtIds from the rows array\n const rowsArr = model.api.arr(['rows'])\n replicaSelectionModel.rowSelection = getCrdtIdsForArrayRange(\n rowsArr,\n selection.min.row,\n selection.max.row,\n )\n }\n\n if (\n isSelectAll(modelSnapshot.columnOrder, selection.min.col, selection.max.col)\n ) {\n replicaSelectionModel.columnSelectAll = true\n } else {\n // Get the arr element CrdtIds from the columnOrder array\n const columnOrderArr = model.api.arr(['columnOrder'])\n replicaSelectionModel.columnSelection = getCrdtIdsForArrayRange(\n columnOrderArr,\n selection.min.col,\n selection.max.col,\n )\n }\n\n return replicaSelectionModel\n}\n\nfunction isSelectAll(arrSnapshot: unknown[], min: number, max: number) {\n // If the min and max cover the entire array, it's a select all\n return min === 0 && max === arrSnapshot.length - 1\n}\n\nfunction getCrdtIdsForArrayRange(array: ArrApi, min: number, max: number) {\n const crdtIds: CrdtId[] = []\n for (let i = min; i <= max; i++) {\n const findChunkResult = array.node.findChunk(i)\n if (findChunkResult) {\n const [chunk, offset] = findChunkResult\n crdtIds.push({ rep: chunk.id.sid, seq: chunk.id.time + offset })\n } else {\n console.warn(\n `getCrdtIdsForArrayRange: No chunk found for array index ${i}. This may indicate an unexpected state.`,\n )\n }\n }\n return crdtIds\n}\n"],"mappings":";AAaA,SAAwBK,EACtBC,GACAC,GACuB;CACvB,IAAMC,IAA+C,EAAE,EACjDC,IAAgBF,EAAMG,IAAIC,aAAa;AA2B7C,QA1BIC,EAAYH,EAAcI,MAAMP,EAAUQ,IAAIC,KAAKT,EAAUU,IAAID,IAAI,GACvEP,EAAsBS,eAAe,KAIrCT,EAAsBY,eAAeC,EADrBd,EAAMG,IAAIS,IAAI,CAAC,OAAO,
|
|
1
|
+
{"version":3,"file":"computeReplicaSelectionModel.js","names":["CrdtId","GridModel","ReplicaSelectionModel","ArrApi","SelectionWithId","computeReplicaSelectionModel","selection","model","replicaSelectionModel","modelSnapshot","api","getSnapshot","isSelectAll","rows","min","row","max","rowSelectAll","rowsArr","arr","rowSelection","getCrdtIdsForArrayRange","columnOrder","col","columnSelectAll","columnOrderArr","columnSelection","arrSnapshot","length","array","crdtIds","i","findChunkResult","node","findChunk","chunk","offset","push","rep","id","sid","seq","time","console","warn"],"sources":["../../../../src/components/DataGrid/utils/computeReplicaSelectionModel.ts"],"sourcesContent":["import {\n CrdtId,\n GridModel,\n ReplicaSelectionModel,\n} from '@/components/DataGrid/DataGridTypes'\nimport { ArrApi } from 'json-joy'\nimport { SelectionWithId } from '@sage-bionetworks/react-datasheet-grid'\n\n/**\n * Compute the ReplicaSelectionModel that should be attached to the grid model\n * @param selection the selection provided by react-datasheet-grid\n * @param model the current Data Grid CRDT Model\n */\nexport default function computeReplicaSelectionModel(\n selection: SelectionWithId,\n model: GridModel,\n): ReplicaSelectionModel {\n const replicaSelectionModel: ReplicaSelectionModel = {}\n const modelSnapshot = model.api.getSnapshot()\n if (isSelectAll(modelSnapshot.rows, selection.min.row, selection.max.row)) {\n replicaSelectionModel.rowSelectAll = true\n } else {\n // Get the arr element CrdtIds from the rows array\n const rowsArr = model.api.arr(['rows'])\n replicaSelectionModel.rowSelection = getCrdtIdsForArrayRange(\n rowsArr,\n selection.min.row,\n selection.max.row,\n )\n }\n\n if (\n isSelectAll(modelSnapshot.columnOrder, selection.min.col, selection.max.col)\n ) {\n replicaSelectionModel.columnSelectAll = true\n } else {\n // Get the arr element CrdtIds from the columnOrder array\n const columnOrderArr = model.api.arr(['columnOrder'])\n replicaSelectionModel.columnSelection = getCrdtIdsForArrayRange(\n columnOrderArr,\n selection.min.col,\n selection.max.col,\n )\n }\n\n return replicaSelectionModel\n}\n\nfunction isSelectAll(arrSnapshot: unknown[], min: number, max: number) {\n // If the min and max cover the entire array, it's a select all\n return min === 0 && max === arrSnapshot.length - 1\n}\n\nfunction getCrdtIdsForArrayRange(array: ArrApi, min: number, max: number) {\n const crdtIds: CrdtId[] = []\n for (let i = min; i <= max; i++) {\n const findChunkResult = array.node.findChunk(i)\n if (findChunkResult) {\n const [chunk, offset] = findChunkResult\n crdtIds.push({ rep: chunk.id.sid, seq: chunk.id.time + offset })\n } else {\n console.warn(\n `getCrdtIdsForArrayRange: No chunk found for array index ${i}. This may indicate an unexpected state.`,\n )\n }\n }\n return crdtIds\n}\n"],"mappings":";AAaA,SAAwBK,EACtBC,GACAC,GACuB;CACvB,IAAMC,IAA+C,EAAE,EACjDC,IAAgBF,EAAMG,IAAIC,aAAa;AA2B7C,QA1BIC,EAAYH,EAAcI,MAAMP,EAAUQ,IAAIC,KAAKT,EAAUU,IAAID,IAAI,GACvEP,EAAsBS,eAAe,KAIrCT,EAAsBY,eAAeC,EADrBd,EAAMG,IAAIS,IAAI,CAAC,OAAO,CAEpCD,EACAZ,EAAUQ,IAAIC,KACdT,EAAUU,IAAID,IACf,EAIDH,EAAYH,EAAca,aAAahB,EAAUQ,IAAIS,KAAKjB,EAAUU,IAAIO,IAAI,GAE5Ef,EAAsBgB,kBAAkB,KAIxChB,EAAsBkB,kBAAkBL,EADjBd,EAAMG,IAAIS,IAAI,CAAC,cAAc,CAElDM,EACAnB,EAAUQ,IAAIS,KACdjB,EAAUU,IAAIO,IACf,EAGIf;;AAGT,SAASI,EAAYe,GAAwBb,GAAaE,GAAa;AAErE,QAAOF,MAAQ,KAAKE,MAAQW,EAAYC,SAAS;;AAGnD,SAASP,EAAwBQ,GAAef,GAAaE,GAAa;CACxE,IAAMc,IAAoB,EAAE;AAC5B,MAAK,IAAIC,IAAIjB,GAAKiB,KAAKf,GAAKe,KAAK;EAC/B,IAAMC,IAAkBH,EAAMI,KAAKC,UAAUH,EAAE;AAC/C,MAAIC,GAAiB;GACnB,IAAM,CAACG,GAAOC,KAAUJ;AACxBF,KAAQO,KAAK;IAAEC,KAAKH,EAAMI,GAAGC;IAAKC,KAAKN,EAAMI,GAAGG,OAAON;IAAQ,CAAC;QAEhEO,SAAQC,KACN,2DAA2Db,EAAC,0CAC7D;;AAGL,QAAOD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extractColumnValidationMessages.js","names":["extractColumnValidationMessages","messages","Map","columnMap","regex","raw","str","trimStart","match","columnName","trim","message","requiredKeyMatch","has","set","get","push"],"sources":["../../../../src/components/DataGrid/utils/extractColumnValidationMessages.ts"],"sourcesContent":["/**\n * Extracts column name and validation message from validation message strings.\n *\n * Example:\n * extractColumnValidationMessages([\"#/platform: null is not a valid enum value\"])\n * -> Map { \"platform\" => [\"null is not a valid enum value\"] }\n *\n * extractColumnValidationMessages([\"#/requiredNumberArrayColumn/0: some error\"])\n * -> Map { \"requiredNumberArrayColumn\" => [\"some error\"] }\n *\n * extractColumnValidationMessages([\"#: row-level error\"])\n * -> Map { \"_row\" => [\"row-level error\"] }\n *\n * extractColumnValidationMessages([\"#: required key [missingColumn] not found\"])\n * -> Map { \"missingColumn\" => [\"required key [missingColumn] not found\"] }\n */\nexport function extractColumnValidationMessages(\n messages: string[],\n): Map<string, string[]> {\n const columnMap = new Map<string, string[]>()\n // Validation message format: \"#/columnName: message\"\n // or for array items: \"#/columnName/0: message\"\n // or for object (row) level: \"#: message\"\n const regex = /^#(?:\\/([^/:]+)(?:\\/\\d+)?)?:\\s*(.*)$/\n\n for (const raw of messages) {\n if (typeof raw !== 'string') continue\n const str = raw.trimStart()\n const match = str.match(regex)\n if (match) {\n let columnName = match[1]?.trim() ?? '_row'\n const message = match[2].trim()\n if (columnName === '_row') {\n const requiredKeyMatch = message.match(\n /^required key \\[([^\\]]+)\\] not found$/i,\n )\n if (requiredKeyMatch) {\n columnName = requiredKeyMatch[1]\n }\n }\n\n if (!columnMap.has(columnName)) {\n columnMap.set(columnName, [])\n }\n columnMap.get(columnName)!.push(message)\n }\n }\n\n return columnMap\n}\n"],"mappings":";AAgBA,SAAgBA,EACdC,GACuB;CACvB,IAAME,oBAAY,IAAID,KAAuB,EAIvCE,IAAQ;AAEd,MAAK,IAAMC,KAAOJ,GAAU;AAC1B,MAAI,OAAOI,KAAQ,SAAU;EAE7B,IAAMG,IADMH,EAAIE,
|
|
1
|
+
{"version":3,"file":"extractColumnValidationMessages.js","names":["extractColumnValidationMessages","messages","Map","columnMap","regex","raw","str","trimStart","match","columnName","trim","message","requiredKeyMatch","has","set","get","push"],"sources":["../../../../src/components/DataGrid/utils/extractColumnValidationMessages.ts"],"sourcesContent":["/**\n * Extracts column name and validation message from validation message strings.\n *\n * Example:\n * extractColumnValidationMessages([\"#/platform: null is not a valid enum value\"])\n * -> Map { \"platform\" => [\"null is not a valid enum value\"] }\n *\n * extractColumnValidationMessages([\"#/requiredNumberArrayColumn/0: some error\"])\n * -> Map { \"requiredNumberArrayColumn\" => [\"some error\"] }\n *\n * extractColumnValidationMessages([\"#: row-level error\"])\n * -> Map { \"_row\" => [\"row-level error\"] }\n *\n * extractColumnValidationMessages([\"#: required key [missingColumn] not found\"])\n * -> Map { \"missingColumn\" => [\"required key [missingColumn] not found\"] }\n */\nexport function extractColumnValidationMessages(\n messages: string[],\n): Map<string, string[]> {\n const columnMap = new Map<string, string[]>()\n // Validation message format: \"#/columnName: message\"\n // or for array items: \"#/columnName/0: message\"\n // or for object (row) level: \"#: message\"\n const regex = /^#(?:\\/([^/:]+)(?:\\/\\d+)?)?:\\s*(.*)$/\n\n for (const raw of messages) {\n if (typeof raw !== 'string') continue\n const str = raw.trimStart()\n const match = str.match(regex)\n if (match) {\n let columnName = match[1]?.trim() ?? '_row'\n const message = match[2].trim()\n if (columnName === '_row') {\n const requiredKeyMatch = message.match(\n /^required key \\[([^\\]]+)\\] not found$/i,\n )\n if (requiredKeyMatch) {\n columnName = requiredKeyMatch[1]\n }\n }\n\n if (!columnMap.has(columnName)) {\n columnMap.set(columnName, [])\n }\n columnMap.get(columnName)!.push(message)\n }\n }\n\n return columnMap\n}\n"],"mappings":";AAgBA,SAAgBA,EACdC,GACuB;CACvB,IAAME,oBAAY,IAAID,KAAuB,EAIvCE,IAAQ;AAEd,MAAK,IAAMC,KAAOJ,GAAU;AAC1B,MAAI,OAAOI,KAAQ,SAAU;EAE7B,IAAMG,IADMH,EAAIE,WACFD,CAAIE,MAAMJ,EAAM;AAC9B,MAAII,GAAO;GACT,IAAIC,IAAaD,EAAM,IAAIE,MAAM,IAAI,QAC/BC,IAAUH,EAAM,GAAGE,MAAM;AAC/B,OAAID,MAAe,QAAQ;IACzB,IAAMG,IAAmBD,EAAQH,MAC/B,yCACD;AACD,IAAII,MACFH,IAAaG,EAAiB;;AAOlCT,GAHKA,EAAUU,IAAIJ,EAAW,IAC5BN,EAAUW,IAAIL,GAAY,EAAE,CAAC,EAE/BN,EAAUY,IAAIN,EAAW,CAAEO,KAAKL,EAAQ;;;AAI5C,QAAOR"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getCellClassName.d.ts","sourceRoot":"","sources":["../../../../src/components/DataGrid/utils/getCellClassName.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,wCAAwC,CAAA;AACxE,OAAO,EAAE,MAAM,EAAE,MAAM,wCAAwC,CAAA;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA;AAEnE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE;IACvC,OAAO,EAAE,WAAW,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,aAAa,CAAC,EAAE,eAAe,GAAG,IAAI,CAAA;IACtC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,gBAAgB,CAAC,EAAE,SAAS,eAAe,EAAE,CAAA;CAC9C,GAAG,MAAM,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"getCellClassName.d.ts","sourceRoot":"","sources":["../../../../src/components/DataGrid/utils/getCellClassName.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,wCAAwC,CAAA;AACxE,OAAO,EAAE,MAAM,EAAE,MAAM,wCAAwC,CAAA;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA;AAEnE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE;IACvC,OAAO,EAAE,WAAW,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,aAAa,CAAC,EAAE,eAAe,GAAG,IAAI,CAAA;IACtC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,gBAAgB,CAAC,EAAE,SAAS,eAAe,EAAE,CAAA;CAC9C,GAAG,MAAM,GAAG,SAAS,CAyErB"}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import e from "classnames";
|
|
2
2
|
//#region src/components/DataGrid/utils/getCellClassName.ts
|
|
3
3
|
function t(t) {
|
|
4
|
-
let { rowData: n, rowIndex: r, columnId: i, selectedRowIndex: a, lastSelection: o, colValues: s, remoteSelections: c } = t, l = a === r, u = n.__cellValidationResults, d = u && i && u.has(i),
|
|
5
|
-
l &&
|
|
6
|
-
let
|
|
7
|
-
o && i && s && (
|
|
8
|
-
let
|
|
9
|
-
if (
|
|
4
|
+
let { rowData: n, rowIndex: r, columnId: i, selectedRowIndex: a, lastSelection: o, colValues: s, remoteSelections: c } = t, l = a === r, u = n.__cellValidationResults, d = n.__validationStatus, f = u != null && i != null && u.has(i), p = [];
|
|
5
|
+
l && p.push("cell-row-selected");
|
|
6
|
+
let m = !1;
|
|
7
|
+
o && i && s && (m = r >= o.min.row && r <= o.max.row && s.findIndex((e) => e.id === i) >= o.min.col && s.findIndex((e) => e.id === i) <= o.max.col, m && p.push("cell-selected")), f && (d === "invalid" && p.push("cell-invalid"), d === "pending" && p.push("cell-unknown"));
|
|
8
|
+
let h = i ? n.__cellChangeInfo?.[i] : void 0;
|
|
9
|
+
if (h && p.push(`cell-changed--${h.category}`), c && i) for (let e of c) {
|
|
10
10
|
let { minRow: t, maxRow: n, columnNames: a } = e.range;
|
|
11
11
|
if (!(r < t || r > n) && !(a !== void 0 && !a.has(i))) {
|
|
12
|
-
|
|
12
|
+
p.push("cell-remote-selected"), p.push(`cell-remote-selected--color-${e.colorIndex}`);
|
|
13
13
|
break;
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
return
|
|
16
|
+
return p.length ? e(p) : void 0;
|
|
17
17
|
}
|
|
18
18
|
//#endregion
|
|
19
19
|
export { t as getCellClassName };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getCellClassName.js","names":["classNames","DataGridRow","SelectionWithId","Column","RemoteSelection","getCellClassName","params","rowData","rowIndex","columnId","selectedRowIndex","lastSelection","colValues","remoteSelections","isSelected","cellValidationResults","__cellValidationResults","
|
|
1
|
+
{"version":3,"file":"getCellClassName.js","names":["classNames","DataGridRow","SelectionWithId","Column","RemoteSelection","getCellClassName","params","rowData","rowIndex","columnId","selectedRowIndex","lastSelection","colValues","remoteSelections","isSelected","cellValidationResults","__cellValidationResults","validationStatus","__validationStatus","hasCellError","has","classList","push","isInSelection","min","row","max","findIndex","col","id","cellChangeInfo","__cellChangeInfo","undefined","category","remote","minRow","maxRow","columnNames","remoteColumnNames","range","colorIndex","length"],"sources":["../../../../src/components/DataGrid/utils/getCellClassName.ts"],"sourcesContent":["import classNames from 'classnames'\nimport { DataGridRow } from '../DataGridTypes'\nimport { SelectionWithId } from '@sage-bionetworks/react-datasheet-grid'\nimport { Column } from '@sage-bionetworks/react-datasheet-grid'\nimport type { RemoteSelection } from '../hooks/useRemoteSelections'\n\nexport function getCellClassName(params: {\n rowData: DataGridRow\n rowIndex: number\n columnId?: string\n selectedRowIndex: number | null\n lastSelection?: SelectionWithId | null\n colValues?: Column[]\n remoteSelections?: readonly RemoteSelection[]\n}): string | undefined {\n const {\n rowData,\n rowIndex,\n columnId,\n selectedRowIndex,\n lastSelection,\n colValues,\n remoteSelections,\n } = params\n\n const isSelected = selectedRowIndex === rowIndex\n const cellValidationResults = rowData.__cellValidationResults\n const validationStatus = rowData.__validationStatus\n const hasCellError =\n cellValidationResults != null &&\n columnId != null &&\n cellValidationResults.has(columnId)\n\n const classList: string[] = []\n\n if (isSelected) {\n classList.push('cell-row-selected')\n }\n\n // Add selection styling based on lastSelection\n let isInSelection = false\n if (lastSelection && columnId && colValues) {\n isInSelection =\n rowIndex >= lastSelection.min.row &&\n rowIndex <= lastSelection.max.row &&\n colValues.findIndex(col => col.id === columnId) >=\n lastSelection.min.col &&\n colValues.findIndex(col => col.id === columnId) <= lastSelection.max.col\n\n if (isInSelection) {\n classList.push('cell-selected')\n }\n }\n\n if (hasCellError) {\n // Confirmed invalid — full red cell background\n if (validationStatus === 'invalid') {\n classList.push('cell-invalid')\n }\n // Pending revalidation — yellow cell background to signal the prior error is unconfirmed\n if (validationStatus === 'pending') {\n classList.push('cell-unknown')\n }\n }\n\n // ── Cell change indicator ─────────────────────────────────────────────────\n const cellChangeInfo = columnId\n ? rowData.__cellChangeInfo?.[columnId]\n : undefined\n if (cellChangeInfo) {\n classList.push(`cell-changed--${cellChangeInfo.category}`)\n }\n\n // ── Remote selection tint ─────────────────────────────────────────────────\n if (remoteSelections && columnId) {\n for (const remote of remoteSelections) {\n const { minRow, maxRow, columnNames: remoteColumnNames } = remote.range\n if (rowIndex < minRow || rowIndex > maxRow) continue\n if (remoteColumnNames !== undefined && !remoteColumnNames.has(columnId))\n continue\n classList.push('cell-remote-selected')\n classList.push(`cell-remote-selected--color-${remote.colorIndex}`)\n break // apply the first matching remote selection only\n }\n }\n\n return classList.length ? classNames(classList) : undefined\n}\n"],"mappings":";;AAMA,SAAgBK,EAAiBC,GAQV;CACrB,IAAM,EACJC,YACAC,aACAC,aACAC,qBACAC,kBACAC,cACAC,wBACEP,GAEEQ,IAAaJ,MAAqBF,GAClCO,IAAwBR,EAAQS,yBAChCC,IAAmBV,EAAQW,oBAC3BC,IACJJ,KAAyB,QACzBN,KAAY,QACZM,EAAsBK,IAAIX,EAAS,EAE/BY,IAAsB,EAAE;AAE9B,CAAIP,KACFO,EAAUC,KAAK,oBAAoB;CAIrC,IAAIC,IAAgB;AAcpB,CAbIZ,KAAiBF,KAAYG,MAC/BW,IACEf,KAAYG,EAAca,IAAIC,OAC9BjB,KAAYG,EAAce,IAAID,OAC9Bb,EAAUe,WAAUC,MAAOA,EAAIC,OAAOpB,EAAS,IAC7CE,EAAca,IAAII,OACpBhB,EAAUe,WAAUC,MAAOA,EAAIC,OAAOpB,EAAS,IAAIE,EAAce,IAAIE,KAEnEL,KACFF,EAAUC,KAAK,gBAAgB,GAI/BH,MAEEF,MAAqB,aACvBI,EAAUC,KAAK,eAAe,EAG5BL,MAAqB,aACvBI,EAAUC,KAAK,eAAe;CAKlC,IAAMQ,IAAiBrB,IACnBF,EAAQwB,mBAAmBtB,KAC3BuB,KAAAA;AAMJ,KALIF,KACFT,EAAUC,KAAK,iBAAiBQ,EAAeG,WAAW,EAIxDpB,KAAoBJ,EACtB,MAAK,IAAMyB,KAAUrB,GAAkB;EACrC,IAAM,EAAEsB,WAAQC,WAAQC,aAAaC,MAAsBJ,EAAOK;AAC9D/B,YAAW2B,KAAU3B,IAAW4B,MAChCE,QAAsBN,KAAAA,KAAa,CAACM,EAAkBlB,IAAIX,EAAS,GAGvEY;GADAA,EAAUC,KAAK,uBAAuB,EACtCD,EAAUC,KAAK,+BAA+BY,EAAOM,aAAa;AAClE;;;AAIJ,QAAOnB,EAAUoB,SAASzC,EAAWqB,EAAU,GAAGW,KAAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JsonRx.js","names":["JsonRxMessage","JsonRxNotification","NOTIFICATION_TYPE_CODE","JsonRxRequest","REQUEST_TYPE_CODE","JsonRxResponse","RESPONSE_TYPE_CODE","JsonRxResponseComplete","RESPONSE_COMPLETE_TYPE_CODE","JsonRxRequestComplete","REQUEST_COMPLETE_TYPE_CODE","JsonRx","fromJson","json","Array","isArray","Error","typeCode","_","requestId","methodName","payload","message"],"sources":["../../../../../src/components/DataGrid/utils/json-rx/JsonRx.ts"],"sourcesContent":["import JsonRxMessage from '@/components/DataGrid/utils/json-rx/JsonRxMessage'\nimport JsonRxNotification, {\n NOTIFICATION_TYPE_CODE,\n} from '@/components/DataGrid/utils/json-rx/JsonRxNotification'\nimport JsonRxRequest, {\n REQUEST_TYPE_CODE,\n} from '@/components/DataGrid/utils/json-rx/JsonRxRequest'\nimport JsonRxResponse, {\n RESPONSE_TYPE_CODE,\n} from '@/components/DataGrid/utils/json-rx/JsonRxResponse'\nimport JsonRxResponseComplete, {\n RESPONSE_COMPLETE_TYPE_CODE,\n} from '@/components/DataGrid/utils/json-rx/JsonRxResponseComplete'\nimport JsonRxRequestComplete, {\n REQUEST_COMPLETE_TYPE_CODE,\n} from './JsonRxRequestComplete'\n\n/**\n * Static utility methods intended to implement the JSON-Rx communication protocol\n * Spec: https://jsonjoy.com/specs/json-rx\n */\nexport default class JsonRx {\n /**\n * Converts a JSON-encoded JSON-Rx message (which is always an array) into the appropriate JsonRxMessage subclass\n *\n * For more information, see the JSON-Rx specification: https://jsonjoy.com/specs/json-rx\n * @param json\n */\n static fromJson(json: unknown): JsonRxMessage {\n if (!Array.isArray(json)) {\n throw new Error('Invalid JSON-Rx message: not an array')\n }\n const typeCode = json[0]\n\n if (typeof typeCode !== 'number') {\n throw new Error(\n `Invalid JSON-Rx message: type code is not a number, received ${typeCode}`,\n )\n }\n\n switch (typeCode) {\n case REQUEST_TYPE_CODE: {\n // Request\n const [_, requestId, methodName, payload] = json\n return new JsonRxRequest(requestId, methodName, payload)\n }\n case REQUEST_COMPLETE_TYPE_CODE: {\n const [_, requestId, methodName, payload] = json\n const message = new JsonRxRequestComplete(\n requestId,\n methodName,\n payload,\n )\n return message\n }\n case RESPONSE_TYPE_CODE: {\n // Response\n const [_, requestId, payload] = json\n return new JsonRxResponse(requestId, payload)\n }\n case RESPONSE_COMPLETE_TYPE_CODE: {\n // ResponseComplete\n const [_, requestId, payload] = json\n return new JsonRxResponseComplete(requestId, payload)\n }\n case NOTIFICATION_TYPE_CODE: {\n // Notification\n const [_, methodName, payload] = json\n return new JsonRxNotification(methodName, payload)\n }\n default:\n throw new Error(\n `Invalid JSON-Rx message: unknown type code ${typeCode}`,\n )\n }\n }\n}\n"],"mappings":";;;;;;AAqBA,IAAqBW,IAArB,MAA4B;CAO1B,OAAOC,SAASC,GAA8B;AAC5C,MAAI,CAACC,MAAMC,QAAQF,EAAK,CACtB,OAAUG,MAAM,wCAAwC;EAE1D,IAAMC,IAAWJ,EAAK;AAEtB,MAAI,OAAOI,KAAa,SACtB,OAAUD,MACR,gEAAgEC,IACjE;AAGH,UAAQA,GAAR;GACE,KAAA,GAAwB;IAEtB,IAAM,CAACC,GAAGC,GAAWC,GAAYC,KAAWR;AAC5C,WAAO,IAAIV,EAAcgB,GAAWC,GAAYC,EAAQ;;GAE1D,KAAA,GAAiC;IAC/B,IAAM,CAACH,GAAGC,GAAWC,GAAYC,KAAWR;AAM5C,
|
|
1
|
+
{"version":3,"file":"JsonRx.js","names":["JsonRxMessage","JsonRxNotification","NOTIFICATION_TYPE_CODE","JsonRxRequest","REQUEST_TYPE_CODE","JsonRxResponse","RESPONSE_TYPE_CODE","JsonRxResponseComplete","RESPONSE_COMPLETE_TYPE_CODE","JsonRxRequestComplete","REQUEST_COMPLETE_TYPE_CODE","JsonRx","fromJson","json","Array","isArray","Error","typeCode","_","requestId","methodName","payload","message"],"sources":["../../../../../src/components/DataGrid/utils/json-rx/JsonRx.ts"],"sourcesContent":["import JsonRxMessage from '@/components/DataGrid/utils/json-rx/JsonRxMessage'\nimport JsonRxNotification, {\n NOTIFICATION_TYPE_CODE,\n} from '@/components/DataGrid/utils/json-rx/JsonRxNotification'\nimport JsonRxRequest, {\n REQUEST_TYPE_CODE,\n} from '@/components/DataGrid/utils/json-rx/JsonRxRequest'\nimport JsonRxResponse, {\n RESPONSE_TYPE_CODE,\n} from '@/components/DataGrid/utils/json-rx/JsonRxResponse'\nimport JsonRxResponseComplete, {\n RESPONSE_COMPLETE_TYPE_CODE,\n} from '@/components/DataGrid/utils/json-rx/JsonRxResponseComplete'\nimport JsonRxRequestComplete, {\n REQUEST_COMPLETE_TYPE_CODE,\n} from './JsonRxRequestComplete'\n\n/**\n * Static utility methods intended to implement the JSON-Rx communication protocol\n * Spec: https://jsonjoy.com/specs/json-rx\n */\nexport default class JsonRx {\n /**\n * Converts a JSON-encoded JSON-Rx message (which is always an array) into the appropriate JsonRxMessage subclass\n *\n * For more information, see the JSON-Rx specification: https://jsonjoy.com/specs/json-rx\n * @param json\n */\n static fromJson(json: unknown): JsonRxMessage {\n if (!Array.isArray(json)) {\n throw new Error('Invalid JSON-Rx message: not an array')\n }\n const typeCode = json[0]\n\n if (typeof typeCode !== 'number') {\n throw new Error(\n `Invalid JSON-Rx message: type code is not a number, received ${typeCode}`,\n )\n }\n\n switch (typeCode) {\n case REQUEST_TYPE_CODE: {\n // Request\n const [_, requestId, methodName, payload] = json\n return new JsonRxRequest(requestId, methodName, payload)\n }\n case REQUEST_COMPLETE_TYPE_CODE: {\n const [_, requestId, methodName, payload] = json\n const message = new JsonRxRequestComplete(\n requestId,\n methodName,\n payload,\n )\n return message\n }\n case RESPONSE_TYPE_CODE: {\n // Response\n const [_, requestId, payload] = json\n return new JsonRxResponse(requestId, payload)\n }\n case RESPONSE_COMPLETE_TYPE_CODE: {\n // ResponseComplete\n const [_, requestId, payload] = json\n return new JsonRxResponseComplete(requestId, payload)\n }\n case NOTIFICATION_TYPE_CODE: {\n // Notification\n const [_, methodName, payload] = json\n return new JsonRxNotification(methodName, payload)\n }\n default:\n throw new Error(\n `Invalid JSON-Rx message: unknown type code ${typeCode}`,\n )\n }\n }\n}\n"],"mappings":";;;;;;AAqBA,IAAqBW,IAArB,MAA4B;CAO1B,OAAOC,SAASC,GAA8B;AAC5C,MAAI,CAACC,MAAMC,QAAQF,EAAK,CACtB,OAAUG,MAAM,wCAAwC;EAE1D,IAAMC,IAAWJ,EAAK;AAEtB,MAAI,OAAOI,KAAa,SACtB,OAAUD,MACR,gEAAgEC,IACjE;AAGH,UAAQA,GAAR;GACE,KAAA,GAAwB;IAEtB,IAAM,CAACC,GAAGC,GAAWC,GAAYC,KAAWR;AAC5C,WAAO,IAAIV,EAAcgB,GAAWC,GAAYC,EAAQ;;GAE1D,KAAA,GAAiC;IAC/B,IAAM,CAACH,GAAGC,GAAWC,GAAYC,KAAWR;AAM5C,WAAOS,IALab,EAClBU,GACAC,GACAC,EAEKC;;GAET,KAAA,GAAyB;IAEvB,IAAM,CAACJ,GAAGC,GAAWE,KAAWR;AAChC,WAAO,IAAIR,EAAec,GAAWE,EAAQ;;GAE/C,KAAA,GAAkC;IAEhC,IAAM,CAACH,GAAGC,GAAWE,KAAWR;AAChC,WAAO,IAAIN,EAAuBY,GAAWE,EAAQ;;GAEvD,KAAA,GAA6B;IAE3B,IAAM,CAACH,GAAGE,GAAYC,KAAWR;AACjC,WAAO,IAAIZ,EAAmBmB,GAAYC,EAAQ;;GAEpD,QACE,OAAUL,MACR,8CAA8CC,IAC/C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modelRowsToGrid.js","names":["DataGridRow","GridModel","GridModelSnapshot","isValidationUpToDateForRow","GRID_ROW_REACT_KEY_PROPERTY","logicalTimestampToString","extractColumnValidationMessages","modelRowsToGrid","model","modelSnapshot","columnNames","columnOrder","rows","gridRows","map","row","rowIndex","rowObj","forEach","index","columnName","data","api","obj","String","node","id","__validationResults","metadata","rowValidation","__validationStatus","isValid","allValidationMessages","__cellValidationResults"],"sources":["../../../../src/components/DataGrid/utils/modelRowsToGrid.ts"],"sourcesContent":["import {\n DataGridRow,\n GridModel,\n GridModelSnapshot,\n} from '@/components/DataGrid/DataGridTypes'\nimport { isValidationUpToDateForRow } from '@/components/DataGrid/utils/isValidationUpToDateForRow'\nimport { GRID_ROW_REACT_KEY_PROPERTY } from './DataGridUtils'\nimport logicalTimestampToString from '@/components/DataGrid/utils/logicalTimestampToString'\nimport { extractColumnValidationMessages } from './extractColumnValidationMessages'\n\n/**\n * Convert model rows to a format suitable for DataSheetGrid\n * @param model\n * @param modelSnapshot\n */\nexport default function modelRowsToGrid(\n model: GridModel | null,\n modelSnapshot: GridModelSnapshot,\n): DataGridRow[] {\n if (!model || !modelSnapshot) return []\n const { columnNames, columnOrder, rows } = modelSnapshot\n const gridRows = rows.map((row, rowIndex): DataGridRow => {\n const rowObj: DataGridRow = {}\n columnOrder.forEach((index: number) => {\n const columnName = columnNames[index]\n if (columnName) {\n rowObj[columnName] = row.data[index]\n }\n })\n\n // Embed the logical timestamp as a string for use as the React key (a stable value unique to each row)\n rowObj[GRID_ROW_REACT_KEY_PROPERTY] = logicalTimestampToString(\n model.api.obj(['rows', String(rowIndex)]).node.id,\n )\n\n rowObj.__validationResults = row.metadata?.rowValidation\n if (rowObj.__validationResults) {\n rowObj.__validationStatus = rowObj.__validationResults?.isValid\n ? 'valid'\n : 'invalid'\n }\n\n if (!isValidationUpToDateForRow(model, rowIndex)) {\n rowObj.__validationStatus = 'pending'\n }\n\n // Parse the validation messages into a Map of column name to messages\n if (rowObj.__validationResults?.allValidationMessages) {\n rowObj.__cellValidationResults = extractColumnValidationMessages(\n rowObj.__validationResults.allValidationMessages,\n )\n }\n\n return rowObj\n })\n return gridRows\n}\n"],"mappings":";;;;;AAeA,SAAwBO,EACtBC,GACAC,GACe;AACf,KAAI,CAACD,KAAS,CAACC,EAAe,QAAO,EAAE;CACvC,IAAM,EAAEC,gBAAaC,gBAAaC,YAASH;AAmC3C,QAlCiBG,EAAKE,KAAKC,GAAKC,MAA0B;EACxD,IAAMC,IAAsB,EAAE;AA+B9B,SA9BAN,EAAYO,SAASC,MAAkB;GACrC,IAAMC,IAAaV,EAAYS;AAC/B,GAAIC,MACFH,EAAOG,KAAcL,EAAIM,KAAKF;IAEhC,EAGFF,EAAOb,KAA+BC,EACpCG,EAAMc,IAAIC,IAAI,CAAC,QAAQC,OAAOR,EAAS,CAAC,CAAC,CAACS,KAAKC,GAChD,EAEDT,EAAOU,sBAAsBZ,EAAIa,UAAUC,eACvCZ,EAAOU,wBACTV,EAAOa,qBAAqBb,EAAOU,qBAAqBI,UACpD,UACA,YAGD5B,EAA2BK,GAAOQ,EAAS,KAC9CC,EAAOa,qBAAqB,YAI1Bb,EAAOU,qBAAqBK,0BAC9Bf,EAAOgB,0BAA0B3B,EAC/BW,EAAOU,oBAAoBK,sBAC5B,GAGIf;
|
|
1
|
+
{"version":3,"file":"modelRowsToGrid.js","names":["DataGridRow","GridModel","GridModelSnapshot","isValidationUpToDateForRow","GRID_ROW_REACT_KEY_PROPERTY","logicalTimestampToString","extractColumnValidationMessages","modelRowsToGrid","model","modelSnapshot","columnNames","columnOrder","rows","gridRows","map","row","rowIndex","rowObj","forEach","index","columnName","data","api","obj","String","node","id","__validationResults","metadata","rowValidation","__validationStatus","isValid","allValidationMessages","__cellValidationResults"],"sources":["../../../../src/components/DataGrid/utils/modelRowsToGrid.ts"],"sourcesContent":["import {\n DataGridRow,\n GridModel,\n GridModelSnapshot,\n} from '@/components/DataGrid/DataGridTypes'\nimport { isValidationUpToDateForRow } from '@/components/DataGrid/utils/isValidationUpToDateForRow'\nimport { GRID_ROW_REACT_KEY_PROPERTY } from './DataGridUtils'\nimport logicalTimestampToString from '@/components/DataGrid/utils/logicalTimestampToString'\nimport { extractColumnValidationMessages } from './extractColumnValidationMessages'\n\n/**\n * Convert model rows to a format suitable for DataSheetGrid\n * @param model\n * @param modelSnapshot\n */\nexport default function modelRowsToGrid(\n model: GridModel | null,\n modelSnapshot: GridModelSnapshot,\n): DataGridRow[] {\n if (!model || !modelSnapshot) return []\n const { columnNames, columnOrder, rows } = modelSnapshot\n const gridRows = rows.map((row, rowIndex): DataGridRow => {\n const rowObj: DataGridRow = {}\n columnOrder.forEach((index: number) => {\n const columnName = columnNames[index]\n if (columnName) {\n rowObj[columnName] = row.data[index]\n }\n })\n\n // Embed the logical timestamp as a string for use as the React key (a stable value unique to each row)\n rowObj[GRID_ROW_REACT_KEY_PROPERTY] = logicalTimestampToString(\n model.api.obj(['rows', String(rowIndex)]).node.id,\n )\n\n rowObj.__validationResults = row.metadata?.rowValidation\n if (rowObj.__validationResults) {\n rowObj.__validationStatus = rowObj.__validationResults?.isValid\n ? 'valid'\n : 'invalid'\n }\n\n if (!isValidationUpToDateForRow(model, rowIndex)) {\n rowObj.__validationStatus = 'pending'\n }\n\n // Parse the validation messages into a Map of column name to messages\n if (rowObj.__validationResults?.allValidationMessages) {\n rowObj.__cellValidationResults = extractColumnValidationMessages(\n rowObj.__validationResults.allValidationMessages,\n )\n }\n\n return rowObj\n })\n return gridRows\n}\n"],"mappings":";;;;;AAeA,SAAwBO,EACtBC,GACAC,GACe;AACf,KAAI,CAACD,KAAS,CAACC,EAAe,QAAO,EAAE;CACvC,IAAM,EAAEC,gBAAaC,gBAAaC,YAASH;AAmC3C,QAlCiBG,EAAKE,KAAKC,GAAKC,MAA0B;EACxD,IAAMC,IAAsB,EAAE;AA+B9B,SA9BAN,EAAYO,SAASC,MAAkB;GACrC,IAAMC,IAAaV,EAAYS;AAC/B,GAAIC,MACFH,EAAOG,KAAcL,EAAIM,KAAKF;IAEhC,EAGFF,EAAOb,KAA+BC,EACpCG,EAAMc,IAAIC,IAAI,CAAC,QAAQC,OAAOR,EAAS,CAAC,CAAC,CAACS,KAAKC,GAChD,EAEDT,EAAOU,sBAAsBZ,EAAIa,UAAUC,eACvCZ,EAAOU,wBACTV,EAAOa,qBAAqBb,EAAOU,qBAAqBI,UACpD,UACA,YAGD5B,EAA2BK,GAAOQ,EAAS,KAC9CC,EAAOa,qBAAqB,YAI1Bb,EAAOU,qBAAqBK,0BAC9Bf,EAAOgB,0BAA0B3B,EAC/BW,EAAOU,oBAAoBK,sBAC5B,GAGIf;GAEFJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseFreeTextUsingJsonSchemaType.js","names":["JSONSchema7Type","parseFreeTextGivenJsonSchemaType","freeText","colType","String","trim","parsed","parseInt","Number","isNaN","toLowerCase","JSON","parse","e"],"sources":["../../../../src/components/DataGrid/utils/parseFreeTextUsingJsonSchemaType.ts"],"sourcesContent":["import { JSONSchema7Type } from 'json-schema'\n\nexport default function parseFreeTextGivenJsonSchemaType(\n freeText: string,\n colType?: JSONSchema7Type,\n): unknown {\n if (!colType || colType === 'string') {\n return String(freeText)\n } else if (colType === 'number' || colType === 'integer') {\n if (freeText.trim() === '') {\n // empty string parse result is 0, so treat it as empty\n return freeText\n }\n let parsed: number\n if (colType === 'integer') {\n parsed = parseInt(freeText, 10)\n } else {\n parsed = Number(freeText)\n }\n if (!isNaN(parsed)) {\n return parsed\n } else {\n return freeText\n }\n } else if (colType === 'boolean') {\n if (freeText.toLowerCase() === 'true') {\n return true\n } else if (freeText.toLowerCase() === 'false') {\n return false\n } else {\n return freeText\n }\n } else if (colType === 'object' || colType === 'array') {\n try {\n const parsed = JSON.parse(freeText)\n return parsed\n } catch (e) {\n // If we can't parse it, just set it to the input value\n return freeText\n }\n } else if (colType === 'null') {\n if (freeText.toLowerCase() === 'null' || freeText.trim() === '') {\n return null\n } else {\n return freeText\n }\n } else {\n // Unknown type, just set it to the input value\n return freeText\n }\n}\n"],"mappings":";AAEA,SAAwBC,EACtBC,GACAC,GACS;AACT,KAAI,CAACA,KAAWA,MAAY,SAC1B,QAAOC,OAAOF,EAAS;KACdC,MAAY,YAAYA,MAAY,WAAW;AACxD,MAAID,EAASG,MAAM,KAAK,GAEtB,QAAOH;EAET,IAAII;AAOF,SANF,AAGEA,IAHEH,MAAY,YACLI,SAASL,GAAU,GAAG,GAEtBM,OAAON,EAAS,EAEtBO,MAAMH,EAAO,GAGTJ,IAFAI;YAIAH,MAAY,UAMnB,QALED,EAASQ,aAAa,KAAK,SACtB,KACER,EAASQ,aAAa,KAAK,UAC7B,KAEAR;UAEAC,MAAY,YAAYA,MAAY,QAC7C,KAAI;AAEF,SADeQ,KAAKC,MAAMV,
|
|
1
|
+
{"version":3,"file":"parseFreeTextUsingJsonSchemaType.js","names":["JSONSchema7Type","parseFreeTextGivenJsonSchemaType","freeText","colType","String","trim","parsed","parseInt","Number","isNaN","toLowerCase","JSON","parse","e"],"sources":["../../../../src/components/DataGrid/utils/parseFreeTextUsingJsonSchemaType.ts"],"sourcesContent":["import { JSONSchema7Type } from 'json-schema'\n\nexport default function parseFreeTextGivenJsonSchemaType(\n freeText: string,\n colType?: JSONSchema7Type,\n): unknown {\n if (!colType || colType === 'string') {\n return String(freeText)\n } else if (colType === 'number' || colType === 'integer') {\n if (freeText.trim() === '') {\n // empty string parse result is 0, so treat it as empty\n return freeText\n }\n let parsed: number\n if (colType === 'integer') {\n parsed = parseInt(freeText, 10)\n } else {\n parsed = Number(freeText)\n }\n if (!isNaN(parsed)) {\n return parsed\n } else {\n return freeText\n }\n } else if (colType === 'boolean') {\n if (freeText.toLowerCase() === 'true') {\n return true\n } else if (freeText.toLowerCase() === 'false') {\n return false\n } else {\n return freeText\n }\n } else if (colType === 'object' || colType === 'array') {\n try {\n const parsed = JSON.parse(freeText)\n return parsed\n } catch (e) {\n // If we can't parse it, just set it to the input value\n return freeText\n }\n } else if (colType === 'null') {\n if (freeText.toLowerCase() === 'null' || freeText.trim() === '') {\n return null\n } else {\n return freeText\n }\n } else {\n // Unknown type, just set it to the input value\n return freeText\n }\n}\n"],"mappings":";AAEA,SAAwBC,EACtBC,GACAC,GACS;AACT,KAAI,CAACA,KAAWA,MAAY,SAC1B,QAAOC,OAAOF,EAAS;KACdC,MAAY,YAAYA,MAAY,WAAW;AACxD,MAAID,EAASG,MAAM,KAAK,GAEtB,QAAOH;EAET,IAAII;AAOF,SANF,AAGEA,IAHEH,MAAY,YACLI,SAASL,GAAU,GAAG,GAEtBM,OAAON,EAAS,EAEtBO,MAAMH,EAAO,GAGTJ,IAFAI;YAIAH,MAAY,UAMnB,QALED,EAASQ,aAAa,KAAK,SACtB,KACER,EAASQ,aAAa,KAAK,UAC7B,KAEAR;UAEAC,MAAY,YAAYA,MAAY,QAC7C,KAAI;AAEF,SADeQ,KAAKC,MAAMV,EACnBI;SACG;AAEV,SAAOJ;;UAEAC,MAAY,OAInB,QAHED,EAASQ,aAAa,KAAK,UAAUR,EAASG,MAAM,KAAK,KACpD,OAEAH;KAIT,QAAOA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"splitPatch.js","names":["Patch","CompactCodecPatch","decode","encode","CompactCodecOperation","CompactCodecTimestamp","getPatchSizeInBytes","patch","TextEncoder","JSON","stringify","length","computeNextPatchHeader","lastPatch","decodedPatch","lastPatchHeader","getId","lastPatchSpan","span","sid","time","splitPatch","maxPatchSizeBytes","ops","binaryEncodedPatch","sizeOfFullPatch","console","warn","firstPatchHeader","splitPatches","currentSplitPatch","i","currentSplitPatchOpCount","sizeOfCurrentSplitPatchWithNextOp","push"],"sources":["../../../../src/components/DataGrid/utils/splitPatch.ts"],"sourcesContent":["import { Patch } from 'json-joy/lib/json-crdt'\nimport {\n CompactCodecPatch,\n decode,\n encode,\n} from 'json-joy/lib/json-crdt-patch/codec/compact'\nimport {\n CompactCodecOperation,\n CompactCodecTimestamp,\n} from 'json-joy/lib/json-crdt-patch/codec/compact/types'\n\n/**\n * Calculates the size in bytes of the UTF-8 string representation of a compact-encoded JSON CRDT Patch.\n * This is useful for determining the size of patch that will be sent in a WebSocket connection, which requires UTF-8\n * encoding.\n * @param patch the compact-encoded JSON CRDT Patch\n * @returns the size in bytes of the UTF-8 string representation of the patch\n */\nexport function getPatchSizeInBytes(patch: CompactCodecPatch): number {\n return new TextEncoder().encode(JSON.stringify(patch)).length\n}\n\n/**\n * Computes the header for the next JSON CRDT patch based on the last patch.\n * @param lastPatch - the previous JSON CRDT patch\n * @returns the header for the next patch, which includes the replica ID and the next timestamp\n */\nfunction computeNextPatchHeader(\n lastPatch: CompactCodecPatch,\n): [CompactCodecTimestamp] {\n // TODO: Compute the next patch header without decoding the entire patch\n // decoding it is inefficient, but easy because it lets us easily compute the span.\n const decodedPatch = decode(lastPatch)\n\n const lastPatchHeader = decodedPatch.getId()!\n const lastPatchSpan = decodedPatch.span()\n\n return [[lastPatchHeader?.sid, lastPatchHeader.time + lastPatchSpan]]\n}\n\n/**\n * Given a json-joy JSON CRDT Patch, splits it into multiple patches if its compact encoding\n * exceeds the specified maximum size in bytes.\n * @param patch\n * @param maxPatchSizeBytes\n * @returns An array of patches that are compact-encoded. Each patch is guaranteed to be within the specified size limit, or to only contain\n * a single operation if it cannot be split further.\n */\nexport function splitPatch(\n patch: Patch,\n maxPatchSizeBytes: number,\n): CompactCodecPatch[] {\n if (!patch.ops || patch.ops.length === 0) {\n return []\n }\n\n const binaryEncodedPatch = encode(patch)\n const sizeOfFullPatch = getPatchSizeInBytes(binaryEncodedPatch)\n\n // Check if this patch needs to be split\n if (sizeOfFullPatch <= maxPatchSizeBytes) {\n return [binaryEncodedPatch]\n }\n\n if (patch.ops.length == 1) {\n console.warn(\n `Patch is too large (${sizeOfFullPatch} B) but cannot be split further since it only contains one operation.`,\n )\n return [binaryEncodedPatch]\n }\n\n const firstPatchHeader = binaryEncodedPatch[0]\n const splitPatches: CompactCodecPatch[] = []\n let currentSplitPatch: CompactCodecPatch = [firstPatchHeader]\n for (let i = 1; i < binaryEncodedPatch.length; i += 1) {\n const currentSplitPatchOpCount = currentSplitPatch.length - 1 // Exclude header\n const sizeOfCurrentSplitPatchWithNextOp = getPatchSizeInBytes([\n ...currentSplitPatch,\n binaryEncodedPatch[i] as CompactCodecOperation,\n ])\n if (\n sizeOfCurrentSplitPatchWithNextOp > maxPatchSizeBytes &&\n currentSplitPatchOpCount > 0\n ) {\n splitPatches.push(currentSplitPatch)\n currentSplitPatch = [computeNextPatchHeader(currentSplitPatch)]\n }\n currentSplitPatch.push(binaryEncodedPatch[i] as CompactCodecOperation)\n }\n if (currentSplitPatch.length > 1) {\n splitPatches.push(currentSplitPatch)\n }\n\n return splitPatches\n}\n"],"mappings":";;AAkBA,SAAgBM,EAAoBC,GAAkC;AACpE,QAAO,IAAIC,aAAa,CAACL,OAAOM,KAAKC,UAAUH,EAAM,CAAC,CAACI;;AAQzD,SAASC,EACPC,GACyB;CAGzB,IAAMC,IAAeZ,EAAOW,EAAU,EAEhCE,IAAkBD,EAAaE,OAAO,EACtCC,IAAgBH,EAAaI,MAAM;AAEzC,QAAO,CAAC,CAACH,GAAiBI,KAAKJ,EAAgBK,OAAOH,EAAc,CAAC;;AAWvE,SAAgBI,EACdd,GACAe,GACqB;AACrB,KAAI,CAACf,EAAMgB,OAAOhB,EAAMgB,IAAIZ,WAAW,EACrC,QAAO,EAAE;CAGX,IAAMa,IAAqBrB,EAAOI,EAAM,EAClCkB,IAAkBnB,EAAoBkB,EAAmB;AAG/D,KAAIC,KAAmBH,EACrB,QAAO,CAACE,EAAmB;AAG7B,KAAIjB,EAAMgB,IAAIZ,UAAU,EAItB,QAHAe,QAAQC,KACN,uBAAuBF,EAAe,uEACvC,EACM,CAACD,EAAmB;CAG7B,IAAMI,IAAmBJ,EAAmB,IACtCK,IAAoC,EAAE,EACxCC,IAAuC,CAACF,EAAiB;AAC7D,MAAK,IAAIG,IAAI,GAAGA,IAAIP,EAAmBb,QAAQoB,KAAK,GAAG;EACrD,IAAMC,IAA2BF,EAAkBnB,SAAS;AAY5DmB,EAX0CxB,EAAoB,CAC5D,GAAGwB,GACHN,EAAmBO,GACpB,
|
|
1
|
+
{"version":3,"file":"splitPatch.js","names":["Patch","CompactCodecPatch","decode","encode","CompactCodecOperation","CompactCodecTimestamp","getPatchSizeInBytes","patch","TextEncoder","JSON","stringify","length","computeNextPatchHeader","lastPatch","decodedPatch","lastPatchHeader","getId","lastPatchSpan","span","sid","time","splitPatch","maxPatchSizeBytes","ops","binaryEncodedPatch","sizeOfFullPatch","console","warn","firstPatchHeader","splitPatches","currentSplitPatch","i","currentSplitPatchOpCount","sizeOfCurrentSplitPatchWithNextOp","push"],"sources":["../../../../src/components/DataGrid/utils/splitPatch.ts"],"sourcesContent":["import { Patch } from 'json-joy/lib/json-crdt'\nimport {\n CompactCodecPatch,\n decode,\n encode,\n} from 'json-joy/lib/json-crdt-patch/codec/compact'\nimport {\n CompactCodecOperation,\n CompactCodecTimestamp,\n} from 'json-joy/lib/json-crdt-patch/codec/compact/types'\n\n/**\n * Calculates the size in bytes of the UTF-8 string representation of a compact-encoded JSON CRDT Patch.\n * This is useful for determining the size of patch that will be sent in a WebSocket connection, which requires UTF-8\n * encoding.\n * @param patch the compact-encoded JSON CRDT Patch\n * @returns the size in bytes of the UTF-8 string representation of the patch\n */\nexport function getPatchSizeInBytes(patch: CompactCodecPatch): number {\n return new TextEncoder().encode(JSON.stringify(patch)).length\n}\n\n/**\n * Computes the header for the next JSON CRDT patch based on the last patch.\n * @param lastPatch - the previous JSON CRDT patch\n * @returns the header for the next patch, which includes the replica ID and the next timestamp\n */\nfunction computeNextPatchHeader(\n lastPatch: CompactCodecPatch,\n): [CompactCodecTimestamp] {\n // TODO: Compute the next patch header without decoding the entire patch\n // decoding it is inefficient, but easy because it lets us easily compute the span.\n const decodedPatch = decode(lastPatch)\n\n const lastPatchHeader = decodedPatch.getId()!\n const lastPatchSpan = decodedPatch.span()\n\n return [[lastPatchHeader?.sid, lastPatchHeader.time + lastPatchSpan]]\n}\n\n/**\n * Given a json-joy JSON CRDT Patch, splits it into multiple patches if its compact encoding\n * exceeds the specified maximum size in bytes.\n * @param patch\n * @param maxPatchSizeBytes\n * @returns An array of patches that are compact-encoded. Each patch is guaranteed to be within the specified size limit, or to only contain\n * a single operation if it cannot be split further.\n */\nexport function splitPatch(\n patch: Patch,\n maxPatchSizeBytes: number,\n): CompactCodecPatch[] {\n if (!patch.ops || patch.ops.length === 0) {\n return []\n }\n\n const binaryEncodedPatch = encode(patch)\n const sizeOfFullPatch = getPatchSizeInBytes(binaryEncodedPatch)\n\n // Check if this patch needs to be split\n if (sizeOfFullPatch <= maxPatchSizeBytes) {\n return [binaryEncodedPatch]\n }\n\n if (patch.ops.length == 1) {\n console.warn(\n `Patch is too large (${sizeOfFullPatch} B) but cannot be split further since it only contains one operation.`,\n )\n return [binaryEncodedPatch]\n }\n\n const firstPatchHeader = binaryEncodedPatch[0]\n const splitPatches: CompactCodecPatch[] = []\n let currentSplitPatch: CompactCodecPatch = [firstPatchHeader]\n for (let i = 1; i < binaryEncodedPatch.length; i += 1) {\n const currentSplitPatchOpCount = currentSplitPatch.length - 1 // Exclude header\n const sizeOfCurrentSplitPatchWithNextOp = getPatchSizeInBytes([\n ...currentSplitPatch,\n binaryEncodedPatch[i] as CompactCodecOperation,\n ])\n if (\n sizeOfCurrentSplitPatchWithNextOp > maxPatchSizeBytes &&\n currentSplitPatchOpCount > 0\n ) {\n splitPatches.push(currentSplitPatch)\n currentSplitPatch = [computeNextPatchHeader(currentSplitPatch)]\n }\n currentSplitPatch.push(binaryEncodedPatch[i] as CompactCodecOperation)\n }\n if (currentSplitPatch.length > 1) {\n splitPatches.push(currentSplitPatch)\n }\n\n return splitPatches\n}\n"],"mappings":";;AAkBA,SAAgBM,EAAoBC,GAAkC;AACpE,QAAO,IAAIC,aAAa,CAACL,OAAOM,KAAKC,UAAUH,EAAM,CAAC,CAACI;;AAQzD,SAASC,EACPC,GACyB;CAGzB,IAAMC,IAAeZ,EAAOW,EAAU,EAEhCE,IAAkBD,EAAaE,OAAO,EACtCC,IAAgBH,EAAaI,MAAM;AAEzC,QAAO,CAAC,CAACH,GAAiBI,KAAKJ,EAAgBK,OAAOH,EAAc,CAAC;;AAWvE,SAAgBI,EACdd,GACAe,GACqB;AACrB,KAAI,CAACf,EAAMgB,OAAOhB,EAAMgB,IAAIZ,WAAW,EACrC,QAAO,EAAE;CAGX,IAAMa,IAAqBrB,EAAOI,EAAM,EAClCkB,IAAkBnB,EAAoBkB,EAAmB;AAG/D,KAAIC,KAAmBH,EACrB,QAAO,CAACE,EAAmB;AAG7B,KAAIjB,EAAMgB,IAAIZ,UAAU,EAItB,QAHAe,QAAQC,KACN,uBAAuBF,EAAe,uEACvC,EACM,CAACD,EAAmB;CAG7B,IAAMI,IAAmBJ,EAAmB,IACtCK,IAAoC,EAAE,EACxCC,IAAuC,CAACF,EAAiB;AAC7D,MAAK,IAAIG,IAAI,GAAGA,IAAIP,EAAmBb,QAAQoB,KAAK,GAAG;EACrD,IAAMC,IAA2BF,EAAkBnB,SAAS;AAY5DmB,EAX0CxB,EAAoB,CAC5D,GAAGwB,GACHN,EAAmBO,GACpB,CAECE,GAAoCX,KACpCU,IAA2B,MAE3BH,EAAaK,KAAKJ,EAAkB,EACpCA,IAAoB,CAAClB,EAAuBkB,EAAkB,CAAC,GAEjEA,EAAkBI,KAAKV,EAAmBO,GAA4B;;AAMxE,QAJID,EAAkBnB,SAAS,KAC7BkB,EAAaK,KAAKJ,EAAkB,EAG/BD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DateTimePicker.js","names":[],"sources":["../../../src/components/DateTimePicker/DateTimePicker.tsx"],"sourcesContent":["import { useSynapseContext } from '@/utils'\nimport { Box, InputBaseProps, TextField, TextFieldProps } from '@mui/material'\nimport { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'\nimport {\n DateTimePicker as MuiDateTimePicker,\n DateTimePickerProps as MuiDateTimePickerProps,\n} from '@mui/x-date-pickers/DateTimePicker'\nimport { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'\nimport dayjs from 'dayjs'\nimport advancedFormat from 'dayjs/plugin/advancedFormat'\nimport timezone from 'dayjs/plugin/timezone'\nimport utc from 'dayjs/plugin/utc'\nimport { useMemo } from 'react'\n\ndayjs.extend(utc)\ndayjs.extend(timezone)\ndayjs.extend(advancedFormat)\n\nfunction TextFieldWithTzShown(props: TextFieldProps) {\n const { utcTime } = useSynapseContext()\n const tzDisplay = utcTime ? 'UTC' : dayjs().tz(dayjs.tz.guess()).format('z')\n\n return (\n <TextField\n {...props}\n slotProps={{\n input: {\n ...props.slotProps?.input,\n endAdornment: (\n <>\n <Box\n sx={{\n ml: 0.5,\n }}\n >\n {tzDisplay}\n </Box>\n {\n (props.slotProps?.input as InputBaseProps | undefined)\n ?.endAdornment\n }\n </>\n ),\n },\n }}\n />\n )\n}\n\nexport default function DateTimePicker(props: MuiDateTimePickerProps) {\n const { value, slots, ...rest } = props\n const { utcTime } = useSynapseContext()\n\n const valueAsDayjs = useMemo(() => {\n if (value == null) {\n return value\n }\n if (utcTime) {\n return dayjs.utc(value)\n } else {\n return dayjs(value)\n }\n }, [utcTime, value])\n\n return (\n <LocalizationProvider dateAdapter={AdapterDayjs}>\n <MuiDateTimePicker\n enableAccessibleFieldDOMStructure={false}\n value={valueAsDayjs}\n slots={{\n ...slots,\n textField: TextFieldWithTzShown,\n }}\n {...rest}\n />\n </LocalizationProvider>\n )\n}\n"],"mappings":";;;;;;;;;;;;AAcA,EAAM,OAAO,EAAI,EACjB,EAAM,OAAO,EAAS,EACtB,EAAM,OAAO,EAAe;AAE5B,SAAS,EAAqB,GAAuB;CACnD,IAAM,EAAE,eAAY,GAAmB,EACjC,IAAY,IAAU,QAAQ,GAAO,CAAC,GAAG,EAAM,GAAG,OAAO,CAAC,CAAC,OAAO,IAAI;AAE5E,QACE,kBAAC,GAAD;EACE,GAAI;EACJ,WAAW,EACT,OAAO;GACL,GAAG,EAAM,WAAW;GACpB,cACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;IACE,IAAI,EACF,IAAI,IACL;cAEA;IACG,CAAA,EAEH,EAAM,WAAW,OACd,aAEL,EAAA,CAAA;GAEN,EACF;EACD,CAAA;;AAIN,SAAwB,EAAe,GAA+B;CACpE,IAAM,EAAE,UAAO,UAAO,GAAG,MAAS,GAC5B,EAAE,eAAY,GAAmB;AAavC,QACE,kBAAC,GAAD;EAAsB,aAAa;YACjC,kBAAC,GAAD;GACE,mCAAmC;GACnC,OAfe,QACf,KAAS,OACJ,IAEL,IACK,EAAM,IAAI,EAAM,GAEhB,EAAM,EAAM,EAEpB,CAAC,GAAS,EAAM,
|
|
1
|
+
{"version":3,"file":"DateTimePicker.js","names":[],"sources":["../../../src/components/DateTimePicker/DateTimePicker.tsx"],"sourcesContent":["import { useSynapseContext } from '@/utils'\nimport { Box, InputBaseProps, TextField, TextFieldProps } from '@mui/material'\nimport { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'\nimport {\n DateTimePicker as MuiDateTimePicker,\n DateTimePickerProps as MuiDateTimePickerProps,\n} from '@mui/x-date-pickers/DateTimePicker'\nimport { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'\nimport dayjs from 'dayjs'\nimport advancedFormat from 'dayjs/plugin/advancedFormat'\nimport timezone from 'dayjs/plugin/timezone'\nimport utc from 'dayjs/plugin/utc'\nimport { useMemo } from 'react'\n\ndayjs.extend(utc)\ndayjs.extend(timezone)\ndayjs.extend(advancedFormat)\n\nfunction TextFieldWithTzShown(props: TextFieldProps) {\n const { utcTime } = useSynapseContext()\n const tzDisplay = utcTime ? 'UTC' : dayjs().tz(dayjs.tz.guess()).format('z')\n\n return (\n <TextField\n {...props}\n slotProps={{\n input: {\n ...props.slotProps?.input,\n endAdornment: (\n <>\n <Box\n sx={{\n ml: 0.5,\n }}\n >\n {tzDisplay}\n </Box>\n {\n (props.slotProps?.input as InputBaseProps | undefined)\n ?.endAdornment\n }\n </>\n ),\n },\n }}\n />\n )\n}\n\nexport default function DateTimePicker(props: MuiDateTimePickerProps) {\n const { value, slots, ...rest } = props\n const { utcTime } = useSynapseContext()\n\n const valueAsDayjs = useMemo(() => {\n if (value == null) {\n return value\n }\n if (utcTime) {\n return dayjs.utc(value)\n } else {\n return dayjs(value)\n }\n }, [utcTime, value])\n\n return (\n <LocalizationProvider dateAdapter={AdapterDayjs}>\n <MuiDateTimePicker\n enableAccessibleFieldDOMStructure={false}\n value={valueAsDayjs}\n slots={{\n ...slots,\n textField: TextFieldWithTzShown,\n }}\n {...rest}\n />\n </LocalizationProvider>\n )\n}\n"],"mappings":";;;;;;;;;;;;AAcA,EAAM,OAAO,EAAI,EACjB,EAAM,OAAO,EAAS,EACtB,EAAM,OAAO,EAAe;AAE5B,SAAS,EAAqB,GAAuB;CACnD,IAAM,EAAE,eAAY,GAAmB,EACjC,IAAY,IAAU,QAAQ,GAAO,CAAC,GAAG,EAAM,GAAG,OAAO,CAAC,CAAC,OAAO,IAAI;AAE5E,QACE,kBAAC,GAAD;EACE,GAAI;EACJ,WAAW,EACT,OAAO;GACL,GAAG,EAAM,WAAW;GACpB,cACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;IACE,IAAI,EACF,IAAI,IACL;cAEA;IACG,CAAA,EAEH,EAAM,WAAW,OACd,aAEL,EAAA,CAAA;GAEN,EACF;EACD,CAAA;;AAIN,SAAwB,EAAe,GAA+B;CACpE,IAAM,EAAE,UAAO,UAAO,GAAG,MAAS,GAC5B,EAAE,eAAY,GAAmB;AAavC,QACE,kBAAC,GAAD;EAAsB,aAAa;YACjC,kBAAC,GAAD;GACE,mCAAmC;GACnC,OAfe,QACf,KAAS,OACJ,IAEL,IACK,EAAM,IAAI,EAAM,GAEhB,EAAM,EAAM,EAEpB,CAAC,GAAS,EAAM,CAMN;GACP,OAAO;IACL,GAAG;IACH,WAAW;IACZ;GACD,GAAI;GACJ,CAAA;EACmB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DirectDownload.js","names":[],"sources":["../../../src/components/DirectDownload/DirectDownload.tsx"],"sourcesContent":["import { useGetFileBatch } from '@/synapse-queries/file/useFiles'\nimport { implementsExternalFileHandleInterface } from '@/utils/types/IsType'\nimport { Tooltip } from '@mui/material'\nimport {\n ExternalFileHandle,\n FileHandleAssociateType,\n} from '@sage-bionetworks/synapse-types'\nimport { forwardRef } from 'react'\nimport IconSvg, { IconSvgProps } from '../IconSvg/IconSvg'\nimport { TOOLTIP_DELAY_SHOW } from '../SynapseTable/SynapseTableConstants'\nimport { useDirectDownloadHandler } from '@/utils/hooks/useDirectDownloadHandler'\n\nexport type DirectFileDownloadProps = {\n associatedObjectId: string\n associatedObjectType: FileHandleAssociateType\n fileHandleId: string\n displayFileName?: boolean\n onClickCallback?: (isExternalLink: boolean) => void // callback if you want to know when the link was clicked\n stopPropagation?: boolean\n iconSvgPropOverrides?: Partial<IconSvgProps>\n}\n\ntype DirectDownloadIconProps = {\n isExternalFile?: boolean\n hasFileAccess: boolean\n onClick?: (isExternalFile: boolean) => void\n getDownloadLink: () => Promise<void>\n stopPropagation: boolean\n externalURL?: string\n displayFileName: boolean\n fileName?: string\n iconSvgPropOverrides?: Partial<IconSvgProps>\n}\n\nconst DirectDownloadIcon = forwardRef<\n HTMLButtonElement,\n DirectDownloadIconProps\n>(function DirectDownloadIcon(props: DirectDownloadIconProps, ref) {\n const {\n isExternalFile,\n onClick,\n getDownloadLink,\n stopPropagation,\n externalURL,\n hasFileAccess,\n displayFileName,\n fileName,\n iconSvgPropOverrides = {},\n } = props\n if (isExternalFile) {\n return (\n <button\n ref={ref}\n className={'btn-download-icon'}\n onClick={event => {\n if (onClick) {\n onClick(isExternalFile)\n if (stopPropagation) event.stopPropagation()\n }\n }}\n >\n <a\n className=\"ignoreLink\"\n rel=\"noopener noreferrer\"\n href={externalURL}\n target=\"_blank\"\n >\n <IconSvg icon=\"download\" {...iconSvgPropOverrides} />\n </a>\n </button>\n )\n }\n if (hasFileAccess) {\n return (\n <button\n ref={ref}\n className={'btn-download-icon'}\n onClick={event => {\n getDownloadLink()\n if (stopPropagation) event.stopPropagation()\n }}\n >\n <IconSvg icon=\"download\" {...iconSvgPropOverrides} />\n {displayFileName && fileName ? fileName : ''}\n </button>\n )\n }\n return <></>\n})\n\nfunction DirectDownload(props: DirectFileDownloadProps) {\n const {\n associatedObjectId,\n associatedObjectType,\n fileHandleId,\n displayFileName = false,\n onClickCallback,\n stopPropagation = false,\n iconSvgPropOverrides,\n } = props\n\n const fileHandleAssociation = {\n fileHandleId: fileHandleId,\n associateObjectId: associatedObjectId,\n associateObjectType: associatedObjectType,\n }\n\n // Get file handle data to ensure we have access / display information\n const { data } = useGetFileBatch({\n requestedFiles: [fileHandleAssociation],\n includeFileHandles: true,\n // don't get the presigned URL with this query, it may expire before the user clicks the download button\n includePreSignedURLs: false,\n includePreviewPreSignedURLs: false,\n })\n\n const fileHandle = data?.requestedFiles[0]?.fileHandle\n const hasFileAccess = Boolean(fileHandle)\n const fileName = fileHandle?.fileName\n const isExternalFile = fileHandle\n ? implementsExternalFileHandleInterface(fileHandle)\n : undefined\n const externalURL: string | undefined = fileHandle\n ? (fileHandle as ExternalFileHandle).externalURL\n : undefined\n\n const { downloadFile } = useDirectDownloadHandler()\n\n const getDownloadLink = async () => {\n await downloadFile({\n fileHandleId,\n associatedObjectId,\n associatedObjectType,\n })\n\n if (onClickCallback) {\n onClickCallback(isExternalFile!)\n }\n }\n\n return (\n <Tooltip\n title=\"Click to begin download of this file\"\n enterNextDelay={TOOLTIP_DELAY_SHOW}\n placement=\"left\"\n >\n <span>\n <DirectDownloadIcon\n isExternalFile={isExternalFile}\n hasFileAccess={hasFileAccess}\n onClick={onClickCallback}\n getDownloadLink={getDownloadLink}\n stopPropagation={stopPropagation}\n externalURL={externalURL}\n displayFileName={displayFileName}\n fileName={fileName}\n iconSvgPropOverrides={iconSvgPropOverrides}\n />\n </span>\n </Tooltip>\n )\n}\n\nexport default DirectDownload\n"],"mappings":";;;;;;;;;AAkCA,IAAM,IAAqB,EAGzB,SAA4B,GAAgC,GAAK;CACjE,IAAM,EACJ,mBACA,YACA,oBACA,oBACA,gBACA,kBACA,oBACA,aACA,0BAAuB,EAAE,KACvB;AAuCJ,QAtCI,IAEA,kBAAC,UAAD;EACO;EACL,WAAW;EACX,UAAS,MAAS;AAChB,GAAI,MACF,EAAQ,EAAe,EACnB,KAAiB,EAAM,iBAAiB;;YAIhD,kBAAC,KAAD;GACE,WAAU;GACV,KAAI;GACJ,MAAM;GACN,QAAO;aAEP,kBAAC,GAAD;IAAS,MAAK;IAAW,GAAI;IAAwB,CAAA;GACnD,CAAA;EACG,CAAA,GAGT,IAEA,kBAAC,UAAD;EACO;EACL,WAAW;EACX,UAAS,MAAS;AAEhB,GADA,GAAiB,EACb,KAAiB,EAAM,iBAAiB;;YALhD,CAQE,kBAAC,GAAD;GAAS,MAAK;GAAW,GAAI;GAAwB,CAAA,EACpD,KAAmB,IAAW,IAAW,GACnC;MAGN,kBAAA,GAAA,EAAK,CAAA;EACZ;AAEF,SAAS,EAAe,GAAgC;CACtD,IAAM,EACJ,uBACA,yBACA,iBACA,qBAAkB,IAClB,oBACA,qBAAkB,IAClB,4BACE,GASE,EAAE,YAAS,EAAgB;EAC/B,gBAAgB,
|
|
1
|
+
{"version":3,"file":"DirectDownload.js","names":[],"sources":["../../../src/components/DirectDownload/DirectDownload.tsx"],"sourcesContent":["import { useGetFileBatch } from '@/synapse-queries/file/useFiles'\nimport { implementsExternalFileHandleInterface } from '@/utils/types/IsType'\nimport { Tooltip } from '@mui/material'\nimport {\n ExternalFileHandle,\n FileHandleAssociateType,\n} from '@sage-bionetworks/synapse-types'\nimport { forwardRef } from 'react'\nimport IconSvg, { IconSvgProps } from '../IconSvg/IconSvg'\nimport { TOOLTIP_DELAY_SHOW } from '../SynapseTable/SynapseTableConstants'\nimport { useDirectDownloadHandler } from '@/utils/hooks/useDirectDownloadHandler'\n\nexport type DirectFileDownloadProps = {\n associatedObjectId: string\n associatedObjectType: FileHandleAssociateType\n fileHandleId: string\n displayFileName?: boolean\n onClickCallback?: (isExternalLink: boolean) => void // callback if you want to know when the link was clicked\n stopPropagation?: boolean\n iconSvgPropOverrides?: Partial<IconSvgProps>\n}\n\ntype DirectDownloadIconProps = {\n isExternalFile?: boolean\n hasFileAccess: boolean\n onClick?: (isExternalFile: boolean) => void\n getDownloadLink: () => Promise<void>\n stopPropagation: boolean\n externalURL?: string\n displayFileName: boolean\n fileName?: string\n iconSvgPropOverrides?: Partial<IconSvgProps>\n}\n\nconst DirectDownloadIcon = forwardRef<\n HTMLButtonElement,\n DirectDownloadIconProps\n>(function DirectDownloadIcon(props: DirectDownloadIconProps, ref) {\n const {\n isExternalFile,\n onClick,\n getDownloadLink,\n stopPropagation,\n externalURL,\n hasFileAccess,\n displayFileName,\n fileName,\n iconSvgPropOverrides = {},\n } = props\n if (isExternalFile) {\n return (\n <button\n ref={ref}\n className={'btn-download-icon'}\n onClick={event => {\n if (onClick) {\n onClick(isExternalFile)\n if (stopPropagation) event.stopPropagation()\n }\n }}\n >\n <a\n className=\"ignoreLink\"\n rel=\"noopener noreferrer\"\n href={externalURL}\n target=\"_blank\"\n >\n <IconSvg icon=\"download\" {...iconSvgPropOverrides} />\n </a>\n </button>\n )\n }\n if (hasFileAccess) {\n return (\n <button\n ref={ref}\n className={'btn-download-icon'}\n onClick={event => {\n getDownloadLink()\n if (stopPropagation) event.stopPropagation()\n }}\n >\n <IconSvg icon=\"download\" {...iconSvgPropOverrides} />\n {displayFileName && fileName ? fileName : ''}\n </button>\n )\n }\n return <></>\n})\n\nfunction DirectDownload(props: DirectFileDownloadProps) {\n const {\n associatedObjectId,\n associatedObjectType,\n fileHandleId,\n displayFileName = false,\n onClickCallback,\n stopPropagation = false,\n iconSvgPropOverrides,\n } = props\n\n const fileHandleAssociation = {\n fileHandleId: fileHandleId,\n associateObjectId: associatedObjectId,\n associateObjectType: associatedObjectType,\n }\n\n // Get file handle data to ensure we have access / display information\n const { data } = useGetFileBatch({\n requestedFiles: [fileHandleAssociation],\n includeFileHandles: true,\n // don't get the presigned URL with this query, it may expire before the user clicks the download button\n includePreSignedURLs: false,\n includePreviewPreSignedURLs: false,\n })\n\n const fileHandle = data?.requestedFiles[0]?.fileHandle\n const hasFileAccess = Boolean(fileHandle)\n const fileName = fileHandle?.fileName\n const isExternalFile = fileHandle\n ? implementsExternalFileHandleInterface(fileHandle)\n : undefined\n const externalURL: string | undefined = fileHandle\n ? (fileHandle as ExternalFileHandle).externalURL\n : undefined\n\n const { downloadFile } = useDirectDownloadHandler()\n\n const getDownloadLink = async () => {\n await downloadFile({\n fileHandleId,\n associatedObjectId,\n associatedObjectType,\n })\n\n if (onClickCallback) {\n onClickCallback(isExternalFile!)\n }\n }\n\n return (\n <Tooltip\n title=\"Click to begin download of this file\"\n enterNextDelay={TOOLTIP_DELAY_SHOW}\n placement=\"left\"\n >\n <span>\n <DirectDownloadIcon\n isExternalFile={isExternalFile}\n hasFileAccess={hasFileAccess}\n onClick={onClickCallback}\n getDownloadLink={getDownloadLink}\n stopPropagation={stopPropagation}\n externalURL={externalURL}\n displayFileName={displayFileName}\n fileName={fileName}\n iconSvgPropOverrides={iconSvgPropOverrides}\n />\n </span>\n </Tooltip>\n )\n}\n\nexport default DirectDownload\n"],"mappings":";;;;;;;;;AAkCA,IAAM,IAAqB,EAGzB,SAA4B,GAAgC,GAAK;CACjE,IAAM,EACJ,mBACA,YACA,oBACA,oBACA,gBACA,kBACA,oBACA,aACA,0BAAuB,EAAE,KACvB;AAuCJ,QAtCI,IAEA,kBAAC,UAAD;EACO;EACL,WAAW;EACX,UAAS,MAAS;AAChB,GAAI,MACF,EAAQ,EAAe,EACnB,KAAiB,EAAM,iBAAiB;;YAIhD,kBAAC,KAAD;GACE,WAAU;GACV,KAAI;GACJ,MAAM;GACN,QAAO;aAEP,kBAAC,GAAD;IAAS,MAAK;IAAW,GAAI;IAAwB,CAAA;GACnD,CAAA;EACG,CAAA,GAGT,IAEA,kBAAC,UAAD;EACO;EACL,WAAW;EACX,UAAS,MAAS;AAEhB,GADA,GAAiB,EACb,KAAiB,EAAM,iBAAiB;;YALhD,CAQE,kBAAC,GAAD;GAAS,MAAK;GAAW,GAAI;GAAwB,CAAA,EACpD,KAAmB,IAAW,IAAW,GACnC;MAGN,kBAAA,GAAA,EAAK,CAAA;EACZ;AAEF,SAAS,EAAe,GAAgC;CACtD,IAAM,EACJ,uBACA,yBACA,iBACA,qBAAkB,IAClB,oBACA,qBAAkB,IAClB,4BACE,GASE,EAAE,YAAS,EAAgB;EAC/B,gBAAgB,CAAC;GAPH;GACd,mBAAmB;GACnB,qBAAqB;GAKJ,CAAsB;EACvC,oBAAoB;EAEpB,sBAAsB;EACtB,6BAA6B;EAC9B,CAAC,EAEI,IAAa,GAAM,eAAe,IAAI,YACtC,IAAgB,EAAQ,GACxB,IAAW,GAAY,UACvB,IAAiB,IACnB,EAAsC,EAAW,GACjD,KAAA,GACE,IAAkC,IACnC,EAAkC,cACnC,KAAA,GAEE,EAAE,oBAAiB,GAA0B;AAcnD,QACE,kBAAC,GAAD;EACE,OAAM;EACN,gBAAA;EACA,WAAU;YAEV,kBAAC,QAAD,EAAA,UACE,kBAAC,GAAD;GACkB;GACD;GACf,SAAS;GACQ,6BAvBW;AAOlC,IANA,MAAM,EAAa;KACjB;KACA;KACA;KACD,CAAC,EAEE,KACF,EAAgB,EAAgB;;GAgBX;GACJ;GACI;GACP;GACY;GACtB,CAAA,EACG,CAAA;EACC,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DirectDownloadButton.js","names":[],"sources":["../../src/components/DirectDownloadButton.tsx"],"sourcesContent":["import { getFiles } from '@/synapse-client/SynapseClient'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport { Button, ButtonProps } from '@mui/material'\nimport {\n BatchFileRequest,\n FileHandleAssociation,\n} from '@sage-bionetworks/synapse-types'\n\nexport type DirectFileDownloadButtonProps = Omit<ButtonProps, 'onClick'> & {\n fileHandleAssociation: FileHandleAssociation\n fileName: string | undefined\n}\n\nfunction DirectDownloadButton(props: DirectFileDownloadButtonProps) {\n const { fileHandleAssociation, fileName, ...buttonProps } = props\n const { accessToken, isAuthenticated } = useSynapseContext()\n\n const getDownloadLink = async () => {\n if (!fileHandleAssociation.fileHandleId || !isAuthenticated) return\n\n const batchFileRequest: BatchFileRequest = {\n requestedFiles: [fileHandleAssociation],\n includePreSignedURLs: true,\n includeFileHandles: false,\n includePreviewPreSignedURLs: false,\n }\n const file = await getFiles(batchFileRequest, accessToken)\n const preSignedURL = file.requestedFiles[0].preSignedURL\n if (!preSignedURL) {\n console.log('Fail to get file download link')\n } else {\n window.open(preSignedURL)\n }\n }\n\n return (\n <Button\n {...buttonProps}\n onClick={() => {\n getDownloadLink()\n }}\n >\n {fileName}\n </Button>\n )\n}\n\nexport default DirectDownloadButton\n"],"mappings":";;;;;AAaA,SAAS,EAAqB,GAAsC;CAClE,IAAM,EAAE,0BAAuB,aAAU,GAAG,MAAgB,GACtD,EAAE,gBAAa,uBAAoB,GAAmB,EAEtD,IAAkB,YAAY;AAClC,MAAI,CAAC,EAAsB,gBAAgB,CAAC,EAAiB;EAS7D,IAAM,
|
|
1
|
+
{"version":3,"file":"DirectDownloadButton.js","names":[],"sources":["../../src/components/DirectDownloadButton.tsx"],"sourcesContent":["import { getFiles } from '@/synapse-client/SynapseClient'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport { Button, ButtonProps } from '@mui/material'\nimport {\n BatchFileRequest,\n FileHandleAssociation,\n} from '@sage-bionetworks/synapse-types'\n\nexport type DirectFileDownloadButtonProps = Omit<ButtonProps, 'onClick'> & {\n fileHandleAssociation: FileHandleAssociation\n fileName: string | undefined\n}\n\nfunction DirectDownloadButton(props: DirectFileDownloadButtonProps) {\n const { fileHandleAssociation, fileName, ...buttonProps } = props\n const { accessToken, isAuthenticated } = useSynapseContext()\n\n const getDownloadLink = async () => {\n if (!fileHandleAssociation.fileHandleId || !isAuthenticated) return\n\n const batchFileRequest: BatchFileRequest = {\n requestedFiles: [fileHandleAssociation],\n includePreSignedURLs: true,\n includeFileHandles: false,\n includePreviewPreSignedURLs: false,\n }\n const file = await getFiles(batchFileRequest, accessToken)\n const preSignedURL = file.requestedFiles[0].preSignedURL\n if (!preSignedURL) {\n console.log('Fail to get file download link')\n } else {\n window.open(preSignedURL)\n }\n }\n\n return (\n <Button\n {...buttonProps}\n onClick={() => {\n getDownloadLink()\n }}\n >\n {fileName}\n </Button>\n )\n}\n\nexport default DirectDownloadButton\n"],"mappings":";;;;;AAaA,SAAS,EAAqB,GAAsC;CAClE,IAAM,EAAE,0BAAuB,aAAU,GAAG,MAAgB,GACtD,EAAE,gBAAa,uBAAoB,GAAmB,EAEtD,IAAkB,YAAY;AAClC,MAAI,CAAC,EAAsB,gBAAgB,CAAC,EAAiB;EAS7D,IAAM,KAAe,MADF,EAAS;GAL1B,gBAAgB,CAAC,EAAsB;GACvC,sBAAsB;GACtB,oBAAoB;GACpB,6BAA6B;GAEH,EAAkB,EAAY,EAChC,eAAe,GAAG;AAC5C,EAAK,IAGH,OAAO,KAAK,EAAa,GAFzB,QAAQ,IAAI,iCAAiC;;AAMjD,QACE,kBAAC,GAAD;EACE,GAAI;EACJ,eAAe;AACb,MAAiB;;YAGlB;EACM,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreatePackageV2.js","names":[],"sources":["../../../src/components/DownloadCart/CreatePackageV2.tsx"],"sourcesContent":["import styles from './CreatePackageV2.module.scss'\nimport {\n createPackageFromDownloadListV2,\n getFileHandleByIdURL,\n} from '@/synapse-client/SynapseClient'\nimport React from 'react'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { Box, Button, Card, InputAdornment, TextField } from '@mui/material'\nimport { DownloadListPackageResponse } from '@sage-bionetworks/synapse-types'\nimport { ChangeEvent, SyntheticEvent, useState } from 'react'\nimport FullWidthAlert, {\n FullWidthAlertVariant,\n} from '../FullWidthAlert/FullWidthAlert'\n\nexport type CreatePackageV2Props = {\n onPackageCreation: () => void\n}\n\ntype AlertConfig = {\n message: string\n variant?: FullWidthAlertVariant\n}\n\nexport const TEMPLATE_ERROR_FILE_NAME =\n 'Please provide a package file name and try again.'\n\nexport const CreatePackageV2 = (\n props: CreatePackageV2Props,\n): React.ReactNode => {\n const { accessToken, keyFactory } = useSynapseContext()\n const queryClient = useQueryClient()\n const [isLoading, setIsLoading] = useState(false)\n const [fileName, setZipFileName] = useState('')\n const [alert, setAlert] = useState<AlertConfig>()\n const [bulkFileDownloadResponse, setBulkFileDownloadResponse] = useState<\n DownloadListPackageResponse | undefined\n >(undefined)\n const { onPackageCreation } = props\n const createPackageHandler = async (event: SyntheticEvent) => {\n event.preventDefault()\n if (!fileName) {\n setAlert({\n message: TEMPLATE_ERROR_FILE_NAME,\n variant: 'danger',\n })\n return\n }\n setIsLoading(true)\n try {\n const fileNameWithZipExtension = `${fileName}.zip`\n const currentBulkFileDownloadResponse =\n await createPackageFromDownloadListV2(\n fileNameWithZipExtension,\n accessToken,\n )\n\n setBulkFileDownloadResponse(currentBulkFileDownloadResponse)\n const { resultFileHandleId } = currentBulkFileDownloadResponse\n try {\n //reset\n window.location.href = await getFileHandleByIdURL(\n resultFileHandleId,\n accessToken,\n )\n setZipFileName('')\n setBulkFileDownloadResponse(undefined)\n queryClient.invalidateQueries({\n queryKey: keyFactory.getDownloadListBaseQueryKey(),\n })\n onPackageCreation()\n } catch (err) {\n console.error('Err on getFileHandleByIdURL = ', err)\n }\n } catch (err) {\n setAlert({\n message: err.reason as string,\n variant: 'danger',\n })\n } finally {\n setIsLoading(false)\n }\n }\n\n const onChange = (event: ChangeEvent<HTMLInputElement>) => {\n setZipFileName(event.target.value)\n }\n\n return (\n <>\n <Card className={styles.CreatePackageV2}>\n <div className={styles.createPackageStep}>\n <span className={styles.createPackageTitle}>\n Create your Download Package\n </span>\n <span className={styles.createPackageDescription}>\n Name your download package and select Download Package to get\n started.\n </span>\n {!isLoading && !bulkFileDownloadResponse && (\n <Box\n sx={{\n display: 'flex',\n alignItems: 'stretch',\n }}\n >\n <TextField\n onChange={onChange}\n type=\"text\"\n placeholder=\"PackageName\"\n sx={{ width: '233px' }}\n slotProps={{\n input: {\n endAdornment: (\n <InputAdornment position=\"end\">.zip</InputAdornment>\n ),\n },\n }}\n />\n <Button\n variant=\"contained\"\n color=\"primary\"\n onClick={e => {\n createPackageHandler(e)\n }}\n sx={{ marginLeft: '20px' }}\n disabled={!fileName}\n >\n Download Package\n </Button>\n </Box>\n )}\n {isLoading && (\n <div className=\"creatingPackage\">\n <span className=\"spinner\" />\n <span style={{ marginLeft: 5 }}>Creating package...</span>\n </div>\n )}\n </div>\n </Card>\n <FullWidthAlert\n show={!!alert}\n variant={alert?.variant ? alert.variant : 'success'}\n description={alert?.message}\n autoCloseAfterDelayInSeconds={10}\n onClose={() => {\n setAlert(undefined)\n }}\n />\n </>\n )\n}\n"],"mappings":";;;;;;;;;AAwBA,IAAa,IACX,qDAEW,KACX,MACoB;CACpB,IAAM,EAAE,gBAAa,kBAAe,GAAmB,EACjD,IAAc,GAAgB,EAC9B,CAAC,GAAW,KAAgB,EAAS,GAAM,EAC3C,CAAC,GAAU,KAAkB,EAAS,GAAG,EACzC,CAAC,GAAO,KAAY,GAAuB,EAC3C,CAAC,GAA0B,KAA+B,EAE9D,KAAA,EAAU,EACN,EAAE,yBAAsB,GACxB,IAAuB,OAAO,MAA0B;AAE5D,MADA,EAAM,gBAAgB,EAClB,CAAC,GAAU;AACb,KAAS;IACP,SAAS;IACT,SAAS;IACV,CAAC;AACF;;AAEF,IAAa,GAAK;AAClB,MAAI;GAEF,IAAM,IACJ,MAAM,
|
|
1
|
+
{"version":3,"file":"CreatePackageV2.js","names":[],"sources":["../../../src/components/DownloadCart/CreatePackageV2.tsx"],"sourcesContent":["import styles from './CreatePackageV2.module.scss'\nimport {\n createPackageFromDownloadListV2,\n getFileHandleByIdURL,\n} from '@/synapse-client/SynapseClient'\nimport React from 'react'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { Box, Button, Card, InputAdornment, TextField } from '@mui/material'\nimport { DownloadListPackageResponse } from '@sage-bionetworks/synapse-types'\nimport { ChangeEvent, SyntheticEvent, useState } from 'react'\nimport FullWidthAlert, {\n FullWidthAlertVariant,\n} from '../FullWidthAlert/FullWidthAlert'\n\nexport type CreatePackageV2Props = {\n onPackageCreation: () => void\n}\n\ntype AlertConfig = {\n message: string\n variant?: FullWidthAlertVariant\n}\n\nexport const TEMPLATE_ERROR_FILE_NAME =\n 'Please provide a package file name and try again.'\n\nexport const CreatePackageV2 = (\n props: CreatePackageV2Props,\n): React.ReactNode => {\n const { accessToken, keyFactory } = useSynapseContext()\n const queryClient = useQueryClient()\n const [isLoading, setIsLoading] = useState(false)\n const [fileName, setZipFileName] = useState('')\n const [alert, setAlert] = useState<AlertConfig>()\n const [bulkFileDownloadResponse, setBulkFileDownloadResponse] = useState<\n DownloadListPackageResponse | undefined\n >(undefined)\n const { onPackageCreation } = props\n const createPackageHandler = async (event: SyntheticEvent) => {\n event.preventDefault()\n if (!fileName) {\n setAlert({\n message: TEMPLATE_ERROR_FILE_NAME,\n variant: 'danger',\n })\n return\n }\n setIsLoading(true)\n try {\n const fileNameWithZipExtension = `${fileName}.zip`\n const currentBulkFileDownloadResponse =\n await createPackageFromDownloadListV2(\n fileNameWithZipExtension,\n accessToken,\n )\n\n setBulkFileDownloadResponse(currentBulkFileDownloadResponse)\n const { resultFileHandleId } = currentBulkFileDownloadResponse\n try {\n //reset\n window.location.href = await getFileHandleByIdURL(\n resultFileHandleId,\n accessToken,\n )\n setZipFileName('')\n setBulkFileDownloadResponse(undefined)\n queryClient.invalidateQueries({\n queryKey: keyFactory.getDownloadListBaseQueryKey(),\n })\n onPackageCreation()\n } catch (err) {\n console.error('Err on getFileHandleByIdURL = ', err)\n }\n } catch (err) {\n setAlert({\n message: err.reason as string,\n variant: 'danger',\n })\n } finally {\n setIsLoading(false)\n }\n }\n\n const onChange = (event: ChangeEvent<HTMLInputElement>) => {\n setZipFileName(event.target.value)\n }\n\n return (\n <>\n <Card className={styles.CreatePackageV2}>\n <div className={styles.createPackageStep}>\n <span className={styles.createPackageTitle}>\n Create your Download Package\n </span>\n <span className={styles.createPackageDescription}>\n Name your download package and select Download Package to get\n started.\n </span>\n {!isLoading && !bulkFileDownloadResponse && (\n <Box\n sx={{\n display: 'flex',\n alignItems: 'stretch',\n }}\n >\n <TextField\n onChange={onChange}\n type=\"text\"\n placeholder=\"PackageName\"\n sx={{ width: '233px' }}\n slotProps={{\n input: {\n endAdornment: (\n <InputAdornment position=\"end\">.zip</InputAdornment>\n ),\n },\n }}\n />\n <Button\n variant=\"contained\"\n color=\"primary\"\n onClick={e => {\n createPackageHandler(e)\n }}\n sx={{ marginLeft: '20px' }}\n disabled={!fileName}\n >\n Download Package\n </Button>\n </Box>\n )}\n {isLoading && (\n <div className=\"creatingPackage\">\n <span className=\"spinner\" />\n <span style={{ marginLeft: 5 }}>Creating package...</span>\n </div>\n )}\n </div>\n </Card>\n <FullWidthAlert\n show={!!alert}\n variant={alert?.variant ? alert.variant : 'success'}\n description={alert?.message}\n autoCloseAfterDelayInSeconds={10}\n onClose={() => {\n setAlert(undefined)\n }}\n />\n </>\n )\n}\n"],"mappings":";;;;;;;;;AAwBA,IAAa,IACX,qDAEW,KACX,MACoB;CACpB,IAAM,EAAE,gBAAa,kBAAe,GAAmB,EACjD,IAAc,GAAgB,EAC9B,CAAC,GAAW,KAAgB,EAAS,GAAM,EAC3C,CAAC,GAAU,KAAkB,EAAS,GAAG,EACzC,CAAC,GAAO,KAAY,GAAuB,EAC3C,CAAC,GAA0B,KAA+B,EAE9D,KAAA,EAAU,EACN,EAAE,yBAAsB,GACxB,IAAuB,OAAO,MAA0B;AAE5D,MADA,EAAM,gBAAgB,EAClB,CAAC,GAAU;AACb,KAAS;IACP,SAAS;IACT,SAAS;IACV,CAAC;AACF;;AAEF,IAAa,GAAK;AAClB,MAAI;GAEF,IAAM,IACJ,MAAM,EACJ,GAHgC,EAAS,OAIzC,EACD;AAEH,KAA4B,EAAgC;GAC5D,IAAM,EAAE,0BAAuB;AAC/B,OAAI;AAWF,IATA,OAAO,SAAS,OAAO,MAAM,EAC3B,GACA,EACD,EACD,EAAe,GAAG,EAClB,EAA4B,KAAA,EAAU,EACtC,EAAY,kBAAkB,EAC5B,UAAU,EAAW,6BAA6B,EACnD,CAAC,EACF,GAAmB;YACZ,GAAK;AACZ,YAAQ,MAAM,kCAAkC,EAAI;;WAE/C,GAAK;AACZ,KAAS;IACP,SAAS,EAAI;IACb,SAAS;IACV,CAAC;YACM;AACR,KAAa,GAAM;;;AAQvB,QACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;EAAM,WAAW,EAAO;YACtB,kBAAC,OAAD;GAAK,WAAW,EAAO;aAAvB;IACE,kBAAC,QAAD;KAAM,WAAW,EAAO;eAAoB;KAErC,CAAA;IACP,kBAAC,QAAD;KAAM,WAAW,EAAO;eAA0B;KAG3C,CAAA;IACN,CAAC,KAAa,CAAC,KACd,kBAAC,GAAD;KACE,IAAI;MACF,SAAS;MACT,YAAY;MACb;eAJH,CAME,kBAAC,GAAD;MACY,WAvBN,MAAyC;AACzD,SAAe,EAAM,OAAO,MAAM;;MAuBtB,MAAK;MACL,aAAY;MACZ,IAAI,EAAE,OAAO,SAAS;MACtB,WAAW,EACT,OAAO,EACL,cACE,kBAAC,GAAD;OAAgB,UAAS;iBAAM;OAAqB,CAAA,EAEvD,EACF;MACD,CAAA,EACF,kBAAC,GAAD;MACE,SAAQ;MACR,OAAM;MACN,UAAS,MAAK;AACZ,SAAqB,EAAE;;MAEzB,IAAI,EAAE,YAAY,QAAQ;MAC1B,UAAU,CAAC;gBACZ;MAEQ,CAAA,CACL;;IAEP,KACC,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,QAAD,EAAM,WAAU,WAAY,CAAA,EAC5B,kBAAC,QAAD;MAAM,OAAO,EAAE,YAAY,GAAG;gBAAE;MAA0B,CAAA,CACtD;;IAEJ;;EACD,CAAA,EACP,kBAAC,GAAD;EACE,MAAM,CAAC,CAAC;EACR,SAAS,GAAO,UAAU,EAAM,UAAU;EAC1C,aAAa,GAAO;EACpB,8BAA8B;EAC9B,eAAe;AACb,KAAS,KAAA,EAAU;;EAErB,CAAA,CACD,EAAA,CAAA"}
|
package/dist/components/DownloadCart/DownloadIneligibleForPackagingFilesFromListButton.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DownloadIneligibleForPackagingFilesFromListButton.js","names":[],"sources":["../../../src/components/DownloadCart/DownloadIneligibleForPackagingFilesFromListButton.tsx"],"sourcesContent":["import { useSynapseContext } from '@/utils'\nimport { implementsExternalFileHandleInterface } from '@/utils/types/IsType'\nimport { calculateFriendlyFileSize } from '@/utils/functions/calculateFriendlyFileSize'\nimport { Button, LinearProgress, Typography } from '@mui/material'\nimport { Download } from '@mui/icons-material'\nimport { SynapseClientError } from '@sage-bionetworks/synapse-client/util/SynapseClientError'\nimport {\n BatchFileRequest,\n BatchFileResult,\n ExternalFileHandle,\n FileEntity,\n FileHandleAssociation,\n FileHandleAssociateType,\n} from '@sage-bionetworks/synapse-types'\nimport { useCallback, useRef, useState } from 'react'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { displayToast } from '../ToastMessage/ToastMessage'\nimport {\n useGetAvailableFilesToDownloadInfinite,\n useGetDownloadListStatistics,\n useRemoveFilesFromDownloadList,\n} from '@/synapse-queries/download/useDownloadList'\nimport { getFiles } from '@/synapse-client/SynapseClient'\nimport { useGetEntityQueryOptions } from '@/synapse-queries/entity/useEntity'\nimport { DialogBase } from '../DialogBase'\nimport { deduplicateFileName, getFileName } from './fileNameUtils'\n\n// showDirectoryPicker is not yet available on the Window interface.\ninterface FileSystemAccessWindow extends Window {\n showDirectoryPicker(options?: {\n mode?: 'read' | 'readwrite'\n startIn?:\n | 'desktop'\n | 'documents'\n | 'downloads'\n | 'music'\n | 'pictures'\n | 'videos'\n }): Promise<FileSystemDirectoryHandle>\n}\n\n/**\n * Type guard to check if File System Access API is available\n */\nfunction supportsFileSystemAccess(\n window: Window,\n): window is FileSystemAccessWindow {\n return 'showDirectoryPicker' in window\n}\n\nconst FILE_BATCH_SIZE = 50 // Maximum batch size for fetching presigned URLs\n\nexport type DownloadIneligibleForPackagingFilesFromListButtonProps = {\n buttonText?: string\n variant?: 'text' | 'outlined' | 'contained'\n}\n\n/**\n * Button component that downloads files from the user's download list that are ineligible for packaging.\n * Uses the infinite query hook to fetch all pages of download list items,\n * batches requests to get presigned URLs, and triggers browser downloads.\n */\nexport function DownloadIneligibleForPackagingFilesFromListButton(\n props: DownloadIneligibleForPackagingFilesFromListButtonProps,\n) {\n const { buttonText = 'Start Multi-file Download', variant = 'contained' } =\n props\n const { accessToken, isAuthenticated } = useSynapseContext()\n const queryClient = useQueryClient()\n const getEntityQueryOptions = useGetEntityQueryOptions<FileEntity>()\n const [isDownloading, setIsDownloading] = useState(false)\n const isDownloadingRef = useRef(false)\n const isCancelledRef = useRef(false)\n const [downloadProgress, setDownloadProgress] = useState<{\n currentFile: string\n fileIndex: number\n totalFiles: number\n bytesDownloaded: number\n totalBytes: number\n } | null>(null)\n\n const { data, status, hasNextPage, fetchNextPage, error } =\n useGetAvailableFilesToDownloadInfinite()\n\n const { mutateAsync: removeFilesFromDownloadList } =\n useRemoveFilesFromDownloadList()\n\n const { refetch: refetchDownloadListStatistics } =\n useGetDownloadListStatistics()\n\n /**\n * Downloads all files from the download list.\n */\n const downloadAllFiles = useCallback(\n async (downloadListItems: typeof data) => {\n // Prevent re-entry if already downloading\n if (isDownloadingRef.current) {\n return\n }\n\n if (!downloadListItems || !isAuthenticated) {\n setIsDownloading(false)\n return\n }\n\n try {\n isDownloadingRef.current = true\n isCancelledRef.current = false\n const allItems = downloadListItems.pages.flatMap(page => page.page)\n\n // Filter to only include files that are NOT eligible for packaging\n const nonPackageableFiles = allItems.filter(\n item => !item.isEligibleForPackaging,\n )\n\n if (nonPackageableFiles.length === 0) {\n displayToast('No non-packageable files available to download', 'info')\n setIsDownloading(false)\n isDownloadingRef.current = false\n return\n }\n\n // Determine if File System Access API is available\n const useFileSystemAccess = supportsFileSystemAccess(window)\n\n // Prompt user to select a directory for downloads BEFORE async operations\n // (must be called during user gesture to avoid SecurityError)\n let directoryHandle: FileSystemDirectoryHandle | undefined\n\n if (useFileSystemAccess) {\n // TypeScript narrowing: we know window has showDirectoryPicker at this point\n const fileSystemWindow = window as unknown as FileSystemAccessWindow\n\n try {\n directoryHandle = await fileSystemWindow.showDirectoryPicker({\n mode: 'readwrite',\n })\n } catch (error) {\n // User cancelled directory picker\n console.error('Failed to select directory:', error)\n displayToast(\n 'Directory selection is required to directly download files from the website.',\n 'warning',\n )\n setIsDownloading(false)\n isDownloadingRef.current = false\n return\n }\n } else {\n // Show info message for browsers without File System Access API\n displayToast(\n 'Your browser will download files individually to your default downloads folder. Each file may trigger a separate download prompt.',\n 'info',\n )\n }\n\n // Initialize progress tracking\n setDownloadProgress({\n currentFile: '',\n fileIndex: 0,\n totalFiles: nonPackageableFiles.length,\n bytesDownloaded: 0,\n totalBytes: 0,\n })\n\n // Fetch entities to get dataFileHandleId for each file\n // Use React Query's ensureQueryData to leverage cache and built-in retry logic (handles 429s with exponential backoff)\n // Map key combines entity ID and version to handle multiple versions of the same entity\n const entityIdToFileHandleId = new Map<string, string>()\n\n // Fetch all entities in parallel - React Query handles concurrency and retries\n const entityPromises = nonPackageableFiles.map(async item => {\n if (isCancelledRef.current) {\n return\n }\n\n try {\n const entity = await queryClient.ensureQueryData(\n getEntityQueryOptions(\n item.fileEntityId,\n item.versionNumber?.toString(),\n ),\n )\n // Use composite key: entityId-version (or entityId if no version)\n const mapKey = `${entity.id!}-${item.versionNumber ?? 'latest'}`\n entityIdToFileHandleId.set(mapKey, entity.dataFileHandleId)\n } catch (error) {\n console.error(`Failed to fetch entity ${item.fileEntityId}:`, error)\n // Continue even if one entity fails\n }\n })\n\n await Promise.all(entityPromises)\n\n // Convert download list items to file handle associations using the fetched dataFileHandleIds\n const fileHandleAssociations: FileHandleAssociation[] =\n nonPackageableFiles\n .filter(item => {\n const mapKey = `${item.fileEntityId}-${\n item.versionNumber ?? 'latest'\n }`\n return entityIdToFileHandleId.has(mapKey)\n })\n .map(item => {\n const mapKey = `${item.fileEntityId}-${\n item.versionNumber ?? 'latest'\n }`\n return {\n fileHandleId: entityIdToFileHandleId.get(mapKey)!,\n associateObjectId: item.fileEntityId,\n associateObjectType: FileHandleAssociateType.FileEntity,\n }\n })\n\n if (fileHandleAssociations.length === 0) {\n displayToast(\n 'Failed to fetch file information for download',\n 'danger',\n )\n setIsDownloading(false)\n isDownloadingRef.current = false\n return\n }\n\n // Split into batches to avoid overwhelming the API\n const batches: FileHandleAssociation[][] = []\n for (\n let i = 0;\n i < fileHandleAssociations.length;\n i += FILE_BATCH_SIZE\n ) {\n batches.push(fileHandleAssociations.slice(i, i + FILE_BATCH_SIZE))\n }\n\n let downloadedCount = 0\n let failedCount = 0\n const successfullyDownloadedItems: typeof nonPackageableFiles = []\n\n // Track used filenames to prevent collisions\n const usedFilenames = new Map<string, number>()\n\n /**\n * Helper function to download file using traditional anchor tag method\n * @returns boolean indicating if the download was successful\n */\n const downloadFileTraditional = async (\n downloadUrl: string,\n fileName: string,\n ): Promise<boolean> => {\n try {\n const response = await fetch(downloadUrl)\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`)\n }\n\n const blob = await response.blob()\n const blobUrl = URL.createObjectURL(blob)\n const anchor = document.createElement('a')\n anchor.href = blobUrl\n anchor.download = fileName\n anchor.style.display = 'none'\n document.body.appendChild(anchor)\n anchor.click()\n document.body.removeChild(anchor)\n\n // Clean up blob URL after a delay to ensure download initiation\n setTimeout(() => URL.revokeObjectURL(blobUrl), 1000)\n\n return true\n } catch (error) {\n console.error(`Failed to download file ${fileName}:`, error)\n // Fallback to window.open method\n try {\n window.open(downloadUrl, '_blank', 'noopener,noreferrer')\n return true\n } catch (fallbackError) {\n console.error(`Fallback window.open also failed:`, fallbackError)\n return false\n }\n }\n }\n\n /**\n * Helper function to process a single file download\n * @returns boolean indicating if download is successful\n */\n const processFileDownload = async (\n fileResult: BatchFileResult['requestedFiles'][0],\n originalItem: (typeof nonPackageableFiles)[0] | undefined,\n ): Promise<boolean> => {\n try {\n let downloadUrl: string | undefined\n\n // Check if this is an external file handle\n if (\n fileResult.fileHandle &&\n implementsExternalFileHandleInterface(fileResult.fileHandle)\n ) {\n // For external file handles, use the externalURL\n downloadUrl = (fileResult.fileHandle as ExternalFileHandle)\n .externalURL\n } else if (fileResult.preSignedURL) {\n // For other file types, use the presigned URL\n downloadUrl = fileResult.preSignedURL\n }\n\n if (!downloadUrl) {\n return false\n }\n\n // Get filename from file result or create a default name\n const baseFileName = getFileName(fileResult, originalItem)\n\n // Handle filename collisions by adding a counter suffix\n const fileName = deduplicateFileName(baseFileName, usedFilenames)\n\n // Update progress with current file info\n const currentFileIndex = downloadedCount + 1\n setDownloadProgress(prev =>\n prev\n ? {\n ...prev,\n currentFile: fileName,\n fileIndex: currentFileIndex,\n bytesDownloaded: 0,\n totalBytes: 0,\n }\n : null,\n )\n\n // Use traditional download method for unsupported browsers\n if (!useFileSystemAccess) {\n const success = await downloadFileTraditional(\n downloadUrl,\n fileName,\n )\n if (success) {\n downloadedCount = currentFileIndex\n if (originalItem) {\n successfullyDownloadedItems.push(originalItem)\n }\n }\n return success\n }\n\n // Use File System Access API for supported browsers\n if (!directoryHandle) {\n return false\n }\n\n try {\n // Fetch the file\n const response = await fetch(downloadUrl)\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`)\n }\n\n // Get total file size from headers\n const contentLength = response.headers.get('content-length')\n const totalBytes = contentLength ? parseInt(contentLength, 10) : 0\n\n // Update progress with file size\n setDownloadProgress(prev =>\n prev\n ? {\n ...prev,\n bytesDownloaded: 0,\n totalBytes,\n }\n : null,\n )\n\n // Create file handle in selected directory\n const fileHandle = await directoryHandle.getFileHandle(fileName, {\n create: true,\n })\n const writableStream = await fileHandle.createWritable()\n\n // Stream the response body to the file with progress tracking\n if (response.body) {\n const reader = response.body.getReader()\n let bytesReceived = 0\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n bytesReceived += value.length\n await writableStream.write(value)\n\n // Update progress\n setDownloadProgress(prev =>\n prev\n ? {\n ...prev,\n bytesDownloaded: bytesReceived,\n }\n : null,\n )\n }\n } catch (streamError) {\n await writableStream.abort()\n throw streamError\n } finally {\n await writableStream.close()\n }\n } else {\n // Fallback if streaming not supported\n try {\n const blob = await response.blob()\n await writableStream.write(blob)\n } finally {\n await writableStream.close()\n }\n }\n\n downloadedCount = currentFileIndex\n\n // Track successfully downloaded item for batch removal\n if (originalItem) {\n successfullyDownloadedItems.push(originalItem)\n }\n return true\n } catch (fetchError) {\n console.error(\n `Failed to fetch/write file ${fileResult.fileHandleId}:`,\n fetchError,\n )\n // Fallback to window.open if File System Access API fails\n try {\n downloadFileTraditional(downloadUrl, fileName)\n downloadedCount = currentFileIndex\n if (originalItem) {\n successfullyDownloadedItems.push(originalItem)\n }\n return true\n } catch (fallbackError) {\n console.error(\n `Fallback downloadFileTraditional also failed for ${fileResult.fileHandleId}:`,\n fallbackError,\n )\n return false\n }\n }\n } catch (error) {\n console.error(\n `Failed to download file ${fileResult.fileHandleId}:`,\n error,\n )\n return false\n }\n }\n\n /**\n * Fallback function to fetch files individually when batch fails\n */\n const fetchIndividually = async (\n batch: FileHandleAssociation[],\n ): Promise<void> => {\n console.info(\n `Attempting to fetch ${batch.length} files individually after batch failure`,\n )\n\n for (const fileHandleAssociation of batch) {\n // Check if user cancelled the operation\n if (isCancelledRef.current) {\n console.info('Individual file fetch cancelled by user')\n break\n }\n\n const singleBatch = [fileHandleAssociation]\n try {\n const batchRequest: BatchFileRequest = {\n requestedFiles: singleBatch,\n includeFileHandles: true,\n includePreSignedURLs: true,\n includePreviewPreSignedURLs: false,\n }\n\n const batchResult = await getFiles(batchRequest, accessToken)\n\n if (batchResult.requestedFiles.length > 0) {\n const fileResult = batchResult.requestedFiles[0]\n const originalItem = nonPackageableFiles.find(\n item =>\n item.fileEntityId ===\n fileHandleAssociation.associateObjectId,\n )\n\n const success = await processFileDownload(\n fileResult,\n originalItem,\n )\n if (!success) {\n failedCount++\n }\n } else {\n failedCount++\n }\n } catch (error) {\n console.error(\n `Failed to fetch individual file ${fileHandleAssociation.fileHandleId}:`,\n error,\n )\n failedCount++\n }\n }\n }\n\n // Process each batch\n for (const batch of batches) {\n // Check if user cancelled the operation\n if (isCancelledRef.current) {\n console.info('Download cancelled by user')\n break\n }\n\n // Try to fetch the entire batch (getFiles has built-in retry logic)\n let batchResult: BatchFileResult | null = null\n try {\n const batchRequest: BatchFileRequest = {\n requestedFiles: batch,\n includeFileHandles: true,\n includePreSignedURLs: true,\n includePreviewPreSignedURLs: false,\n }\n batchResult = await getFiles(batchRequest, accessToken)\n } catch (error) {\n console.error('Failed to fetch batch:', error)\n }\n\n if (batchResult) {\n // Batch fetch succeeded, process all files\n for (let i = 0; i < batchResult.requestedFiles.length; i++) {\n // Check if user cancelled the operation\n if (isCancelledRef.current) {\n console.info(\n 'Download cancelled by user during batch processing',\n )\n break\n }\n\n const fileResult = batchResult.requestedFiles[i]\n const originalItem = nonPackageableFiles.find(\n item => item.fileEntityId === batch[i].associateObjectId,\n )\n\n const success = await processFileDownload(\n fileResult,\n originalItem,\n )\n if (!success) {\n failedCount++\n }\n }\n } else {\n // Batch fetch failed after retries, try fetching files individually\n await fetchIndividually(batch)\n }\n }\n\n // Remove all successfully downloaded files from the download list in one batch\n if (successfullyDownloadedItems.length > 0) {\n await removeFilesFromDownloadList({\n batchToRemove: successfullyDownloadedItems.map(\n (item: (typeof nonPackageableFiles)[0]) => ({\n fileEntityId: item.fileEntityId,\n versionNumber: item.versionNumber,\n }),\n ),\n })\n // Refetch statistics after removing files\n await refetchDownloadListStatistics()\n // Scroll to top of page to show updated statistics\n window.scrollTo({ top: 0, behavior: 'smooth' })\n }\n\n // Show completion message\n if (isCancelledRef.current) {\n displayToast(\n `Download cancelled. ${downloadedCount} file${\n downloadedCount !== 1 ? 's were' : ' was'\n } downloaded before cancellation.`,\n 'info',\n )\n } else if (downloadedCount > 0) {\n displayToast(\n `Download started for ${downloadedCount} file${\n downloadedCount !== 1 ? 's' : ''\n }${\n failedCount > 0\n ? `. ${failedCount} file${failedCount !== 1 ? 's' : ''} failed.`\n : '.'\n }`,\n failedCount > 0 ? 'warning' : 'success',\n )\n } else {\n displayToast('No files could be downloaded', 'warning')\n }\n } catch (error) {\n console.error('Error downloading files:', error)\n const message =\n (error as SynapseClientError | undefined)?.reason ??\n (error instanceof Error ? error.message : undefined) ??\n 'An error occurred while downloading files'\n displayToast(message, 'danger')\n } finally {\n setDownloadProgress(null)\n setIsDownloading(false)\n isDownloadingRef.current = false\n }\n },\n [\n accessToken,\n isAuthenticated,\n queryClient,\n getEntityQueryOptions,\n removeFilesFromDownloadList,\n refetchDownloadListStatistics,\n ],\n )\n\n const handleClick = useCallback(async () => {\n if (isDownloading) {\n return\n }\n setIsDownloading(true)\n\n // Fetch all remaining pages imperatively, then download\n try {\n let stillHasNextPage = hasNextPage\n let latestData = data\n while (stillHasNextPage && fetchNextPage) {\n const result = await fetchNextPage()\n stillHasNextPage = result.hasNextPage\n if (result.data) {\n latestData = result.data\n }\n }\n\n // All pages loaded, now download\n if (status === 'success' && latestData) {\n void downloadAllFiles(latestData)\n } else {\n // Failed to load data\n setIsDownloading(false)\n isDownloadingRef.current = false\n displayToast(\n 'Failed to load download list. Please try again.',\n 'danger',\n )\n }\n } catch (error) {\n console.error('Error downloading files:', error)\n setIsDownloading(false)\n isDownloadingRef.current = false\n const message =\n (error as SynapseClientError | undefined)?.reason ??\n (error instanceof Error ? error.message : undefined) ??\n 'An error occurred while preparing files for download'\n displayToast(message, 'danger')\n }\n }, [\n isDownloading,\n hasNextPage,\n fetchNextPage,\n status,\n data,\n downloadAllFiles,\n ])\n\n const handleCancel = useCallback(() => {\n isCancelledRef.current = true\n setDownloadProgress(null)\n setIsDownloading(false)\n isDownloadingRef.current = false\n }, [])\n\n if (error) {\n return null\n }\n\n return (\n <>\n <DialogBase\n open={!!downloadProgress}\n title=\"Downloading Files\"\n hasCloseButton={false}\n onCancel={handleCancel}\n maxWidth=\"sm\"\n content={\n downloadProgress ? (\n <>\n <Typography\n variant=\"body2\"\n color=\"text.secondary\"\n gutterBottom\n id=\"download-progress-description\"\n >\n File {downloadProgress.fileIndex} of{' '}\n {downloadProgress.totalFiles}\n </Typography>\n <Typography variant=\"body2\" noWrap gutterBottom>\n {downloadProgress.currentFile}\n </Typography>\n {downloadProgress.totalBytes > 0 && (\n <>\n <LinearProgress\n variant=\"determinate\"\n value={\n (downloadProgress.bytesDownloaded /\n downloadProgress.totalBytes) *\n 100\n }\n sx={{ my: 2 }}\n aria-label=\"Download progress\"\n />\n <Typography\n variant=\"body2\"\n color=\"text.secondary\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n >\n {calculateFriendlyFileSize(\n downloadProgress.bytesDownloaded,\n )}{' '}\n of {calculateFriendlyFileSize(downloadProgress.totalBytes)}\n </Typography>\n </>\n )}\n {downloadProgress.totalBytes === 0 && (\n <LinearProgress sx={{ my: 2 }} aria-label=\"Download progress\" />\n )}\n </>\n ) : null\n }\n actions={\n <Button variant=\"outlined\" color=\"error\" onClick={handleCancel}>\n Cancel\n </Button>\n }\n DialogProps={{\n 'aria-describedby': 'download-progress-description',\n disableEscapeKeyDown: false,\n }}\n />\n <Button\n variant={variant}\n onClick={() => {\n void handleClick()\n }}\n loading={isDownloading}\n startIcon={<Download />}\n >\n {buttonText}\n </Button>\n </>\n )\n}\n\nexport default DownloadIneligibleForPackagingFilesFromListButton\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DownloadIneligibleForPackagingFilesFromListButton.js","names":[],"sources":["../../../src/components/DownloadCart/DownloadIneligibleForPackagingFilesFromListButton.tsx"],"sourcesContent":["import { useSynapseContext } from '@/utils'\nimport { implementsExternalFileHandleInterface } from '@/utils/types/IsType'\nimport { calculateFriendlyFileSize } from '@/utils/functions/calculateFriendlyFileSize'\nimport { Button, LinearProgress, Typography } from '@mui/material'\nimport { Download } from '@mui/icons-material'\nimport { SynapseClientError } from '@sage-bionetworks/synapse-client/util/SynapseClientError'\nimport {\n BatchFileRequest,\n BatchFileResult,\n ExternalFileHandle,\n FileEntity,\n FileHandleAssociation,\n FileHandleAssociateType,\n} from '@sage-bionetworks/synapse-types'\nimport { useCallback, useRef, useState } from 'react'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { displayToast } from '../ToastMessage/ToastMessage'\nimport {\n useGetAvailableFilesToDownloadInfinite,\n useGetDownloadListStatistics,\n useRemoveFilesFromDownloadList,\n} from '@/synapse-queries/download/useDownloadList'\nimport { getFiles } from '@/synapse-client/SynapseClient'\nimport { useGetEntityQueryOptions } from '@/synapse-queries/entity/useEntity'\nimport { DialogBase } from '../DialogBase'\nimport { deduplicateFileName, getFileName } from './fileNameUtils'\n\n// showDirectoryPicker is not yet available on the Window interface.\ninterface FileSystemAccessWindow extends Window {\n showDirectoryPicker(options?: {\n mode?: 'read' | 'readwrite'\n startIn?:\n | 'desktop'\n | 'documents'\n | 'downloads'\n | 'music'\n | 'pictures'\n | 'videos'\n }): Promise<FileSystemDirectoryHandle>\n}\n\n/**\n * Type guard to check if File System Access API is available\n */\nfunction supportsFileSystemAccess(\n window: Window,\n): window is FileSystemAccessWindow {\n return 'showDirectoryPicker' in window\n}\n\nconst FILE_BATCH_SIZE = 50 // Maximum batch size for fetching presigned URLs\n\nexport type DownloadIneligibleForPackagingFilesFromListButtonProps = {\n buttonText?: string\n variant?: 'text' | 'outlined' | 'contained'\n}\n\n/**\n * Button component that downloads files from the user's download list that are ineligible for packaging.\n * Uses the infinite query hook to fetch all pages of download list items,\n * batches requests to get presigned URLs, and triggers browser downloads.\n */\nexport function DownloadIneligibleForPackagingFilesFromListButton(\n props: DownloadIneligibleForPackagingFilesFromListButtonProps,\n) {\n const { buttonText = 'Start Multi-file Download', variant = 'contained' } =\n props\n const { accessToken, isAuthenticated } = useSynapseContext()\n const queryClient = useQueryClient()\n const getEntityQueryOptions = useGetEntityQueryOptions<FileEntity>()\n const [isDownloading, setIsDownloading] = useState(false)\n const isDownloadingRef = useRef(false)\n const isCancelledRef = useRef(false)\n const [downloadProgress, setDownloadProgress] = useState<{\n currentFile: string\n fileIndex: number\n totalFiles: number\n bytesDownloaded: number\n totalBytes: number\n } | null>(null)\n\n const { data, status, hasNextPage, fetchNextPage, error } =\n useGetAvailableFilesToDownloadInfinite()\n\n const { mutateAsync: removeFilesFromDownloadList } =\n useRemoveFilesFromDownloadList()\n\n const { refetch: refetchDownloadListStatistics } =\n useGetDownloadListStatistics()\n\n /**\n * Downloads all files from the download list.\n */\n const downloadAllFiles = useCallback(\n async (downloadListItems: typeof data) => {\n // Prevent re-entry if already downloading\n if (isDownloadingRef.current) {\n return\n }\n\n if (!downloadListItems || !isAuthenticated) {\n setIsDownloading(false)\n return\n }\n\n try {\n isDownloadingRef.current = true\n isCancelledRef.current = false\n const allItems = downloadListItems.pages.flatMap(page => page.page)\n\n // Filter to only include files that are NOT eligible for packaging\n const nonPackageableFiles = allItems.filter(\n item => !item.isEligibleForPackaging,\n )\n\n if (nonPackageableFiles.length === 0) {\n displayToast('No non-packageable files available to download', 'info')\n setIsDownloading(false)\n isDownloadingRef.current = false\n return\n }\n\n // Determine if File System Access API is available\n const useFileSystemAccess = supportsFileSystemAccess(window)\n\n // Prompt user to select a directory for downloads BEFORE async operations\n // (must be called during user gesture to avoid SecurityError)\n let directoryHandle: FileSystemDirectoryHandle | undefined\n\n if (useFileSystemAccess) {\n // TypeScript narrowing: we know window has showDirectoryPicker at this point\n const fileSystemWindow = window as unknown as FileSystemAccessWindow\n\n try {\n directoryHandle = await fileSystemWindow.showDirectoryPicker({\n mode: 'readwrite',\n })\n } catch (error) {\n // User cancelled directory picker\n console.error('Failed to select directory:', error)\n displayToast(\n 'Directory selection is required to directly download files from the website.',\n 'warning',\n )\n setIsDownloading(false)\n isDownloadingRef.current = false\n return\n }\n } else {\n // Show info message for browsers without File System Access API\n displayToast(\n 'Your browser will download files individually to your default downloads folder. Each file may trigger a separate download prompt.',\n 'info',\n )\n }\n\n // Initialize progress tracking\n setDownloadProgress({\n currentFile: '',\n fileIndex: 0,\n totalFiles: nonPackageableFiles.length,\n bytesDownloaded: 0,\n totalBytes: 0,\n })\n\n // Fetch entities to get dataFileHandleId for each file\n // Use React Query's ensureQueryData to leverage cache and built-in retry logic (handles 429s with exponential backoff)\n // Map key combines entity ID and version to handle multiple versions of the same entity\n const entityIdToFileHandleId = new Map<string, string>()\n\n // Fetch all entities in parallel - React Query handles concurrency and retries\n const entityPromises = nonPackageableFiles.map(async item => {\n if (isCancelledRef.current) {\n return\n }\n\n try {\n const entity = await queryClient.ensureQueryData(\n getEntityQueryOptions(\n item.fileEntityId,\n item.versionNumber?.toString(),\n ),\n )\n // Use composite key: entityId-version (or entityId if no version)\n const mapKey = `${entity.id!}-${item.versionNumber ?? 'latest'}`\n entityIdToFileHandleId.set(mapKey, entity.dataFileHandleId)\n } catch (error) {\n console.error(`Failed to fetch entity ${item.fileEntityId}:`, error)\n // Continue even if one entity fails\n }\n })\n\n await Promise.all(entityPromises)\n\n // Convert download list items to file handle associations using the fetched dataFileHandleIds\n const fileHandleAssociations: FileHandleAssociation[] =\n nonPackageableFiles\n .filter(item => {\n const mapKey = `${item.fileEntityId}-${\n item.versionNumber ?? 'latest'\n }`\n return entityIdToFileHandleId.has(mapKey)\n })\n .map(item => {\n const mapKey = `${item.fileEntityId}-${\n item.versionNumber ?? 'latest'\n }`\n return {\n fileHandleId: entityIdToFileHandleId.get(mapKey)!,\n associateObjectId: item.fileEntityId,\n associateObjectType: FileHandleAssociateType.FileEntity,\n }\n })\n\n if (fileHandleAssociations.length === 0) {\n displayToast(\n 'Failed to fetch file information for download',\n 'danger',\n )\n setIsDownloading(false)\n isDownloadingRef.current = false\n return\n }\n\n // Split into batches to avoid overwhelming the API\n const batches: FileHandleAssociation[][] = []\n for (\n let i = 0;\n i < fileHandleAssociations.length;\n i += FILE_BATCH_SIZE\n ) {\n batches.push(fileHandleAssociations.slice(i, i + FILE_BATCH_SIZE))\n }\n\n let downloadedCount = 0\n let failedCount = 0\n const successfullyDownloadedItems: typeof nonPackageableFiles = []\n\n // Track used filenames to prevent collisions\n const usedFilenames = new Map<string, number>()\n\n /**\n * Helper function to download file using traditional anchor tag method\n * @returns boolean indicating if the download was successful\n */\n const downloadFileTraditional = async (\n downloadUrl: string,\n fileName: string,\n ): Promise<boolean> => {\n try {\n const response = await fetch(downloadUrl)\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`)\n }\n\n const blob = await response.blob()\n const blobUrl = URL.createObjectURL(blob)\n const anchor = document.createElement('a')\n anchor.href = blobUrl\n anchor.download = fileName\n anchor.style.display = 'none'\n document.body.appendChild(anchor)\n anchor.click()\n document.body.removeChild(anchor)\n\n // Clean up blob URL after a delay to ensure download initiation\n setTimeout(() => URL.revokeObjectURL(blobUrl), 1000)\n\n return true\n } catch (error) {\n console.error(`Failed to download file ${fileName}:`, error)\n // Fallback to window.open method\n try {\n window.open(downloadUrl, '_blank', 'noopener,noreferrer')\n return true\n } catch (fallbackError) {\n console.error(`Fallback window.open also failed:`, fallbackError)\n return false\n }\n }\n }\n\n /**\n * Helper function to process a single file download\n * @returns boolean indicating if download is successful\n */\n const processFileDownload = async (\n fileResult: BatchFileResult['requestedFiles'][0],\n originalItem: (typeof nonPackageableFiles)[0] | undefined,\n ): Promise<boolean> => {\n try {\n let downloadUrl: string | undefined\n\n // Check if this is an external file handle\n if (\n fileResult.fileHandle &&\n implementsExternalFileHandleInterface(fileResult.fileHandle)\n ) {\n // For external file handles, use the externalURL\n downloadUrl = (fileResult.fileHandle as ExternalFileHandle)\n .externalURL\n } else if (fileResult.preSignedURL) {\n // For other file types, use the presigned URL\n downloadUrl = fileResult.preSignedURL\n }\n\n if (!downloadUrl) {\n return false\n }\n\n // Get filename from file result or create a default name\n const baseFileName = getFileName(fileResult, originalItem)\n\n // Handle filename collisions by adding a counter suffix\n const fileName = deduplicateFileName(baseFileName, usedFilenames)\n\n // Update progress with current file info\n const currentFileIndex = downloadedCount + 1\n setDownloadProgress(prev =>\n prev\n ? {\n ...prev,\n currentFile: fileName,\n fileIndex: currentFileIndex,\n bytesDownloaded: 0,\n totalBytes: 0,\n }\n : null,\n )\n\n // Use traditional download method for unsupported browsers\n if (!useFileSystemAccess) {\n const success = await downloadFileTraditional(\n downloadUrl,\n fileName,\n )\n if (success) {\n downloadedCount = currentFileIndex\n if (originalItem) {\n successfullyDownloadedItems.push(originalItem)\n }\n }\n return success\n }\n\n // Use File System Access API for supported browsers\n if (!directoryHandle) {\n return false\n }\n\n try {\n // Fetch the file\n const response = await fetch(downloadUrl)\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`)\n }\n\n // Get total file size from headers\n const contentLength = response.headers.get('content-length')\n const totalBytes = contentLength ? parseInt(contentLength, 10) : 0\n\n // Update progress with file size\n setDownloadProgress(prev =>\n prev\n ? {\n ...prev,\n bytesDownloaded: 0,\n totalBytes,\n }\n : null,\n )\n\n // Create file handle in selected directory\n const fileHandle = await directoryHandle.getFileHandle(fileName, {\n create: true,\n })\n const writableStream = await fileHandle.createWritable()\n\n // Stream the response body to the file with progress tracking\n if (response.body) {\n const reader = response.body.getReader()\n let bytesReceived = 0\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n bytesReceived += value.length\n await writableStream.write(value)\n\n // Update progress\n setDownloadProgress(prev =>\n prev\n ? {\n ...prev,\n bytesDownloaded: bytesReceived,\n }\n : null,\n )\n }\n } catch (streamError) {\n await writableStream.abort()\n throw streamError\n } finally {\n await writableStream.close()\n }\n } else {\n // Fallback if streaming not supported\n try {\n const blob = await response.blob()\n await writableStream.write(blob)\n } finally {\n await writableStream.close()\n }\n }\n\n downloadedCount = currentFileIndex\n\n // Track successfully downloaded item for batch removal\n if (originalItem) {\n successfullyDownloadedItems.push(originalItem)\n }\n return true\n } catch (fetchError) {\n console.error(\n `Failed to fetch/write file ${fileResult.fileHandleId}:`,\n fetchError,\n )\n // Fallback to window.open if File System Access API fails\n try {\n downloadFileTraditional(downloadUrl, fileName)\n downloadedCount = currentFileIndex\n if (originalItem) {\n successfullyDownloadedItems.push(originalItem)\n }\n return true\n } catch (fallbackError) {\n console.error(\n `Fallback downloadFileTraditional also failed for ${fileResult.fileHandleId}:`,\n fallbackError,\n )\n return false\n }\n }\n } catch (error) {\n console.error(\n `Failed to download file ${fileResult.fileHandleId}:`,\n error,\n )\n return false\n }\n }\n\n /**\n * Fallback function to fetch files individually when batch fails\n */\n const fetchIndividually = async (\n batch: FileHandleAssociation[],\n ): Promise<void> => {\n console.info(\n `Attempting to fetch ${batch.length} files individually after batch failure`,\n )\n\n for (const fileHandleAssociation of batch) {\n // Check if user cancelled the operation\n if (isCancelledRef.current) {\n console.info('Individual file fetch cancelled by user')\n break\n }\n\n const singleBatch = [fileHandleAssociation]\n try {\n const batchRequest: BatchFileRequest = {\n requestedFiles: singleBatch,\n includeFileHandles: true,\n includePreSignedURLs: true,\n includePreviewPreSignedURLs: false,\n }\n\n const batchResult = await getFiles(batchRequest, accessToken)\n\n if (batchResult.requestedFiles.length > 0) {\n const fileResult = batchResult.requestedFiles[0]\n const originalItem = nonPackageableFiles.find(\n item =>\n item.fileEntityId ===\n fileHandleAssociation.associateObjectId,\n )\n\n const success = await processFileDownload(\n fileResult,\n originalItem,\n )\n if (!success) {\n failedCount++\n }\n } else {\n failedCount++\n }\n } catch (error) {\n console.error(\n `Failed to fetch individual file ${fileHandleAssociation.fileHandleId}:`,\n error,\n )\n failedCount++\n }\n }\n }\n\n // Process each batch\n for (const batch of batches) {\n // Check if user cancelled the operation\n if (isCancelledRef.current) {\n console.info('Download cancelled by user')\n break\n }\n\n // Try to fetch the entire batch (getFiles has built-in retry logic)\n let batchResult: BatchFileResult | null = null\n try {\n const batchRequest: BatchFileRequest = {\n requestedFiles: batch,\n includeFileHandles: true,\n includePreSignedURLs: true,\n includePreviewPreSignedURLs: false,\n }\n batchResult = await getFiles(batchRequest, accessToken)\n } catch (error) {\n console.error('Failed to fetch batch:', error)\n }\n\n if (batchResult) {\n // Batch fetch succeeded, process all files\n for (let i = 0; i < batchResult.requestedFiles.length; i++) {\n // Check if user cancelled the operation\n if (isCancelledRef.current) {\n console.info(\n 'Download cancelled by user during batch processing',\n )\n break\n }\n\n const fileResult = batchResult.requestedFiles[i]\n const originalItem = nonPackageableFiles.find(\n item => item.fileEntityId === batch[i].associateObjectId,\n )\n\n const success = await processFileDownload(\n fileResult,\n originalItem,\n )\n if (!success) {\n failedCount++\n }\n }\n } else {\n // Batch fetch failed after retries, try fetching files individually\n await fetchIndividually(batch)\n }\n }\n\n // Remove all successfully downloaded files from the download list in one batch\n if (successfullyDownloadedItems.length > 0) {\n await removeFilesFromDownloadList({\n batchToRemove: successfullyDownloadedItems.map(\n (item: (typeof nonPackageableFiles)[0]) => ({\n fileEntityId: item.fileEntityId,\n versionNumber: item.versionNumber,\n }),\n ),\n })\n // Refetch statistics after removing files\n await refetchDownloadListStatistics()\n // Scroll to top of page to show updated statistics\n window.scrollTo({ top: 0, behavior: 'smooth' })\n }\n\n // Show completion message\n if (isCancelledRef.current) {\n displayToast(\n `Download cancelled. ${downloadedCount} file${\n downloadedCount !== 1 ? 's were' : ' was'\n } downloaded before cancellation.`,\n 'info',\n )\n } else if (downloadedCount > 0) {\n displayToast(\n `Download started for ${downloadedCount} file${\n downloadedCount !== 1 ? 's' : ''\n }${\n failedCount > 0\n ? `. ${failedCount} file${failedCount !== 1 ? 's' : ''} failed.`\n : '.'\n }`,\n failedCount > 0 ? 'warning' : 'success',\n )\n } else {\n displayToast('No files could be downloaded', 'warning')\n }\n } catch (error) {\n console.error('Error downloading files:', error)\n const message =\n (error as SynapseClientError | undefined)?.reason ??\n (error instanceof Error ? error.message : undefined) ??\n 'An error occurred while downloading files'\n displayToast(message, 'danger')\n } finally {\n setDownloadProgress(null)\n setIsDownloading(false)\n isDownloadingRef.current = false\n }\n },\n [\n accessToken,\n isAuthenticated,\n queryClient,\n getEntityQueryOptions,\n removeFilesFromDownloadList,\n refetchDownloadListStatistics,\n ],\n )\n\n const handleClick = useCallback(async () => {\n if (isDownloading) {\n return\n }\n setIsDownloading(true)\n\n // Fetch all remaining pages imperatively, then download\n try {\n let stillHasNextPage = hasNextPage\n let latestData = data\n while (stillHasNextPage && fetchNextPage) {\n const result = await fetchNextPage()\n stillHasNextPage = result.hasNextPage\n if (result.data) {\n latestData = result.data\n }\n }\n\n // All pages loaded, now download\n if (status === 'success' && latestData) {\n void downloadAllFiles(latestData)\n } else {\n // Failed to load data\n setIsDownloading(false)\n isDownloadingRef.current = false\n displayToast(\n 'Failed to load download list. Please try again.',\n 'danger',\n )\n }\n } catch (error) {\n console.error('Error downloading files:', error)\n setIsDownloading(false)\n isDownloadingRef.current = false\n const message =\n (error as SynapseClientError | undefined)?.reason ??\n (error instanceof Error ? error.message : undefined) ??\n 'An error occurred while preparing files for download'\n displayToast(message, 'danger')\n }\n }, [\n isDownloading,\n hasNextPage,\n fetchNextPage,\n status,\n data,\n downloadAllFiles,\n ])\n\n const handleCancel = useCallback(() => {\n isCancelledRef.current = true\n setDownloadProgress(null)\n setIsDownloading(false)\n isDownloadingRef.current = false\n }, [])\n\n if (error) {\n return null\n }\n\n return (\n <>\n <DialogBase\n open={!!downloadProgress}\n title=\"Downloading Files\"\n hasCloseButton={false}\n onCancel={handleCancel}\n maxWidth=\"sm\"\n content={\n downloadProgress ? (\n <>\n <Typography\n variant=\"body2\"\n color=\"text.secondary\"\n gutterBottom\n id=\"download-progress-description\"\n >\n File {downloadProgress.fileIndex} of{' '}\n {downloadProgress.totalFiles}\n </Typography>\n <Typography variant=\"body2\" noWrap gutterBottom>\n {downloadProgress.currentFile}\n </Typography>\n {downloadProgress.totalBytes > 0 && (\n <>\n <LinearProgress\n variant=\"determinate\"\n value={\n (downloadProgress.bytesDownloaded /\n downloadProgress.totalBytes) *\n 100\n }\n sx={{ my: 2 }}\n aria-label=\"Download progress\"\n />\n <Typography\n variant=\"body2\"\n color=\"text.secondary\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n >\n {calculateFriendlyFileSize(\n downloadProgress.bytesDownloaded,\n )}{' '}\n of {calculateFriendlyFileSize(downloadProgress.totalBytes)}\n </Typography>\n </>\n )}\n {downloadProgress.totalBytes === 0 && (\n <LinearProgress sx={{ my: 2 }} aria-label=\"Download progress\" />\n )}\n </>\n ) : null\n }\n actions={\n <Button variant=\"outlined\" color=\"error\" onClick={handleCancel}>\n Cancel\n </Button>\n }\n DialogProps={{\n 'aria-describedby': 'download-progress-description',\n disableEscapeKeyDown: false,\n }}\n />\n <Button\n variant={variant}\n onClick={() => {\n void handleClick()\n }}\n loading={isDownloading}\n startIcon={<Download />}\n >\n {buttonText}\n </Button>\n </>\n )\n}\n\nexport default DownloadIneligibleForPackagingFilesFromListButton\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DownloadListActionsRequired.js","names":[],"sources":["../../../src/components/DownloadCart/DownloadListActionsRequired.tsx"],"sourcesContent":["import { useGetAllDownloadListActionsRequired } from '@/synapse-queries'\nimport useTrackTransientListItems from '@/utils/hooks/useTrackTransientListItems'\nimport { Box } from '@mui/material'\nimport { times } from 'lodash-es'\nimport { LoadingActionRequiredCard } from './ActionRequiredCard/ActionRequiredCard'\nimport { ActionRequiredListItem } from './ActionRequiredListItem'\n\nexport type DownloadListActionsRequiredProps = {\n /** Invoked when a user clicks \"View Sharing Settings\" for a set of files that require the Download permission*/\n onViewSharingSettingsClicked?: (benefactorId: string) => void\n}\n\nexport function DownloadListActionsRequired(\n props: DownloadListActionsRequiredProps,\n) {\n const { onViewSharingSettingsClicked } = props\n\n // This component will track all completed actions, based on which actions are omitted from the ActionsRequiredResponse as the user performs required tasks\n // For accurate tracking, we must make sure we have all data. So we will fetch all pages instead of one page at a time.\n const { data: currentActionsRequired, isLoading } =\n useGetAllDownloadListActionsRequired({\n throwOnError: true,\n })\n\n // PORTALS-2950 - Keep a record of actions that disappear from the server response - i.e. the 'completed' actions\n const allCompleteAndIncompleteActions = useTrackTransientListItems(\n currentActionsRequired,\n )\n\n return (\n <>\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'column',\n gap: 3,\n pt: 5,\n }}\n >\n {allCompleteAndIncompleteActions.map((item, index) => {\n if (item) {\n return (\n <ActionRequiredListItem\n key={index}\n action={item.action}\n count={item.count}\n onViewSharingSettingsClicked={onViewSharingSettingsClicked}\n />\n )\n } else return false\n })}\n {isLoading && times(3).map(k => <LoadingActionRequiredCard key={k} />)}\n </Box>\n </>\n )\n}\n"],"mappings":";;;;;;;;;AAYA,SAAgB,EACd,GACA;CACA,IAAM,EAAE,oCAAiC,GAInC,EAAE,MAAM,GAAwB,iBACpC,EAAqC,EACnC,cAAc,IACf,CAAC;AAOJ,QACE,kBAAA,GAAA,EAAA,UACE,kBAAC,GAAD;EACE,IAAI;GACF,SAAS;GACT,eAAe;GACf,KAAK;GACL,IAAI;GACL;YANH,CANoC,EACtC,
|
|
1
|
+
{"version":3,"file":"DownloadListActionsRequired.js","names":[],"sources":["../../../src/components/DownloadCart/DownloadListActionsRequired.tsx"],"sourcesContent":["import { useGetAllDownloadListActionsRequired } from '@/synapse-queries'\nimport useTrackTransientListItems from '@/utils/hooks/useTrackTransientListItems'\nimport { Box } from '@mui/material'\nimport { times } from 'lodash-es'\nimport { LoadingActionRequiredCard } from './ActionRequiredCard/ActionRequiredCard'\nimport { ActionRequiredListItem } from './ActionRequiredListItem'\n\nexport type DownloadListActionsRequiredProps = {\n /** Invoked when a user clicks \"View Sharing Settings\" for a set of files that require the Download permission*/\n onViewSharingSettingsClicked?: (benefactorId: string) => void\n}\n\nexport function DownloadListActionsRequired(\n props: DownloadListActionsRequiredProps,\n) {\n const { onViewSharingSettingsClicked } = props\n\n // This component will track all completed actions, based on which actions are omitted from the ActionsRequiredResponse as the user performs required tasks\n // For accurate tracking, we must make sure we have all data. So we will fetch all pages instead of one page at a time.\n const { data: currentActionsRequired, isLoading } =\n useGetAllDownloadListActionsRequired({\n throwOnError: true,\n })\n\n // PORTALS-2950 - Keep a record of actions that disappear from the server response - i.e. the 'completed' actions\n const allCompleteAndIncompleteActions = useTrackTransientListItems(\n currentActionsRequired,\n )\n\n return (\n <>\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'column',\n gap: 3,\n pt: 5,\n }}\n >\n {allCompleteAndIncompleteActions.map((item, index) => {\n if (item) {\n return (\n <ActionRequiredListItem\n key={index}\n action={item.action}\n count={item.count}\n onViewSharingSettingsClicked={onViewSharingSettingsClicked}\n />\n )\n } else return false\n })}\n {isLoading && times(3).map(k => <LoadingActionRequiredCard key={k} />)}\n </Box>\n </>\n )\n}\n"],"mappings":";;;;;;;;;AAYA,SAAgB,EACd,GACA;CACA,IAAM,EAAE,oCAAiC,GAInC,EAAE,MAAM,GAAwB,iBACpC,EAAqC,EACnC,cAAc,IACf,CAAC;AAOJ,QACE,kBAAA,GAAA,EAAA,UACE,kBAAC,GAAD;EACE,IAAI;GACF,SAAS;GACT,eAAe;GACf,KAAK;GACL,IAAI;GACL;YANH,CANoC,EACtC,EAaK,CAAgC,KAAK,GAAM,MACtC,IAEA,kBAAC,GAAD;GAEE,QAAQ,EAAK;GACb,OAAO,EAAK;GACkB;GAC9B,EAJK,EAIL,GAEQ,GACd,EACD,KAAa,EAAM,EAAE,CAAC,KAAI,MAAK,kBAAC,GAAD,EAAqC,EAAL,EAAK,CAAC,CAClE;KACL,CAAA"}
|