From a07b1a19f3ea003fbebb6fb17de84f92e21efaf6 Mon Sep 17 00:00:00 2001 From: Jake McDermott Date: Wed, 3 Feb 2021 14:59:32 -0500 Subject: [PATCH] Add system prompt and config --- awx/api/serializers.py | 7 + awx/api/views/__init__.py | 2 +- .../ManagementJobEdit/ManagementJobEdit.jsx | 70 +++++++- .../LaunchManagementPrompt.jsx | 83 +++++++++ .../ManagementJobList/ManagementJobList.jsx | 2 + .../ManagementJobListItem.jsx | 168 +++++++++++------- 6 files changed, 267 insertions(+), 65 deletions(-) create mode 100644 awx/ui_next/src/screens/ManagementJob/ManagementJobList/LaunchManagementPrompt.jsx diff --git a/awx/api/serializers.py b/awx/api/serializers.py index c0d738207b..82af53b8b6 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -3359,6 +3359,13 @@ class SystemJobTemplateSerializer(UnifiedJobTemplateSerializer): del result['default_days'] return result + def __init__(self, *args, **kwargs): + super(SystemJobTemplateSerializer, self).__init__(*args, **kwargs) + for field_name, field_instance in self.fields.items(): + if field_name != 'default_days': + field_instance.read_only = True + + class SystemJobSerializer(UnifiedJobSerializer): diff --git a/awx/api/views/__init__.py b/awx/api/views/__init__.py index 29b26c120d..f532bab606 100644 --- a/awx/api/views/__init__.py +++ b/awx/api/views/__init__.py @@ -3423,7 +3423,7 @@ class SystemJobTemplateList(ListAPIView): return super(SystemJobTemplateList, self).get(request, *args, **kwargs) -class SystemJobTemplateDetail(RetrieveAPIView): +class SystemJobTemplateDetail(RetrieveUpdateAPIView): model = models.SystemJobTemplate serializer_class = serializers.SystemJobTemplateSerializer diff --git a/awx/ui_next/src/screens/ManagementJob/ManagementJobEdit/ManagementJobEdit.jsx b/awx/ui_next/src/screens/ManagementJob/ManagementJobEdit/ManagementJobEdit.jsx index 9ddff5539a..17908d9894 100644 --- a/awx/ui_next/src/screens/ManagementJob/ManagementJobEdit/ManagementJobEdit.jsx +++ b/awx/ui_next/src/screens/ManagementJob/ManagementJobEdit/ManagementJobEdit.jsx @@ -1,9 +1,71 @@ -import React from 'react'; +import React, { useState } from 'react'; +import { t } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { Formik } from 'formik'; +import { Form } from '@patternfly/react-core'; +import { useHistory } from 'react-router-dom'; +import { SystemJobTemplatesAPI } from '../../../api'; +import FormField, { FormSubmitError } from '../../../components/FormField'; +import FormActionGroup from '../../../components/FormActionGroup/FormActionGroup'; +import { FormColumnLayout } from '../../../components/FormLayout'; +import { minMaxValue } from '../../../util/validators'; import { CardBody } from '../../../components/Card'; -function ManagementJobEdit() { - return Management Job Edit; +function ManagementJobEdit({ i18n, managementJob }) { + const history = useHistory(); + const [formError, setFormError] = useState(null); + + const handleCancel = () => { + history.push(`/management_jobs/${managementJob?.id}/details`); + }; + + const handleSubmit = async values => { + try { + await SystemJobTemplatesAPI.update(managementJob?.id, { + default_days: values.dataRetention, + }); + history.push(`/management_jobs/${managementJob?.id}/details`); + } catch (error) { + setFormError(error); + } + }; + + return ( + + {managementJob?.default_days ? ( + + {formik => ( +
+ + + + + +
+ )} +
+ ) : null} +
+ ); } -export default ManagementJobEdit; +export default withI18n()(ManagementJobEdit); diff --git a/awx/ui_next/src/screens/ManagementJob/ManagementJobList/LaunchManagementPrompt.jsx b/awx/ui_next/src/screens/ManagementJob/ManagementJobList/LaunchManagementPrompt.jsx new file mode 100644 index 0000000000..ad010be710 --- /dev/null +++ b/awx/ui_next/src/screens/ManagementJob/ManagementJobList/LaunchManagementPrompt.jsx @@ -0,0 +1,83 @@ +import React, { useState } from 'react'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import { Button, TextInput, Tooltip } from '@patternfly/react-core'; +import { RocketIcon } from '@patternfly/react-icons'; + +import AlertModal from '../../../components/AlertModal'; + +const clamp = (val, min, max) => { + if (val < min) { + return min; + } + if (val > max) { + return max; + } + return val; +}; + +function LaunchManagementPrompt({ + i18n, + isOpen, + isLoading, + onClick, + onClose, + onConfirm, + defaultDays, +}) { + const [dataRetention, setDataRetention] = useState(defaultDays); + return ( + <> + + + + onConfirm(dataRetention)} + > + {i18n._(t`Launch`)} + , + , + ]} + > + {i18n._(t`Set how many days of data should be retained.`)} + + setDataRetention(clamp(value, 0, Number.MAX_SAFE_INTEGER)) + } + aria-label={i18n._(t`Launch`)} + /> + + + ); +} + +export default withI18n()(LaunchManagementPrompt); diff --git a/awx/ui_next/src/screens/ManagementJob/ManagementJobList/ManagementJobList.jsx b/awx/ui_next/src/screens/ManagementJob/ManagementJobList/ManagementJobList.jsx index e7a0bfccc1..1a54713c60 100644 --- a/awx/ui_next/src/screens/ManagementJob/ManagementJobList/ManagementJobList.jsx +++ b/awx/ui_next/src/screens/ManagementJob/ManagementJobList/ManagementJobList.jsx @@ -91,6 +91,7 @@ function ManagementJobList({ i18n }) { name, description, has_configurable_retention, + default_days, }) => ( )} diff --git a/awx/ui_next/src/screens/ManagementJob/ManagementJobList/ManagementJobListItem.jsx b/awx/ui_next/src/screens/ManagementJob/ManagementJobList/ManagementJobListItem.jsx index 5969397952..79c0e25ea1 100644 --- a/awx/ui_next/src/screens/ManagementJob/ManagementJobList/ManagementJobListItem.jsx +++ b/awx/ui_next/src/screens/ManagementJob/ManagementJobList/ManagementJobListItem.jsx @@ -11,10 +11,13 @@ import { DataListItemCells, Tooltip, } from '@patternfly/react-core'; -import { PencilAltIcon, RocketIcon } from '@patternfly/react-icons'; +import { RocketIcon, PencilAltIcon } from '@patternfly/react-icons'; import styled from 'styled-components'; import { SystemJobTemplatesAPI } from '../../../api'; +import AlertModal from '../../../components/AlertModal'; +import ErrorDetail from '../../../components/ErrorDetail'; +import LaunchManagementPrompt from './LaunchManagementPrompt'; const DataListAction = styled(_DataListAction)` align-items: center; @@ -31,6 +34,7 @@ function ManagementJobListItem({ id, name, description, + defaultDays, }) { const detailsUrl = `/management_jobs/${id}/details`; const editUrl = `/management_jobs/${id}/edit`; @@ -39,6 +43,28 @@ function ManagementJobListItem({ const history = useHistory(); const [isLaunchLoading, setIsLaunchLoading] = useState(false); + const [isManagementPromptOpen, setIsManagementPromptOpen] = useState(false); + const [isManagementPromptLoading, setIsManagementPromptLoading] = useState( + false + ); + const [managementPromptError, setManagementPromptError] = useState(null); + const handleManagementPromptClick = () => setIsManagementPromptOpen(true); + const handleManagementPromptClose = () => setIsManagementPromptOpen(false); + + const handleManagementPromptConfirm = async days => { + setIsManagementPromptLoading(true); + try { + const { data } = await SystemJobTemplatesAPI.launch(id, { + extra_vars: { days }, + }); + history.push(`/jobs/management/${data.id}/output`); + } catch (error) { + setManagementPromptError(error); + } finally { + setIsManagementPromptLoading(false); + } + }; + const handleLaunch = async () => { setIsLaunchLoading(true); try { @@ -52,67 +78,89 @@ function ManagementJobListItem({ }; return ( - - - - - {name} - - , - - {i18n._(t`Description:`)} {description} - , - ]} - /> - - {isSuperUser ? ( - <> - + + + - - - {isConfigurable ? ( - - + + + ) : ( + - - - - ) : null} - - ) : null} - - - + + + )}{' '} + + ) : null} + + + + {managementPromptError && ( + <> + setManagementPromptError(null)} + title={i18n._(t`Management job launch error`)} + label={i18n._(t`Management job launch error`)} + > + + + + )} + ); }