diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/ic-delete.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/ic-delete.svg index 84699dec2ca..b9bc4e99afa 100644 --- a/openmetadata-ui/src/main/resources/ui/src/assets/svg/ic-delete.svg +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/ic-delete.svg @@ -1,4 +1,4 @@ - + diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/ic-edit.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/ic-edit.svg index 872f66d8db6..79dc2fa9600 100644 --- a/openmetadata-ui/src/main/resources/ui/src/assets/svg/ic-edit.svg +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/ic-edit.svg @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/openmetadata-ui/src/main/resources/ui/src/axiosAPIs/alertsAPI.ts b/openmetadata-ui/src/main/resources/ui/src/axiosAPIs/alertsAPI.ts index 8e7a794809a..4886bc8e6f8 100644 --- a/openmetadata-ui/src/main/resources/ui/src/axiosAPIs/alertsAPI.ts +++ b/openmetadata-ui/src/main/resources/ui/src/axiosAPIs/alertsAPI.ts @@ -40,7 +40,20 @@ export const getAlertsFromId = async ( params: { ...params, include: 'all', - fields: 'alertActions', + }, + }); + + return response.data; +}; + +export const getAlertsFromName = async ( + name: string, + params?: Pick +) => { + const response = await axiosClient.get(`${BASE_URL}/name/${name}`, { + params: { + ...params, + include: 'all', }, }); @@ -51,7 +64,6 @@ export const getAllAlerts = async (params: ListAlertsRequestParams) => { const response = await axiosClient.get>(BASE_URL, { params: { ...params, - fields: 'alertActions', }, }); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Alerts/AlertsDetails/AlertDetails.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Alerts/AlertsDetails/AlertDetails.component.tsx new file mode 100644 index 00000000000..900eb9ea283 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/Alerts/AlertsDetails/AlertDetails.component.tsx @@ -0,0 +1,234 @@ +/* + * Copyright 2022 Collate + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { CheckCircleOutlined, CloseCircleOutlined } from '@ant-design/icons'; +import Icon from '@ant-design/icons/lib/components/Icon'; +import { Button, Card, Col, Divider, Row, Space, Tag, Typography } from 'antd'; +import { isArray } from 'lodash'; +import React, { Fragment } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Link } from 'react-router-dom'; +import { ReactComponent as IconDelete } from '../../../assets/svg/ic-delete.svg'; +import { ReactComponent as IconEdit } from '../../../assets/svg/ic-edit.svg'; +import { + AlertAction, + AlertActionType, +} from '../../../generated/alerts/alertAction'; +import { + Alerts, + AlertTriggerType, + Effect, +} from '../../../generated/alerts/alerts'; +import { + EDIT_LINK_PATH, + getAlertActionTypeDisplayName, + getAlertsActionTypeIcon, + getDisplayNameForEntities, + getDisplayNameForTriggerType, + getFunctionDisplayName, +} from '../../../utils/Alerts/AlertsUtil'; +import { getHostNameFromURL } from '../../../utils/CommonUtils'; +import RichTextEditorPreviewer from '../../common/rich-text-editor/RichTextEditorPreviewer'; +import TitleBreadcrumb from '../../common/title-breadcrumb/title-breadcrumb.component'; +import { TitleBreadcrumbProps } from '../../common/title-breadcrumb/title-breadcrumb.interface'; + +interface AlertDetailsComponentProps { + alerts: Alerts; + alertActions: AlertAction[]; + onDelete: () => void; + breadcrumb: TitleBreadcrumbProps['titleLinks']; + allowDelete?: boolean; + allowEdit?: boolean; +} + +export const AlertDetailsComponent = ({ + alerts, + alertActions, + onDelete, + breadcrumb, + allowDelete = true, + allowEdit = true, +}: AlertDetailsComponentProps) => { + const { t } = useTranslation(); + + return ( + + +
+ + + {allowEdit && ( + + + + )} + {allowDelete && ( + + )} + +
+ + + + {alerts.description && ( + <> + + + + )} + + + + {t('label.trigger')} + + + {getDisplayNameForTriggerType( + alerts?.triggerConfig.type ?? AlertTriggerType.AllDataAssets + )} + : + + + {alerts?.triggerConfig.entities + ?.map(getDisplayNameForEntities) + ?.join(', ')} + + + + {t('label.filter')} + + {alerts?.filteringRules?.map((filter) => { + const conditions = isArray(filter.condition) + ? filter.condition.join(', ') + : filter.condition; + const effect = filter.effect === Effect.Include ? '===' : '!=='; + const conditionName = getFunctionDisplayName( + filter.fullyQualifiedName ?? '' + ); + + return ( + + + {`${conditionName} ${effect} ${conditions}`} + +
+
+ ); + })} +
+ + + {t('label.destination')} + + + {alertActions.map((action) => ( + + {action.alertActionType === AlertActionType.ActivityFeed ? ( + + {getAlertsActionTypeIcon(action.alertActionType)} + + {getAlertActionTypeDisplayName( + action.alertActionType ?? AlertActionType.GenericWebhook + )} + + ) : ( + }> + + {action.alertActionType === AlertActionType.Email && ( + <> + + {t('label.send-to')}:{' '} +
+ {action.alertActionConfig?.receivers?.map( + (rec) => ( + {rec} + ) + )} +
+
+ + + + {action.alertActionConfig.sendToAdmins ? ( + + ) : ( + + )}{' '} + {t('label.admin-plural')} + + + {action.alertActionConfig.sendToOwners ? ( + + ) : ( + + )}{' '} + {t('label.owner-plural')} + + + {action.alertActionConfig.sendToFollowers ? ( + + ) : ( + + )}{' '} + {t('label.follower-plural')} + + + + + )} + {action.alertActionType !== AlertActionType.Email && ( + <> + + + {t('label.webhook')}:{' '} + + {getHostNameFromURL( + action.alertActionConfig?.endpoint ?? '-' + )} + + + + {t('label.batch-size')}:{' '} + + {action.batchSize} + + + + {t('message.field-timeout-description')}:{' '} + + {action.timeout} + + + + {t('label.secret-key')}:{' '} + + + {action.alertActionConfig?.secretKey ? '****' : '-'} + + + )} +
+
+ )} + + ))} +
+
+ + + ); +}; diff --git a/openmetadata-ui/src/main/resources/ui/src/constants/GlobalSettings.constants.ts b/openmetadata-ui/src/main/resources/ui/src/constants/GlobalSettings.constants.ts index ca011061cd5..a6180e590f3 100644 --- a/openmetadata-ui/src/main/resources/ui/src/constants/GlobalSettings.constants.ts +++ b/openmetadata-ui/src/main/resources/ui/src/constants/GlobalSettings.constants.ts @@ -15,7 +15,7 @@ import { ResourceEntity } from '../components/PermissionProvider/PermissionProvi export enum GlobalSettingsMenuCategory { ACCESS = 'access', - COLLABORATION = 'collaboration', + NOTIFICATIONS = 'notifications', CUSTOM_ATTRIBUTES = 'customAttributes', DATA_QUALITY = 'dataQuality', EVENT_PUBLISHERS = 'eventPublishers', @@ -41,11 +41,12 @@ export enum GlobalSettingOptions { BOTS = 'bots', TABLES = 'tables', MSTEAMS = 'msteams', - ACTIVITY_FEED = 'activityFeed', + ACTIVITY_FEED = 'activityFeeds', ELASTIC_SEARCH = 'elasticSearch', ALERTS = 'alerts', + ALERT = 'alert', ADD_ALERTS = 'add-alerts', - EDIT_ALERTS = 'edit', + EDIT_ALERTS = 'edit-alert', } export const GLOBAL_SETTING_PERMISSION_RESOURCES = [ diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/en-us.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/en-us.json index a21bdefccc5..c8328c5bc1d 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/en-us.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/en-us.json @@ -600,7 +600,8 @@ "follower-plural": "Followers", "email-plural": "Emails", "no-tier": "No Tier", - "dbt-run-result-http-path": "dbt Run Results HTTP Path" + "dbt-run-result-http-path": "dbt Run Results HTTP Path", + "field-change": "Field Change" }, "message": { "service-email-required": "Service account Email is required", diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/AddAlertPage/AddAlertPage.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/AddAlertPage/AddAlertPage.tsx index b7db46273cb..aba24ea611c 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/AddAlertPage/AddAlertPage.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/AddAlertPage/AddAlertPage.tsx @@ -64,15 +64,13 @@ import { ProviderType, TriggerConfig, } from '../../generated/alerts/alerts'; -import { - AlertActionType, - CreateAlertAction, -} from '../../generated/alerts/api/createAlertAction'; +import { AlertActionType } from '../../generated/alerts/api/createAlertAction'; import { EntitySpelFilters } from '../../generated/alerts/entitySpelFilters'; import { Function } from '../../generated/type/function'; import { getAlertActionTypeDisplayName, getAlertsActionTypeIcon, + getDisplayNameForEntities, getDisplayNameForTriggerType, getFunctionDisplayName, listLengthValidator, @@ -80,7 +78,7 @@ import { } from '../../utils/Alerts/AlertsUtil'; import { getSettingPath } from '../../utils/RouterUtils'; import SVGIcons, { Icons } from '../../utils/SvgUtils'; -import { showErrorToast } from '../../utils/ToastUtils'; +import { showErrorToast, showSuccessToast } from '../../utils/ToastUtils'; import './add-alerts-page.styles.less'; const AddAlertPage = () => { @@ -177,7 +175,6 @@ const AddAlertPage = () => { const isEditMode = useMemo(() => !isEmpty(fqn), [fqn]); const updateCreateAlertActions = async (alertActions: AlertAction[]) => { - const api = isEditMode ? updateAlertAction : createAlertAction; if (isEditMode) { if (!form.isFieldTouched(['alertActions'])) { // If destination is not changed return given alertAction as it is @@ -192,18 +189,19 @@ const AddAlertPage = () => { // Else Create AlertActions and return new IDs const promises = - alertActions?.map((action) => - api( - pick(action, [ - 'alertActionConfig', - 'alertActionType', - 'name', - 'displayName', - 'timeout', - 'batchSize', - ]) as CreateAlertAction - ) - ) ?? []; + alertActions?.map((action) => { + const api = action.id ? updateAlertAction : createAlertAction; + const alertAction = pick(action, [ + 'alertActionConfig', + 'alertActionType', + 'name', + 'displayName', + 'timeout', + 'batchSize', + ]) as AlertAction; + + return api(alertAction); + }) ?? []; const responses = await Promise.allSettled(promises); @@ -237,18 +235,9 @@ const AddAlertPage = () => { )?.join(', ')})`, })); - const modifiedAlertActions = alertActions?.map( - (action) => - ({ - ...action, - name: action.name ?? action.displayName, - displayName: action.displayName, - } as unknown as AlertAction) - ); - try { const requestAlertActions = await updateCreateAlertActions( - modifiedAlertActions + alertActions as unknown as AlertAction[] ); try { @@ -258,14 +247,14 @@ const AddAlertPage = () => { alertActions: requestAlertActions, }); - showErrorToast( + showSuccessToast( t(`server.${isEditMode ? 'update' : 'create'}-entity-success`, { entity: t('label.alert-plural'), }) ); history.push( getSettingPath( - GlobalSettingsMenuCategory.COLLABORATION, + GlobalSettingsMenuCategory.NOTIFICATIONS, GlobalSettingOptions.ALERTS ) ); @@ -445,17 +434,7 @@ const AddAlertPage = () => { return ( <> - - - - @@ -621,7 +594,7 @@ const AddAlertPage = () => { options={ selectedTrigger.entities?.map((entity) => ({ value: entity, - label: startCase(entity), + label: getDisplayNameForEntities(entity), })) ?? [] } placeholder={t('label.select-data-assets')} @@ -685,7 +658,7 @@ const AddAlertPage = () => { )}