Skip to content

Commit

Permalink
feat(HMS-1772): Allow selecting custom resource group
Browse files Browse the repository at this point in the history
  • Loading branch information
ezr-ondrej committed Oct 17, 2023
1 parent 02eb147 commit 3e73a67
Show file tree
Hide file tree
Showing 10 changed files with 218 additions and 3 deletions.
7 changes: 7 additions & 0 deletions src/API/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,10 @@ export const fetchLaunchTemplates = async (sourceID, region) => {
} = await axios.get(provisioningUrl(`sources/${sourceID}/launch_templates?region=${region}`));
return data;
};

export const fetchResourceGroups = async (sourceID) => {
const {
data: { azure },
} = await axios.get(provisioningUrl(`sources/${sourceID}/upload_info`));
return azure?.resource_groups;
};
1 change: 1 addition & 0 deletions src/API/queryKeys.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export const PUBKEYS_QUERY_KEY = ['pubkeys'];
export const instanceTypesQueryKeys = (region) => ['instanceTypes', region];
export const IMAGE_REGIONS_KEY = 'image_region';
export const TEMPLATES_KEY = 'templates';
export const AZURE_RG_KEY = 'azure_resource_group';
39 changes: 39 additions & 0 deletions src/Components/AzureResourceGroup/AzureResourceGroup.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react';
import userEvent from '@testing-library/user-event';
import { render, screen } from '../../mocks/utils';
import { provisioningUrl } from '../../API/helpers';
import { azureSourceUploadInfo } from '../../mocks/fixtures/sources.fixtures';
import AzureResourceGroup from '.';

describe('AzureResourceGroup', () => {
test('populate resource group select', async () => {
await mountSelectAndOpen();
const items = await screen.findAllByLabelText(/^Resource group/);
expect(items).toHaveLength(azureSourceUploadInfo.azure.resource_groups.length);
});

test('handles error', async () => {
const { server, rest } = window.msw;

server.use(
rest.get(provisioningUrl('sources/:sourceID/upload_info'), (req, res, ctx) => {
return res(ctx.status(500), ctx.json({ msg: 'AWS API error: unable to get AWS upload info' }));
})
);

render(<AzureResourceGroup />, {
contextValues: { chosenSource: '66' },
});

expect(await screen.findByText('Can not fetch resource groups')).toBeInTheDocument();
});
});

const mountSelectAndOpen = async () => {
render(<AzureResourceGroup />, {
contextValues: { chosenSource: '66' },
});
const selectDropdown = await screen.findByLabelText('Select resource group');
await userEvent.click(selectDropdown);
return selectDropdown;
};
98 changes: 98 additions & 0 deletions src/Components/AzureResourceGroup/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import React from 'react';

import { Spinner, Select, SelectOption, TextInput } from '@patternfly/react-core';
import { useQuery } from '@tanstack/react-query';
import { AZURE_RG_KEY } from '../../API/queryKeys';
import { fetchResourceGroups } from '../../API';
import { useWizardContext } from '../Common/WizardContext';

