mirror of
https://github.com/ansible/awx.git
synced 2026-01-14 19:30:39 -03:30
Adds the list of the survey questions.
TODO: Add delete functionality. Add sort functionality. Add preview functionality. Toolbar will be built out with the other functionalities.
This commit is contained in:
parent
7a3ece7fd2
commit
edb3f6df55
@ -64,6 +64,16 @@ class JobTemplates extends SchedulesMixin(
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
readScheduleList(id, params) {
|
||||
return this.http.get(`${this.baseUrl}${id}/schedules/`, {
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
readSurvey(id) {
|
||||
return this.http.get(`${this.baseUrl}${id}/survey_spec/`);
|
||||
}
|
||||
}
|
||||
|
||||
export default JobTemplates;
|
||||
|
||||
@ -15,6 +15,7 @@ import { ResourceAccessList } from '@components/ResourceAccessList';
|
||||
import JobTemplateDetail from './JobTemplateDetail';
|
||||
import JobTemplateEdit from './JobTemplateEdit';
|
||||
import { JobTemplatesAPI, OrganizationsAPI } from '@api';
|
||||
import SurveyList from './shared/SurveyList';
|
||||
|
||||
class Template extends Component {
|
||||
constructor(props) {
|
||||
@ -131,7 +132,7 @@ class Template extends Component {
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Survey`),
|
||||
link: '/home',
|
||||
link: `${match.url}/survey`,
|
||||
}
|
||||
);
|
||||
|
||||
@ -238,6 +239,12 @@ class Template extends Component {
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{template && (
|
||||
<Route
|
||||
path="/templates/:templateType/:id/survey"
|
||||
render={() => <SurveyList template={template} />}
|
||||
/>
|
||||
)}
|
||||
<Route
|
||||
key="not-found"
|
||||
path="*"
|
||||
|
||||
@ -52,6 +52,7 @@ class Templates extends Component {
|
||||
[`/templates/${template.type}/${template.id}/completed_jobs`]: i18n._(
|
||||
t`Completed Jobs`
|
||||
),
|
||||
[`/templates/${template.type}/${template.id}/survey`]: i18n._(t`Survey`),
|
||||
};
|
||||
this.setState({ breadcrumbConfig });
|
||||
};
|
||||
|
||||
48
awx/ui_next/src/screens/Template/shared/SurveyList.jsx
Normal file
48
awx/ui_next/src/screens/Template/shared/SurveyList.jsx
Normal file
@ -0,0 +1,48 @@
|
||||
import React, { useEffect, useCallback } from 'react';
|
||||
import { withI18n } from '@lingui/react';
|
||||
|
||||
import useRequest from '@util/useRequest';
|
||||
import ContentError from '@components/ContentError';
|
||||
import ContentLoading from '@components/ContentLoading';
|
||||
import { JobTemplatesAPI } from '@api';
|
||||
import SurveyListItem from './SurveyListItem';
|
||||
|
||||
function SurveyList({ template }) {
|
||||
const {
|
||||
result: questions,
|
||||
error: contentError,
|
||||
isLoading,
|
||||
request: fetchSurvey,
|
||||
} = useRequest(
|
||||
useCallback(async () => {
|
||||
const {
|
||||
data: { spec },
|
||||
} = await JobTemplatesAPI.readSurvey(template.id);
|
||||
|
||||
return spec.map((s, index) => ({ ...s, id: index }));
|
||||
}, [template.id])
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
fetchSurvey();
|
||||
}, [fetchSurvey]);
|
||||
if (contentError) {
|
||||
return <ContentError error={contentError} />;
|
||||
}
|
||||
if (isLoading) {
|
||||
return <ContentLoading />;
|
||||
}
|
||||
|
||||
return (
|
||||
questions?.length > 0 &&
|
||||
questions.map((question, index) => (
|
||||
<SurveyListItem
|
||||
key={question.id}
|
||||
isLast={index === questions.length - 1}
|
||||
isFirst={index === 0}
|
||||
question={question}
|
||||
/>
|
||||
))
|
||||
);
|
||||
}
|
||||
export default withI18n()(SurveyList);
|
||||
47
awx/ui_next/src/screens/Template/shared/SurveyList.test.jsx
Normal file
47
awx/ui_next/src/screens/Template/shared/SurveyList.test.jsx
Normal file
@ -0,0 +1,47 @@
|
||||
import React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { mountWithContexts } from '@testUtils/enzymeHelpers';
|
||||
import SurveyList from './SurveyList';
|
||||
import { JobTemplatesAPI } from '@api';
|
||||
import mockJobTemplateData from './data.job_template.json';
|
||||
|
||||
jest.mock('@api/models/JobTemplates');
|
||||
|
||||
describe('<SurveyList />', () => {
|
||||
beforeEach(() => {
|
||||
JobTemplatesAPI.readSurvey.mockResolvedValue({
|
||||
data: { spec: [{ question_name: 'Foo', type: 'text', default: 'Bar' }] },
|
||||
});
|
||||
});
|
||||
test('expect component to mount successfully', async () => {
|
||||
let wrapper;
|
||||
await act(async () => {
|
||||
wrapper = await mountWithContexts(
|
||||
<SurveyList template={mockJobTemplateData} />
|
||||
);
|
||||
});
|
||||
expect(wrapper.length).toBe(1);
|
||||
});
|
||||
test('expect api to be called to get survey', async () => {
|
||||
let wrapper;
|
||||
await act(async () => {
|
||||
wrapper = await mountWithContexts(
|
||||
<SurveyList template={mockJobTemplateData} />
|
||||
);
|
||||
});
|
||||
expect(JobTemplatesAPI.readSurvey).toBeCalledWith(7);
|
||||
wrapper.update();
|
||||
expect(wrapper.find('SurveyListItem').length).toBe(1);
|
||||
});
|
||||
test('error in retrieving the survey throws an error', async () => {
|
||||
JobTemplatesAPI.readSurvey.mockRejectedValue(new Error());
|
||||
let wrapper;
|
||||
await act(async () => {
|
||||
wrapper = await mountWithContexts(
|
||||
<SurveyList template={{ ...mockJobTemplateData, id: 'a' }} />
|
||||
);
|
||||
});
|
||||
wrapper.update();
|
||||
expect(wrapper.find('ContentError').length).toBe(1);
|
||||
});
|
||||
});
|
||||
80
awx/ui_next/src/screens/Template/shared/SurveyListItem.jsx
Normal file
80
awx/ui_next/src/screens/Template/shared/SurveyListItem.jsx
Normal file
@ -0,0 +1,80 @@
|
||||
import React from 'react';
|
||||
import { t } from '@lingui/macro';
|
||||
import { withI18n } from '@lingui/react';
|
||||
|
||||
import {
|
||||
Button as _Button,
|
||||
DataList,
|
||||
DataListAction as _DataListAction,
|
||||
DataListCheck,
|
||||
DataListItemCells,
|
||||
DataListItemRow,
|
||||
DataListItem,
|
||||
DataListCell,
|
||||
Stack,
|
||||
StackItem,
|
||||
} from '@patternfly/react-core';
|
||||
import { CaretDownIcon, CaretUpIcon } from '@patternfly/react-icons';
|
||||
import styled from 'styled-components';
|
||||
|
||||
const DataListAction = styled(_DataListAction)`
|
||||
margin-left: 0;
|
||||
margin-right: 20px;
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
`;
|
||||
const Button = styled(_Button)`
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
padding-left: 0;
|
||||
`;
|
||||
function SurveyListItem({ question, i18n, isLast, isFirst }) {
|
||||
return (
|
||||
<DataList aria-label={i18n._(t`Survey List`)}>
|
||||
<DataListItem aria-labelledby={i18n._(t`Survey questions`)}>
|
||||
<DataListItemRow>
|
||||
<DataListAction
|
||||
id="sortQuestions"
|
||||
aria-labelledby={i18n._(t`Sort question order`)}
|
||||
aria-label={i18n._(t`Sort question order`)}
|
||||
>
|
||||
<Stack>
|
||||
<StackItem>
|
||||
<Button
|
||||
variant="plain"
|
||||
aria-label={i18n._(t`move up`)}
|
||||
isDisabled={isFirst}
|
||||
>
|
||||
<CaretUpIcon />
|
||||
</Button>
|
||||
</StackItem>
|
||||
<StackItem>
|
||||
<Button
|
||||
variant="plain"
|
||||
aria-label={i18n._(t`move down`)}
|
||||
isDisabled={isLast}
|
||||
>
|
||||
<CaretDownIcon />
|
||||
</Button>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
</DataListAction>
|
||||
<DataListCheck checked={false} aria-labelledby="survey check" />
|
||||
<DataListItemCells
|
||||
dataListCells={[
|
||||
<DataListCell key={question.question_name}>
|
||||
{question.question_name}
|
||||
</DataListCell>,
|
||||
<DataListCell key={question.type}>{question.type}</DataListCell>,
|
||||
<DataListCell key={question.default}>
|
||||
{question.default}
|
||||
</DataListCell>,
|
||||
]}
|
||||
/>
|
||||
</DataListItemRow>
|
||||
</DataListItem>
|
||||
</DataList>
|
||||
);
|
||||
}
|
||||
|
||||
export default withI18n()(SurveyListItem);
|
||||
@ -0,0 +1,47 @@
|
||||
import React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { mountWithContexts } from '@testUtils/enzymeHelpers';
|
||||
import SurveyListItem from './SurveyListItem';
|
||||
|
||||
describe('<SurveyListItem />', () => {
|
||||
const item = { question_name: 'Foo', default: 'Bar', type: 'text' };
|
||||
test('renders successfully', () => {
|
||||
let wrapper;
|
||||
act(() => {
|
||||
wrapper = mountWithContexts(
|
||||
<SurveyListItem question={item} isFirst={false} isLast={false} />
|
||||
);
|
||||
});
|
||||
expect(wrapper.length).toBe(1);
|
||||
});
|
||||
test('fields are rendering properly', () => {
|
||||
let wrapper;
|
||||
act(() => {
|
||||
wrapper = mountWithContexts(
|
||||
<SurveyListItem question={item} isFirst={false} isLast={false} />
|
||||
);
|
||||
});
|
||||
const moveUp = wrapper.find('Button[aria-label="move up"]');
|
||||
const moveDown = wrapper.find('Button[aria-label="move down"]');
|
||||
expect(moveUp.length).toBe(1);
|
||||
expect(moveDown.length).toBe(1);
|
||||
expect(wrapper.find('DataListCheck').length).toBe(1);
|
||||
expect(wrapper.find('DataListCell').length).toBe(3);
|
||||
});
|
||||
test('move up and move down buttons are disabled', () => {
|
||||
let wrapper;
|
||||
act(() => {
|
||||
wrapper = mountWithContexts(
|
||||
<SurveyListItem question={item} isFirst isLast />
|
||||
);
|
||||
});
|
||||
const moveUp = wrapper
|
||||
.find('Button[aria-label="move up"]')
|
||||
.prop('isDisabled');
|
||||
const moveDown = wrapper
|
||||
.find('Button[aria-label="move down"]')
|
||||
.prop('isDisabled');
|
||||
expect(moveUp).toBe(true);
|
||||
expect(moveDown).toBe(true);
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user