Launch button in stable environments
This moves Beta only features to stable environment: - Sharing Images through Sources - Launch button This tries to avoid any refactoring, just moving components from Beta to stable with minimal changes.
This commit is contained in:
parent
e5575d7a2d
commit
2a8e5a10df
12 changed files with 523 additions and 782 deletions
|
|
@ -7,14 +7,12 @@ import { useNavigate, useParams } from 'react-router-dom';
|
|||
|
||||
import ImageCreator from './ImageCreator';
|
||||
import {
|
||||
awsTargetStable,
|
||||
awsTargetBeta,
|
||||
awsTarget,
|
||||
fileSystemConfiguration,
|
||||
googleCloudTarger,
|
||||
googleCloudTarget,
|
||||
imageName,
|
||||
imageOutput,
|
||||
msAzureTargetStable,
|
||||
msAzureTargetBeta,
|
||||
msAzureTarget,
|
||||
packages,
|
||||
packagesContentSources,
|
||||
registration,
|
||||
|
|
@ -516,8 +514,6 @@ const CreateImageWizard = () => {
|
|||
|
||||
const { isBeta, isProd } = useGetEnvironment();
|
||||
|
||||
const awsTarget = isBeta() ? awsTargetBeta : awsTargetStable;
|
||||
const msAzureTarget = isBeta() ? msAzureTargetBeta : msAzureTargetStable;
|
||||
let initialState = requestToState(
|
||||
composeRequest,
|
||||
distroInfo,
|
||||
|
|
@ -622,7 +618,7 @@ const CreateImageWizard = () => {
|
|||
fields: [
|
||||
imageOutput,
|
||||
awsTarget,
|
||||
googleCloudTarger,
|
||||
googleCloudTarget,
|
||||
msAzureTarget,
|
||||
registration,
|
||||
packages,
|
||||
|
|
|
|||
|
|
@ -1,187 +0,0 @@
|
|||
import React from 'react';
|
||||
|
||||
import componentTypes from '@data-driven-forms/react-form-renderer/component-types';
|
||||
import validatorTypes from '@data-driven-forms/react-form-renderer/validator-types';
|
||||
import {
|
||||
Button,
|
||||
HelperText,
|
||||
HelperTextItem,
|
||||
Title,
|
||||
} from '@patternfly/react-core';
|
||||
import { ExternalLinkAltIcon } from '@patternfly/react-icons';
|
||||
|
||||
import nextStepMapper from './imageOutputStepMapper';
|
||||
import StepTemplate from './stepTemplate';
|
||||
|
||||
import { DEFAULT_AWS_REGION } from '../../../constants';
|
||||
import CustomButtons from '../formComponents/CustomButtons';
|
||||
|
||||
const SourcesButton = () => {
|
||||
return (
|
||||
<Button
|
||||
component="a"
|
||||
target="_blank"
|
||||
variant="link"
|
||||
icon={<ExternalLinkAltIcon />}
|
||||
iconPosition="right"
|
||||
isInline
|
||||
href={'settings/sources'}
|
||||
>
|
||||
Create and manage sources here
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default {
|
||||
StepTemplate,
|
||||
id: 'wizard-target-aws',
|
||||
title: 'Amazon Web Services',
|
||||
customTitle: (
|
||||
<Title headingLevel="h1" size="xl">
|
||||
Target environment - Amazon Web Services
|
||||
</Title>
|
||||
),
|
||||
name: 'aws-target-env',
|
||||
substepOf: 'Target environment',
|
||||
nextStep: ({ values }) => nextStepMapper(values, { skipAws: true }),
|
||||
buttons: CustomButtons,
|
||||
fields: [
|
||||
{
|
||||
component: componentTypes.PLAIN_TEXT,
|
||||
name: 'plain-text-component',
|
||||
label: (
|
||||
<p>
|
||||
Your image will be uploaded to AWS and shared with the account you
|
||||
provide below.
|
||||
</p>
|
||||
),
|
||||
},
|
||||
{
|
||||
component: componentTypes.PLAIN_TEXT,
|
||||
name: 'plain-text-component',
|
||||
label: (
|
||||
<p>
|
||||
<b>The shared image will expire within 14 days.</b> To permanently
|
||||
access the image, copy the image, which will be shared to your account
|
||||
by Red Hat, to your own AWS account.
|
||||
</p>
|
||||
),
|
||||
},
|
||||
{
|
||||
component: componentTypes.RADIO,
|
||||
label: 'Share method:',
|
||||
name: 'aws-target-type',
|
||||
initialValue: 'aws-target-type-source',
|
||||
autoFocus: true,
|
||||
options: [
|
||||
{
|
||||
label: 'Use an account configured from Sources.',
|
||||
description:
|
||||
'Use a configured source to launch environments directly from the console.',
|
||||
value: 'aws-target-type-source',
|
||||
'data-testid': 'aws-radio-source',
|
||||
autoFocus: true,
|
||||
},
|
||||
{
|
||||
label: 'Manually enter an account ID.',
|
||||
value: 'aws-target-type-account-id',
|
||||
'data-testid': 'aws-radio-account-id',
|
||||
className: 'pf-u-mt-sm',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
component: 'aws-sources-select',
|
||||
name: 'aws-sources-select',
|
||||
className: 'pf-u-max-width',
|
||||
label: 'Source Name',
|
||||
isRequired: true,
|
||||
validate: [
|
||||
{
|
||||
type: validatorTypes.REQUIRED,
|
||||
},
|
||||
],
|
||||
condition: {
|
||||
when: 'aws-target-type',
|
||||
is: 'aws-target-type-source',
|
||||
},
|
||||
},
|
||||
{
|
||||
component: componentTypes.PLAIN_TEXT,
|
||||
name: 'aws-sources-select-description',
|
||||
label: <SourcesButton />,
|
||||
condition: {
|
||||
when: 'aws-target-type',
|
||||
is: 'aws-target-type-source',
|
||||
},
|
||||
},
|
||||
{
|
||||
component: componentTypes.TEXT_FIELD,
|
||||
name: 'aws-account-id',
|
||||
className: 'pf-u-w-25',
|
||||
'data-testid': 'aws-account-id',
|
||||
type: 'text',
|
||||
label: 'AWS account ID',
|
||||
isRequired: true,
|
||||
validate: [
|
||||
{
|
||||
type: validatorTypes.REQUIRED,
|
||||
},
|
||||
{
|
||||
type: validatorTypes.EXACT_LENGTH,
|
||||
threshold: 12,
|
||||
},
|
||||
],
|
||||
condition: {
|
||||
when: 'aws-target-type',
|
||||
is: 'aws-target-type-account-id',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'gallery-layout',
|
||||
component: 'gallery-layout',
|
||||
minWidths: { default: '12.5rem' },
|
||||
maxWidths: { default: '12.5rem' },
|
||||
fields: [
|
||||
{
|
||||
component: componentTypes.TEXT_FIELD,
|
||||
name: 'aws-default-region',
|
||||
value: DEFAULT_AWS_REGION,
|
||||
'data-testid': 'aws-default-region',
|
||||
type: 'text',
|
||||
label: 'Default Region',
|
||||
isReadOnly: true,
|
||||
isRequired: true,
|
||||
helperText: (
|
||||
<HelperText>
|
||||
<HelperTextItem component="div" variant="indeterminate">
|
||||
Images are built in the default region but can be copied to
|
||||
other regions later.
|
||||
</HelperTextItem>
|
||||
</HelperText>
|
||||
),
|
||||
},
|
||||
{
|
||||
component: componentTypes.TEXT_FIELD,
|
||||
name: 'aws-associated-account-id',
|
||||
'data-testid': 'aws-associated-account-id',
|
||||
type: 'text',
|
||||
label: 'Associated Account ID',
|
||||
isReadOnly: true,
|
||||
isRequired: true,
|
||||
helperText: (
|
||||
<HelperText>
|
||||
<HelperTextItem component="div" variant="indeterminate">
|
||||
This is the account associated with the source.
|
||||
</HelperTextItem>
|
||||
</HelperText>
|
||||
),
|
||||
condition: {
|
||||
when: 'aws-target-type',
|
||||
is: 'aws-target-type-source',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
@ -2,7 +2,13 @@ import React from 'react';
|
|||
|
||||
import componentTypes from '@data-driven-forms/react-form-renderer/component-types';
|
||||
import validatorTypes from '@data-driven-forms/react-form-renderer/validator-types';
|
||||
import { HelperText, HelperTextItem, Title } from '@patternfly/react-core';
|
||||
import {
|
||||
Button,
|
||||
HelperText,
|
||||
HelperTextItem,
|
||||
Title,
|
||||
} from '@patternfly/react-core';
|
||||
import { ExternalLinkAltIcon } from '@patternfly/react-icons';
|
||||
|
||||
import nextStepMapper from './imageOutputStepMapper';
|
||||
import StepTemplate from './stepTemplate';
|
||||
|
|
@ -10,6 +16,22 @@ import StepTemplate from './stepTemplate';
|
|||
import { DEFAULT_AWS_REGION } from '../../../constants';
|
||||
import CustomButtons from '../formComponents/CustomButtons';
|
||||
|
||||
const SourcesButton = () => {
|
||||
return (
|
||||
<Button
|
||||
component="a"
|
||||
target="_blank"
|
||||
variant="link"
|
||||
icon={<ExternalLinkAltIcon />}
|
||||
iconPosition="right"
|
||||
isInline
|
||||
href={'settings/sources'}
|
||||
>
|
||||
Create and manage sources here
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default {
|
||||
StepTemplate,
|
||||
id: 'wizard-target-aws',
|
||||
|
|
@ -45,6 +67,54 @@ export default {
|
|||
</p>
|
||||
),
|
||||
},
|
||||
{
|
||||
component: componentTypes.RADIO,
|
||||
label: 'Share method:',
|
||||
name: 'aws-target-type',
|
||||
initialValue: 'aws-target-type-source',
|
||||
autoFocus: true,
|
||||
options: [
|
||||
{
|
||||
label: 'Use an account configured from Sources.',
|
||||
description:
|
||||
'Use a configured source to launch environments directly from the console.',
|
||||
value: 'aws-target-type-source',
|
||||
'data-testid': 'aws-radio-source',
|
||||
autoFocus: true,
|
||||
},
|
||||
{
|
||||
label: 'Manually enter an account ID.',
|
||||
value: 'aws-target-type-account-id',
|
||||
'data-testid': 'aws-radio-account-id',
|
||||
className: 'pf-u-mt-sm',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
component: 'aws-sources-select',
|
||||
name: 'aws-sources-select',
|
||||
className: 'pf-u-max-width',
|
||||
label: 'Source Name',
|
||||
isRequired: true,
|
||||
validate: [
|
||||
{
|
||||
type: validatorTypes.REQUIRED,
|
||||
},
|
||||
],
|
||||
condition: {
|
||||
when: 'aws-target-type',
|
||||
is: 'aws-target-type-source',
|
||||
},
|
||||
},
|
||||
{
|
||||
component: componentTypes.PLAIN_TEXT,
|
||||
name: 'aws-sources-select-description',
|
||||
label: <SourcesButton />,
|
||||
condition: {
|
||||
when: 'aws-target-type',
|
||||
is: 'aws-target-type-source',
|
||||
},
|
||||
},
|
||||
{
|
||||
component: componentTypes.TEXT_FIELD,
|
||||
name: 'aws-account-id',
|
||||
|
|
@ -53,7 +123,6 @@ export default {
|
|||
type: 'text',
|
||||
label: 'AWS account ID',
|
||||
isRequired: true,
|
||||
autoFocus: true,
|
||||
validate: [
|
||||
{
|
||||
type: validatorTypes.REQUIRED,
|
||||
|
|
@ -63,29 +132,56 @@ export default {
|
|||
threshold: 12,
|
||||
},
|
||||
],
|
||||
condition: {
|
||||
when: 'aws-target-type',
|
||||
is: 'aws-target-type-account-id',
|
||||
},
|
||||
},
|
||||
{
|
||||
component: componentTypes.TEXT_FIELD,
|
||||
name: 'aws-default-region',
|
||||
className: 'pf-u-w-25',
|
||||
'data-testid': 'aws-default-region',
|
||||
type: 'text',
|
||||
label: 'Default Region',
|
||||
value: DEFAULT_AWS_REGION,
|
||||
isReadOnly: true,
|
||||
isRequired: true,
|
||||
helperText: (
|
||||
<HelperText>
|
||||
<HelperTextItem
|
||||
component="div"
|
||||
variant="indeterminate"
|
||||
className="pf-u-w-25"
|
||||
>
|
||||
Images are built in the default region but can be copied to other
|
||||
regions later.
|
||||
</HelperTextItem>
|
||||
</HelperText>
|
||||
),
|
||||
name: 'gallery-layout',
|
||||
component: 'gallery-layout',
|
||||
minWidths: { default: '12.5rem' },
|
||||
maxWidths: { default: '12.5rem' },
|
||||
fields: [
|
||||
{
|
||||
component: componentTypes.TEXT_FIELD,
|
||||
name: 'aws-default-region',
|
||||
value: DEFAULT_AWS_REGION,
|
||||
'data-testid': 'aws-default-region',
|
||||
type: 'text',
|
||||
label: 'Default Region',
|
||||
isReadOnly: true,
|
||||
isRequired: true,
|
||||
helperText: (
|
||||
<HelperText>
|
||||
<HelperTextItem component="div" variant="indeterminate">
|
||||
Images are built in the default region but can be copied to
|
||||
other regions later.
|
||||
</HelperTextItem>
|
||||
</HelperText>
|
||||
),
|
||||
},
|
||||
{
|
||||
component: componentTypes.TEXT_FIELD,
|
||||
name: 'aws-associated-account-id',
|
||||
'data-testid': 'aws-associated-account-id',
|
||||
type: 'text',
|
||||
label: 'Associated Account ID',
|
||||
isReadOnly: true,
|
||||
isRequired: true,
|
||||
helperText: (
|
||||
<HelperText>
|
||||
<HelperTextItem component="div" variant="indeterminate">
|
||||
This is the account associated with the source.
|
||||
</HelperTextItem>
|
||||
</HelperText>
|
||||
),
|
||||
condition: {
|
||||
when: 'aws-target-type',
|
||||
is: 'aws-target-type-source',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
export { default as awsTargetStable } from './aws';
|
||||
export { default as awsTargetBeta } from './aws.beta';
|
||||
export { default as googleCloudTarger } from './googleCloud';
|
||||
export { default as msAzureTargetStable } from './msAzure';
|
||||
export { default as msAzureTargetBeta } from './msAzure.beta';
|
||||
export { default as awsTarget } from './aws';
|
||||
export { default as googleCloudTarget } from './googleCloud';
|
||||
export { default as msAzureTarget } from './msAzure';
|
||||
export { default as packages } from './packages';
|
||||
export { default as packagesContentSources } from './packagesContentSources';
|
||||
export { default as registration } from './registration';
|
||||
|
|
|
|||
|
|
@ -1,262 +0,0 @@
|
|||
import React from 'react';
|
||||
|
||||
import componentTypes from '@data-driven-forms/react-form-renderer/component-types';
|
||||
import validatorTypes from '@data-driven-forms/react-form-renderer/validator-types';
|
||||
import { Button, Text, TextContent, Title } from '@patternfly/react-core';
|
||||
import { ExternalLinkAltIcon } from '@patternfly/react-icons';
|
||||
|
||||
import nextStepMapper from './imageOutputStepMapper';
|
||||
import StepTemplate from './stepTemplate';
|
||||
|
||||
import CustomButtons from '../formComponents/CustomButtons';
|
||||
|
||||
const SourcesButton = () => {
|
||||
return (
|
||||
<Button
|
||||
component="a"
|
||||
target="_blank"
|
||||
variant="link"
|
||||
icon={<ExternalLinkAltIcon />}
|
||||
iconPosition="right"
|
||||
isInline
|
||||
href={'settings/sources'}
|
||||
>
|
||||
Create and manage sources here
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default {
|
||||
StepTemplate,
|
||||
id: 'wizard-target-msazure',
|
||||
title: 'Microsoft Azure',
|
||||
customTitle: (
|
||||
<Title headingLevel="h1" size="xl">
|
||||
Target environment - Microsoft Azure
|
||||
</Title>
|
||||
),
|
||||
name: 'ms-azure-target-env',
|
||||
substepOf: 'Target environment',
|
||||
nextStep: ({ values }) =>
|
||||
nextStepMapper(values, {
|
||||
skipAws: true,
|
||||
skipGoogle: true,
|
||||
skipAzure: true,
|
||||
}),
|
||||
buttons: CustomButtons,
|
||||
fields: [
|
||||
{
|
||||
component: componentTypes.PLAIN_TEXT,
|
||||
name: 'azure-description',
|
||||
label: (
|
||||
<TextContent>
|
||||
<Text>
|
||||
Upon build, Image Builder sends the image to the selected authorized
|
||||
Azure account. The image will be uploaded to the resource group in
|
||||
the subscription you specify.
|
||||
</Text>
|
||||
<Text>
|
||||
To authorize Image Builder to push images to Microsoft Azure, the
|
||||
account owner must configure Image Builder as an authorized
|
||||
application for a specific tenant ID and give it the role of
|
||||
"Contributor" for the resource group you want to upload
|
||||
to. This applies even when defining target by Source selection.
|
||||
<br />
|
||||
<Button
|
||||
component="a"
|
||||
target="_blank"
|
||||
variant="link"
|
||||
icon={<ExternalLinkAltIcon />}
|
||||
iconPosition="right"
|
||||
isInline
|
||||
href="https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow"
|
||||
>
|
||||
Learn more about OAuth 2.0
|
||||
</Button>
|
||||
</Text>
|
||||
</TextContent>
|
||||
),
|
||||
},
|
||||
{
|
||||
component: componentTypes.RADIO,
|
||||
label: 'Share method:',
|
||||
name: 'azure-type',
|
||||
initialValue: 'azure-type-source',
|
||||
autoFocus: true,
|
||||
options: [
|
||||
{
|
||||
label: 'Use an account configured from Sources.',
|
||||
description:
|
||||
'Use a configured source to launch environments directly from the console.',
|
||||
value: 'azure-type-source',
|
||||
'data-testid': 'azure-radio-source',
|
||||
autoFocus: true,
|
||||
},
|
||||
{
|
||||
label: 'Manually enter the account information.',
|
||||
value: 'azure-type-manual',
|
||||
'data-testid': 'azure-radio-manual',
|
||||
className: 'pf-u-mt-sm',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
component: 'azure-sources-select',
|
||||
name: 'azure-sources-select',
|
||||
className: 'pf-u-max-width',
|
||||
label: 'Source Name',
|
||||
isRequired: true,
|
||||
validate: [
|
||||
{
|
||||
type: validatorTypes.REQUIRED,
|
||||
},
|
||||
],
|
||||
condition: {
|
||||
when: 'azure-type',
|
||||
is: 'azure-type-source',
|
||||
},
|
||||
},
|
||||
{
|
||||
component: componentTypes.PLAIN_TEXT,
|
||||
name: 'azure-sources-select-description',
|
||||
label: <SourcesButton />,
|
||||
condition: {
|
||||
when: 'azure-type',
|
||||
is: 'azure-type-source',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'gallery-layout',
|
||||
component: 'gallery-layout',
|
||||
minWidths: { default: '12.5rem' },
|
||||
maxWidths: { default: '12.5rem' },
|
||||
fields: [
|
||||
{
|
||||
component: componentTypes.TEXT_FIELD,
|
||||
name: 'azure-tenant-id',
|
||||
'data-testid': 'azure-tenant-id-source',
|
||||
type: 'text',
|
||||
label: 'Azure Tenant GUID',
|
||||
isRequired: true,
|
||||
isReadOnly: true,
|
||||
},
|
||||
{
|
||||
component: componentTypes.TEXT_FIELD,
|
||||
name: 'azure-subscription-id',
|
||||
'data-testid': 'azure-subscription-id-source',
|
||||
type: 'text',
|
||||
label: 'Subscription ID',
|
||||
isRequired: true,
|
||||
isReadOnly: true,
|
||||
condition: {
|
||||
when: 'azure-type',
|
||||
is: 'azure-type-source',
|
||||
},
|
||||
},
|
||||
],
|
||||
condition: {
|
||||
when: 'azure-type',
|
||||
is: 'azure-type-source',
|
||||
},
|
||||
},
|
||||
{
|
||||
component: componentTypes.TEXT_FIELD,
|
||||
name: 'azure-tenant-id',
|
||||
className: 'pf-u-w-50',
|
||||
'data-testid': 'azure-tenant-id-manual',
|
||||
type: 'text',
|
||||
label: 'Azure Tenant GUID',
|
||||
isRequired: true,
|
||||
autoFocus: true,
|
||||
validate: [
|
||||
{
|
||||
type: validatorTypes.REQUIRED,
|
||||
},
|
||||
{
|
||||
type: validatorTypes.PATTERN,
|
||||
pattern:
|
||||
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
|
||||
message: 'Please enter a valid tenant ID',
|
||||
},
|
||||
],
|
||||
condition: {
|
||||
when: 'azure-type',
|
||||
is: 'azure-type-manual',
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'azure-auth-button',
|
||||
name: 'azure-auth-button',
|
||||
'data-testid': 'azure-auth-button',
|
||||
required: true,
|
||||
isRequired: true,
|
||||
},
|
||||
{
|
||||
component: componentTypes.TEXT_FIELD,
|
||||
name: 'azure-subscription-id',
|
||||
className: 'pf-u-w-50',
|
||||
'data-testid': 'azure-subscription-id-manual',
|
||||
type: 'text',
|
||||
label: 'Subscription ID',
|
||||
isRequired: true,
|
||||
validate: [
|
||||
{
|
||||
type: validatorTypes.REQUIRED,
|
||||
},
|
||||
{
|
||||
type: validatorTypes.PATTERN,
|
||||
pattern:
|
||||
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
|
||||
message: 'Please enter a valid subscription ID',
|
||||
},
|
||||
],
|
||||
condition: {
|
||||
when: 'azure-type',
|
||||
is: 'azure-type-manual',
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'azure-resource-groups',
|
||||
name: 'azure-resource-group',
|
||||
className: 'pf-u-max-width',
|
||||
'data-testid': 'azure-resource-group-select',
|
||||
label: 'Resource group',
|
||||
isRequired: true,
|
||||
validate: [
|
||||
{
|
||||
type: validatorTypes.REQUIRED,
|
||||
},
|
||||
],
|
||||
condition: {
|
||||
when: 'azure-type',
|
||||
is: 'azure-type-source',
|
||||
},
|
||||
},
|
||||
{
|
||||
component: componentTypes.TEXT_FIELD,
|
||||
name: 'azure-resource-group',
|
||||
className: 'pf-u-w-50',
|
||||
'data-testid': 'azure-resource-group-manual',
|
||||
type: 'text',
|
||||
label: 'Resource group',
|
||||
isRequired: true,
|
||||
validate: [
|
||||
{
|
||||
type: validatorTypes.REQUIRED,
|
||||
},
|
||||
{
|
||||
type: validatorTypes.PATTERN,
|
||||
pattern: /^[-\w._()]+[-\w_()]$/,
|
||||
message:
|
||||
'Resource group names only allow alphanumeric characters, ' +
|
||||
'periods, underscores, hyphens, and parenthesis and cannot end in a period',
|
||||
},
|
||||
],
|
||||
condition: {
|
||||
when: 'azure-type',
|
||||
is: 'azure-type-manual',
|
||||
},
|
||||
},
|
||||
// TODO check oauth2 thing too here?
|
||||
],
|
||||
};
|
||||
|
|
@ -10,6 +10,22 @@ import StepTemplate from './stepTemplate';
|
|||
|
||||
import CustomButtons from '../formComponents/CustomButtons';
|
||||
|
||||
const SourcesButton = () => {
|
||||
return (
|
||||
<Button
|
||||
component="a"
|
||||
target="_blank"
|
||||
variant="link"
|
||||
icon={<ExternalLinkAltIcon />}
|
||||
iconPosition="right"
|
||||
isInline
|
||||
href={'settings/sources'}
|
||||
>
|
||||
Create and manage sources here
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default {
|
||||
StepTemplate,
|
||||
id: 'wizard-target-msazure',
|
||||
|
|
@ -43,7 +59,8 @@ export default {
|
|||
To authorize Image Builder to push images to Microsoft Azure, the
|
||||
account owner must configure Image Builder as an authorized
|
||||
application for a specific tenant ID and give it the role of
|
||||
"Contributor" to at least one resource group.
|
||||
"Contributor" for the resource group you want to upload
|
||||
to. This applies even when defining target by Source selection.
|
||||
<br />
|
||||
<Button
|
||||
component="a"
|
||||
|
|
@ -60,14 +77,95 @@ export default {
|
|||
</TextContent>
|
||||
),
|
||||
},
|
||||
{
|
||||
component: componentTypes.RADIO,
|
||||
label: 'Share method:',
|
||||
name: 'azure-type',
|
||||
initialValue: 'azure-type-source',
|
||||
autoFocus: true,
|
||||
options: [
|
||||
{
|
||||
label: 'Use an account configured from Sources.',
|
||||
description:
|
||||
'Use a configured source to launch environments directly from the console.',
|
||||
value: 'azure-type-source',
|
||||
'data-testid': 'azure-radio-source',
|
||||
autoFocus: true,
|
||||
},
|
||||
{
|
||||
label: 'Manually enter the account information.',
|
||||
value: 'azure-type-manual',
|
||||
'data-testid': 'azure-radio-manual',
|
||||
className: 'pf-u-mt-sm',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
component: 'azure-sources-select',
|
||||
name: 'azure-sources-select',
|
||||
className: 'pf-u-max-width',
|
||||
label: 'Source Name',
|
||||
isRequired: true,
|
||||
validate: [
|
||||
{
|
||||
type: validatorTypes.REQUIRED,
|
||||
},
|
||||
],
|
||||
condition: {
|
||||
when: 'azure-type',
|
||||
is: 'azure-type-source',
|
||||
},
|
||||
},
|
||||
{
|
||||
component: componentTypes.PLAIN_TEXT,
|
||||
name: 'azure-sources-select-description',
|
||||
label: <SourcesButton />,
|
||||
condition: {
|
||||
when: 'azure-type',
|
||||
is: 'azure-type-source',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'gallery-layout',
|
||||
component: 'gallery-layout',
|
||||
minWidths: { default: '12.5rem' },
|
||||
maxWidths: { default: '12.5rem' },
|
||||
fields: [
|
||||
{
|
||||
component: componentTypes.TEXT_FIELD,
|
||||
name: 'azure-tenant-id',
|
||||
'data-testid': 'azure-tenant-id-source',
|
||||
type: 'text',
|
||||
label: 'Azure Tenant GUID',
|
||||
isRequired: true,
|
||||
isReadOnly: true,
|
||||
},
|
||||
{
|
||||
component: componentTypes.TEXT_FIELD,
|
||||
name: 'azure-subscription-id',
|
||||
'data-testid': 'azure-subscription-id-source',
|
||||
type: 'text',
|
||||
label: 'Subscription ID',
|
||||
isRequired: true,
|
||||
isReadOnly: true,
|
||||
condition: {
|
||||
when: 'azure-type',
|
||||
is: 'azure-type-source',
|
||||
},
|
||||
},
|
||||
],
|
||||
condition: {
|
||||
when: 'azure-type',
|
||||
is: 'azure-type-source',
|
||||
},
|
||||
},
|
||||
{
|
||||
component: componentTypes.TEXT_FIELD,
|
||||
name: 'azure-tenant-id',
|
||||
className: 'pf-u-w-50',
|
||||
'data-testid': 'azure-tenant-id',
|
||||
'data-testid': 'azure-tenant-id-manual',
|
||||
type: 'text',
|
||||
label: 'Azure Tenant GUID',
|
||||
required: true,
|
||||
isRequired: true,
|
||||
autoFocus: true,
|
||||
validate: [
|
||||
|
|
@ -81,6 +179,10 @@ export default {
|
|||
message: 'Please enter a valid tenant ID',
|
||||
},
|
||||
],
|
||||
condition: {
|
||||
when: 'azure-type',
|
||||
is: 'azure-type-manual',
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'azure-auth-button',
|
||||
|
|
@ -93,7 +195,7 @@ export default {
|
|||
component: componentTypes.TEXT_FIELD,
|
||||
name: 'azure-subscription-id',
|
||||
className: 'pf-u-w-50',
|
||||
'data-testid': 'azure-subscription-id',
|
||||
'data-testid': 'azure-subscription-id-manual',
|
||||
type: 'text',
|
||||
label: 'Subscription ID',
|
||||
isRequired: true,
|
||||
|
|
@ -108,12 +210,33 @@ export default {
|
|||
message: 'Please enter a valid subscription ID',
|
||||
},
|
||||
],
|
||||
condition: {
|
||||
when: 'azure-type',
|
||||
is: 'azure-type-manual',
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'azure-resource-groups',
|
||||
name: 'azure-resource-group',
|
||||
className: 'pf-u-max-width',
|
||||
'data-testid': 'azure-resource-group-select',
|
||||
label: 'Resource group',
|
||||
isRequired: true,
|
||||
validate: [
|
||||
{
|
||||
type: validatorTypes.REQUIRED,
|
||||
},
|
||||
],
|
||||
condition: {
|
||||
when: 'azure-type',
|
||||
is: 'azure-type-source',
|
||||
},
|
||||
},
|
||||
{
|
||||
component: componentTypes.TEXT_FIELD,
|
||||
name: 'azure-resource-group',
|
||||
className: 'pf-u-w-50',
|
||||
'data-testid': 'azure-resource-group',
|
||||
'data-testid': 'azure-resource-group-manual',
|
||||
type: 'text',
|
||||
label: 'Resource group',
|
||||
isRequired: true,
|
||||
|
|
@ -129,6 +252,10 @@ export default {
|
|||
'periods, underscores, hyphens, and parenthesis and cannot end in a period',
|
||||
},
|
||||
],
|
||||
condition: {
|
||||
when: 'azure-type',
|
||||
is: 'azure-type-manual',
|
||||
},
|
||||
},
|
||||
// TODO check oauth2 thing too here?
|
||||
],
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import ImageLinkDirect from './ImageLinkDirect';
|
|||
|
||||
import { MODAL_ANCHOR } from '../../constants';
|
||||
import { selectImageById } from '../../store/composesSlice';
|
||||
import { useGetEnvironment } from '../../Utilities/useGetEnvironment';
|
||||
|
||||
const getImageProvider = ({ imageType }) => {
|
||||
switch (imageType) {
|
||||
|
|
@ -97,12 +96,10 @@ const ImageLink = ({ imageId, isExpired, isInClonesTable }) => {
|
|||
const image = useSelector((state) => selectImageById(state, imageId));
|
||||
const uploadStatus = image.uploadStatus;
|
||||
const { initialized: chromeInitialized, getEnvironment } = useChrome();
|
||||
const { isBeta } = useGetEnvironment();
|
||||
const azureFeatureFlag = useFlag('provisioning.azure');
|
||||
const gcpFeatureFlag = useFlag('provisioning.gcp');
|
||||
const scalprum = useScalprum();
|
||||
const hasProvisioning =
|
||||
chromeInitialized && scalprum.config?.provisioning && isBeta();
|
||||
const hasProvisioning = chromeInitialized && scalprum.config?.provisioning;
|
||||
|
||||
if (!uploadStatus || image.status !== 'success') return null;
|
||||
|
||||
|
|
|
|||
3
src/store/actions/index.js
Normal file
3
src/store/actions/index.js
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
import actions from 'actions';
|
||||
|
||||
export default actions;
|
||||
|
|
@ -38,7 +38,7 @@ jest.mock('@redhat-cloud-services/frontend-components/useChrome', () => ({
|
|||
};
|
||||
},
|
||||
},
|
||||
isBeta: () => true,
|
||||
isBeta: () => false,
|
||||
isProd: () => true,
|
||||
getEnvironment: () => 'prod',
|
||||
}),
|
||||
|
|
@ -1,15 +1,17 @@
|
|||
import React from 'react';
|
||||
import '@testing-library/jest-dom';
|
||||
|
||||
import { screen, waitFor } from '@testing-library/react';
|
||||
import { act, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import CreateImageWizard from '../../../Components/CreateImageWizard/CreateImageWizard';
|
||||
import ShareImageModal from '../../../Components/ShareImageModal/ShareImageModal';
|
||||
import {
|
||||
clickBack,
|
||||
clickNext,
|
||||
getNextButton,
|
||||
renderCustomRoutesWithReduxRouter,
|
||||
verifyCancelButton,
|
||||
} from '../../testUtils';
|
||||
|
||||
const routes = [
|
||||
|
|
@ -39,12 +41,14 @@ jest.mock('@redhat-cloud-services/frontend-components/useChrome', () => ({
|
|||
};
|
||||
},
|
||||
},
|
||||
isBeta: () => true,
|
||||
isBeta: () => false,
|
||||
isProd: () => true,
|
||||
getEnvironment: () => 'prod',
|
||||
}),
|
||||
}));
|
||||
|
||||
let router = undefined;
|
||||
|
||||
describe('Step Upload to Azure', () => {
|
||||
const getSourceDropdown = async () => {
|
||||
const sourceDropdown = await screen.findByRole('textbox', {
|
||||
|
|
@ -63,12 +67,13 @@ describe('Step Upload to Azure', () => {
|
|||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
router = undefined;
|
||||
});
|
||||
|
||||
const user = userEvent.setup();
|
||||
const setUp = async () => {
|
||||
renderCustomRoutesWithReduxRouter('imagewizard', {}, routes);
|
||||
// select aws as upload destination
|
||||
({ router } = renderCustomRoutesWithReduxRouter('imagewizard', {}, routes));
|
||||
// select Azure as upload destination
|
||||
const azureTile = screen.getByTestId('upload-azure');
|
||||
azureTile.click();
|
||||
|
||||
|
|
@ -79,6 +84,50 @@ describe('Step Upload to Azure', () => {
|
|||
);
|
||||
};
|
||||
|
||||
test('clicking Next loads Registration', async () => {
|
||||
await setUp();
|
||||
|
||||
await user.click(screen.getByTestId('azure-radio-manual'));
|
||||
// Randomly generated GUID
|
||||
await user.type(
|
||||
screen.getByTestId('azure-tenant-id-manual'),
|
||||
'b8f86d22-4371-46ce-95e7-65c415f3b1e2'
|
||||
);
|
||||
await user.type(
|
||||
screen.getByTestId('azure-subscription-id-manual'),
|
||||
'60631143-a7dc-4d15-988b-ba83f3c99711'
|
||||
);
|
||||
await user.type(
|
||||
screen.getByTestId('azure-resource-group-manual'),
|
||||
'testResourceGroup'
|
||||
);
|
||||
await act(async () => {
|
||||
await clickNext();
|
||||
});
|
||||
|
||||
await screen.findByRole('textbox', {
|
||||
name: 'Select activation key',
|
||||
});
|
||||
|
||||
await screen.findByText(
|
||||
'Automatically register and enable advanced capabilities'
|
||||
);
|
||||
});
|
||||
|
||||
test('clicking Back loads Release', async () => {
|
||||
await setUp();
|
||||
|
||||
await clickBack();
|
||||
|
||||
screen.getByTestId('upload-azure');
|
||||
});
|
||||
|
||||
test('clicking Cancel loads landing page', async () => {
|
||||
await setUp();
|
||||
|
||||
await verifyCancelButton(router);
|
||||
});
|
||||
|
||||
test('azure step basics works', async () => {
|
||||
await setUp();
|
||||
|
||||
|
|
@ -90,18 +139,18 @@ describe('Step Upload to Azure', () => {
|
|||
|
||||
expect(await getNextButton()).toHaveClass('pf-m-disabled');
|
||||
|
||||
await user.type(
|
||||
screen.getByTestId('azure-tenant-id-manual'),
|
||||
'c983c2cd-94d7-44e1-9c6e-9cfa3a40995f'
|
||||
);
|
||||
await user.type(
|
||||
screen.getByTestId('azure-subscription-id-manual'),
|
||||
'f8f200aa-6234-4bfb-86c2-163d33dffc0c'
|
||||
);
|
||||
await user.type(
|
||||
screen.getByTestId('azure-resource-group-manual'),
|
||||
'testGroup'
|
||||
);
|
||||
const tenantId = screen.getByTestId('azure-tenant-id-manual');
|
||||
expect(tenantId).toHaveValue('');
|
||||
expect(tenantId).toBeEnabled();
|
||||
await user.type(tenantId, 'c983c2cd-94d7-44e1-9c6e-9cfa3a40995f');
|
||||
const subscription = screen.getByTestId('azure-subscription-id-manual');
|
||||
expect(subscription).toHaveValue('');
|
||||
expect(subscription).toBeEnabled();
|
||||
await user.type(subscription, 'f8f200aa-6234-4bfb-86c2-163d33dffc0c');
|
||||
const resourceGroup = screen.getByTestId('azure-resource-group-manual');
|
||||
expect(resourceGroup).toHaveValue('');
|
||||
expect(resourceGroup).toBeEnabled();
|
||||
await user.type(resourceGroup, 'testGroup');
|
||||
|
||||
expect(await getNextButton()).not.toHaveClass('pf-m-disabled');
|
||||
|
||||
|
|
@ -10,20 +10,17 @@ import {
|
|||
within,
|
||||
} from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { rest } from 'msw';
|
||||
|
||||
import api from '../../../api.js';
|
||||
import CreateImageWizard from '../../../Components/CreateImageWizard/CreateImageWizard';
|
||||
import ShareImageModal from '../../../Components/ShareImageModal/ShareImageModal';
|
||||
import { RHEL_8, RHEL_9, PROVISIONING_API } from '../../../constants.js';
|
||||
import { RHEL_8 } from '../../../constants.js';
|
||||
import { mockComposesEmpty } from '../../fixtures/composes';
|
||||
import { customizations } from '../../fixtures/customizations';
|
||||
import { mockPkgResultAlphaContentSources } from '../../fixtures/packages';
|
||||
import { server } from '../../mocks/server.js';
|
||||
import {
|
||||
clickBack,
|
||||
clickNext,
|
||||
getNextButton,
|
||||
renderCustomRoutesWithReduxRouter,
|
||||
} from '../../testUtils';
|
||||
|
||||
|
|
@ -117,168 +114,6 @@ describe('Create Image Wizard', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('Step Upload to AWS', () => {
|
||||
const user = userEvent.setup();
|
||||
const setUp = async () => {
|
||||
({ router, store } = renderCustomRoutesWithReduxRouter(
|
||||
'imagewizard',
|
||||
{},
|
||||
routes
|
||||
));
|
||||
|
||||
// select aws as upload destination
|
||||
const awsTile = await screen.findByTestId('upload-aws');
|
||||
await act(async () => {
|
||||
awsTile.click();
|
||||
});
|
||||
|
||||
await clickNext();
|
||||
|
||||
expect(screen.getByRole('heading', { level: 1 })).toHaveTextContent(
|
||||
'Target environment - Amazon Web Services'
|
||||
);
|
||||
};
|
||||
|
||||
test('component renders error state correctly', async () => {
|
||||
await setUp();
|
||||
server.use(
|
||||
rest.get(`${PROVISIONING_API}/sources`, (_req, res, ctx) =>
|
||||
res(ctx.status(500))
|
||||
)
|
||||
);
|
||||
|
||||
await screen.findByText(
|
||||
/sources cannot be reached, try again later or enter an aws account id manually\./i
|
||||
);
|
||||
});
|
||||
|
||||
test('validation works', async () => {
|
||||
await setUp();
|
||||
|
||||
// jsdom seems to render the next button differently than the browser. The
|
||||
// next button is enabled briefly during the test. This does not occur in
|
||||
// the browser. Using findByRole instead of getByRole to get the next
|
||||
// button allows us to capture its 'final' state.
|
||||
expect(await getNextButton()).toHaveClass('pf-m-disabled');
|
||||
|
||||
await user.click(
|
||||
screen.getByRole('radio', { name: /manually enter an account id\./i })
|
||||
);
|
||||
|
||||
expect(await getNextButton()).toHaveClass('pf-m-disabled');
|
||||
|
||||
await user.type(screen.getByTestId('aws-account-id'), '012345678901');
|
||||
|
||||
expect(await getNextButton()).not.toHaveClass('pf-m-disabled');
|
||||
|
||||
screen
|
||||
.getByRole('radio', { name: /use an account configured from sources\./i })
|
||||
.click();
|
||||
|
||||
expect(await getNextButton()).toHaveClass('pf-m-disabled');
|
||||
|
||||
const sourceDropdown = screen.getByRole('textbox', {
|
||||
name: /select source/i,
|
||||
});
|
||||
// Wait for isSuccess === true, dropdown is disabled while isSuccess === false
|
||||
await waitFor(() => expect(sourceDropdown).toBeEnabled());
|
||||
sourceDropdown.click();
|
||||
|
||||
const source = await screen.findByRole('option', {
|
||||
name: /my_source/i,
|
||||
});
|
||||
source.click();
|
||||
|
||||
expect(await getNextButton()).not.toHaveClass('pf-m-disabled');
|
||||
});
|
||||
|
||||
test('compose request share_with_sources field is correct', async () => {
|
||||
await setUp();
|
||||
|
||||
const sourceDropdown = await screen.findByRole('textbox', {
|
||||
name: /select source/i,
|
||||
});
|
||||
// Wait for isSuccess === true, dropdown is disabled while isSuccess === false
|
||||
await waitFor(() => expect(sourceDropdown).toBeEnabled());
|
||||
await act(async () => {
|
||||
sourceDropdown.click();
|
||||
});
|
||||
|
||||
const source = await screen.findByRole('option', {
|
||||
name: /my_source/i,
|
||||
});
|
||||
await act(async () => {
|
||||
source.click();
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
await clickNext();
|
||||
});
|
||||
|
||||
// registration
|
||||
await screen.findByRole('textbox', {
|
||||
name: 'Select activation key',
|
||||
});
|
||||
|
||||
const registerLaterRadio = screen.getByLabelText('Register later');
|
||||
await act(async () => {
|
||||
await user.click(registerLaterRadio);
|
||||
});
|
||||
|
||||
// click through to review step
|
||||
await act(async () => {
|
||||
await clickNext();
|
||||
await clickNext();
|
||||
await clickNext();
|
||||
await clickNext();
|
||||
await clickNext();
|
||||
});
|
||||
|
||||
const composeImage = jest
|
||||
.spyOn(api, 'composeImage')
|
||||
.mockImplementation((body) => {
|
||||
expect(body).toEqual({
|
||||
distribution: RHEL_9,
|
||||
image_name: undefined,
|
||||
customizations: {
|
||||
packages: undefined,
|
||||
},
|
||||
image_requests: [
|
||||
{
|
||||
architecture: 'x86_64',
|
||||
image_type: 'aws',
|
||||
upload_request: {
|
||||
type: 'aws',
|
||||
options: {
|
||||
share_with_sources: ['123'],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
const id = 'edbae1c2-62bc-42c1-ae0c-3110ab718f5a';
|
||||
return Promise.resolve({ id });
|
||||
});
|
||||
|
||||
const create = screen.getByRole('button', { name: /Create/ });
|
||||
await act(async () => {
|
||||
create.click();
|
||||
});
|
||||
|
||||
// API request sent to backend
|
||||
expect(composeImage).toHaveBeenCalledTimes(1);
|
||||
|
||||
// returns back to the landing page
|
||||
await waitFor(() =>
|
||||
expect(router.state.location.pathname).toBe('/insights/image-builder')
|
||||
);
|
||||
expect(store.getState().composes.allIds).toEqual([
|
||||
'edbae1c2-62bc-42c1-ae0c-3110ab718f5a',
|
||||
]);
|
||||
// set test timeout of 10 seconds
|
||||
}, 10000);
|
||||
});
|
||||
|
||||
describe('Step Packages', () => {
|
||||
const user = userEvent.setup();
|
||||
const setUp = async () => {
|
||||
|
|
|
|||
|
|
@ -10,17 +10,19 @@ import {
|
|||
within,
|
||||
} from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { rest } from 'msw';
|
||||
|
||||
import api from '../../../api.js';
|
||||
import CreateImageWizard from '../../../Components/CreateImageWizard/CreateImageWizard';
|
||||
import ShareImageModal from '../../../Components/ShareImageModal/ShareImageModal';
|
||||
import { RHEL_8 } from '../../../constants.js';
|
||||
import { RHEL_8, RHEL_9, PROVISIONING_API } from '../../../constants.js';
|
||||
import { mockComposesEmpty } from '../../fixtures/composes';
|
||||
import {
|
||||
mockPkgResultAlpha,
|
||||
mockPkgResultAll,
|
||||
mockPkgResultPartial,
|
||||
} from '../../fixtures/packages';
|
||||
import { server } from '../../mocks/server.js';
|
||||
import {
|
||||
clickBack,
|
||||
clickNext,
|
||||
|
|
@ -93,6 +95,23 @@ const searchForChosenPackages = async (searchbox, searchTerm) => {
|
|||
}
|
||||
};
|
||||
|
||||
const switchToAWSManual = () => {
|
||||
const manualRadio = screen.getByRole('radio', {
|
||||
name: /manually enter an account id\./i,
|
||||
});
|
||||
manualRadio.click();
|
||||
return manualRadio;
|
||||
};
|
||||
|
||||
const getSourceDropdown = async () => {
|
||||
const sourceDropdown = screen.getByRole('textbox', {
|
||||
name: /select source/i,
|
||||
});
|
||||
await waitFor(() => expect(sourceDropdown).toBeEnabled());
|
||||
|
||||
return sourceDropdown;
|
||||
};
|
||||
|
||||
beforeAll(() => {
|
||||
// scrollTo is not defined in jsdom
|
||||
window.HTMLElement.prototype.scrollTo = function () {};
|
||||
|
|
@ -141,6 +160,7 @@ describe('Step Image output', () => {
|
|||
|
||||
await clickNext();
|
||||
|
||||
switchToAWSManual();
|
||||
screen.getByText('AWS account ID');
|
||||
});
|
||||
|
||||
|
|
@ -257,7 +277,11 @@ describe('Step Image output', () => {
|
|||
describe('Step Upload to AWS', () => {
|
||||
const user = userEvent.setup();
|
||||
const setUp = async () => {
|
||||
({ router } = renderCustomRoutesWithReduxRouter('imagewizard', {}, routes));
|
||||
({ router, store } = renderCustomRoutesWithReduxRouter(
|
||||
'imagewizard',
|
||||
{},
|
||||
routes
|
||||
));
|
||||
|
||||
// select aws as upload destination
|
||||
const awsTile = screen.getByTestId('upload-aws');
|
||||
|
|
@ -271,8 +295,9 @@ describe('Step Upload to AWS', () => {
|
|||
};
|
||||
|
||||
test('clicking Next loads Registration', async () => {
|
||||
setUp();
|
||||
await setUp();
|
||||
|
||||
switchToAWSManual();
|
||||
await user.type(
|
||||
await screen.findByTestId('aws-account-id'),
|
||||
'012345678901'
|
||||
|
|
@ -304,14 +329,136 @@ describe('Step Upload to AWS', () => {
|
|||
await verifyCancelButton(router);
|
||||
});
|
||||
|
||||
test('the aws account id fieldis shown and required', async () => {
|
||||
test('component renders error state correctly', async () => {
|
||||
await setUp();
|
||||
server.use(
|
||||
rest.get(`${PROVISIONING_API}/sources`, (_req, res, ctx) =>
|
||||
res(ctx.status(500))
|
||||
)
|
||||
);
|
||||
|
||||
await screen.findByText(
|
||||
/sources cannot be reached, try again later or enter an aws account id manually\./i
|
||||
);
|
||||
});
|
||||
|
||||
test('validation works', async () => {
|
||||
await setUp();
|
||||
|
||||
const accessKeyId = screen.getByTestId('aws-account-id');
|
||||
expect(accessKeyId).toHaveValue('');
|
||||
expect(accessKeyId).toBeEnabled();
|
||||
// expect(accessKeyId).toBeRequired(); // DDf does not support required value
|
||||
// jsdom seems to render the next button differently than the browser. The
|
||||
// next button is enabled briefly during the test. This does not occur in
|
||||
// the browser. Using findByRole instead of getByRole to get the next
|
||||
// button allows us to capture its 'final' state.
|
||||
expect(await getNextButton()).toHaveClass('pf-m-disabled');
|
||||
|
||||
await user.click(
|
||||
screen.getByRole('radio', { name: /manually enter an account id\./i })
|
||||
);
|
||||
|
||||
expect(await getNextButton()).toHaveClass('pf-m-disabled');
|
||||
|
||||
const awsAccId = screen.getByTestId('aws-account-id');
|
||||
expect(awsAccId).toHaveValue('');
|
||||
expect(awsAccId).toBeEnabled();
|
||||
await user.type(awsAccId, '012345678901');
|
||||
|
||||
expect(await getNextButton()).not.toHaveClass('pf-m-disabled');
|
||||
|
||||
screen
|
||||
.getByRole('radio', { name: /use an account configured from sources\./i })
|
||||
.click();
|
||||
|
||||
expect(await getNextButton()).toHaveClass('pf-m-disabled');
|
||||
|
||||
const sourceDropdown = await getSourceDropdown();
|
||||
sourceDropdown.click();
|
||||
|
||||
const source = await screen.findByRole('option', {
|
||||
name: /my_source/i,
|
||||
});
|
||||
source.click();
|
||||
|
||||
expect(await getNextButton()).not.toHaveClass('pf-m-disabled');
|
||||
});
|
||||
|
||||
test('compose request share_with_sources field is correct', async () => {
|
||||
await setUp();
|
||||
|
||||
const sourceDropdown = await getSourceDropdown();
|
||||
sourceDropdown.click();
|
||||
|
||||
const source = await screen.findByRole('option', {
|
||||
name: /my_source/i,
|
||||
});
|
||||
await act(async () => {
|
||||
source.click();
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
await clickNext();
|
||||
});
|
||||
|
||||
// registration
|
||||
await screen.findByRole('textbox', {
|
||||
name: 'Select activation key',
|
||||
});
|
||||
|
||||
const registerLaterRadio = screen.getByLabelText('Register later');
|
||||
await act(async () => {
|
||||
await user.click(registerLaterRadio);
|
||||
});
|
||||
|
||||
// click through to review step
|
||||
await act(async () => {
|
||||
await clickNext();
|
||||
await clickNext();
|
||||
await clickNext();
|
||||
await clickNext();
|
||||
});
|
||||
|
||||
const composeImage = jest
|
||||
.spyOn(api, 'composeImage')
|
||||
.mockImplementation((body) => {
|
||||
expect(body).toEqual({
|
||||
distribution: RHEL_9,
|
||||
image_name: undefined,
|
||||
customizations: {
|
||||
packages: undefined,
|
||||
},
|
||||
image_requests: [
|
||||
{
|
||||
architecture: 'x86_64',
|
||||
image_type: 'aws',
|
||||
upload_request: {
|
||||
type: 'aws',
|
||||
options: {
|
||||
share_with_sources: ['123'],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
const id = 'edbae1c2-62bc-42c1-ae0c-3110ab718f5a';
|
||||
return Promise.resolve({ id });
|
||||
});
|
||||
|
||||
const create = screen.getByRole('button', { name: /Create/ });
|
||||
await act(async () => {
|
||||
create.click();
|
||||
});
|
||||
|
||||
// API request sent to backend
|
||||
expect(composeImage).toHaveBeenCalledTimes(1);
|
||||
|
||||
// returns back to the landing page
|
||||
await waitFor(() =>
|
||||
expect(router.state.location.pathname).toBe('/insights/image-builder')
|
||||
);
|
||||
expect(store.getState().composes.allIds).toEqual([
|
||||
'edbae1c2-62bc-42c1-ae0c-3110ab718f5a',
|
||||
]);
|
||||
// set test timeout of 10 seconds
|
||||
}, 10000);
|
||||
});
|
||||
|
||||
describe('Step Upload to Google', () => {
|
||||
|
|
@ -380,83 +527,6 @@ describe('Step Upload to Google', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('Step Upload to Azure', () => {
|
||||
const user = userEvent.setup();
|
||||
const setUp = async () => {
|
||||
({ router } = renderCustomRoutesWithReduxRouter('imagewizard', {}, routes));
|
||||
|
||||
// select aws as upload destination
|
||||
const awsTile = screen.getByTestId('upload-azure');
|
||||
await awsTile.click();
|
||||
await clickNext();
|
||||
|
||||
expect(screen.getByRole('heading', { level: 1 })).toHaveTextContent(
|
||||
'Target environment - Microsoft Azure'
|
||||
);
|
||||
};
|
||||
|
||||
test('clicking Next loads Registration', async () => {
|
||||
await setUp();
|
||||
// Randomly generated GUID
|
||||
await user.type(
|
||||
screen.getByTestId('azure-tenant-id'),
|
||||
'b8f86d22-4371-46ce-95e7-65c415f3b1e2'
|
||||
);
|
||||
await user.type(
|
||||
screen.getByTestId('azure-subscription-id'),
|
||||
'60631143-a7dc-4d15-988b-ba83f3c99711'
|
||||
);
|
||||
await user.type(
|
||||
screen.getByTestId('azure-resource-group'),
|
||||
'testResourceGroup'
|
||||
);
|
||||
await act(async () => {
|
||||
await clickNext();
|
||||
});
|
||||
|
||||
await screen.findByRole('textbox', {
|
||||
name: 'Select activation key',
|
||||
});
|
||||
|
||||
await screen.findByText(
|
||||
'Automatically register and enable advanced capabilities'
|
||||
);
|
||||
});
|
||||
|
||||
test('clicking Back loads Release', async () => {
|
||||
await setUp();
|
||||
|
||||
await clickBack();
|
||||
|
||||
screen.getByTestId('upload-azure');
|
||||
});
|
||||
|
||||
test('clicking Cancel loads landing page', async () => {
|
||||
await setUp();
|
||||
|
||||
await verifyCancelButton(router);
|
||||
});
|
||||
|
||||
test('the azure upload fields are shown and required', async () => {
|
||||
await setUp();
|
||||
|
||||
const tenantId = screen.getByTestId('azure-tenant-id');
|
||||
expect(tenantId).toHaveValue('');
|
||||
expect(tenantId).toBeEnabled();
|
||||
// expect(tenantId).toBeRequired(); // DDf does not support required value
|
||||
|
||||
const subscription = screen.getByTestId('azure-subscription-id');
|
||||
expect(subscription).toHaveValue('');
|
||||
expect(subscription).toBeEnabled();
|
||||
// expect(subscription).toBeRequired(); // DDf does not support required value
|
||||
|
||||
const resourceGroup = screen.getByTestId('azure-resource-group');
|
||||
expect(resourceGroup).toHaveValue('');
|
||||
expect(resourceGroup).toBeEnabled();
|
||||
// expect(resourceGroup).toBeRequired(); // DDf does not support required value
|
||||
});
|
||||
});
|
||||
|
||||
describe('Step Registration', () => {
|
||||
const user = userEvent.setup();
|
||||
const setUp = async () => {
|
||||
|
|
@ -469,6 +539,9 @@ describe('Step Registration', () => {
|
|||
await act(async () => {
|
||||
await clickNext();
|
||||
});
|
||||
await user.click(
|
||||
screen.getByRole('radio', { name: /manually enter an account id\./i })
|
||||
);
|
||||
await user.type(screen.getByTestId('aws-account-id'), '012345678901');
|
||||
await act(async () => {
|
||||
await clickNext();
|
||||
|
|
@ -497,6 +570,9 @@ describe('Step Registration', () => {
|
|||
|
||||
await clickBack();
|
||||
|
||||
await user.click(
|
||||
screen.getByRole('radio', { name: /manually enter an account id\./i })
|
||||
);
|
||||
screen.getByText('AWS account ID');
|
||||
});
|
||||
|
||||
|
|
@ -745,6 +821,7 @@ describe('Step File system configuration', () => {
|
|||
});
|
||||
|
||||
// aws step
|
||||
switchToAWSManual();
|
||||
await user.type(screen.getByTestId('aws-account-id'), '012345678901');
|
||||
await act(async () => {
|
||||
await clickNext();
|
||||
|
|
@ -817,6 +894,7 @@ describe('Step Packages', () => {
|
|||
});
|
||||
|
||||
// aws step
|
||||
switchToAWSManual();
|
||||
const aai = screen.getByTestId('aws-account-id');
|
||||
await act(async () => {
|
||||
await user.type(aai, '012345678901');
|
||||
|
|
@ -1265,6 +1343,7 @@ describe('Step Details', () => {
|
|||
});
|
||||
|
||||
// aws step
|
||||
switchToAWSManual();
|
||||
await user.type(screen.getByTestId('aws-account-id'), '012345678901');
|
||||
await act(async () => {
|
||||
await clickNext();
|
||||
|
|
@ -1337,6 +1416,7 @@ describe('Step Review', () => {
|
|||
});
|
||||
|
||||
// aws step
|
||||
switchToAWSManual();
|
||||
await user.type(screen.getByTestId('aws-account-id'), '012345678901');
|
||||
await act(async () => {
|
||||
await clickNext();
|
||||
|
|
@ -1388,6 +1468,7 @@ describe('Step Review', () => {
|
|||
});
|
||||
|
||||
// aws step
|
||||
switchToAWSManual();
|
||||
await user.type(screen.getByTestId('aws-account-id'), '012345678901');
|
||||
await act(async () => {
|
||||
await clickNext();
|
||||
|
|
@ -1507,6 +1588,9 @@ describe('Click through all steps', () => {
|
|||
await act(async () => {
|
||||
bn.click();
|
||||
});
|
||||
await user.click(
|
||||
screen.getByRole('radio', { name: /manually enter an account id\./i })
|
||||
);
|
||||
await user.type(screen.getByTestId('aws-account-id'), '012345678901');
|
||||
const bn1 = screen.getByRole('button', { name: /Next/ });
|
||||
await act(async () => {
|
||||
|
|
@ -1519,17 +1603,18 @@ describe('Click through all steps', () => {
|
|||
bn2.click();
|
||||
});
|
||||
|
||||
await user.click(screen.getByTestId('azure-radio-manual'));
|
||||
// Randomly generated GUID
|
||||
await user.type(
|
||||
screen.getByTestId('azure-tenant-id'),
|
||||
screen.getByTestId('azure-tenant-id-manual'),
|
||||
'b8f86d22-4371-46ce-95e7-65c415f3b1e2'
|
||||
);
|
||||
await user.type(
|
||||
screen.getByTestId('azure-subscription-id'),
|
||||
screen.getByTestId('azure-subscription-id-manual'),
|
||||
'60631143-a7dc-4d15-988b-ba83f3c99711'
|
||||
);
|
||||
await user.type(
|
||||
screen.getByTestId('azure-resource-group'),
|
||||
screen.getByTestId('azure-resource-group-manual'),
|
||||
'testResourceGroup'
|
||||
);
|
||||
const bn3 = screen.getByRole('button', { name: /Next/ });
|
||||
|
|
@ -1994,9 +2079,14 @@ describe('Keyboard accessibility', () => {
|
|||
});
|
||||
|
||||
// Target environment aws
|
||||
const awsInput = screen.getByRole('textbox', { name: /aws account id/i });
|
||||
expect(awsInput).toHaveFocus();
|
||||
await user.type(awsInput, '012345678901');
|
||||
expect(screen.getByTestId('aws-radio-source')).toHaveFocus();
|
||||
const awsSourceDropdown = await getSourceDropdown();
|
||||
awsSourceDropdown.click();
|
||||
const awsSource = await screen.findByRole('option', {
|
||||
name: /my_source/i,
|
||||
});
|
||||
awsSource.click();
|
||||
|
||||
await act(async () => {
|
||||
await clickNext();
|
||||
});
|
||||
|
|
@ -2012,20 +2102,19 @@ describe('Keyboard accessibility', () => {
|
|||
});
|
||||
|
||||
// Target environment azure
|
||||
const tenantIDInput = screen.getByTestId('azure-tenant-id');
|
||||
expect(tenantIDInput).toHaveFocus();
|
||||
await user.type(
|
||||
screen.getByTestId('azure-tenant-id'),
|
||||
'b8f86d22-4371-46ce-95e7-65c415f3b1e2'
|
||||
);
|
||||
await user.type(
|
||||
screen.getByTestId('azure-subscription-id'),
|
||||
'60631143-a7dc-4d15-988b-ba83f3c99711'
|
||||
);
|
||||
await user.type(
|
||||
screen.getByTestId('azure-resource-group'),
|
||||
'testResourceGroup'
|
||||
);
|
||||
expect(screen.getByTestId('azure-radio-source')).toHaveFocus();
|
||||
const azureSourceDropdown = await getSourceDropdown();
|
||||
azureSourceDropdown.click();
|
||||
const azureSource = await screen.findByRole('option', {
|
||||
name: /azureSource1/i,
|
||||
});
|
||||
azureSource.click();
|
||||
|
||||
const resourceGroupDropdown = await screen.findByRole('textbox', {
|
||||
name: /select resource group/i,
|
||||
});
|
||||
await user.click(resourceGroupDropdown);
|
||||
await user.click(screen.getByLabelText('Resource group myResourceGroup1'));
|
||||
await act(async () => {
|
||||
await clickNext();
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue