Skip to content

Commit 0fab318

Browse files
committed
Merge branch 'master' of https://github.com/RedHatInsights/sources-ui into add_member_sort
# Conflicts: # src/components/addSourceWizard/hardcodedComponents/azure/subscriptionWatch.js # src/test/components/addApplication/addApplicationSchema.test.js
2 parents 946557d + a65ffe2 commit 0fab318

File tree

11 files changed

+207
-81
lines changed

11 files changed

+207
-81
lines changed

src/api/entities.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ export const getSourcesApi = () => ({
6767
unpauseApplication: (id) => axiosInstanceInsights.post(`${SOURCES_API_BASE_V3}/applications/${id}/unpause`),
6868
pauseSource: (id) => axiosInstanceInsights.post(`${SOURCES_API_BASE_V3}/sources/${id}/pause`),
6969
unpauseSource: (id) => axiosInstanceInsights.post(`${SOURCES_API_BASE_V3}/sources/${id}/unpause`),
70+
getLighthouseLink: () =>
71+
axiosInstanceInsights.get(`${SOURCES_API_BASE_V3}/app_meta_data?filter[name]=azure_lighthouse_template`),
7072
});
7173

7274
export const doLoadAppTypes = () => getSourcesApi().doLoadAppTypes();

src/components/FormComponents/SourceWizardSummary.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const alertMapper = (appName, sourceType, intl) => {
4343
);
4444
}
4545

