diff --git a/src/components/Insights/EndpointNPlusOneInsight/mockData.ts b/src/components/Insights/EndpointNPlusOneInsight/mockData.ts index bf1c8d8b4..cdf4a4fb4 100644 --- a/src/components/Insights/EndpointNPlusOneInsight/mockData.ts +++ b/src/components/Insights/EndpointNPlusOneInsight/mockData.ts @@ -2,7 +2,8 @@ import { InsightType } from "../../../types"; import { EndpointSuspectedNPlusOneInsight, InsightCategory, - InsightScope + InsightScope, + InsightStatus } from "../types"; export const mockedEndpointNPlusOneInsight: EndpointSuspectedNPlusOneInsight = { @@ -87,5 +88,6 @@ export const mockedEndpointNPlusOneInsight: EndpointSuspectedNPlusOneInsight = { prefixedCodeObjectId: "method:org.springframework.samples.petclinic.sample.SampleInsightsController$_$genNPlusOneWithoutInternalSpan", customStartTime: null, - actualStartTime: "2023-06-16T10:30:33.027Z" + actualStartTime: "2023-06-16T10:30:33.027Z", + status: InsightStatus.Active }; diff --git a/src/components/Insights/common/InsightCard/InsightHeader/InisghtHeader.stories.tsx b/src/components/Insights/common/InsightCard/InsightHeader/InisghtHeader.stories.tsx index a20987bf2..b34b55cb6 100644 --- a/src/components/Insights/common/InsightCard/InsightHeader/InisghtHeader.stories.tsx +++ b/src/components/Insights/common/InsightCard/InsightHeader/InisghtHeader.stories.tsx @@ -20,7 +20,6 @@ export const Default: Story = { importance: 3, insightType: "HotSpot", isNew: true, - isAsync: true, - isActive: true + isAsync: true } }; diff --git a/src/components/Insights/common/InsightCard/InsightHeader/InsightStatusBadge/InsightStatusBadge.stories.tsx b/src/components/Insights/common/InsightCard/InsightHeader/InsightStatusBadge/InsightStatusBadge.stories.tsx new file mode 100644 index 000000000..f21f88170 --- /dev/null +++ b/src/components/Insights/common/InsightCard/InsightHeader/InsightStatusBadge/InsightStatusBadge.stories.tsx @@ -0,0 +1,39 @@ +import { Meta, StoryObj } from "@storybook/react"; +import { InsightStatusBadge } from "."; +import { InsightStatus } from "../../../../types"; + +// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction +const meta: Meta = { + title: "Insights/common/InsightCard/InsightHeader/InsightStatusBadge", + component: InsightStatusBadge, + 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 Active: Story = { + args: { + status: InsightStatus.Active + } +}; + +export const Evaluating: Story = { + args: { + status: InsightStatus.InEvaluation + } +}; +export const PossiblyFixed: Story = { + args: { + status: InsightStatus.PossiblyFixed + } +}; +export const Regression: Story = { + args: { + status: InsightStatus.Regression + } +}; diff --git a/src/components/Insights/common/InsightCard/InsightHeader/InsightStatusBadge/getInsightStatusInfo.ts b/src/components/Insights/common/InsightCard/InsightHeader/InsightStatusBadge/getInsightStatusInfo.ts new file mode 100644 index 000000000..ad305c3ea --- /dev/null +++ b/src/components/Insights/common/InsightCard/InsightHeader/InsightStatusBadge/getInsightStatusInfo.ts @@ -0,0 +1,35 @@ +import { DefaultTheme } from "styled-components/dist/types"; +import { InsightStatus } from "../../../../types"; + +interface InsightStatusInfo { + label: string; + color: string; +} + +export const getInsightStatusInfo = ( + status: InsightStatus, + theme: DefaultTheme +): InsightStatusInfo | undefined => { + switch (status) { + case InsightStatus.Active: + return { + label: "Active", + color: theme.colors.v3.status.success + }; + case InsightStatus.InEvaluation: + return { + label: "Evaluating", + color: theme.colors.v3.status.medium + }; + case InsightStatus.PossiblyFixed: + return { + label: "Possibly Fixed", + color: theme.colors.v3.status.low + }; + case InsightStatus.Regression: + return { + label: "Regression", + color: theme.colors.v3.status.backgroundLow + }; + } +}; diff --git a/src/components/Insights/common/InsightCard/InsightHeader/InsightStatusBadge/index.tsx b/src/components/Insights/common/InsightCard/InsightHeader/InsightStatusBadge/index.tsx new file mode 100644 index 000000000..45db05afc --- /dev/null +++ b/src/components/Insights/common/InsightCard/InsightHeader/InsightStatusBadge/index.tsx @@ -0,0 +1,21 @@ +import { useTheme } from "styled-components"; +import { getInsightStatusInfo } from "./getInsightStatusInfo"; +import * as s from "./styles"; +import { InsightStatusBadgeProps } from "./types"; + +export const InsightStatusBadge = (props: InsightStatusBadgeProps) => { + const theme = useTheme(); + + const statusInfo = getInsightStatusInfo(props.status, theme); + + if (!statusInfo) { + return null; + } + + return ( + + + {statusInfo.label} + + ); +}; diff --git a/src/components/Insights/common/InsightCard/InsightHeader/InsightStatusBadge/styles.ts b/src/components/Insights/common/InsightCard/InsightHeader/InsightStatusBadge/styles.ts new file mode 100644 index 000000000..94652267f --- /dev/null +++ b/src/components/Insights/common/InsightCard/InsightHeader/InsightStatusBadge/styles.ts @@ -0,0 +1,29 @@ +import styled, { css } from "styled-components"; +import { footnoteRegularTypography } from "../../../../../common/App/typographies"; +import { getInsightStatusInfo } from "./getInsightStatusInfo"; +import { IndicatorProps } from "./types"; + +export const Container = styled.div` + ${footnoteRegularTypography} + + display: flex; + align-items: center; + gap: 4px; + color: ${({ theme }) => theme.colors.v3.text.secondary}; + padding: 4px 0; +`; + +export const Indicator = styled.div` + border-radius: 50%; + width: 6px; + height: 6px; + ${({ theme, $status }) => { + const statusInfo = getInsightStatusInfo($status, theme); + + return statusInfo + ? css` + background: ${statusInfo.color}; + ` + : ""; + }} +`; diff --git a/src/components/Insights/common/InsightCard/InsightHeader/InsightStatusBadge/types.ts b/src/components/Insights/common/InsightCard/InsightHeader/InsightStatusBadge/types.ts new file mode 100644 index 000000000..1bf542b98 --- /dev/null +++ b/src/components/Insights/common/InsightCard/InsightHeader/InsightStatusBadge/types.ts @@ -0,0 +1,9 @@ +import { InsightStatus } from "../../../../types"; + +export interface InsightStatusBadgeProps { + status: InsightStatus; +} + +export interface IndicatorProps { + $status: InsightStatus; +} diff --git a/src/components/Insights/common/InsightCard/InsightHeader/index.tsx b/src/components/Insights/common/InsightCard/InsightHeader/index.tsx index b72dd0ce3..fd45b7ab8 100644 --- a/src/components/Insights/common/InsightCard/InsightHeader/index.tsx +++ b/src/components/Insights/common/InsightCard/InsightHeader/index.tsx @@ -13,9 +13,12 @@ import { Tag } from "../../../../common/v3/Tag"; import { TagType } from "../../../../common/v3/Tag/types"; import { Tooltip } from "../../../../common/v3/Tooltip"; import { AsyncTag } from "./AsyncTag"; +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"; @@ -76,7 +79,7 @@ export const InsightHeader = (props: InsightHeaderProps) => { )} - {props.criticality > 0.8 && ( + {props.criticality > HIGH_CRITICALITY_THRESHOLD && ( @@ -85,12 +88,7 @@ export const InsightHeader = (props: InsightHeaderProps) => { )} {props.isAsync && } {props.isNew && } - {props.isActive && ( - - - Active - - )} + {props.status && } {!config.scope?.span && props.spanInfo && ( diff --git a/src/components/Insights/common/InsightCard/InsightHeader/styles.ts b/src/components/Insights/common/InsightCard/InsightHeader/styles.ts index 4d9672e21..c5e186a24 100644 --- a/src/components/Insights/common/InsightCard/InsightHeader/styles.ts +++ b/src/components/Insights/common/InsightCard/InsightHeader/styles.ts @@ -1,8 +1,5 @@ import styled from "styled-components"; -import { - bodyMediumTypography, - footnoteRegularTypography -} from "../../../../common/App/typographies"; +import { bodyMediumTypography } from "../../../../common/App/typographies"; export const Container = styled.div` display: flex; @@ -49,20 +46,3 @@ export const WarningTriangleContainer = styled.div` display: flex; color: ${({ theme }) => theme.colors.v3.status.high}; `; - -export const Active = styled.div` - ${footnoteRegularTypography} - - display: flex; - align-items: center; - gap: 4px; - color: ${({ theme }) => theme.colors.v3.text.secondary}; - padding: 4px; -`; - -export const Indicator = styled.div` - border-radius: 50%; - width: 6px; - height: 6px; - background: ${({ theme }) => theme.colors.v3.status.success}; -`; diff --git a/src/components/Insights/common/InsightCard/InsightHeader/types.ts b/src/components/Insights/common/InsightCard/InsightHeader/types.ts index 6afed02bb..537e2d317 100644 --- a/src/components/Insights/common/InsightCard/InsightHeader/types.ts +++ b/src/components/Insights/common/InsightCard/InsightHeader/types.ts @@ -1,8 +1,8 @@ import { SpanInfo } from "../../../../../types"; +import { InsightStatus } from "../../../types"; export interface InsightHeaderProps { insightType: string; - isActive?: boolean; tags?: []; importance: number; isAsync?: boolean; @@ -10,4 +10,5 @@ export interface InsightHeaderProps { criticality: number; spanInfo?: SpanInfo | null; onSpanLinkClick: (spanCodeObjectId: string) => void; + status?: InsightStatus; } diff --git a/src/components/Insights/common/InsightCard/index.tsx b/src/components/Insights/common/InsightCard/index.tsx index ba112773d..369ab7c54 100644 --- a/src/components/Insights/common/InsightCard/index.tsx +++ b/src/components/Insights/common/InsightCard/index.tsx @@ -115,11 +115,11 @@ export const InsightCard = (props: InsightCardProps) => { props.insight.isRecalculateEnabled && buttonsToRender.push({ - tooltip: "Recalculate", + tooltip: "Recheck", button: (btnProps) => (