From e6fc32b006ad2abfbe2226dad1f3109af1d4d0bf Mon Sep 17 00:00:00 2001 From: Kyrylo Shmidt Date: Thu, 7 Mar 2024 10:40:22 +0100 Subject: [PATCH 1/4] Add "Could affect production" notification bar --- .../InsightCard/InsightHeader/index.tsx | 10 ---- .../InsightCard/InsightHeader/styles.ts | 5 -- .../ProductionAffectionBar.stories.tsx | 26 +++++++++ .../ProductionAffectionBar/index.tsx | 24 +++++++++ .../ProductionAffectionBar/styles.ts | 34 ++++++++++++ .../ProductionAffectionBar/types.ts | 8 +++ .../Insights/common/InsightCard/index.tsx | 41 ++++++++++++-- .../Insights/common/InsightCard/types.ts | 5 +- .../EndpointBottleneckInsight/index.tsx | 7 +-- .../EndpointNPlusOneInsight/index.tsx | 7 +-- .../index.tsx | 7 +-- .../HighNumberOfQueriesInsight/index.tsx | 10 ++-- .../insights/ScalingIssueInsight/index.tsx | 11 ++-- .../SpanEndpointBottleneckInsight/index.tsx | 10 ++-- .../insights/SpanNPlusOneInsight/index.tsx | 10 ++-- .../SpanQueryOptimizationInsight/index.tsx | 11 ++-- src/components/Insights/index.tsx | 5 +- src/components/Insights/tracking.ts | 9 ++-- src/components/common/App/themes/darkTheme.ts | 3 +- .../common/App/themes/lightTheme.ts | 3 +- src/components/common/App/v3colors.ts | 4 +- .../common/icons/16px/SparkleIcon.tsx | 33 ++++++++++++ src/components/common/v3/JiraButton/index.tsx | 54 ++++++++++++------- src/components/common/v3/JiraButton/types.ts | 7 ++- src/styled.d.ts | 1 + 25 files changed, 241 insertions(+), 104 deletions(-) create mode 100644 src/components/Insights/common/InsightCard/ProductionAffectionBar/ProductionAffectionBar.stories.tsx create mode 100644 src/components/Insights/common/InsightCard/ProductionAffectionBar/index.tsx create mode 100644 src/components/Insights/common/InsightCard/ProductionAffectionBar/styles.ts create mode 100644 src/components/Insights/common/InsightCard/ProductionAffectionBar/types.ts create mode 100644 src/components/common/icons/16px/SparkleIcon.tsx diff --git a/src/components/Insights/common/InsightCard/InsightHeader/index.tsx b/src/components/Insights/common/InsightCard/InsightHeader/index.tsx index fd45b7ab8..928089a10 100644 --- a/src/components/Insights/common/InsightCard/InsightHeader/index.tsx +++ b/src/components/Insights/common/InsightCard/InsightHeader/index.tsx @@ -6,7 +6,6 @@ import { import { roundTo } from "../../../../../utils/roundTo"; import { ConfigContext } from "../../../../common/App/ConfigContext"; import { InfoCircleIcon } from "../../../../common/icons/InfoCircleIcon"; -import { WarningTriangleIcon } from "../../../../common/icons/WarningTriangleIcon"; import { Link } from "../../../../common/v3/Link"; import { NewTag } from "../../../../common/v3/NewTag"; import { Tag } from "../../../../common/v3/Tag"; @@ -17,8 +16,6 @@ import { InsightStatusBadge } from "./InsightStatusBadge"; import * as s from "./styles"; import { InsightHeaderProps } from "./types"; -const HIGH_CRITICALITY_THRESHOLD = 0.8; - const getTagType = (criticality: number): TagType => { if (criticality < 0.2) { return "lowSeverity"; @@ -79,13 +76,6 @@ export const InsightHeader = (props: InsightHeaderProps) => { )} - {props.criticality > HIGH_CRITICALITY_THRESHOLD && ( - - - - - - )} {props.isAsync && } {props.isNew && } {props.status && } diff --git a/src/components/Insights/common/InsightCard/InsightHeader/styles.ts b/src/components/Insights/common/InsightCard/InsightHeader/styles.ts index c5e186a24..30a1bfc59 100644 --- a/src/components/Insights/common/InsightCard/InsightHeader/styles.ts +++ b/src/components/Insights/common/InsightCard/InsightHeader/styles.ts @@ -41,8 +41,3 @@ export const BadgeContainer = styled.div` gap: 8px; height: 24px; `; - -export const WarningTriangleContainer = styled.div` - display: flex; - color: ${({ theme }) => theme.colors.v3.status.high}; -`; diff --git a/src/components/Insights/common/InsightCard/ProductionAffectionBar/ProductionAffectionBar.stories.tsx b/src/components/Insights/common/InsightCard/ProductionAffectionBar/ProductionAffectionBar.stories.tsx new file mode 100644 index 000000000..acc33650c --- /dev/null +++ b/src/components/Insights/common/InsightCard/ProductionAffectionBar/ProductionAffectionBar.stories.tsx @@ -0,0 +1,26 @@ +import { Meta, StoryObj } from "@storybook/react"; +import { ProductionAffectionBar } from "."; + +// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction +const meta: Meta = { + title: "Insights/common/InsightCard/ProductionAffectionBar", + component: ProductionAffectionBar, + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/react/configure/story-layout + layout: "fullscreen" + } +}; + +export default meta; + +type Story = StoryObj; + +export const WithoutTicket: Story = { + args: {} +}; + +export const WithTicket: Story = { + args: { + isTicketCreated: true + } +}; diff --git a/src/components/Insights/common/InsightCard/ProductionAffectionBar/index.tsx b/src/components/Insights/common/InsightCard/ProductionAffectionBar/index.tsx new file mode 100644 index 000000000..07f89f3bf --- /dev/null +++ b/src/components/Insights/common/InsightCard/ProductionAffectionBar/index.tsx @@ -0,0 +1,24 @@ +import { SparkleIcon } from "../../../../common/icons/16px/SparkleIcon"; +import { Link } from "../../../../common/v3/Link"; +import * as s from "./styles"; +import { ProductionAffectionBarProps } from "./types"; + +export const ProductionAffectionBar = (props: ProductionAffectionBarProps) => { + const handleCreateTicketLinkClick = () => { + props.onCreateTicket(); + }; + + return ( + + + + + Could affect production + {props.isTicketCreated ? ( + Ticket Created + ) : ( + Create Ticket + )} + + ); +}; diff --git a/src/components/Insights/common/InsightCard/ProductionAffectionBar/styles.ts b/src/components/Insights/common/InsightCard/ProductionAffectionBar/styles.ts new file mode 100644 index 000000000..749f192fc --- /dev/null +++ b/src/components/Insights/common/InsightCard/ProductionAffectionBar/styles.ts @@ -0,0 +1,34 @@ +import styled from "styled-components"; +import { footnoteRegularTypography } from "../../../../common/App/typographies"; +import { ContainerProps } from "./types"; + +export const Container = styled.div` + ${footnoteRegularTypography} + + border-radius: 4px; + border: 1px solid ${({ theme }) => theme.colors.v3.status.high}; + background: ${({ theme, $isActive }) => + $isActive + ? theme.colors.v3.status.backgroundHigh + : theme.colors.v3.pieChart.darkRed}; + display: flex; + align-items: center; + padding: 6px 8px; + gap: 4px; +`; + +export const SparkleIconContainer = styled.div` + color: ${({ theme }) => theme.colors.v3.status.high}; +`; + +export const Title = styled.span` + color: ${({ theme }) => theme.colors.v3.text.primary}; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + margin-right: auto; +`; + +export const TicketStatus = styled.div` + color: ${({ theme }) => theme.colors.v3.text.secondary}; +`; diff --git a/src/components/Insights/common/InsightCard/ProductionAffectionBar/types.ts b/src/components/Insights/common/InsightCard/ProductionAffectionBar/types.ts new file mode 100644 index 000000000..818f68783 --- /dev/null +++ b/src/components/Insights/common/InsightCard/ProductionAffectionBar/types.ts @@ -0,0 +1,8 @@ +export interface ProductionAffectionBarProps { + isTicketCreated: boolean; + onCreateTicket: () => void; +} + +export interface ContainerProps { + $isActive: boolean; +} diff --git a/src/components/Insights/common/InsightCard/index.tsx b/src/components/Insights/common/InsightCard/index.tsx index 0c818d99b..f447d7f04 100644 --- a/src/components/Insights/common/InsightCard/index.tsx +++ b/src/components/Insights/common/InsightCard/index.tsx @@ -21,16 +21,21 @@ import { sendTrackingEvent } from "../../../../utils/sendTrackingEvent"; import { actions } from "../../actions"; import { trackingEvents } from "../../tracking"; import { DismissInsightPayload, UndismissInsightPayload } from "../../types"; +import { ProductionAffectionBar } from "./ProductionAffectionBar"; const IS_NEW_TIME_LIMIT = 1000 * 60 * 10; // in milliseconds +const HIGH_CRITICALITY_THRESHOLD = 0.8; export const InsightCard = (props: InsightCardProps) => { const [isRecalculatingStarted, setIsRecalculatingStarted] = useState(false); + + const isCritical = props.insight.criticality > HIGH_CRITICALITY_THRESHOLD; + const handleRefreshLinkClick = () => { props.onRefresh(props.insight.type); }; - const handleRecalculateClick = () => { + const handleRecheckButtonClick = () => { props.insight.prefixedCodeObjectId && props.onRecalculate && props.onRecalculate(props.insight.id); @@ -100,7 +105,7 @@ export const InsightCard = (props: InsightCardProps) => { }; const handleDismissClick = () => { - sendTrackingEvent(trackingEvents.DISMISS_BUTTON_CLICKED, { + sendTrackingEvent(trackingEvents.INSIGHT_DISMISS_BUTTON_CLICKED, { insightType: props.insight.type }); @@ -114,7 +119,7 @@ export const InsightCard = (props: InsightCardProps) => { }; const handleShowClick = () => { - sendTrackingEvent(trackingEvents.SHOW_BUTTON_CLICKED, { + sendTrackingEvent(trackingEvents.INSIGHT_SHOW_BUTTON_CLICKED, { insightType: props.insight.type }); @@ -127,6 +132,25 @@ export const InsightCard = (props: InsightCardProps) => { props.onRefresh(props.insight.type); }; + const openTicketInfo = ( + spanCodeObjectId: string | undefined, + event: string + ) => { + if (props.onJiraButtonClick) { + props.onJiraButtonClick(spanCodeObjectId, event); + } + }; + + const handleCreateTicketLinkClick = () => { + sendTrackingEvent(trackingEvents.INSIGHT_CREATE_TICKET_LINK_CLICKED, { + insightType: props.insight.type + }); + openTicketInfo( + props.jiraTicketInfo?.spanCodeObjectId, + "create ticket link clicked" + ); + }; + const renderActions = () => { const buttonsToRender: { tooltip: string; @@ -153,7 +177,7 @@ export const InsightCard = (props: InsightCardProps) => {