diff options
author | Revanshu Paliwal <revanshu.paliwal@sonarsource.com> | 2023-08-11 16:16:42 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2023-08-14 20:02:58 +0000 |
commit | 813bc9b7dc048471e7462e5698654039d260a10e (patch) | |
tree | c0061816be9394a85dd75e5265be130b9047efb0 /server | |
parent | 645ea0a8706c5af91fac25e343410c330345b558 (diff) | |
download | sonarqube-813bc9b7dc048471e7462e5698654039d260a10e.tar.gz sonarqube-813bc9b7dc048471e7462e5698654039d260a10e.zip |
SONAR-20086 Updating Azure PAT form to use custom hook
Diffstat (limited to 'server')
3 files changed, 85 insertions, 133 deletions
diff --git a/server/sonar-web/src/main/js/apps/create/project/Azure/AzurePersonalAccessTokenForm.tsx b/server/sonar-web/src/main/js/apps/create/project/Azure/AzurePersonalAccessTokenForm.tsx index 3f71739e892..55a12b730d4 100644 --- a/server/sonar-web/src/main/js/apps/create/project/Azure/AzurePersonalAccessTokenForm.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/Azure/AzurePersonalAccessTokenForm.tsx @@ -31,51 +31,52 @@ import * as React from 'react'; import { FormattedMessage } from 'react-intl'; import { translate } from '../../../../helpers/l10n'; import { AlmSettingsInstance } from '../../../../types/alm-settings'; +import { usePersonalAccessToken } from '../usePersonalAccessToken'; export interface AzurePersonalAccessTokenFormProps { almSetting: AlmSettingsInstance; - onPersonalAccessTokenCreate: (token: string) => void; - submitting?: boolean; - validationFailed: boolean; - firstConnection?: boolean; + onPersonalAccessTokenCreate: () => void; + resetPat: boolean; } function getAzurePatUrl(url: string) { return `${url.replace(/\/$/, '')}/_usersSettings/tokens`; } -export default function AzurePersonalAccessTokenForm(props: AzurePersonalAccessTokenFormProps) { +export default function AzurePersonalAccessTokenForm({ + almSetting, + resetPat, + onPersonalAccessTokenCreate, +}: AzurePersonalAccessTokenFormProps) { const { - almSetting: { url }, - submitting = false, - validationFailed, + password, firstConnection, - } = props; - - const [touched, setTouched] = React.useState(false); - React.useEffect(() => { - setTouched(false); - }, [submitting]); + validationFailed, + touched, + submitting, + validationErrorMessage, + checkingPat, + handlePasswordChange, + handleSubmit, + } = usePersonalAccessToken(almSetting, resetPat, onPersonalAccessTokenCreate); - const [token, setToken] = React.useState(''); + if (checkingPat) { + return <DeferredSpinner className="sw-ml-2" loading />; + } - const isInvalid = (validationFailed && !touched) || (touched && !token); + const isInvalid = (validationFailed && !touched) || (touched && !password); + const { url } = almSetting; let errorMessage; - if (!token) { + if (!password) { errorMessage = translate('onboarding.create_project.pat_form.pat_required'); } else if (isInvalid) { - errorMessage = translate('onboarding.create_project.pat_incorrect.azure'); + errorMessage = + validationErrorMessage ?? translate('onboarding.create_project.pat_incorrect.azure'); } return ( - <form - className="sw-mt-3 sw-w-[50%]" - onSubmit={(e: React.SyntheticEvent<HTMLFormElement>) => { - e.preventDefault(); - props.onPersonalAccessTokenCreate(token); - }} - > + <form className="sw-mt-3 sw-w-[50%]" onSubmit={handleSubmit}> <LightPrimary as="h2" className="sw-heading-md"> {translate('onboarding.create_project.pat_form.title')} </LightPrimary> @@ -112,12 +113,9 @@ export default function AzurePersonalAccessTokenForm(props: AzurePersonalAccessT id="personal_access_token" minLength={1} name="personal_access_token" - onChange={(e: React.ChangeEvent<HTMLInputElement>) => { - setToken(e.target.value); - setTouched(true); - }} + onChange={handlePasswordChange} type="text" - value={token} + value={password} size="large" isInvalid={isInvalid} /> diff --git a/server/sonar-web/src/main/js/apps/create/project/Azure/AzureProjectCreate.tsx b/server/sonar-web/src/main/js/apps/create/project/Azure/AzureProjectCreate.tsx index 3dfad9a6ed9..1ed1577464c 100644 --- a/server/sonar-web/src/main/js/apps/create/project/Azure/AzureProjectCreate.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/Azure/AzureProjectCreate.tsx @@ -19,11 +19,9 @@ */ import * as React from 'react'; import { - checkPersonalAccessTokenIsValid, getAzureProjects, getAzureRepositories, searchAzureRepositories, - setAlmPersonalAccessToken, setupAzureProjectCreation, } from '../../../../api/alm-integrations'; import { Location, Router } from '../../../../components/hoc/withRouter'; @@ -31,7 +29,6 @@ import { AzureProject, AzureRepository } from '../../../../types/alm-integration import { AlmSettingsInstance } from '../../../../types/alm-settings'; import { Dict } from '../../../../types/types'; import { CreateProjectApiCallback } from '../types'; -import { tokenExistedBefore } from '../utils'; import AzureCreateProjectRenderer from './AzureProjectCreateRenderer'; interface Props { @@ -46,16 +43,13 @@ interface Props { interface State { loading: boolean; loadingRepositories: Dict<boolean>; - patIsValid?: boolean; projects?: AzureProject[]; repositories: Dict<AzureRepository[]>; searching?: boolean; searchResults?: AzureRepository[]; searchQuery?: string; selectedAlmInstance?: AlmSettingsInstance; - submittingToken?: boolean; - tokenValidationFailed: boolean; - firstConnection?: boolean; + showPersonalAccessTokenForm: boolean; } export default class AzureProjectCreate extends React.PureComponent<Props, State> { @@ -66,10 +60,9 @@ export default class AzureProjectCreate extends React.PureComponent<Props, State this.state = { selectedAlmInstance: props.almInstances[0], loading: false, + showPersonalAccessTokenForm: true, loadingRepositories: {}, repositories: {}, - tokenValidationFailed: false, - firstConnection: false, }; } @@ -93,45 +86,48 @@ export default class AzureProjectCreate extends React.PureComponent<Props, State } fetchData = async () => { - this.setState({ loading: true }); - - const { patIsValid, error } = await this.checkPersonalAccessToken(); - - let projects: AzureProject[] | undefined; - if (patIsValid) { - projects = await this.fetchAzureProjects(); - } - - const { repositories } = this.state; + const { showPersonalAccessTokenForm } = this.state; + + if (!showPersonalAccessTokenForm) { + this.setState({ loading: true }); + let projects: AzureProject[] | undefined; + try { + projects = await this.fetchAzureProjects(); + } catch (_) { + if (this.mounted) { + this.setState({ showPersonalAccessTokenForm: true, loading: false }); + } + } - let firstProjectName: string; + const { repositories } = this.state; - if (projects && projects.length > 0) { - firstProjectName = projects[0].name; + let firstProjectName: string; - this.setState(({ loadingRepositories }) => ({ - loadingRepositories: { ...loadingRepositories, [firstProjectName]: true }, - })); + if (projects && projects.length > 0) { + firstProjectName = projects[0].name; - const repos = await this.fetchAzureRepositories(firstProjectName); - repositories[firstProjectName] = repos; - } + this.setState(({ loadingRepositories }) => ({ + loadingRepositories: { ...loadingRepositories, [firstProjectName]: true }, + })); - if (this.mounted) { - this.setState(({ loadingRepositories }) => { - if (firstProjectName) { - loadingRepositories[firstProjectName] = false; - } + const repos = await this.fetchAzureRepositories(firstProjectName); + repositories[firstProjectName] = repos; + } - return { - patIsValid, - loading: false, - loadingRepositories: { ...loadingRepositories }, - projects, - repositories, - firstConnection: tokenExistedBefore(error), - }; - }); + if (this.mounted) { + this.setState(({ loadingRepositories }) => { + if (firstProjectName !== '') { + loadingRepositories[firstProjectName] = false; + } + + return { + loading: false, + loadingRepositories: { ...loadingRepositories }, + projects, + repositories, + }; + }); + } } }; @@ -224,53 +220,20 @@ export default class AzureProjectCreate extends React.PureComponent<Props, State } }; - checkPersonalAccessToken = () => { - const { selectedAlmInstance } = this.state; - - if (!selectedAlmInstance) { - return Promise.resolve({ patIsValid: false, error: '' }); - } - - return checkPersonalAccessTokenIsValid(selectedAlmInstance.key).then(({ status, error }) => { - return { patIsValid: status, error }; - }); - }; - - handlePersonalAccessTokenCreate = async (token: string) => { - const { selectedAlmInstance } = this.state; - - if (!selectedAlmInstance || token.length < 1) { - return; - } - - this.setState({ submittingToken: true, tokenValidationFailed: false }); - - try { - await setAlmPersonalAccessToken(selectedAlmInstance.key, token); - const { patIsValid } = await this.checkPersonalAccessToken(); - - if (this.mounted) { - this.setState({ - submittingToken: false, - patIsValid, - tokenValidationFailed: !patIsValid, - }); - - if (patIsValid) { - this.cleanUrl(); - this.fetchData(); - } - } - } catch (e) { - if (this.mounted) { - this.setState({ submittingToken: false }); - } - } + handlePersonalAccessTokenCreate = async () => { + this.setState({ showPersonalAccessTokenForm: false }); + this.cleanUrl(); + await this.fetchData(); }; onSelectedAlmInstanceChange = (instance: AlmSettingsInstance) => { this.setState( - { selectedAlmInstance: instance, searchResults: undefined, searchQuery: '' }, + { + selectedAlmInstance: instance, + searchResults: undefined, + searchQuery: '', + showPersonalAccessTokenForm: true, + }, () => { this.fetchData().catch(() => { /* noop */ @@ -284,16 +247,13 @@ export default class AzureProjectCreate extends React.PureComponent<Props, State const { loading, loadingRepositories, - patIsValid, + showPersonalAccessTokenForm, projects, repositories, searching, searchResults, searchQuery, selectedAlmInstance, - submittingToken, - tokenValidationFailed, - firstConnection, } = this.state; return ( @@ -312,11 +272,11 @@ export default class AzureProjectCreate extends React.PureComponent<Props, State searchQuery={searchQuery} almInstances={almInstances} selectedAlmInstance={selectedAlmInstance} - showPersonalAccessTokenForm={!patIsValid || Boolean(location.query.resetPat)} - submittingToken={submittingToken} - tokenValidationFailed={tokenValidationFailed} + resetPat={Boolean(location.query.resetPat)} + showPersonalAccessTokenForm={ + showPersonalAccessTokenForm || Boolean(location.query.resetPat) + } onSelectedAlmInstanceChange={this.onSelectedAlmInstanceChange} - firstConnection={firstConnection} /> ); } diff --git a/server/sonar-web/src/main/js/apps/create/project/Azure/AzureProjectCreateRenderer.tsx b/server/sonar-web/src/main/js/apps/create/project/Azure/AzureProjectCreateRenderer.tsx index a6e4fb2ef26..94c4ec746cd 100644 --- a/server/sonar-web/src/main/js/apps/create/project/Azure/AzureProjectCreateRenderer.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/Azure/AzureProjectCreateRenderer.tsx @@ -45,7 +45,7 @@ export interface AzureProjectCreateRendererProps { loadingRepositories: Dict<boolean>; onImportRepository: (resository: AzureRepository) => void; onOpenProject: (key: string) => void; - onPersonalAccessTokenCreate: (token: string) => void; + onPersonalAccessTokenCreate: () => void; onSearch: (query: string) => void; projects?: AzureProject[]; repositories: Dict<AzureRepository[]>; @@ -55,10 +55,8 @@ export interface AzureProjectCreateRendererProps { almInstances?: AlmSettingsInstance[]; selectedAlmInstance?: AlmSettingsInstance; showPersonalAccessTokenForm?: boolean; - submittingToken?: boolean; - tokenValidationFailed: boolean; + resetPat: boolean; onSelectedAlmInstanceChange: (instance: AlmSettingsInstance) => void; - firstConnection?: boolean; } export default function AzureProjectCreateRenderer(props: AzureProjectCreateRendererProps) { @@ -73,10 +71,8 @@ export default function AzureProjectCreateRenderer(props: AzureProjectCreateRend searchQuery, almInstances, showPersonalAccessTokenForm, - submittingToken, - tokenValidationFailed, + resetPat, selectedAlmInstance, - firstConnection, } = props; const showCountError = !loading && (!almInstances || almInstances?.length === 0); @@ -131,9 +127,7 @@ export default function AzureProjectCreateRenderer(props: AzureProjectCreateRend <AzurePersonalAccessTokenForm almSetting={selectedAlmInstance} onPersonalAccessTokenCreate={props.onPersonalAccessTokenCreate} - submitting={submittingToken} - validationFailed={tokenValidationFailed} - firstConnection={firstConnection} + resetPat={resetPat} /> </div> ) : ( |