diff --git a/catalog-rest-service/src/main/java/org/openmetadata/catalog/events/MSTeamsWebhookPublisher.java b/catalog-rest-service/src/main/java/org/openmetadata/catalog/events/MSTeamsWebhookPublisher.java new file mode 100644 index 00000000000..17be15513e4 --- /dev/null +++ b/catalog-rest-service/src/main/java/org/openmetadata/catalog/events/MSTeamsWebhookPublisher.java @@ -0,0 +1,64 @@ +package org.openmetadata.catalog.events; + +import java.util.concurrent.TimeUnit; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.Invocation; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import lombok.extern.slf4j.Slf4j; +import org.openmetadata.catalog.events.errors.EventPublisherException; +import org.openmetadata.catalog.jdbi3.CollectionDAO; +import org.openmetadata.catalog.resources.events.EventResource; +import org.openmetadata.catalog.slack.SlackRetriableException; +import org.openmetadata.catalog.slack.TeamsMessage; +import org.openmetadata.catalog.type.ChangeEvent; +import org.openmetadata.catalog.type.Webhook; +import org.openmetadata.catalog.util.ChangeEventParser; + +@Slf4j +public class MSTeamsWebhookPublisher extends WebhookPublisher { + private final Invocation.Builder target; + private final Client client; + + public MSTeamsWebhookPublisher(Webhook webhook, CollectionDAO dao) { + super(webhook, dao); + String msTeamsWebhookURL = webhook.getEndpoint().toString(); + ClientBuilder clientBuilder = ClientBuilder.newBuilder(); + clientBuilder.connectTimeout(webhook.getTimeout(), TimeUnit.SECONDS); + clientBuilder.readTimeout(webhook.getReadTimeout(), TimeUnit.SECONDS); + client = clientBuilder.build(); + target = client.target(msTeamsWebhookURL).request(); + } + + @Override + public void onStart() { + LOG.info("Slack Webhook Publisher Started"); + } + + @Override + public void onShutdown() { + if (client != null) { + client.close(); + } + } + + @Override + public void publish(EventResource.ChangeEventList events) throws EventPublisherException { + for (ChangeEvent event : events.getData()) { + try { + TeamsMessage teamsMessage = ChangeEventParser.buildTeamsMessage(event); + Response response = + target.post(javax.ws.rs.client.Entity.entity(teamsMessage, MediaType.APPLICATION_JSON_TYPE)); + if (response.getStatus() >= 300 && response.getStatus() < 400) { + throw new EventPublisherException( + "Slack webhook callback is getting redirected. " + "Please check your configuration"); + } else if (response.getStatus() >= 300 && response.getStatus() < 600) { + throw new SlackRetriableException(response.getStatusInfo().getReasonPhrase()); + } + } catch (Exception e) { + LOG.error("Failed to publish event {} to slack due to {} ", event, e.getMessage()); + } + } + } +} diff --git a/catalog-rest-service/src/main/java/org/openmetadata/catalog/jdbi3/WebhookRepository.java b/catalog-rest-service/src/main/java/org/openmetadata/catalog/jdbi3/WebhookRepository.java index dc337cd9675..9ae4cd67e6e 100644 --- a/catalog-rest-service/src/main/java/org/openmetadata/catalog/jdbi3/WebhookRepository.java +++ b/catalog-rest-service/src/main/java/org/openmetadata/catalog/jdbi3/WebhookRepository.java @@ -28,9 +28,9 @@ import lombok.extern.slf4j.Slf4j; import org.openmetadata.catalog.Entity; import org.openmetadata.catalog.events.EventPubSub; import org.openmetadata.catalog.events.EventPubSub.ChangeEventHolder; +import org.openmetadata.catalog.events.MSTeamsWebhookPublisher; import org.openmetadata.catalog.events.WebhookPublisher; import org.openmetadata.catalog.filter.EventFilter; -import org.openmetadata.catalog.kafka.KafkaWebhookEventPublisher; import org.openmetadata.catalog.resources.events.WebhookResource; import org.openmetadata.catalog.slack.SlackWebhookEventPublisher; import org.openmetadata.catalog.type.Webhook; @@ -90,8 +90,8 @@ public class WebhookRepository extends EntityRepository { WebhookPublisher publisher; if (webhook.getWebhookType() == WebhookType.slack) { publisher = new SlackWebhookEventPublisher(webhook, daoCollection); - } else if (webhook.getWebhookType() == WebhookType.kafka) { - publisher = new KafkaWebhookEventPublisher(webhook, daoCollection); + } else if (webhook.getWebhookType() == WebhookType.msteams) { + publisher = new MSTeamsWebhookPublisher(webhook, daoCollection); } else { publisher = new WebhookPublisher(webhook, daoCollection); } diff --git a/catalog-rest-service/src/main/java/org/openmetadata/catalog/slack/SlackWebhookEventPublisher.java b/catalog-rest-service/src/main/java/org/openmetadata/catalog/slack/SlackWebhookEventPublisher.java index 08770600251..03933d0ef85 100644 --- a/catalog-rest-service/src/main/java/org/openmetadata/catalog/slack/SlackWebhookEventPublisher.java +++ b/catalog-rest-service/src/main/java/org/openmetadata/catalog/slack/SlackWebhookEventPublisher.java @@ -24,8 +24,8 @@ public class SlackWebhookEventPublisher extends WebhookPublisher { super(webhook, dao); String slackWebhookURL = webhook.getEndpoint().toString(); ClientBuilder clientBuilder = ClientBuilder.newBuilder(); - clientBuilder.connectTimeout(10, TimeUnit.SECONDS); - clientBuilder.readTimeout(12, TimeUnit.SECONDS); + clientBuilder.connectTimeout(webhook.getTimeout(), TimeUnit.SECONDS); + clientBuilder.readTimeout(webhook.getReadTimeout(), TimeUnit.SECONDS); client = clientBuilder.build(); target = client.target(slackWebhookURL).request(); } diff --git a/catalog-rest-service/src/main/java/org/openmetadata/catalog/slack/TeamsMessage.java b/catalog-rest-service/src/main/java/org/openmetadata/catalog/slack/TeamsMessage.java new file mode 100644 index 00000000000..9c712453278 --- /dev/null +++ b/catalog-rest-service/src/main/java/org/openmetadata/catalog/slack/TeamsMessage.java @@ -0,0 +1,34 @@ +package org.openmetadata.catalog.slack; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import lombok.Getter; +import lombok.Setter; + +@JsonIgnoreProperties(ignoreUnknown = true) +@Getter +@Setter +public class TeamsMessage { + @Getter + @Setter + public static class Section { + @JsonProperty("activityTitle") + public String activityTitle; + + @JsonProperty("activityText") + public String activityText; + } + + @JsonProperty("@type") + public String type = "MessageCard"; + + @JsonProperty("@context") + public String context = "http://schema.org/extensions"; + + @JsonProperty("summary") + public String summary; + + @JsonProperty("sections") + public List
sections; +} diff --git a/catalog-rest-service/src/main/java/org/openmetadata/catalog/util/ChangeEventParser.java b/catalog-rest-service/src/main/java/org/openmetadata/catalog/util/ChangeEventParser.java index e361f85295b..fbc471f120a 100644 --- a/catalog-rest-service/src/main/java/org/openmetadata/catalog/util/ChangeEventParser.java +++ b/catalog-rest-service/src/main/java/org/openmetadata/catalog/util/ChangeEventParser.java @@ -41,6 +41,7 @@ import org.openmetadata.catalog.EntityInterface; import org.openmetadata.catalog.resources.feeds.MessageParser.EntityLink; import org.openmetadata.catalog.slack.SlackAttachment; import org.openmetadata.catalog.slack.SlackMessage; +import org.openmetadata.catalog.slack.TeamsMessage; import org.openmetadata.catalog.type.ChangeDescription; import org.openmetadata.catalog.type.ChangeEvent; import org.openmetadata.catalog.type.EntityReference; @@ -67,17 +68,104 @@ public final class ChangeEventParser { public enum PUBLISH_TO { FEED, - SLACK + SLACK, + TEAMS } - public static String getEntityUrl(ChangeEvent event) { + public static String getBold(PUBLISH_TO publishTo) { + switch (publishTo) { + case FEED: + case TEAMS: + // TEAMS and FEED bold formatting is same + return FEED_BOLD; + case SLACK: + return SLACK_BOLD; + default: + return "INVALID"; + } + } + + public static String getLineBreak(PUBLISH_TO publishTo) { + switch (publishTo) { + case FEED: + case TEAMS: + // TEAMS and FEED bold formatting is same + return FEED_LINE_BREAK; + case SLACK: + return SLACK_LINE_BREAK; + default: + return "INVALID"; + } + } + + public static String getAddMarker(PUBLISH_TO publishTo) { + switch (publishTo) { + case FEED: + return FEED_SPAN_ADD; + case TEAMS: + // TEAMS and FEED bold formatting is same + return "**"; + case SLACK: + return "*"; + default: + return "INVALID"; + } + } + + public static String getAddMarkerClose(PUBLISH_TO publishTo) { + switch (publishTo) { + case FEED: + return FEED_SPAN_CLOSE; + case TEAMS: + // TEAMS and FEED bold formatting is same + return "** "; + case SLACK: + return "* "; + default: + return "INVALID"; + } + } + + public static String getRemoveMarker(PUBLISH_TO publishTo) { + switch (publishTo) { + case FEED: + return FEED_SPAN_REMOVE; + case TEAMS: + // TEAMS and FEED bold formatting is same + return "~~"; + case SLACK: + return "~"; + default: + return "INVALID"; + } + } + + public static String getRemoveMarkerClose(PUBLISH_TO publishTo) { + switch (publishTo) { + case FEED: + return FEED_SPAN_CLOSE; + case TEAMS: + // TEAMS and FEED bold formatting is same + return "~~ "; + case SLACK: + return "~ "; + default: + return "INVALID"; + } + } + + public static String getEntityUrl(PUBLISH_TO publishTo, ChangeEvent event) { EntityInterface entity = (EntityInterface) event.getEntity(); URI urlInstance = entity.getHref(); String fqn = event.getEntityFullyQualifiedName(); if (Objects.nonNull(urlInstance)) { String scheme = urlInstance.getScheme(); String host = urlInstance.getHost(); - return String.format("<%s://%s/%s/%s|%s>", scheme, host, event.getEntityType(), fqn, fqn); + if (publishTo == PUBLISH_TO.SLACK) { + return String.format("<%s://%s/%s/%s|%s>", scheme, host, event.getEntityType(), fqn, fqn); + } else if (publishTo == PUBLISH_TO.TEAMS) { + return String.format("[%s](%s://%s/%s/%s)", fqn, scheme, host, event.getEntityType(), fqn); + } } return urlInstance.toString(); } @@ -87,7 +175,7 @@ public final class ChangeEventParser { slackMessage.setUsername(event.getUserName()); if (event.getEntity() != null) { String headerTxt = "%s posted on " + event.getEntityType() + " %s"; - String headerText = String.format(headerTxt, event.getUserName(), getEntityUrl(event)); + String headerText = String.format(headerTxt, event.getUserName(), getEntityUrl(PUBLISH_TO.SLACK, event)); slackMessage.setText(headerText); } Map messages = @@ -105,6 +193,28 @@ public final class ChangeEventParser { return slackMessage; } + public static TeamsMessage buildTeamsMessage(ChangeEvent event) { + TeamsMessage teamsMessage = new TeamsMessage(); + teamsMessage.setSummary("Change Event From OMD"); + TeamsMessage.Section teamsSections = new TeamsMessage.Section(); + if (event.getEntity() != null) { + String headerTxt = "%s posted on " + event.getEntityType() + " %s"; + String headerText = String.format(headerTxt, event.getUserName(), getEntityUrl(PUBLISH_TO.TEAMS, event)); + teamsSections.setActivityTitle(headerText); + } + Map messages = + getFormattedMessages(PUBLISH_TO.TEAMS, event.getChangeDescription(), (EntityInterface) event.getEntity()); + List attachmentList = new ArrayList<>(); + for (var entry : messages.entrySet()) { + TeamsMessage.Section section = new TeamsMessage.Section(); + section.setActivityTitle(teamsSections.getActivityTitle()); + section.setActivityText(entry.getValue()); + attachmentList.add(section); + } + teamsMessage.setSections(attachmentList); + return teamsMessage; + } + public static Map getFormattedMessages( PUBLISH_TO publishTo, ChangeDescription changeDescription, EntityInterface entity) { // Store a map of entityLink -> message @@ -278,16 +388,9 @@ public final class ChangeEventParser { String fieldValue = getFieldValue(newFieldValue); if (Entity.FIELD_FOLLOWERS.equals(updatedField)) { message = - String.format( - ("Followed " + (publishTo == PUBLISH_TO.FEED ? FEED_BOLD : SLACK_BOLD) + " `%s`"), - link.getEntityType(), - link.getEntityFQN()); + String.format(("Followed " + getBold(publishTo) + " `%s`"), link.getEntityType(), link.getEntityFQN()); } else if (fieldValue != null && !fieldValue.isEmpty()) { - message = - String.format( - ("Added " + (publishTo == PUBLISH_TO.FEED ? FEED_BOLD : SLACK_BOLD) + ": `%s`"), - updatedField, - fieldValue); + message = String.format(("Added " + getBold(publishTo) + ": `%s`"), updatedField, fieldValue); } break; case UPDATE: @@ -297,7 +400,7 @@ public final class ChangeEventParser { if (Entity.FIELD_FOLLOWERS.equals(updatedField)) { message = String.format("Unfollowed %s `%s`", link.getEntityType(), link.getEntityFQN()); } else { - message = String.format(("Deleted " + (publishTo == PUBLISH_TO.FEED ? FEED_BOLD : SLACK_BOLD)), updatedField); + message = String.format(("Deleted " + getBold(publishTo)), updatedField); } break; default: @@ -313,7 +416,7 @@ public final class ChangeEventParser { if (nullOrEmpty(diff)) { return StringUtils.EMPTY; } else { - String field = String.format("Updated %s: %s", (publishTo == PUBLISH_TO.FEED ? FEED_BOLD : SLACK_BOLD), diff); + String field = String.format("Updated %s: %s", getBold(publishTo), diff); return String.format(field, updatedField); } } @@ -330,17 +433,12 @@ public final class ChangeEventParser { "%s: %s", key, getPlaintextDiff(publishTo, oldJson.get(key).toString(), newJson.get(key).toString()))); } } - String updates = String.join((publishTo == PUBLISH_TO.FEED ? FEED_LINE_BREAK : SLACK_LINE_BREAK), labels); + String updates = String.join(getLineBreak(publishTo), labels); // Include name of the field if the json contains "name" key if (newJson.containsKey("name")) { updatedField = String.format("%s.%s", updatedField, newJson.getString("name")); } - String format = - String.format( - "Updated %s:%s%s", - publishTo == PUBLISH_TO.FEED ? FEED_BOLD : SLACK_BOLD, - publishTo == PUBLISH_TO.FEED ? FEED_LINE_BREAK : SLACK_LINE_BREAK, - updates); + String format = String.format("Updated %s:%s%s", getBold(publishTo), getLineBreak(publishTo), updates); return String.format(format, updatedField); } @@ -351,9 +449,7 @@ public final class ChangeEventParser { } if (oldValue == null || oldValue.toString().isEmpty()) { - String format = - String.format( - "Updated %s to %s", publishTo == PUBLISH_TO.FEED ? FEED_BOLD : SLACK_BOLD, getFieldValue(newValue)); + String format = String.format("Updated %s to %s", getBold(publishTo), getFieldValue(newValue)); return String.format(format, updatedField); } else if (updatedField.contains("tags") || updatedField.contains(FIELD_OWNER)) { return getPlainTextUpdateMessage(publishTo, updatedField, getFieldValue(oldValue), getFieldValue(newValue)); @@ -426,21 +522,10 @@ public final class ChangeEventParser { // Replace them with html tags to render nicely in the UI // Example: This is a test sentenceline // This is a test sentenceline - String spanAdd; - String spanAddClose; - String spanRemove; - String spanRemoveClose; - if (publishTo == PUBLISH_TO.FEED) { - spanAdd = FEED_SPAN_ADD; - spanAddClose = FEED_SPAN_CLOSE; - spanRemove = FEED_SPAN_REMOVE; - spanRemoveClose = FEED_SPAN_CLOSE; - } else { - spanAdd = "*"; - spanAddClose = "* "; - spanRemove = "~"; - spanRemoveClose = "~ "; - } + String spanAdd = getAddMarker(publishTo); + String spanAddClose = getAddMarkerClose(publishTo); + String spanRemove = getRemoveMarker(publishTo); + String spanRemoveClose = getRemoveMarkerClose(publishTo); if (diff != null) { diff = replaceMarkers(diff, addMarker, spanAdd, spanAddClose); diff = replaceMarkers(diff, removeMarker, spanRemove, spanRemoveClose); diff --git a/catalog-rest-service/src/main/resources/json/schema/entity/events/webhook.json b/catalog-rest-service/src/main/resources/json/schema/entity/events/webhook.json index 07f633de851..387069dbc3d 100644 --- a/catalog-rest-service/src/main/resources/json/schema/entity/events/webhook.json +++ b/catalog-rest-service/src/main/resources/json/schema/entity/events/webhook.json @@ -12,7 +12,7 @@ "type": "string", "javaType": "org.openmetadata.catalog.type.WebhookType", "default": "generic", - "enum": ["slack", "generic", "kafka"], + "enum": ["slack", "generic", "msteams"], "javaEnums": [ { "name": "slack" @@ -21,7 +21,7 @@ "name": "generic" }, { - "name": "kafka" + "name": "msteams" } ] } @@ -77,6 +77,11 @@ "type": "integer", "default": 10 }, + "readTimeout": { + "description": "Read timeout in seconds. (Default 12s).", + "type": "integer", + "default": 12 + }, "enabled": { "description": "When set to `true`, the webhook event notification is enabled. Set it to `false` to disable the subscription. (Default `true`).", "type": "boolean", diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/ms-teams-grey.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/ms-teams-grey.svg new file mode 100644 index 00000000000..a2d975bae3e --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/ms-teams-grey.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/ms-teams.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/ms-teams.svg new file mode 100644 index 00000000000..e1c41e4a2a8 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/ms-teams.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/components/AddWebhook/AddWebhook.tsx b/openmetadata-ui/src/main/resources/ui/src/components/AddWebhook/AddWebhook.tsx index e44fc20b2ad..d3ba1f4a6e0 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/AddWebhook/AddWebhook.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/AddWebhook/AddWebhook.tsx @@ -32,6 +32,7 @@ import { GlobalSettingsMenuCategory, } from '../../constants/globalSettings.constants'; import { + CONFIGURE_MS_TEAMS_TEXT, CONFIGURE_SLACK_TEXT, CONFIGURE_WEBHOOK_TEXT, NO_PERMISSION_FOR_ACTION, @@ -57,6 +58,7 @@ import { getSettingPath } from '../../utils/RouterUtils'; import SVGIcons, { Icons } from '../../utils/SvgUtils'; import { Button } from '../buttons/Button/Button'; import CopyToClipboardButton from '../buttons/CopyToClipboardButton/CopyToClipboardButton'; +import CardV1 from '../common/Card/CardV1'; import RichTextEditor from '../common/rich-text-editor/RichTextEditor'; import TitleBreadcrumb from '../common/title-breadcrumb/title-breadcrumb.component'; import PageLayout from '../containers/PageLayout'; @@ -71,6 +73,12 @@ import { EVENT_FILTER_FORM_INITIAL_VALUE, } from './WebhookConstants'; +const CONFIGURE_TEXT: { [key: string]: string } = { + msteams: CONFIGURE_MS_TEAMS_TEXT, + slack: CONFIGURE_SLACK_TEXT, + generic: CONFIGURE_WEBHOOK_TEXT, +}; + const Field = ({ children }: { children: React.ReactNode }) => { return
{children}
; }; @@ -374,12 +382,11 @@ const AddWebhook: FunctionComponent = ({ const fetchRightPanel = useCallback(() => { return (
-
Configure Webhooks
-
- {webhookType === WebhookType.Slack - ? CONFIGURE_SLACK_TEXT - : CONFIGURE_WEBHOOK_TEXT} -
+
); }, [webhookType]); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Webhooks/WebhooksV1.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Webhooks/WebhooksV1.tsx index 047263ec853..6ea670a56f4 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Webhooks/WebhooksV1.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Webhooks/WebhooksV1.tsx @@ -11,12 +11,13 @@ * limitations under the License. */ -import { Card, Col, Row, Select, Space, Tooltip } from 'antd'; +import { Col, Row, Select, Space, Tooltip } from 'antd'; import classNames from 'classnames'; import { isEmpty, isNil } from 'lodash'; import React, { FC, useEffect, useMemo, useState } from 'react'; import { PAGE_SIZE } from '../../constants/constants'; import { + MS_TEAMS_LISTING_TEXT, NO_PERMISSION_FOR_ACTION, SLACK_LISTING_TEXT, WEBHOOK_LISTING_TEXT, @@ -27,6 +28,7 @@ import { Operation } from '../../generated/entity/policies/policy'; import { checkPermission } from '../../utils/PermissionsUtils'; import { statuses } from '../AddWebhook/WebhookConstants'; import { Button } from '../buttons/Button/Button'; +import CardV1 from '../common/Card/CardV1'; import ErrorPlaceHolder from '../common/error-with-placeholder/ErrorPlaceHolder'; import NextPrevious from '../common/next-previous/NextPrevious'; import WebhookDataCard from '../common/webhook-data-card/WebhookDataCard'; @@ -36,9 +38,21 @@ import { ResourceEntity } from '../PermissionProvider/PermissionProvider.interfa import { WebhooksV1Props } from './WebhooksV1.interface'; import './webhookV1.less'; +const LISTING_TEXT: { [key: string]: string } = { + msteams: MS_TEAMS_LISTING_TEXT, + slack: SLACK_LISTING_TEXT, + generic: WEBHOOK_LISTING_TEXT, +}; + +const WEBHOOKS_INTEGRATION: { [key: string]: string } = { + msteams: 'MS Teams', + slack: 'Slack', + generic: 'Webhook', +}; + const WebhooksV1: FC = ({ data = [], - webhookType, + webhookType = WebhookType.Generic, paging, selectedStatus = [], onAddWebhook, @@ -68,16 +82,9 @@ const WebhooksV1: FC = ({ const rightPanel = useMemo(() => { return ( - -
- {webhookType === WebhookType.Slack - ? SLACK_LISTING_TEXT - : WEBHOOK_LISTING_TEXT} -
-
+
+ +
); }, []); @@ -100,7 +107,7 @@ const WebhooksV1: FC = ({ theme="primary" variant="contained" onClick={onAddWebhook}> - Add {webhookType === WebhookType.Slack ? 'Slack' : 'Webhook'} + Add {WEBHOOKS_INTEGRATION[webhookType]}

@@ -115,7 +122,9 @@ const WebhooksV1: FC = ({ }, [data, selectedStatus]); if (data.length === 0) { - return fetchErrorPlaceHolder('No webhooks found'); + return fetchErrorPlaceHolder( + `No ${WEBHOOKS_INTEGRATION[webhookType]} found` + ); } return ( @@ -155,8 +164,7 @@ const WebhooksV1: FC = ({ theme="primary" variant="contained" onClick={onAddWebhook}> - Add{' '} - {webhookType === WebhookType.Slack ? 'Slack' : 'Webhook'} + Add {WEBHOOKS_INTEGRATION[webhookType]} )} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/Card/CardV1.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/Card/CardV1.tsx new file mode 100644 index 00000000000..4cde25eda1a --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/Card/CardV1.tsx @@ -0,0 +1,33 @@ +/* + * 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 { Card } from 'antd'; +import { lowerCase } from 'lodash'; +import React from 'react'; + +interface CardProps { + description: string; + id: string; + heading?: string; +} + +const CardV1 = ({ description, id, heading }: CardProps) => { + return ( + + {heading ?
{heading}
: ''} +
{description}
+
+ ); +}; + +export default CardV1; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/webhook-data-card/WebhookDataCard.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/webhook-data-card/WebhookDataCard.tsx index 628f99e4d66..d2de68fb036 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/webhook-data-card/WebhookDataCard.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/webhook-data-card/WebhookDataCard.tsx @@ -26,11 +26,17 @@ type Props = { onClick?: (name: string) => void; }; +const ICON: { [key: string]: string } = { + generic: Icons.WEBHOOK, + msteams: Icons.MSTEAMS_GREY, + slack: Icons.SLACK_GREY, +}; + const WebhookDataCard: FunctionComponent = ({ name, description, endpoint, - type, + type = WebhookType.Generic, status = Status.Disabled, onClick, }: Props) => { @@ -44,11 +50,7 @@ const WebhookDataCard: FunctionComponent = ({ data-testid="webhook-data-card">
- +