mirror of
https://github.com/ansible/awx.git
synced 2026-04-11 21:19:22 -02: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:
@@ -64,6 +64,16 @@ class JobTemplates extends SchedulesMixin(
|
|||||||
params,
|
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;
|
export default JobTemplates;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { ResourceAccessList } from '@components/ResourceAccessList';
|
|||||||
import JobTemplateDetail from './JobTemplateDetail';
|
import JobTemplateDetail from './JobTemplateDetail';
|
||||||
import JobTemplateEdit from './JobTemplateEdit';
|
import JobTemplateEdit from './JobTemplateEdit';
|
||||||
import { JobTemplatesAPI, OrganizationsAPI } from '@api';
|
import { JobTemplatesAPI, OrganizationsAPI } from '@api';
|
||||||
|
import SurveyList from './shared/SurveyList';
|
||||||
|
|
||||||
class Template extends Component {
|
class Template extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@@ -131,7 +132,7 @@ class Template extends Component {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: i18n._(t`Survey`),
|
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
|
<Route
|
||||||
key="not-found"
|
key="not-found"
|
||||||
path="*"
|
path="*"
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ class Templates extends Component {
|
|||||||
[`/templates/${template.type}/${template.id}/completed_jobs`]: i18n._(
|
[`/templates/${template.type}/${template.id}/completed_jobs`]: i18n._(
|
||||||
t`Completed Jobs`
|
t`Completed Jobs`
|
||||||
),
|
),
|
||||||
|
[`/templates/${template.type}/${template.id}/survey`]: i18n._(t`Survey`),
|
||||||
};
|
};
|
||||||
this.setState({ breadcrumbConfig });
|
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);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user