synapse-react-client 4.0.40 → 4.0.41

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.
Files changed (195) hide show
  1. package/dist/SWC.index.d.ts +1 -0
  2. package/dist/SWC.index.d.ts.map +1 -1
  3. package/dist/SWC.index.js +2 -1
  4. package/dist/SWC.index.js.map +1 -1
  5. package/dist/components/AccessRequirement/ImposeRestrictionDialog/ImposeRestrictionDialog.d.ts +1 -0
  6. package/dist/components/AccessRequirement/ImposeRestrictionDialog/ImposeRestrictionDialog.d.ts.map +1 -1
  7. package/dist/components/AccessRequirement/ImposeRestrictionDialog/ImposeRestrictionDialog.js +12 -12
  8. package/dist/components/AccessRequirement/ImposeRestrictionDialog/ImposeRestrictionDialog.js.map +1 -1
  9. package/dist/components/Aridhia/AridhiaAccessStatus.d.ts.map +1 -1
  10. package/dist/components/Aridhia/AridhiaAccessStatus.js +51 -48
  11. package/dist/components/Aridhia/AridhiaAccessStatus.js.map +1 -1
  12. package/dist/components/Authentication/Constants.d.ts +4 -0
  13. package/dist/components/Authentication/Constants.d.ts.map +1 -1
  14. package/dist/components/Authentication/Constants.js +5 -2
  15. package/dist/components/Authentication/Constants.js.map +1 -1
  16. package/dist/components/Authentication/RecoveryCodeGrid.d.ts.map +1 -1
  17. package/dist/components/Authentication/RecoveryCodeGrid.js +8 -1
  18. package/dist/components/Authentication/RecoveryCodeGrid.js.map +1 -1
  19. package/dist/components/Authentication/RegenerateBackupCodesWarning.js +4 -1
  20. package/dist/components/Authentication/RegenerateBackupCodesWarning.js.map +1 -1
  21. package/dist/components/Authentication/TOTPForm.d.ts.map +1 -1
  22. package/dist/components/Authentication/TOTPForm.js +20 -18
  23. package/dist/components/Authentication/TOTPForm.js.map +1 -1
  24. package/dist/components/Authentication/TwoFactorBackupCodes.d.ts.map +1 -1
  25. package/dist/components/Authentication/TwoFactorBackupCodes.js +41 -12
  26. package/dist/components/Authentication/TwoFactorBackupCodes.js.map +1 -1
  27. package/dist/components/Authentication/TwoFactorEnrollmentForm.d.ts.map +1 -1
  28. package/dist/components/Authentication/TwoFactorEnrollmentForm.js +74 -71
  29. package/dist/components/Authentication/TwoFactorEnrollmentForm.js.map +1 -1
  30. package/dist/components/DataGrid/components/ReorderColumnsDialog.d.ts.map +1 -1
  31. package/dist/components/DataGrid/components/ReorderColumnsDialog.js +43 -46
  32. package/dist/components/DataGrid/components/ReorderColumnsDialog.js.map +1 -1
  33. package/dist/components/FormTemplateEditor/ChoiceOptionsEditor.d.ts +11 -0
  34. package/dist/components/FormTemplateEditor/ChoiceOptionsEditor.d.ts.map +1 -0
  35. package/dist/components/FormTemplateEditor/ChoiceOptionsEditor.js +61 -0
  36. package/dist/components/FormTemplateEditor/ChoiceOptionsEditor.js.map +1 -0
  37. package/dist/components/FormTemplateEditor/FieldDefinitionDrawer.d.ts +33 -0
  38. package/dist/components/FormTemplateEditor/FieldDefinitionDrawer.d.ts.map +1 -0
  39. package/dist/components/FormTemplateEditor/FieldDefinitionDrawer.js +187 -0
  40. package/dist/components/FormTemplateEditor/FieldDefinitionDrawer.js.map +1 -0
  41. package/dist/components/FormTemplateEditor/FormTemplatePreview.d.ts +14 -0
  42. package/dist/components/FormTemplateEditor/FormTemplatePreview.d.ts.map +1 -0
  43. package/dist/components/FormTemplateEditor/FormTemplatePreview.js +83 -0
  44. package/dist/components/FormTemplateEditor/FormTemplatePreview.js.map +1 -0
  45. package/dist/components/FormTemplateEditor/JsonSchemaBodyEditor.d.ts +13 -0
  46. package/dist/components/FormTemplateEditor/JsonSchemaBodyEditor.d.ts.map +1 -0
  47. package/dist/components/FormTemplateEditor/JsonSchemaBodyEditor.js +33 -0
  48. package/dist/components/FormTemplateEditor/JsonSchemaBodyEditor.js.map +1 -0
  49. package/dist/components/FormTemplateEditor/formTemplateValidation.d.ts +32 -0
  50. package/dist/components/FormTemplateEditor/formTemplateValidation.d.ts.map +1 -0
  51. package/dist/components/FormTemplateEditor/formTemplateValidation.js +75 -0
  52. package/dist/components/FormTemplateEditor/formTemplateValidation.js.map +1 -0
  53. package/dist/components/FormTemplateEditor/schemaFieldUtils.d.ts +25 -0
  54. package/dist/components/FormTemplateEditor/schemaFieldUtils.d.ts.map +1 -0
  55. package/dist/components/FormTemplateEditor/schemaFieldUtils.js +66 -0
  56. package/dist/components/FormTemplateEditor/schemaFieldUtils.js.map +1 -0
  57. package/dist/components/FormTemplateEditor/useSaveFormTemplate.d.ts +28 -0
  58. package/dist/components/FormTemplateEditor/useSaveFormTemplate.d.ts.map +1 -0
  59. package/dist/components/FormTemplateEditor/useSaveFormTemplate.js +39 -0
  60. package/dist/components/FormTemplateEditor/useSaveFormTemplate.js.map +1 -0
  61. package/dist/components/FormTemplateEditor/utils.d.ts +21 -0
  62. package/dist/components/FormTemplateEditor/utils.d.ts.map +1 -0
  63. package/dist/components/FormTemplateEditor/utils.js +27 -0
  64. package/dist/components/FormTemplateEditor/utils.js.map +1 -0
  65. package/dist/components/JsonSchemaForm/CustomFormContext.d.ts +1 -1
  66. package/dist/components/JsonSchemaForm/CustomFormContext.d.ts.map +1 -1
  67. package/dist/components/JsonSchemaForm/JsonSchemaForm.css +1 -1
  68. package/dist/components/JsonSchemaForm/JsonSchemaForm.module.js +1 -1
  69. package/dist/components/JsonSchemaForm/JsonSchemaForm.module.js.map +1 -1
  70. package/dist/components/JsonSchemaForm/JsonSchemaForm.module.scss +6 -1
  71. package/dist/components/JsonSchemaForm/templates/RJSFInputLabel.d.ts.map +1 -1
  72. package/dist/components/JsonSchemaForm/templates/RJSFInputLabel.js +4 -0
  73. package/dist/components/JsonSchemaForm/templates/RJSFInputLabel.js.map +1 -1
  74. package/dist/components/QueryBuilder/FilterConditionRow.css +1 -1
  75. package/dist/components/QueryBuilder/FilterConditionRow.d.ts +2 -0
  76. package/dist/components/QueryBuilder/FilterConditionRow.d.ts.map +1 -1
  77. package/dist/components/QueryBuilder/FilterConditionRow.js +112 -109
  78. package/dist/components/QueryBuilder/FilterConditionRow.js.map +1 -1
  79. package/dist/components/QueryBuilder/FilterConditionRow.module.js +10 -11
  80. package/dist/components/QueryBuilder/FilterConditionRow.module.js.map +1 -1
  81. package/dist/components/QueryBuilder/FilterConditionRow.module.scss +0 -5
  82. package/dist/components/QueryBuilder/FilterGroupNode.css +1 -1
  83. package/dist/components/QueryBuilder/FilterGroupNode.d.ts +4 -0
  84. package/dist/components/QueryBuilder/FilterGroupNode.d.ts.map +1 -1
  85. package/dist/components/QueryBuilder/FilterGroupNode.js +85 -51
  86. package/dist/components/QueryBuilder/FilterGroupNode.js.map +1 -1
  87. package/dist/components/QueryBuilder/FilterGroupNode.module.js +10 -9
  88. package/dist/components/QueryBuilder/FilterGroupNode.module.js.map +1 -1
  89. package/dist/components/QueryBuilder/FilterGroupNode.module.scss +9 -0
  90. package/dist/components/QueryBuilder/QBDragHandle.d.ts +10 -0
  91. package/dist/components/QueryBuilder/QBDragHandle.d.ts.map +1 -0
  92. package/dist/components/QueryBuilder/QBDragHandle.js +22 -0
  93. package/dist/components/QueryBuilder/QBDragHandle.js.map +1 -0
  94. package/dist/components/QueryBuilder/QueryBuilderControls.d.ts.map +1 -1
  95. package/dist/components/QueryBuilder/QueryBuilderControls.js +112 -107
  96. package/dist/components/QueryBuilder/QueryBuilderControls.js.map +1 -1
  97. package/dist/components/QueryBuilder/qbTreeToReadable.js +11 -11
  98. package/dist/components/QueryBuilder/queryBuilderDnd.d.ts +27 -0
  99. package/dist/components/QueryBuilder/queryBuilderDnd.d.ts.map +1 -0
  100. package/dist/components/QueryBuilder/queryBuilderDnd.js +41 -0
  101. package/dist/components/QueryBuilder/queryBuilderDnd.js.map +1 -0
  102. package/dist/components/QueryBuilder/queryBuilderDrag.css +1 -0
  103. package/dist/components/QueryBuilder/queryBuilderDrag.module.js +8 -0
  104. package/dist/components/QueryBuilder/queryBuilderDrag.module.js.map +1 -0
  105. package/dist/components/QueryBuilder/queryBuilderDrag.module.scss +12 -0
  106. package/dist/components/QueryBuilder/queryBuilderOperations.d.ts +13 -0
  107. package/dist/components/QueryBuilder/queryBuilderOperations.d.ts.map +1 -1
  108. package/dist/components/QueryBuilder/queryBuilderOperations.js +39 -36
  109. package/dist/components/QueryBuilder/queryBuilderOperations.js.map +1 -1
  110. package/dist/components/QueryWrapperPlotNav/QueryWrapperPlotNav.d.ts.map +1 -1
  111. package/dist/components/QueryWrapperPlotNav/QueryWrapperPlotNav.js +46 -47
  112. package/dist/components/QueryWrapperPlotNav/QueryWrapperPlotNav.js.map +1 -1
  113. package/dist/components/entity/page/title_bar/EntityPageTitleBar.d.ts +0 -1
  114. package/dist/components/entity/page/title_bar/EntityPageTitleBar.d.ts.map +1 -1
  115. package/dist/components/entity/page/title_bar/EntityPageTitleBar.js +35 -36
  116. package/dist/components/entity/page/title_bar/EntityPageTitleBar.js.map +1 -1
  117. package/dist/components/styled/LeftRightPanel.d.ts.map +1 -1
  118. package/dist/components/styled/LeftRightPanel.js +19 -2
  119. package/dist/components/styled/LeftRightPanel.js.map +1 -1
  120. package/dist/mocks/accessRequirement/mockFormTemplates.d.ts +2 -2
  121. package/dist/mocks/accessRequirement/mockFormTemplates.d.ts.map +1 -1
  122. package/dist/mocks/accessRequirement/mockFormTemplates.js +7 -14
  123. package/dist/mocks/accessRequirement/mockFormTemplates.js.map +1 -1
  124. package/dist/mocks/accessRequirement/mockJsonSchemas.d.ts +4 -1
  125. package/dist/mocks/accessRequirement/mockJsonSchemas.d.ts.map +1 -1
  126. package/dist/mocks/accessRequirement/mockJsonSchemas.js +36 -15
  127. package/dist/mocks/accessRequirement/mockJsonSchemas.js.map +1 -1
  128. package/dist/mocks/msw/handlers/asyncJobHandlers.d.ts +41 -14
  129. package/dist/mocks/msw/handlers/asyncJobHandlers.d.ts.map +1 -1
  130. package/dist/mocks/msw/handlers/asyncJobHandlers.js +53 -44
  131. package/dist/mocks/msw/handlers/asyncJobHandlers.js.map +1 -1
  132. package/dist/mocks/msw/handlers/chatHandlers.d.ts.map +1 -1
  133. package/dist/mocks/msw/handlers/chatHandlers.js +19 -13
  134. package/dist/mocks/msw/handlers/chatHandlers.js.map +1 -1
  135. package/dist/mocks/msw/handlers/schemaHandlers.d.ts +2 -1
  136. package/dist/mocks/msw/handlers/schemaHandlers.d.ts.map +1 -1
  137. package/dist/mocks/msw/handlers/schemaHandlers.js +13 -7
  138. package/dist/mocks/msw/handlers/schemaHandlers.js.map +1 -1
  139. package/dist/mocks/msw/handlers/searchQueryHandlers.d.ts.map +1 -1
  140. package/dist/mocks/msw/handlers/searchQueryHandlers.js +24 -18
  141. package/dist/mocks/msw/handlers/searchQueryHandlers.js.map +1 -1
  142. package/dist/mocks/msw/handlers/tableQueryHandlers.d.ts.map +1 -1
  143. package/dist/mocks/msw/handlers/tableQueryHandlers.js +35 -16
  144. package/dist/mocks/msw/handlers/tableQueryHandlers.js.map +1 -1
  145. package/dist/synapse-queries/KeyFactory.d.ts +1 -2
  146. package/dist/synapse-queries/KeyFactory.d.ts.map +1 -1
  147. package/dist/synapse-queries/KeyFactory.js +2 -5
  148. package/dist/synapse-queries/KeyFactory.js.map +1 -1
  149. package/dist/synapse-queries/dataaccess/index.d.ts +0 -1
  150. package/dist/synapse-queries/dataaccess/index.d.ts.map +1 -1
  151. package/dist/synapse-queries/dataaccess/index.js +3 -4
  152. package/dist/synapse-queries/index.js +180 -184
  153. package/dist/synapse-queries/jsonschema/useCreateJsonSchema.d.ts +9 -0
  154. package/dist/synapse-queries/jsonschema/useCreateJsonSchema.d.ts.map +1 -0
  155. package/dist/synapse-queries/jsonschema/useCreateJsonSchema.js +22 -0
  156. package/dist/synapse-queries/jsonschema/useCreateJsonSchema.js.map +1 -0
  157. package/dist/testutils/vitest.setup.js +18 -9
  158. package/dist/testutils/vitest.setup.js.map +1 -1
  159. package/dist/tsconfig.build.tsbuildinfo +1 -1
  160. package/dist/utils/APIConstants.d.ts +1 -0
  161. package/dist/utils/APIConstants.d.ts.map +1 -1
  162. package/dist/utils/APIConstants.js +2 -2
  163. package/dist/utils/APIConstants.js.map +1 -1
  164. package/dist/utils/appendFinalQueryParamKey.d.ts.map +1 -1
  165. package/dist/utils/appendFinalQueryParamKey.js +4 -1
  166. package/dist/utils/appendFinalQueryParamKey.js.map +1 -1
  167. package/dist/utils/featureflag/FeatureFlags.d.ts +1 -0
  168. package/dist/utils/featureflag/FeatureFlags.d.ts.map +1 -1
  169. package/dist/utils/featureflag/FeatureFlags.js +1 -1
  170. package/dist/utils/featureflag/FeatureFlags.js.map +1 -1
  171. package/dist/utils/functions/ArrayUtils.d.ts +3 -0
  172. package/dist/utils/functions/ArrayUtils.d.ts.map +1 -1
  173. package/dist/utils/functions/ArrayUtils.js +7 -1
  174. package/dist/utils/functions/ArrayUtils.js.map +1 -1
  175. package/dist/utils/jsonschema/generateDataAccessSchema.d.ts +26 -0
  176. package/dist/utils/jsonschema/generateDataAccessSchema.d.ts.map +1 -0
  177. package/dist/utils/jsonschema/generateDataAccessSchema.js +28 -0
  178. package/dist/utils/jsonschema/generateDataAccessSchema.js.map +1 -0
  179. package/dist/utils/jsonschema/submissionContext.d.ts +86 -0
  180. package/dist/utils/jsonschema/submissionContext.d.ts.map +1 -0
  181. package/dist/utils/jsonschema/submissionContext.js +186 -0
  182. package/dist/utils/jsonschema/submissionContext.js.map +1 -0
  183. package/package.json +5 -3
  184. package/dist/components/AccessRequirement/AddConditionsForUseButton/AddConditionsForUseButton.d.ts +0 -6
  185. package/dist/components/AccessRequirement/AddConditionsForUseButton/AddConditionsForUseButton.d.ts.map +0 -1
  186. package/dist/components/AccessRequirement/AddConditionsForUseButton/AddConditionsForUseButton.js +0 -32
  187. package/dist/components/AccessRequirement/AddConditionsForUseButton/AddConditionsForUseButton.js.map +0 -1
  188. package/dist/components/entity/page/title_bar/TitleBarProperties.d.ts +0 -9
  189. package/dist/components/entity/page/title_bar/TitleBarProperties.d.ts.map +0 -1
  190. package/dist/components/entity/page/title_bar/TitleBarProperties.js +0 -24
  191. package/dist/components/entity/page/title_bar/TitleBarProperties.js.map +0 -1
  192. package/dist/synapse-queries/dataaccess/useGenerateDataAccessSchema.d.ts +0 -21
  193. package/dist/synapse-queries/dataaccess/useGenerateDataAccessSchema.d.ts.map +0 -1
  194. package/dist/synapse-queries/dataaccess/useGenerateDataAccessSchema.js +0 -34
  195. package/dist/synapse-queries/dataaccess/useGenerateDataAccessSchema.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"TwoFactorBackupCodes.d.ts","sourceRoot":"","sources":["../../../src/components/Authentication/TwoFactorBackupCodes.tsx"],"names":[],"mappings":"AAyBA,MAAM,MAAM,yBAAyB,GAAG;IAEtC,0BAA0B,CAAC,EAAE,OAAO,CAAA;IAEpC,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,CAAA;AAED,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,2CAqK5E"}
