From 7042542e6ae6470a77e60333d636ab00d77a6243 Mon Sep 17 00:00:00 2001 From: Keith Grant Date: Wed, 2 Sep 2020 16:49:04 -0700 Subject: [PATCH 1/6] add ArrayDetail --- .../src/components/DetailList/ArrayDetail.jsx | 35 +++++++++++++++++++ .../src/components/DetailList/DetailList.jsx | 2 +- .../src/components/DetailList/index.js | 1 + .../NotificationTemplateDetail.jsx | 21 +++++------ 4 files changed, 48 insertions(+), 11 deletions(-) create mode 100644 awx/ui_next/src/components/DetailList/ArrayDetail.jsx diff --git a/awx/ui_next/src/components/DetailList/ArrayDetail.jsx b/awx/ui_next/src/components/DetailList/ArrayDetail.jsx new file mode 100644 index 0000000000..a946a5976f --- /dev/null +++ b/awx/ui_next/src/components/DetailList/ArrayDetail.jsx @@ -0,0 +1,35 @@ +import 'styled-components/macro'; +import React from 'react'; +import styled from 'styled-components'; +import { TextListItemVariants } from '@patternfly/react-core'; +import { DetailName, DetailValue } from './Detail'; + +const Value = styled(DetailValue)` + margin-top: var(--pf-global--spacer--xs); + padding: var(--pf-global--spacer--xs); + border: 1px solid var(--pf-global--BorderColor--100); + max-height: 5.5em; + overflow: auto; +`; + +function ArrayDetail({ label, value, dataCy }) { + const labelCy = dataCy ? `${dataCy}-label` : null; + const valueCy = dataCy ? `${dataCy}-value` : null; + + const vals = Array.isArray(value) ? value : [value]; + + return ( +
+ + {label} + + + {vals.map(v => ( +
{v}
+ ))} +
+
+ ); +} + +export default ArrayDetail; diff --git a/awx/ui_next/src/components/DetailList/DetailList.jsx b/awx/ui_next/src/components/DetailList/DetailList.jsx index 59185b0931..85bde3494a 100644 --- a/awx/ui_next/src/components/DetailList/DetailList.jsx +++ b/awx/ui_next/src/components/DetailList/DetailList.jsx @@ -11,7 +11,7 @@ const DetailList = ({ children, stacked, ...props }) => ( export default styled(DetailList)` display: grid; grid-gap: 20px; - align-items: center; + align-items: start; ${props => props.stacked ? ` diff --git a/awx/ui_next/src/components/DetailList/index.js b/awx/ui_next/src/components/DetailList/index.js index 8bebb27ce4..332cfa2f6b 100644 --- a/awx/ui_next/src/components/DetailList/index.js +++ b/awx/ui_next/src/components/DetailList/index.js @@ -3,6 +3,7 @@ export { default as Detail, DetailName, DetailValue } from './Detail'; export { default as DeletedDetail } from './DeletedDetail'; export { default as UserDateDetail } from './UserDateDetail'; export { default as DetailBadge } from './DetailBadge'; +export { default as ArrayDetail } from './ArrayDetail'; /* NOTE: ObjectDetail cannot be imported here, as it causes circular dependencies in testing environment. Import it directly from diff --git a/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.jsx b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.jsx index a70f691e02..6b19621c54 100644 --- a/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.jsx +++ b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.jsx @@ -7,6 +7,7 @@ import AlertModal from '../../../components/AlertModal'; import { CardBody, CardActionsRow } from '../../../components/Card'; import { Detail, + ArrayDetail, DetailList, DeletedDetail, } from '../../../components/DetailList'; @@ -81,9 +82,9 @@ function NotificationTemplateDetail({ i18n, template }) { value={configuration.host} dataCy="nt-detail-host" /> - - - - - Date: Tue, 8 Sep 2020 12:49:59 -0700 Subject: [PATCH 2/6] add custom messages to Notification Detail --- .../{ObjectDetail.jsx => CodeDetail.jsx} | 15 +- .../src/components/DetailList/index.js | 2 +- .../NotificationTemplate.jsx | 1 + .../NotificationTemplateDetail.jsx | 182 +++++++++++++++++- .../shared/NotificationTemplateForm.jsx | 37 +--- .../shared/hasCustomMessages.js | 40 ++++ 6 files changed, 228 insertions(+), 49 deletions(-) rename awx/ui_next/src/components/DetailList/{ObjectDetail.jsx => CodeDetail.jsx} (77%) create mode 100644 awx/ui_next/src/screens/NotificationTemplate/shared/hasCustomMessages.js diff --git a/awx/ui_next/src/components/DetailList/ObjectDetail.jsx b/awx/ui_next/src/components/DetailList/CodeDetail.jsx similarity index 77% rename from awx/ui_next/src/components/DetailList/ObjectDetail.jsx rename to awx/ui_next/src/components/DetailList/CodeDetail.jsx index bf008866a8..9b9a2f0568 100644 --- a/awx/ui_next/src/components/DetailList/ObjectDetail.jsx +++ b/awx/ui_next/src/components/DetailList/CodeDetail.jsx @@ -1,11 +1,11 @@ import 'styled-components/macro'; import React from 'react'; -import { shape, node, number } from 'prop-types'; +import { shape, node, number, oneOf } from 'prop-types'; import { TextListItemVariants } from '@patternfly/react-core'; import { DetailName, DetailValue } from './Detail'; import CodeMirrorInput from '../CodeMirrorInput'; -function ObjectDetail({ value, label, rows, fullHeight }) { +function CodeDetail({ value, label, mode, rows, fullHeight }) { return ( <> ); } -ObjectDetail.propTypes = { +CodeDetail.propTypes = { value: shape.isRequired, label: node.isRequired, rows: number, + mode: oneOf(['json', 'yaml', 'jinja2']).isRequired, }; -ObjectDetail.defaultProps = { +CodeDetail.defaultProps = { rows: null, }; -export default ObjectDetail; +export default CodeDetail; diff --git a/awx/ui_next/src/components/DetailList/index.js b/awx/ui_next/src/components/DetailList/index.js index 332cfa2f6b..d5e2ccd8a4 100644 --- a/awx/ui_next/src/components/DetailList/index.js +++ b/awx/ui_next/src/components/DetailList/index.js @@ -5,7 +5,7 @@ export { default as UserDateDetail } from './UserDateDetail'; export { default as DetailBadge } from './DetailBadge'; export { default as ArrayDetail } from './ArrayDetail'; /* - NOTE: ObjectDetail cannot be imported here, as it causes circular + NOTE: CodeDetail cannot be imported here, as it causes circular dependencies in testing environment. Import it directly from DetailList/ObjectDetail */ diff --git a/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplate.jsx b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplate.jsx index 005dd0e40b..cd9f60f968 100644 --- a/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplate.jsx +++ b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplate.jsx @@ -106,6 +106,7 @@ function NotificationTemplate({ setBreadcrumb, i18n }) { diff --git a/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.jsx b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.jsx index 6b19621c54..4d178fa7db 100644 --- a/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.jsx +++ b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.jsx @@ -11,19 +11,21 @@ import { DetailList, DeletedDetail, } from '../../../components/DetailList'; -import ObjectDetail from '../../../components/DetailList/ObjectDetail'; +import CodeDetail from '../../../components/DetailList/CodeDetail'; import DeleteButton from '../../../components/DeleteButton'; import ErrorDetail from '../../../components/ErrorDetail'; import { NotificationTemplatesAPI } from '../../../api'; import useRequest, { useDismissableError } from '../../../util/useRequest'; +import hasCustomMessages from '../shared/hasCustomMessages'; import { NOTIFICATION_TYPES } from '../constants'; -function NotificationTemplateDetail({ i18n, template }) { +function NotificationTemplateDetail({ i18n, template, defaultMessages }) { const history = useHistory(); const { notification_configuration: configuration, summary_fields, + messages, } = template; const { request: deleteTemplate, isLoading, error: deleteError } = useRequest( @@ -34,6 +36,7 @@ function NotificationTemplateDetail({ i18n, template }) { ); const { error, dismissError } = useDismissableError(deleteError); + const typeMessageDefaults = defaultMessages[template.notification_type]; return ( @@ -275,7 +278,7 @@ function NotificationTemplateDetail({ i18n, template }) { dataCy="nt-detail-twilio-source-phone" /> @@ -312,14 +315,23 @@ function NotificationTemplateDetail({ i18n, template }) { value={configuration.http_method} dataCy="nt-detail-webhook-http-method" /> - )} + {hasCustomMessages(messages, typeMessageDefaults) && ( + + )} {summary_fields.user_capabilities && @@ -359,4 +371,164 @@ function NotificationTemplateDetail({ i18n, template }) { ); } +function CustomMessageDetails({ messages, defaults, type, i18n }) { + const showMessages = type !== 'webhook'; + const showBodies = ['email', 'pagerduty', 'webhook'].includes(type); + + return ( + <> + {showMessages && ( + + )} + {showBodies && ( + + )} + {showMessages && ( + + )} + {showBodies && ( + + )} + {showMessages && ( + + )} + {showBodies && ( + + )} + {showMessages && ( + + )} + {showBodies && ( + + )} + {showMessages && ( + + )} + {showBodies && ( + + )} + {showMessages && ( + + )} + {showBodies && ( + + )} + {showMessages && ( + + )} + {showBodies && ( + + )} + + ); +} + export default withI18n()(NotificationTemplateDetail); diff --git a/awx/ui_next/src/screens/NotificationTemplate/shared/NotificationTemplateForm.jsx b/awx/ui_next/src/screens/NotificationTemplate/shared/NotificationTemplateForm.jsx index 50477fabeb..d3fcda1521 100644 --- a/awx/ui_next/src/screens/NotificationTemplate/shared/NotificationTemplateForm.jsx +++ b/awx/ui_next/src/screens/NotificationTemplate/shared/NotificationTemplateForm.jsx @@ -13,6 +13,7 @@ import { required } from '../../../util/validators'; import { FormColumnLayout } from '../../../components/FormLayout'; import TypeInputsSubForm from './TypeInputsSubForm'; import CustomMessagesSubForm from './CustomMessagesSubForm'; +import hasCustomMessages from './hasCustomMessages'; import typeFieldNames, { initialConfigValues } from './typeFieldNames'; function NotificationTemplateFormFields({ i18n, defaultMessages }) { @@ -210,42 +211,6 @@ NotificationTemplateForm.defaultProps = { export default withI18n()(NotificationTemplateForm); -function hasCustomMessages(messages, defaults) { - return ( - isCustomized(messages.started, defaults.started) || - isCustomized(messages.success, defaults.success) || - isCustomized(messages.error, defaults.error) || - isCustomized( - messages.workflow_approval.approved, - defaults.workflow_approval.approved - ) || - isCustomized( - messages.workflow_approval.denied, - defaults.workflow_approval.denied - ) || - isCustomized( - messages.workflow_approval.running, - defaults.workflow_approval.running - ) || - isCustomized( - messages.workflow_approval.timed_out, - defaults.workflow_approval.timed_out - ) - ); -} -function isCustomized(message, defaultMessage) { - if (!message) { - return false; - } - if (message.message && message.message !== defaultMessage.message) { - return true; - } - if (message.body && message.body !== defaultMessage.body) { - return true; - } - return false; -} - function normalizeFields(values, defaultMessages) { return normalizeTypeFields(normalizeMessageFields(values, defaultMessages)); } diff --git a/awx/ui_next/src/screens/NotificationTemplate/shared/hasCustomMessages.js b/awx/ui_next/src/screens/NotificationTemplate/shared/hasCustomMessages.js new file mode 100644 index 0000000000..460bcfba0c --- /dev/null +++ b/awx/ui_next/src/screens/NotificationTemplate/shared/hasCustomMessages.js @@ -0,0 +1,40 @@ +export default function hasCustomMessages(messages, defaults) { + if (!messages) { + return false; + } + + return ( + isCustomized(messages.started, defaults.started) || + isCustomized(messages.success, defaults.success) || + isCustomized(messages.error, defaults.error) || + isCustomized( + messages.workflow_approval.approved, + defaults.workflow_approval.approved + ) || + isCustomized( + messages.workflow_approval.denied, + defaults.workflow_approval.denied + ) || + isCustomized( + messages.workflow_approval.running, + defaults.workflow_approval.running + ) || + isCustomized( + messages.workflow_approval.timed_out, + defaults.workflow_approval.timed_out + ) + ); +} + +function isCustomized(message, defaultMessage) { + if (!message) { + return false; + } + if (message.message && message.message !== defaultMessage.message) { + return true; + } + if (message.body && message.body !== defaultMessage.body) { + return true; + } + return false; +} From 6af427d4e126e65a92de3802745d11b883078637 Mon Sep 17 00:00:00 2001 From: Keith Grant Date: Tue, 8 Sep 2020 14:45:20 -0700 Subject: [PATCH 3/6] update test snapshot --- .../ResourceAccessListItem.test.jsx.snap | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/awx/ui_next/src/components/ResourceAccessList/__snapshots__/ResourceAccessListItem.test.jsx.snap b/awx/ui_next/src/components/ResourceAccessList/__snapshots__/ResourceAccessListItem.test.jsx.snap index 7c8126fb4d..d9bb8bed4e 100644 --- a/awx/ui_next/src/components/ResourceAccessList/__snapshots__/ResourceAccessListItem.test.jsx.snap +++ b/awx/ui_next/src/components/ResourceAccessList/__snapshots__/ResourceAccessListItem.test.jsx.snap @@ -407,12 +407,12 @@ exports[` initially renders succesfully 1`] = ` "componentStyle": ComponentStyle { "componentId": "sc-bwzfXH", "isStatic": false, - "lastClassName": "kVCDmm", + "lastClassName": "gAzXep", "rules": Array [ " display: grid; grid-gap: 20px; - align-items: center; + align-items: start; ", [Function], " @@ -433,15 +433,15 @@ exports[` initially renders succesfully 1`] = ` stacked={true} >
initially renders succesfully 1`] = ` "componentStyle": ComponentStyle { "componentId": "sc-bwzfXH", "isStatic": false, - "lastClassName": "kVCDmm", + "lastClassName": "gAzXep", "rules": Array [ " display: grid; grid-gap: 20px; - align-items: center; + align-items: start; ", [Function], " @@ -656,15 +656,15 @@ exports[` initially renders succesfully 1`] = ` stacked={true} >
Date: Mon, 14 Sep 2020 15:17:39 -0700 Subject: [PATCH 4/6] handle null messages.workflow_approval --- .../NotificationTemplateDetail.jsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.jsx b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.jsx index 4d178fa7db..5761e737a3 100644 --- a/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.jsx +++ b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.jsx @@ -435,7 +435,7 @@ function CustomMessageDetails({ messages, defaults, type, i18n }) { Date: Mon, 14 Sep 2020 16:05:03 -0700 Subject: [PATCH 5/6] handle null messages.workflow_approval some more --- .../shared/NotificationTemplateForm.jsx | 12 ++++++------ .../NotificationTemplate/shared/hasCustomMessages.js | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/awx/ui_next/src/screens/NotificationTemplate/shared/NotificationTemplateForm.jsx b/awx/ui_next/src/screens/NotificationTemplate/shared/NotificationTemplateForm.jsx index d3fcda1521..bc668d7686 100644 --- a/awx/ui_next/src/screens/NotificationTemplate/shared/NotificationTemplateForm.jsx +++ b/awx/ui_next/src/screens/NotificationTemplate/shared/NotificationTemplateForm.jsx @@ -118,8 +118,8 @@ function NotificationTemplateForm({ const defs = defaultMessages[template.notification_type || 'email']; const mergeDefaultMessages = (templ = {}, def) => { return { - message: templ.message || def.message || '', - body: templ.body || def.body || '', + message: templ?.message || def.message || '', + body: templ?.body || def.body || '', }; }; @@ -145,25 +145,25 @@ function NotificationTemplateForm({ workflow_approval: { approved: { ...mergeDefaultMessages( - messages.workflow_approval.approved, + messages.workflow_approval?.approved, defs.workflow_approval.approved ), }, denied: { ...mergeDefaultMessages( - messages.workflow_approval.denied, + messages.workflow_approval?.denied, defs.workflow_approval.denied ), }, running: { ...mergeDefaultMessages( - messages.workflow_approval.running, + messages.workflow_approval?.running, defs.workflow_approval.running ), }, timed_out: { ...mergeDefaultMessages( - messages.workflow_approval.timed_out, + messages.workflow_approval?.timed_out, defs.workflow_approval.timed_out ), }, diff --git a/awx/ui_next/src/screens/NotificationTemplate/shared/hasCustomMessages.js b/awx/ui_next/src/screens/NotificationTemplate/shared/hasCustomMessages.js index 460bcfba0c..418adaf852 100644 --- a/awx/ui_next/src/screens/NotificationTemplate/shared/hasCustomMessages.js +++ b/awx/ui_next/src/screens/NotificationTemplate/shared/hasCustomMessages.js @@ -8,19 +8,19 @@ export default function hasCustomMessages(messages, defaults) { isCustomized(messages.success, defaults.success) || isCustomized(messages.error, defaults.error) || isCustomized( - messages.workflow_approval.approved, + messages.workflow_approval?.approved, defaults.workflow_approval.approved ) || isCustomized( - messages.workflow_approval.denied, + messages.workflow_approval?.denied, defaults.workflow_approval.denied ) || isCustomized( - messages.workflow_approval.running, + messages.workflow_approval?.running, defaults.workflow_approval.running ) || isCustomized( - messages.workflow_approval.timed_out, + messages.workflow_approval?.timed_out, defaults.workflow_approval.timed_out ) ); From fa0abc0dd876e50886c55aafd9b132858e4ce673 Mon Sep 17 00:00:00 2001 From: Keith Grant Date: Tue, 15 Sep 2020 10:56:55 -0700 Subject: [PATCH 6/6] notification templates: fix un-select all --- .../NotificationTemplateList/NotificationTemplateList.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateList/NotificationTemplateList.jsx b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateList/NotificationTemplateList.jsx index 3dac16f6a2..8b2b721b04 100644 --- a/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateList/NotificationTemplateList.jsx +++ b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateList/NotificationTemplateList.jsx @@ -124,7 +124,7 @@ function NotificationTemplatesList({ i18n }) { {...props} showSelectAll isAllSelected={isAllSelected} - onSelectAll={() => setSelected([...templates])} + onSelectAll={set => setSelected(set ? [...templates] : [])} qsConfig={QS_CONFIG} additionalControls={[ ...(canAdd