synapse-react-client 4.0.24 → 4.0.25
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/components/AccessRequirementList/ManagedACTAccessRequirementRequestFlow/DataAccessRequestAccessorsFilesForm/DataAccessRequestAccessorsFilesForm.js.map +1 -1
- package/dist/components/AclEditor/useUpdateAcl.js.map +1 -1
- package/dist/components/Authentication/TwoFactorBackupCodes.js.map +1 -1
- package/dist/components/Authentication/TwoFactorEnrollmentForm.js.map +1 -1
- package/dist/components/Breadcrumbs/Breadcrumbs.d.ts +3 -0
- package/dist/components/Breadcrumbs/Breadcrumbs.d.ts.map +1 -1
- package/dist/components/Breadcrumbs/Breadcrumbs.js +43 -30
- package/dist/components/Breadcrumbs/Breadcrumbs.js.map +1 -1
- package/dist/components/CannedRejectionDialog/CannedRejectionDialog.js.map +1 -1
- package/dist/components/ChallengeSubmission/SubmissionDirectoryList.js.map +1 -1
- package/dist/components/CopyToClipboardString/CopyToClipboardString.d.ts +7 -1
- package/dist/components/CopyToClipboardString/CopyToClipboardString.d.ts.map +1 -1
- package/dist/components/CopyToClipboardString/CopyToClipboardString.js +22 -16
- package/dist/components/CopyToClipboardString/CopyToClipboardString.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/EntityIcon.d.ts +1 -0
- package/dist/components/EntityIcon.d.ts.map +1 -1
- package/dist/components/EntityIcon.js +37 -36
- package/dist/components/EntityIcon.js.map +1 -1
- package/dist/components/EntitySidebar/EntitySidebar.css +1 -0
- package/dist/components/EntitySidebar/EntitySidebar.d.ts +7 -0
- package/dist/components/EntitySidebar/EntitySidebar.d.ts.map +1 -0
- package/dist/components/EntitySidebar/EntitySidebar.js +62 -0
- package/dist/components/EntitySidebar/EntitySidebar.js.map +1 -0
- package/dist/components/EntitySidebar/EntitySidebar.module.js +17 -0
- package/dist/components/EntitySidebar/EntitySidebar.module.js.map +1 -0
- package/dist/components/EntitySidebar/EntitySidebar.module.scss +87 -0
- package/dist/components/Evaluation/EvaluationRoundEditorList.js.map +1 -1
- package/dist/components/GenericCard/BioregistryRules.js.map +1 -1
- package/dist/components/IconSvg/IconSvg.d.ts +2 -1
- package/dist/components/IconSvg/IconSvg.d.ts.map +1 -1
- package/dist/components/IconSvg/IconSvg.js +112 -89
- package/dist/components/IconSvg/IconSvg.js.map +1 -1
- package/dist/components/Plot/UpsetPlot.js.map +1 -1
- package/dist/components/SchemaDrivenAnnotationEditor/field/AdditionalPropertiesSchemaField.js.map +1 -1
- package/dist/components/StorybookComponentWrapper.js.map +1 -1
- package/dist/components/SynapseTable/TablePagination.js.map +1 -1
- package/dist/components/SynapseTable/datasets/DatasetItemsEditor.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/TableColumnSchemaForm.js.map +1 -1
- package/dist/components/TanStackTable/StyledTanStackTable.js.map +1 -1
- package/dist/components/entity/page/breadcrumbs/EntityPageBreadcrumbs.d.ts +1 -8
- package/dist/components/entity/page/breadcrumbs/EntityPageBreadcrumbs.d.ts.map +1 -1
- package/dist/components/entity/page/breadcrumbs/EntityPageBreadcrumbs.js +17 -12
- package/dist/components/entity/page/breadcrumbs/EntityPageBreadcrumbs.js.map +1 -1
- package/dist/components/entity/page/title_bar/EntityPageTitleBar.d.ts.map +1 -1
- package/dist/components/entity/page/title_bar/EntityPageTitleBar.js +20 -16
- package/dist/components/entity/page/title_bar/EntityPageTitleBar.js.map +1 -1
- package/dist/components/entity/page/title_bar/TitleBarProperties.d.ts +0 -1
- package/dist/components/entity/page/title_bar/TitleBarProperties.d.ts.map +1 -1
- package/dist/components/entity/page/title_bar/TitleBarProperties.js +17 -82
- package/dist/components/entity/page/title_bar/TitleBarProperties.js.map +1 -1
- package/dist/components/entity/page/title_bar/useGetEntityTitleBarProperties.d.ts.map +1 -1
- package/dist/components/entity/page/title_bar/useGetEntityTitleBarProperties.js +3 -4
- package/dist/components/entity/page/title_bar/useGetEntityTitleBarProperties.js.map +1 -1
- package/dist/components/menu/ComplexMenu.d.ts.map +1 -1
- package/dist/components/menu/ComplexMenu.js +5 -3
- package/dist/components/menu/ComplexMenu.js.map +1 -1
- package/dist/testutils/ReactQueryMockUtils.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types/ThemeTypes.d.ts +2 -2
- package/dist/utils/functions/IsEqualTreatUndefinedAsMissing.js.map +1 -1
- package/dist/utils/hooks/useDebouncedEffect.js.map +1 -1
- package/dist/utils/hooks/useDetectSSOCode.js.map +1 -1
- package/dist/utils/hooks/useImmutableTableQuery/useImmutableTableQuery.js.map +1 -1
- package/dist/utils/hooks/useLogin.js.map +1 -1
- package/package.json +5 -5
package/dist/SWC.index.d.ts
CHANGED
|
@@ -62,6 +62,7 @@ declare const SynapseComponents: {
|
|
|
62
62
|
enableSorting?: boolean;
|
|
63
63
|
onEntityIdClicked?: (entityId: string) => void;
|
|
64
64
|
}>>;
|
|
65
|
+
EntitySidebar: import("react").LazyExoticComponent<typeof import("./components/EntitySidebar/EntitySidebar").default>;
|
|
65
66
|
EntityTypeIcon: import("react").LazyExoticComponent<typeof import("./components/EntityIcon").EntityTypeIcon>;
|
|
66
67
|
EntityUploadModal: import("react").LazyExoticComponent<import("react").ForwardRefExoticComponent<{
|
|
67
68
|
entityId: string;
|
package/dist/SWC.index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SWC.index.d.ts","sourceRoot":"","sources":["../src/SWC.index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAEL,qBAAqB,EACtB,MAAM,wCAAwC,CAAA;AAC/C,OAAO,aAAa,EAAE,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC5D,OAAO,KAAK,cAAc,MAAM,mBAAmB,CAAA;AACnD,OAAO,QAAQ,MAAM,0BAA0B,CAAA;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAA;AACzE,OAAO,EACL,6BAA6B,EAC7B,4BAA4B,EAC5B,6BAA6B,EAC7B,8BAA8B,EAC/B,MAAM,mCAAmC,CAAA;AAC1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAA;AACzE,OAAO,EAEL,sBAAsB,EACtB,iBAAiB,EAClB,MAAM,gCAAgC,CAAA;AACvC,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAA;AAEhE,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAA;AAGxD,OAAO,mBAAmB,CAAA;AAK1B,QAAA,MAAM,YAAY;;CAEjB,CAAA;AAED,QAAA,MAAM,cAAc;;;;;CAKnB,CAAA;AAED,QAAA,MAAM,iBAAiB
|
|
1
|
+
{"version":3,"file":"SWC.index.d.ts","sourceRoot":"","sources":["../src/SWC.index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAEL,qBAAqB,EACtB,MAAM,wCAAwC,CAAA;AAC/C,OAAO,aAAa,EAAE,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC5D,OAAO,KAAK,cAAc,MAAM,mBAAmB,CAAA;AACnD,OAAO,QAAQ,MAAM,0BAA0B,CAAA;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAA;AACzE,OAAO,EACL,6BAA6B,EAC7B,4BAA4B,EAC5B,6BAA6B,EAC7B,8BAA8B,EAC/B,MAAM,mCAAmC,CAAA;AAC1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAA;AACzE,OAAO,EAEL,sBAAsB,EACtB,iBAAiB,EAClB,MAAM,gCAAgC,CAAA;AACvC,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAA;AAEhE,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAA;AAGxD,OAAO,mBAAmB,CAAA;AAK1B,QAAA,MAAM,YAAY;;CAEjB,CAAA;AAED,QAAA,MAAM,cAAc;;;;;CAKnB,CAAA;AAED,QAAA,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqMtB,CAAA;AAED,QAAA,MAAM,SAAS;;;;;;CAMd,CAAA;AAGD,QAAA,MAAM,yBAAyB,QAAkB,CAAA;AAEjD,OAAO,EACL,SAAS,EACT,UAAU,EACV,yBAAyB,EACzB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,YAAY,EACZ,cAAc,EACd,QAAQ,EACR,UAAU,EACV,qBAAqB,GACtB,CAAA"}
|
package/dist/SWC.index.js
CHANGED
|
@@ -54,6 +54,7 @@ var x = { BackendDestinationEnum: r }, S = {
|
|
|
54
54
|
EntityPageBreadcrumbs: b(() => import("./components/entity/page/breadcrumbs/EntityPageBreadcrumbs.js")),
|
|
55
55
|
EntityPageTitleBar: b(() => import("./components/entity/page/title_bar/EntityPageTitleBar.js")),
|
|
56
56
|
EntityTreeTable: b(() => import("./components/EntityTreeTable/EntityTreeTable.js")),
|
|
57
|
+
EntitySidebar: b(() => import("./components/EntitySidebar/EntitySidebar.js")),
|
|
57
58
|
EntityTypeIcon: b(() => import("./components/EntityIcon.js")),
|
|
58
59
|
EntityUploadModal: b(() => import("./components/EntityUpload/EntityUploadModal.js")),
|
|
59
60
|
EntityViewScopeEditorModal: b(() => import("./components/EntityViewScopeEditor/EntityViewScopeEditorModal.js")),
|
|
@@ -113,7 +114,7 @@ var x = { BackendDestinationEnum: r }, S = {
|
|
|
113
114
|
sendSearchResultsReturnedEvent: y,
|
|
114
115
|
sendSearchResultReturnedEvent: v,
|
|
115
116
|
sendSearchResultClickedEvent: _
|
|
116
|
-
}, T = "4.0.
|
|
117
|
+
}, T = "4.0.25";
|
|
117
118
|
//#endregion
|
|
118
119
|
export { w as Analytics, a as HttpClient, d as Palettes, o as SynapseClient, C as SynapseComponents, n as SynapseConstants, S as SynapseContext, x as SynapseEnums, m as SynapseQueries, T as SynapseReactClientVersion, p as SynapseSessionManager, i as xssOptions };
|
|
119
120
|
|
package/dist/SWC.index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SWC.index.js","names":[],"sources":["../src/SWC.index.ts"],"sourcesContent":["/**\n * SWC.index.ts represents the entry point for the Synapse React Client library as it is published to NPM and\n * used by SynapseWebClient.\n *\n * If you wish to export a component or other object to be used by SynapseWebClient, you should add it to this file.\n */\n\nimport { lazy } from 'react'\nimport {\n displayToast,\n SynapseToastContainer,\n} from './components/ToastMessage/ToastMessage'\nimport SynapseClient, { HttpClient } from './synapse-client'\nimport * as SynapseQueries from './synapse-queries'\nimport Palettes from './theme/palette/Palettes'\nimport { SynapseConstants } from './utils'\nimport { sendAnalyticsEvent } from './utils/analytics/sendAnalyticsEvent'\nimport {\n sendSearchQuerySubmittedEvent,\n sendSearchResultClickedEvent,\n sendSearchResultReturnedEvent,\n sendSearchResultsReturnedEvent,\n} from './utils/analytics/sendSearchEvent'\nimport { FullContextProvider } from './utils/context/FullContextProvider'\nimport {\n SynapseContextConsumer,\n SynapseContextProvider,\n useSynapseContext,\n} from './utils/context/SynapseContext'\nimport { BackendDestinationEnum } from './utils/functions'\nimport { xssOptions } from './utils/functions/SanitizeHtmlUtils'\nimport { getCurrentCookiePreferences } from './utils/hooks'\nimport { SynapseSessionManager } from './utils/AppUtils'\n\n// Also include scss in the bundle\nimport './style/main.scss'\n\n// Injected at build time by Vite's `define`\ndeclare const __SRC_VERSION__: string\n\nconst SynapseEnums = {\n BackendDestinationEnum,\n}\n\nconst SynapseContext = {\n FullContextProvider,\n SynapseContextProvider,\n SynapseContextConsumer,\n useSynapseContext,\n}\n\nconst SynapseComponents = {\n AccessRequirementAclEditor: lazy(\n () => import('./components/AccessRequirementAclEditor'),\n ),\n AccessRequirementList: lazy(\n () => import('./components/AccessRequirementList/AccessRequirementList'),\n ),\n AccessRequirementRelatedProjectsList: lazy(\n () => import('./components/AccessRequirementRelatedProjectsList'),\n ),\n AccountLevelBadges: lazy(\n () => import('./components/AccountLevelBadges/AccountLevelBadges'),\n ),\n AddToDownloadListConfirmationAlert: lazy(\n () =>\n import('./components/download_list/AddToDownloadListConfirmationAlert/AddToDownloadListConfirmationAlert'),\n ),\n AvailableEvaluationQueueList: lazy(\n () =>\n import('./components/ChallengeSubmission/AvailableEvaluationQueueList'),\n ),\n CertificationQuiz: lazy(\n () => import('./components/CertificationQuiz/CertificationQuiz'),\n ),\n CookiesNotification: lazy(() => import('./components/CookiesNotification')),\n CreateOrUpdateAccessRequirementWizard: lazy(\n () => import('./components/CreateOrUpdateAccessRequirementWizard'),\n ),\n CreateOrUpdateDoiModal: lazy(\n () => import('./components/doi/CreateOrUpdateDoiModal'),\n ),\n CreateTableFromCsvDialog: lazy(\n () => import('./components/table/CsvPreview/CreateTableFromCsvDialog'),\n ),\n CreateTableViewWizard: lazy(\n () => import('./components/CreateTableViewWizard/CreateTableViewWizard'),\n ),\n CreatedByModifiedBy: lazy(\n () => import('./components/entity/page/CreatedByModifiedBy'),\n ),\n CsvPreview: lazy(() => import('./components/table/CsvPreview/CsvPreview')),\n CuratorDashboard: lazy(\n () => import('./features/curator/dashboard/CuratorDashboard'),\n ),\n DatasetItemsEditor: lazy(\n () => import('./components/SynapseTable/datasets/DatasetItemsEditor'),\n ),\n DiscussionThread: lazy(() => import('./components/Forum/DiscussionThread')),\n DownloadCartPage: lazy(\n () => import('./components/DownloadCart/DownloadCartPage'),\n ),\n EntityAclEditorModal: lazy(\n () => import('./components/EntityAclEditor/EntityAclEditorModal'),\n ),\n EntityActionMenu: lazy(\n () => import('./components/entity/page/action_menu/EntityActionMenu'),\n ),\n EntityBadgeIcons: lazy(\n () => import('./components/EntityBadgeIcons/EntityBadgeIcons'),\n ),\n EntityCitation: lazy(() => import('./components/EntityCitation')),\n EntityFinder: lazy(() => import('./components/EntityFinder/EntityFinder')),\n EntityForm: lazy(() => import('./components/EntityForm/EntityForm')),\n EntityHeaderTable: lazy(() => import('./components/EntityHeaderTable')),\n EntityModal: lazy(() => import('./components/entity/metadata/EntityModal')),\n EntityPageBreadcrumbs: lazy(\n () => import('./components/entity/page/breadcrumbs/EntityPageBreadcrumbs'),\n ),\n EntityPageTitleBar: lazy(\n () => import('./components/entity/page/title_bar/EntityPageTitleBar'),\n ),\n EntityTreeTable: lazy(\n () => import('./components/EntityTreeTable/EntityTreeTable'),\n ),\n EntityTypeIcon: lazy(() => import('./components/EntityIcon')),\n EntityUploadModal: lazy(\n () => import('./components/EntityUpload/EntityUploadModal'),\n ),\n EntityViewScopeEditorModal: lazy(\n () =>\n import('./components/EntityViewScopeEditor/EntityViewScopeEditorModal'),\n ),\n CreateProjectModal: lazy(() =>\n import('./components/CreateProjectModal/CreateProjectModal').then(m => ({\n default: m.CreateProjectModal,\n })),\n ),\n ErrorPage: lazy(() => import('./components/error/ErrorPage')),\n EvaluationCard: lazy(() => import('./components/Evaluation/EvaluationCard')),\n EvaluationEditorPage: lazy(\n () => import('./components/Evaluation/EvaluationEditorPage'),\n ),\n FavoritesPage: lazy(() => import('./components/favorites/FavoritesPage')),\n ForumSearch: lazy(() => import('./components/ForumSearch/ForumSearch')),\n FullWidthAlert: lazy(\n () => import('./components/FullWidthAlert/FullWidthAlert'),\n ),\n GoogleAnalytics: lazy(\n () => import('./components/GoogleAnalytics/GoogleAnalytics'),\n ),\n GovernanceMarkdownGithub: lazy(\n () => import('./components/Markdown/GovernanceMarkdownGithub'),\n ),\n GridPage: lazy(() => import('./features/curator/GridPage/GridPage')),\n HasAccess: lazy(() => import('./components/HasAccess/HasAccessV2')),\n HelpPopover: lazy(() => import('./components/HelpPopover/HelpPopover')),\n HtmlPreview: lazy(\n () => import('./components/FilePreview/HtmlPreview/HtmlPreview'),\n ),\n IDUReport: lazy(() => import('./components/IDUReport/IDUReport')),\n IconSvg: lazy(() => import('./components/IconSvg/IconSvg')),\n MetadataTasksPage: lazy(\n () =>\n import('./features/entity/metadata-task/components/MetadataTasksPage'),\n ),\n OAuthManagement: lazy(\n () => import('./components/OAuthClientManagement/OAuthManagement'),\n ),\n OrientationBanner: lazy(\n () => import('./components/OrientationBanner/OrientationBanner'),\n ),\n PageProgress: lazy(() => import('./components/PageProgress/PageProgress')),\n ProjectDataAvailability: lazy(\n () => import('./components/ProjectStorage/ProjectDataAvailability'),\n ),\n ProjectVisibilityChip: lazy(\n () => import('./components/ProjectVisibilityChip/ProjectVisibilityChip'),\n ),\n ProvenanceGraph: lazy(\n () => import('./components/ProvenanceGraph/ProvenanceGraph'),\n ),\n QueryWrapperPlotNav: lazy(\n () => import('./components/QueryWrapperPlotNav/QueryWrapperPlotNav'),\n ),\n RejectProfileValidationRequestModal: lazy(\n () => import('./components/dataaccess/RejectProfileValidationRequestModal'),\n ),\n ReviewerDashboard: lazy(\n () => import('./components/dataaccess/ReviewerDashboard'),\n ),\n SearchQueryWrapperPlotNav: lazy(\n () =>\n import('./components/SearchQueryWrapperPlotNav/SearchQueryWrapperPlotNav'),\n ),\n ShareThisPage: lazy(() => import('./components/ShareThisPage')),\n SkeletonButton: lazy(() => import('./components/Skeleton/SkeletonButton')),\n SqlDefinedTableEditorModal: lazy(\n () =>\n import('./components/SqlDefinedTableEditor/SqlDefinedTableEditorModal'),\n ),\n StandaloneQueryWrapper: lazy(\n () => import('./components/StandaloneQueryWrapper/StandaloneQueryWrapper'),\n ),\n StatisticsPlot: lazy(() => import('./components/StatisticsPlot')),\n SubmissionViewScopeEditorModal: lazy(\n () =>\n import('./components/SubmissionViewScopeEditor/SubmissionViewScopeEditorModal'),\n ),\n SubscriptionPage: lazy(() => import('./components/SubscriptionPage')),\n SynapseChat: lazy(() => import('./components/SynapseChat/SynapseChat')),\n SynapseGrid: lazy(() => import('./components/DataGrid/SynapseGrid')),\n SynapseFooter: lazy(() => import('./components/SynapseFooter/SynapseFooter')),\n SynapseHomepageV2: lazy(\n () => import('./components/SynapseHomepageV2/SynapseHomepageV2'),\n ),\n SynapseNavDrawer: lazy(\n () => import('./components/SynapseNavDrawer/SynapseNavDrawer'),\n ),\n SynapsePlansPage: lazy(\n () => import('./components/SynapseHomepageV2/SynapsePlansPage'),\n ),\n SynapsePortalBanners: lazy(\n () => import('./components/SynapsePortalBanners/SynapsePortalBanners'),\n ),\n SynapseSearchPage: lazy(\n () => import('./components/SynapseSearchPageResults/SynapseSearchPage'),\n ),\n SynapseToastContainer,\n TableColumnSchemaEditor: lazy(\n () =>\n import('./components/TableColumnSchemaEditor/TableColumnSchemaEditor'),\n ),\n TrashCanList: lazy(() => import('./components/trash/TrashCanList')),\n UpdateTableWithCsvDialog: lazy(\n () => import('./components/table/CsvPreview/UpdateTableWithCsvDialog'),\n ),\n UserAccessRequestHistoryPlace: lazy(\n () =>\n import('./components/dataaccess/UserAccessRequestHistory/UserAccessRequestHistoryPlace'),\n ),\n UserCard: lazy(() => import('./components/UserCard/UserCard')),\n UserProfileLinks: lazy(\n () => import('./components/UserProfileLinks/UserProfileLinks'),\n ),\n displayToast,\n getCurrentCookiePreferences,\n}\n\nconst Analytics = {\n sendAnalyticsEvent,\n sendSearchQuerySubmittedEvent,\n sendSearchResultsReturnedEvent,\n sendSearchResultReturnedEvent,\n sendSearchResultClickedEvent,\n}\n\n// Include the version in the build\nconst SynapseReactClientVersion = __SRC_VERSION__\n\nexport {\n Analytics,\n HttpClient,\n SynapseReactClientVersion,\n SynapseComponents,\n SynapseConstants,\n SynapseClient,\n SynapseContext,\n SynapseEnums,\n SynapseQueries,\n Palettes,\n xssOptions,\n SynapseSessionManager,\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAwCA,IAAM,IAAe,EACnB,0BACF,GAEM,IAAiB;CACrB;CACA;CACA;CACA;AACF,GAEM,IAAoB;CACxB,4BAA4B,QACpB,OAAO,mDACf;CACA,uBAAuB,QACf,OAAO,8DACf;CACA,sCAAsC,QAC9B,OAAO,6DACf;CACA,oBAAoB,QACZ,OAAO,wDACf;CACA,oCAAoC,QAEhC,OAAO,sGACX;CACA,8BAA8B,QAE1B,OAAO,mEACX;CACA,mBAAmB,QACX,OAAO,sDACf;CACA,qBAAqB,QAAW,OAAO,4CAAmC;CAC1E,uCAAuC,QAC/B,OAAO,8DACf;CACA,wBAAwB,QAChB,OAAO,6CACf;CACA,0BAA0B,QAClB,OAAO,4DACf;CACA,uBAAuB,QACf,OAAO,8DACf;CACA,qBAAqB,QACb,OAAO,kDACf;CACA,YAAY,QAAW,OAAO,8CAA2C;CACzE,kBAAkB,QACV,OAAO,mDACf;CACA,oBAAoB,QACZ,OAAO,2DACf;CACA,kBAAkB,QAAW,OAAO,yCAAsC;CAC1E,kBAAkB,QACV,OAAO,gDACf;CACA,sBAAsB,QACd,OAAO,uDACf;CACA,kBAAkB,QACV,OAAO,2DACf;CACA,kBAAkB,QACV,OAAO,oDACf;CACA,gBAAgB,QAAW,OAAO,uCAA8B;CAChE,cAAc,QAAW,OAAO,4CAAyC;CACzE,YAAY,QAAW,OAAO,wCAAqC;CACnE,mBAAmB,QAAW,OAAO,0CAAiC;CACtE,aAAa,QAAW,OAAO,8CAA2C;CAC1E,uBAAuB,QACf,OAAO,gEACf;CACA,oBAAoB,QACZ,OAAO,2DACf;CACA,iBAAiB,QACT,OAAO,kDACf;CACA,gBAAgB,QAAW,OAAO,6BAA0B;CAC5D,mBAAmB,QACX,OAAO,iDACf;CACA,4BAA4B,QAExB,OAAO,mEACX;CACA,oBAAoB,QAClB,OAAO,yDAAsD,MAAK,OAAM,EACtE,SAAS,EAAE,mBACb,EAAE,CACJ;CACA,WAAW,QAAW,OAAO,kCAA+B;CAC5D,gBAAgB,QAAW,OAAO,4CAAyC;CAC3E,sBAAsB,QACd,OAAO,kDACf;CACA,eAAe,QAAW,OAAO,0CAAuC;CACxE,aAAa,QAAW,OAAO,0CAAuC;CACtE,gBAAgB,QACR,OAAO,gDACf;CACA,iBAAiB,QACT,OAAO,kDACf;CACA,0BAA0B,QAClB,OAAO,oDACf;CACA,UAAU,QAAW,OAAO,0CAAuC;CACnE,WAAW,QAAW,OAAO,wCAAqC;CAClE,aAAa,QAAW,OAAO,0CAAuC;CACtE,aAAa,QACL,OAAO,sDACf;CACA,WAAW,QAAW,OAAO,sCAAmC;CAChE,SAAS,QAAW,OAAO,kCAA+B;CAC1D,mBAAmB,QAEf,OAAO,kEACX;CACA,iBAAiB,QACT,OAAO,wDACf;CACA,mBAAmB,QACX,OAAO,sDACf;CACA,cAAc,QAAW,OAAO,4CAAyC;CACzE,yBAAyB,QACjB,OAAO,yDACf;CACA,uBAAuB,QACf,OAAO,8DACf;CACA,iBAAiB,QACT,OAAO,kDACf;CACA,qBAAqB,QACb,OAAO,0DACf;CACA,qCAAqC,QAC7B,OAAO,iEACf;CACA,mBAAmB,QACX,OAAO,+CACf;CACA,2BAA2B,QAEvB,OAAO,sEACX;CACA,eAAe,QAAW,OAAO,sCAA6B;CAC9D,gBAAgB,QAAW,OAAO,0CAAuC;CACzE,4BAA4B,QAExB,OAAO,mEACX;CACA,wBAAwB,QAChB,OAAO,gEACf;CACA,gBAAgB,QAAW,OAAO,iCAA8B;CAChE,gCAAgC,QAE5B,OAAO,2EACX;CACA,kBAAkB,QAAW,OAAO,yCAAgC;CACpE,aAAa,QAAW,OAAO,0CAAuC;CACtE,aAAa,QAAW,OAAO,uCAAoC;CACnE,eAAe,QAAW,OAAO,8CAA2C;CAC5E,mBAAmB,QACX,OAAO,sDACf;CACA,kBAAkB,QACV,OAAO,oDACf;CACA,kBAAkB,QACV,OAAO,qDACf;CACA,sBAAsB,QACd,OAAO,4DACf;CACA,mBAAmB,QACX,OAAO,6DACf;CACA;CACA,yBAAyB,QAErB,OAAO,kEACX;CACA,cAAc,QAAW,OAAO,qCAAkC;CAClE,0BAA0B,QAClB,OAAO,4DACf;CACA,+BAA+B,QAE3B,OAAO,oFACX;CACA,UAAU,QAAW,OAAO,oCAAiC;CAC7D,kBAAkB,QACV,OAAO,oDACf;CACA;CACA;AACF,GAEM,IAAY;CAChB;CACA;CACA;CACA;CACA;AACF,GAGM,IAAA"}
|
|
1
|
+
{"version":3,"file":"SWC.index.js","names":[],"sources":["../src/SWC.index.ts"],"sourcesContent":["/**\n * SWC.index.ts represents the entry point for the Synapse React Client library as it is published to NPM and\n * used by SynapseWebClient.\n *\n * If you wish to export a component or other object to be used by SynapseWebClient, you should add it to this file.\n */\n\nimport { lazy } from 'react'\nimport {\n displayToast,\n SynapseToastContainer,\n} from './components/ToastMessage/ToastMessage'\nimport SynapseClient, { HttpClient } from './synapse-client'\nimport * as SynapseQueries from './synapse-queries'\nimport Palettes from './theme/palette/Palettes'\nimport { SynapseConstants } from './utils'\nimport { sendAnalyticsEvent } from './utils/analytics/sendAnalyticsEvent'\nimport {\n sendSearchQuerySubmittedEvent,\n sendSearchResultClickedEvent,\n sendSearchResultReturnedEvent,\n sendSearchResultsReturnedEvent,\n} from './utils/analytics/sendSearchEvent'\nimport { FullContextProvider } from './utils/context/FullContextProvider'\nimport {\n SynapseContextConsumer,\n SynapseContextProvider,\n useSynapseContext,\n} from './utils/context/SynapseContext'\nimport { BackendDestinationEnum } from './utils/functions'\nimport { xssOptions } from './utils/functions/SanitizeHtmlUtils'\nimport { getCurrentCookiePreferences } from './utils/hooks'\nimport { SynapseSessionManager } from './utils/AppUtils'\n\n// Also include scss in the bundle\nimport './style/main.scss'\n\n// Injected at build time by Vite's `define`\ndeclare const __SRC_VERSION__: string\n\nconst SynapseEnums = {\n BackendDestinationEnum,\n}\n\nconst SynapseContext = {\n FullContextProvider,\n SynapseContextProvider,\n SynapseContextConsumer,\n useSynapseContext,\n}\n\nconst SynapseComponents = {\n AccessRequirementAclEditor: lazy(\n () => import('./components/AccessRequirementAclEditor'),\n ),\n AccessRequirementList: lazy(\n () => import('./components/AccessRequirementList/AccessRequirementList'),\n ),\n AccessRequirementRelatedProjectsList: lazy(\n () => import('./components/AccessRequirementRelatedProjectsList'),\n ),\n AccountLevelBadges: lazy(\n () => import('./components/AccountLevelBadges/AccountLevelBadges'),\n ),\n AddToDownloadListConfirmationAlert: lazy(\n () =>\n import('./components/download_list/AddToDownloadListConfirmationAlert/AddToDownloadListConfirmationAlert'),\n ),\n AvailableEvaluationQueueList: lazy(\n () =>\n import('./components/ChallengeSubmission/AvailableEvaluationQueueList'),\n ),\n CertificationQuiz: lazy(\n () => import('./components/CertificationQuiz/CertificationQuiz'),\n ),\n CookiesNotification: lazy(() => import('./components/CookiesNotification')),\n CreateOrUpdateAccessRequirementWizard: lazy(\n () => import('./components/CreateOrUpdateAccessRequirementWizard'),\n ),\n CreateOrUpdateDoiModal: lazy(\n () => import('./components/doi/CreateOrUpdateDoiModal'),\n ),\n CreateTableFromCsvDialog: lazy(\n () => import('./components/table/CsvPreview/CreateTableFromCsvDialog'),\n ),\n CreateTableViewWizard: lazy(\n () => import('./components/CreateTableViewWizard/CreateTableViewWizard'),\n ),\n CreatedByModifiedBy: lazy(\n () => import('./components/entity/page/CreatedByModifiedBy'),\n ),\n CsvPreview: lazy(() => import('./components/table/CsvPreview/CsvPreview')),\n CuratorDashboard: lazy(\n () => import('./features/curator/dashboard/CuratorDashboard'),\n ),\n DatasetItemsEditor: lazy(\n () => import('./components/SynapseTable/datasets/DatasetItemsEditor'),\n ),\n DiscussionThread: lazy(() => import('./components/Forum/DiscussionThread')),\n DownloadCartPage: lazy(\n () => import('./components/DownloadCart/DownloadCartPage'),\n ),\n EntityAclEditorModal: lazy(\n () => import('./components/EntityAclEditor/EntityAclEditorModal'),\n ),\n EntityActionMenu: lazy(\n () => import('./components/entity/page/action_menu/EntityActionMenu'),\n ),\n EntityBadgeIcons: lazy(\n () => import('./components/EntityBadgeIcons/EntityBadgeIcons'),\n ),\n EntityCitation: lazy(() => import('./components/EntityCitation')),\n EntityFinder: lazy(() => import('./components/EntityFinder/EntityFinder')),\n EntityForm: lazy(() => import('./components/EntityForm/EntityForm')),\n EntityHeaderTable: lazy(() => import('./components/EntityHeaderTable')),\n EntityModal: lazy(() => import('./components/entity/metadata/EntityModal')),\n EntityPageBreadcrumbs: lazy(\n () => import('./components/entity/page/breadcrumbs/EntityPageBreadcrumbs'),\n ),\n EntityPageTitleBar: lazy(\n () => import('./components/entity/page/title_bar/EntityPageTitleBar'),\n ),\n EntityTreeTable: lazy(\n () => import('./components/EntityTreeTable/EntityTreeTable'),\n ),\n EntitySidebar: lazy(() => import('./components/EntitySidebar/EntitySidebar')),\n EntityTypeIcon: lazy(() => import('./components/EntityIcon')),\n EntityUploadModal: lazy(\n () => import('./components/EntityUpload/EntityUploadModal'),\n ),\n EntityViewScopeEditorModal: lazy(\n () =>\n import('./components/EntityViewScopeEditor/EntityViewScopeEditorModal'),\n ),\n CreateProjectModal: lazy(() =>\n import('./components/CreateProjectModal/CreateProjectModal').then(m => ({\n default: m.CreateProjectModal,\n })),\n ),\n ErrorPage: lazy(() => import('./components/error/ErrorPage')),\n EvaluationCard: lazy(() => import('./components/Evaluation/EvaluationCard')),\n EvaluationEditorPage: lazy(\n () => import('./components/Evaluation/EvaluationEditorPage'),\n ),\n FavoritesPage: lazy(() => import('./components/favorites/FavoritesPage')),\n ForumSearch: lazy(() => import('./components/ForumSearch/ForumSearch')),\n FullWidthAlert: lazy(\n () => import('./components/FullWidthAlert/FullWidthAlert'),\n ),\n GoogleAnalytics: lazy(\n () => import('./components/GoogleAnalytics/GoogleAnalytics'),\n ),\n GovernanceMarkdownGithub: lazy(\n () => import('./components/Markdown/GovernanceMarkdownGithub'),\n ),\n GridPage: lazy(() => import('./features/curator/GridPage/GridPage')),\n HasAccess: lazy(() => import('./components/HasAccess/HasAccessV2')),\n HelpPopover: lazy(() => import('./components/HelpPopover/HelpPopover')),\n HtmlPreview: lazy(\n () => import('./components/FilePreview/HtmlPreview/HtmlPreview'),\n ),\n IDUReport: lazy(() => import('./components/IDUReport/IDUReport')),\n IconSvg: lazy(() => import('./components/IconSvg/IconSvg')),\n MetadataTasksPage: lazy(\n () =>\n import('./features/entity/metadata-task/components/MetadataTasksPage'),\n ),\n OAuthManagement: lazy(\n () => import('./components/OAuthClientManagement/OAuthManagement'),\n ),\n OrientationBanner: lazy(\n () => import('./components/OrientationBanner/OrientationBanner'),\n ),\n PageProgress: lazy(() => import('./components/PageProgress/PageProgress')),\n ProjectDataAvailability: lazy(\n () => import('./components/ProjectStorage/ProjectDataAvailability'),\n ),\n ProjectVisibilityChip: lazy(\n () => import('./components/ProjectVisibilityChip/ProjectVisibilityChip'),\n ),\n ProvenanceGraph: lazy(\n () => import('./components/ProvenanceGraph/ProvenanceGraph'),\n ),\n QueryWrapperPlotNav: lazy(\n () => import('./components/QueryWrapperPlotNav/QueryWrapperPlotNav'),\n ),\n RejectProfileValidationRequestModal: lazy(\n () => import('./components/dataaccess/RejectProfileValidationRequestModal'),\n ),\n ReviewerDashboard: lazy(\n () => import('./components/dataaccess/ReviewerDashboard'),\n ),\n SearchQueryWrapperPlotNav: lazy(\n () =>\n import('./components/SearchQueryWrapperPlotNav/SearchQueryWrapperPlotNav'),\n ),\n ShareThisPage: lazy(() => import('./components/ShareThisPage')),\n SkeletonButton: lazy(() => import('./components/Skeleton/SkeletonButton')),\n SqlDefinedTableEditorModal: lazy(\n () =>\n import('./components/SqlDefinedTableEditor/SqlDefinedTableEditorModal'),\n ),\n StandaloneQueryWrapper: lazy(\n () => import('./components/StandaloneQueryWrapper/StandaloneQueryWrapper'),\n ),\n StatisticsPlot: lazy(() => import('./components/StatisticsPlot')),\n SubmissionViewScopeEditorModal: lazy(\n () =>\n import('./components/SubmissionViewScopeEditor/SubmissionViewScopeEditorModal'),\n ),\n SubscriptionPage: lazy(() => import('./components/SubscriptionPage')),\n SynapseChat: lazy(() => import('./components/SynapseChat/SynapseChat')),\n SynapseGrid: lazy(() => import('./components/DataGrid/SynapseGrid')),\n SynapseFooter: lazy(() => import('./components/SynapseFooter/SynapseFooter')),\n SynapseHomepageV2: lazy(\n () => import('./components/SynapseHomepageV2/SynapseHomepageV2'),\n ),\n SynapseNavDrawer: lazy(\n () => import('./components/SynapseNavDrawer/SynapseNavDrawer'),\n ),\n SynapsePlansPage: lazy(\n () => import('./components/SynapseHomepageV2/SynapsePlansPage'),\n ),\n SynapsePortalBanners: lazy(\n () => import('./components/SynapsePortalBanners/SynapsePortalBanners'),\n ),\n SynapseSearchPage: lazy(\n () => import('./components/SynapseSearchPageResults/SynapseSearchPage'),\n ),\n SynapseToastContainer,\n TableColumnSchemaEditor: lazy(\n () =>\n import('./components/TableColumnSchemaEditor/TableColumnSchemaEditor'),\n ),\n TrashCanList: lazy(() => import('./components/trash/TrashCanList')),\n UpdateTableWithCsvDialog: lazy(\n () => import('./components/table/CsvPreview/UpdateTableWithCsvDialog'),\n ),\n UserAccessRequestHistoryPlace: lazy(\n () =>\n import('./components/dataaccess/UserAccessRequestHistory/UserAccessRequestHistoryPlace'),\n ),\n UserCard: lazy(() => import('./components/UserCard/UserCard')),\n UserProfileLinks: lazy(\n () => import('./components/UserProfileLinks/UserProfileLinks'),\n ),\n displayToast,\n getCurrentCookiePreferences,\n}\n\nconst Analytics = {\n sendAnalyticsEvent,\n sendSearchQuerySubmittedEvent,\n sendSearchResultsReturnedEvent,\n sendSearchResultReturnedEvent,\n sendSearchResultClickedEvent,\n}\n\n// Include the version in the build\nconst SynapseReactClientVersion = __SRC_VERSION__\n\nexport {\n Analytics,\n HttpClient,\n SynapseReactClientVersion,\n SynapseComponents,\n SynapseConstants,\n SynapseClient,\n SynapseContext,\n SynapseEnums,\n SynapseQueries,\n Palettes,\n xssOptions,\n SynapseSessionManager,\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataAccessRequestAccessorsFilesForm.js","names":[],"sources":["../../../../../src/components/AccessRequirementList/ManagedACTAccessRequirementRequestFlow/DataAccessRequestAccessorsFilesForm/DataAccessRequestAccessorsFilesForm.tsx"],"sourcesContent":["import { NewReleasesOutlined } from '@mui/icons-material'\nimport {\n Alert,\n AlertProps as MuiAlertProps,\n Box,\n Button,\n DialogActions,\n DialogContent,\n DialogTitle,\n Divider,\n IconButton,\n Link,\n Stack,\n Typography,\n} from '@mui/material'\nimport { deepEquals } from '@rjsf/utils'\nimport { SynapseClientError } from '@sage-bionetworks/synapse-client/util/SynapseClientError'\nimport {\n AccessorChange,\n AccessType,\n FileHandleAssociateType,\n FileHandleAssociation,\n FileUploadComplete,\n ManagedACTAccessRequirement,\n Renewal,\n Request,\n RestrictableObjectType,\n UploadCallbackResp,\n} from '@sage-bionetworks/synapse-types'\nimport { ReactNode, useEffect, useState } from 'react'\nimport {\n useGetCurrentUserProfile,\n useGetDataAccessRequestForUpdate,\n useSubmitDataAccessRequest,\n useUpdateDataAccessRequest,\n} from '../../../../synapse-queries'\nimport { useSynapseContext } from '../../../../utils'\nimport { SynapseErrorBoundary } from '../../../error/ErrorBanner'\nimport IconSvg from '../../../IconSvg/IconSvg'\nimport DataAccessRequestAccessorsEditor, {\n DataAccessRequestAccessorsEditorProps,\n} from '../DataAccessRequestAccessorsEditor'\nimport DocumentTemplate from '../DocumentTemplate'\nimport ManagedACTAccessRequirementFormWikiWrapper from '../ManagedACTAccessRequirementFormWikiWrapper'\nimport { UploadDocumentField } from '../UploadDocumentField'\n\nfunction AccessorRequirementHelpText(props: {\n managedACTAccessRequirement: ManagedACTAccessRequirement\n}) {\n const { managedACTAccessRequirement } = props\n let link: string = ''\n let msg: string = ''\n\n if (\n managedACTAccessRequirement.isCertifiedUserRequired &&\n managedACTAccessRequirement.isValidatedProfileRequired\n ) {\n link = 'https://help.synapse.org/docs/User-Types.2007072795.html'\n msg =\n 'All data requesters must be certified users and have a validated user profile.'\n } else if (managedACTAccessRequirement.isCertifiedUserRequired) {\n link =\n 'https://help.synapse.org/docs/User-Types.2007072795.html#UserAccountTiers-CertifiedUsers'\n msg = 'All data requesters must be a certified user.'\n } else if (managedACTAccessRequirement.isValidatedProfileRequired) {\n link =\n 'https://help.synapse.org/docs/User-Types.2007072795.html#UserAccountTiers-ValidatedUsers'\n msg = 'All data requesters must have a validated user profile.'\n }\n return (\n <>\n {managedACTAccessRequirement.isDUCRequired ? (\n <Box sx={{ display: 'flex', gap: 2, alignItems: 'center', py: 1 }}>\n <NewReleasesOutlined sx={{ color: 'error.main' }} />\n <div>\n You must list the Synapse user names of all collaborators listed in\n your Data Use Certificate (DUC).\n </div>\n </Box>\n ) : (\n ''\n )}\n {msg}{' '}\n {link && (\n <Link href={link} target={'_blank'} rel={'noreferrer'}>\n Learn more\n </Link>\n )}\n </>\n )\n}\n\nexport type DataAccessRequestAccessorsFilesFormProps = {\n /**\n * The ID of the object of interest. This corresponds to the subjectId of the {@link CreateSubmissionRequest}\n */\n subjectId: string\n /* The type of the subject */\n subjectType: RestrictableObjectType\n /* The access requirement to which the user is requesting access */\n managedACTAccessRequirement: ManagedACTAccessRequirement\n onSubmissionCreated: (submissionId: string) => void\n researchProjectId: string\n onHide: () => void\n /* Callback invoked when the user clicks cancel. The unsaved, modified dataAccessRequest is returned so the calling component may prompt the user to save this data */\n onCancel: (modifiedDataAccessRequest: Request | Renewal) => void\n /** Callback invoked when the 'Back' action button is clicked */\n onBackClicked: () => void\n}\n\nexport type AlertProps = {\n key: MuiAlertProps['severity']\n message: string | ReactNode\n}\n\n/**\n * Step 2 of the Data Access Request/Renewal flow prompts the user to\n * - Manage the list of accessors, i.e. Synapse users who will gain, renew, or lose access\n * - Download and upload documents required by the Access Requirement\n * - If a renewal, provide publications and a summary of use statement.\n *\n * The component expects a researchProjectId, which should reference complete researchProject created in Step 1.\n * The user may click a \"Submit\" button, which will save the request and issue a data access submission that references\n * the requestId created/updated in this component.\n */\nexport default function DataAccessRequestAccessorsFilesForm(\n props: DataAccessRequestAccessorsFilesFormProps,\n) {\n const {\n onSubmissionCreated,\n managedACTAccessRequirement,\n subjectId,\n subjectType,\n researchProjectId,\n onCancel,\n onBackClicked,\n } = props\n const { isAuthenticated } = useSynapseContext()\n const { data: user } = useGetCurrentUserProfile({ enabled: isAuthenticated })\n const [alert, setAlert] = useState<AlertProps | undefined>()\n const [accessorChanges, setAccessorChanges] = useState<\n AccessorChange[] | undefined\n >()\n const [summaryOfUse, setSummaryOfUse] = useState<string | undefined>()\n const [publication, setPublication] = useState<string | undefined>()\n\n const { data: dataAccessRequest, isLoading: isLoadingGetDataAccessRequest } =\n useGetDataAccessRequestForUpdate(String(managedACTAccessRequirement.id), {\n enabled: isAuthenticated,\n // Infinite staleTime ensures this won't get re-fetched unless explicitly invalidated by the mutation\n staleTime: Infinity,\n // This call should never fail, so if we run into an error, throwing to an error boundary is acceptable\n throwOnError: true,\n })\n\n const isRenewal =\n dataAccessRequest?.concreteType ===\n 'org.sagebionetworks.repo.model.dataaccess.Renewal'\n\n function onError(e: SynapseClientError) {\n console.log('RequestDataAccessStep2: Error updating form', e)\n setAlert({\n key: 'error',\n message: getErrorMessage(e.reason),\n })\n }\n\n const { mutate: submit, isPending: submitDataAccessRequestIsPending } =\n useSubmitDataAccessRequest({\n onSuccess: submission => {\n onSubmissionCreated(submission.submissionId)\n },\n onError: onError,\n })\n\n const {\n mutateAsync: updateRequestAsync,\n isPending: updateDataAccessRequestIsPending,\n } = useUpdateDataAccessRequest({\n onError: onError,\n })\n\n const isLoading =\n isLoadingGetDataAccessRequest ||\n updateDataAccessRequestIsPending ||\n submitDataAccessRequestIsPending\n\n /**\n * This effect comprises a collection of updates we should immediately apply to a data access request.\n */\n useEffect(() => {\n if (dataAccessRequest && user) {\n let shouldUpdate = false\n\n // Attach the researchProjectId to the request\n if (!dataAccessRequest.researchProjectId) {\n dataAccessRequest.researchProjectId = researchProjectId\n shouldUpdate = true\n }\n\n // Add the current user with GAIN_ACCESS to the list of accessors\n const currentUserWithGainAccess: AccessorChange = {\n userId: user.ownerId,\n type: isRenewal ? AccessType.RENEW_ACCESS : AccessType.GAIN_ACCESS,\n }\n if (\n !dataAccessRequest.accessorChanges ||\n !dataAccessRequest.accessorChanges.find(item =>\n deepEquals(item, currentUserWithGainAccess),\n )\n ) {\n dataAccessRequest.accessorChanges = [\n currentUserWithGainAccess,\n ...(dataAccessRequest.accessorChanges || []),\n ]\n shouldUpdate = true\n }\n\n // SWC-5765: Filter out duplicate accessors\n const seen = new Set()\n const uniqueAccessorChanges = dataAccessRequest.accessorChanges.filter(\n accessorChange => {\n return seen.has(accessorChange.userId)\n ? false\n : seen.add(accessorChange.userId)\n },\n )\n if (\n uniqueAccessorChanges.length !==\n dataAccessRequest.accessorChanges.length\n ) {\n dataAccessRequest.accessorChanges = uniqueAccessorChanges\n shouldUpdate = true\n }\n\n if (shouldUpdate) {\n updateRequestAsync(dataAccessRequest)\n }\n }\n }, [\n dataAccessRequest,\n isRenewal,\n researchProjectId,\n updateRequestAsync,\n user,\n ])\n\n /**\n * Fields other than uploaded files are NOT immediately synced with the server. Set local state if these values exist in the\n * fetched object, and no value exists in local state.\n */\n useEffect(() => {\n if (dataAccessRequest) {\n if (dataAccessRequest.accessorChanges && accessorChanges == undefined) {\n setAccessorChanges(dataAccessRequest.accessorChanges)\n }\n if (\n isRenewal &&\n dataAccessRequest.publication &&\n publication == undefined\n ) {\n setPublication(dataAccessRequest.publication)\n }\n if (\n isRenewal &&\n dataAccessRequest.summaryOfUse &&\n summaryOfUse == undefined\n ) {\n setSummaryOfUse(dataAccessRequest.summaryOfUse)\n }\n }\n // Intentionally only re-synchronize state when server state changes\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [dataAccessRequest])\n\n function getDataAccessRequestWithLocalState(): Request | Renewal {\n return {\n ...dataAccessRequest,\n // append local state to the request\n accessorChanges: accessorChanges,\n publication,\n summaryOfUse,\n } as Request | Renewal\n }\n\n async function handleSubmit() {\n if (dataAccessRequest) {\n // Save the request\n const requestObject = await updateRequestAsync(\n getDataAccessRequestWithLocalState(),\n )\n // Create a submission and attach the request\n submit({\n request: {\n requestId: requestObject.id,\n requestEtag: requestObject.etag,\n subjectId: subjectId,\n subjectType: subjectType,\n },\n accessRequirementId: String(managedACTAccessRequirement.id),\n })\n }\n }\n\n const getErrorMessage = (reason: string = '') => {\n return (\n <>\n <strong>Sorry, there is an error in submitting your request.</strong>\n <br />\n {reason}\n </>\n )\n }\n\n const onAccessorChange: DataAccessRequestAccessorsEditorProps['onChange'] =\n updater => {\n // Copy the array so the caller doesn't have to worry about immutability\n setAccessorChanges([...updater(accessorChanges || [])])\n }\n\n const onClearAttachment = (fid: string) => {\n updateRequestAsync({\n ...dataAccessRequest!,\n attachments: dataAccessRequest!.attachments?.filter(item => item !== fid),\n })\n }\n\n const uploadCallback = (\n data: UploadCallbackResp,\n context: keyof Pick<\n Request,\n 'attachments' | 'irbFileHandleId' | 'ducFileHandleId'\n >,\n ) => {\n if (data.resp && data.success) {\n // Files are uploaded and synced with the server immediately\n const uploadResponse: FileUploadComplete = data.resp\n if (context === 'attachments') {\n updateRequestAsync({\n ...dataAccessRequest!,\n attachments: [\n ...(dataAccessRequest!.attachments || []),\n uploadResponse.fileHandleId,\n ],\n })\n } else {\n updateRequestAsync({\n ...dataAccessRequest!,\n [context]: uploadResponse.fileHandleId,\n })\n }\n } else if (!data.success && data.error) {\n // show the error\n console.log(\n 'RequestDataAccessStep2: Error uploading the file',\n data.error,\n )\n setAlert({\n key: 'error',\n message: getErrorMessage(data.error.reason),\n })\n }\n }\n\n const ducFileHandleAssociation: FileHandleAssociation[] =\n dataAccessRequest?.ducFileHandleId\n ? [\n {\n fileHandleId: dataAccessRequest?.ducFileHandleId,\n associateObjectType:\n FileHandleAssociateType.DataAccessRequestAttachment,\n associateObjectId: String(dataAccessRequest.id),\n },\n ]\n : []\n const irbFileHandleAssociation: FileHandleAssociation[] =\n dataAccessRequest?.irbFileHandleId\n ? [\n {\n fileHandleId: dataAccessRequest.irbFileHandleId,\n associateObjectType:\n FileHandleAssociateType.DataAccessRequestAttachment,\n associateObjectId: String(dataAccessRequest.id),\n },\n ]\n : []\n\n const attachmentFileHandleAssociations: FileHandleAssociation[] =\n (dataAccessRequest?.attachments || []).map(attachmentFileHandleId => ({\n fileHandleId: attachmentFileHandleId,\n associateObjectType: FileHandleAssociateType.DataAccessRequestAttachment,\n associateObjectId: String(dataAccessRequest!.id),\n })) ?? []\n\n return (\n <>\n <DialogTitle>\n <Stack\n direction=\"row\"\n sx={{\n alignItems: 'center',\n gap: '5px',\n }}\n >\n Request Access\n <Box sx={{ flexGrow: 1 }} />\n <IconButton onClick={props.onHide}>\n <IconSvg icon={'close'} wrap={false} sx={{ color: 'grey.700' }} />\n </IconButton>\n </Stack>\n </DialogTitle>\n <DialogContent>\n <ManagedACTAccessRequirementFormWikiWrapper\n managedACTAccessRequirementId={String(managedACTAccessRequirement.id)}\n >\n <Box\n component={'form'}\n sx={{\n // Must set a minHeight to ensure the user picker in the DataAccessRequestAccessorsEditor doesn't get cut off\n minHeight: '475px',\n }}\n onSubmit={e => e.preventDefault()}\n >\n <Typography variant={'body1'} sx={{ mb: 2 }}>\n Please provide the information below to submit the request for\n access.\n </Typography>\n\n {dataAccessRequest && user && (\n <DataAccessRequestAccessorsEditor\n accessorChanges={accessorChanges || []}\n onChange={onAccessorChange}\n isRenewal={isRenewal}\n helpText={\n <AccessorRequirementHelpText\n managedACTAccessRequirement={managedACTAccessRequirement}\n />\n }\n />\n )}\n\n {(managedACTAccessRequirement?.isDUCRequired ||\n managedACTAccessRequirement?.isIRBApprovalRequired ||\n managedACTAccessRequirement?.areOtherAttachmentsRequired) && (\n <Divider sx={{ my: 4 }} />\n )}\n {/* DUC */}\n {managedACTAccessRequirement?.isDUCRequired && (\n <>\n {managedACTAccessRequirement?.ducTemplateFileHandleId && (\n <DocumentTemplate\n title={'Download DUC Template'}\n description={\n 'As a first step, you will need to download the most current version of the Data Use Certificate.'\n }\n fileHandleAssociation={{\n fileHandleId:\n managedACTAccessRequirement.ducTemplateFileHandleId,\n associateObjectType:\n FileHandleAssociateType.AccessRequirementAttachment,\n associateObjectId: String(managedACTAccessRequirement.id),\n }}\n downloadButtonText={'Download DUC Template'}\n />\n )}\n <Typography variant={'headline3'} sx={{ mt: 4, mb: 2 }}>\n Fill out and upload a Data Use Certificate\n </Typography>\n <Typography variant={'body1'} sx={{ my: 2 }}>\n You must download and fill out a Data Use Certificate (DUC).\n Be sure to upload the completed DUC below once you've\n completed it.\n </Typography>\n <Typography variant={'body1'} component={'ol'}>\n <li>Download the DUC template file.</li>\n <li>\n Fill out the DUC template, following the instructions in the\n file.\n </li>\n <li>\n Upload the completed certificate using the button below:\n </li>\n </Typography>\n <SynapseErrorBoundary>\n <UploadDocumentField\n id={'duc'}\n isLoading={isLoading}\n uploadCallback={resp =>\n uploadCallback(resp, 'ducFileHandleId')\n }\n documentName={'Data Use Certificate'}\n fileHandleAssociations={ducFileHandleAssociation}\n />\n </SynapseErrorBoundary>\n {(managedACTAccessRequirement?.isIRBApprovalRequired ||\n managedACTAccessRequirement?.areOtherAttachmentsRequired) && (\n <Divider sx={{ my: 4 }} />\n )}\n </>\n )}\n\n {/* IRB */}\n {managedACTAccessRequirement?.isIRBApprovalRequired && (\n <>\n <Typography variant={'headline3'} sx={{ my: 2 }}>\n IRB Approval\n </Typography>\n <Typography variant={'body1'} sx={{ my: 2 }}>\n Upload a signed IRB letter on institutional letterhead. The\n letter must include the names of all the datasets requested,\n as well as the names of the data requesters above. Use the\n button below to upload the document.\n </Typography>\n <SynapseErrorBoundary>\n <UploadDocumentField\n id={'irb'}\n isLoading={isLoading}\n documentName={'IRB Approval Letter'}\n uploadCallback={resp =>\n uploadCallback(resp, 'irbFileHandleId')\n }\n fileHandleAssociations={irbFileHandleAssociation}\n />\n </SynapseErrorBoundary>\n {managedACTAccessRequirement?.areOtherAttachmentsRequired && (\n <Divider sx={{ my: 4 }} />\n )}\n </>\n )}\n\n {\n /* Attachments */\n managedACTAccessRequirement?.areOtherAttachmentsRequired && (\n <>\n <Typography variant={'headline3'} sx={{ my: 2 }}>\n Upload other required documents\n </Typography>\n <Typography variant={'body1'} sx={{ my: 2 }}>\n You must upload other required documents. Please review the\n instructions to gain data access to determine which\n documents must also be uploaded.\n </Typography>\n <SynapseErrorBoundary>\n <UploadDocumentField\n id={'file-attachment'}\n isLoading={isLoading}\n documentName={'Attachment'}\n uploadCallback={res => uploadCallback(res, 'attachments')}\n isMultiFileUpload={true}\n fileHandleAssociations={attachmentFileHandleAssociations}\n onClearAttachment={onClearAttachment}\n />\n </SynapseErrorBoundary>\n </>\n )\n }\n\n {\n // SWC-7319 - Per GovernanceInnovation, do not show these fields on renewal\n // Publications & Summary of Use\n // isRenewal && (\n // <>\n // <TextField\n // id={'publications'}\n // label={'Publication(s)'}\n // disabled={submitDataAccessRequestIsPending}\n // multiline\n // rows={3}\n // value={publication}\n // onChange={(e: ChangeEvent<HTMLTextAreaElement>) =>\n // setPublication(e.target.value)\n // }\n // />\n // <TextField\n // id={'summaryOfUse'}\n // label={'Summary of use'}\n // value={summaryOfUse}\n // disabled={submitDataAccessRequestIsPending}\n // multiline\n // rows={3}\n // onChange={(e: ChangeEvent<HTMLTextAreaElement>) =>\n // setSummaryOfUse(e.target.value)\n // }\n // />\n // </>\n // )\n }\n </Box>\n </ManagedACTAccessRequirementFormWikiWrapper>\n {alert && <Alert severity={alert.key}>{alert.message}</Alert>}\n </DialogContent>\n <DialogActions>\n <Button\n variant={'outlined'}\n onClick={() => {\n onBackClicked()\n }}\n >\n Back\n </Button>\n <Box sx={{ flexGrow: 1 }}>{/* spacer */}</Box>\n\n <Button\n variant=\"outlined\"\n disabled={submitDataAccessRequestIsPending}\n onClick={() => {\n if (dataAccessRequest) {\n // include the local state in the onCancel callback so the user may save their changes\n onCancel(getDataAccessRequestWithLocalState())\n }\n }}\n >\n Cancel\n </Button>\n <Button\n variant=\"contained\"\n disabled={submitDataAccessRequestIsPending}\n onClick={() => {\n handleSubmit()\n }}\n >\n Submit\n </Button>\n </DialogActions>\n </>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DataAccessRequestAccessorsFilesForm.js","names":[],"sources":["../../../../../src/components/AccessRequirementList/ManagedACTAccessRequirementRequestFlow/DataAccessRequestAccessorsFilesForm/DataAccessRequestAccessorsFilesForm.tsx"],"sourcesContent":["import { NewReleasesOutlined } from '@mui/icons-material'\nimport {\n Alert,\n AlertProps as MuiAlertProps,\n Box,\n Button,\n DialogActions,\n DialogContent,\n DialogTitle,\n Divider,\n IconButton,\n Link,\n Stack,\n Typography,\n} from '@mui/material'\nimport { deepEquals } from '@rjsf/utils'\nimport { SynapseClientError } from '@sage-bionetworks/synapse-client/util/SynapseClientError'\nimport {\n AccessorChange,\n AccessType,\n FileHandleAssociateType,\n FileHandleAssociation,\n FileUploadComplete,\n ManagedACTAccessRequirement,\n Renewal,\n Request,\n RestrictableObjectType,\n UploadCallbackResp,\n} from '@sage-bionetworks/synapse-types'\nimport { ReactNode, useEffect, useState } from 'react'\nimport {\n useGetCurrentUserProfile,\n useGetDataAccessRequestForUpdate,\n useSubmitDataAccessRequest,\n useUpdateDataAccessRequest,\n} from '../../../../synapse-queries'\nimport { useSynapseContext } from '../../../../utils'\nimport { SynapseErrorBoundary } from '../../../error/ErrorBanner'\nimport IconSvg from '../../../IconSvg/IconSvg'\nimport DataAccessRequestAccessorsEditor, {\n DataAccessRequestAccessorsEditorProps,\n} from '../DataAccessRequestAccessorsEditor'\nimport DocumentTemplate from '../DocumentTemplate'\nimport ManagedACTAccessRequirementFormWikiWrapper from '../ManagedACTAccessRequirementFormWikiWrapper'\nimport { UploadDocumentField } from '../UploadDocumentField'\n\nfunction AccessorRequirementHelpText(props: {\n managedACTAccessRequirement: ManagedACTAccessRequirement\n}) {\n const { managedACTAccessRequirement } = props\n let link: string = ''\n let msg: string = ''\n\n if (\n managedACTAccessRequirement.isCertifiedUserRequired &&\n managedACTAccessRequirement.isValidatedProfileRequired\n ) {\n link = 'https://help.synapse.org/docs/User-Types.2007072795.html'\n msg =\n 'All data requesters must be certified users and have a validated user profile.'\n } else if (managedACTAccessRequirement.isCertifiedUserRequired) {\n link =\n 'https://help.synapse.org/docs/User-Types.2007072795.html#UserAccountTiers-CertifiedUsers'\n msg = 'All data requesters must be a certified user.'\n } else if (managedACTAccessRequirement.isValidatedProfileRequired) {\n link =\n 'https://help.synapse.org/docs/User-Types.2007072795.html#UserAccountTiers-ValidatedUsers'\n msg = 'All data requesters must have a validated user profile.'\n }\n return (\n <>\n {managedACTAccessRequirement.isDUCRequired ? (\n <Box sx={{ display: 'flex', gap: 2, alignItems: 'center', py: 1 }}>\n <NewReleasesOutlined sx={{ color: 'error.main' }} />\n <div>\n You must list the Synapse user names of all collaborators listed in\n your Data Use Certificate (DUC).\n </div>\n </Box>\n ) : (\n ''\n )}\n {msg}{' '}\n {link && (\n <Link href={link} target={'_blank'} rel={'noreferrer'}>\n Learn more\n </Link>\n )}\n </>\n )\n}\n\nexport type DataAccessRequestAccessorsFilesFormProps = {\n /**\n * The ID of the object of interest. This corresponds to the subjectId of the {@link CreateSubmissionRequest}\n */\n subjectId: string\n /* The type of the subject */\n subjectType: RestrictableObjectType\n /* The access requirement to which the user is requesting access */\n managedACTAccessRequirement: ManagedACTAccessRequirement\n onSubmissionCreated: (submissionId: string) => void\n researchProjectId: string\n onHide: () => void\n /* Callback invoked when the user clicks cancel. The unsaved, modified dataAccessRequest is returned so the calling component may prompt the user to save this data */\n onCancel: (modifiedDataAccessRequest: Request | Renewal) => void\n /** Callback invoked when the 'Back' action button is clicked */\n onBackClicked: () => void\n}\n\nexport type AlertProps = {\n key: MuiAlertProps['severity']\n message: string | ReactNode\n}\n\n/**\n * Step 2 of the Data Access Request/Renewal flow prompts the user to\n * - Manage the list of accessors, i.e. Synapse users who will gain, renew, or lose access\n * - Download and upload documents required by the Access Requirement\n * - If a renewal, provide publications and a summary of use statement.\n *\n * The component expects a researchProjectId, which should reference complete researchProject created in Step 1.\n * The user may click a \"Submit\" button, which will save the request and issue a data access submission that references\n * the requestId created/updated in this component.\n */\nexport default function DataAccessRequestAccessorsFilesForm(\n props: DataAccessRequestAccessorsFilesFormProps,\n) {\n const {\n onSubmissionCreated,\n managedACTAccessRequirement,\n subjectId,\n subjectType,\n researchProjectId,\n onCancel,\n onBackClicked,\n } = props\n const { isAuthenticated } = useSynapseContext()\n const { data: user } = useGetCurrentUserProfile({ enabled: isAuthenticated })\n const [alert, setAlert] = useState<AlertProps | undefined>()\n const [accessorChanges, setAccessorChanges] = useState<\n AccessorChange[] | undefined\n >()\n const [summaryOfUse, setSummaryOfUse] = useState<string | undefined>()\n const [publication, setPublication] = useState<string | undefined>()\n\n const { data: dataAccessRequest, isLoading: isLoadingGetDataAccessRequest } =\n useGetDataAccessRequestForUpdate(String(managedACTAccessRequirement.id), {\n enabled: isAuthenticated,\n // Infinite staleTime ensures this won't get re-fetched unless explicitly invalidated by the mutation\n staleTime: Infinity,\n // This call should never fail, so if we run into an error, throwing to an error boundary is acceptable\n throwOnError: true,\n })\n\n const isRenewal =\n dataAccessRequest?.concreteType ===\n 'org.sagebionetworks.repo.model.dataaccess.Renewal'\n\n function onError(e: SynapseClientError) {\n console.log('RequestDataAccessStep2: Error updating form', e)\n setAlert({\n key: 'error',\n message: getErrorMessage(e.reason),\n })\n }\n\n const { mutate: submit, isPending: submitDataAccessRequestIsPending } =\n useSubmitDataAccessRequest({\n onSuccess: submission => {\n onSubmissionCreated(submission.submissionId)\n },\n onError: onError,\n })\n\n const {\n mutateAsync: updateRequestAsync,\n isPending: updateDataAccessRequestIsPending,\n } = useUpdateDataAccessRequest({\n onError: onError,\n })\n\n const isLoading =\n isLoadingGetDataAccessRequest ||\n updateDataAccessRequestIsPending ||\n submitDataAccessRequestIsPending\n\n /**\n * This effect comprises a collection of updates we should immediately apply to a data access request.\n */\n useEffect(() => {\n if (dataAccessRequest && user) {\n let shouldUpdate = false\n\n // Attach the researchProjectId to the request\n if (!dataAccessRequest.researchProjectId) {\n dataAccessRequest.researchProjectId = researchProjectId\n shouldUpdate = true\n }\n\n // Add the current user with GAIN_ACCESS to the list of accessors\n const currentUserWithGainAccess: AccessorChange = {\n userId: user.ownerId,\n type: isRenewal ? AccessType.RENEW_ACCESS : AccessType.GAIN_ACCESS,\n }\n if (\n !dataAccessRequest.accessorChanges ||\n !dataAccessRequest.accessorChanges.find(item =>\n deepEquals(item, currentUserWithGainAccess),\n )\n ) {\n dataAccessRequest.accessorChanges = [\n currentUserWithGainAccess,\n ...(dataAccessRequest.accessorChanges || []),\n ]\n shouldUpdate = true\n }\n\n // SWC-5765: Filter out duplicate accessors\n const seen = new Set()\n const uniqueAccessorChanges = dataAccessRequest.accessorChanges.filter(\n accessorChange => {\n return seen.has(accessorChange.userId)\n ? false\n : seen.add(accessorChange.userId)\n },\n )\n if (\n uniqueAccessorChanges.length !==\n dataAccessRequest.accessorChanges.length\n ) {\n dataAccessRequest.accessorChanges = uniqueAccessorChanges\n shouldUpdate = true\n }\n\n if (shouldUpdate) {\n updateRequestAsync(dataAccessRequest)\n }\n }\n }, [\n dataAccessRequest,\n isRenewal,\n researchProjectId,\n updateRequestAsync,\n user,\n ])\n\n /**\n * Fields other than uploaded files are NOT immediately synced with the server. Set local state if these values exist in the\n * fetched object, and no value exists in local state.\n */\n useEffect(() => {\n if (dataAccessRequest) {\n if (dataAccessRequest.accessorChanges && accessorChanges == undefined) {\n setAccessorChanges(dataAccessRequest.accessorChanges)\n }\n if (\n isRenewal &&\n dataAccessRequest.publication &&\n publication == undefined\n ) {\n setPublication(dataAccessRequest.publication)\n }\n if (\n isRenewal &&\n dataAccessRequest.summaryOfUse &&\n summaryOfUse == undefined\n ) {\n setSummaryOfUse(dataAccessRequest.summaryOfUse)\n }\n }\n // Intentionally only re-synchronize state when server state changes\n // oxlint-disable-next-line react-hooks/exhaustive-deps\n }, [dataAccessRequest])\n\n function getDataAccessRequestWithLocalState(): Request | Renewal {\n return {\n ...dataAccessRequest,\n // append local state to the request\n accessorChanges: accessorChanges,\n publication,\n summaryOfUse,\n } as Request | Renewal\n }\n\n async function handleSubmit() {\n if (dataAccessRequest) {\n // Save the request\n const requestObject = await updateRequestAsync(\n getDataAccessRequestWithLocalState(),\n )\n // Create a submission and attach the request\n submit({\n request: {\n requestId: requestObject.id,\n requestEtag: requestObject.etag,\n subjectId: subjectId,\n subjectType: subjectType,\n },\n accessRequirementId: String(managedACTAccessRequirement.id),\n })\n }\n }\n\n const getErrorMessage = (reason: string = '') => {\n return (\n <>\n <strong>Sorry, there is an error in submitting your request.</strong>\n <br />\n {reason}\n </>\n )\n }\n\n const onAccessorChange: DataAccessRequestAccessorsEditorProps['onChange'] =\n updater => {\n // Copy the array so the caller doesn't have to worry about immutability\n setAccessorChanges([...updater(accessorChanges || [])])\n }\n\n const onClearAttachment = (fid: string) => {\n updateRequestAsync({\n ...dataAccessRequest!,\n attachments: dataAccessRequest!.attachments?.filter(item => item !== fid),\n })\n }\n\n const uploadCallback = (\n data: UploadCallbackResp,\n context: keyof Pick<\n Request,\n 'attachments' | 'irbFileHandleId' | 'ducFileHandleId'\n >,\n ) => {\n if (data.resp && data.success) {\n // Files are uploaded and synced with the server immediately\n const uploadResponse: FileUploadComplete = data.resp\n if (context === 'attachments') {\n updateRequestAsync({\n ...dataAccessRequest!,\n attachments: [\n ...(dataAccessRequest!.attachments || []),\n uploadResponse.fileHandleId,\n ],\n })\n } else {\n updateRequestAsync({\n ...dataAccessRequest!,\n [context]: uploadResponse.fileHandleId,\n })\n }\n } else if (!data.success && data.error) {\n // show the error\n console.log(\n 'RequestDataAccessStep2: Error uploading the file',\n data.error,\n )\n setAlert({\n key: 'error',\n message: getErrorMessage(data.error.reason),\n })\n }\n }\n\n const ducFileHandleAssociation: FileHandleAssociation[] =\n dataAccessRequest?.ducFileHandleId\n ? [\n {\n fileHandleId: dataAccessRequest?.ducFileHandleId,\n associateObjectType:\n FileHandleAssociateType.DataAccessRequestAttachment,\n associateObjectId: String(dataAccessRequest.id),\n },\n ]\n : []\n const irbFileHandleAssociation: FileHandleAssociation[] =\n dataAccessRequest?.irbFileHandleId\n ? [\n {\n fileHandleId: dataAccessRequest.irbFileHandleId,\n associateObjectType:\n FileHandleAssociateType.DataAccessRequestAttachment,\n associateObjectId: String(dataAccessRequest.id),\n },\n ]\n : []\n\n const attachmentFileHandleAssociations: FileHandleAssociation[] =\n (dataAccessRequest?.attachments || []).map(attachmentFileHandleId => ({\n fileHandleId: attachmentFileHandleId,\n associateObjectType: FileHandleAssociateType.DataAccessRequestAttachment,\n associateObjectId: String(dataAccessRequest!.id),\n })) ?? []\n\n return (\n <>\n <DialogTitle>\n <Stack\n direction=\"row\"\n sx={{\n alignItems: 'center',\n gap: '5px',\n }}\n >\n Request Access\n <Box sx={{ flexGrow: 1 }} />\n <IconButton onClick={props.onHide}>\n <IconSvg icon={'close'} wrap={false} sx={{ color: 'grey.700' }} />\n </IconButton>\n </Stack>\n </DialogTitle>\n <DialogContent>\n <ManagedACTAccessRequirementFormWikiWrapper\n managedACTAccessRequirementId={String(managedACTAccessRequirement.id)}\n >\n <Box\n component={'form'}\n sx={{\n // Must set a minHeight to ensure the user picker in the DataAccessRequestAccessorsEditor doesn't get cut off\n minHeight: '475px',\n }}\n onSubmit={e => e.preventDefault()}\n >\n <Typography variant={'body1'} sx={{ mb: 2 }}>\n Please provide the information below to submit the request for\n access.\n </Typography>\n\n {dataAccessRequest && user && (\n <DataAccessRequestAccessorsEditor\n accessorChanges={accessorChanges || []}\n onChange={onAccessorChange}\n isRenewal={isRenewal}\n helpText={\n <AccessorRequirementHelpText\n managedACTAccessRequirement={managedACTAccessRequirement}\n />\n }\n />\n )}\n\n {(managedACTAccessRequirement?.isDUCRequired ||\n managedACTAccessRequirement?.isIRBApprovalRequired ||\n managedACTAccessRequirement?.areOtherAttachmentsRequired) && (\n <Divider sx={{ my: 4 }} />\n )}\n {/* DUC */}\n {managedACTAccessRequirement?.isDUCRequired && (\n <>\n {managedACTAccessRequirement?.ducTemplateFileHandleId && (\n <DocumentTemplate\n title={'Download DUC Template'}\n description={\n 'As a first step, you will need to download the most current version of the Data Use Certificate.'\n }\n fileHandleAssociation={{\n fileHandleId:\n managedACTAccessRequirement.ducTemplateFileHandleId,\n associateObjectType:\n FileHandleAssociateType.AccessRequirementAttachment,\n associateObjectId: String(managedACTAccessRequirement.id),\n }}\n downloadButtonText={'Download DUC Template'}\n />\n )}\n <Typography variant={'headline3'} sx={{ mt: 4, mb: 2 }}>\n Fill out and upload a Data Use Certificate\n </Typography>\n <Typography variant={'body1'} sx={{ my: 2 }}>\n You must download and fill out a Data Use Certificate (DUC).\n Be sure to upload the completed DUC below once you've\n completed it.\n </Typography>\n <Typography variant={'body1'} component={'ol'}>\n <li>Download the DUC template file.</li>\n <li>\n Fill out the DUC template, following the instructions in the\n file.\n </li>\n <li>\n Upload the completed certificate using the button below:\n </li>\n </Typography>\n <SynapseErrorBoundary>\n <UploadDocumentField\n id={'duc'}\n isLoading={isLoading}\n uploadCallback={resp =>\n uploadCallback(resp, 'ducFileHandleId')\n }\n documentName={'Data Use Certificate'}\n fileHandleAssociations={ducFileHandleAssociation}\n />\n </SynapseErrorBoundary>\n {(managedACTAccessRequirement?.isIRBApprovalRequired ||\n managedACTAccessRequirement?.areOtherAttachmentsRequired) && (\n <Divider sx={{ my: 4 }} />\n )}\n </>\n )}\n\n {/* IRB */}\n {managedACTAccessRequirement?.isIRBApprovalRequired && (\n <>\n <Typography variant={'headline3'} sx={{ my: 2 }}>\n IRB Approval\n </Typography>\n <Typography variant={'body1'} sx={{ my: 2 }}>\n Upload a signed IRB letter on institutional letterhead. The\n letter must include the names of all the datasets requested,\n as well as the names of the data requesters above. Use the\n button below to upload the document.\n </Typography>\n <SynapseErrorBoundary>\n <UploadDocumentField\n id={'irb'}\n isLoading={isLoading}\n documentName={'IRB Approval Letter'}\n uploadCallback={resp =>\n uploadCallback(resp, 'irbFileHandleId')\n }\n fileHandleAssociations={irbFileHandleAssociation}\n />\n </SynapseErrorBoundary>\n {managedACTAccessRequirement?.areOtherAttachmentsRequired && (\n <Divider sx={{ my: 4 }} />\n )}\n </>\n )}\n\n {\n /* Attachments */\n managedACTAccessRequirement?.areOtherAttachmentsRequired && (\n <>\n <Typography variant={'headline3'} sx={{ my: 2 }}>\n Upload other required documents\n </Typography>\n <Typography variant={'body1'} sx={{ my: 2 }}>\n You must upload other required documents. Please review the\n instructions to gain data access to determine which\n documents must also be uploaded.\n </Typography>\n <SynapseErrorBoundary>\n <UploadDocumentField\n id={'file-attachment'}\n isLoading={isLoading}\n documentName={'Attachment'}\n uploadCallback={res => uploadCallback(res, 'attachments')}\n isMultiFileUpload={true}\n fileHandleAssociations={attachmentFileHandleAssociations}\n onClearAttachment={onClearAttachment}\n />\n </SynapseErrorBoundary>\n </>\n )\n }\n\n {\n // SWC-7319 - Per GovernanceInnovation, do not show these fields on renewal\n // Publications & Summary of Use\n // isRenewal && (\n // <>\n // <TextField\n // id={'publications'}\n // label={'Publication(s)'}\n // disabled={submitDataAccessRequestIsPending}\n // multiline\n // rows={3}\n // value={publication}\n // onChange={(e: ChangeEvent<HTMLTextAreaElement>) =>\n // setPublication(e.target.value)\n // }\n // />\n // <TextField\n // id={'summaryOfUse'}\n // label={'Summary of use'}\n // value={summaryOfUse}\n // disabled={submitDataAccessRequestIsPending}\n // multiline\n // rows={3}\n // onChange={(e: ChangeEvent<HTMLTextAreaElement>) =>\n // setSummaryOfUse(e.target.value)\n // }\n // />\n // </>\n // )\n }\n </Box>\n </ManagedACTAccessRequirementFormWikiWrapper>\n {alert && <Alert severity={alert.key}>{alert.message}</Alert>}\n </DialogContent>\n <DialogActions>\n <Button\n variant={'outlined'}\n onClick={() => {\n onBackClicked()\n }}\n >\n Back\n </Button>\n <Box sx={{ flexGrow: 1 }}>{/* spacer */}</Box>\n\n <Button\n variant=\"outlined\"\n disabled={submitDataAccessRequestIsPending}\n onClick={() => {\n if (dataAccessRequest) {\n // include the local state in the onCancel callback so the user may save their changes\n onCancel(getDataAccessRequestWithLocalState())\n }\n }}\n >\n Cancel\n </Button>\n <Button\n variant=\"contained\"\n disabled={submitDataAccessRequestIsPending}\n onClick={() => {\n handleSubmit()\n }}\n >\n Submit\n </Button>\n </DialogActions>\n </>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useUpdateAcl.js","names":[],"sources":["../../../src/components/AclEditor/useUpdateAcl.ts"],"sourcesContent":["import { useGlobalIsEditingContext } from '@/utils/context/GlobalIsEditingContext'\nimport { ACCESS_TYPE, ResourceAccess } from '@sage-bionetworks/synapse-types'\nimport {\n Dispatch,\n SetStateAction,\n useCallback,\n useEffect,\n useState,\n} from 'react'\nimport { noop } from 'lodash-es'\nimport useSortResourceAccessList from './useSortResourceAccessList'\n\nexport const PRINCIPAL_ALREADY_ADDED_ERROR_MESSAGE =\n 'User or team already has permissions.'\n\nexport type UseUpdateAclOptions = {\n initialResourceAccessList?: ResourceAccess[]\n onChange?: (resourceAccessList: ResourceAccess[]) => void\n onError?: (e: string) => void\n}\n\ntype UseUpdateAclReturn = {\n /** The ResourceAccess list that is being updated. It will automatically be sorted unless the `add`, `update` or `remove` functions are called. */\n resourceAccessList: ResourceAccess[]\n /** Set the ResourceAccess list. Does not prevent re-sorting */\n setResourceAccessList: Dispatch<SetStateAction<ResourceAccess[]>>\n /** Adds a principal to the list with the provided accessTypes */\n addResourceAccessItem: (\n principalId: number,\n accessTypes: ACCESS_TYPE[],\n ) => void\n /** Updates the principal in the list with the provided accessTypes */\n updateResourceAccessItem: (\n principalId: number,\n accessType: ACCESS_TYPE[],\n ) => void\n /** Removes the principal from the list */\n removeResourceAccessItem: (principalId: number) => void\n /** Resets the dirty state of the form, which will immediately trigger sorting the resourceAccessList */\n resetDirtyState: () => void\n}\n\nconst EMPTY_ARRAY: ResourceAccess[] = []\n\nexport default function useUpdateAcl(\n options: UseUpdateAclOptions = {},\n): UseUpdateAclReturn {\n const {\n initialResourceAccessList = EMPTY_ARRAY,\n onChange = noop,\n onError = noop,\n } = options\n const [isDirty, setIsDirty] = useState(false)\n const { setIsEditing } = useGlobalIsEditingContext()\n\n // When the form is dirty, set the global editing state to true\n useEffect(() => {\n setIsEditing(isDirty)\n return () => {\n setIsEditing(false)\n }\n }, [isDirty, setIsEditing])\n\n const [resourceAccessList, setResourceAccessList] = useState<\n ResourceAccess[]\n >(initialResourceAccessList)\n const [hasSorted, setHasSorted] = useState(false)\n\n // While the form has not been edited, sort the resourceAccessList\n const { sortedResourceAccessList, isLoading: isLoadingSortedList } =\n useSortResourceAccessList(resourceAccessList)\n useEffect(() => {\n if (\n !isDirty &&\n !isLoadingSortedList &&\n !hasSorted &&\n sortedResourceAccessList != null\n ) {\n setResourceAccessList(sortedResourceAccessList)\n // `useSortResourceAccessList` will return a new array every time `resourceAccessList` changes, so we need to\n // track if we've already sorted to prevent an infinite loop\n setHasSorted(true)\n }\n }, [hasSorted, isDirty, isLoadingSortedList, sortedResourceAccessList])\n\n useEffect(() => {\n onChange(resourceAccessList)\n //
|
|
1
|
+
{"version":3,"file":"useUpdateAcl.js","names":[],"sources":["../../../src/components/AclEditor/useUpdateAcl.ts"],"sourcesContent":["import { useGlobalIsEditingContext } from '@/utils/context/GlobalIsEditingContext'\nimport { ACCESS_TYPE, ResourceAccess } from '@sage-bionetworks/synapse-types'\nimport {\n Dispatch,\n SetStateAction,\n useCallback,\n useEffect,\n useState,\n} from 'react'\nimport { noop } from 'lodash-es'\nimport useSortResourceAccessList from './useSortResourceAccessList'\n\nexport const PRINCIPAL_ALREADY_ADDED_ERROR_MESSAGE =\n 'User or team already has permissions.'\n\nexport type UseUpdateAclOptions = {\n initialResourceAccessList?: ResourceAccess[]\n onChange?: (resourceAccessList: ResourceAccess[]) => void\n onError?: (e: string) => void\n}\n\ntype UseUpdateAclReturn = {\n /** The ResourceAccess list that is being updated. It will automatically be sorted unless the `add`, `update` or `remove` functions are called. */\n resourceAccessList: ResourceAccess[]\n /** Set the ResourceAccess list. Does not prevent re-sorting */\n setResourceAccessList: Dispatch<SetStateAction<ResourceAccess[]>>\n /** Adds a principal to the list with the provided accessTypes */\n addResourceAccessItem: (\n principalId: number,\n accessTypes: ACCESS_TYPE[],\n ) => void\n /** Updates the principal in the list with the provided accessTypes */\n updateResourceAccessItem: (\n principalId: number,\n accessType: ACCESS_TYPE[],\n ) => void\n /** Removes the principal from the list */\n removeResourceAccessItem: (principalId: number) => void\n /** Resets the dirty state of the form, which will immediately trigger sorting the resourceAccessList */\n resetDirtyState: () => void\n}\n\nconst EMPTY_ARRAY: ResourceAccess[] = []\n\nexport default function useUpdateAcl(\n options: UseUpdateAclOptions = {},\n): UseUpdateAclReturn {\n const {\n initialResourceAccessList = EMPTY_ARRAY,\n onChange = noop,\n onError = noop,\n } = options\n const [isDirty, setIsDirty] = useState(false)\n const { setIsEditing } = useGlobalIsEditingContext()\n\n // When the form is dirty, set the global editing state to true\n useEffect(() => {\n setIsEditing(isDirty)\n return () => {\n setIsEditing(false)\n }\n }, [isDirty, setIsEditing])\n\n const [resourceAccessList, setResourceAccessList] = useState<\n ResourceAccess[]\n >(initialResourceAccessList)\n const [hasSorted, setHasSorted] = useState(false)\n\n // While the form has not been edited, sort the resourceAccessList\n const { sortedResourceAccessList, isLoading: isLoadingSortedList } =\n useSortResourceAccessList(resourceAccessList)\n useEffect(() => {\n if (\n !isDirty &&\n !isLoadingSortedList &&\n !hasSorted &&\n sortedResourceAccessList != null\n ) {\n setResourceAccessList(sortedResourceAccessList)\n // `useSortResourceAccessList` will return a new array every time `resourceAccessList` changes, so we need to\n // track if we've already sorted to prevent an infinite loop\n setHasSorted(true)\n }\n }, [hasSorted, isDirty, isLoadingSortedList, sortedResourceAccessList])\n\n useEffect(() => {\n onChange(resourceAccessList)\n // oxlint-disable-next-line react-hooks/exhaustive-deps\n }, [resourceAccessList])\n\n const addResourceAccessItem = useCallback(\n (principalId: number, accessTypes: ACCESS_TYPE[]) => {\n setIsDirty(true)\n if (principalId) {\n setResourceAccessList(resourceAccessList => {\n const alreadyReviewer = resourceAccessList.some(\n resourceAccess => resourceAccess.principalId === principalId,\n )\n if (alreadyReviewer) {\n onError(PRINCIPAL_ALREADY_ADDED_ERROR_MESSAGE)\n } else {\n const newResourceAccess: ResourceAccess = {\n principalId: principalId,\n accessType: accessTypes,\n }\n return [...resourceAccessList, newResourceAccess]\n }\n return resourceAccessList\n })\n }\n },\n [onError],\n )\n\n const updateResourceAccessItem = useCallback(\n (principalId: number, accessType: ACCESS_TYPE[]) => {\n setIsDirty(true)\n setResourceAccessList(resourceAccessList =>\n resourceAccessList.map(resourceAccess => {\n return resourceAccess.principalId === principalId\n ? { ...resourceAccess, accessType }\n : resourceAccess\n }),\n )\n },\n [],\n )\n\n const removeResourceAccessItem = useCallback((principalId: number) => {\n setIsDirty(true)\n setResourceAccessList(resourceAccessList =>\n resourceAccessList.filter(\n raListItem => raListItem.principalId !== principalId,\n ),\n )\n }, [])\n\n const resetDirtyState = useCallback(() => {\n setIsDirty(false)\n }, [])\n\n return {\n resourceAccessList,\n setResourceAccessList,\n addResourceAccessItem,\n updateResourceAccessItem,\n removeResourceAccessItem,\n resetDirtyState,\n }\n}\n"],"mappings":";;;;;AAYA,IAAa,IACX,yCA6BI,IAAgC,CAAC;AAEvC,SAAwB,EACtB,IAA+B,CAAC,GACZ;CACpB,IAAM,EACJ,+BAA4B,GAC5B,cAAW,GACX,aAAU,MACR,GACE,CAAC,GAAS,KAAc,EAAS,EAAK,GACtC,EAAE,oBAAiB,EAA0B;CAGnD,SACE,EAAa,CAAO,SACP;EACX,EAAa,EAAK;CACpB,IACC,CAAC,GAAS,CAAY,CAAC;CAE1B,IAAM,CAAC,GAAoB,KAAyB,EAElD,CAAyB,GACrB,CAAC,GAAW,KAAgB,EAAS,EAAK,GAG1C,EAAE,6BAA0B,WAAW,MAC3C,EAA0B,CAAkB;CAuE9C,OAtEA,QAAgB;EACd,AACE,CAAC,KACD,CAAC,KACD,CAAC,KACD,KAA4B,SAE5B,EAAsB,CAAwB,GAG9C,EAAa,EAAI;CAErB,GAAG;EAAC;EAAW;EAAS;EAAqB;CAAwB,CAAC,GAEtE,QAAgB;EACd,EAAS,CAAkB;CAE7B,GAAG,CAAC,CAAkB,CAAC,GAqDhB;EACL;EACA;EACA,uBAtD4B,GAC3B,GAAqB,MAA+B;GAEnD,AADA,EAAW,EAAI,GACX,KACF,GAAsB,MAAsB;IAI1C,IAHwB,EAAmB,MACzC,MAAkB,EAAe,gBAAgB,CAE/C,GACF,EAAQ,CAAqC;SACxC;KACL,IAAM,IAAoC;MAC3B;MACb,YAAY;KACd;KACA,OAAO,CAAC,GAAG,GAAoB,CAAiB;IAClD;IACA,OAAO;GACT,CAAC;EAEL,GACA,CAAC,CAAO,CAiCR;EACA,0BA/B+B,GAC9B,GAAqB,MAA8B;GAElD,AADA,EAAW,EAAI,GACf,GAAsB,MACpB,EAAmB,KAAI,MACd,EAAe,gBAAgB,IAClC;IAAE,GAAG;IAAgB;GAAW,IAChC,CACL,CACH;EACF,GACA,CAAC,CAoBD;EACA,0BAlB+B,GAAa,MAAwB;GAEpE,AADA,EAAW,EAAI,GACf,GAAsB,MACpB,EAAmB,QACjB,MAAc,EAAW,gBAAgB,CAC3C,CACF;EACF,GAAG,CAAC,CAWF;EACA,iBAVsB,QAAkB;GACxC,EAAW,EAAK;EAClB,GAAG,CAAC,CAQF;CACF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TwoFactorBackupCodes.js","names":[],"sources":["../../../src/components/Authentication/TwoFactorBackupCodes.tsx"],"sourcesContent":["import {\n LeftRightPanel,\n StyledOuterContainer,\n} from '@/components/styled/LeftRightPanel'\nimport { createRecoveryCodes } from '@/synapse-client/SynapseClient'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport { useMediaPrintOnly } from '@/utils/hooks/useMediaPrintOnly'\nimport {\n Alert,\n Box,\n Button,\n IconButton,\n Typography,\n useTheme,\n} from '@mui/material'\nimport { SynapseClientError } from '@sage-bionetworks/synapse-client/util/SynapseClientError'\nimport { TwoFactorAuthRecoveryCodes } from '@sage-bionetworks/synapse-types'\nimport { useMutation } from '@tanstack/react-query'\nimport { useCallback, useEffect, useState } from 'react'\nimport IconSvg from '../IconSvg/IconSvg'\nimport { displayToast } from '../ToastMessage/ToastMessage'\nimport { RecoveryCodeGrid } from './RecoveryCodeGrid'\nimport { RegenerateBackupCodesWarning } from './RegenerateBackupCodesWarning'\nimport { copyStringToClipboard } from '@/utils/functions/StringUtils'\n\nexport type TwoFactorBackupCodesProps = {\n /* Whether to show a warning before generating new codes, to prevent users from overwriting their existing codes */\n showReplaceOldCodesWarning?: boolean\n /* Invoked when the user decides not to generate new codes, or has acknowledged new codes. */\n onClose: () => void\n}\n\nexport default function TwoFactorBackupCodes(props: TwoFactorBackupCodesProps) {\n const { showReplaceOldCodesWarning, onClose } = props\n const theme = useTheme()\n const [hasConfirmedRegeneration, setHasConfirmedRegeneration] = useState(\n !showReplaceOldCodesWarning,\n )\n\n const { accessToken } = useSynapseContext()\n\n const {\n mutate: generateCodes,\n data: recoveryCodes,\n error,\n } = useMutation<TwoFactorAuthRecoveryCodes, SynapseClientError>({\n mutationFn: () => createRecoveryCodes(accessToken),\n onMutate: () => {\n setHasConfirmedRegeneration(true)\n },\n })\n\n // Generate codes on mount if no warning is shown\n useEffect(() => {\n if (!showReplaceOldCodesWarning) {\n generateCodes()\n }\n // Run on mount only\n //
|
|
1
|
+
{"version":3,"file":"TwoFactorBackupCodes.js","names":[],"sources":["../../../src/components/Authentication/TwoFactorBackupCodes.tsx"],"sourcesContent":["import {\n LeftRightPanel,\n StyledOuterContainer,\n} from '@/components/styled/LeftRightPanel'\nimport { createRecoveryCodes } from '@/synapse-client/SynapseClient'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport { useMediaPrintOnly } from '@/utils/hooks/useMediaPrintOnly'\nimport {\n Alert,\n Box,\n Button,\n IconButton,\n Typography,\n useTheme,\n} from '@mui/material'\nimport { SynapseClientError } from '@sage-bionetworks/synapse-client/util/SynapseClientError'\nimport { TwoFactorAuthRecoveryCodes } from '@sage-bionetworks/synapse-types'\nimport { useMutation } from '@tanstack/react-query'\nimport { useCallback, useEffect, useState } from 'react'\nimport IconSvg from '../IconSvg/IconSvg'\nimport { displayToast } from '../ToastMessage/ToastMessage'\nimport { RecoveryCodeGrid } from './RecoveryCodeGrid'\nimport { RegenerateBackupCodesWarning } from './RegenerateBackupCodesWarning'\nimport { copyStringToClipboard } from '@/utils/functions/StringUtils'\n\nexport type TwoFactorBackupCodesProps = {\n /* Whether to show a warning before generating new codes, to prevent users from overwriting their existing codes */\n showReplaceOldCodesWarning?: boolean\n /* Invoked when the user decides not to generate new codes, or has acknowledged new codes. */\n onClose: () => void\n}\n\nexport default function TwoFactorBackupCodes(props: TwoFactorBackupCodesProps) {\n const { showReplaceOldCodesWarning, onClose } = props\n const theme = useTheme()\n const [hasConfirmedRegeneration, setHasConfirmedRegeneration] = useState(\n !showReplaceOldCodesWarning,\n )\n\n const { accessToken } = useSynapseContext()\n\n const {\n mutate: generateCodes,\n data: recoveryCodes,\n error,\n } = useMutation<TwoFactorAuthRecoveryCodes, SynapseClientError>({\n mutationFn: () => createRecoveryCodes(accessToken),\n onMutate: () => {\n setHasConfirmedRegeneration(true)\n },\n })\n\n // Generate codes on mount if no warning is shown\n useEffect(() => {\n if (!showReplaceOldCodesWarning) {\n generateCodes()\n }\n // Run on mount only\n // oxlint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n const { visibleOnPrintClassName, hiddenOnPrintClassName } =\n useMediaPrintOnly()\n\n const copyCodesToClipboard = useCallback(() => {\n const codes = (recoveryCodes?.codes || []).join('\\n')\n copyStringToClipboard(codes).then(() => {\n displayToast('Recovery codes copied to clipboard', 'success')\n })\n }, [recoveryCodes])\n\n if (showReplaceOldCodesWarning && !hasConfirmedRegeneration) {\n return (\n <StyledOuterContainer sx={{ display: 'flex', flexDirection: 'column' }}>\n <RegenerateBackupCodesWarning\n onConfirm={generateCodes}\n onCancel={onClose}\n />\n </StyledOuterContainer>\n )\n }\n\n return (\n <LeftRightPanel\n className={visibleOnPrintClassName}\n leftContent={\n <Box\n sx={{\n py: 10,\n px: 8,\n height: '100%',\n position: 'relative',\n }}\n >\n <IconButton\n type=\"button\"\n onClick={onClose}\n className={hiddenOnPrintClassName}\n sx={{\n position: 'absolute',\n top: theme.spacing(2),\n left: theme.spacing(2),\n }}\n >\n <IconSvg\n icon=\"arrowBack\"\n wrap={false}\n sx={{ height: '24px', width: '24px' }}\n />\n </IconButton>\n <Typography variant=\"headline1\" sx={{ mt: 7 }}>\n Backup codes\n </Typography>\n {showReplaceOldCodesWarning && (\n <Alert\n severity=\"warning\"\n className={hiddenOnPrintClassName}\n sx={{\n my: 2,\n }}\n icon={false}\n >\n <strong>These new codes have replaced your old codes.</strong>{' '}\n Please save these codes and use them from now on.\n </Alert>\n )}\n <RecoveryCodeGrid recoveryCodes={recoveryCodes} />\n {error && (\n <Alert severity={'error'} sx={{ my: 2 }} icon={false}>\n {error.message}\n </Alert>\n )}\n <Box\n className={hiddenOnPrintClassName}\n sx={{\n display: 'grid',\n gridTemplateColumns: '1fr 1fr',\n gap: '10px',\n mb: '10px',\n }}\n >\n <Button\n variant={'outlined'}\n onClick={copyCodesToClipboard}\n disabled={!recoveryCodes}\n >\n Copy Codes\n </Button>\n <Button\n variant={'outlined'}\n disabled={!recoveryCodes}\n onClick={window.print}\n >\n Print Codes\n </Button>\n </Box>\n <Button\n variant={'contained'}\n className={hiddenOnPrintClassName}\n fullWidth\n disabled={!recoveryCodes}\n onClick={onClose}\n >\n Done\n </Button>\n </Box>\n }\n rightContent={\n <Box\n sx={{\n py: 10,\n height: '100%',\n background: `url(https://s3.amazonaws.com/static.synapse.org/images/twofactor-graphic.svg) no-repeat right bottom`,\n backgroundSize: '100%',\n }}\n >\n <Box\n sx={{\n mt: 7,\n px: 9,\n }}\n >\n <Typography variant=\"headline1\" sx={{ mb: 2.5 }}>\n Save these codes\n </Typography>\n <Typography variant=\"body1\" sx={{ my: 2 }}>\n You can use these 10 backup codes to access your account if you\n ever lose access to your authentication device.\n </Typography>\n <Typography variant=\"body1\" sx={{ my: 2 }}>\n Each code can only be used once.\n </Typography>\n </Box>\n </Box>\n }\n />\n )\n}\n"],"mappings":";;;;;;;;;;;;;;AAgCA,SAAwB,EAAqB,GAAkC;CAC7E,IAAM,EAAE,+BAA4B,eAAY,GAC1C,IAAQ,EAAS,GACjB,CAAC,GAA0B,KAA+B,EAC9D,CAAC,CACH,GAEM,EAAE,mBAAgB,EAAkB,GAEpC,EACJ,QAAQ,GACR,MAAM,GACN,aACE,EAA4D;EAC9D,kBAAkB,EAAoB,CAAW;EACjD,gBAAgB;GACd,EAA4B,EAAI;EAClC;CACF,CAAC;CAGD,QAAgB;EACd,AAAK,KACH,EAAc;CAIlB,GAAG,CAAC,CAAC;CAEL,IAAM,EAAE,4BAAyB,8BAC/B,EAAkB,GAEd,IAAuB,QAAkB;EAE7C,GADe,GAAe,SAAS,CAAC,GAAG,KAAK,IAC1B,CAAK,EAAE,WAAW;GACtC,EAAa,sCAAsC,SAAS;EAC9D,CAAC;CACH,GAAG,CAAC,CAAa,CAAC;CAalB,OAXI,KAA8B,CAAC,IAE/B,kBAAC,GAAD;EAAsB,IAAI;GAAE,SAAS;GAAQ,eAAe;EAAS;YACnE,kBAAC,GAAD;GACE,WAAW;GACX,UAAU;EACX,CAAA;CACmB,CAAA,IAKxB,kBAAC,GAAD;EACE,WAAW;EACX,aACE,kBAAC,GAAD;GACE,IAAI;IACF,IAAI;IACJ,IAAI;IACJ,QAAQ;IACR,UAAU;GACZ;aANF;IAQE,kBAAC,GAAD;KACE,MAAK;KACL,SAAS;KACT,WAAW;KACX,IAAI;MACF,UAAU;MACV,KAAK,EAAM,QAAQ,CAAC;MACpB,MAAM,EAAM,QAAQ,CAAC;KACvB;eAEA,kBAAC,GAAD;MACE,MAAK;MACL,MAAM;MACN,IAAI;OAAE,QAAQ;OAAQ,OAAO;MAAO;KACrC,CAAA;IACS,CAAA;IACZ,kBAAC,GAAD;KAAY,SAAQ;KAAY,IAAI,EAAE,IAAI,EAAE;eAAG;IAEnC,CAAA;IACX,KACC,kBAAC,GAAD;KACE,UAAS;KACT,WAAW;KACX,IAAI,EACF,IAAI,EACN;KACA,MAAM;eANR;MAQE,kBAAC,UAAD,EAAA,UAAQ,gDAAqD,CAAA;MAAE;MAAI;KAE9D;;IAET,kBAAC,GAAD,EAAiC,iBAAgB,CAAA;IAChD,KACC,kBAAC,GAAD;KAAO,UAAU;KAAS,IAAI,EAAE,IAAI,EAAE;KAAG,MAAM;eAC5C,EAAM;IACF,CAAA;IAET,kBAAC,GAAD;KACE,WAAW;KACX,IAAI;MACF,SAAS;MACT,qBAAqB;MACrB,KAAK;MACL,IAAI;KACN;eAPF,CASE,kBAAC,GAAD;MACE,SAAS;MACT,SAAS;MACT,UAAU,CAAC;gBACZ;KAEO,CAAA,GACR,kBAAC,GAAD;MACE,SAAS;MACT,UAAU,CAAC;MACX,SAAS,OAAO;gBACjB;KAEO,CAAA,CACL;;IACL,kBAAC,GAAD;KACE,SAAS;KACT,WAAW;KACX,WAAA;KACA,UAAU,CAAC;KACX,SAAS;eACV;IAEO,CAAA;GACL;;EAEP,cACE,kBAAC,GAAD;GACE,IAAI;IACF,IAAI;IACJ,QAAQ;IACR,YAAY;IACZ,gBAAgB;GAClB;aAEA,kBAAC,GAAD;IACE,IAAI;KACF,IAAI;KACJ,IAAI;IACN;cAJF;KAME,kBAAC,GAAD;MAAY,SAAQ;MAAY,IAAI,EAAE,IAAI,IAAI;gBAAG;KAErC,CAAA;KACZ,kBAAC,GAAD;MAAY,SAAQ;MAAQ,IAAI,EAAE,IAAI,EAAE;gBAAG;KAG/B,CAAA;KACZ,kBAAC,GAAD;MAAY,SAAQ;MAAQ,IAAI,EAAE,IAAI,EAAE;gBAAG;KAE/B,CAAA;IACT;;EACF,CAAA;CAER,CAAA;AAEL"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TwoFactorEnrollmentForm.js","names":[],"sources":["../../../src/components/Authentication/TwoFactorEnrollmentForm.tsx"],"sourcesContent":["import { StyledOuterContainer } from '@/components/styled/LeftRightPanel'\nimport { TOTP_CLOCK_SKEW_ERROR_APPENDAGE } from '@/components/Authentication/Constants'\nimport { useFinishTwoFactorEnrollment } from '@/synapse-queries/auth/useTwoFactorEnrollment'\nimport { StyledComponent } from '@emotion/styled'\nimport {\n Box,\n BoxProps,\n Button,\n Divider,\n IconButton,\n Link,\n Paper,\n Stack,\n styled,\n Typography,\n} from '@mui/material'\nimport { TotpSecret } from '@sage-bionetworks/synapse-types'\nimport * as qrcode from 'qrcode'\n// qrcode is CJS-only; use namespace import for Vite dev mode CJS interop.\nconst { toCanvas } = qrcode\nimport { useEffect, useRef, useState } from 'react'\nimport FullWidthAlert from '../FullWidthAlert/FullWidthAlert'\nimport IconSvg from '../IconSvg/IconSvg'\nimport { SynapseSpinner } from '../LoadingScreen/LoadingScreen'\nimport TextField from '../TextField/TextField'\nimport TwoFactorSecretDialog from './TwoFactorSecretDialog'\n\n/**\n * Returns a URL that can be used to generate a QR code that 2FA authenticator apps can interpret.\n * This uses the username fro TotpSecret to create the friendly name for the account in the authenticator app.\n * @param secret\n */\nfunction toOtpAuthUrl(secret: TotpSecret) {\n return `otpauth://totp/Synapse:${secret.username}?secret=${secret.secret}&issuer=Sage%20Bionetworks&algorithm=${secret.alg}&digits=${secret.digits}&period=${secret.period}`\n}\n\nconst Section: StyledComponent<BoxProps> = styled(\n (props: BoxProps) => (\n <Box\n sx={{\n my: 3,\n ...props.sx,\n }}\n {...props}\n />\n ),\n {\n label: 'Section',\n },\n)(() => ({}))\n\nconst SectionInnerGrid = styled(Box, { label: 'SectionInnerGrid' })(\n ({ theme }) => ({\n display: 'grid',\n gridTemplateColumns: 'auto 200px',\n columnGap: theme.spacing(5),\n [theme.breakpoints.down('sm')]: {\n gridTemplateColumns: '1fr',\n gap: '18px',\n },\n }),\n)\n\nexport const TWO_FACTOR_DOCS_LINK =\n 'https://help.synapse.org/docs/Managing-Your-Account.2055405596.html#Adding-Two-Factor-Authentication-(2FA)-to-your-account'\n\nexport type TwoFactorEnrollmentFormProps = {\n totpSecret: TotpSecret\n onTwoFactorEnrollmentSuccess: () => void\n onBackClicked: () => void\n}\n\nexport default function TwoFactorEnrollmentForm(\n props: TwoFactorEnrollmentFormProps,\n) {\n const { onTwoFactorEnrollmentSuccess, onBackClicked, totpSecret } = props\n\n const [totp, setTotp] = useState('')\n const [hasQrCode, setHasQrCode] = useState(false)\n const [showSecretInModal, setShowSecretInModal] = useState(false)\n const qrCodeCanvasElement = useRef<HTMLCanvasElement>(null)\n\n const {\n mutate: finishEnrollment,\n isPending: isFinishingEnrollment,\n error,\n } = useFinishTwoFactorEnrollment({\n onSuccess: onTwoFactorEnrollmentSuccess,\n })\n\n useEffect(() => {\n async function createQrCode() {\n if (totpSecret && qrCodeCanvasElement.current) {\n await toCanvas(qrCodeCanvasElement.current, toOtpAuthUrl(totpSecret), {\n version: 10,\n margin: 0,\n scale: 3.5,\n })\n setHasQrCode(true)\n }\n }\n void createQrCode()\n }, [totpSecret])\n\n return (\n <StyledOuterContainer>\n <Paper\n sx={{\n position: 'relative',\n width: { xs: '100%', md: '800px' },\n py: 6.5,\n px: 8,\n mx: 'auto',\n }}\n >\n {onBackClicked && (\n <IconButton\n type=\"button\"\n onClick={() => {\n onBackClicked()\n }}\n sx={theme => ({\n position: 'absolute',\n top: theme.spacing(2),\n left: theme.spacing(2),\n })}\n >\n <IconSvg\n icon=\"arrowBack\"\n wrap={false}\n sx={{ height: '24px', width: '24px' }}\n />\n </IconButton>\n )}\n <Section>\n <Typography variant=\"headline2\" sx={{ mb: 3 }}>\n Activate Two-factor Authentication\n </Typography>\n <Typography variant=\"body1\">\n After setting up 2FA, you’ll use an authenticator app as part of\n your login process, in addition to your existing password. If you\n log in using your Google\n {/* eslint-disable-next-line no-constant-binary-expression -- Remove conditionality when NIH RAS login is supported */}\n {false && ', NIH RAS,'} or ORCiD account, you may need to use 2FA as\n part of\n {/*those processes*/}\n that process as well.{' '}\n <Link href={TWO_FACTOR_DOCS_LINK}>Learn more about 2FA</Link>.\n </Typography>\n </Section>\n <Section>\n <SectionInnerGrid>\n <Box>\n <Typography variant=\"body1\" sx={{ fontWeight: 700 }}>\n Step 1. Get one of these apps\n </Typography>\n <Typography variant=\"body1\">\n Download and install one of these authentication apps to set up\n 2FA on your mobile device, tablet, or desktop. If you have one\n of these apps already installed, you can skip this step.\n </Typography>\n </Box>\n <Stack\n sx={theme => ({\n justifyContent: 'space-between',\n flexShrink: 0,\n [theme.breakpoints.down('sm')]: {\n gap: '20px',\n },\n })}\n >\n <Link href={'https://authy.com/download/'}>Authy</Link>\n <Link\n href={\n 'https://duo.com/product/multi-factor-authentication-mfa/duo-mobile-app'\n }\n >\n DUO Mobile\n </Link>\n <Link href={'https://googleauthenticator.net/'}>\n Google Authenticator\n </Link>\n <Link\n href={\n 'https://www.microsoft.com/en-us/security/mobile-authenticator-app'\n }\n >\n Microsoft Authenticator\n </Link>\n </Stack>\n </SectionInnerGrid>\n </Section>\n <Divider />\n <Section>\n <SectionInnerGrid>\n <Box>\n <Typography variant=\"body1\" sx={{ fontWeight: 700 }}>\n Step 2. Scan the QR Code\n </Typography>\n <Typography component=\"ol\" variant=\"body1\" sx={{ pl: 2, my: 1 }}>\n <li>Open your authenticator app</li>\n <li>Tap the "+" button</li>\n <li>Use your camera to scan the image to the right</li>\n </Typography>\n <Link\n onClick={() => {\n setShowSecretInModal(true)\n }}\n >\n Can't use your camera?\n </Link>\n <TwoFactorSecretDialog\n secret={totpSecret?.secret ?? ''}\n open={showSecretInModal}\n onClose={() => setShowSecretInModal(false)}\n />\n </Box>\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'middle',\n height: 'auto',\n }}\n >\n {!hasQrCode && <SynapseSpinner size={50} />}\n <canvas\n style={{ display: hasQrCode ? undefined : 'none' }}\n ref={qrCodeCanvasElement}\n />\n </Box>\n </SectionInnerGrid>\n </Section>\n <Divider />\n <Section>\n <SectionInnerGrid>\n <Box>\n <Typography variant=\"body1\" sx={{ fontWeight: 700 }}>\n Step 3. Enter the Verification Code\n </Typography>\n <Typography variant=\"body1\">\n After scanning in the QR code in step 2, your app will provide a\n 6-digit code. Enter it in in the field to the right.\n </Typography>\n </Box>\n <form\n onSubmit={e => {\n e.preventDefault()\n finishEnrollment({\n secretId: totpSecret.secretId,\n totp,\n })\n }}\n >\n <Stack\n direction={'row'}\n sx={{\n gap: 2,\n height: '48px',\n }}\n >\n <TextField\n autoFocus\n slotProps={{ htmlInput: { maxLength: totpSecret?.digits } }}\n value={totp}\n onChange={e => {\n setTotp(e.target.value)\n }}\n />\n <Button\n type={'submit'}\n variant={'contained'}\n sx={{ flexShrink: 0 }}\n disabled={\n isFinishingEnrollment || totp.length != totpSecret?.digits\n }\n >\n Activate\n </Button>\n </Stack>\n </form>\n </SectionInnerGrid>\n </Section>\n {error && (\n <FullWidthAlert\n variant={'danger'}\n isGlobal={false}\n description={\n error.reason.toLowerCase().includes('invalid totp code')\n ? `${error.reason}. ${TOTP_CLOCK_SKEW_ERROR_APPENDAGE}`\n : error.reason\n }\n />\n )}\n </Paper>\n </StyledOuterContainer>\n )\n}\n\nexport const EXPORTED_FOR_UNIT_TESTING = { toOtpAuthUrl }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TwoFactorEnrollmentForm.js","names":[],"sources":["../../../src/components/Authentication/TwoFactorEnrollmentForm.tsx"],"sourcesContent":["import { StyledOuterContainer } from '@/components/styled/LeftRightPanel'\nimport { TOTP_CLOCK_SKEW_ERROR_APPENDAGE } from '@/components/Authentication/Constants'\nimport { useFinishTwoFactorEnrollment } from '@/synapse-queries/auth/useTwoFactorEnrollment'\nimport { StyledComponent } from '@emotion/styled'\nimport {\n Box,\n BoxProps,\n Button,\n Divider,\n IconButton,\n Link,\n Paper,\n Stack,\n styled,\n Typography,\n} from '@mui/material'\nimport { TotpSecret } from '@sage-bionetworks/synapse-types'\nimport * as qrcode from 'qrcode'\n// qrcode is CJS-only; use namespace import for Vite dev mode CJS interop.\nconst { toCanvas } = qrcode\nimport { useEffect, useRef, useState } from 'react'\nimport FullWidthAlert from '../FullWidthAlert/FullWidthAlert'\nimport IconSvg from '../IconSvg/IconSvg'\nimport { SynapseSpinner } from '../LoadingScreen/LoadingScreen'\nimport TextField from '../TextField/TextField'\nimport TwoFactorSecretDialog from './TwoFactorSecretDialog'\n\n/**\n * Returns a URL that can be used to generate a QR code that 2FA authenticator apps can interpret.\n * This uses the username fro TotpSecret to create the friendly name for the account in the authenticator app.\n * @param secret\n */\nfunction toOtpAuthUrl(secret: TotpSecret) {\n return `otpauth://totp/Synapse:${secret.username}?secret=${secret.secret}&issuer=Sage%20Bionetworks&algorithm=${secret.alg}&digits=${secret.digits}&period=${secret.period}`\n}\n\nconst Section: StyledComponent<BoxProps> = styled(\n (props: BoxProps) => (\n <Box\n sx={{\n my: 3,\n ...props.sx,\n }}\n {...props}\n />\n ),\n {\n label: 'Section',\n },\n)(() => ({}))\n\nconst SectionInnerGrid = styled(Box, { label: 'SectionInnerGrid' })(\n ({ theme }) => ({\n display: 'grid',\n gridTemplateColumns: 'auto 200px',\n columnGap: theme.spacing(5),\n [theme.breakpoints.down('sm')]: {\n gridTemplateColumns: '1fr',\n gap: '18px',\n },\n }),\n)\n\nexport const TWO_FACTOR_DOCS_LINK =\n 'https://help.synapse.org/docs/Managing-Your-Account.2055405596.html#Adding-Two-Factor-Authentication-(2FA)-to-your-account'\n\nexport type TwoFactorEnrollmentFormProps = {\n totpSecret: TotpSecret\n onTwoFactorEnrollmentSuccess: () => void\n onBackClicked: () => void\n}\n\nexport default function TwoFactorEnrollmentForm(\n props: TwoFactorEnrollmentFormProps,\n) {\n const { onTwoFactorEnrollmentSuccess, onBackClicked, totpSecret } = props\n\n const [totp, setTotp] = useState('')\n const [hasQrCode, setHasQrCode] = useState(false)\n const [showSecretInModal, setShowSecretInModal] = useState(false)\n const qrCodeCanvasElement = useRef<HTMLCanvasElement>(null)\n\n const {\n mutate: finishEnrollment,\n isPending: isFinishingEnrollment,\n error,\n } = useFinishTwoFactorEnrollment({\n onSuccess: onTwoFactorEnrollmentSuccess,\n })\n\n useEffect(() => {\n async function createQrCode() {\n if (totpSecret && qrCodeCanvasElement.current) {\n await toCanvas(qrCodeCanvasElement.current, toOtpAuthUrl(totpSecret), {\n version: 10,\n margin: 0,\n scale: 3.5,\n })\n setHasQrCode(true)\n }\n }\n void createQrCode()\n }, [totpSecret])\n\n return (\n <StyledOuterContainer>\n <Paper\n sx={{\n position: 'relative',\n width: { xs: '100%', md: '800px' },\n py: 6.5,\n px: 8,\n mx: 'auto',\n }}\n >\n {onBackClicked && (\n <IconButton\n type=\"button\"\n onClick={() => {\n onBackClicked()\n }}\n sx={theme => ({\n position: 'absolute',\n top: theme.spacing(2),\n left: theme.spacing(2),\n })}\n >\n <IconSvg\n icon=\"arrowBack\"\n wrap={false}\n sx={{ height: '24px', width: '24px' }}\n />\n </IconButton>\n )}\n <Section>\n <Typography variant=\"headline2\" sx={{ mb: 3 }}>\n Activate Two-factor Authentication\n </Typography>\n <Typography variant=\"body1\">\n After setting up 2FA, you’ll use an authenticator app as part of\n your login process, in addition to your existing password. If you\n log in using your Google\n {/* oxlint-disable-next-line no-constant-binary-expression -- Remove conditionality when NIH RAS login is supported */}\n {false && ', NIH RAS,'} or ORCiD account, you may need to use 2FA as\n part of\n {/*those processes*/}\n that process as well.{' '}\n <Link href={TWO_FACTOR_DOCS_LINK}>Learn more about 2FA</Link>.\n </Typography>\n </Section>\n <Section>\n <SectionInnerGrid>\n <Box>\n <Typography variant=\"body1\" sx={{ fontWeight: 700 }}>\n Step 1. Get one of these apps\n </Typography>\n <Typography variant=\"body1\">\n Download and install one of these authentication apps to set up\n 2FA on your mobile device, tablet, or desktop. If you have one\n of these apps already installed, you can skip this step.\n </Typography>\n </Box>\n <Stack\n sx={theme => ({\n justifyContent: 'space-between',\n flexShrink: 0,\n [theme.breakpoints.down('sm')]: {\n gap: '20px',\n },\n })}\n >\n <Link href={'https://authy.com/download/'}>Authy</Link>\n <Link\n href={\n 'https://duo.com/product/multi-factor-authentication-mfa/duo-mobile-app'\n }\n >\n DUO Mobile\n </Link>\n <Link href={'https://googleauthenticator.net/'}>\n Google Authenticator\n </Link>\n <Link\n href={\n 'https://www.microsoft.com/en-us/security/mobile-authenticator-app'\n }\n >\n Microsoft Authenticator\n </Link>\n </Stack>\n </SectionInnerGrid>\n </Section>\n <Divider />\n <Section>\n <SectionInnerGrid>\n <Box>\n <Typography variant=\"body1\" sx={{ fontWeight: 700 }}>\n Step 2. Scan the QR Code\n </Typography>\n <Typography component=\"ol\" variant=\"body1\" sx={{ pl: 2, my: 1 }}>\n <li>Open your authenticator app</li>\n <li>Tap the "+" button</li>\n <li>Use your camera to scan the image to the right</li>\n </Typography>\n <Link\n onClick={() => {\n setShowSecretInModal(true)\n }}\n >\n Can't use your camera?\n </Link>\n <TwoFactorSecretDialog\n secret={totpSecret?.secret ?? ''}\n open={showSecretInModal}\n onClose={() => setShowSecretInModal(false)}\n />\n </Box>\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'middle',\n height: 'auto',\n }}\n >\n {!hasQrCode && <SynapseSpinner size={50} />}\n <canvas\n style={{ display: hasQrCode ? undefined : 'none' }}\n ref={qrCodeCanvasElement}\n />\n </Box>\n </SectionInnerGrid>\n </Section>\n <Divider />\n <Section>\n <SectionInnerGrid>\n <Box>\n <Typography variant=\"body1\" sx={{ fontWeight: 700 }}>\n Step 3. Enter the Verification Code\n </Typography>\n <Typography variant=\"body1\">\n After scanning in the QR code in step 2, your app will provide a\n 6-digit code. Enter it in in the field to the right.\n </Typography>\n </Box>\n <form\n onSubmit={e => {\n e.preventDefault()\n finishEnrollment({\n secretId: totpSecret.secretId,\n totp,\n })\n }}\n >\n <Stack\n direction={'row'}\n sx={{\n gap: 2,\n height: '48px',\n }}\n >\n <TextField\n autoFocus\n slotProps={{ htmlInput: { maxLength: totpSecret?.digits } }}\n value={totp}\n onChange={e => {\n setTotp(e.target.value)\n }}\n />\n <Button\n type={'submit'}\n variant={'contained'}\n sx={{ flexShrink: 0 }}\n disabled={\n isFinishingEnrollment || totp.length != totpSecret?.digits\n }\n >\n Activate\n </Button>\n </Stack>\n </form>\n </SectionInnerGrid>\n </Section>\n {error && (\n <FullWidthAlert\n variant={'danger'}\n isGlobal={false}\n description={\n error.reason.toLowerCase().includes('invalid totp code')\n ? `${error.reason}. ${TOTP_CLOCK_SKEW_ERROR_APPENDAGE}`\n : error.reason\n }\n />\n )}\n </Paper>\n </StyledOuterContainer>\n )\n}\n\nexport const EXPORTED_FOR_UNIT_TESTING = { toOtpAuthUrl }\n"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SxProps } from '@mui/material';
|
|
2
|
+
import { EntityType } from '@sage-bionetworks/synapse-client';
|
|
2
3
|
import { MouseEventHandler } from 'react';
|
|
3
4
|
export type BreadcrumbItem = {
|
|
4
5
|
text: string;
|
|
@@ -6,6 +7,7 @@ export type BreadcrumbItem = {
|
|
|
6
7
|
to?: string;
|
|
7
8
|
href?: string;
|
|
8
9
|
onClick?: MouseEventHandler;
|
|
10
|
+
entityType?: EntityType;
|
|
9
11
|
};
|
|
10
12
|
type BreadcrumbsProps = {
|
|
11
13
|
/** The items to show in the breadcrumbs */
|
|
@@ -14,6 +16,7 @@ type BreadcrumbsProps = {
|
|
|
14
16
|
sx?: SxProps;
|
|
15
17
|
/** If defined, truncate individual item strings to be no longer than this value */
|
|
16
18
|
maxBreadcrumbLength?: number;
|
|
19
|
+
iconVariant?: 'twoTone' | 'outlined';
|
|
17
20
|
};
|
|
18
21
|
export declare function Breadcrumbs(props: BreadcrumbsProps): import("react/jsx-runtime").JSX.Element;
|
|
19
22
|
export default Breadcrumbs;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Breadcrumbs.d.ts","sourceRoot":"","sources":["../../../src/components/Breadcrumbs/Breadcrumbs.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Breadcrumbs.d.ts","sourceRoot":"","sources":["../../../src/components/Breadcrumbs/Breadcrumbs.tsx"],"names":[],"mappings":"AACA,OAAO,EAGL,OAAO,EAIR,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAA;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAA;AAIzC,MAAM,MAAM,cAAc,GAAG;IAE3B,IAAI,EAAE,MAAM,CAAA;IAEZ,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB,EAAE,CAAC,EAAE,MAAM,CAAA;IAEX,IAAI,CAAC,EAAE,MAAM,CAAA;IAEb,OAAO,CAAC,EAAE,iBAAiB,CAAA;IAE3B,UAAU,CAAC,EAAE,UAAU,CAAA;CACxB,CAAA;AAED,KAAK,gBAAgB,GAAG;IACtB,2CAA2C;IAC3C,KAAK,EAAE,cAAc,EAAE,CAAA;IACvB,uCAAuC;IACvC,EAAE,CAAC,EAAE,OAAO,CAAA;IACZ,mFAAmF;IACnF,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,WAAW,CAAC,EAAE,SAAS,GAAG,UAAU,CAAA;CACrC,CAAA;AAYD,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,2CA8ClD;AAED,eAAe,WAAW,CAAA"}
|
|
@@ -1,40 +1,53 @@
|
|
|
1
1
|
import { truncateString as e } from "../../utils/functions/StringUtils.js";
|
|
2
|
-
import t from "../
|
|
3
|
-
import {
|
|
4
|
-
import { jsx as
|
|
5
|
-
import { Link as
|
|
2
|
+
import { EntityTypeIcon as t } from "../EntityIcon.js";
|
|
3
|
+
import { Box as n, Breadcrumbs as r, Link as i, Tooltip as a, Typography as o } from "@mui/material";
|
|
4
|
+
import { jsx as s, jsxs as c } from "react/jsx-runtime";
|
|
5
|
+
import { Link as l } from "react-router";
|
|
6
6
|
//#region src/components/Breadcrumbs/Breadcrumbs.tsx
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
var u = /* @__PURE__ */ s(n, {
|
|
8
|
+
sx: { color: "grey.400" },
|
|
9
|
+
children: "/"
|
|
10
|
+
});
|
|
11
|
+
function d(d) {
|
|
12
|
+
let { items: f, sx: p, maxBreadcrumbLength: m, iconVariant: h } = d;
|
|
13
|
+
return /* @__PURE__ */ s(r, {
|
|
14
|
+
separator: u,
|
|
14
15
|
itemsBeforeCollapse: 2,
|
|
15
16
|
itemsAfterCollapse: 2,
|
|
16
|
-
sx:
|
|
17
|
-
children:
|
|
18
|
-
let
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
17
|
+
sx: p,
|
|
18
|
+
children: f.map((r, u) => {
|
|
19
|
+
let d = r.text;
|
|
20
|
+
m && (d = e(r.text, m));
|
|
21
|
+
let f = d === r.text ? null : r.text;
|
|
22
|
+
return /* @__PURE__ */ c(n, {
|
|
23
|
+
sx: {
|
|
24
|
+
display: "flex",
|
|
25
|
+
alignItems: "center",
|
|
26
|
+
gap: "8px"
|
|
27
|
+
},
|
|
28
|
+
children: [r.entityType && /* @__PURE__ */ s(t, {
|
|
29
|
+
type: r.entityType,
|
|
30
|
+
variant: h
|
|
31
|
+
}), /* @__PURE__ */ s(a, {
|
|
32
|
+
title: f,
|
|
33
|
+
placement: "top",
|
|
34
|
+
children: /* @__PURE__ */ s(o, {
|
|
35
|
+
variant: "breadcrumb1",
|
|
36
|
+
children: r.current ? d : /* @__PURE__ */ s(i, {
|
|
37
|
+
component: r.to ? l : i,
|
|
38
|
+
to: r.to,
|
|
39
|
+
href: r.href,
|
|
40
|
+
onClick: r.onClick,
|
|
41
|
+
underline: "hover",
|
|
42
|
+
children: d
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
})]
|
|
46
|
+
}, u);
|
|
34
47
|
})
|
|
35
48
|
});
|
|
36
49
|
}
|
|
37
50
|
//#endregion
|
|
38
|
-
export {
|
|
51
|
+
export { d as Breadcrumbs, d as default };
|
|
39
52
|
|
|
40
53
|
//# sourceMappingURL=Breadcrumbs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Breadcrumbs.js","names":[],"sources":["../../../src/components/Breadcrumbs/Breadcrumbs.tsx"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"Breadcrumbs.js","names":[],"sources":["../../../src/components/Breadcrumbs/Breadcrumbs.tsx"],"sourcesContent":["import { truncateString } from '@/utils/functions/StringUtils'\nimport {\n Breadcrumbs as MuiBreadcrumbs,\n Link,\n SxProps,\n Tooltip,\n Typography,\n Box,\n} from '@mui/material'\nimport { EntityType } from '@sage-bionetworks/synapse-client'\nimport { MouseEventHandler } from 'react'\nimport { Link as RouterLink } from 'react-router'\nimport EntityTypeIcon from '../EntityIcon'\n\nexport type BreadcrumbItem = {\n /* The text to show in the breadcrumb item. Strings > 25 characters will be truncated */\n text: string\n /* Whether this item represents the current page. If true, this item will not have a link. Default false */\n current?: boolean\n /* Link for the item, if using react-router */\n to?: string\n /* Link for the item, if it should be a normal anchor */\n href?: string\n /* Event handler fired when the link is clicked */\n onClick?: MouseEventHandler\n /* If defined, show an icon for this entity type */\n entityType?: EntityType\n}\n\ntype BreadcrumbsProps = {\n /** The items to show in the breadcrumbs */\n items: BreadcrumbItem[]\n /** sx passed to the MUI Breadcrumbs */\n sx?: SxProps\n /** If defined, truncate individual item strings to be no longer than this value */\n maxBreadcrumbLength?: number\n iconVariant?: 'twoTone' | 'outlined'\n}\n\nconst BREADCRUMB_SEPARATOR = (\n <Box\n sx={{\n color: 'grey.400',\n }}\n >\n /\n </Box>\n)\n\nexport function Breadcrumbs(props: BreadcrumbsProps) {\n const { items, sx, maxBreadcrumbLength, iconVariant } = props\n return (\n <MuiBreadcrumbs\n separator={BREADCRUMB_SEPARATOR}\n itemsBeforeCollapse={2}\n itemsAfterCollapse={2}\n sx={sx}\n >\n {items.map((data, index) => {\n let displayedText = data.text\n if (maxBreadcrumbLength) {\n displayedText = truncateString(data.text, maxBreadcrumbLength)\n }\n\n const tooltipText = displayedText !== data.text ? data.text : null\n return (\n <Box\n sx={{ display: 'flex', alignItems: 'center', gap: '8px' }}\n key={index}\n >\n {data.entityType && (\n <EntityTypeIcon type={data.entityType} variant={iconVariant} />\n )}\n <Tooltip title={tooltipText} placement=\"top\">\n <Typography variant={'breadcrumb1'}>\n {data.current ? (\n displayedText\n ) : (\n <Link\n component={data.to ? RouterLink : Link}\n to={data.to}\n href={data.href}\n onClick={data.onClick}\n underline=\"hover\"\n >\n {displayedText}\n </Link>\n )}\n </Typography>\n </Tooltip>\n </Box>\n )\n })}\n </MuiBreadcrumbs>\n )\n}\n\nexport default Breadcrumbs\n"],"mappings":";;;;;;AAuCA,IAAM,IACJ,kBAAC,GAAD;CACE,IAAI,EACF,OAAO,WACT;WACD;AAEI,CAAA;AAGP,SAAgB,EAAY,GAAyB;CACnD,IAAM,EAAE,UAAO,OAAI,wBAAqB,mBAAgB;CACxD,OACE,kBAAC,GAAD;EACE,WAAW;EACX,qBAAqB;EACrB,oBAAoB;EAChB;YAEH,EAAM,KAAK,GAAM,MAAU;GAC1B,IAAI,IAAgB,EAAK;GACzB,AAAI,MACF,IAAgB,EAAe,EAAK,MAAM,CAAmB;GAG/D,IAAM,IAAc,MAAkB,EAAK,OAAmB,OAAZ,EAAK;GACvD,OACE,kBAAC,GAAD;IACE,IAAI;KAAE,SAAS;KAAQ,YAAY;KAAU,KAAK;IAAM;cAD1D,CAIG,EAAK,cACJ,kBAAC,GAAD;KAAgB,MAAM,EAAK;KAAY,SAAS;IAAc,CAAA,GAEhE,kBAAC,GAAD;KAAS,OAAO;KAAa,WAAU;eACrC,kBAAC,GAAD;MAAY,SAAS;gBAClB,EAAK,UACJ,IAEA,kBAAC,GAAD;OACE,WAAW,EAAK,KAAK,IAAa;OAClC,IAAI,EAAK;OACT,MAAM,EAAK;OACX,SAAS,EAAK;OACd,WAAU;iBAET;MACG,CAAA;KAEE,CAAA;IACL,CAAA,CACN;MAtBE,CAsBF;EAET,CAAC;CACa,CAAA;AAEpB"}
|