From edb3f6df556fb33f56572d3b104b86c22bf98822 Mon Sep 17 00:00:00 2001 From: Alex Corey Date: Tue, 3 Mar 2020 22:33:28 -0500 Subject: [PATCH] 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. --- awx/ui_next/src/api/models/JobTemplates.js | 10 +++ awx/ui_next/src/screens/Template/Template.jsx | 9 ++- .../src/screens/Template/Templates.jsx | 1 + .../screens/Template/shared/SurveyList.jsx | 48 +++++++++++ .../Template/shared/SurveyList.test.jsx | 47 +++++++++++ .../Template/shared/SurveyListItem.jsx | 80 +++++++++++++++++++ .../Template/shared/SurveyListItem.test.jsx | 47 +++++++++++ 7 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 awx/ui_next/src/screens/Template/shared/SurveyList.jsx create mode 100644 awx/ui_next/src/screens/Template/shared/SurveyList.test.jsx create mode 100644 awx/ui_next/src/screens/Template/shared/SurveyListItem.jsx create mode 100644 awx/ui_next/src/screens/Template/shared/SurveyListItem.test.jsx diff --git a/awx/ui_next/src/api/models/JobTemplates.js b/awx/ui_next/src/api/models/JobTemplates.js index 9e2e4ee851..98174bc1e7 100644 --- a/awx/ui_next/src/api/models/JobTemplates.js +++ b/awx/ui_next/src/api/models/JobTemplates.js @@ -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; diff --git a/awx/ui_next/src/screens/Template/Template.jsx b/awx/ui_next/src/screens/Template/Template.jsx index a600563a4a..9de406abaf 100644 --- a/awx/ui_next/src/screens/Template/Template.jsx +++ b/awx/ui_next/src/screens/Template/Template.jsx @@ -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 && ( + } + /> + )} { + const { + data: { spec }, + } = await JobTemplatesAPI.readSurvey(template.id); + + return spec.map((s, index) => ({ ...s, id: index })); + }, [template.id]) + ); + + useEffect(() => { + fetchSurvey(); + }, [fetchSurvey]); + if (contentError) { + return ; + } + if (isLoading) { + return ; + } + + return ( + questions?.length > 0 && + questions.map((question, index) => ( + + )) + ); +} +export default withI18n()(SurveyList); diff --git a/awx/ui_next/src/screens/Template/shared/SurveyList.test.jsx b/awx/ui_next/src/screens/Template/shared/SurveyList.test.jsx new file mode 100644 index 0000000000..271ddf39bb --- /dev/null +++ b/awx/ui_next/src/screens/Template/shared/SurveyList.test.jsx @@ -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('', () => { + 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( + + ); + }); + expect(wrapper.length).toBe(1); + }); + test('expect api to be called to get survey', async () => { + let wrapper; + await act(async () => { + wrapper = await mountWithContexts( + + ); + }); + 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( + + ); + }); + wrapper.update(); + expect(wrapper.find('ContentError').length).toBe(1); + }); +}); diff --git a/awx/ui_next/src/screens/Template/shared/SurveyListItem.jsx b/awx/ui_next/src/screens/Template/shared/SurveyListItem.jsx new file mode 100644 index 0000000000..f50b428c25 --- /dev/null +++ b/awx/ui_next/src/screens/Template/shared/SurveyListItem.jsx @@ -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 ( + + + + + + + + + + + + + + + + {question.question_name} + , + {question.type}, + + {question.default} + , + ]} + /> + + + + ); +} + +export default withI18n()(SurveyListItem); diff --git a/awx/ui_next/src/screens/Template/shared/SurveyListItem.test.jsx b/awx/ui_next/src/screens/Template/shared/SurveyListItem.test.jsx new file mode 100644 index 0000000000..2c55648eee --- /dev/null +++ b/awx/ui_next/src/screens/Template/shared/SurveyListItem.test.jsx @@ -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('', () => { + const item = { question_name: 'Foo', default: 'Bar', type: 'text' }; + test('renders successfully', () => { + let wrapper; + act(() => { + wrapper = mountWithContexts( + + ); + }); + expect(wrapper.length).toBe(1); + }); + test('fields are rendering properly', () => { + let wrapper; + act(() => { + wrapper = mountWithContexts( + + ); + }); + 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( + + ); + }); + 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); + }); +});