V2Wizard: Create a folder for Azure step and copy needed components

This created a new folder for the Azure step and copies components that will be needed:
- AzureAuthButton.tsx
- AzureResouceGroups.tsx
- AzureSourcesSelect.tsx
This commit is contained in:
mgold1234 2024-02-04 21:22:03 +02:00 committed by Lucas Garfield
parent 47461f9089
commit fa016c3228
3 changed files with 294 additions and 0 deletions

View file

@ -0,0 +1,35 @@
import React from 'react';
import useFormApi from '@data-driven-forms/react-form-renderer/use-form-api';
import { Button, FormGroup } from '@patternfly/react-core';
const AzureAuthButton = () => {
const { getState } = useFormApi();
const tenantId = getState()?.values?.['azure-tenant-id'];
const guidRegex = new RegExp(
'^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$',
'i'
);
return (
<FormGroup>
<Button
component="a"
target="_blank"
variant="secondary"
isDisabled={!guidRegex.test(tenantId)}
href={
'https://login.microsoftonline.com/' +
tenantId +
'/oauth2/v2.0/authorize?client_id=b94bb246-b02c-4985-9c22-d44e66f657f4&scope=openid&' +
'response_type=code&response_mode=query&redirect_uri=https://portal.azure.com'
}
>
Authorize Image Builder
</Button>
</FormGroup>
);
};
export default AzureAuthButton;

View file

@ -0,0 +1,96 @@
import React, { useState } from 'react';
import FormSpy from '@data-driven-forms/react-form-renderer/form-spy';
import useFieldApi from '@data-driven-forms/react-form-renderer/use-field-api';
import useFormApi from '@data-driven-forms/react-form-renderer/use-form-api';
import { FormGroup, Spinner } from '@patternfly/react-core';
import {
Select,
SelectOption,
SelectVariant,
} from '@patternfly/react-core/deprecated';
import PropTypes from 'prop-types';
import { useGetSourceUploadInfoQuery } from '../../../store/provisioningApi';
const AzureResourceGroups = ({ label, isRequired, className, ...props }) => {
const { change, getState } = useFormApi();
const { input } = useFieldApi(props);
const [isOpen, setIsOpen] = useState(false);
const [sourceId, setSourceId] = useState(
getState()?.values?.['azure-sources-select']
);
const onFormChange = ({ values }) => {
setSourceId(values['azure-sources-select']);
};
const { data: sourceDetails, isFetching } = useGetSourceUploadInfoQuery(
{ id: sourceId },
{
skip: !sourceId,
}
);
const resourceGroups =
(sourceId && sourceDetails?.azure?.resource_groups) || [];
const setResourceGroup = (_, selection) => {
setIsOpen(false);
change(input.name, selection);
};
const handleClear = () => {
change(input.name, undefined);
};
return (
<FormGroup
isRequired={isRequired}
label={label}
data-testid="azure-resource-groups"
>
<FormSpy subscription={{ values: true }} onChange={onFormChange} />
<Select
ouiaId="resource_group_select"
variant={SelectVariant.typeahead}
className={className}
onToggle={() => setIsOpen(!isOpen)}
onSelect={setResourceGroup}
onClear={handleClear}
selections={input.value}
isOpen={isOpen}
placeholderText="Select resource group"
typeAheadAriaLabel="Select resource group"
>
{isFetching && (
<SelectOption
isNoResultsOption={true}
data-testid="azure-resource-groups-loading"
>
<Spinner size="lg" />
</SelectOption>
)}
{resourceGroups.map((name, index) => (
<SelectOption
key={index}
value={name}
aria-label={`Resource group ${name}`}
/>
))}
</Select>
</FormGroup>
);
};
AzureResourceGroups.propTypes = {
label: PropTypes.node,
isRequired: PropTypes.bool,
className: PropTypes.string,
};
AzureResourceGroups.defaultProps = {
label: '',
isRequired: false,
className: '',
};
export default AzureResourceGroups;

View file

