Skip to content
This repository has been archived by the owner on Sep 5, 2024. It is now read-only.

[#857] Add skeleton for Conversion Hosts Settings components #858

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions app/javascript/react/screens/App/Settings/Settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,14 @@ import ConversionHostsSettings from './screens/ConversionHostsSettings';
const Settings = props => {
const { match, redirectTo } = props;

// TODO remove this when we are ready to release ConversionHostsSettings
const hideConversionHostSettings = true;

return (
<React.Fragment>
<Toolbar>
<Breadcrumb.Item href="/dashboard/maintab?tab=compute">{__('Compute')}</Breadcrumb.Item>
<Breadcrumb.Item href="#/plans">{__('Migration')}</Breadcrumb.Item>
<Breadcrumb.Item active>{__('Migration Settings')}</Breadcrumb.Item>
</Toolbar>
{hideConversionHostSettings ? (
{props.hideConversionHostSettings ? (
<React.Fragment>
<h2>{__('Concurrent Migrations')}</h2>
<GeneralSettings />
Expand All @@ -41,7 +38,8 @@ const Settings = props => {

Settings.propTypes = {
match: PropTypes.object,
redirectTo: PropTypes.func
redirectTo: PropTypes.func,
hideConversionHostSettings: PropTypes.bool // TODO remove this when we are ready to release ConversionHostsSettings
};

export default Settings;
24 changes: 23 additions & 1 deletion app/javascript/react/screens/App/Settings/SettingsActions.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import URI from 'urijs';
import API from '../../../../common/API';

import { V2V_FETCH_SERVERS, V2V_FETCH_SETTINGS, V2V_PATCH_SETTINGS } from './SettingsConstants';
import {
V2V_FETCH_SERVERS,
V2V_FETCH_SETTINGS,
V2V_PATCH_SETTINGS,
FETCH_V2V_CONVERSION_HOSTS,
SHOW_V2V_CONVERSION_HOST_WIZARD,
HIDE_V2V_CONVERSION_HOST_WIZARD
} from './SettingsConstants';
import { getApiSettingsFromFormValues } from './helpers';

const _getServersActionCreator = url => dispatch =>
Expand Down Expand Up @@ -42,3 +49,18 @@ export const patchSettingsAction = (servers, newSettings) => {
const settingsUrls = servers.map(server => new URI(`${server.href}/settings`).toString());
return _patchSettingsActionCreator(settingsUrls, newSettings);
};

const _getConversionHostsActionCreator = url => dispatch =>
dispatch({
type: FETCH_V2V_CONVERSION_HOSTS,
payload: API.get(url)
});

export const fetchConversionHostsAction = url => {
const uri = new URI(url);
return _getConversionHostsActionCreator(uri.toString());
};

export const showConversionHostWizard = () => dispatch => dispatch({ type: SHOW_V2V_CONVERSION_HOST_WIZARD });

export const hideConversionHostWizard = () => dispatch => dispatch({ type: HIDE_V2V_CONVERSION_HOST_WIZARD });
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
export const V2V_FETCH_SERVERS = 'V2V_FETCH_SERVERS';
export const V2V_FETCH_SETTINGS = 'V2V_FETCH_SETTINGS';
export const V2V_PATCH_SETTINGS = 'V2V_PATCH_SETTINGS';
export const FETCH_V2V_CONVERSION_HOSTS = 'FETCH_V2V_CONVERSION_HOSTS';
export const SHOW_V2V_CONVERSION_HOST_WIZARD = 'SHOW_V2V_CONVERSION_HOST_WIZARD';
export const HIDE_V2V_CONVERSION_HOST_WIZARD = 'HIDE_V2V_CONVERSION_HOST_WIZARD';
39 changes: 37 additions & 2 deletions app/javascript/react/screens/App/Settings/SettingsReducer.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import Immutable from 'seamless-immutable';

import { V2V_FETCH_SERVERS, V2V_FETCH_SETTINGS, V2V_PATCH_SETTINGS } from './SettingsConstants';
import {
V2V_FETCH_SERVERS,
V2V_FETCH_SETTINGS,
V2V_PATCH_SETTINGS,
FETCH_V2V_CONVERSION_HOSTS,
SHOW_V2V_CONVERSION_HOST_WIZARD,
HIDE_V2V_CONVERSION_HOST_WIZARD
} from './SettingsConstants';

import { getFormValuesFromApiSettings } from './helpers';

export const initialState = Immutable({
Expand All @@ -14,7 +22,12 @@ export const initialState = Immutable({
savedSettings: {},
isSavingSettings: false,
savingSettingsRejected: false,
errorSavingSettings: null
errorSavingSettings: null,
isFetchingConversionHosts: false,
isRejectedConversionHosts: false,
errorFetchingConversionHosts: null,
conversionHosts: [],
conversionHostWizardVisible: false
});

export default (state = initialState, action) => {
Expand Down Expand Up @@ -70,6 +83,28 @@ export default (state = initialState, action) => {
.set('errorSavingSettings', null)
.set('savedSettings', getFormValuesFromApiSettings(action.payload));

case `${FETCH_V2V_CONVERSION_HOSTS}_PENDING`:
return state
.set('isFetchingConversionHosts', true)
.set('isRejectedConversionHosts', false)
.set('errorFetchingConversionHosts', null);
case `${FETCH_V2V_CONVERSION_HOSTS}_FULFILLED`:
mturley marked this conversation as resolved.
Show resolved Hide resolved
return state
.set('conversionHosts', action.payload.data.resources)
.set('isFetchingConversionHosts', false)
.set('isRejectedConversionHosts', false)
.set('errorFetchingConversionHosts', null);
case `${FETCH_V2V_CONVERSION_HOSTS}_REJECTED`:
return state
.set('isFetchingConversionHosts', false)
.set('isRejectedConversionHosts', true)
.set('errorFetchingConversionHosts', action.payload);

case SHOW_V2V_CONVERSION_HOST_WIZARD:
return state.set('conversionHostWizardVisible', true);
case HIDE_V2V_CONVERSION_HOST_WIZARD:
return state.set('conversionHostWizardVisible', false);

default:
return state;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';
import { shallow } from 'enzyme';
import Settings from '../Settings';

describe('Settings component', () => {
it('renders correctly', () => {
const component = shallow(<Settings match={{ path: '/settings' }} />);
expect(component).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import {
fetchSettingsData,
patchSettingsData
} from '../settings.fixures';
import { requestConversionHostsData } from '../../Mappings/screens/MappingWizard/components/MappingWizardGeneralStep/mappingWizardGeneralStep.fixtures';
import { initialState } from '../SettingsReducer';
import { mockRequest, mockReset } from '../../../../../common/mockRequests';
import { SHOW_V2V_CONVERSION_HOST_WIZARD, HIDE_V2V_CONVERSION_HOST_WIZARD } from '../SettingsConstants';

const middlewares = [thunk, promiseMiddleware()];
const mockStore = configureMockStore(middlewares);
Expand Down Expand Up @@ -100,4 +102,36 @@ describe('settings actions', () => {
expect(store.getActions()).toMatchSnapshot();
});
});

it('should fetch conversion hosts and return PENDING and FULFILLED action', () => {
mturley marked this conversation as resolved.
Show resolved Hide resolved
const { fetchConversionHostsUrl } = requestConversionHostsData;
mockRequest({
url: fetchConversionHostsUrl,
status: 200
});
return store.dispatch(actions.fetchConversionHostsAction(fetchConversionHostsUrl)).then(() => {
expect(store.getActions()).toMatchSnapshot();
});
});

it('should fetch conversion hosts and return PENDING and REJECTED action', () => {
mturley marked this conversation as resolved.
Show resolved Hide resolved
const { fetchConversionHostsUrl } = requestConversionHostsData;
mockRequest({
url: fetchConversionHostsUrl,
status: 500
});
return store.dispatch(actions.fetchConversionHostsAction(fetchConversionHostsUrl)).catch(() => {
expect(store.getActions()).toMatchSnapshot();
});
});

it('should dispatch show wizard action', () => {
mturley marked this conversation as resolved.
Show resolved Hide resolved
store.dispatch(actions.showConversionHostWizard());
expect(store.getActions()).toEqual([{ type: SHOW_V2V_CONVERSION_HOST_WIZARD }]);
});

it('should dispatch hide wizard action', () => {
mturley marked this conversation as resolved.
Show resolved Hide resolved
store.dispatch(actions.hideConversionHostWizard());
expect(store.getActions()).toEqual([{ type: HIDE_V2V_CONVERSION_HOST_WIZARD }]);
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import settingsReducer, { initialState } from '../SettingsReducer';
import { V2V_FETCH_SERVERS, V2V_FETCH_SETTINGS, V2V_PATCH_SETTINGS } from '../SettingsConstants';
import {
V2V_FETCH_SERVERS,
V2V_FETCH_SETTINGS,
V2V_PATCH_SETTINGS,
FETCH_V2V_CONVERSION_HOSTS,
SHOW_V2V_CONVERSION_HOST_WIZARD,
HIDE_V2V_CONVERSION_HOST_WIZARD
} from '../SettingsConstants';
import { servers, settings } from '../settings.fixures';

it('sets default state', () => {
Expand Down Expand Up @@ -102,3 +109,49 @@ describe('saving settings', () => {
expect(state).toMatchSnapshot();
});
});

describe('fetching conversion hosts', () => {
it('is pending', () => {
const action = {
type: `${FETCH_V2V_CONVERSION_HOSTS}_PENDING`
};
const prevState = initialState.set('isRejectedConversionHosts', true);
const state = settingsReducer(prevState, action);
expect(state).toMatchSnapshot();
});

it('is rejected', () => {
const action = {
type: `${FETCH_V2V_CONVERSION_HOSTS}_REJECTED`,
payload: 'error'
};
const prevState = initialState.set('isFetchingConversionHosts', true);
const state = settingsReducer(prevState, action);
expect(state).toMatchSnapshot();
});

it('is successful', () => {
const action = {
type: `${FETCH_V2V_CONVERSION_HOSTS}_FULFILLED`,
payload: { data: { resources: [{ mock: 'conversionHost' }] } }
};
const prevState = initialState.set('isRejectedConversionHosts', true).set('isFetchingConversionHosts', true);
const state = settingsReducer(prevState, action);
expect(state).toMatchSnapshot();
});
});

describe('showing and hiding the conversion host wizard', () => {
it('shows', () => {
const action = { type: SHOW_V2V_CONVERSION_HOST_WIZARD };
const state = settingsReducer(initialState, action);
expect(state.conversionHostWizardVisible).toBeTruthy();
});

it('hides', () => {
const action = { type: HIDE_V2V_CONVERSION_HOST_WIZARD };
const prevState = initialState.set('conversionHostWizardVisible', true);
const state = settingsReducer(prevState, action);
expect(state.conversionHostWizardVisible).toBeFalsy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Settings component renders correctly 1`] = `
<React.Fragment>
<Toolbar>
<BreadcrumbItem
active={false}
href="/dashboard/maintab?tab=compute"
>
Compute
</BreadcrumbItem>
<BreadcrumbItem
active={false}
href="#/plans"
>
Migration
</BreadcrumbItem>
<BreadcrumbItem
active={true}
>
Migration Settings
</BreadcrumbItem>
</Toolbar>
<div
style={
Object {
"marginTop": 10,
}
}
>
<Uncontrolled(Tabs)
activeKey="/settings"
id="settings-tabs"
onSelect={[Function]}
>
<Tab
eventKey="/settings"
title="Concurrent Migrations"
>
<Connect(ReduxForm) />
</Tab>
<Tab
eventKey="/settings/conversion_hosts"
title="Conversion Hosts"
>
<Connect(ConversionHostsSettings) />
</Tab>
</Uncontrolled(Tabs)>
</div>
</React.Fragment>
`;
Original file line number Diff line number Diff line change
@@ -1,5 +1,29 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`settings actions should fetch conversion hosts and return PENDING and FULFILLED action 1`] = `
Array [
Object {
"type": "FETCH_V2V_CONVERSION_HOSTS_PENDING",
},
Object {
"type": "FETCH_V2V_CONVERSION_HOSTS_FULFILLED",
},
]
`;

exports[`settings actions should fetch conversion hosts and return PENDING and REJECTED action 1`] = `
Array [
Object {
"type": "FETCH_V2V_CONVERSION_HOSTS_PENDING",
},
Object {
"error": true,
"payload": [Error: <mocked error>],
"type": "FETCH_V2V_CONVERSION_HOSTS_REJECTED",
},
]
`;

exports[`settings actions should fetch servers and return PENDING and FULFILLED action 1`] = `
Array [
Object {
Expand Down
Loading