const AzureResourceGroup = () => {
const [isOpen, setIsOpen] = React.useState(false);
const [{ chosenSource, azureResourceGroup }, setWizardContext] = useWizardContext();
const [selection, setSelection] = React.useState(azureResourceGroup);

const {
isInitialLoading: isLoading,
error,
data: resourceGroups,
} = useQuery([AZURE_RG_KEY, chosenSource], () => fetchResourceGroups(chosenSource), {
staleTime: 30 * 1000, // data is considered fresh for 30 seconds
enabled: !!chosenSource,
});

if (!chosenSource || chosenSource === '') {
return (
<>
<TextInput
ouiaId="azure_resource_group_readonly"
className="pf-c-form-control"
readOnly
type="text"
value="Select account to load resource groups"
aria-label="Select resource group - disabled"
/>
</>
);
}

if (isLoading) {
return <Spinner isSVG size="sm" aria-label="loading resource groups" />;
}

if (error) {
return (
<>
<Select
validated="error"
ouiaId="instance_type_empty"
isDisabled
placeholderText="Can not fetch resource groups"
toggleAriaLabel="Select resource group"
/>
</>
);
}

const clearSelection = () => {
setWizardContext((prevState) => ({
...prevState,
azureResourceGroup: null,
}));
setSelection(null);
setIsOpen(false);
};

const onSelect = (event, selection, isPlaceholder) => {
if (isPlaceholder) {
clearSelection();
} else {
setWizardContext((prevState) => ({
...prevState,
azureResourceGroup: selection,
}));
setSelection(selection);
setIsOpen(false);
}
};

return (
<Select
variant="typeahead"
ouiaId="select_resource_group"
onToggle={(isExpanded) => setIsOpen(isExpanded)}
onSelect={onSelect}
isOpen={isOpen}
onClear={clearSelection}
selections={selection}
placeholderText="redhat-deployed (default)"
typeAheadAriaLabel="Select resource group"
maxHeight="220px"
>
{resourceGroups.map((name, idx) => (
<SelectOption aria-label={`Resource group ${name}`} key={idx} value={name} />
))}
</Select>
);
};

export default AzureResourceGroup;
20 changes: 19 additions & 1 deletion src/Components/LaunchDescriptionList/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,22 @@ import { useQuery } from '@tanstack/react-query';
import { fetchLaunchTemplates } from '../../API';
import { humanizeProvider } from '../Common/helpers';
import { TEMPLATES_KEY } from '../../API/queryKeys';
import { AZURE_PROVIDER } from '../../constants';