1
+ {"version":3,"file":"TwoFactorBackupCodes.d.ts","sourceRoot":"","sources":["../../../src/components/Authentication/TwoFactorBackupCodes.tsx"],"names":[],"mappings":"AAyBA,MAAM,MAAM,yBAAyB,GAAG;IAEtC,0BAA0B,CAAC,EAAE,OAAO,CAAA;IAEpC,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,CAAA;AAED,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,2CAuL5E"}
@@ -40,10 +40,15 @@ function S(S) {
40
40
  className: M,
41
41
  leftContent: /* @__PURE__ */ b(m, {
42
42
  sx: {
43
- py: 10,
44
- px: 8,
45
- height: "100%",
46
- position: "relative"
43
+ py: {
44
+ xs: "10px",
45
+ md: 10
46
+ },
47
+ px: {
48
+ xs: "10px",
49
+ md: 8
50
+ },
51
+ height: "100%"
47
52
  },
48
53
  children: [
49
54
  /* @__PURE__ */ y(g, {
@@ -52,8 +57,14 @@ function S(S) {
52
57
  className: N,
53
58
  sx: {
54
59
  position: "absolute",
55
- top: T.spacing(2),
56
- left: T.spacing(2)
60
+ top: {
61
+ xs: 0,
62
+ md: T.spacing(2)
63
+ },
64
+ left: {
65
+ xs: 0,
66
+ md: T.spacing(2)
67
+ }
57
68
  },
58
69
  children: /* @__PURE__ */ y(i, {
59
70
  icon: "arrowBack",
@@ -66,7 +77,10 @@ function S(S) {
66
77
  }),
67
78
  /* @__PURE__ */ y(_, {
68
79
  variant: "headline1",
69
- sx: { mt: 7 },
80
+ sx: { mt: {
81
+ xs: 0,
82
+ md: 7
83
+ } },
70
84
  children: "Backup codes"
71
85
  }),
72
86
  C && /* @__PURE__ */ b(p, {
@@ -119,20 +133,35 @@ function S(S) {
119
133
  }),
120
134
  rightContent: /* @__PURE__ */ y(m, {
121
135
  sx: {
122
- py: 10,
136
+ padding: {
137
+ xs: "60px 0 0 0",
138
+ md: 10
139
+ },
123
140
  height: "100%",
124
- background: "url(https://s3.amazonaws.com/static.synapse.org/images/twofactor-graphic.svg) no-repeat right bottom",
141
+ background: {
142
+ xs: "none",
143
+ md: "url(https://s3.amazonaws.com/static.synapse.org/images/twofactor-graphic.svg) no-repeat right bottom"
144
+ },
125
145
  backgroundSize: "100%"
126
146
  },
127
147
  children: /* @__PURE__ */ b(m, {
128
148
  sx: {
129
- mt: 7,
130
- px: 9
149
+ mt: {
150
+ xs: 0,
151
+ md: 7
152
+ },
153
+ px: {
154
+ xs: "10px",
155
+ md: 9
156
+ }
131
157
  },
132
158
  children: [
133
159
  /* @__PURE__ */ y(_, {
134
160
  variant: "headline1",
135
- sx: { mb: 2.5 },
161
+ sx: (e) => ({
162
+ mb: 2.5,
163
+ [e.breakpoints.down("md")]: { fontSize: "18px" }
164
+ }),
136
165
  children: "Save these codes"
137
166
  }),
138
167
  /* @__PURE__ */ y(_, {
@@ -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 // 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
+ {"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: { xs: '10px', md: 10 },\n px: { xs: '10px', md: 8 },\n height: '100%',\n }}\n >\n <IconButton\n type=\"button\"\n onClick={onClose}\n className={hiddenOnPrintClassName}\n sx={{\n position: 'absolute',\n top: { xs: 0, md: theme.spacing(2) },\n left: { xs: 0, md: 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: { xs: 0, md: 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 padding: { xs: '60px 0 0 0', md: 10 },\n height: '100%',\n background: {\n xs: 'none',\n md: `url(https://s3.amazonaws.com/static.synapse.org/images/twofactor-graphic.svg) no-repeat right bottom`,\n },\n backgroundSize: '100%',\n }}\n >\n <Box\n sx={{\n mt: { xs: 0, md: 7 },\n px: { xs: '10px', md: 9 },\n }}\n >\n <Typography\n variant=\"headline1\"\n sx={theme => ({\n mb: 2.5,\n [theme.breakpoints.down('md')]: { fontSize: '18px' },\n })}\n >\n Save these codes\n </Typography>\n <Typography\n variant=\"body1\"\n sx={{\n my: 2,\n }}\n >\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\n variant=\"body1\"\n sx={{\n my: 2,\n }}\n >\n Each code can only be used once.\n </Typography>\n </Box>\n </Box>\n }\n />\n )\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"TwoFactorEnrollmentForm.d.ts","sourceRoot":"","sources":["../../../src/components/Authentication/TwoFactorEnrollmentForm.tsx"],"names":[],"mappings":"AAgBA,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAW5D;;;;GAIG;AACH,iBAAS,YAAY,CAAC,MAAM,EAAE,UAAU,UAEvC;AA6BD,eAAO,MAAM,oBAAoB,+HAC6F,CAAA;AAE9H,MAAM,MAAM,4BAA4B,GAAG;IACzC,UAAU,EAAE,UAAU,CAAA;IACtB,4BAA4B,EAAE,MAAM,IAAI,CAAA;IACxC,aAAa,EAAE,MAAM,IAAI,CAAA;CAC1B,CAAA;AAED,MAAM,CAAC,OAAO,UAAU,uBAAuB,CAC7C,KAAK,EAAE,4BAA4B,2CAgOpC;AAED,eAAO,MAAM,yBAAyB;;CAAmB,CAAA"}
1
+ {"version":3,"file":"TwoFactorEnrollmentForm.d.ts","sourceRoot":"","sources":["../../../src/components/Authentication/TwoFactorEnrollmentForm.tsx"],"names":[],"mappings":"AAmBA,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAW5D;;;;GAIG;AACH,iBAAS,YAAY,CAAC,MAAM,EAAE,UAAU,UAEvC;AA6BD,eAAO,MAAM,oBAAoB,+HAC6F,CAAA;AAE9H,MAAM,MAAM,4BAA4B,GAAG;IACzC,UAAU,EAAE,UAAU,CAAA;IACtB,4BAA4B,EAAE,MAAM,IAAI,CAAA;IACxC,aAAa,EAAE,MAAM,IAAI,CAAA;CAC1B,CAAA;AAED,MAAM,CAAC,OAAO,UAAU,uBAAuB,CAC7C,KAAK,EAAE,4BAA4B,2CAqOpC;AAED,eAAO,MAAM,yBAAyB;;CAAmB,CAAA"}
@@ -1,27 +1,27 @@
1
1
  import e from "../FullWidthAlert/FullWidthAlert.js";
2
- import "./Constants.js";
3
- import { SynapseSpinner as t } from "../LoadingScreen/LoadingScreen.js";
4
- import { useFinishTwoFactorEnrollment as n } from "../../synapse-queries/auth/useTwoFactorEnrollment.js";
5
- import r from "../IconSvg/IconSvg.js";
6
- import i from "../TextField/TextField.js";
7
- import { StyledOuterContainer as a } from "../styled/LeftRightPanel.js";
8
- import o from "./TwoFactorSecretDialog.js";
9
- import { useEffect as s, useRef as c, useState as l } from "react";
10
- import { Box as u, Button as d, Divider as f, IconButton as p, Link as m, Paper as h, Stack as g, Typography as _, styled as v } from "@mui/material";
11
- import { jsx as y, jsxs as b } from "react/jsx-runtime";
12
- import * as x from "qrcode";
2
+ import { NUMERIC_CODE_HTML_INPUT_PROPS as t } from "./Constants.js";
3
+ import { SynapseSpinner as n } from "../LoadingScreen/LoadingScreen.js";
4
+ import { useFinishTwoFactorEnrollment as r } from "../../synapse-queries/auth/useTwoFactorEnrollment.js";
5
+ import i from "../IconSvg/IconSvg.js";
6
+ import a from "../TextField/TextField.js";
7
+ import { StyledOuterContainer as o } from "../styled/LeftRightPanel.js";
8
+ import s from "./TwoFactorSecretDialog.js";
9
+ import { useEffect as c, useRef as l, useState as u } from "react";
10
+ import { Box as d, Button as f, Divider as p, IconButton as m, Link as h, Paper as g, Stack as _, Typography as v, styled as y } from "@mui/material";
11
+ import { jsx as b, jsxs as x } from "react/jsx-runtime";
12
+ import * as S from "qrcode";
13
13
  //#region src/components/Authentication/TwoFactorEnrollmentForm.tsx
14
- var { toCanvas: S } = x;
15
- function C(e) {
14
+ var { toCanvas: C } = S;
15
+ function w(e) {
16
16
  return `otpauth://totp/Synapse:${e.username}?secret=${e.secret}&issuer=Sage%20Bionetworks&algorithm=${e.alg}&digits=${e.digits}&period=${e.period}`;
17
17
  }
18
- var w = v((e) => /* @__PURE__ */ y(u, {
18
+ var T = y((e) => /* @__PURE__ */ b(d, {
19
19
  sx: {
20
20
  my: 3,
21
21
  ...e.sx
22
22
  },
23
23
  ...e
24
- }), { label: "Section" })(() => ({})), T = v(u, { label: "SectionInnerGrid" })(({ theme: e }) => ({
24
+ }), { label: "Section" })(() => ({})), E = y(d, { label: "SectionInnerGrid" })(({ theme: e }) => ({
25
25
  display: "grid",
26
26
  gridTemplateColumns: "auto 200px",
27
27
  columnGap: e.spacing(5),
@@ -29,19 +29,19 @@ var w = v((e) => /* @__PURE__ */ y(u, {
29
29
  gridTemplateColumns: "1fr",
30
30
  gap: "18px"
31
31
  }
32
- })), E = "https://help.synapse.org/docs/Managing-Your-Account.2055405596.html#Adding-Two-Factor-Authentication-(2FA)-to-your-account";
33
- function D(v) {
34
- let { onTwoFactorEnrollmentSuccess: x, onBackClicked: D, totpSecret: O } = v, [k, A] = l(""), [j, M] = l(!1), [N, P] = l(!1), F = c(null), { mutate: I, isPending: L, error: R } = n({ onSuccess: x });
35
- return s(() => {
32
+ })), D = "https://help.synapse.org/docs/Managing-Your-Account.2055405596.html#Adding-Two-Factor-Authentication-(2FA)-to-your-account";
33
+ function O(y) {
34
+ let { onTwoFactorEnrollmentSuccess: S, onBackClicked: O, totpSecret: k } = y, [A, j] = u(""), [M, N] = u(!1), [P, F] = u(!1), I = l(null), { mutate: L, isPending: R, error: z } = r({ onSuccess: S });
35
+ return c(() => {
36
36
  async function e() {
37
- O && F.current && (await S(F.current, C(O), {
37
+ k && I.current && (await C(I.current, w(k), {
38
38
  version: 10,
39
39
  margin: 0,
40
40
  scale: 3.5
41
- }), M(!0));
41
+ }), N(!0));
42
42
  }
43
43
  e();
44
- }, [O]), /* @__PURE__ */ y(a, { children: /* @__PURE__ */ b(h, {
44
+ }, [k]), /* @__PURE__ */ b(o, { children: /* @__PURE__ */ x(g, {
45
45
  sx: {
46
46
  position: "relative",
47
47
  width: {
@@ -53,17 +53,17 @@ function D(v) {
53
53
  mx: "auto"
54
54
  },
55
55
  children: [
56
- D && /* @__PURE__ */ y(p, {
56
+ O && /* @__PURE__ */ b(m, {
57
57
  type: "button",
58
58
  onClick: () => {
59
- D();
59
+ O();
60
60
  },
61
61
  sx: (e) => ({
62
62
  position: "absolute",
63
63
  top: e.spacing(2),
64
64
  left: e.spacing(2)
65
65
  }),
66
- children: /* @__PURE__ */ y(r, {
66
+ children: /* @__PURE__ */ b(i, {
67
67
  icon: "arrowBack",
68
68
  wrap: !1,
69
69
  sx: {
@@ -72,11 +72,11 @@ function D(v) {
72
72
  }
73
73
  })
74
74
  }),
75
- /* @__PURE__ */ b(w, { children: [/* @__PURE__ */ y(_, {
75
+ /* @__PURE__ */ x(T, { children: [/* @__PURE__ */ b(v, {
76
76
  variant: "headline2",
77
77
  sx: { mb: 3 },
78
78
  children: "Activate Two-factor Authentication"
79
- }), /* @__PURE__ */ b(_, {
79
+ }), /* @__PURE__ */ x(v, {
80
80
  variant: "body1",
81
81
  children: [
82
82
  "After setting up 2FA, you’ll use an authenticator app as part of your login process, in addition to your existing password. If you log in using your Google",
@@ -84,53 +84,53 @@ function D(v) {
84
84
  " or ORCiD account, you may need to use 2FA as part of",
85
85
  "that process as well.",
86
86
  " ",
87
- /* @__PURE__ */ y(m, {
88
- href: E,
87
+ /* @__PURE__ */ b(h, {
88
+ href: D,
89
89
  children: "Learn more about 2FA"
90
90
  }),
91
91
  "."
92
92
  ]
93
93
  })] }),
94
- /* @__PURE__ */ y(w, { children: /* @__PURE__ */ b(T, { children: [/* @__PURE__ */ b(u, { children: [/* @__PURE__ */ y(_, {
94
+ /* @__PURE__ */ b(T, { children: /* @__PURE__ */ x(E, { children: [/* @__PURE__ */ x(d, { children: [/* @__PURE__ */ b(v, {
95
95
  variant: "body1",
96
96
  sx: { fontWeight: 700 },
97
97
  children: "Step 1. Get one of these apps"
98
- }), /* @__PURE__ */ y(_, {
98
+ }), /* @__PURE__ */ b(v, {
99
99
  variant: "body1",
100
100
  children: "Download and install one of these authentication apps to set up 2FA on your mobile device, tablet, or desktop. If you have one of these apps already installed, you can skip this step."
101
- })] }), /* @__PURE__ */ b(g, {
101
+ })] }), /* @__PURE__ */ x(_, {
102
102
  sx: (e) => ({
103
103
  justifyContent: "space-between",
104
104
  flexShrink: 0,
105
105
  [e.breakpoints.down("sm")]: { gap: "20px" }
106
106
  }),
107
107
  children: [
108
- /* @__PURE__ */ y(m, {
108
+ /* @__PURE__ */ b(h, {
109
109
  href: "https://authy.com/download/",
110
110
  children: "Authy"
111
111
  }),
112
- /* @__PURE__ */ y(m, {
112
+ /* @__PURE__ */ b(h, {
113
113
  href: "https://duo.com/product/multi-factor-authentication-mfa/duo-mobile-app",
114
114
  children: "DUO Mobile"
115
115
  }),
116
- /* @__PURE__ */ y(m, {
116
+ /* @__PURE__ */ b(h, {
117
117
  href: "https://googleauthenticator.net/",
118
118
  children: "Google Authenticator"
119
119
  }),
120
- /* @__PURE__ */ y(m, {
120
+ /* @__PURE__ */ b(h, {
121
121
  href: "https://www.microsoft.com/en-us/security/mobile-authenticator-app",
122
122
  children: "Microsoft Authenticator"
123
123
  })
124
124
  ]
125
125
  })] }) }),
126
- /* @__PURE__ */ y(f, {}),
127
- /* @__PURE__ */ y(w, { children: /* @__PURE__ */ b(T, { children: [/* @__PURE__ */ b(u, { children: [
128
- /* @__PURE__ */ y(_, {
126
+ /* @__PURE__ */ b(p, {}),
127
+ /* @__PURE__ */ b(T, { children: /* @__PURE__ */ x(E, { children: [/* @__PURE__ */ x(d, { children: [
128
+ /* @__PURE__ */ b(v, {
129
129
  variant: "body1",
130
130
  sx: { fontWeight: 700 },
131
131
  children: "Step 2. Scan the QR Code"
132
132
  }),
133
- /* @__PURE__ */ b(_, {
133
+ /* @__PURE__ */ x(v, {
134
134
  component: "ol",
135
135
  variant: "body1",
136
136
  sx: {
@@ -138,81 +138,84 @@ function D(v) {
138
138
  my: 1
139
139
  },
140
140
  children: [
141
- /* @__PURE__ */ y("li", { children: "Open your authenticator app" }),
142
- /* @__PURE__ */ y("li", { children: "Tap the \"+\" button" }),
143
- /* @__PURE__ */ y("li", { children: "Use your camera to scan the image to the right" })
141
+ /* @__PURE__ */ b("li", { children: "Open your authenticator app" }),
142
+ /* @__PURE__ */ b("li", { children: "Tap the \"+\" button" }),
143
+ /* @__PURE__ */ b("li", { children: "Use your camera to scan the image to the right" })
144
144
  ]
145
145
  }),
146
- /* @__PURE__ */ y(m, {
146
+ /* @__PURE__ */ b(h, {
147
147
  onClick: () => {
148
- P(!0);
148
+ F(!0);
149
149
  },
150
150
  children: "Can't use your camera?"
151
151
  }),
152
- /* @__PURE__ */ y(o, {
153
- secret: O?.secret ?? "",
154
- open: N,
155
- onClose: () => P(!1)
152
+ /* @__PURE__ */ b(s, {
153
+ secret: k?.secret ?? "",
154
+ open: P,
155
+ onClose: () => F(!1)
156
156
  })
157
- ] }), /* @__PURE__ */ b(u, {
157
+ ] }), /* @__PURE__ */ x(d, {
158
158
  sx: {
159
159
  display: "flex",
160
160
  justifyContent: "center",
161
161
  alignItems: "middle",
162
162
  height: "auto"
163
163
  },
164
- children: [!j && /* @__PURE__ */ y(t, { size: 50 }), /* @__PURE__ */ y("canvas", {
165
- style: { display: j ? void 0 : "none" },
166
- ref: F
164
+ children: [!M && /* @__PURE__ */ b(n, { size: 50 }), /* @__PURE__ */ b("canvas", {
165
+ style: { display: M ? void 0 : "none" },
166
+ ref: I
167
167
  })]
168
168
  })] }) }),
169
- /* @__PURE__ */ y(f, {}),
170
- /* @__PURE__ */ y(w, { children: /* @__PURE__ */ b(T, { children: [/* @__PURE__ */ b(u, { children: [/* @__PURE__ */ y(_, {
169
+ /* @__PURE__ */ b(p, {}),
170
+ /* @__PURE__ */ b(T, { children: /* @__PURE__ */ x(E, { children: [/* @__PURE__ */ x(d, { children: [/* @__PURE__ */ b(v, {
171
171
  variant: "body1",
172
172
  sx: { fontWeight: 700 },
173
173
  children: "Step 3. Enter the Verification Code"
174
- }), /* @__PURE__ */ y(_, {
174
+ }), /* @__PURE__ */ b(v, {
175
175
  variant: "body1",
176
176
  children: "After scanning in the QR code in step 2, your app will provide a 6-digit code. Enter it in in the field to the right."
177
- })] }), /* @__PURE__ */ y("form", {
177
+ })] }), /* @__PURE__ */ b("form", {
178
178
  onSubmit: (e) => {
179
- e.preventDefault(), I({
180
- secretId: O.secretId,
181
- totp: k
179
+ e.preventDefault(), L({
180
+ secretId: k.secretId,
181
+ totp: A
182
182
  });
183
183
  },
184
- children: /* @__PURE__ */ b(g, {
184
+ children: /* @__PURE__ */ x(_, {
185
185
  direction: "row",
186
186
  sx: {
187
187
  gap: 2,
188
188
  height: "48px"
189
189
  },
190
- children: [/* @__PURE__ */ y(i, {
190
+ children: [/* @__PURE__ */ b(a, {
191
191
  autoFocus: !0,
192
- slotProps: { htmlInput: { maxLength: O?.digits } },
193
- value: k,
192
+ slotProps: { htmlInput: {
193
+ ...t,
194
+ maxLength: k?.digits
195
+ } },
196
+ value: A,
194
197
  onChange: (e) => {
195
- A(e.target.value);
198
+ j(e.target.value);
196
199
  }
197
- }), /* @__PURE__ */ y(d, {
200
+ }), /* @__PURE__ */ b(f, {
198
201
  type: "submit",
199
202
  variant: "contained",
200
203
  sx: { flexShrink: 0 },
201
- disabled: L || k.length != O?.digits,
204
+ disabled: R || A.length != k?.digits,
202
205
  children: "Activate"
203
206
  })]
204
207
  })
205
208
  })] }) }),
206
- R && /* @__PURE__ */ y(e, {
209
+ z && /* @__PURE__ */ b(e, {
207
210
  variant: "danger",
208
211
  isGlobal: !1,
209
- description: R.reason.toLowerCase().includes("invalid totp code") ? `${R.reason}. Please ensure automatic date and time is enabled in your device settings and try again.` : R.reason
212
+ description: z.reason.toLowerCase().includes("invalid totp code") ? `${z.reason}. Please ensure automatic date and time is enabled in your device settings and try again.` : z.reason
210
213
  })
211
214
  ]
212
215
  }) });
213
216
  }
214
- var O = { toOtpAuthUrl: C };
217
+ var k = { toOtpAuthUrl: w };
215
218
  //#endregion
216
- export { O as EXPORTED_FOR_UNIT_TESTING, E as TWO_FACTOR_DOCS_LINK, D as default };
219
+ export { k as EXPORTED_FOR_UNIT_TESTING, D as TWO_FACTOR_DOCS_LINK, O as default };
217
220
 
218
221
  //# sourceMappingURL=TwoFactorEnrollmentForm.js.map
@@ -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 {/* 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 &quot;+&quot; 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&apos;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 {\n NUMERIC_CODE_HTML_INPUT_PROPS,\n TOTP_CLOCK_SKEW_ERROR_APPENDAGE,\n} 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 &quot;+&quot; 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&apos;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={{\n htmlInput: {\n ...NUMERIC_CODE_HTML_INPUT_PROPS,\n maxLength: totpSecret?.digits,\n },\n }}\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 +1 @@
1
- {"version":3,"file":"ReorderColumnsDialog.d.ts","sourceRoot":"","sources":["../../../../src/components/DataGrid/components/ReorderColumnsDialog.tsx"],"names":[],"mappings":"AAoBA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAIzC,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,EAAE,OAAO,CAAA;IACb,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,UAAU,EAAE,WAAW,GAAG,SAAS,CAAA;IACnC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,iGAAiG;IACjG,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,MAAM,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,KAAK,IAAI,CAAA;IAC1C,QAAQ,EAAE,MAAM,IAAI,CAAA;CACrB,CAAA;AASD,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,2CA8J5E"}
1
+ {"version":3,"file":"ReorderColumnsDialog.d.ts","sourceRoot":"","sources":["../../../../src/components/DataGrid/components/ReorderColumnsDialog.tsx"],"names":[],"mappings":"AAqBA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAIzC,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,EAAE,OAAO,CAAA;IACb,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,UAAU,EAAE,WAAW,GAAG,SAAS,CAAA;IACnC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,iGAAiG;IACjG,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,MAAM,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,KAAK,IAAI,CAAA;IAC1C,QAAQ,EAAE,MAAM,IAAI,CAAA;CACrB,CAAA;AAED,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,2CA8J5E"}