Merge pull request #5751 from keithjgrant/5502-inventory-group-refresh

Inventory details refresh

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
softwarefactory-project-zuul[bot]
2020-01-24 19:24:25 +00:00
committed by GitHub
5 changed files with 83 additions and 13 deletions

View File

@@ -1,4 +1,4 @@
import React, { useState } from 'react'; import React, { useState, useEffect } from 'react';
import { string, number } from 'prop-types'; import { string, number } from 'prop-types';
import { Split, SplitItem, TextListItemVariants } from '@patternfly/react-core'; import { Split, SplitItem, TextListItemVariants } from '@patternfly/react-core';
import { DetailName, DetailValue } from '@components/DetailList'; import { DetailName, DetailValue } from '@components/DetailList';
@@ -7,11 +7,30 @@ import CodeMirrorInput from './CodeMirrorInput';
import YamlJsonToggle from './YamlJsonToggle'; import YamlJsonToggle from './YamlJsonToggle';
import { JSON_MODE, YAML_MODE } from './constants'; import { JSON_MODE, YAML_MODE } from './constants';
function getValueAsMode(value, mode) {
if (!value) {
if (mode === JSON_MODE) {
return '{}';
}
return '---';
}
const modeMatches = isJson(value) === (mode === JSON_MODE);
if (modeMatches) {
return value;
}
return mode === YAML_MODE ? jsonToYaml(value) : yamlToJson(value);
}
function VariablesDetail({ value, label, rows }) { function VariablesDetail({ value, label, rows }) {
const [mode, setMode] = useState(isJson(value) ? JSON_MODE : YAML_MODE); const [mode, setMode] = useState(isJson(value) ? JSON_MODE : YAML_MODE);
const [currentValue, setCurrentValue] = useState(value); const [currentValue, setCurrentValue] = useState(value || '---');
const [error, setError] = useState(null); const [error, setError] = useState(null);
useEffect(() => {
setCurrentValue(getValueAsMode(value, mode));
/* eslint-disable-next-line react-hooks/exhaustive-deps */
}, [value]);
return ( return (
<> <>
<DetailName <DetailName
@@ -35,11 +54,7 @@ function VariablesDetail({ value, label, rows }) {
mode={mode} mode={mode}
onChange={newMode => { onChange={newMode => {
try { try {
const newVal = setCurrentValue(getValueAsMode(currentValue, newMode));
newMode === YAML_MODE
? jsonToYaml(currentValue)
: yamlToJson(currentValue);
setCurrentValue(newVal);
setMode(newMode); setMode(newMode);
} catch (err) { } catch (err) {
setError(err); setError(err);
@@ -56,7 +71,7 @@ function VariablesDetail({ value, label, rows }) {
> >
<CodeMirrorInput <CodeMirrorInput
mode={mode} mode={mode}
value={currentValue || '---'} // When github issue https://github.com/ansible/awx/issues/5502 gets resolved this line of code should be revisited and refactored if possible. value={currentValue}
readOnly readOnly
rows={rows} rows={rows}
css="margin-top: 10px" css="margin-top: 10px"

View File

@@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import { shallow } from 'enzyme'; import { act } from 'react-dom/test-utils';
import { shallow, mount } from 'enzyme';
import VariablesDetail from './VariablesDetail'; import VariablesDetail from './VariablesDetail';
jest.mock('@api'); jest.mock('@api');
@@ -40,9 +41,42 @@ describe('<VariablesDetail>', () => {
expect(input2.prop('mode')).toEqual('yaml'); expect(input2.prop('mode')).toEqual('yaml');
expect(input2.prop('value')).toEqual('foo: bar\n'); expect(input2.prop('value')).toEqual('foo: bar\n');
}); });
test('should render label and value= --- when there are no values', () => { test('should render label and value= --- when there are no values', () => {
const wrapper = shallow(<VariablesDetail value="" label="Variables" />); const wrapper = shallow(<VariablesDetail value="" label="Variables" />);
expect(wrapper.find('Styled(CodeMirrorInput)').length).toBe(1); expect(wrapper.find('Styled(CodeMirrorInput)').length).toBe(1);
expect(wrapper.find('div.pf-c-form__label').text()).toBe('Variables'); expect(wrapper.find('div.pf-c-form__label').text()).toBe('Variables');
}); });
test('should update value if prop changes', () => {
const wrapper = mount(
<VariablesDetail value="---foo: bar" label="Variables" />
);
act(() => {
wrapper.find('YamlJsonToggle').invoke('onChange')('javascript');
});
wrapper.setProps({
value: '---bar: baz',
});
wrapper.update();
const input = wrapper.find('Styled(CodeMirrorInput)');
expect(input.prop('mode')).toEqual('javascript');
expect(input.prop('value')).toEqual('{\n "bar": "baz"\n}');
});
test('should default yaml value to "---"', () => {
const wrapper = shallow(<VariablesDetail value="" label="Variables" />);
const input = wrapper.find('Styled(CodeMirrorInput)');
expect(input.prop('value')).toEqual('---');
});
test('should default empty json to "{}"', () => {
const wrapper = mount(<VariablesDetail value="" label="Variables" />);
act(() => {
wrapper.find('YamlJsonToggle').invoke('onChange')('javascript');
});
wrapper.setProps({ value: '' });
const input = wrapper.find('Styled(CodeMirrorInput)');
expect(input.prop('value')).toEqual('{}');
});
}); });

View File

@@ -37,6 +37,7 @@ function Inventory({ i18n, setBreadcrumb }) {
useEffect(() => { useEffect(() => {
async function fetchData() { async function fetchData() {
try { try {
setHasContentLoading(true);
const { data } = await InventoriesAPI.readDetail(match.params.id); const { data } = await InventoriesAPI.readDetail(match.params.id);
setBreadcrumb(data); setBreadcrumb(data);
setInventory(data); setInventory(data);

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect, useRef } from 'react';
import { Link, useHistory } from 'react-router-dom'; import { Link, useHistory } from 'react-router-dom';
import { withI18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
@@ -18,19 +18,29 @@ function InventoryDetail({ inventory, i18n }) {
const [hasContentLoading, setHasContentLoading] = useState(true); const [hasContentLoading, setHasContentLoading] = useState(true);
const [contentError, setContentError] = useState(null); const [contentError, setContentError] = useState(null);
const history = useHistory(); const history = useHistory();
const isMounted = useRef(null);
useEffect(() => { useEffect(() => {
isMounted.current = true;
(async () => { (async () => {
setHasContentLoading(true); setHasContentLoading(true);
try { try {
const { data } = await InventoriesAPI.readInstanceGroups(inventory.id); const { data } = await InventoriesAPI.readInstanceGroups(inventory.id);
if (!isMounted.current) {
return;
}
setInstanceGroups(data.results); setInstanceGroups(data.results);
} catch (err) { } catch (err) {
setContentError(err); setContentError(err);
} finally { } finally {
setHasContentLoading(false); if (isMounted.current) {
setHasContentLoading(false);
}
} }
})(); })();
return () => {
isMounted.current = false;
};
}, [inventory.id]); }, [inventory.id]);
const deleteInventory = async () => { const deleteInventory = async () => {

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect, useRef } from 'react';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { object } from 'prop-types'; import { object } from 'prop-types';
@@ -15,8 +15,10 @@ function InventoryEdit({ inventory }) {
const [contentLoading, setContentLoading] = useState(true); const [contentLoading, setContentLoading] = useState(true);
const [credentialTypeId, setCredentialTypeId] = useState(null); const [credentialTypeId, setCredentialTypeId] = useState(null);
const history = useHistory(); const history = useHistory();
const isMounted = useRef(null);
useEffect(() => { useEffect(() => {
isMounted.current = true;
const loadData = async () => { const loadData = async () => {
try { try {
const [ const [
@@ -32,15 +34,23 @@ function InventoryEdit({ inventory }) {
kind: 'insights', kind: 'insights',
}), }),
]); ]);
if (!isMounted.current) {
return;
}
setInstanceGroups(loadedInstanceGroups); setInstanceGroups(loadedInstanceGroups);
setCredentialTypeId(loadedCredentialTypeId[0].id); setCredentialTypeId(loadedCredentialTypeId[0].id);
} catch (err) { } catch (err) {
setError(err); setError(err);
} finally { } finally {
setContentLoading(false); if (isMounted.current) {
setContentLoading(false);
}
} }
}; };
loadData(); loadData();
return () => {
isMounted.current = false;
};
}, [inventory.id, contentLoading, inventory, credentialTypeId]); }, [inventory.id, contentLoading, inventory, credentialTypeId]);
const handleCancel = () => { const handleCancel = () => {