mirror of
https://github.com/ansible/awx.git
synced 2026-05-19 14:57:39 -02:30
Adds popover for Notification Templates and Instance group details (#12197)
This commit is contained in:
@@ -154,7 +154,7 @@ VariablesDetail.propTypes = {
|
|||||||
label: node.isRequired,
|
label: node.isRequired,
|
||||||
rows: oneOfType([number, string]),
|
rows: oneOfType([number, string]),
|
||||||
dataCy: string,
|
dataCy: string,
|
||||||
helpText: string,
|
helpText: oneOfType([node, string]),
|
||||||
name: string.isRequired,
|
name: string.isRequired,
|
||||||
};
|
};
|
||||||
VariablesDetail.defaultProps = {
|
VariablesDetail.defaultProps = {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import React from 'react';
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { TextListItemVariants } from '@patternfly/react-core';
|
import { TextListItemVariants } from '@patternfly/react-core';
|
||||||
import { DetailName, DetailValue } from './Detail';
|
import { DetailName, DetailValue } from './Detail';
|
||||||
|
import Popover from '../Popover';
|
||||||
|
|
||||||
const Value = styled(DetailValue)`
|
const Value = styled(DetailValue)`
|
||||||
margin-top: var(--pf-global--spacer--xs);
|
margin-top: var(--pf-global--spacer--xs);
|
||||||
@@ -12,7 +13,7 @@ const Value = styled(DetailValue)`
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
function ArrayDetail({ label, value, dataCy }) {
|
function ArrayDetail({ label, helpText, value, dataCy }) {
|
||||||
const labelCy = dataCy ? `${dataCy}-label` : null;
|
const labelCy = dataCy ? `${dataCy}-label` : null;
|
||||||
const valueCy = dataCy ? `${dataCy}-value` : null;
|
const valueCy = dataCy ? `${dataCy}-value` : null;
|
||||||
|
|
||||||
@@ -22,6 +23,7 @@ function ArrayDetail({ label, value, dataCy }) {
|
|||||||
<div css="grid-column: span 2">
|
<div css="grid-column: span 2">
|
||||||
<DetailName component={TextListItemVariants.dt} data-cy={labelCy}>
|
<DetailName component={TextListItemVariants.dt} data-cy={labelCy}>
|
||||||
{label}
|
{label}
|
||||||
|
{helpText && <Popover header={label} content={helpText} id={dataCy} />}
|
||||||
</DetailName>
|
</DetailName>
|
||||||
<Value component={TextListItemVariants.dd} data-cy={valueCy}>
|
<Value component={TextListItemVariants.dd} data-cy={valueCy}>
|
||||||
{vals.map((v) => (
|
{vals.map((v) => (
|
||||||
|
|||||||
@@ -9,11 +9,12 @@ const Detail = styled(_Detail)`
|
|||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
function DetailBadge({ label, content, dataCy = null }) {
|
function DetailBadge({ label, helpText, content, dataCy = null }) {
|
||||||
return (
|
return (
|
||||||
<Detail
|
<Detail
|
||||||
label={label}
|
label={label}
|
||||||
dataCy={dataCy}
|
dataCy={dataCy}
|
||||||
|
helpText={helpText}
|
||||||
value={<Badge isRead>{content}</Badge>}
|
value={<Badge isRead>{content}</Badge>}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ function ContainerGroupDetails({ instanceGroup }) {
|
|||||||
{instanceGroup.summary_fields.credential && (
|
{instanceGroup.summary_fields.credential && (
|
||||||
<Detail
|
<Detail
|
||||||
label={t`Credential`}
|
label={t`Credential`}
|
||||||
|
helpText={t`Credential to authenticate with Kubernetes or OpenShift`}
|
||||||
value={
|
value={
|
||||||
<Link
|
<Link
|
||||||
to={`/credentials/${instanceGroup?.summary_fields?.credential?.id}`}
|
to={`/credentials/${instanceGroup?.summary_fields?.credential?.id}`}
|
||||||
@@ -81,6 +82,7 @@ function ContainerGroupDetails({ instanceGroup }) {
|
|||||||
: instanceGroup.pod_spec_override
|
: instanceGroup.pod_spec_override
|
||||||
}
|
}
|
||||||
rows={6}
|
rows={6}
|
||||||
|
helpText={t`Custom Kubernetes or OpenShift Pod specification.`}
|
||||||
name="pod_spec_override"
|
name="pod_spec_override"
|
||||||
dataCy="container-group-detail-pod-spec-override"
|
dataCy="container-group-detail-pod-spec-override"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -62,10 +62,14 @@ function InstanceGroupDetails({ instanceGroup }) {
|
|||||||
<DetailBadge
|
<DetailBadge
|
||||||
label={t`Policy instance minimum`}
|
label={t`Policy instance minimum`}
|
||||||
dataCy="instance-group-policy-instance-minimum"
|
dataCy="instance-group-policy-instance-minimum"
|
||||||
|
helpText={t`Minimum number of instances that will be automatically
|
||||||
|
assigned to this group when new instances come online.`}
|
||||||
content={instanceGroup.policy_instance_minimum}
|
content={instanceGroup.policy_instance_minimum}
|
||||||
/>
|
/>
|
||||||
<DetailBadge
|
<DetailBadge
|
||||||
label={t`Policy instance percentage`}
|
label={t`Policy instance percentage`}
|
||||||
|
helpText={t`Minimum percentage of all instances that will be automatically
|
||||||
|
assigned to this group when new instances come online.`}
|
||||||
dataCy="instance-group-policy-instance-percentage"
|
dataCy="instance-group-policy-instance-percentage"
|
||||||
content={`${instanceGroup.policy_instance_percentage} %`}
|
content={`${instanceGroup.policy_instance_percentage} %`}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import useRequest, { useDismissableError } from 'hooks/useRequest';
|
|||||||
import StatusLabel from 'components/StatusLabel';
|
import StatusLabel from 'components/StatusLabel';
|
||||||
import hasCustomMessages from '../shared/hasCustomMessages';
|
import hasCustomMessages from '../shared/hasCustomMessages';
|
||||||
import { NOTIFICATION_TYPES } from '../constants';
|
import { NOTIFICATION_TYPES } from '../constants';
|
||||||
|
import helpText from '../shared/Notifications.helptext';
|
||||||
|
|
||||||
const NUM_RETRIES = 25;
|
const NUM_RETRIES = 25;
|
||||||
const RETRY_TIMEOUT = 5000;
|
const RETRY_TIMEOUT = 5000;
|
||||||
@@ -34,7 +35,6 @@ function NotificationTemplateDetail({ template, defaultMessages }) {
|
|||||||
const [testStatus, setTestStatus] = useState(
|
const [testStatus, setTestStatus] = useState(
|
||||||
template.summary_fields?.recent_notifications[0]?.status ?? undefined
|
template.summary_fields?.recent_notifications[0]?.status ?? undefined
|
||||||
);
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
created,
|
created,
|
||||||
modified,
|
modified,
|
||||||
@@ -151,6 +151,7 @@ function NotificationTemplateDetail({ template, defaultMessages }) {
|
|||||||
/>
|
/>
|
||||||
<ArrayDetail
|
<ArrayDetail
|
||||||
label={t`Recipient List`}
|
label={t`Recipient List`}
|
||||||
|
helpText={helpText.emailRecepients}
|
||||||
value={configuration.recipients}
|
value={configuration.recipients}
|
||||||
dataCy="nt-detail-recipients"
|
dataCy="nt-detail-recipients"
|
||||||
/>
|
/>
|
||||||
@@ -166,6 +167,7 @@ function NotificationTemplateDetail({ template, defaultMessages }) {
|
|||||||
/>
|
/>
|
||||||
<Detail
|
<Detail
|
||||||
label={t`Timeout`}
|
label={t`Timeout`}
|
||||||
|
helpText={helpText.emailTimeout}
|
||||||
value={configuration.timeout}
|
value={configuration.timeout}
|
||||||
dataCy="nt-detail-timeout"
|
dataCy="nt-detail-timeout"
|
||||||
/>
|
/>
|
||||||
@@ -178,6 +180,7 @@ function NotificationTemplateDetail({ template, defaultMessages }) {
|
|||||||
<>
|
<>
|
||||||
<Detail
|
<Detail
|
||||||
label={t`Grafana URL`}
|
label={t`Grafana URL`}
|
||||||
|
helpText={helpText.grafanaUrl}
|
||||||
value={configuration.grafana_url}
|
value={configuration.grafana_url}
|
||||||
dataCy="nt-detail-grafana-url"
|
dataCy="nt-detail-grafana-url"
|
||||||
/>
|
/>
|
||||||
@@ -193,6 +196,7 @@ function NotificationTemplateDetail({ template, defaultMessages }) {
|
|||||||
/>
|
/>
|
||||||
<ArrayDetail
|
<ArrayDetail
|
||||||
label={t`Tags for the Annotation`}
|
label={t`Tags for the Annotation`}
|
||||||
|
helpText={helpText.grafanaTags}
|
||||||
value={configuration.annotation_tags}
|
value={configuration.annotation_tags}
|
||||||
dataCy="nt-detail-"
|
dataCy="nt-detail-"
|
||||||
/>
|
/>
|
||||||
@@ -222,6 +226,7 @@ function NotificationTemplateDetail({ template, defaultMessages }) {
|
|||||||
/>
|
/>
|
||||||
<ArrayDetail
|
<ArrayDetail
|
||||||
label={t`Destination Channels or Users`}
|
label={t`Destination Channels or Users`}
|
||||||
|
helpText={helpText.ircTargets}
|
||||||
value={configuration.targets}
|
value={configuration.targets}
|
||||||
dataCy="nt-detail-channels"
|
dataCy="nt-detail-channels"
|
||||||
/>
|
/>
|
||||||
@@ -311,11 +316,13 @@ function NotificationTemplateDetail({ template, defaultMessages }) {
|
|||||||
{template.notification_type === 'slack' && (
|
{template.notification_type === 'slack' && (
|
||||||
<>
|
<>
|
||||||
<ArrayDetail
|
<ArrayDetail
|
||||||
|
helpText={helpText.slackChannels}
|
||||||
label={t`Destination Channels`}
|
label={t`Destination Channels`}
|
||||||
value={configuration.channels}
|
value={configuration.channels}
|
||||||
dataCy="nt-detail-slack-channels"
|
dataCy="nt-detail-slack-channels"
|
||||||
/>
|
/>
|
||||||
<Detail
|
<Detail
|
||||||
|
helpText={helpText.slackColor}
|
||||||
label={t`Notification Color`}
|
label={t`Notification Color`}
|
||||||
value={configuration.hex_color}
|
value={configuration.hex_color}
|
||||||
dataCy="nt-detail-slack-color"
|
dataCy="nt-detail-slack-color"
|
||||||
@@ -326,11 +333,13 @@ function NotificationTemplateDetail({ template, defaultMessages }) {
|
|||||||
<>
|
<>
|
||||||
<Detail
|
<Detail
|
||||||
label={t`Source Phone Number`}
|
label={t`Source Phone Number`}
|
||||||
|
helpText={helpText.twilioSourcePhoneNumber}
|
||||||
value={configuration.from_number}
|
value={configuration.from_number}
|
||||||
dataCy="nt-detail-twilio-source-phone"
|
dataCy="nt-detail-twilio-source-phone"
|
||||||
/>
|
/>
|
||||||
<ArrayDetail
|
<ArrayDetail
|
||||||
label={t`Destination SMS Number(s)`}
|
label={t`Destination SMS Number(s)`}
|
||||||
|
helpText={helpText.twilioDestinationNumbers}
|
||||||
value={configuration.to_numbers}
|
value={configuration.to_numbers}
|
||||||
dataCy="nt-detail-twilio-destination-numbers"
|
dataCy="nt-detail-twilio-destination-numbers"
|
||||||
/>
|
/>
|
||||||
@@ -367,6 +376,7 @@ function NotificationTemplateDetail({ template, defaultMessages }) {
|
|||||||
/>
|
/>
|
||||||
<CodeDetail
|
<CodeDetail
|
||||||
label={t`HTTP Headers`}
|
label={t`HTTP Headers`}
|
||||||
|
helpText={helpText.webhookHeaders}
|
||||||
value={JSON.stringify(configuration.headers)}
|
value={JSON.stringify(configuration.headers)}
|
||||||
mode="json"
|
mode="json"
|
||||||
rows={6}
|
rows={6}
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { t } from '@lingui/macro';
|
||||||
|
|
||||||
|
const helpText = {
|
||||||
|
emailRecepients: t`Use one email address per line to create a recipient list for this type of notification.`,
|
||||||
|
emailTimeout: t`The amount of time (in seconds) before the email
|
||||||
|
notification stops trying to reach the host and times out. Ranges
|
||||||
|
from 1 to 120 seconds.`,
|
||||||
|
grafanaUrl: t`The base URL of the Grafana server - the
|
||||||
|
/api/annotations endpoint will be added automatically to the base
|
||||||
|
Grafana URL.`,
|
||||||
|
grafanaTags: t`Use one Annotation Tag per line, without commas.`,
|
||||||
|
ircTargets: t`Use one IRC channel or username per line. The pound
|
||||||
|
symbol (#) for channels, and the at (@) symbol for users, are not
|
||||||
|
required.`,
|
||||||
|
slackChannels: (
|
||||||
|
<>
|
||||||
|
{t`One Slack channel per line. The pound symbol (#)
|
||||||
|
is required for channels. To respond to or start a thread to a specific message add the parent message Id to the channel where the parent message Id is 16 digits. A dot (.) must be manually inserted after the 10th digit. ie:#destination-channel, 1231257890.006423. See Slack`}{' '}
|
||||||
|
<a href="https://api.slack.com/messaging/retrieving#individual_messages">{t`documentation`}</a>{' '}
|
||||||
|
<span>{t`for more information.`}</span>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
slackColor: t`Specify a notification color. Acceptable colors are hex
|
||||||
|
color code (example: #3af or #789abc).`,
|
||||||
|
twilioSourcePhoneNumber: t`The number associated with the "Messaging
|
||||||
|
Service" in Twilio with the format +18005550199.`,
|
||||||
|
twilioDestinationNumbers: t`Use one phone number per line to specify where to
|
||||||
|
route SMS messages. Phone numbers should be formatted +11231231234. For more information see Twilio documentation`,
|
||||||
|
webhookHeaders: t`Specify HTTP Headers in JSON format. Refer to
|
||||||
|
the Ansible Tower documentation for example syntax.`,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default helpText;
|
||||||
@@ -25,6 +25,7 @@ import {
|
|||||||
twilioPhoneNumber,
|
twilioPhoneNumber,
|
||||||
} from 'util/validators';
|
} from 'util/validators';
|
||||||
import { NotificationType } from 'types';
|
import { NotificationType } from 'types';
|
||||||
|
import helpText from './Notifications.helptext';
|
||||||
|
|
||||||
const TypeFields = {
|
const TypeFields = {
|
||||||
email: EmailFields,
|
email: EmailFields,
|
||||||
@@ -37,7 +38,6 @@ const TypeFields = {
|
|||||||
twilio: TwilioFields,
|
twilio: TwilioFields,
|
||||||
webhook: WebhookFields,
|
webhook: WebhookFields,
|
||||||
};
|
};
|
||||||
|
|
||||||
function TypeInputsSubForm({ type }) {
|
function TypeInputsSubForm({ type }) {
|
||||||
const Fields = TypeFields[type];
|
const Fields = TypeFields[type];
|
||||||
return (
|
return (
|
||||||
@@ -87,8 +87,7 @@ function EmailFields() {
|
|||||||
validate={required(null)}
|
validate={required(null)}
|
||||||
isRequired
|
isRequired
|
||||||
rows={3}
|
rows={3}
|
||||||
tooltip={t`Enter one email address per line to create a recipient
|
tooltip={helpText.emailRecepients}
|
||||||
list for this type of notification.`}
|
|
||||||
/>
|
/>
|
||||||
<FormField
|
<FormField
|
||||||
id="email-sender"
|
id="email-sender"
|
||||||
@@ -117,9 +116,7 @@ function EmailFields() {
|
|||||||
isRequired
|
isRequired
|
||||||
min="1"
|
min="1"
|
||||||
max="120"
|
max="120"
|
||||||
tooltip={t`The amount of time (in seconds) before the email
|
tooltip={helpText.emailTimeout}
|
||||||
notification stops trying to reach the host and times out. Ranges
|
|
||||||
from 1 to 120 seconds.`}
|
|
||||||
/>
|
/>
|
||||||
<FormGroup fieldId="email-options" label={t`E-mail options`}>
|
<FormGroup fieldId="email-options" label={t`E-mail options`}>
|
||||||
<FormCheckboxLayout>
|
<FormCheckboxLayout>
|
||||||
@@ -149,9 +146,7 @@ function GrafanaFields() {
|
|||||||
type="text"
|
type="text"
|
||||||
validate={required(null)}
|
validate={required(null)}
|
||||||
isRequired
|
isRequired
|
||||||
tooltip={t`The base URL of the Grafana server - the
|
tooltip={helpText.grafanaUrl}
|
||||||
/api/annotations endpoint will be added automatically to the base
|
|
||||||
Grafana URL.`}
|
|
||||||
/>
|
/>
|
||||||
<PasswordField
|
<PasswordField
|
||||||
id="grafana-key"
|
id="grafana-key"
|
||||||
@@ -178,7 +173,7 @@ function GrafanaFields() {
|
|||||||
name="notification_configuration.annotation_tags"
|
name="notification_configuration.annotation_tags"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
rows={3}
|
rows={3}
|
||||||
tooltip={t`Enter one Annotation Tag per line, without commas.`}
|
tooltip={helpText.grafanaTags}
|
||||||
/>
|
/>
|
||||||
<CheckboxField
|
<CheckboxField
|
||||||
id="grafana-ssl"
|
id="grafana-ssl"
|
||||||
@@ -229,9 +224,7 @@ function IRCFields() {
|
|||||||
type="textarea"
|
type="textarea"
|
||||||
validate={required(null)}
|
validate={required(null)}
|
||||||
isRequired
|
isRequired
|
||||||
tooltip={t`Enter one IRC channel or username per line. The pound
|
tooltip={helpText.ircTargets}
|
||||||
symbol (#) for channels, and the at (@) symbol for users, are not
|
|
||||||
required.`}
|
|
||||||
/>
|
/>
|
||||||
<CheckboxField
|
<CheckboxField
|
||||||
id="grafana-ssl"
|
id="grafana-ssl"
|
||||||
@@ -362,14 +355,7 @@ function SlackFields() {
|
|||||||
type="textarea"
|
type="textarea"
|
||||||
validate={required(null)}
|
validate={required(null)}
|
||||||
isRequired
|
isRequired
|
||||||
tooltip={
|
tooltip={helpText.slackChannels}
|
||||||
<>
|
|
||||||
{t`Enter one Slack channel per line. The pound symbol (#)
|
|
||||||
is required for channels. To respond to or start a thread to a specific message add the parent message Id to the channel where the parent message Id is 16 digits. A dot (.) must be manually inserted after the 10th digit. ie:#destination-channel, 1231257890.006423. See Slack`}{' '}
|
|
||||||
<a href="https://api.slack.com/messaging/retrieving#individual_messages">{t`documentation`}</a>{' '}
|
|
||||||
<span>{t`for more information.`}</span>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<PasswordField
|
<PasswordField
|
||||||
id="slack-token"
|
id="slack-token"
|
||||||
@@ -383,8 +369,7 @@ function SlackFields() {
|
|||||||
label={t`Notification color`}
|
label={t`Notification color`}
|
||||||
name="notification_configuration.hex_color"
|
name="notification_configuration.hex_color"
|
||||||
type="text"
|
type="text"
|
||||||
tooltip={t`Specify a notification color. Acceptable colors are hex
|
tooltip={helpText.slackColor}
|
||||||
color code (example: #3af or #789abc).`}
|
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@@ -407,8 +392,7 @@ function TwilioFields() {
|
|||||||
type="text"
|
type="text"
|
||||||
validate={combine([required(null), twilioPhoneNumber()])}
|
validate={combine([required(null), twilioPhoneNumber()])}
|
||||||
isRequired
|
isRequired
|
||||||
tooltip={t`Enter the number associated with the "Messaging
|
tooltip={helpText.twilioSourcePhoneNumber}
|
||||||
Service" in Twilio in the format +18005550199.`}
|
|
||||||
/>
|
/>
|
||||||
<ArrayTextField
|
<ArrayTextField
|
||||||
id="twilio-destination-numbers"
|
id="twilio-destination-numbers"
|
||||||
@@ -417,8 +401,7 @@ function TwilioFields() {
|
|||||||
type="textarea"
|
type="textarea"
|
||||||
validate={combine([required(null), twilioPhoneNumber()])}
|
validate={combine([required(null), twilioPhoneNumber()])}
|
||||||
isRequired
|
isRequired
|
||||||
tooltip={t`Enter one phone number per line to specify where to
|
tooltip={helpText.twilioDestinationNumbers}
|
||||||
route SMS messages. Phone numbers should be formatted +11231231234. For more information see Twilio documentation`}
|
|
||||||
/>
|
/>
|
||||||
<FormField
|
<FormField
|
||||||
id="twilio-account-sid"
|
id="twilio-account-sid"
|
||||||
@@ -469,8 +452,7 @@ function WebhookFields() {
|
|||||||
name="notification_configuration.headers"
|
name="notification_configuration.headers"
|
||||||
label={t`HTTP Headers`}
|
label={t`HTTP Headers`}
|
||||||
mode="javascript"
|
mode="javascript"
|
||||||
tooltip={t`Specify HTTP Headers in JSON format. Refer to
|
tooltip={helpText.webhookHeaders}
|
||||||
the Ansible Tower documentation for example syntax.`}
|
|
||||||
rows={5}
|
rows={5}
|
||||||
/>
|
/>
|
||||||
</FormFullWidthLayout>
|
</FormFullWidthLayout>
|
||||||
|
|||||||
Reference in New Issue
Block a user