From ddb7197ff9b2399a4b86bf241eae3497673add4b Mon Sep 17 00:00:00 2001 From: Stan Dzhumaev Date: Fri, 10 Jan 2025 13:30:55 -0800 Subject: [PATCH] [AXON-45] First approximation of API token auth for JIRA --- src/react/atlascode/config/ConfigPage.tsx | 2 +- .../atlascode/config/auth/AuthDialog.tsx | 510 ------------------ .../config/auth/SiteAuthenticator.tsx | 145 +++-- .../config/auth/dialog/AuthDialog.tsx | 253 +++++++++ .../config/auth/dialog/CustomSiteAuthForm.tsx | 278 ++++++++++ .../auth/dialog/JiraApiTokenAuthForm.tsx | 92 ++++ .../atlascode/config/auth/dialog/TabPanel.tsx | 25 + .../atlascode/config/auth/dialog/types.ts | 23 + .../atlascode/onboarding/OnboardingPage.tsx | 2 +- 9 files changed, 779 insertions(+), 551 deletions(-) delete mode 100644 src/react/atlascode/config/auth/AuthDialog.tsx create mode 100644 src/react/atlascode/config/auth/dialog/AuthDialog.tsx create mode 100644 src/react/atlascode/config/auth/dialog/CustomSiteAuthForm.tsx create mode 100644 src/react/atlascode/config/auth/dialog/JiraApiTokenAuthForm.tsx create mode 100644 src/react/atlascode/config/auth/dialog/TabPanel.tsx create mode 100644 src/react/atlascode/config/auth/dialog/types.ts diff --git a/src/react/atlascode/config/ConfigPage.tsx b/src/react/atlascode/config/ConfigPage.tsx index cc3c5a64..65cfc551 100644 --- a/src/react/atlascode/config/ConfigPage.tsx +++ b/src/react/atlascode/config/ConfigPage.tsx @@ -18,7 +18,7 @@ import { ConfigControllerContext, useConfigController } from './configController import { ConfigSection, ConfigSubSection, ConfigTarget } from '../../../lib/ipc/models/config'; import React, { useCallback, useEffect, useState } from 'react'; -import { AuthDialog } from './auth/AuthDialog'; +import { AuthDialog } from './auth/dialog/AuthDialog'; import { BitbucketPanel } from './bitbucket/BitbucketPanel'; import { ErrorDisplay } from '../common/ErrorDisplay'; import { ExplorePanel } from './explore/ExplorePanel'; diff --git a/src/react/atlascode/config/auth/AuthDialog.tsx b/src/react/atlascode/config/auth/AuthDialog.tsx deleted file mode 100644 index d562a89c..00000000 --- a/src/react/atlascode/config/auth/AuthDialog.tsx +++ /dev/null @@ -1,510 +0,0 @@ -import { ToggleWithLabel } from '@atlassianlabs/guipi-core-components'; -import { - Box, - Button, - Dialog, - DialogActions, - DialogContent, - DialogContentText, - DialogTitle, - Grid, - IconButton, - Radio, - RadioGroup, - Switch, - Tab, - Tabs, - TextField, - Typography, -} from '@material-ui/core'; -import Visibility from '@material-ui/icons/Visibility'; -import VisibilityOff from '@material-ui/icons/VisibilityOff'; -import React, { memo, useCallback, useState } from 'react'; -import { - AuthInfo, - AuthInfoState, - BasicAuthInfo, - emptyAuthInfo, - emptyUserInfo, - PATAuthInfo, - Product, - ProductJira, - SiteInfo, -} from '../../../../atlclients/authInfo'; -import { emptySiteWithAuthInfo, SiteWithAuthInfo } from '../../../../lib/ipc/toUI/config'; -import { useFormValidation } from '../../common/form/useFormValidation'; -import { validateRequiredString, validateStartsWithProtocol } from '../../util/fieldValidators'; -import { ATLASCODE_TEST_HOST } from 'src/constants'; - -export type AuthDialogProps = { - open: boolean; - doClose: () => void; - onExited: () => void; - save: (site: SiteInfo, auth: AuthInfo) => void; - product: Product; - authEntry?: SiteWithAuthInfo; -}; - -type FormFields = { - baseUrl: string; - contextPathEnabled: boolean; - customSSLType: string; - contextPath: string; - username: string; - password: string; - personalAccessToken: string; - customSSLEnabled: boolean; - sslCertPaths: string; - pfxPath: string; - pfxPassphrase: string; -}; - -interface AuthFormState { - showPassword: boolean; - showPFXPassphrase: boolean; -} - -const emptyAuthFormState: AuthFormState = { - showPassword: false, - showPFXPassphrase: false, -}; - -const normalizeContextPath = (cPath: string): string | undefined => { - if (!cPath || cPath.trim() === '' || cPath.trim() === '/') { - return undefined; - } - - return ('/' + cPath) // Make sure there's at least one leading slash - .replace(/\/+/g, '/') // Make sure there are no duplicated slashes anywhere - .replace(/\/+$/g, ''); // Make sure there's no trailing slash -}; - -const isCustomUrl = (data?: string) => { - if (!data) { - return false; - } - - try { - const url = new URL(data); - - // To allow for testing flow of AXON-32 - if (url.hostname.endsWith(ATLASCODE_TEST_HOST)) { - return true; - } - - return ( - !url.hostname.endsWith('atlassian.net') && - !url.hostname.endsWith('jira.com') && - !url.hostname.endsWith('jira-dev.com') && - !url.hostname.endsWith('bitbucket.org') && - !url.hostname.endsWith('bb-inf.net') - ); - } catch (e) { - return false; - } -}; - -interface TabPanelProps { - children?: React.ReactNode; - dir?: string; - index: any; - value: any; -} - -function TabPanel(props: TabPanelProps) { - const { children, value, index, ...other } = props; - - return ( - - ); -} - -export const AuthDialog: React.FunctionComponent = memo( - ({ open, doClose, onExited, save, product, authEntry }) => { - const [authFormState, updateState] = useState(emptyAuthFormState); - const [authTypeTabIndex, setAuthTypeTabIndex] = useState(0); - - const defaultSiteWithAuth = authEntry ? authEntry : emptySiteWithAuthInfo; - - const defaultSSLType = - defaultSiteWithAuth.site.pfxPath !== undefined && defaultSiteWithAuth.site.pfxPath !== '' - ? 'customClientSSL' - : 'customServerSSL'; - const defaultContextPathEnabled = - defaultSiteWithAuth.site.contextPath !== undefined && defaultSiteWithAuth.site.contextPath !== ''; - - const defaultSSLEnabled = - defaultSiteWithAuth.site.customSSLCertPaths !== undefined && - defaultSiteWithAuth.site.customSSLCertPaths !== ''; - - const { register, watches, handleSubmit, errors, isValid } = useFormValidation({ - baseUrl: defaultSiteWithAuth.site.baseLinkUrl, - contextPathEnabled: defaultContextPathEnabled, - customSSLEnabled: defaultSSLEnabled, - customSSLType: defaultSSLType, - }); - - const helperText = - product.key === ProductJira.key - ? 'You can enter a cloud or server url like https://jiracloud.atlassian.net or https://jira.mydomain.com' - : 'You can enter a cloud or server url like https://bitbucket.org or https://bitbucket.mydomain.com'; - - const handleSave = useCallback( - (data: any) => { - const customSSLCerts = - data.customSSLEnabled && data.customSSLType === 'customServerSSL' ? data.sslCertPaths : undefined; - const pfxCert = - data.customSSLEnabled && data.customSSLType === 'customClientSSL' ? data.pfxPath : undefined; - const pfxPassphrase = - data.customSSLEnabled && data.customSSLType === 'customClientSSL' ? data.pfxPassphrase : undefined; - const contextPath = data.contextPathEnabled ? normalizeContextPath(data.contextPath) : undefined; - - const url = new URL(data.baseUrl); - - const siteInfo: SiteInfo = { - host: url.host, - protocol: url.protocol, - product: product, - customSSLCertPaths: customSSLCerts, - pfxPath: pfxCert, - pfxPassphrase: pfxPassphrase, - contextPath: contextPath, - }; - - if (!isCustomUrl(data.baseUrl)) { - save(siteInfo, emptyAuthInfo); - } else if (data.personalAccessToken) { - const authInfo: PATAuthInfo = { - token: data.personalAccessToken, - user: emptyUserInfo, - state: AuthInfoState.Valid, - }; - save(siteInfo, authInfo); - } else { - const authInfo: BasicAuthInfo = { - username: data.username, - password: data.password, - user: emptyUserInfo, - state: AuthInfoState.Valid, - }; - save(siteInfo, authInfo); - } - - updateState(emptyAuthFormState); - setAuthTypeTabIndex(0); - doClose(); - }, - [doClose, product, save], - ); - - const preventClickDefault = useCallback( - (event: React.MouseEvent) => event.preventDefault(), - [], - ); - - const registerUrl = useCallback(register(validateStartsWithProtocol), []); // eslint-disable-line react-hooks/exhaustive-deps - const registerRequiredString = useCallback(register(validateRequiredString), []); // eslint-disable-line react-hooks/exhaustive-deps - return ( - - - Authenticate - - - {`Add ${product.name} Site`} - - - - - {!errors.baseUrl && isCustomUrl(watches.baseUrl) && ( - - - - } - spacing={1} - variant="body1" - label="Use context path" - /> - - {watches.contextPathEnabled && ( - - - - - - )} - , value: any) => { - setAuthTypeTabIndex(value); - }} - > - - - - - - - - - - updateState({ - ...authFormState, - showPassword: !authFormState.showPassword, - }) - } - onMouseDown={preventClickDefault} - > - {authFormState.showPassword ? ( - - ) : ( - - )} - - ), - }} - /> - - - - - - - - - - } - spacing={1} - variant="body1" - label="Use Custom SSL Settings" - /> - - - {watches.customSSLEnabled && ( - - - - - } - spacing={1} - label="Use custom CA certificate(s) (e.g. a self-signed cert)" - variant="body1" - /> - - } - spacing={1} - label="Use custom client-side certificates (CA certificates bundled in PKCS#12 (pfx)" - variant="body1" - /> - - - - )} - - {watches.customSSLEnabled && watches.customSSLType === 'customServerSSL' && ( - - - - - - )} - - {watches.customSSLEnabled && watches.customSSLType === 'customClientSSL' && ( - - - - - - - updateState({ - ...authFormState, - showPFXPassphrase: !authFormState.showPFXPassphrase, - }) - } - onMouseDown={preventClickDefault} - > - {authFormState.showPFXPassphrase ? ( - - ) : ( - - )} - - ), - }} - /> - - - )} - - )} - - - - - - - - - ); - }, -); diff --git a/src/react/atlascode/config/auth/SiteAuthenticator.tsx b/src/react/atlascode/config/auth/SiteAuthenticator.tsx index bf47ab7a..2bf241d5 100644 --- a/src/react/atlascode/config/auth/SiteAuthenticator.tsx +++ b/src/react/atlascode/config/auth/SiteAuthenticator.tsx @@ -4,7 +4,7 @@ import React, { memo, useCallback, useContext } from 'react'; import { AuthDialogControllerContext } from './useAuthDialog'; import { CloudAuthButton } from './CloudAuthButton'; import DomainIcon from '@material-ui/icons/Domain'; -import { Product } from '../../../../atlclients/authInfo'; +import { Product, ProductJira } from '../../../../atlclients/authInfo'; import { SiteList } from './SiteList'; import { SiteWithAuthInfo } from '../../../../lib/ipc/toUI/config'; import { Features } from 'src/util/featureFlags'; @@ -47,46 +47,113 @@ export const SiteAuthenticator: React.FunctionComponent return ( - - - - - - - - - - - - - - - - - - + {useNewAuth && product.key === ProductJira.key ? ( + + ) : ( + + )} ); }, ); + +interface AuthContainerProps { + isRemote: boolean; + product: Product; + openProductAuth: () => void; + sites: SiteWithAuthInfo[]; + handleEdit: (swa: SiteWithAuthInfo) => void; +} + +const LegacyAuthContainer = ({ isRemote, product, openProductAuth, sites, handleEdit }: AuthContainerProps) => ( + + + + + + + + + + + + + + + + + + + + +); + +const AuthContainer = ({ isRemote, product, openProductAuth, sites, handleEdit }: AuthContainerProps) => ( + + + + + + {!isRemote && ( + + + + + + + + + )} + {isRemote && ( + + + + + + )} + + + + + + + + +); diff --git a/src/react/atlascode/config/auth/dialog/AuthDialog.tsx b/src/react/atlascode/config/auth/dialog/AuthDialog.tsx new file mode 100644 index 00000000..61030a9f --- /dev/null +++ b/src/react/atlascode/config/auth/dialog/AuthDialog.tsx @@ -0,0 +1,253 @@ +import { + Box, + Button, + Dialog, + DialogActions, + DialogContent, + DialogContentText, + DialogTitle, + Grid, + TextField, + Typography, +} from '@material-ui/core'; +import React, { memo, useCallback, useState } from 'react'; +import { + AuthInfo, + AuthInfoState, + BasicAuthInfo, + emptyAuthInfo, + emptyUserInfo, + PATAuthInfo, + Product, + ProductJira, + SiteInfo, +} from '../../../../../atlclients/authInfo'; +import { emptySiteWithAuthInfo, SiteWithAuthInfo } from '../../../../../lib/ipc/toUI/config'; +import { useFormValidation } from '../../../common/form/useFormValidation'; +import { validateRequiredString, validateStartsWithProtocol } from '../../../util/fieldValidators'; +import { emptyAuthFormState, FormFields } from './types'; +import { JiraBasicAuthForm } from './JiraApiTokenAuthForm'; +import { CustomSiteAuthForm } from './CustomSiteAuthForm'; + +export type AuthDialogProps = { + open: boolean; + doClose: () => void; + onExited: () => void; + save: (site: SiteInfo, auth: AuthInfo) => void; + product: Product; + authEntry?: SiteWithAuthInfo; +}; + +export const AuthDialog: React.FunctionComponent = memo( + ({ open, doClose, onExited, save, product, authEntry }) => { + const [authFormState, updateState] = useState(emptyAuthFormState); + + const defaultSiteWithAuth = authEntry ? authEntry : emptySiteWithAuthInfo; + + const defaultSSLType = + defaultSiteWithAuth.site.pfxPath !== undefined && defaultSiteWithAuth.site.pfxPath !== '' + ? 'customClientSSL' + : 'customServerSSL'; + const defaultContextPathEnabled = + defaultSiteWithAuth.site.contextPath !== undefined && defaultSiteWithAuth.site.contextPath !== ''; + + const defaultSSLEnabled = + defaultSiteWithAuth.site.customSSLCertPaths !== undefined && + defaultSiteWithAuth.site.customSSLCertPaths !== ''; + + const { register, watches, handleSubmit, errors, isValid } = useFormValidation({ + baseUrl: defaultSiteWithAuth.site.baseLinkUrl, + contextPathEnabled: defaultContextPathEnabled, + customSSLEnabled: defaultSSLEnabled, + customSSLType: defaultSSLType, + }); + + const helperText = + product.key === ProductJira.key + ? 'You can enter a cloud or server url like https://jiracloud.atlassian.net or https://jira.mydomain.com' + : 'You can enter a cloud or server url like https://bitbucket.org or https://bitbucket.mydomain.com'; + + const authFormType = selectAuthFormType(product, watches, errors); + + const handleSave = useCallback( + (data: any) => { + const customSSLCerts = + data.customSSLEnabled && data.customSSLType === 'customServerSSL' ? data.sslCertPaths : undefined; + const pfxCert = + data.customSSLEnabled && data.customSSLType === 'customClientSSL' ? data.pfxPath : undefined; + const pfxPassphrase = + data.customSSLEnabled && data.customSSLType === 'customClientSSL' ? data.pfxPassphrase : undefined; + const contextPath = data.contextPathEnabled ? normalizeContextPath(data.contextPath) : undefined; + + const url = new URL(data.baseUrl); + + const siteInfo: SiteInfo = { + host: url.host, + protocol: url.protocol, + product: product, + customSSLCertPaths: customSSLCerts, + pfxPath: pfxCert, + pfxPassphrase: pfxPassphrase, + contextPath: contextPath, + }; + + switch (authFormType) { + case AuthFormType.JiraCloud: + const authInfo: BasicAuthInfo = { + username: data.username, + password: data.password, + user: emptyUserInfo, + state: AuthInfoState.Valid, + }; + save(siteInfo, authInfo); + break; + case AuthFormType.CustomSite: + if (data.personalAccessToken) { + const authInfo: PATAuthInfo = { + token: data.personalAccessToken, + user: emptyUserInfo, + state: AuthInfoState.Valid, + }; + save(siteInfo, authInfo); + } else { + const authInfo: BasicAuthInfo = { + username: data.username, + password: data.password, + user: emptyUserInfo, + state: AuthInfoState.Valid, + }; + save(siteInfo, authInfo); + } + break; + default: + if (data.baseUrl && !isCustomUrl(data.baseUrl)) { + save(siteInfo, emptyAuthInfo); + } + break; + } + + updateState(emptyAuthFormState); + doClose(); + }, + [doClose, product, save, authFormType], + ); + + const preventClickDefault = useCallback( + (event: React.MouseEvent) => event.preventDefault(), + [], + ); + + const registerUrl = useCallback(register(validateStartsWithProtocol), []); // eslint-disable-line react-hooks/exhaustive-deps + const registerRequiredString = useCallback(register(validateRequiredString), []); // eslint-disable-line react-hooks/exhaustive-deps + + return ( + + + Authenticate + + + {`Add ${product.name} Site`} + + + + + + {authFormType === AuthFormType.JiraCloud && ( + // For Jira Cloud, show the API token form as the only option + + )} + + {authFormType === AuthFormType.CustomSite && ( + // For custom sites, show the tabbed view with BasicAuth, PAT, and all the options + + )} + + + + + + + + + ); + }, +); + +enum AuthFormType { + JiraCloud = 'jiraCloud', + CustomSite = 'customSite', + None = 'none', +} + +function selectAuthFormType(product: Product, watches: any, errors: any): AuthFormType { + if (!watches.baseUrl || errors.baseUrl) { + return AuthFormType.None; + } + + if (product.key === ProductJira.key && !isCustomUrl(watches.baseUrl)) { + return AuthFormType.JiraCloud; + } + + if (watches.baseUrl && !errors.baseUrl && isCustomUrl(watches.baseUrl)) { + return AuthFormType.CustomSite; + } + + return AuthFormType.None; +} + +const cloudHostnames = ['atlassian.net', 'jira.com', 'jira-dev.com', 'bitbucket.org', 'bb-inf.net']; + +function isCustomUrl(url: string): boolean { + try { + const urlObj = new URL(url); + return cloudHostnames.every((host) => !urlObj.hostname.endsWith(host)); + } catch (e) { + return false; + } +} + +export const normalizeContextPath = (cPath: string): string | undefined => { + if (!cPath || cPath.trim() === '' || cPath.trim() === '/') { + return undefined; + } + + return ('/' + cPath) // Make sure there's at least one leading slash + .replace(/\/+/g, '/') // Make sure there are no duplicated slashes anywhere + .replace(/\/+$/g, ''); // Make sure there's no trailing slash +}; diff --git a/src/react/atlascode/config/auth/dialog/CustomSiteAuthForm.tsx b/src/react/atlascode/config/auth/dialog/CustomSiteAuthForm.tsx new file mode 100644 index 00000000..d53031b2 --- /dev/null +++ b/src/react/atlascode/config/auth/dialog/CustomSiteAuthForm.tsx @@ -0,0 +1,278 @@ +import { ToggleWithLabel } from '@atlassianlabs/guipi-core-components'; +import { Box, Grid, IconButton, Radio, RadioGroup, Switch, Tab, Tabs, TextField } from '@material-ui/core'; +import Visibility from '@material-ui/icons/Visibility'; +import VisibilityOff from '@material-ui/icons/VisibilityOff'; +import { SiteWithAuthInfo } from 'src/lib/ipc/toUI/config'; +import React, { useState } from 'react'; +import { TabPanel } from './TabPanel'; +import { BasicAuthInfo } from 'src/atlclients/authInfo'; + +export type CustomSiteAuthFormProps = { + defaultSiteWithAuth: SiteWithAuthInfo; + defaultContextPathEnabled: boolean; + defaultSSLEnabled: boolean; + watches: any; + register: any; + errors: any; + registerRequiredString: any; + authFormState: any; + updateState: any; + preventClickDefault: any; + defaultSSLType: string; +}; + +export const CustomSiteAuthForm = ({ + defaultSiteWithAuth, + defaultContextPathEnabled, + defaultSSLEnabled, + watches, + register, + errors, + registerRequiredString, + authFormState, + updateState, + preventClickDefault, + defaultSSLType, +}: CustomSiteAuthFormProps) => { + const [authTypeTabIndex, setAuthTypeTabIndex] = useState(0); + + return ( + + + + } + spacing={1} + variant="body1" + label="Use context path" + /> + + {watches.contextPathEnabled && ( + + + + + + )} + , value: any) => { + setAuthTypeTabIndex(value); + }} + > + + + + + + + + + + updateState({ + ...authFormState, + showPassword: !authFormState.showPassword, + }) + } + onMouseDown={preventClickDefault} + > + {authFormState.showPassword ? ( + + ) : ( + + )} + + ), + }} + /> + + + + + + + + + + } + spacing={1} + variant="body1" + label="Use Custom SSL Settings" + /> + + + {watches.customSSLEnabled && ( + + + + + } + spacing={1} + label="Use custom CA certificate(s) (e.g. a self-signed cert)" + variant="body1" + /> + + } + spacing={1} + label="Use custom client-side certificates (CA certificates bundled in PKCS#12 (pfx)" + variant="body1" + /> + + + + )} + + {watches.customSSLEnabled && watches.customSSLType === 'customServerSSL' && ( + + + + + + )} + + {watches.customSSLEnabled && watches.customSSLType === 'customClientSSL' && ( + + + + + + + updateState({ + ...authFormState, + showPFXPassphrase: !authFormState.showPFXPassphrase, + }) + } + onMouseDown={preventClickDefault} + > + {authFormState.showPFXPassphrase ? ( + + ) : ( + + )} + + ), + }} + /> + + + )} + + ); +}; diff --git a/src/react/atlascode/config/auth/dialog/JiraApiTokenAuthForm.tsx b/src/react/atlascode/config/auth/dialog/JiraApiTokenAuthForm.tsx new file mode 100644 index 00000000..6aaefdf7 --- /dev/null +++ b/src/react/atlascode/config/auth/dialog/JiraApiTokenAuthForm.tsx @@ -0,0 +1,92 @@ +import { SiteWithAuthInfo } from 'src/lib/ipc/toUI/config'; +import { AuthFormState } from './types'; +import React from 'react'; +import { Box, Grid, IconButton, Link, TextField, Typography } from '@material-ui/core'; +import { BasicAuthInfo } from 'src/atlclients/authInfo'; +import Visibility from '@material-ui/icons/Visibility'; +import VisibilityOff from '@material-ui/icons/VisibilityOff'; + +type JiraBasicAuthFormProps = { + defaultSiteWithAuth: SiteWithAuthInfo; + errors: any; + registerRequiredString: any; + authFormState: AuthFormState; + updateState: (state: AuthFormState) => void; + preventClickDefault: (event: React.MouseEvent) => void; +}; + +export const JiraBasicAuthForm = ({ + defaultSiteWithAuth, + errors, + registerRequiredString, + authFormState, + updateState, + preventClickDefault, +}: JiraBasicAuthFormProps) => { + return ( + + + + This looks like a Jira Cloud site ☁ + + You can use an{' '} + API Token to + connect to this site. Read more about Atlassian API tokens{' '} + + here + + . + + + + + + + + + updateState({ + ...authFormState, + showPassword: !authFormState.showPassword, + }) + } + onMouseDown={preventClickDefault} + > + {authFormState.showPassword ? ( + + ) : ( + + )} + + ), + }} + /> + + + ); +}; diff --git a/src/react/atlascode/config/auth/dialog/TabPanel.tsx b/src/react/atlascode/config/auth/dialog/TabPanel.tsx new file mode 100644 index 00000000..f203bcf5 --- /dev/null +++ b/src/react/atlascode/config/auth/dialog/TabPanel.tsx @@ -0,0 +1,25 @@ +import { Box } from '@material-ui/core'; +import React from 'react'; + +export type TabPanelProps = { + children?: React.ReactNode; + dir?: string; + index: any; + value: any; +}; + +export function TabPanel(props: TabPanelProps) { + const { children, value, index, ...other } = props; + + return ( + + ); +} diff --git a/src/react/atlascode/config/auth/dialog/types.ts b/src/react/atlascode/config/auth/dialog/types.ts new file mode 100644 index 00000000..2737c3fd --- /dev/null +++ b/src/react/atlascode/config/auth/dialog/types.ts @@ -0,0 +1,23 @@ +export type FormFields = { + baseUrl: string; + contextPathEnabled: boolean; + customSSLType: string; + contextPath: string; + username: string; + password: string; + personalAccessToken: string; + customSSLEnabled: boolean; + sslCertPaths: string; + pfxPath: string; + pfxPassphrase: string; +}; + +export interface AuthFormState { + showPassword: boolean; + showPFXPassphrase: boolean; +} + +export const emptyAuthFormState: AuthFormState = { + showPassword: false, + showPFXPassphrase: false, +}; diff --git a/src/react/atlascode/onboarding/OnboardingPage.tsx b/src/react/atlascode/onboarding/OnboardingPage.tsx index dd59095e..2bbedd36 100644 --- a/src/react/atlascode/onboarding/OnboardingPage.tsx +++ b/src/react/atlascode/onboarding/OnboardingPage.tsx @@ -1,7 +1,7 @@ import { Button, Container, lighten, makeStyles, Step, StepLabel, Stepper, Theme, Typography } from '@material-ui/core'; import React, { useCallback, useEffect, useState } from 'react'; import { AuthInfo, SiteInfo } from '../../../atlclients/authInfo'; -import { AuthDialog } from '../config/auth/AuthDialog'; +import { AuthDialog } from '../config/auth/dialog/AuthDialog'; import { AuthDialogControllerContext, useAuthDialog } from '../config/auth/useAuthDialog'; import LandingPage from './LandingPage'; import { OnboardingControllerContext, useOnboardingController } from './onboardingController';