46-
if (appName === CLOUD_METER_APP_NAME && ['azure', 'google'].includes(sourceType)) {
46+
if (appName === CLOUD_METER_APP_NAME && ['google'].includes(sourceType)) {
4747
return (
4848
<Alert
4949
variant="info"
Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,75 @@
1-
import React from 'react';
1+
import React, { useEffect, useState } from 'react';
22
import { useIntl } from 'react-intl';
33

4-
import { ClipboardCopy, Text, TextContent, TextList, TextListItem, TextListVariants, TextVariants } from '@patternfly/react-core';
4+
import { Button, Text, TextContent } from '@patternfly/react-core';
5+
import { getSourcesApi } from '../../../../api/entities';
6+
import useFormApi from '@data-driven-forms/react-form-renderer/use-form-api';
57

6-
const API_LINK = 'https://access.redhat.com/management/api';
7-
8-
export const OfflineToken = () => {
8+
export const LightHouseDescription = () => {
99
const intl = useIntl();
10+
const [link, setLink] = useState();
11+
const [error, setError] = useState(null);
12+
13+
const formOptions = useFormApi();
14+
15+
useEffect(() => {
16+
getSourcesApi()
17+
.getLighthouseLink()
18+
.then(({ data }) => setLink(data?.[0]?.payload))
19+
.catch((e) => {
20+
// eslint-disable-next-line no-console
21+
console.error(e);
22+
setError(
23+
intl.formatMessage({
24+
id: 'subwatch.iampolicy.subWatchConfigError',
25+
defaultMessage: 'There is an error with loading of the configuration. Please go back and return to this step.',
26+
})
27+
);
28+
});
29+
}, []);
1030

1131
return (
1232
<TextContent>
1333
<Text>
1434
{intl.formatMessage({
15-
id: 'subwatch.azure.tokenDesc',
16-
defaultMessage: 'Generate a token to authenticate the calls to APIs for Red Hat services.',
35+
id: 'subwatch.lighthouse.desc',
36+
defaultMessage:
37+
"Complete configuration steps in Azure Lighthouse according to Microsoft instructions. When you're finished, return to this wizard to finish creating this Azure source.",
1738
})}
1839
</Text>
19-
<TextList component={TextListVariants.ol} className="pf-u-ml-0">
20-
<TextListItem>
21-
{intl.formatMessage(
22-
{
23-
id: 'subwatch.azure.tokenLink',
24-
defaultMessage: 'To obtain an offline token, follow the steps at {link}.',
25-
},
26-
{
27-
link: (
28-
<Text key="link" rel="noopener noreferrer" target="_blank" component={TextVariants.a} href={API_LINK}>
29-
{API_LINK}
30-
</Text>
31-
),
32-
}
33-
)}
34-
</TextListItem>
35-
</TextList>
40+
<Button
41+
component="a"
42+
target="_blank"
43+
rel="noopener noreferrer"
44+
href={link}
45+
isLoading={!link}
46+
isDisabled={!link}
47+
onClick={() => {
48+
formOptions.change('lighthouse-clicked', true);
49+
}}
50+
>
51+
{intl.formatMessage({
52+
id: 'subwatch.lighthouse.button',
53+
defaultMessage: 'Take me to Lighthouse',
54+
})}
55+
</Button>
56+
{error}
3657
</TextContent>
3758
);
3859
};
3960

40-
export const AnsiblePlaybook = () => {
61+
export const SubscriptionID = () => {
4162
const intl = useIntl();
4263

4364
return (
4465
<TextContent>
45-
<Text component={TextVariants.p}>
66+
<Text>
4667
{intl.formatMessage({
47-
id: 'subwatch.azure.ansiblePlaybookDesc',
48-
defaultMessage: 'Download and run the following commands against a running Azure VM.',
68+
id: 'subwatch.subscriptionId.desc',
69+
defaultMessage:
70+
'Log in to your Azure account and navigate to your subscriptions. Copy the subscription ID you wish to use and paste it into the field below.',
4971
})}
5072
</Text>
51-
<ClipboardCopy className="pf-u-mb-lg">ansible-galaxy collection install redhatinsights.subscriptions</ClipboardCopy>
52-
<ClipboardCopy>
53-
{
54-
'ansible-playbook -i <AZURE_VM_HOSTNAME>, -b ~/.ansible/collections/ansible_collections/redhatinsights/subscriptions/playbooks/verify_account.yml -e rh_api_refresh_token=<OFFLINE_AUTH_TOKEN>'
55-
}
56-
</ClipboardCopy>
5773
</TextContent>
5874
);
5975
};

src/components/addSourceWizard/hardcodedSchemas.js

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -332,43 +332,52 @@ const hardcodedSchemas = {
332332
},
333333
},
334334
},
335-
[emptyAuthType.type]: {
335+
lighthouse_subscription_id: {
336336
[CLOUD_METER_APP_NAME]: {
337337
skipSelection: true,
338338
useApplicationAuth: true,
339339
customSteps: true,
340340
additionalSteps: [
341341
{
342-
title: <FormattedMessage id="subwatch.azure.tokenTitle" defaultMessage="Obtain offline token" />,
343-
nextStep: 'cost-azure-playbook',
344-
substepOf: {
345-
name: 'eaa',
346-
title: <FormattedMessage id="subwatch.azure.substepTitle" defaultMessage="Enable account access" />,
347-
},
342+
title: <FormattedMessage id="subwatch.lighthouse.title" defaultMessage="Configure Azure Lighthouse" />,
343+
nextStep: 'subwatch-lighthouse-sub-id',
348344
fields: [
349345
{
350346
name: 'azure-1',
351347
component: 'description',
352-
Content: SWAzure.OfflineToken,
348+
Content: SWAzure.LightHouseDescription,
353349
},
354350
{
355351
component: componentTypes.TEXT_FIELD,
356352
name: 'authentication.authtype',
357353
hideField: true,
358-
initialValue: emptyAuthType.type,
354+
initialValue: 'lighthouse_subscription_id',
359355
initializeOnMount: true,
360356
},
357+
{
358+
component: componentTypes.TEXT_FIELD,
359+
name: 'lighthouse-clicked',
360+
hideField: true,
361+
validate: [{ type: 'required' }],
362+
},
361363
],
362364
},
363365
{
364-
title: <FormattedMessage id="subwatch.azure.playbookTitle" defaultMessage="Run Ansible playbook" />,
365-
name: 'cost-azure-playbook',
366-
substepOf: 'eaa',
366+
title: <FormattedMessage id="subwatch.lighthouse.subscriptionId" defaultMessage="Set subscription ID" />,
367+
name: 'subwatch-lighthouse-sub-id',
367368
fields: [
368369
{
369370
name: 'azure-2',
370371
component: 'description',
371-
Content: SWAzure.AnsiblePlaybook,
372+
Content: SWAzure.SubscriptionID,
373+
},
374+
{
375+
component: 'text-field',
376+
name: 'authentication.username',
377+
label: 'Subscription ID',
378+
isRequired: true,
379+
placeholder: '291bba3f-e0a5-47bc-a099-3bdcb2a50a05',
380+
validate: [{ type: 'required' }],
372381
},
373382
],
374383
},

src/test/__mocks__/applicationTypes.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export const SUB_WATCH_APP = {
5050
display_name: 'RHEL management',
5151
id: '5',
5252
name: '/insights/platform/cloud-meter',
53-
supported_authentication_types: { amazon: ['cloud-meter-arn'] },
53+
supported_authentication_types: { amazon: ['cloud-meter-arn'], azure: ['lighthouse_subscription_id'] },
5454
supported_source_types: ['amazon', 'azure', 'google'],
5555
updated_at: '2020-02-18T19:38:52Z',
5656
};

src/test/__mocks__/sourceTypes.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,26 @@ export const AZURE_TYPE = {
315315
icon_url: '/apps/chrome/assets/images/partners-icons/microsoft-azure.svg',
316316
schema: {
317317
authentication: [
318+
{
319+
type: 'lighthouse_subscription_id',
320+
name: 'Subscription ID',
321+
fields: [
322+
{
323+
component: 'text-field',
324+
name: 'authentication.authtype',
325+
hideField: true,
326+
initializeOnMount: true,
327+
initialValue: 'lighthouse_subscription_id',
328+
},
329+
{
330+
component: 'text-field',
331+
name: 'authentication.username',
332+
label: 'Subscription ID',
333+
isRequired: true,
334+
validate: [{ type: 'required' }],
335+
},
336+
],
337+
},
318338
{
319339
type: 'tenant_id_client_id_client_secret',
320340
name: 'Tenant ID, Client ID, Client Secret',
Lines changed: 74 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,87 @@
11
import React from 'react';
2-
import { screen } from '@testing-library/react';
2+
import { screen, waitFor } from '@testing-library/react';
3+
import userEvent from '@testing-library/user-event';
34

45
import render from '../../__mocks__/render';
56

67
import * as SubAzure from '../../../../components/addSourceWizard/hardcodedComponents/azure/subscriptionWatch';
8+
import * as api from '../../../../api/entities';
9+
import * as useFormApi from '@data-driven-forms/react-form-renderer/use-form-api/use-form-api';
710

811
describe('Azure-Subwatch hardcoded schemas', () => {
9-
it('OfflineToken is rendered correctly', () => {
10-
render(<SubAzure.OfflineToken />);
12+
describe('LightHouseDescription', () => {
13+
it('is rendered correctly', async () => {
14+
const getLighthouseLink = mockApi();
1115

12-
expect(screen.getByText('Generate a token to authenticate the calls to APIs for Red Hat services.')).toBeInTheDocument();
13-
expect(screen.getByText('To obtain an offline token, follow the steps at', { exact: false })).toBeInTheDocument();
14-
expect(screen.getByText('https://access.redhat.com/management/api', { selector: 'a' })).toBeInTheDocument();
16+
api.getSourcesApi = () => ({
17+
getLighthouseLink,
18+
});
19+
20+
render(<SubAzure.LightHouseDescription />);
21+
22+
expect(
23+
screen.getByText(
24+
"Complete configuration steps in Azure Lighthouse according to Microsoft instructions. When you're finished, return to this wizard to finish creating this Azure source."
25+
)
26+
).toBeInTheDocument();
27+
expect(screen.getByText('Take me to Lighthouse')).toHaveAttribute('aria-disabled', 'true');
28+
29+
getLighthouseLink.resolve({ data: [{ payload: 'href123' }] });
30+
31+
await waitFor(() => expect(screen.getByText('Take me to Lighthouse')).not.toHaveAttribute('aria-disabled', 'true'));
32+
expect(screen.getByText('Take me to Lighthouse')).toHaveAttribute('href', 'href123');
33+
});
34+
35+
it('is rendered with error', async () => {
36+
const _cons = console.error;
37+
console.error = jest.fn();
38+
39+
const getLighthouseLink = mockApi();
40+
41+
api.getSourcesApi = () => ({
42+
getLighthouseLink,
43+
});
44+
45+
render(<SubAzure.LightHouseDescription />);
46+
47+
getLighthouseLink.reject();
48+
49+
await waitFor(() => expect(screen.getByText('Take me to Lighthouse')).toHaveAttribute('aria-disabled', 'true'));
50+
expect(
51+
screen.getByText('There is an error with loading of the configuration. Please go back and return to this step.')
52+
).toBeInTheDocument();
53+
54+
console.error = _cons;
55+
});
56+
57+
it('button changes the value', async () => {
58+
const change = jest.fn();
59+
60+
const mock = jest.spyOn(useFormApi, 'default').mockImplementation(() => ({ change }));
61+
62+
api.getSourcesApi = () => ({
63+
getLighthouseLink: jest.fn().mockResolvedValue({ data: [{ payload: 'href123' }] }),
64+
});
65+
66+
render(<SubAzure.LightHouseDescription />);
67+
68+
const user = userEvent.setup();
69+
70+
await user.click(screen.getByText('Take me to Lighthouse'));
71+
72+
expect(change).toHaveBeenCalledWith('lighthouse-clicked', true);
73+
74+
mock.mockRestore();
75+
});
1576
});
1677

17-
it('AnsiblePlaybook is rendered correctly', () => {
18-
render(<SubAzure.AnsiblePlaybook />);
78+
it('SubscriptionID is rendered correctly', () => {
79+
render(<SubAzure.SubscriptionID />);
1980

20-
expect(screen.getByText('Download and run the following commands against a running Azure VM.')).toBeInTheDocument();
21-
expect(screen.getAllByLabelText('Copyable input')[0]).toHaveValue(
22-
'ansible-galaxy collection install redhatinsights.subscriptions'
23-
);
24-
expect(screen.getAllByLabelText('Copyable input')[1]).toHaveValue(
25-
'ansible-playbook -i <AZURE_VM_HOSTNAME>, -b ~/.ansible/collections/ansible_collections/redhatinsights/subscriptions/playbooks/verify_account.yml -e rh_api_refresh_token=<OFFLINE_AUTH_TOKEN>'
26-
);
81+
expect(
82+
screen.getByText(
83+
'Log in to your Azure account and navigate to your subscriptions. Copy the subscription ID you wish to use and paste it into the field below.'
84+
)
85+
).toBeInTheDocument();
2786
});
2887
});

src/test/addSourceWizard/addSourceWizard/schemaBuilder.test.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ describe('schema builder', () => {
316316

317317
describe('createAuthTypeSelection', () => {
318318
it('generate single selection', () => {
319-
const fields = AZURE_TYPE.schema.authentication[0].fields.filter(({ stepKey }) => !stepKey);
319+
const fields = AZURE_TYPE.schema.authentication[1].fields.filter(({ stepKey }) => !stepKey);
320320
const expectedName = `${AZURE_TYPE.name}-${TOPOLOGY_INV_APP.id}`;
321321

322322
expectedSchema = expect.objectContaining({
@@ -342,7 +342,7 @@ describe('schema builder', () => {
342342
});
343343

344344
it('generate single selection with endpoints', () => {
345-
const fields = AZURE_TYPE.schema.authentication[0].fields.filter(({ stepKey }) => !stepKey);
345+
const fields = AZURE_TYPE.schema.authentication[1].fields.filter(({ stepKey }) => !stepKey);
346346
const expectedName = `${AZURE_TYPE.name}-${TOPOLOGY_INV_APP.id}`;
347347

348348
expectedSchema = expect.objectContaining({
@@ -417,12 +417,12 @@ describe('schema builder', () => {
417417
'azure-2',
418418
'azure-3',
419419
'azure-5',
420+
'azure-lighthouse_subscription_id-/insights/platform/cloud-meter-additional-step',
421+
'subwatch-lighthouse-sub-id',
420422
'azure-tenant_id_client_id_client_secret-/insights/platform/cost-management-additional-step',
421423
'azure-sub-id',
422424
'configure-roles',
423425
'export-schedule',
424-
'azure-empty-/insights/platform/cloud-meter-additional-step',
425-
'cost-azure-playbook',
426426
'google-generic',
427427
'google-2',
428428
'google-5',

src/test/api/entities.test.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,15 @@ describe('entities spec', () => {
264264

265265
expect(result).toEqual(OK_RESPONSE);
266266
});
267+
268+
it('getLighthouseLink', async () => {
269+
const method = 'Get';
270+
mock[`on${method}`](`/api/sources/v3.1/app_meta_data?filter[name]=azure_lighthouse_template`).reply(200, OK_RESPONSE);
271+
272+
const result = await api.getSourcesApi().getLighthouseLink();
273+
274+
expect(result).toEqual(OK_RESPONSE);
275+
});
267276
});
268277

269278
it('doRemoveSource fails', async () => {

0 commit comments

Comments
 (0)