use VariablesDetail for displaying variables field in details views

This commit is contained in:
Keith Grant
2019-12-16 16:11:24 -08:00
parent cde39413c9
commit 2f7607a080
6 changed files with 90 additions and 107 deletions

View File

@@ -1 +1,2 @@
// eslint-disable-next-line import/prefer-default-export
export { default as TabbedCardHeader } from './TabbedCardHeader'; export { default as TabbedCardHeader } from './TabbedCardHeader';

View File

@@ -1,6 +1,7 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { string, number } from 'prop-types'; import { string, number } from 'prop-types';
import { Split, SplitItem } from '@patternfly/react-core'; import { Split, SplitItem, TextListItemVariants } from '@patternfly/react-core';
import { DetailName, DetailValue } from '@components/DetailList';
import CodeMirrorInput from './CodeMirrorInput'; import CodeMirrorInput from './CodeMirrorInput';
import YamlJsonToggle from './YamlJsonToggle'; import YamlJsonToggle from './YamlJsonToggle';
import { yamlToJson, jsonToYaml, isJson } from '../../util/yaml'; import { yamlToJson, jsonToYaml, isJson } from '../../util/yaml';
@@ -10,11 +11,16 @@ const JSON_MODE = 'javascript';
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 [val, setVal] = useState(value); const [currentValue, setCurrentValue] = useState(value);
const [error, setError] = useState(null); const [error, setError] = useState(null);
return ( return (
<div css="margin: 20px 0"> <>
<DetailName
component={TextListItemVariants.dt}
fullWidth
css="grid-column: 1 / -1"
>
<Split gutter="sm"> <Split gutter="sm">
<SplitItem> <SplitItem>
<div className="pf-c-form__label"> <div className="pf-c-form__label">
@@ -32,8 +38,10 @@ function VariablesDetail({ value, label, rows }) {
onChange={newMode => { onChange={newMode => {
try { try {
const newVal = const newVal =
newMode === YAML_MODE ? jsonToYaml(val) : yamlToJson(val); newMode === YAML_MODE
setVal(newVal); ? jsonToYaml(currentValue)
: yamlToJson(currentValue);
setCurrentValue(newVal);
setMode(newMode); setMode(newMode);
} catch (err) { } catch (err) {
setError(err); setError(err);
@@ -42,9 +50,15 @@ function VariablesDetail({ value, label, rows }) {
/> />
</SplitItem> </SplitItem>
</Split> </Split>
</DetailName>
<DetailValue
component={TextListItemVariants.dd}
fullWidth
css="grid-column: 1 / -1; margin-top: -20px"
>
<CodeMirrorInput <CodeMirrorInput
mode={mode} mode={mode}
value={val} value={currentValue}
readOnly readOnly
rows={rows} rows={rows}
css="margin-top: 10px" css="margin-top: 10px"
@@ -57,7 +71,8 @@ function VariablesDetail({ value, label, rows }) {
Error: {error.message} Error: {error.message}
</div> </div>
)} )}
</div> </DetailValue>
</>
); );
} }
VariablesDetail.propTypes = { VariablesDetail.propTypes = {

View File

@@ -7,7 +7,6 @@ import YamlJsonToggle from './YamlJsonToggle';
import { yamlToJson, jsonToYaml } from '../../util/yaml'; import { yamlToJson, jsonToYaml } from '../../util/yaml';
const YAML_MODE = 'yaml'; const YAML_MODE = 'yaml';
const JSON_MODE = 'javascript';
function VariablesField({ id, name, label, readOnly }) { function VariablesField({ id, name, label, readOnly }) {
// TODO: detect initial mode // TODO: detect initial mode

View File

@@ -4,10 +4,9 @@ import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import styled from 'styled-components'; import styled from 'styled-components';
import { Host } from '@types'; import { Host } from '@types';
import { formatDateString } from '@util/dates';
import { Button, CardBody } from '@patternfly/react-core'; import { Button, CardBody } from '@patternfly/react-core';
import { DetailList, Detail } from '@components/DetailList'; import { DetailList, Detail, UserDateDetail } from '@components/DetailList';
import CodeMirrorInput from '@components/CodeMirrorInput'; import { VariablesDetail } from '@components/CodeMirrorInput';
const ActionButtonWrapper = styled.div` const ActionButtonWrapper = styled.div`
display: flex; display: flex;
@@ -21,30 +20,6 @@ const ActionButtonWrapper = styled.div`
function HostDetail({ host, i18n }) { function HostDetail({ host, i18n }) {
const { created, description, id, modified, name, summary_fields } = host; const { created, description, id, modified, name, summary_fields } = host;
let createdBy = '';
if (created) {
if (summary_fields.created_by && summary_fields.created_by.username) {
createdBy = i18n._(
t`${formatDateString(created)} by ${summary_fields.created_by.username}`
);
} else {
createdBy = formatDateString(created);
}
}
let modifiedBy = '';
if (modified) {
if (summary_fields.modified_by && summary_fields.modified_by.username) {
modifiedBy = i18n._(
t`${formatDateString(modified)} by ${
summary_fields.modified_by.username
}`
);
} else {
modifiedBy = formatDateString(modified);
}
}
return ( return (
<CardBody> <CardBody>
<DetailList gutter="sm"> <DetailList gutter="sm">
@@ -66,23 +41,20 @@ function HostDetail({ host, i18n }) {
} }
/> />
)} )}
{/* TODO: Link to user in users */} <UserDateDetail
<Detail label={i18n._(t`Created`)} value={createdBy} /> label={i18n._(t`Created`)}
{/* TODO: Link to user in users */} date={created}
<Detail label={i18n._(t`Last Modified`)} value={modifiedBy} /> user={summary_fields.created_by}
<Detail
fullWidth
label={i18n._(t`Variables`)}
value={
<CodeMirrorInput
mode="yaml"
readOnly
value={host.variables}
onChange={() => {}}
rows={6}
hasErrors={false}
/> />
} <UserDateDetail
label={i18n._(t`Last Modified`)}
date={modified}
user={summary_fields.modified_by}
/>
<VariablesDetail
label={i18n._(t`Variables`)}
value={host.variables}
rows={6}
/> />
</DetailList> </DetailList>
<ActionButtonWrapper> <ActionButtonWrapper>

View File

@@ -30,7 +30,7 @@ describe('<HostDetail />', () => {
mountWithContexts(<HostDetail host={mockHost} />); mountWithContexts(<HostDetail host={mockHost} />);
}); });
test('should render Details', async done => { test('should render Details', async () => {
const wrapper = mountWithContexts(<HostDetail host={mockHost} />); const wrapper = mountWithContexts(<HostDetail host={mockHost} />);
const testParams = [ const testParams = [
{ label: 'Name', value: 'Foo' }, { label: 'Name', value: 'Foo' },
@@ -46,23 +46,22 @@ describe('<HostDetail />', () => {
expect(detail.find('dt').text()).toBe(label); expect(detail.find('dt').text()).toBe(label);
expect(detail.find('dd').text()).toBe(value); expect(detail.find('dd').text()).toBe(value);
} }
done();
}); });
test('should show edit button for users with edit permission', async done => { test('should show edit button for users with edit permission', async () => {
const wrapper = mountWithContexts(<HostDetail host={mockHost} />); const wrapper = mountWithContexts(<HostDetail host={mockHost} />);
const editButton = await waitForElement(wrapper, 'HostDetail Button'); // VariablesDetail has two buttons
const editButton = wrapper.find('Button').at(2);
expect(editButton.text()).toEqual('Edit'); expect(editButton.text()).toEqual('Edit');
expect(editButton.prop('to')).toBe('/hosts/1/edit'); expect(editButton.prop('to')).toBe('/hosts/1/edit');
done();
}); });
test('should hide edit button for users without edit permission', async done => { test('should hide edit button for users without edit permission', async () => {
const readOnlyHost = { ...mockHost }; const readOnlyHost = { ...mockHost };
readOnlyHost.summary_fields.user_capabilities.edit = false; readOnlyHost.summary_fields.user_capabilities.edit = false;
const wrapper = mountWithContexts(<HostDetail host={readOnlyHost} />); const wrapper = mountWithContexts(<HostDetail host={readOnlyHost} />);
await waitForElement(wrapper, 'HostDetail'); await waitForElement(wrapper, 'HostDetail');
expect(wrapper.find('HostDetail Button').length).toBe(0); // VariablesDetail has two buttons
done(); expect(wrapper.find('Button').length).toBe(2);
}); });
}); });

View File

@@ -56,16 +56,13 @@ function InventoryDetail({ inventory, i18n }) {
) )
} }
/> />
</DetailList>
{inventory.variables && ( {inventory.variables && (
<VariablesDetail <VariablesDetail
id="job-artifacts"
label={i18n._(t`Variables`)} label={i18n._(t`Variables`)}
value={inventory.variables} value={inventory.variables}
rows={4} rows={4}
/> />
)} )}
<DetailList>
<UserDateDetail <UserDateDetail
label={i18n._(t`Created`)} label={i18n._(t`Created`)}
date={inventory.created} date={inventory.created}