@ -0,0 +1,163 @@
import React, { useState, useEffect } from 'react';
import FormSpy from '@data-driven-forms/react-form-renderer/form-spy';
import useFieldApi from '@data-driven-forms/react-form-renderer/use-field-api';
import useFormApi from '@data-driven-forms/react-form-renderer/use-form-api';
import { Alert } from '@patternfly/react-core';
import { FormGroup, Spinner } from '@patternfly/react-core';
import {
Select,
SelectOption,
SelectVariant,
} from '@patternfly/react-core/deprecated';
import PropTypes from 'prop-types';
import { extractProvisioningList } from '../../../store/helpers';
import {
useGetSourceListQuery,
useGetSourceUploadInfoQuery,
} from '../../../store/provisioningApi';
const AzureSourcesSelect = ({ label, isRequired, className, ...props }) => {
const { change } = useFormApi();
const { input } = useFieldApi(props);
const [isOpen, setIsOpen] = useState(false);
const selectedSourceId = input.value;
const {
data: rawSources,
isFetching,
isSuccess,
isError,
refetch,
} = useGetSourceListQuery({ provider: 'azure' });
const sources = extractProvisioningList(rawSources);
const {
data: sourceDetails,
isFetching: isFetchingDetails,
isSuccess: isSuccessDetails,
isError: isErrorDetails,
} = useGetSourceUploadInfoQuery(
{ id: selectedSourceId },
{
skip: !selectedSourceId,
}
);
useEffect(() => {
if (isFetchingDetails || !isSuccessDetails) return;
change('azure-tenant-id', sourceDetails?.azure?.tenant_id);
change('azure-subscription-id', sourceDetails?.azure?.subscription_id);
}, [
isFetchingDetails,
isSuccessDetails,
sourceDetails?.azure?.subscription_id,
sourceDetails?.azure?.tenant_id,
change,
]);
const onFormChange = ({ values }) => {
if (
values['azure-type'] !== 'azure-type-source' ||
values[input.name] === undefined
) {
change(input.name, undefined);
change('azure-tenant-id', undefined);
change('azure-subscription-id', undefined);
}
};
const handleSelect = (_, sourceName) => {
const sourceId = sources.find((source) => source.name === sourceName).id;
change(input.name, sourceId);
setIsOpen(false);
};
const handleClear = () => {
change(input.name, undefined);
};
const handleToggle = () => {
// Refetch upon opening (but not upon closing)
if (!isOpen) {
refetch();
}
setIsOpen(!isOpen);
};
return (
<>
<FormSpy subscription={{ values: true }} onChange={onFormChange} />
<FormGroup
isRequired={isRequired}
label={label}
data-testid="azure-sources"
>
<Select
ouiaId="source_select"
variant={SelectVariant.typeahead}
className={className}
onToggle={handleToggle}
onSelect={handleSelect}
onClear={handleClear}
selections={
selectedSourceId
? sources.find((source) => source.id === selectedSourceId)?.name
: undefined
}
isOpen={isOpen}
placeholderText="Select source"
typeAheadAriaLabel="Select source"
menuAppendTo="parent"
maxHeight="25rem"
isDisabled={!isSuccess}
>
{isSuccess &&
sources.map((source) => (
<SelectOption key={source.id} value={source.name} />
))}
{isFetching && (
<SelectOption isNoResultsOption={true}>
<Spinner size="lg" />
</SelectOption>
)}
</Select>
</FormGroup>
<>
{isError && (
<Alert
variant={'danger'}
isPlain
isInline
title={'Sources unavailable'}
>
Sources cannot be reached, try again later or enter an account info
for upload manually.
</Alert>
)}
{!isError && isErrorDetails && (
<Alert
variant={'danger'}
isPlain
isInline
title={'Azure details unavailable'}
>
Could not fetch Tenant id and Subscription id from Azure for given
Source. Check Sources page for the source availability or select a
different Source.
</Alert>
)}
</>
</>
);
};
AzureSourcesSelect.propTypes = {
className: PropTypes.string,
label: PropTypes.node,
isRequired: PropTypes.bool,
};
export default AzureSourcesSelect;