const LaunchDescriptionList = ({ imageName }) => {
const [
{ chosenRegion, chosenSshKeyName, uploadedKey, chosenInstanceType, chosenNumOfInstances, chosenSource, sshPublicName, provider, chosenTemplate },
{
chosenRegion,
chosenSshKeyName,
uploadedKey,
chosenInstanceType,
chosenNumOfInstances,
chosenSource,
sshPublicName,
provider,
chosenTemplate,
azureResourceGroup,
},
] = useWizardContext();
const { sources } = useSourcesData(provider);
const { data: templates } = useQuery([TEMPLATES_KEY, `${chosenRegion}-${chosenSource}`], () => fetchLaunchTemplates(chosenSource, chosenRegion), {
Expand Down Expand Up @@ -41,6 +53,12 @@ const LaunchDescriptionList = ({ imageName }) => {
<DescriptionListTerm>Account</DescriptionListTerm>
<DescriptionListDescription>{getChosenSourceName()}</DescriptionListDescription>
</DescriptionListGroup>
{provider === AZURE_PROVIDER && azureResourceGroup && (
<DescriptionListGroup>
<DescriptionListTerm>Resource group</DescriptionListTerm>
<DescriptionListDescription>{azureResourceGroup}</DescriptionListDescription>
</DescriptionListGroup>
)}
<DescriptionListGroup>
<DescriptionListTerm>{regionLabel}</DescriptionListTerm>
<DescriptionListDescription>{chosenRegion}</DescriptionListDescription>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import SourcesSelect from '../../../SourcesSelect';
import InstanceCounter from '../../../InstanceCounter';
import InstanceTypesSelect from '../../../InstanceTypesSelect';
import RegionsSelect from '../../../RegionsSelect';
import AzureResourceGroup from '../../../AzureResourceGroup';
import { useWizardContext } from '../../../Common/WizardContext';

const AccountCustomizationsAzure = ({ setStepValidated, image }) => {
Expand Down Expand Up @@ -77,6 +78,30 @@ const AccountCustomizationsAzure = ({ setStepValidated, image }) => {
>
<RegionsSelect provider={AZURE_PROVIDER} currentRegion={wizardContext.chosenRegion} onChange={onRegionChange} composeID={image.id} />
</FormGroup>
<FormGroup
label="Azure resource group"
fieldId="azure-resource-group-select"
labelIcon={
<Popover
headerContent={<div>Azure resource group</div>}
bodyContent={<div>Azure resource group to deploy the VM resources into. If left blank, defaults to &lsquo;redhat-deployed&rsquo;.</div>}
>
<Button
ouiaId="resource_group_help"
type="button"
aria-label="More info for resource group field"
onClick={(e) => e.preventDefault()}
aria-describedby="azure-resource-group-select"
className="pf-c-form__group-label-help"
variant="plain"
>
<HelpIcon noVerticalAlign />
</Button>
</Popover>
}
>
<AzureResourceGroup />
</FormGroup>
<FormGroup
label="Select instance size"
isRequired
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const ReservationProgress = ({ setLaunchSuccess }) => {
chosenImageID,
provider,
chosenTemplate,
azureResourceGroup,
},
] = useWizardContext();
const { nextInterval, currentInterval } = useInterval(POLLING_BACKOFF_INTERVAL);
Expand All @@ -65,6 +66,7 @@ const ReservationProgress = ({ setLaunchSuccess }) => {
[region(provider)]: chosenRegion,
pubkey_id: chosenSshKeyId,
...(chosenTemplate && { launch_template_id: chosenTemplate }),
...(azureResourceGroup && { resource_group: azureResourceGroup }),
});

React.useEffect(() => {
Expand Down
18 changes: 18 additions & 0 deletions src/mocks/fixtures/sources.fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,28 @@ export const gcpSourcesList = {
],
};

export const azureSourcesList = {
data: [
{
name: 'Azure Source 1',
id: '66',
},
],
};

export const gcpSourceUploadInfo = () => ({ gcp: {} });

export const awsSourceUploadInfo = (account_id = '123456789') => ({ aws: { account_id } });

export const azureSourceUploadInfo = {
azure: {
resource_groups: ['testGroup', 'Cool Group'],
subscription_id: '617807e1-e4e0-4855-983c-1e3ce1e49674',
tenant_id: '617807e1-e4e0-481c-983c-be3ce1e49253',
},
provider: 'azure',
};

export const awsSourceFailedUploadInfo = () => ({
msg: 'AWS API error: unable to get AWS upload info',
trace_id: 'trcid',
Expand Down
4 changes: 3 additions & 1 deletion src/mocks/handlers.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { rest } from 'msw';
import { imageBuilderURL, provisioningUrl } from '../API/helpers';
import { awsInstanceTypeList, azureInstanceTypeList } from './fixtures/instanceTypes.fixtures';
import { sourcesList, gcpSourcesList, awsSourceUploadInfo, gcpSourceUploadInfo } from './fixtures/sources.fixtures';
import { sourcesList, gcpSourcesList, awsSourceUploadInfo, azureSourceUploadInfo, gcpSourceUploadInfo } from './fixtures/sources.fixtures';
import { pubkeysList } from './fixtures/pubkeys.fixtures';
import { clonedImages, parentImage, successfulCloneStatus } from './fixtures/image.fixtures';
import {
Expand Down Expand Up @@ -30,6 +30,8 @@ export const handlers = [
return res(ctx.status(200), ctx.json(awsSourceUploadInfo()));
} else if (sourceID === '10') {
return res(ctx.status(200), ctx.json(gcpSourceUploadInfo()));
} else if (sourceID === '66') {
return res(ctx.status(200), ctx.json(azureSourceUploadInfo));
}
}),
rest.get(provisioningUrl('pubkeys'), (req, res, ctx) => {
Expand Down
7 changes: 6 additions & 1 deletion src/mocks/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,19 @@ import { render } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { WizardProvider } from '../Components/Common/WizardContext';

const AllProviders = ({ children, provider, ...contextValues }) => {
const AllProviders = ({ children, provider, queryRetries = false, ...contextValues }) => {
const queryClient = new QueryClient({
logger: {
log: console.log,
warn: console.warn,
// ✅ no more errors on the console
error: () => {},
},
defaultOptions: {
queries: {
retry: queryRetries,
},
},
});

return (
Expand Down

0 comments on commit 3e73a67

Please sign in to comment.