Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EPMRPP-89476 || CRUD for Slack Notification rule with dynamic fields #3821

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/localization/translated/be.json
Original file line number Diff line number Diff line change
Expand Up @@ -1485,7 +1485,7 @@
"NotificationsEnableForm.integrationSettings": "Налады інтэграцыі",
"NotificationsEnableForm.integrationSettingsDescription": "Наладзьце злучэнне плагінаў з серверамі",
"NotificationsEnableForm.notConfiguredIntegration": "Integration not configured yet",
"NotificationsEnableForm.tabDescription": "Кіруйце апавяшчэннямі аб запуску для розных каналаў сувязі: Email, Slack, Teams і г.д.",
"NotificationsEnableForm.tabDescription": "Кіруйце апавяшчэннямі аб запуску для розных каналаў сувязі: Email, Slack, і г.д.",
"NotificationsEnableForm.title": "Няма інтэграцыі з E-mail серверам",
"NotificationsEnableForm.toggleNotificationsLabel": "Аўтаматычныя апавяшчэнні па электроннай пошце",
"NotificationsEnableForm.toggleNotificationsNote": "Адпраўляць апавяшчэнні па электроннай пошце аб заканчэнні запуску",
Expand Down
2 changes: 1 addition & 1 deletion app/localization/translated/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -1485,7 +1485,7 @@
"NotificationsEnableForm.integrationSettings": "Настройки интеграции",
"NotificationsEnableForm.integrationSettingsDescription": "Настройте соединение плагинов с серверами",
"NotificationsEnableForm.notConfiguredIntegration": "Интеграция еще не настроена",
"NotificationsEnableForm.tabDescription": "Управляйте уведомлениями, связанными с запуском, для разных каналов связи: E-mail, Slack, Teams и т. д.",
"NotificationsEnableForm.tabDescription": "Управляйте уведомлениями, связанными с запуском, для разных каналов связи: E-mail, Slack, и т. д.",
"NotificationsEnableForm.title": "Нет интеграции с E-mail сервером",
"NotificationsEnableForm.toggleNotificationsLabel": "Автоматические уведомления по электронной почте",
"NotificationsEnableForm.toggleNotificationsNote": "Отправлять уведомления по электронной почте о завершении запуска",
Expand Down
2 changes: 1 addition & 1 deletion app/localization/translated/uk.json
Original file line number Diff line number Diff line change
Expand Up @@ -1485,7 +1485,7 @@
"NotificationsEnableForm.integrationSettings": "Налаштування інтеграції",
"NotificationsEnableForm.integrationSettingsDescription": "Налаштувати підключення плагінів до серверів",
"NotificationsEnableForm.notConfiguredIntegration": "Інтеграцію ще не налаштовано",
"NotificationsEnableForm.tabDescription": "Керуйте повідомленнями, пов'язаними із запуском, для різних каналів зв'язку: Email, Slack, Teams і т.д.",
"NotificationsEnableForm.tabDescription": "Керуйте повідомленнями, пов'язаними із запуском, для різних каналів зв'язку: Email, Slack, і т.д.",
"NotificationsEnableForm.title": "Немає інтеграції з електронною поштою сервером",
"NotificationsEnableForm.toggleNotificationsLabel": "Автоматичне сповіщення електронною поштою",
"NotificationsEnableForm.toggleNotificationsNote": "Надсилайте сповіщення електронною поштою про завершення запуску",
Expand Down
4 changes: 2 additions & 2 deletions app/localization/translated/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -1485,7 +1485,7 @@
"NotificationsEnableForm.integrationSettings": "集成设置",
"NotificationsEnableForm.integrationSettingsDescription": "配置插件与服务器的连接",
"NotificationsEnableForm.notConfiguredIntegration": "尚未配置集成",
"NotificationsEnableForm.tabDescription": "跨多个通信渠道管理与启动相关的通知:Email、Slack、Teams 等。",
"NotificationsEnableForm.tabDescription": "跨多个通信渠道管理与启动相关的通知:Email、Slack, 等。",
"NotificationsEnableForm.title": "未与电子邮件集成",
"NotificationsEnableForm.toggleNotificationsLabel": "电子邮件通知",
"NotificationsEnableForm.toggleNotificationsNote": "在启测试任务成时发送电子邮件通知",
Expand Down Expand Up @@ -2190,4 +2190,4 @@
"usersGrid.roleNonAdmin": "非管理",
"usersGrid.type": "类型",
"usersGrid.user": "登录"
}
}
4 changes: 2 additions & 2 deletions app/src/controllers/project/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ export const projectNotificationsSelector = createSelector(
({ notifications = [] }) =>
notifications.map((notification) => ({
...notification,
informOwner: notification.recipients.includes(OWNER),
recipients: notification.recipients.filter((item) => item !== OWNER),
informOwner: notification.recipients?.includes(OWNER),
recipients: notification.recipients?.filter((item) => item !== OWNER),
})),
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@
* limitations under the License.
*/

import React from 'react';
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames/bind';
import { defineMessages, useIntl } from 'react-intl';
import { AttributeListContainer } from 'components/containers/attributeListContainer';
import { EMAIL } from 'common/constants/pluginNames';
import { ruleField } from 'pages/inside/projectSettingsPageContainer/content/notifications/propTypes';
import { ATTRIBUTES_OPERATORS, LAUNCH_CASES } from '../../notifications/constants';
import styles from './notificationRuleContent.scss';

Expand Down Expand Up @@ -81,7 +83,17 @@ const messages = defineMessages({
});

export const NotificationRuleContent = ({
item: { informOwner, recipients, attributes, attributesOperator, launchNames, sendCase },
item: {
type,
informOwner,
recipients,
attributes,
attributesOperator,
launchNames,
sendCase,
ruleDetails,
ruleFields,
},
}) => {
const { formatMessage } = useIntl();

Expand Down Expand Up @@ -109,6 +121,31 @@ export const NotificationRuleContent = ({
return formatMessage(messages.attributesLabel);
}
};
const renderDynamicFields = () => {
if (type === EMAIL)
return (
<>
<span className={cx('field')}>{formatMessage(messages.recipientsLabel)}</span>
<span className={cx('value')}>{recipientsValue.join(SEPARATOR)}</span>
</>
);
else {
return (
ruleDetails &&
ruleFields.reduce((acc, field) => {
if (ruleDetails[field.name]) {
acc.push(
<Fragment key={field.name}>
<span className={cx('field')}>{field.label}</span>
<span className={cx('value')}>{ruleDetails[field.name]}</span>
</Fragment>,
);
}
return acc;
}, [])
);
}
};

return (
<div className={cx('info')}>
Expand All @@ -120,8 +157,7 @@ export const NotificationRuleContent = ({
)}
<span className={cx('field')}>{formatMessage(messages.inCaseLabel)}</span>
<span className={cx('value')}>{inCaseOptions[sendCase]}</span>
<span className={cx('field')}>{formatMessage(messages.recipientsLabel)}</span>
<span className={cx('value')}>{recipientsValue.join(SEPARATOR)}</span>
{renderDynamicFields()}
{attributes.length > 0 && (
<>
<span className={cx('field', 'attributes-text')}>{getAttributesFieldText()}</span>
Expand All @@ -133,13 +169,17 @@ export const NotificationRuleContent = ({
</div>
);
};

NotificationRuleContent.propTypes = {
item: PropTypes.shape({
type: PropTypes.string.isRequired,
launchNames: PropTypes.array,
sendCase: PropTypes.string,
recipients: PropTypes.array,
attributes: PropTypes.array,
informOwner: PropTypes.bool,
ruleDetails: PropTypes.object,
ruleFields: PropTypes.arrayOf(ruleField),
attributesOperator: PropTypes.oneOf([ATTRIBUTES_OPERATORS.AND, ATTRIBUTES_OPERATORS.OR]),
}).isRequired,
};
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ export const LAUNCH_NAMES_FIELD_KEY = 'launchNames';
export const ATTRIBUTES_FIELD_KEY = 'attributes';
export const ENABLED_FIELD_KEY = 'enabled';
export const ATTRIBUTES_OPERATOR_FIELD_KEY = 'attributesOperator';
export const FIELD_TYPE_TEXT = 'text';
export const FIELD_TYPE_MULTILINE_TEXT = 'multilineText';

export const LAUNCH_CASES = {
ALWAYS: 'always',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export const messages = defineMessages({
tabDescription: {
id: 'NotificationsEnableForm.tabDescription',
defaultMessage:
'Manage your launch related notifications for different communication channels: Email, Slack, Teams, etc. ',
'Manage your launch related notifications for different communication channels: Email, Slack, etc. ',
},
allNotifications: {
id: 'NotificationsEnableForm.allNotifications',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ import { Checkbox } from 'componentLibrary/checkbox';
import { PROJECT_SETTINGS_NOTIFICATIONS_EVENTS } from 'analyticsEvents/projectSettingsPageEvents';
import { AttributeListFormField } from 'components/containers/AttributeListFormField';
import { RadioGroup } from 'componentLibrary/radioGroup';
import { EMAIL } from 'common/constants/pluginNames';
import { FieldTextFlex } from 'componentLibrary/fieldTextFlex';
import { ruleField } from 'pages/inside/projectSettingsPageContainer/content/notifications/propTypes';
import { RecipientsContainer } from './recipientsContainer';
import { LaunchNamesContainer } from './launchNamesContainer';
import {
Expand All @@ -56,6 +59,8 @@ import {
RECIPIENTS_FIELD_KEY,
RULE_NAME_FIELD_KEY,
SEND_CASE_FIELD_KEY,
FIELD_TYPE_TEXT,
FIELD_TYPE_MULTILINE_TEXT,
} from '../../constants';
import styles from './addEditNotificationModal.scss';

Expand Down Expand Up @@ -196,6 +201,10 @@ const NOTIFICATION_FORM = 'notificationForm';

const attributesValueSelector = formValueSelector(NOTIFICATION_FORM);

const fieldByType = {
[FIELD_TYPE_TEXT]: FieldText,
[FIELD_TYPE_MULTILINE_TEXT]: FieldTextFlex,
};
const AddEditNotificationModal = ({
data,
data: { onSave },
Expand Down Expand Up @@ -333,25 +342,51 @@ const AddEditNotificationModal = ({
<FieldText label={formatMessage(messages.nameLabel)} defaultWidth={false} isRequired />
</FieldErrorHint>
</FieldProvider>
<FieldElement
name={RECIPIENTS_FIELD_KEY}
className={cx('autocomplete')}
type="text"
label={formatMessage(messages.recipientsLabel)}
dataAutomationId={RECIPIENTS_FIELD_KEY + FIELD}
>
<FieldErrorHint provideHint={false}>
<RecipientsContainer />
</FieldErrorHint>
</FieldElement>
<FieldElement
name={INFORM_OWNER_FIELD_KEY}
type="text"
className={cx('checkbox')}
dataAutomationId={INFORM_OWNER_FIELD_KEY + FIELD}
>
<Checkbox>{formatMessage(messages.launchOwnerLabel)}</Checkbox>
</FieldElement>
{data.type === EMAIL ? (
<>
<FieldElement
name={RECIPIENTS_FIELD_KEY}
className={cx('autocomplete')}
type="text"
label={formatMessage(messages.recipientsLabel)}
dataAutomationId={RECIPIENTS_FIELD_KEY + FIELD}
>
<FieldErrorHint provideHint={false}>
<RecipientsContainer />
</FieldErrorHint>
</FieldElement>
<FieldElement
name={INFORM_OWNER_FIELD_KEY}
type="text"
className={cx('checkbox')}
dataAutomationId={INFORM_OWNER_FIELD_KEY + FIELD}
>
<Checkbox>{formatMessage(messages.launchOwnerLabel)}</Checkbox>
</FieldElement>
</>
) : (
data.ruleFields.map((field) => {
AmsterGet marked this conversation as resolved.
Show resolved Hide resolved
const TypedComponent = fieldByType[field.type];
return (
<FieldElement
name={field.name}
key={field.name}
type={field.type}
className={cx('dynamicField')}
description={field.description}
>
<FieldErrorHint provideHint={false}>
<TypedComponent
label={field.label}
placeholder={field.placeholder}
defaultWidth={false}
isRequired={field.required}
/>
</FieldErrorHint>
</FieldElement>
);
})
)}
<FieldElement
label={formatMessage(messages.inCaseLabel)}
name={SEND_CASE_FIELD_KEY}
Expand Down Expand Up @@ -403,13 +438,37 @@ const AddEditNotificationModal = ({
</ModalLayout>
);
};

const getDynamicFieldValidation = (type, inputValues, ruleFields = []) => {
if (type === EMAIL) {
return {
recipients: bindMessageToValidator(
validate.createNotificationRecipientsValidator(inputValues.informOwner),
'recipientsHint',
)(inputValues.recipients),
};
} else {
return ruleFields.reduce((acc, field) => {
const { type: validationType, errorMessage } = field.validation || {};
if (validate[validationType]) {
acc[field.name] = bindMessageToValidator(
validate[validationType],
errorMessage,
)(inputValues[field.name]);
}
return acc;
}, {});
}
};

AddEditNotificationModal.propTypes = {
data: PropTypes.shape({
type: PropTypes.string,
notification: PropTypes.object,
notifications: PropTypes.array,
onSave: PropTypes.func,
eventsInfo: PropTypes.object,
ruleFields: PropTypes.arrayOf(ruleField),
actionType: PropTypes.oneOf([
MODAL_ACTION_TYPE_ADD,
MODAL_ACTION_TYPE_EDIT,
Expand All @@ -429,23 +488,19 @@ AddEditNotificationModal.defaultProps = {
export default withModal('addEditNotificationModal')(
reduxForm({
form: NOTIFICATION_FORM,
validate: (
{ ruleName, recipients, informOwner, launchNames, attributes },
{ data: { notification, notifications } },
) => ({
ruleName: commonValidators.createRuleNameValidator(
notifications.map((item) => ({ name: item.ruleName, ...item })),
notification?.id,
)(ruleName),
recipients: bindMessageToValidator(
validate.createNotificationRecipientsValidator(informOwner),
'recipientsHint',
)(recipients),
attributes: !validate.attributesArray(attributes),
launchNames: bindMessageToValidator(
validate.notificationLaunchNames,
'launchesHint',
)(launchNames),
}),
validate: (inputValues, { data: { type, notification, notifications, ruleFields } }) => {
return {
ruleName: commonValidators.createRuleNameValidator(
notifications.map((item) => ({ name: item.ruleName, ...item })),
notification?.id,
)(inputValues.ruleName),
...getDynamicFieldValidation(type, inputValues, ruleFields),
attributes: !validate.attributesArray(inputValues.attributes),
launchNames: bindMessageToValidator(
validate.notificationLaunchNames,
'launchesHint',
)(inputValues.launchNames),
};
},
})(AddEditNotificationModal),
);
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,8 @@
margin-top: 8px;
}
}

.dynamicField{
margin-top: 16px;
margin-bottom: 16px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,11 @@ export const Notifications = () => {
</Layout>
{allNotificationPlugins.map((item) => (
<RuleGroup
ruleFields={item.details.ruleFields}
key={`rule-section-${item.name}`}
pluginName={item.name}
isPluginEnabled={item.enabled}
typedRules={notificationRulesByTypes[item.name]}
notifications={notifications}
rules={notificationRulesByTypes[item.name] || []}
/>
))}
<NotificationsFooter />
Expand Down
Loading
Loading