From 30b07fb0413d247ba64be0d6f3b3e6b0a05e7924 Mon Sep 17 00:00:00 2001 From: Kyrylo Shmidt Date: Thu, 29 Feb 2024 11:43:06 +0100 Subject: [PATCH 01/56] Fix insight types, connect new insight cards --- .../Insights/BottleneckInsight/mockData.ts | 5 + .../DurationBreakdownInsight.stories.tsx | 1 + .../DurationInsight.stories.tsx | 7 + .../DurationSlowdownSourceInsight.stories.tsx | 1 + .../EndpointNPlusOneInsight/mockData.ts | 1 + .../mockData.ts | 1 + .../ErrorsInsight/ErrorsInsight.stories.tsx | 1 + .../ExcessiveAPICallsInsight.stories.tsx | 1 + .../HighNumberOfQueriesInsight/mockData.ts | 7 +- .../InsightCard/InsightCard.stories.tsx | 11 +- .../InsightJiraTicket.stories.tsx | 1 + src/components/Insights/Insights.stories.tsx | 13 +- .../Insights/InsightsPage/index.tsx | 230 +++++++----------- src/components/Insights/InsightsPage/types.ts | 9 +- .../Insights/NPlusOneInsight/mockData.ts | 11 +- .../NoScalingIssueInsight.stories.tsx | 1 + .../PerformanceAtScaleInsight.stories.tsx | 1 + .../QueryOptimizationInsight/mockData.ts | 1 + .../RequestBreakdownInsight.stories.tsx | 1 + .../Insights/ScalingIssueInsight/mockData.ts | 5 +- .../SessionInViewInsight.stories.tsx | 1 + .../SlowEndpointInsight.stories.tsx | 1 + .../SpanBottleneckInsight/mockData.ts | 1 + .../Insights/SpanNexusInsight/mockData.ts | 1 + .../TopUsageInsight.stories.tsx | 1 + .../TrafficInsight/TrafficInsight.stories.tsx | 2 + .../DurationInsight.stories.tsx | 7 + .../ExcessiveAPICallsInsight.stories.tsx | 2 + .../HighNumberOfQueriesInsight/index.tsx | 4 - .../HighNumberOfQueriesInsight/mockData.ts | 7 +- .../SlowEndpointInsight.stories.tsx | 1 + .../insights/SpanNexusInsight/mockData.ts | 1 + .../TrafficInsight/TrafficInsight.stories.tsx | 1 + src/components/Insights/types.ts | 55 +++-- src/utils/getInsightTypeInfo.ts | 19 ++ src/utils/getInsightTypeOrderPriority.ts | 8 +- 36 files changed, 233 insertions(+), 188 deletions(-) diff --git a/src/components/Insights/BottleneckInsight/mockData.ts b/src/components/Insights/BottleneckInsight/mockData.ts index 6ec96c3ef..a3cf801f8 100644 --- a/src/components/Insights/BottleneckInsight/mockData.ts +++ b/src/components/Insights/BottleneckInsight/mockData.ts @@ -6,6 +6,7 @@ import { } from "../types"; export const mockedBottleneckInsight: SpanEndpointBottleneckInsight = { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-1cce7979ac6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", @@ -48,6 +49,10 @@ export const mockedBottleneckInsight: SpanEndpointBottleneckInsight = { unit: "sec", raw: 3887134558.2822084 }, + impact: 0.14877828054298645, + severity: 0.2877828054298645, + criticality: 0.5687782805429865, + requestPercentage: 35, p50: { fraction: 0, maxDuration: { diff --git a/src/components/Insights/DurationBreakdownInsight/DurationBreakdownInsight.stories.tsx b/src/components/Insights/DurationBreakdownInsight/DurationBreakdownInsight.stories.tsx index 063e23179..1c0bbc5a4 100644 --- a/src/components/Insights/DurationBreakdownInsight/DurationBreakdownInsight.stories.tsx +++ b/src/components/Insights/DurationBreakdownInsight/DurationBreakdownInsight.stories.tsx @@ -20,6 +20,7 @@ type Story = StoryObj; export const Default: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-7cce7979ac6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", diff --git a/src/components/Insights/DurationInsight/DurationInsight.stories.tsx b/src/components/Insights/DurationInsight/DurationInsight.stories.tsx index df40a87c5..1cf110bad 100644 --- a/src/components/Insights/DurationInsight/DurationInsight.stories.tsx +++ b/src/components/Insights/DurationInsight/DurationInsight.stories.tsx @@ -20,6 +20,7 @@ type Story = StoryObj; export const WithAverage: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", @@ -136,6 +137,7 @@ export const WithAverage: Story = { export const WithChange: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-7cce7979ad6d", firstDetected: null, lastDetected: null, @@ -242,6 +244,7 @@ export const WithChange: Story = { export const WithEvaluatingChange: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-7cce7979ad6d", firstDetected: null, lastDetected: null, @@ -348,6 +351,7 @@ export const WithEvaluatingChange: Story = { export const HistogramWithManyBars: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-7cce7979ad6d", firstDetected: null, lastDetected: null, @@ -4872,6 +4876,7 @@ export const HistogramWithManyBars: Story = { export const HistogramWithGaps: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-7cce7979ad6d", firstDetected: null, lastDetected: null, @@ -5126,6 +5131,7 @@ export const HistogramWithGaps: Story = { export const HistogramWithAFewBars: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-7cce7979ad6d", firstDetected: null, lastDetected: null, @@ -5280,6 +5286,7 @@ export const HistogramWithAFewBars: Story = { export const EmptyStateBug: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-7cce7979ad6d", name: "Performance Stats", type: InsightType.SpanDurations, diff --git a/src/components/Insights/DurationSlowdownSourceInsight/DurationSlowdownSourceInsight.stories.tsx b/src/components/Insights/DurationSlowdownSourceInsight/DurationSlowdownSourceInsight.stories.tsx index 4f602ec3f..b9307512c 100644 --- a/src/components/Insights/DurationSlowdownSourceInsight/DurationSlowdownSourceInsight.stories.tsx +++ b/src/components/Insights/DurationSlowdownSourceInsight/DurationSlowdownSourceInsight.stories.tsx @@ -20,6 +20,7 @@ type Story = StoryObj; export const WithEvaluatingChange: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-7cde7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", diff --git a/src/components/Insights/EndpointNPlusOneInsight/mockData.ts b/src/components/Insights/EndpointNPlusOneInsight/mockData.ts index 80c92f8de..bf1c8d8b4 100644 --- a/src/components/Insights/EndpointNPlusOneInsight/mockData.ts +++ b/src/components/Insights/EndpointNPlusOneInsight/mockData.ts @@ -6,6 +6,7 @@ import { } from "../types"; export const mockedEndpointNPlusOneInsight: EndpointSuspectedNPlusOneInsight = { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-7cce7919ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", diff --git a/src/components/Insights/EndpointQueryOptimizationInsight/mockData.ts b/src/components/Insights/EndpointQueryOptimizationInsight/mockData.ts index 689a4156f..68c6589cc 100644 --- a/src/components/Insights/EndpointQueryOptimizationInsight/mockData.ts +++ b/src/components/Insights/EndpointQueryOptimizationInsight/mockData.ts @@ -7,6 +7,7 @@ import { export const mockedEndpointQueryOptimizationInsight: EndpointQueryOptimizationInsight = { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-7cce7989ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", diff --git a/src/components/Insights/ErrorsInsight/ErrorsInsight.stories.tsx b/src/components/Insights/ErrorsInsight/ErrorsInsight.stories.tsx index c9f454065..f7f9ef336 100644 --- a/src/components/Insights/ErrorsInsight/ErrorsInsight.stories.tsx +++ b/src/components/Insights/ErrorsInsight/ErrorsInsight.stories.tsx @@ -20,6 +20,7 @@ type Story = StoryObj; export const Default: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-3cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", diff --git a/src/components/Insights/ExcessiveAPICallsInsight/ExcessiveAPICallsInsight.stories.tsx b/src/components/Insights/ExcessiveAPICallsInsight/ExcessiveAPICallsInsight.stories.tsx index ae26aaf24..0a9f566f7 100644 --- a/src/components/Insights/ExcessiveAPICallsInsight/ExcessiveAPICallsInsight.stories.tsx +++ b/src/components/Insights/ExcessiveAPICallsInsight/ExcessiveAPICallsInsight.stories.tsx @@ -20,6 +20,7 @@ type Story = StoryObj; export const Default: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9688-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", diff --git a/src/components/Insights/HighNumberOfQueriesInsight/mockData.ts b/src/components/Insights/HighNumberOfQueriesInsight/mockData.ts index ff1ac43da..669203bd3 100644 --- a/src/components/Insights/HighNumberOfQueriesInsight/mockData.ts +++ b/src/components/Insights/HighNumberOfQueriesInsight/mockData.ts @@ -7,6 +7,7 @@ import { export const mockedHighNumberOfQueriesInsight: EndpointHighNumberOfQueriesInsight = { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9623-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", @@ -24,12 +25,6 @@ export const mockedHighNumberOfQueriesInsight: EndpointHighNumberOfQueriesInsigh importance: 3, queriesCount: 250, typicalCount: 4, - medianDuration: { - value: 150, - unit: "ms", - raw: 150000000.0 - }, - requestFraction: 0.3, traceId: "00D37A4E7208E0F6E89AA7E2E37446A6", scope: InsightScope.EntrySpan, endpointSpan: "HTTP POST /owners/{ownerId}/pets/new", diff --git a/src/components/Insights/InsightCard/InsightCard.stories.tsx b/src/components/Insights/InsightCard/InsightCard.stories.tsx index 619869388..83e7f98ba 100644 --- a/src/components/Insights/InsightCard/InsightCard.stories.tsx +++ b/src/components/Insights/InsightCard/InsightCard.stories.tsx @@ -2,7 +2,11 @@ import { Meta, StoryObj } from "@storybook/react"; import { InsightCard } from "."; import { InsightType } from "../../../types"; import { Button } from "../../common/Button"; -import { InsightCategory, InsightScope } from "../types"; +import { + EndpointSuspectedNPlusOneInsight, + InsightCategory, + InsightScope +} from "../types"; // More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction const meta: Meta = { @@ -21,6 +25,7 @@ type Story = StoryObj; export const Default: Story = { args: { data: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9638-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", @@ -93,12 +98,12 @@ export const Default: Story = { ], environment: "SAMPLE_ENV", severity: 0, - isRecalculateEnabled: false, + isRecalculateEnabled: true, prefixedCodeObjectId: "method:org.springframework.samples.petclinic.sample.SampleInsightsController$_$genNPlusOneWithoutInternalSpan", customStartTime: null, actualStartTime: "2023-06-16T10:30:33.027Z" - }, + } as EndpointSuspectedNPlusOneInsight, stats: "Some stats", isAsync: true, content: ( diff --git a/src/components/Insights/InsightJiraTicket/InsightJiraTicket.stories.tsx b/src/components/Insights/InsightJiraTicket/InsightJiraTicket.stories.tsx index db7f6d3b0..f09be3595 100644 --- a/src/components/Insights/InsightJiraTicket/InsightJiraTicket.stories.tsx +++ b/src/components/Insights/InsightJiraTicket/InsightJiraTicket.stories.tsx @@ -18,6 +18,7 @@ export default meta; type Story = StoryObj; const insight = { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4d5d-9628-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", diff --git a/src/components/Insights/Insights.stories.tsx b/src/components/Insights/Insights.stories.tsx index 7b18fec0d..2da03a953 100644 --- a/src/components/Insights/Insights.stories.tsx +++ b/src/components/Insights/Insights.stories.tsx @@ -11,6 +11,7 @@ import { InsightCategory, InsightScope, InsightsStatus, + SpanNPlusOneInsight, ViewMode } from "./types"; @@ -53,6 +54,7 @@ export const Default: Story = { // needsObservabilityFix: false, insights: [ { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8362-4c5d-9628-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", @@ -158,8 +160,9 @@ export const Default: Story = { "method:org.springframework.samples.petclinic.domain.OwnerValidation$_$ValidateOwner", customStartTime: null, actualStartTime: "2023-07-27T08:23:56.500827Z" - }, + } as SpanNPlusOneInsight, { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "62b55792-8262-4c5d-9628-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", @@ -232,6 +235,7 @@ export const Default: Story = { actualStartTime: "2023-06-26T00:00:00.000Z" }, { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-3262-4c5d-9628-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", @@ -287,6 +291,7 @@ export const Default: Story = { actualStartTime: "2023-06-26T13:53:53.645Z" }, { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-4262-4c5d-9628-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", @@ -328,6 +333,7 @@ export const Default: Story = { actualStartTime: "2023-06-26T13:53:57.956Z" }, { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8252-4c5d-9628-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", @@ -385,6 +391,7 @@ export const Default: Story = { actualStartTime: "2023-06-12T13:48:59.404Z" }, { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-5628-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", @@ -481,6 +488,7 @@ export const Default: Story = { actualStartTime: "2023-06-12T13:49:08.186Z" }, { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-6cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", @@ -557,6 +565,7 @@ export const Default: Story = { actualStartTime: "2023-06-12T13:49:03.486Z" }, { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-7cce8979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", @@ -653,6 +662,7 @@ export const Default: Story = { actualStartTime: "2023-06-13T00:00:00.000Z" }, { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-7cce9979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", @@ -806,6 +816,7 @@ export const NoObservability: Story = { }; const errorsInsight: CodeObjectErrorsInsight = { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-7cce7979ad1d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", diff --git a/src/components/Insights/InsightsPage/index.tsx b/src/components/Insights/InsightsPage/index.tsx index df7c410c2..ca7dd2439 100644 --- a/src/components/Insights/InsightsPage/index.tsx +++ b/src/components/Insights/InsightsPage/index.tsx @@ -11,60 +11,48 @@ import { ConfigContext } from "../../common/App/ConfigContext"; import { Card } from "../../common/Card"; import { EmptyState } from "../../common/EmptyState"; import { CardsIcon } from "../../common/icons/CardsIcon"; -import { BottleneckInsight } from "../BottleneckInsight"; import { DurationBreakdownInsight } from "../DurationBreakdownInsight"; -import { DurationInsight } from "../DurationInsight"; -import { DurationSlowdownSourceInsight } from "../DurationSlowdownSourceInsight"; -import { EndpointNPlusOneInsight } from "../EndpointNPlusOneInsight"; import { EndpointQueryOptimizationInsight } from "../EndpointQueryOptimizationInsight"; -import { ErrorsInsight } from "../ErrorsInsight"; -import { ExcessiveAPICallsInsight } from "../ExcessiveAPICallsInsight"; -import { HighNumberOfQueriesInsight } from "../HighNumberOfQueriesInsight"; -import { InsightCard } from "../InsightCard"; import { NPlusOneInsight } from "../NPlusOneInsight"; -import { NoScalingIssueInsight } from "../NoScalingIssueInsight"; -import { PerformanceAtScaleInsight } from "../PerformanceAtScaleInsight"; import { QueryOptimizationInsight } from "../QueryOptimizationInsight"; import { RequestBreakdownInsight } from "../RequestBreakdownInsight"; import { ScalingIssueInsight } from "../ScalingIssueInsight"; import { SessionInViewInsight } from "../SessionInViewInsight"; -import { SlowEndpointInsight } from "../SlowEndpointInsight"; -import { SpanBottleneckInsight } from "../SpanBottleneckInsight"; -import { SpanNexusInsight } from "../SpanNexusInsight"; import { TopUsageInsight } from "../TopUsageInsight"; -import { TrafficInsight } from "../TrafficInsight"; import { actions } from "../actions"; +import { DurationInsight } from "../common/insights/DurationInsight"; +import { ExcessiveAPICallsInsight } from "../common/insights/ExcessiveAPICallsInsight"; +import { HighNumberOfQueriesInsight } from "../common/insights/HighNumberOfQueriesInsight"; +import { SlowEndpointInsight } from "../common/insights/SlowEndpointInsight"; +import { SpanNexusInsight } from "../common/insights/SpanNexusInsight"; +import { TrafficInsight } from "../common/insights/TrafficInsight"; import { Description } from "../styles"; import { trackingEvents } from "../tracking"; import { isChattyApiEndpointInsight, - isCodeObjectErrorsInsight, - isCodeObjectHotSpotInsight, isEndpointBreakdownInsight, - isEndpointDurationSlowdownInsight, isEndpointHighNumberOfQueriesInsight, isEndpointHighUsageInsight, isEndpointLowUsageInsight, isEndpointNormalUsageInsight, isEndpointQueryOptimizationInsight, - isEndpointSlowestSpansInsight, - isEndpointSuspectedNPlusOneInsight, isSessionInViewEndpointInsight, isSlowEndpointInsight, isSpanDurationBreakdownInsight, isSpanDurationsInsight, - isSpanEndpointBottleneckInsight, isSpanNPlusOneInsight, isSpanNexusInsight, isSpanQueryOptimizationInsight, isSpanScalingBadlyInsight, - isSpanScalingInsufficientDataInsight, - isSpanScalingWellInsight, isSpanUsagesInsight } from "../typeGuards"; import { CodeObjectInsight, GenericCodeObjectInsight, Trace } from "../types"; import * as s from "./styles"; -import { InsightPageProps, isInsightJiraTicketHintShownPayload } from "./types"; +import { + InsightPageProps, + MarkInsightTypesAsViewedPayload, + isInsightJiraTicketHintShownPayload +} from "./types"; const getInsightToShowJiraHint = (insights: CodeObjectInsight[]): number => { const insightsWithJiraButton = [ @@ -93,23 +81,23 @@ const renderInsightCard = ( isJiraHintEnabled: boolean, onRefresh: () => void ): JSX.Element | undefined => { - const handleErrorSelect = (errorId: string, insightType: InsightType) => { - sendTrackingEvent(globalTrackingEvents.USER_ACTION, { - action: `Follow ${insightType} link` - }); - window.sendMessageToDigma({ - action: actions.GO_TO_ERROR, - payload: { - errorId - } - }); - }; + // const handleErrorSelect = (errorId: string, insightType: InsightType) => { + // sendTrackingEvent(globalTrackingEvents.USER_ACTION, { + // action: `Follow ${insightType} link` + // }); + // window.sendMessageToDigma({ + // action: actions.GO_TO_ERROR, + // payload: { + // errorId + // } + // }); + // }; - const handleErrorsExpandButtonClick = () => { - window.sendMessageToDigma({ - action: actions.GO_TO_ERRORS - }); - }; + // const handleErrorsExpandButtonClick = () => { + // window.sendMessageToDigma({ + // action: actions.GO_TO_ERRORS + // }); + // }; const handleHistogramButtonClick = ( instrumentationLibrary: string, @@ -206,6 +194,7 @@ const renderInsightCard = ( /> ); } + if (isSpanDurationBreakdownInsight(insight)) { return ( ); } + if (isSpanUsagesInsight(insight)) { return ( ); } - if (isSpanEndpointBottleneckInsight(insight)) { - return ( - - ); - } - if (isEndpointSlowestSpansInsight(insight)) { - return ( - - ); - } + + // if (isSpanEndpointBottleneckInsight(insight)) { + // return ( + // + // ); + // } + + // if (isEndpointSlowestSpansInsight(insight)) { + // return ( + // + // ); + // } + if (isSlowEndpointInsight(insight)) { return ( ); } + if ( isEndpointLowUsageInsight(insight) || isEndpointNormalUsageInsight(insight) || @@ -279,32 +273,22 @@ const renderInsightCard = ( /> ); } - if (isCodeObjectErrorsInsight(insight)) { - return ( - - ); - } - if (isEndpointSuspectedNPlusOneInsight(insight)) { - return ( - - ); - } + + // if (isEndpointSuspectedNPlusOneInsight(insight)) { + // return ( + // + // ); + // } + if (isSpanNPlusOneInsight(insight)) { return ( ); } + if (isSpanScalingBadlyInsight(insight)) { return ( ); } - if (isCodeObjectHotSpotInsight(insight)) { - return ( - - Major errors occur or propagate through this function - - } - onRecalculate={handleRecalculate} - onRefresh={onRefresh} - /> - ); - } - if (isEndpointDurationSlowdownInsight(insight)) { - return ( - - ); - } + + // if (isEndpointDurationSlowdownInsight(insight)) { + // return ( + // + // ); + // } if (isEndpointBreakdownInsight(insight)) { return ( @@ -371,30 +343,6 @@ const renderInsightCard = ( ); } - if (isSpanScalingWellInsight(insight)) { - return ( - - ); - } - - if (isSpanScalingInsufficientDataInsight(insight)) { - return ( - - ); - } - if (isSessionInViewEndpointInsight(insight)) { return ( { }, [previousPage, props.page, config, previousConfig]); useEffect(() => { - window.sendMessageToDigma({ + window.sendMessageToDigma({ action: actions.MARK_INSIGHT_TYPES_AS_VIEWED, payload: { insightTypes: props.insights.map((x) => ({ diff --git a/src/components/Insights/InsightsPage/types.ts b/src/components/Insights/InsightsPage/types.ts index 53a9e870c..a56b32b34 100644 --- a/src/components/Insights/InsightsPage/types.ts +++ b/src/components/Insights/InsightsPage/types.ts @@ -1,4 +1,4 @@ -import { GenericCodeObjectInsight } from "../types"; +import { GenericCodeObjectInsight, InsightType } from "../types"; export interface InsightPageProps { insights: GenericCodeObjectInsight[]; @@ -14,3 +14,10 @@ export interface InsightPageProps { export interface isInsightJiraTicketHintShownPayload { value: boolean; } + +export interface MarkInsightTypesAsViewedPayload { + insightTypes: { + type: InsightType; + reopenCount: number; + }[]; +} diff --git a/src/components/Insights/NPlusOneInsight/mockData.ts b/src/components/Insights/NPlusOneInsight/mockData.ts index 338c6c527..7a51ce12e 100644 --- a/src/components/Insights/NPlusOneInsight/mockData.ts +++ b/src/components/Insights/NPlusOneInsight/mockData.ts @@ -2,6 +2,7 @@ import { InsightType } from "../../../types"; import { InsightCategory, InsightScope, SpanNPlusOneInsight } from "../types"; export const mockedNPlusOneInsight: SpanNPlusOneInsight = { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-8cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", @@ -54,7 +55,15 @@ export const mockedNPlusOneInsight: SpanNPlusOneInsight = { occurrences: 100, criticality: 0.8, impact: 0, - severity: 0 + severity: 0, + requestPercentage: 50, + traceId: "00D37A4E7208E0F6E89AA7E2E37446A6", + commitId: "a1b2c3d", + duration: { + value: 1.64, + unit: "sec", + raw: 1636050588.0 + } } ], scope: InsightScope.Span, diff --git a/src/components/Insights/NoScalingIssueInsight/NoScalingIssueInsight.stories.tsx b/src/components/Insights/NoScalingIssueInsight/NoScalingIssueInsight.stories.tsx index 84a187e36..088953766 100644 --- a/src/components/Insights/NoScalingIssueInsight/NoScalingIssueInsight.stories.tsx +++ b/src/components/Insights/NoScalingIssueInsight/NoScalingIssueInsight.stories.tsx @@ -20,6 +20,7 @@ type Story = StoryObj; export const Default: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c7d-9628-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", diff --git a/src/components/Insights/PerformanceAtScaleInsight/PerformanceAtScaleInsight.stories.tsx b/src/components/Insights/PerformanceAtScaleInsight/PerformanceAtScaleInsight.stories.tsx index 5cf80a451..5326df24c 100644 --- a/src/components/Insights/PerformanceAtScaleInsight/PerformanceAtScaleInsight.stories.tsx +++ b/src/components/Insights/PerformanceAtScaleInsight/PerformanceAtScaleInsight.stories.tsx @@ -20,6 +20,7 @@ type Story = StoryObj; export const Default: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55492-8262-4c5d-9628-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", diff --git a/src/components/Insights/QueryOptimizationInsight/mockData.ts b/src/components/Insights/QueryOptimizationInsight/mockData.ts index da81088e0..841d06801 100644 --- a/src/components/Insights/QueryOptimizationInsight/mockData.ts +++ b/src/components/Insights/QueryOptimizationInsight/mockData.ts @@ -6,6 +6,7 @@ import { } from "../types"; export const mockedQueryOptimizationInsight: QueryOptimizationInsight = { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c8d-9628-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", diff --git a/src/components/Insights/RequestBreakdownInsight/RequestBreakdownInsight.stories.tsx b/src/components/Insights/RequestBreakdownInsight/RequestBreakdownInsight.stories.tsx index 7e6fdb610..4ca60c889 100644 --- a/src/components/Insights/RequestBreakdownInsight/RequestBreakdownInsight.stories.tsx +++ b/src/components/Insights/RequestBreakdownInsight/RequestBreakdownInsight.stories.tsx @@ -23,6 +23,7 @@ export default meta; type Story = StoryObj; const data: EndpointBreakdownInsight = { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-7cce7979dd6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", diff --git a/src/components/Insights/ScalingIssueInsight/mockData.ts b/src/components/Insights/ScalingIssueInsight/mockData.ts index 2915783e1..ca1c101dd 100644 --- a/src/components/Insights/ScalingIssueInsight/mockData.ts +++ b/src/components/Insights/ScalingIssueInsight/mockData.ts @@ -1,11 +1,12 @@ import { InsightType } from "../../../types"; import { - SpanScalingBadlyInsight, InsightCategory, - InsightScope + InsightScope, + SpanScalingBadlyInsight } from "../types"; export const mockedSpanScalingInsight: SpanScalingBadlyInsight = { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "90b55792-8262-4c5d-9628-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", diff --git a/src/components/Insights/SessionInViewInsight/SessionInViewInsight.stories.tsx b/src/components/Insights/SessionInViewInsight/SessionInViewInsight.stories.tsx index 0b86f65a8..22ecf1ce5 100644 --- a/src/components/Insights/SessionInViewInsight/SessionInViewInsight.stories.tsx +++ b/src/components/Insights/SessionInViewInsight/SessionInViewInsight.stories.tsx @@ -20,6 +20,7 @@ type Story = StoryObj; export const Default: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5a-9628-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", diff --git a/src/components/Insights/SlowEndpointInsight/SlowEndpointInsight.stories.tsx b/src/components/Insights/SlowEndpointInsight/SlowEndpointInsight.stories.tsx index 217bef041..9999a6d01 100644 --- a/src/components/Insights/SlowEndpointInsight/SlowEndpointInsight.stories.tsx +++ b/src/components/Insights/SlowEndpointInsight/SlowEndpointInsight.stories.tsx @@ -20,6 +20,7 @@ type Story = StoryObj; export const Default: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c3d-9628-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", diff --git a/src/components/Insights/SpanBottleneckInsight/mockData.ts b/src/components/Insights/SpanBottleneckInsight/mockData.ts index 7bbecdffa..cbff1e07d 100644 --- a/src/components/Insights/SpanBottleneckInsight/mockData.ts +++ b/src/components/Insights/SpanBottleneckInsight/mockData.ts @@ -6,6 +6,7 @@ import { } from "../types"; export const mockedSpanBottleneckInsight: EndpointSlowestSpansInsight = { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-7dce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", diff --git a/src/components/Insights/SpanNexusInsight/mockData.ts b/src/components/Insights/SpanNexusInsight/mockData.ts index 0dc1395b6..f07736609 100644 --- a/src/components/Insights/SpanNexusInsight/mockData.ts +++ b/src/components/Insights/SpanNexusInsight/mockData.ts @@ -2,6 +2,7 @@ import { InsightType } from "../../../types"; import { InsightCategory, InsightScope, SpanNexusInsight } from "../types"; export const mockedSpanNexusInsight: SpanNexusInsight = { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b54792-8262-4c5d-9628-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", diff --git a/src/components/Insights/TopUsageInsight/TopUsageInsight.stories.tsx b/src/components/Insights/TopUsageInsight/TopUsageInsight.stories.tsx index 27571f955..f23daf0fa 100644 --- a/src/components/Insights/TopUsageInsight/TopUsageInsight.stories.tsx +++ b/src/components/Insights/TopUsageInsight/TopUsageInsight.stories.tsx @@ -20,6 +20,7 @@ type Story = StoryObj; export const Default: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8162-4c5d-9628-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", diff --git a/src/components/Insights/TrafficInsight/TrafficInsight.stories.tsx b/src/components/Insights/TrafficInsight/TrafficInsight.stories.tsx index babc350ce..299d0bbcd 100644 --- a/src/components/Insights/TrafficInsight/TrafficInsight.stories.tsx +++ b/src/components/Insights/TrafficInsight/TrafficInsight.stories.tsx @@ -20,6 +20,7 @@ type Story = StoryObj; export const LowTraffic: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-3c5d-9628-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", @@ -82,6 +83,7 @@ export const LowTraffic: Story = { export const HighTraffic: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-3c5d-9628-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", diff --git a/src/components/Insights/common/insights/DurationInsight/DurationInsight.stories.tsx b/src/components/Insights/common/insights/DurationInsight/DurationInsight.stories.tsx index 43b7295cc..a13c58041 100644 --- a/src/components/Insights/common/insights/DurationInsight/DurationInsight.stories.tsx +++ b/src/components/Insights/common/insights/DurationInsight/DurationInsight.stories.tsx @@ -19,6 +19,7 @@ type Story = StoryObj; export const WithAverage: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", @@ -135,6 +136,7 @@ export const WithAverage: Story = { export const WithChange: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-7cce7979ad6d", firstDetected: null, lastDetected: null, @@ -241,6 +243,7 @@ export const WithChange: Story = { export const WithEvaluatingChange: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-7cce7979ad6d", firstDetected: null, lastDetected: null, @@ -347,6 +350,7 @@ export const WithEvaluatingChange: Story = { export const HistogramWithManyBars: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-7cce7979ad6d", firstDetected: null, lastDetected: null, @@ -4871,6 +4875,7 @@ export const HistogramWithManyBars: Story = { export const HistogramWithGaps: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-7cce7979ad6d", firstDetected: null, lastDetected: null, @@ -5125,6 +5130,7 @@ export const HistogramWithGaps: Story = { export const HistogramWithAFewBars: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-7cce7979ad6d", firstDetected: null, lastDetected: null, @@ -5279,6 +5285,7 @@ export const HistogramWithAFewBars: Story = { export const EmptyStateBug: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9628-7cce7979ad6d", name: "Performance Stats", type: InsightType.SpanDurations, diff --git a/src/components/Insights/common/insights/ExcessiveAPICallsInsight/ExcessiveAPICallsInsight.stories.tsx b/src/components/Insights/common/insights/ExcessiveAPICallsInsight/ExcessiveAPICallsInsight.stories.tsx index ac10eff92..20faae2ba 100644 --- a/src/components/Insights/common/insights/ExcessiveAPICallsInsight/ExcessiveAPICallsInsight.stories.tsx +++ b/src/components/Insights/common/insights/ExcessiveAPICallsInsight/ExcessiveAPICallsInsight.stories.tsx @@ -19,6 +19,7 @@ type Story = StoryObj; export const Default: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9688-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", @@ -138,6 +139,7 @@ export const Default: Story = { export const EmptyTrace: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9688-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", diff --git a/src/components/Insights/common/insights/HighNumberOfQueriesInsight/index.tsx b/src/components/Insights/common/insights/HighNumberOfQueriesInsight/index.tsx index 3d4f8498d..49d6e1806 100644 --- a/src/components/Insights/common/insights/HighNumberOfQueriesInsight/index.tsx +++ b/src/components/Insights/common/insights/HighNumberOfQueriesInsight/index.tsx @@ -1,4 +1,3 @@ -import { getDurationString } from "../../../../../utils/getDurationString"; import { sendTrackingEvent } from "../../../../../utils/sendTrackingEvent"; import { InfoCircleIcon } from "../../../../common/icons/InfoCircleIcon"; import { Tag } from "../../../../common/v3/Tag"; @@ -64,9 +63,6 @@ export const HighNumberOfQueriesInsight = ( > - - {getDurationString(props.insight.medianDuration)} - } diff --git a/src/components/Insights/common/insights/HighNumberOfQueriesInsight/mockData.ts b/src/components/Insights/common/insights/HighNumberOfQueriesInsight/mockData.ts index beda9abbd..967c1775c 100644 --- a/src/components/Insights/common/insights/HighNumberOfQueriesInsight/mockData.ts +++ b/src/components/Insights/common/insights/HighNumberOfQueriesInsight/mockData.ts @@ -7,6 +7,7 @@ import { export const mockedHighNumberOfQueriesInsight: EndpointHighNumberOfQueriesInsight = { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c5d-9623-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", @@ -24,12 +25,6 @@ export const mockedHighNumberOfQueriesInsight: EndpointHighNumberOfQueriesInsigh importance: 3, queriesCount: 250, typicalCount: 4, - medianDuration: { - value: 150, - unit: "ms", - raw: 150000000.0 - }, - requestFraction: 0.3, traceId: "00D37A4E7208E0F6E89AA7E2E37446A6", scope: InsightScope.EntrySpan, endpointSpan: "HTTP POST /owners/{ownerId}/pets/new", diff --git a/src/components/Insights/common/insights/SlowEndpointInsight/SlowEndpointInsight.stories.tsx b/src/components/Insights/common/insights/SlowEndpointInsight/SlowEndpointInsight.stories.tsx index 93478a7f2..c964e901a 100644 --- a/src/components/Insights/common/insights/SlowEndpointInsight/SlowEndpointInsight.stories.tsx +++ b/src/components/Insights/common/insights/SlowEndpointInsight/SlowEndpointInsight.stories.tsx @@ -18,6 +18,7 @@ type Story = StoryObj; export const Default: Story = { args: { insight: { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-4c3d-9628-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", diff --git a/src/components/Insights/common/insights/SpanNexusInsight/mockData.ts b/src/components/Insights/common/insights/SpanNexusInsight/mockData.ts index c872748d7..c21c7c05e 100644 --- a/src/components/Insights/common/insights/SpanNexusInsight/mockData.ts +++ b/src/components/Insights/common/insights/SpanNexusInsight/mockData.ts @@ -6,6 +6,7 @@ import { } from "../../../types"; export const mockedSpanNexusInsight: SpanNexusInsight = { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b54792-8262-4c5d-9628-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", diff --git a/src/components/Insights/common/insights/TrafficInsight/TrafficInsight.stories.tsx b/src/components/Insights/common/insights/TrafficInsight/TrafficInsight.stories.tsx index ff340ec39..688ade3b2 100644 --- a/src/components/Insights/common/insights/TrafficInsight/TrafficInsight.stories.tsx +++ b/src/components/Insights/common/insights/TrafficInsight/TrafficInsight.stories.tsx @@ -23,6 +23,7 @@ export default meta; type Story = StoryObj; const BaseTrafficInsight = { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", id: "60b55792-8262-3c5d-9628-7cce7979ad6d", firstDetected: "2023-12-05T17:25:47.010Z", lastDetected: "2024-01-05T13:14:47.010Z", diff --git a/src/components/Insights/types.ts b/src/components/Insights/types.ts index 0fd58e8dd..43d0079ca 100644 --- a/src/components/Insights/types.ts +++ b/src/components/Insights/types.ts @@ -29,10 +29,12 @@ export type GenericCodeObjectInsight = | EndpointNormalUsageInsight | EndpointHighUsageInsight | EndpointSlowestSpansInsight + | EndpointBottleneckInsight | SlowEndpointInsight | SpanScalingBadlyInsight | SpanNPlusOneInsight | EndpointSuspectedNPlusOneInsight + | EndpointSpanNPlusOneInsight | CodeObjectHotSpotInsight | CodeObjectErrorsInsight | EndpointDurationSlowdownInsight @@ -177,6 +179,7 @@ export interface CodeObjectInsight extends Insight { reopenCount: number; ticketLink: string | null; id: string; + sourceSpanCodeObjectInsight: string; } export interface SpanInsight extends CodeObjectInsight { @@ -282,6 +285,10 @@ export interface SpanEndpointBottleneckInsight extends SpanInsight { }; probabilityOfBeingBottleneck: number; avgDurationWhenBeingBottleneck: Duration; + impact: number; + severity: number; + criticality: number; + requestPercentage: number; /** * @deprecated @@ -392,7 +399,9 @@ export interface EndpointHighUsageInsight extends EndpointInsight { maxCallsIn1Min: number; } -// obsolete +/** + * @deprecated + */ export interface EndpointSlowestSpansInsight extends EndpointInsight { name: "Bottleneck Detected"; type: InsightType.SlowestSpans; @@ -429,7 +438,7 @@ export interface EndpointBottleneckInsight extends EndpointInsight { specifity: InsightSpecificity.TargetFound; importance: InsightImportance.Critical; isRecalculateEnabled: true; - spans: { + span: { spanInfo: SpanInfo; probabilityOfBeingBottleneck: number; avgDurationWhenBeingBottleneck: Duration; @@ -552,6 +561,10 @@ export interface SpanNPlusOneInsight extends SpanInsight { criticality: number; impact: number; severity: number; + traceId: string; + duration: Duration; + commitId: string; + requestPercentage: number; }[]; /** @@ -560,6 +573,9 @@ export interface SpanNPlusOneInsight extends SpanInsight { span: SpanInfo; } +/** + * @deprecated + */ export interface EndpointSuspectedNPlusOneInsight extends EndpointInsight { name: "Suspected N+1 Query"; type: InsightType.EndpointSpanNPlusOne; @@ -588,7 +604,7 @@ export interface EndpointSpanNPlusOneInsight extends EndpointInsight { specifity: InsightSpecificity.TargetAndReasonFound; importance: InsightImportance.HighlyImportant; isRecalculateEnabled: true; - spans: { + span: { occurrences: number; internalSpan: SpanInfo | null; clientSpan: SpanInfo; @@ -631,8 +647,7 @@ export interface CodeObjectErrorsInsight extends CodeObjectInsight { }[]; } -// obsolete -export interface DurationSlowdownSource { +export interface EndpointSlowdownSource { percentile: string; spanInfo: SpanInfo; level: number; @@ -642,17 +657,14 @@ export interface DurationSlowdownSource { changeVerified: boolean; } -export interface EndpointSlowdownSources { - percentile: string; - spanInfo: SpanInfo; - level: number; - previousDuration: Duration; - currentDuration: Duration; - changeTime: string; - changeVerified: boolean; -} +/** + * @deprecated + */ +export type DurationSlowdownSource = EndpointSlowdownSource; -// obsolete +/** + * @deprecated + */ export interface EndpointDurationSlowdownInsight extends EndpointInsight { name: "Endpoint Duration Slowdown Source"; type: InsightType.EndpointDurationSlowdown; @@ -669,7 +681,7 @@ export interface EndpointSlowdownSourceInsight extends EndpointInsight { category: InsightCategory.Performance; specifity: InsightSpecificity.OwnInsight; importance: InsightImportance.Critical; - endpointSlowdownSources: EndpointSlowdownSources[]; + endpointSlowdownSources: EndpointSlowdownSource[] | null; decorators: CodeObjectDecorator[]; } @@ -701,6 +713,9 @@ export interface EndpointBreakdownInsight extends EndpointInsight { export type SpanUsageStatusInsight = SpanInsight; +/** + * @deprecated + */ export interface SpanScalingWellInsight extends SpanInsight { name: "Scaling Well"; type: InsightType.SpanScalingWell; @@ -713,11 +728,17 @@ export interface SpanScalingWellInsight extends SpanInsight { flowHash: string | null; } +/** + * @deprecated + */ export interface Concurrency { calls: number; meanDuration: Duration; } +/** + * @deprecated + */ export interface SpanScalingInsufficientDataInsight extends SpanInsight { name: "Scaling Insufficient Data"; type: InsightType.SpanScalingInsufficientData; @@ -757,9 +778,7 @@ export interface EndpointHighNumberOfQueriesInsight extends EndpointInsight { type: InsightType.EndpointHighNumberOfQueries; queriesCount: number; typicalCount: number; - medianDuration: Duration; traceId: string | null; - requestFraction: number; quantile?: number; } diff --git a/src/utils/getInsightTypeInfo.ts b/src/utils/getInsightTypeInfo.ts index 6e9c4baf7..4617d760b 100644 --- a/src/utils/getInsightTypeInfo.ts +++ b/src/utils/getInsightTypeInfo.ts @@ -58,16 +58,28 @@ export const getInsightTypeInfo = ( icon: MeterHighIcon, label: "Endpoint High Traffic" }, + // deprecated [InsightType.SlowestSpans]: { icon: BottleneckIcon, label: "Bottleneck", description: descriptionProvider.BottleneckDescription }, + [InsightType.EndpointBottleneck]: { + icon: BottleneckIcon, + label: "Bottleneck", + description: descriptionProvider.BottleneckDescription + }, + // deprecated [InsightType.EndpointSpanNPlusOne]: { icon: SQLDatabaseIcon, label: "Suspected N-Plus-1", description: descriptionProvider.NPlusOneDescription }, + [InsightType.EndpointSpanNPlusOneV2]: { + icon: SQLDatabaseIcon, + label: "Suspected N-Plus-1", + description: descriptionProvider.NPlusOneDescription + }, [InsightType.SpanNPlusOne]: { icon: SQLDatabaseIcon, label: "Suspected N-Plus-1", @@ -95,18 +107,25 @@ export const getInsightTypeInfo = ( icon: ClockWithTicksIcon, label: "Duration Breakdown" }, + // deprecated [InsightType.EndpointDurationSlowdown]: { icon: SnailIcon, label: "Duration Slowdown Source Detected" }, + [InsightType.EndpointSlowdownSource]: { + icon: SnailIcon, + label: "Duration Slowdown Source Detected" + }, [InsightType.EndpointBreakdown]: { icon: PieChartIcon, label: "Request Breakdown" }, + // deprecated [InsightType.SpanScalingWell]: { icon: ScalesIcon, label: "No Scaling Issue Detected" }, + // deprecated [InsightType.SpanScalingInsufficientData]: { icon: ScalesIcon, label: "Performance at Scale" diff --git a/src/utils/getInsightTypeOrderPriority.ts b/src/utils/getInsightTypeOrderPriority.ts index 68fd09209..4e2e7cde7 100644 --- a/src/utils/getInsightTypeOrderPriority.ts +++ b/src/utils/getInsightTypeOrderPriority.ts @@ -10,11 +10,11 @@ export const getInsightTypeOrderPriority = (type: string): number => { [InsightType.EndpointBreakdown]: 5, [InsightType.HighUsage]: 10, [InsightType.SlowEndpoint]: 20, - [InsightType.EndpointDurationSlowdown]: 25, + [InsightType.EndpointSlowdownSource]: 25, [InsightType.LowUsage]: 30, - [InsightType.SlowestSpans]: 40, + [InsightType.EndpointBottleneck]: 40, [InsightType.NormalUsage]: 50, - [InsightType.EndpointSpanNPlusOne]: 55, + [InsightType.EndpointSpanNPlusOneV2]: 55, [InsightType.EndpointSessionInView]: 56, [InsightType.EndpointChattyApi]: 57, [InsightType.EndpointHighNumberOfQueries]: 58, @@ -23,9 +23,7 @@ export const getInsightTypeOrderPriority = (type: string): number => { // Span insights [InsightType.SpanDurations]: 60, [InsightType.SpanUsages]: 61, - [InsightType.SpanScalingInsufficientData]: 62, [InsightType.SpanScalingBadly]: 63, - [InsightType.SpanScalingWell]: 64, [InsightType.SpanNPlusOne]: 65, [InsightType.SpanEndpointBottleneck]: 67, [InsightType.SpanDurationBreakdown]: 68, From 7304e6fbe01a532f49ba535fd8078c90617c263d Mon Sep 17 00:00:00 2001 From: opoliarush <156646693+opoliarush@users.noreply.github.com> Date: Thu, 29 Feb 2024 15:39:03 +0200 Subject: [PATCH 02/56] Nplus one (#563) * Add N-Plus-One insights --- .../Insights/common/InsightCard/index.tsx | 1 + .../Insights/common/InsightCard/types.ts | 3 +- .../EndpointNPlusOneInsight.stories.tsx | 23 +++ .../EndpointNPlusOneInsight/index.tsx | 106 +++++++++++++ .../EndpointNPlusOneInsight/mockData.ts | 90 +++++++++++ .../EndpointNPlusOneInsight/styles.ts | 12 ++ .../insights/EndpointNPlusOneInsight/types.ts | 19 +++ .../ExcessiveAPICallsInsight/index.tsx | 13 +- .../ExcessiveAPICallsInsight/styles.ts | 19 --- .../HighNumberOfQueriesInsight/index.tsx | 9 +- .../HighNumberOfQueriesInsight/styles.ts | 39 ----- .../insights/SlowEndpointInsight/index.tsx | 5 +- .../insights/SlowEndpointInsight/styles.ts | 6 - .../SpanNPlusOneInsight.stories.tsx | 29 ++++ .../insights/SpanNPlusOneInsight/index.tsx | 140 ++++++++++++++++++ .../insights/SpanNPlusOneInsight/mockData.ts | 131 ++++++++++++++++ .../insights/SpanNPlusOneInsight/styles.ts | 14 ++ .../insights/SpanNPlusOneInsight/types.ts | 19 +++ .../insights/SpanNexusInsight/index.tsx | 5 +- .../insights/SpanNexusInsight/styles.ts | 6 - .../Insights/common/insights/styles.ts | 26 ++++ src/components/Insights/types.ts | 1 + src/components/common/v3/JiraButton/index.tsx | 5 +- src/components/common/v3/JiraButton/types.ts | 6 +- 24 files changed, 639 insertions(+), 88 deletions(-) create mode 100644 src/components/Insights/common/insights/EndpointNPlusOneInsight/EndpointNPlusOneInsight.stories.tsx create mode 100644 src/components/Insights/common/insights/EndpointNPlusOneInsight/index.tsx create mode 100644 src/components/Insights/common/insights/EndpointNPlusOneInsight/mockData.ts create mode 100644 src/components/Insights/common/insights/EndpointNPlusOneInsight/styles.ts create mode 100644 src/components/Insights/common/insights/EndpointNPlusOneInsight/types.ts create mode 100644 src/components/Insights/common/insights/SpanNPlusOneInsight/SpanNPlusOneInsight.stories.tsx create mode 100644 src/components/Insights/common/insights/SpanNPlusOneInsight/index.tsx create mode 100644 src/components/Insights/common/insights/SpanNPlusOneInsight/mockData.ts create mode 100644 src/components/Insights/common/insights/SpanNPlusOneInsight/styles.ts create mode 100644 src/components/Insights/common/insights/SpanNPlusOneInsight/types.ts create mode 100644 src/components/Insights/common/insights/styles.ts diff --git a/src/components/Insights/common/InsightCard/index.tsx b/src/components/Insights/common/InsightCard/index.tsx index 060671e2f..1a8033724 100644 --- a/src/components/Insights/common/InsightCard/index.tsx +++ b/src/components/Insights/common/InsightCard/index.tsx @@ -138,6 +138,7 @@ export const InsightCard = (props: InsightCardProps) => { onTicketInfoButtonClick={props.onJiraButtonClick} ticketLink={props.jiraTicketInfo?.ticketLink} isHintEnabled={props.jiraTicketInfo?.isHintEnabled} + spanCodeObjectId={props.jiraTicketInfo?.spanCodeObjectId} /> )} {props.onPin && } diff --git a/src/components/Insights/common/InsightCard/types.ts b/src/components/Insights/common/InsightCard/types.ts index 928cb56dc..58eb94a14 100644 --- a/src/components/Insights/common/InsightCard/types.ts +++ b/src/components/Insights/common/InsightCard/types.ts @@ -25,6 +25,7 @@ export interface InsightCardProps { jiraTicketInfo?: { ticketLink?: string | null; isHintEnabled?: boolean; + spanCodeObjectId?: string; }; - onJiraButtonClick?: (event: string) => void; + onJiraButtonClick?: (spanCodeObjectId: string, event: string) => void; } diff --git a/src/components/Insights/common/insights/EndpointNPlusOneInsight/EndpointNPlusOneInsight.stories.tsx b/src/components/Insights/common/insights/EndpointNPlusOneInsight/EndpointNPlusOneInsight.stories.tsx new file mode 100644 index 000000000..201adf1b1 --- /dev/null +++ b/src/components/Insights/common/insights/EndpointNPlusOneInsight/EndpointNPlusOneInsight.stories.tsx @@ -0,0 +1,23 @@ +import { Meta, StoryObj } from "@storybook/react"; +import { EndpointNPlusOneInsight } from "."; +import { mockedEndpointNPlusOneInsight } from "./mockData"; + +// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction +const meta: Meta = { + title: "Insights/common/insights/EndpointNPlusOneInsight", + component: EndpointNPlusOneInsight, + 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 Default: Story = { + args: { + insight: mockedEndpointNPlusOneInsight + } +}; diff --git a/src/components/Insights/common/insights/EndpointNPlusOneInsight/index.tsx b/src/components/Insights/common/insights/EndpointNPlusOneInsight/index.tsx new file mode 100644 index 000000000..1c2a605b3 --- /dev/null +++ b/src/components/Insights/common/insights/EndpointNPlusOneInsight/index.tsx @@ -0,0 +1,106 @@ +import { useContext } from "react"; +import { getDurationString } from "../../../../../utils/getDurationString"; +import { sendTrackingEvent } from "../../../../../utils/sendTrackingEvent"; +import { ConfigContext } from "../../../../common/App/ConfigContext"; +import { InfoCircleIcon } from "../../../../common/icons/InfoCircleIcon"; +import { Tooltip } from "../../../../common/v3/Tooltip"; +import { trackingEvents } from "../../../tracking"; +import { InsightType, Trace } from "../../../types"; +import { InsightCard } from "../../InsightCard"; +import { ColumnsContainer } from "../../InsightCard/ColumnsContainer"; +import { KeyValue } from "../../InsightCard/KeyValue"; +import { ContentContainer, Description, Details } from "../styles"; +import * as s from "./styles"; +import { EndpointNPlusOneInsightProps } from "./types"; + +export const EndpointNPlusOneInsight = ( + props: EndpointNPlusOneInsightProps +) => { + const config = useContext(ConfigContext); + const { span } = props.insight; + + const handleSpanLinkClick = (spanCodeObjectId: string) => { + props.onAssetLinkClick(spanCodeObjectId, props.insight.type); + }; + + const handleTicketInfoButtonClick = ( + spanCodeObjectId: string, + event: string + ) => { + sendTrackingEvent(trackingEvents.JIRA_TICKET_INFO_BUTTON_CLICKED, { + insightType: props.insight.type + }); + props.onJiraTicketCreate && + props.onJiraTicketCreate(props.insight, spanCodeObjectId, event); + }; + + const handleTraceButtonClick = ( + trace: Trace, + insightType: InsightType, + spanCodeObjectId: string + ) => { + props.onTraceButtonClick(trace, insightType, spanCodeObjectId); + }; + + const spanInfo = span.internalSpan || span.clientSpan; + const spanName = spanInfo.displayName; + + return ( + + handleTraceButtonClick( + { + name: spanName, + id: span.traceId + }, + props.insight.type, + spanInfo.spanCodeObjectId + ) + : undefined + } + jiraTicketInfo={{ + ticketLink: span.ticketLink, + isHintEnabled: props.isJiraHintEnabled, + spanCodeObjectId: spanInfo.spanCodeObjectId + }} + content={ + +
+ Assets + handleSpanLinkClick(spanInfo.spanCodeObjectId)} + /> +
+ + {span.occurrences} + + +
Requests
+ +
+ + } + > + {span.requestPercentage}% +
+ + {getDurationString(span.duration)} + +
+
+ } + onRecalculate={props.onRecalculate} + onRefresh={props.onRefresh} + /> + ); +}; diff --git a/src/components/Insights/common/insights/EndpointNPlusOneInsight/mockData.ts b/src/components/Insights/common/insights/EndpointNPlusOneInsight/mockData.ts new file mode 100644 index 000000000..8b5cce804 --- /dev/null +++ b/src/components/Insights/common/insights/EndpointNPlusOneInsight/mockData.ts @@ -0,0 +1,90 @@ +import { + EndpointSpanNPlusOneInsight, + InsightCategory, + InsightScope, + InsightType +} from "../../../types"; + +export const mockedEndpointNPlusOneInsight: EndpointSpanNPlusOneInsight = { + id: "60b55792-8262-4c5d-9628-7cce7919ad6d", + firstDetected: "2023-12-05T17:25:47.010Z", + lastDetected: "2024-01-05T13:14:47.010Z", + criticality: 0, + firstCommitId: "b3f7b3f", + lastCommitId: "a1b2c3d", + deactivatedCommitId: null, + reopenCount: 0, + ticketLink: null, + impact: 0, + name: "Suspected N+1 Query", + type: InsightType.EndpointSpanNPlusOneV2, + category: InsightCategory.Performance, + specifity: 2, + importance: 3, + span: { + occurrences: 200, + internalSpan: null, + clientSpan: { + name: "1D138649EB4FFA92C0E3C8103404F2", + displayName: "select * from users where id = :id", + instrumentationLibrary: "SampleInsightsController", + spanCodeObjectId: + "span:SampleInsightsController$_$1D138649EB4FFA92C0E3C8103404F2", + methodCodeObjectId: null, + kind: "Client", + codeObjectId: null + }, + traceId: "9C510BC1E1CD59DD7E820BC3E8DFD4C4", + duration: { + value: 70.08, + unit: "μs", + raw: 70081 + }, + fraction: 0.08985711281727758, + criticality: 0.3, + impact: 0, + severity: 0, + ticketLink: "https://digma.ai/1", + requestPercentage: 98 + }, + scope: InsightScope.EntrySpan, + endpointSpan: "HTTP GET /SampleInsights/NPlusOneWithoutInternalSpan", + spanCodeObjectId: + "span:io.opentelemetry.tomcat-10.0$_$HTTP GET /SampleInsights/NPlusOneWithoutInternalSpan", + route: "epHTTP:HTTP GET /SampleInsights/NPlusOneWithoutInternalSpan", + serviceName: "PetClinic", + spanInfo: { + name: "HTTP GET /SampleInsights/NPlusOneWithoutInternalSpan", + displayName: "HTTP GET /SampleInsights/NPlusOneWithoutInternalSpan", + instrumentationLibrary: "io.opentelemetry.tomcat-10.0", + spanCodeObjectId: + "span:io.opentelemetry.tomcat-10.0$_$HTTP GET /SampleInsights/NPlusOneWithoutInternalSpan", + methodCodeObjectId: + "method:org.springframework.samples.petclinic.sample.SampleInsightsController$_$genNPlusOneWithoutInternalSpan", + kind: "Server", + codeObjectId: + "org.springframework.samples.petclinic.sample.SampleInsightsController$_$genNPlusOneWithoutInternalSpan" + }, + shortDisplayInfo: { + title: "", + targetDisplayName: "", + subtitle: "", + description: "" + }, + codeObjectId: + "org.springframework.samples.petclinic.sample.SampleInsightsController$_$genNPlusOneWithoutInternalSpan", + decorators: [ + { + title: "N+1 Suspected", + description: "Supected NPlus One" + } + ], + environment: "SAMPLE_ENV", + severity: 0, + isRecalculateEnabled: true, + prefixedCodeObjectId: + "method:org.springframework.samples.petclinic.sample.SampleInsightsController$_$genNPlusOneWithoutInternalSpan", + customStartTime: null, + actualStartTime: "2023-06-16T10:30:33.027Z", + sourceSpanCodeObjectInsight: "" +}; diff --git a/src/components/Insights/common/insights/EndpointNPlusOneInsight/styles.ts b/src/components/Insights/common/insights/EndpointNPlusOneInsight/styles.ts new file mode 100644 index 000000000..f1cafeb5a --- /dev/null +++ b/src/components/Insights/common/insights/EndpointNPlusOneInsight/styles.ts @@ -0,0 +1,12 @@ +import styled from "styled-components"; +import { ListItem } from "../../InsightCard/ListItem"; + +export const InfoContainer = styled.div` + display: flex; + gap: 4px; + align-items: center; +`; + +export const SpanListItem = styled(ListItem)` + padding: 4px; +`; diff --git a/src/components/Insights/common/insights/EndpointNPlusOneInsight/types.ts b/src/components/Insights/common/insights/EndpointNPlusOneInsight/types.ts new file mode 100644 index 000000000..4362c2b9d --- /dev/null +++ b/src/components/Insights/common/insights/EndpointNPlusOneInsight/types.ts @@ -0,0 +1,19 @@ +import { + EndpointSpanNPlusOneInsight, + InsightProps, + InsightType, + Trace +} from "../../../types"; + +export interface EndpointNPlusOneInsightProps extends InsightProps { + insight: EndpointSpanNPlusOneInsight; + onAssetLinkClick: ( + spanCodeObjectId: string, + insightType: InsightType + ) => void; + onTraceButtonClick: ( + trace: Trace, + insightType: InsightType, + spanCodeObjectId: string + ) => void; +} diff --git a/src/components/Insights/common/insights/ExcessiveAPICallsInsight/index.tsx b/src/components/Insights/common/insights/ExcessiveAPICallsInsight/index.tsx index 36cc36715..d228fe104 100644 --- a/src/components/Insights/common/insights/ExcessiveAPICallsInsight/index.tsx +++ b/src/components/Insights/common/insights/ExcessiveAPICallsInsight/index.tsx @@ -6,6 +6,7 @@ import { Button } from "../../../../common/v3/Button"; import { Pagination } from "../../../../common/v3/Pagination"; import { InsightType, Trace } from "../../../types"; import { InsightCard } from "../../InsightCard"; +import { ContentContainer, Description, ListContainer } from "../styles"; import * as s from "./styles"; import { ExcessiveAPICallsInsightProps } from "./types"; @@ -38,11 +39,11 @@ export const ExcessiveAPICallsInsight = ( - + + Excessive API calls to specific endpoint found - - + + {pageItems.map((span) => { const spanName = span.clientSpan.displayName; const traceId = span.traceId; @@ -81,8 +82,8 @@ export const ExcessiveAPICallsInsight = ( onPageChange={setPage} withDescription={true} /> - - + + } onRecalculate={props.onRecalculate} onRefresh={props.onRefresh} diff --git a/src/components/Insights/common/insights/ExcessiveAPICallsInsight/styles.ts b/src/components/Insights/common/insights/ExcessiveAPICallsInsight/styles.ts index d80182dfc..39395a748 100644 --- a/src/components/Insights/common/insights/ExcessiveAPICallsInsight/styles.ts +++ b/src/components/Insights/common/insights/ExcessiveAPICallsInsight/styles.ts @@ -1,25 +1,6 @@ import styled from "styled-components"; -import { caption1RegularTypography } from "../../../../common/App/typographies"; import { ListItem } from "../../InsightCard/ListItem"; -export const ContentContainer = styled.div` - display: flex; - flex-direction: column; - gap: 4px; -`; - -export const List = styled.div` - display: flex; - flex-direction: column; - gap: 4px; -`; - -export const Description = styled.div` - color: ${({ theme }) => theme.colors.v3.text.tertiary}; - - ${caption1RegularTypography} -`; - export const SpanListItem = styled(ListItem)` padding: 4px; `; diff --git a/src/components/Insights/common/insights/HighNumberOfQueriesInsight/index.tsx b/src/components/Insights/common/insights/HighNumberOfQueriesInsight/index.tsx index 49d6e1806..104dc4b77 100644 --- a/src/components/Insights/common/insights/HighNumberOfQueriesInsight/index.tsx +++ b/src/components/Insights/common/insights/HighNumberOfQueriesInsight/index.tsx @@ -2,12 +2,12 @@ import { sendTrackingEvent } from "../../../../../utils/sendTrackingEvent"; import { InfoCircleIcon } from "../../../../common/icons/InfoCircleIcon"; import { Tag } from "../../../../common/v3/Tag"; import { Tooltip } from "../../../../common/v3/Tooltip"; -import { Description } from "../../../styles"; import { trackingEvents } from "../../../tracking"; import { InsightType, Trace } from "../../../types"; import { InsightCard } from "../../InsightCard"; import { ColumnsContainer } from "../../InsightCard/ColumnsContainer"; import { KeyValue } from "../../InsightCard/KeyValue"; +import { ContentContainer, Description } from "../styles"; import * as s from "./styles"; import { HighNumberOfQueriesInsightProps } from "./types"; @@ -37,7 +37,7 @@ export const HighNumberOfQueriesInsight = ( + {insight.quantile === 0.95 && ( Affecting the slowest 5% of requests. )} @@ -64,14 +64,15 @@ export const HighNumberOfQueriesInsight = ( - + } onRecalculate={props.onRecalculate} onRefresh={props.onRefresh} onJiraButtonClick={handleCreateJiraTicketButtonClick} jiraTicketInfo={{ ticketLink: insight.ticketLink, - isHintEnabled: props.isJiraHintEnabled + isHintEnabled: props.isJiraHintEnabled, + spanCodeObjectId: props.insight.spanInfo?.spanCodeObjectId }} onGoToTrace={ traceId diff --git a/src/components/Insights/common/insights/HighNumberOfQueriesInsight/styles.ts b/src/components/Insights/common/insights/HighNumberOfQueriesInsight/styles.ts index 917de6764..5b16399ca 100644 --- a/src/components/Insights/common/insights/HighNumberOfQueriesInsight/styles.ts +++ b/src/components/Insights/common/insights/HighNumberOfQueriesInsight/styles.ts @@ -1,48 +1,9 @@ import styled from "styled-components"; -export const ContentContainer = styled.div` - display: flex; - flex-direction: column; - gap: 8px; -`; - -export const Stats = styled.div` - display: flex; - border-radius: 4px; - gap: 20px; - justify-content: space-between; -`; - -export const Stat = styled.div` - display: flex; - flex-direction: column; - gap: 8px; - overflow: hidden; -`; - -export const KeyContainer = styled.span` - display: flex; - align-items: center; - gap: 4px; -`; - -export const Key = styled.span` - font-size: 14px; - font-weight: 510; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; -`; - export const IconContainer = styled.span` display: flex; `; -export const ActionsContainer = styled.div` - display: flex; - gap: 8px; -`; - export const TypicalLabel = styled.div` display: flex; gap: 4px; diff --git a/src/components/Insights/common/insights/SlowEndpointInsight/index.tsx b/src/components/Insights/common/insights/SlowEndpointInsight/index.tsx index a64c31701..273024d6c 100644 --- a/src/components/Insights/common/insights/SlowEndpointInsight/index.tsx +++ b/src/components/Insights/common/insights/SlowEndpointInsight/index.tsx @@ -4,6 +4,7 @@ import { Tag } from "../../../../common/v3/Tag"; import { InsightCard } from "../../InsightCard"; import { ColumnsContainer } from "../../InsightCard/ColumnsContainer"; import { KeyValue } from "../../InsightCard/KeyValue"; +import { Description } from "../styles"; import * as s from "./styles"; import { SlowEndpointInsightProps } from "./types"; @@ -19,12 +20,12 @@ export const SlowEndpointInsight = (props: SlowEndpointInsightProps) => { content={ - + {`On average requests are slower than other endpoints by ${roundTo( diff, 2 )}%`} - + diff --git a/src/components/Insights/common/insights/SlowEndpointInsight/styles.ts b/src/components/Insights/common/insights/SlowEndpointInsight/styles.ts index 7b6ffa5e6..451869f09 100644 --- a/src/components/Insights/common/insights/SlowEndpointInsight/styles.ts +++ b/src/components/Insights/common/insights/SlowEndpointInsight/styles.ts @@ -1,11 +1,5 @@ import styled from "styled-components"; -import { caption1RegularTypography } from "../../../../common/App/typographies"; export const ContentContainer = styled.div` padding: 8px 0; `; - -export const Description = styled.div` - color: ${({ theme }) => theme.colors.v3.text.secondary}; - ${caption1RegularTypography} -`; diff --git a/src/components/Insights/common/insights/SpanNPlusOneInsight/SpanNPlusOneInsight.stories.tsx b/src/components/Insights/common/insights/SpanNPlusOneInsight/SpanNPlusOneInsight.stories.tsx new file mode 100644 index 000000000..1f88ebf90 --- /dev/null +++ b/src/components/Insights/common/insights/SpanNPlusOneInsight/SpanNPlusOneInsight.stories.tsx @@ -0,0 +1,29 @@ +import { Meta, StoryObj } from "@storybook/react"; +import { SpanNPlusOneInsight } from "."; +import { mockedNPlusOneInsight } from "./mockData"; + +// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction +const meta: Meta = { + title: "Insights/common/insights/SpanNPlusOneInsight", + component: SpanNPlusOneInsight, + 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 Default: Story = { + args: { + insight: mockedNPlusOneInsight + } +}; + +export const LinkedJira: Story = { + args: { + insight: { ...mockedNPlusOneInsight, ticketLink: "https://digma.ai/1" } + } +}; diff --git a/src/components/Insights/common/insights/SpanNPlusOneInsight/index.tsx b/src/components/Insights/common/insights/SpanNPlusOneInsight/index.tsx new file mode 100644 index 000000000..62d989b72 --- /dev/null +++ b/src/components/Insights/common/insights/SpanNPlusOneInsight/index.tsx @@ -0,0 +1,140 @@ +import { useContext, useState } from "react"; +import { getDurationString } from "../../../../../utils/getDurationString"; +import { sendTrackingEvent } from "../../../../../utils/sendTrackingEvent"; +import { trimEndpointScheme } from "../../../../../utils/trimEndpointScheme"; +import { ConfigContext } from "../../../../common/App/ConfigContext"; +import { InfoCircleIcon } from "../../../../common/icons/InfoCircleIcon"; +import { Tooltip } from "../../../../common/v3/Tooltip"; +import { trackingEvents } from "../../../tracking"; +import { InsightType, Trace } from "../../../types"; +import { InsightCard } from "../../InsightCard"; +import { ColumnsContainer } from "../../InsightCard/ColumnsContainer"; +import { KeyValue } from "../../InsightCard/KeyValue"; +import { ListItem } from "../../InsightCard/ListItem"; +import { Select } from "../../InsightCard/Select"; +import { ContentContainer, Description, Details } from "../styles"; +import * as s from "./styles"; +import { SpanNPlusOneInsightProps } from "./types"; + +export const SpanNPlusOneInsight = (props: SpanNPlusOneInsightProps) => { + const { + insight: { type, endpoints, ticketLink } + } = props; + + const config = useContext(ConfigContext); + const [selectedEndpoint, setSelectedEndpoint] = useState( + props.insight.endpoints.length ? props.insight.endpoints[0] : null + ); + + const handleSpanLinkClick = (spanCodeObjectId?: string) => { + spanCodeObjectId && props.onAssetLinkClick(spanCodeObjectId, type); + }; + + const handleTraceButtonClick = ( + trace: Trace, + insightType: InsightType, + spanCodeObjectId?: string + ) => { + props.onTraceButtonClick(trace, insightType, spanCodeObjectId); + }; + + const handleCreateJiraTicketButtonClick = (event: string) => { + sendTrackingEvent(trackingEvents.JIRA_TICKET_INFO_BUTTON_CLICKED, { + insightType: type + }); + props.onJiraTicketCreate && + props.onJiraTicketCreate(props.insight, undefined, event); + }; + + const spanName = props.insight.clientSpanName || undefined; + const spanCodeObjectId = props.insight.clientSpanCodeObjectId || undefined; + const traceId = props.insight.traceId; + + return ( + + handleTraceButtonClick( + { + name: spanName, + id: traceId + }, + props.insight.type, + spanCodeObjectId + ) + : undefined + } + content={ + +
+ Effected Endpoints ({endpoints.length}) + { + const selected = + endpoints.find( + (x) => x.endpointInfo.spanCodeObjectId === selectedOption + ) || null; + + setSelectedEndpoint(selected); + }} + options={props.insight.slowEndpoints.map((x) => { + const spanCodeObjectId = x.endpointInfo.spanCodeObjectId; + const route = trimEndpointScheme(x.endpointInfo.route); + return { + label: route, + customContent: ( + + {x.endpointInfo.serviceName} + handleSpanLinkClick(spanCodeObjectId)} + /> + + ), + value: spanCodeObjectId + }; + })} + /> +
+ {selectedEndpoint && ( + + + {roundTo( + selectedEndpoint.probabilityOfBeingBottleneck * 100, + 2 + )} + % + + + } + > + {selectedEndpoint.requestPercentage}% + + + {getDurationString( + selectedEndpoint.avgDurationWhenBeingBottleneck + )} + + + )} +
+ } + /> + ); +}; diff --git a/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/styles.ts b/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/styles.ts new file mode 100644 index 000000000..861aa220a --- /dev/null +++ b/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/styles.ts @@ -0,0 +1,8 @@ +import styled from "styled-components"; +import { footnoteRegularTypography } from "../../../../common/App/typographies"; + +export const SelectedItem = styled.div` + display: flex; + align-items: center; + ${footnoteRegularTypography} +`; diff --git a/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/types.ts b/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/types.ts new file mode 100644 index 000000000..00e15c7ff --- /dev/null +++ b/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/types.ts @@ -0,0 +1,10 @@ +import { InsightType, SpanEndpointBottleneckInsight } from "../../../types"; + +export interface SpanEndpointBottleneckEndpointsProps { + insight: SpanEndpointBottleneckInsight; + + onAssetLinkClick: ( + spanCodeObjectId: string, + insightType: InsightType + ) => void; +} diff --git a/src/components/Insights/common/insights/SpanNPlusOneInsight/index.tsx b/src/components/Insights/common/insights/SpanNPlusOneInsight/index.tsx index 62d989b72..4d9a5f7ee 100644 --- a/src/components/Insights/common/insights/SpanNPlusOneInsight/index.tsx +++ b/src/components/Insights/common/insights/SpanNPlusOneInsight/index.tsx @@ -3,10 +3,9 @@ import { getDurationString } from "../../../../../utils/getDurationString"; import { sendTrackingEvent } from "../../../../../utils/sendTrackingEvent"; import { trimEndpointScheme } from "../../../../../utils/trimEndpointScheme"; import { ConfigContext } from "../../../../common/App/ConfigContext"; -import { InfoCircleIcon } from "../../../../common/icons/InfoCircleIcon"; -import { Tooltip } from "../../../../common/v3/Tooltip"; import { trackingEvents } from "../../../tracking"; import { InsightType, Trace } from "../../../types"; +import { Info } from "../../Info"; import { InsightCard } from "../../InsightCard"; import { ColumnsContainer } from "../../InsightCard/ColumnsContainer"; import { KeyValue } from "../../InsightCard/KeyValue"; @@ -108,14 +107,10 @@ export const SpanNPlusOneInsight = (props: SpanNPlusOneInsightProps) => { - -
Requests
- -
- + } > {selectedEndpoint.requestPercentage}% diff --git a/src/components/Insights/types.ts b/src/components/Insights/types.ts index 247f9e21c..27554b05a 100644 --- a/src/components/Insights/types.ts +++ b/src/components/Insights/types.ts @@ -444,6 +444,7 @@ export interface EndpointBottleneckInsight extends EndpointInsight { avgDurationWhenBeingBottleneck: Duration; criticality: number; ticketLink: string | null; + requestPercentage: number; /** * @deprecated From a7ef48b170c20f878ea754872846556fb9edd396 Mon Sep 17 00:00:00 2001 From: olehp Date: Thu, 29 Feb 2024 17:21:31 +0200 Subject: [PATCH 04/56] bottleneck --- .../insights/EndpointBottleneckInsight/index.tsx | 6 +++++- .../SpanEndpointBottleneckInsight/index.tsx | 16 ++++++++++++++++ .../SpanEndpointBottleneckInsight/types.ts | 8 ++++++-- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/components/Insights/common/insights/EndpointBottleneckInsight/index.tsx b/src/components/Insights/common/insights/EndpointBottleneckInsight/index.tsx index 287824eaa..70515080d 100644 --- a/src/components/Insights/common/insights/EndpointBottleneckInsight/index.tsx +++ b/src/components/Insights/common/insights/EndpointBottleneckInsight/index.tsx @@ -14,7 +14,7 @@ export const EndpointBottleneckInsight = ( props: EndpointBottleneckInsightProps ) => { const { insight } = props; - const { span } = insight; + const { span, ticketLink } = insight; const handleSpanLinkClick = (spanCodeObjectId: string) => { props.onAssetLinkClick(spanCodeObjectId, insight.type); @@ -37,6 +37,10 @@ export const EndpointBottleneckInsight = ( return (
diff --git a/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/index.tsx b/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/index.tsx index 586d88f0f..22190bdef 100644 --- a/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/index.tsx +++ b/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/index.tsx @@ -1,7 +1,9 @@ import { useState } from "react"; import { getDurationString } from "../../../../../utils/getDurationString"; import { roundTo } from "../../../../../utils/roundTo"; +import { sendTrackingEvent } from "../../../../../utils/sendTrackingEvent"; import { trimEndpointScheme } from "../../../../../utils/trimEndpointScheme"; +import { trackingEvents } from "../../../tracking"; import { Info } from "../../Info"; import { InsightCard } from "../../InsightCard"; import { ColumnsContainer } from "../../InsightCard/ColumnsContainer"; @@ -24,6 +26,14 @@ export const SpanBottleneckEndpoints = ( props.onAssetLinkClick(spanCodeObjectId, props?.insight.type); }; + const handleCreateJiraTicketButtonClick = (event: string) => { + sendTrackingEvent(trackingEvents.JIRA_TICKET_INFO_BUTTON_CLICKED, { + insightType: props.insight.type + }); + props.onJiraTicketCreate && + props.onJiraTicketCreate(props.insight, undefined, event); + }; + const endpoints = props.insight.slowEndpoints; if (endpoints.length === 0) { @@ -33,6 +43,12 @@ export const SpanBottleneckEndpoints = ( return (
diff --git a/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/types.ts b/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/types.ts index 00e15c7ff..c227559b4 100644 --- a/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/types.ts +++ b/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/types.ts @@ -1,6 +1,10 @@ -import { InsightType, SpanEndpointBottleneckInsight } from "../../../types"; +import { + InsightProps, + InsightType, + SpanEndpointBottleneckInsight +} from "../../../types"; -export interface SpanEndpointBottleneckEndpointsProps { +export interface SpanEndpointBottleneckEndpointsProps extends InsightProps { insight: SpanEndpointBottleneckInsight; onAssetLinkClick: ( From e93e8ddd6b8b56dcc4bad10bd21192c243a7484e Mon Sep 17 00:00:00 2001 From: olehp Date: Thu, 29 Feb 2024 17:23:02 +0200 Subject: [PATCH 05/56] fix comments --- src/components/common/v3/JiraButton/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/common/v3/JiraButton/index.tsx b/src/components/common/v3/JiraButton/index.tsx index 9a1f1e454..cd3dcbbe5 100644 --- a/src/components/common/v3/JiraButton/index.tsx +++ b/src/components/common/v3/JiraButton/index.tsx @@ -42,13 +42,13 @@ export const JiraButton = (props: JiraButtonProps) => { { icon: , label: "View", - id: ticketLink, + id: "view", onClick: handleViewButtonClick }, { icon: , label: "Edit", - id: props.spanCodeObjectId ?? "", + id: "edit", onClick: () => openTicketInfo("edit menu item click") } ]} From 5670212c3aaca62e1671698867edfb7041c3c026 Mon Sep 17 00:00:00 2001 From: olehp Date: Thu, 29 Feb 2024 17:38:42 +0200 Subject: [PATCH 06/56] fix comments --- .../EndpointBottleneckInsight/index.tsx | 3 +- .../SpanEndpointBottleneckInsight/index.tsx | 47 +++++---- .../insights/SpanNPlusOneInsight/index.tsx | 48 ++++++---- src/components/Insights/types.ts | 96 ++++++++++--------- 4 files changed, 110 insertions(+), 84 deletions(-) diff --git a/src/components/Insights/common/insights/EndpointBottleneckInsight/index.tsx b/src/components/Insights/common/insights/EndpointBottleneckInsight/index.tsx index 70515080d..4077bdb3f 100644 --- a/src/components/Insights/common/insights/EndpointBottleneckInsight/index.tsx +++ b/src/components/Insights/common/insights/EndpointBottleneckInsight/index.tsx @@ -39,7 +39,8 @@ export const EndpointBottleneckInsight = ( insight={insight} jiraTicketInfo={{ isHintEnabled: props.isJiraHintEnabled, - spanCodeObjectId: props.insight.spanInfo?.spanCodeObjectId + spanCodeObjectId: props.insight.spanInfo?.spanCodeObjectId, + ticketLink }} content={ diff --git a/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/index.tsx b/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/index.tsx index 22190bdef..bdf1bff0b 100644 --- a/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/index.tsx +++ b/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/index.tsx @@ -1,9 +1,10 @@ -import { useState } from "react"; +import { ReactNode, useState } from "react"; import { getDurationString } from "../../../../../utils/getDurationString"; import { roundTo } from "../../../../../utils/roundTo"; import { sendTrackingEvent } from "../../../../../utils/sendTrackingEvent"; import { trimEndpointScheme } from "../../../../../utils/trimEndpointScheme"; import { trackingEvents } from "../../../tracking"; +import { BottleneckEndpointInfo } from "../../../types"; import { Info } from "../../Info"; import { InsightCard } from "../../InsightCard"; import { ColumnsContainer } from "../../InsightCard/ColumnsContainer"; @@ -14,6 +15,29 @@ import { ContentContainer, Description, Details } from "../styles"; import * as s from "./styles"; import { SpanEndpointBottleneckEndpointsProps } from "./types"; +const renderOptions = ( + endpoints: BottleneckEndpointInfo[], + handleLinkClick: (spanCodeObjectId?: string) => void +): { label: string; customContent: ReactNode; value: string }[] => { + return endpoints.map((x) => { + const spanCodeObjectId = x.endpointInfo.spanCodeObjectId; + const route = trimEndpointScheme(x.endpointInfo.route); + return { + label: route, + customContent: ( + + {x.endpointInfo.serviceName} + handleLinkClick(spanCodeObjectId)} + /> + + ), + value: spanCodeObjectId + }; + }); +}; + export const SpanBottleneckEndpoints = ( props: SpanEndpointBottleneckEndpointsProps ) => { @@ -63,23 +87,10 @@ export const SpanBottleneckEndpoints = ( setSelectedEndpoint(selected); }} - options={props.insight.slowEndpoints.map((x) => { - const spanCodeObjectId = x.endpointInfo.spanCodeObjectId; - const route = trimEndpointScheme(x.endpointInfo.route); - return { - label: route, - customContent: ( - - {x.endpointInfo.serviceName} - handleSpanLinkClick(spanCodeObjectId)} - /> - - ), - value: spanCodeObjectId - }; - })} + options={renderOptions( + props.insight.slowEndpoints, + handleSpanLinkClick + )} />
{selectedEndpoint && ( diff --git a/src/components/Insights/common/insights/SpanNPlusOneInsight/index.tsx b/src/components/Insights/common/insights/SpanNPlusOneInsight/index.tsx index 4d9a5f7ee..d4831692c 100644 --- a/src/components/Insights/common/insights/SpanNPlusOneInsight/index.tsx +++ b/src/components/Insights/common/insights/SpanNPlusOneInsight/index.tsx @@ -1,10 +1,10 @@ -import { useContext, useState } from "react"; +import { ReactNode, useContext, useState } from "react"; import { getDurationString } from "../../../../../utils/getDurationString"; import { sendTrackingEvent } from "../../../../../utils/sendTrackingEvent"; import { trimEndpointScheme } from "../../../../../utils/trimEndpointScheme"; import { ConfigContext } from "../../../../common/App/ConfigContext"; import { trackingEvents } from "../../../tracking"; -import { InsightType, Trace } from "../../../types"; +import { InsightType, NPlusOneEndpointInfo, Trace } from "../../../types"; import { Info } from "../../Info"; import { InsightCard } from "../../InsightCard"; import { ColumnsContainer } from "../../InsightCard/ColumnsContainer"; @@ -15,6 +15,29 @@ import { ContentContainer, Description, Details } from "../styles"; import * as s from "./styles"; import { SpanNPlusOneInsightProps } from "./types"; +const renderOptions = ( + endpoints: NPlusOneEndpointInfo[], + handleLinkClick: (spanCodeObjectId?: string) => void +): { label: string; customContent: ReactNode; value: string }[] => { + return endpoints.map((x) => { + const spanCodeObjectId = x.endpointInfo.entrySpanCodeObjectId; + const route = trimEndpointScheme(x.endpointInfo.route); + return { + label: route, + customContent: ( + + {x.endpointInfo.serviceName} + handleLinkClick(spanCodeObjectId)} + /> + + ), + value: spanCodeObjectId + }; + }); +}; + export const SpanNPlusOneInsight = (props: SpanNPlusOneInsightProps) => { const { insight: { type, endpoints, ticketLink } @@ -80,23 +103,10 @@ export const SpanNPlusOneInsight = (props: SpanNPlusOneInsightProps) => { setSelectedEndpoint(selected); }} - options={props.insight.endpoints.map((x) => { - const spanCodeObjectId = x.endpointInfo.entrySpanCodeObjectId; - const route = trimEndpointScheme(x.endpointInfo.route); - return { - label: route, - customContent: ( - - {x.endpointInfo.serviceName} - handleSpanLinkClick(spanCodeObjectId)} - /> - - ), - value: spanCodeObjectId - }; - })} + options={renderOptions( + props.insight.endpoints, + handleSpanLinkClick + )} />
diff --git a/src/components/Insights/types.ts b/src/components/Insights/types.ts index 27554b05a..7abbee0fb 100644 --- a/src/components/Insights/types.ts +++ b/src/components/Insights/types.ts @@ -268,41 +268,43 @@ interface Percentile { maxDuration: Duration; } +export interface BottleneckEndpointInfo { + endpointInfo: { + route: string; + instrumentationLibrary: string; + serviceName: string; + codeObjectId: string; + spanCodeObjectId: string; + spanName: string; + }; + probabilityOfBeingBottleneck: number; + avgDurationWhenBeingBottleneck: Duration; + impact: number; + severity: number; + criticality: number; + requestPercentage: number; + + /** + * @deprecated + */ + p50: Percentile; + /** + * @deprecated + */ + p95: Percentile; + /** + * @deprecated + */ + p99: Percentile; +} + export interface SpanEndpointBottleneckInsight extends SpanInsight { name: "Bottleneck"; type: InsightType.SpanEndpointBottleneck; category: InsightCategory.Performance; specifity: InsightSpecificity.TargetFound; importance: InsightImportance.Critical; - slowEndpoints: { - endpointInfo: { - route: string; - instrumentationLibrary: string; - serviceName: string; - codeObjectId: string; - spanCodeObjectId: string; - spanName: string; - }; - probabilityOfBeingBottleneck: number; - avgDurationWhenBeingBottleneck: Duration; - impact: number; - severity: number; - criticality: number; - requestPercentage: number; - - /** - * @deprecated - */ - p50: Percentile; - /** - * @deprecated - */ - p95: Percentile; - /** - * @deprecated - */ - p99: Percentile; - }[]; + slowEndpoints: BottleneckEndpointInfo[]; /** * @deprecated @@ -539,6 +541,24 @@ export interface SpanScalingBadlyInsight extends SpanInsight { spanInstrumentationLibrary: string; } +export interface NPlusOneEndpointInfo { + endpointInfo: { + route: string; + instrumentationLibrary: string; + spanCodeObjectId: string; + entrySpanCodeObjectId: string; + serviceName: string; + }; + occurrences: number; + criticality: number; + impact: number; + severity: number; + traceId: string; + duration: Duration; + commitId: string; + requestPercentage: number; +} + export interface SpanNPlusOneInsight extends SpanInsight { name: "N+1"; type: InsightType.SpanNPlusOne; @@ -550,23 +570,7 @@ export interface SpanNPlusOneInsight extends SpanInsight { clientSpanName: string | null; clientSpanCodeObjectId: string | null; duration: Duration; - endpoints: { - endpointInfo: { - route: string; - instrumentationLibrary: string; - spanCodeObjectId: string; - entrySpanCodeObjectId: string; - serviceName: string; - }; - occurrences: number; - criticality: number; - impact: number; - severity: number; - traceId: string; - duration: Duration; - commitId: string; - requestPercentage: number; - }[]; + endpoints: NPlusOneEndpointInfo[]; /** * @deprecated From a5d45f414ca68e011e87320f9e13980b6614eb4b Mon Sep 17 00:00:00 2001 From: Kyrylo Shmidt Date: Thu, 29 Feb 2024 17:18:26 +0100 Subject: [PATCH 07/56] Add request breakdown insight --- .../ExcessiveAPICallsInsight/index.tsx | 32 +-- .../InsightHeader/AsyncTag/styles.ts | 4 +- .../PercentileViewModeToggle.stories.tsx | 22 ++ .../PercentileViewModeToggle/index.tsx | 17 ++ .../PercentileViewModeToggle/types.ts | 4 + .../Insights/common/InsightCard/index.tsx | 58 +++-- .../ReferenceLineLabel/index.tsx | 15 +- .../DurationInsight/XAxisTick/index.tsx | 16 +- .../insights/DurationInsight/constants.ts | 2 +- .../common/insights/DurationInsight/index.tsx | 16 +- .../RequestBreakdownInsight.stories.tsx | 217 ++++++++++++++++ .../RequestBreakdownInsight/index.tsx | 240 ++++++++++++++++++ .../RequestBreakdownInsight/styles.ts | 134 ++++++++++ .../insights/RequestBreakdownInsight/types.ts | 16 ++ src/components/common/App/themes/darkTheme.ts | 2 + .../common/App/themes/lightTheme.ts | 2 + src/components/common/v3/Button/styles.ts | 11 +- src/components/common/v3/Toggle/index.tsx | 22 ++ src/components/common/v3/Toggle/styles.ts | 29 +++ src/components/common/v3/Toggle/types.ts | 16 ++ src/styled.d.ts | 14 +- 21 files changed, 811 insertions(+), 78 deletions(-) create mode 100644 src/components/Insights/common/InsightCard/PercentileViewModeToggle/PercentileViewModeToggle.stories.tsx create mode 100644 src/components/Insights/common/InsightCard/PercentileViewModeToggle/index.tsx create mode 100644 src/components/Insights/common/InsightCard/PercentileViewModeToggle/types.ts create mode 100644 src/components/Insights/common/insights/RequestBreakdownInsight/RequestBreakdownInsight.stories.tsx create mode 100644 src/components/Insights/common/insights/RequestBreakdownInsight/index.tsx create mode 100644 src/components/Insights/common/insights/RequestBreakdownInsight/styles.ts create mode 100644 src/components/Insights/common/insights/RequestBreakdownInsight/types.ts create mode 100644 src/components/common/v3/Toggle/index.tsx create mode 100644 src/components/common/v3/Toggle/styles.ts create mode 100644 src/components/common/v3/Toggle/types.ts diff --git a/src/components/Insights/ExcessiveAPICallsInsight/index.tsx b/src/components/Insights/ExcessiveAPICallsInsight/index.tsx index e46a9d90e..a4addf574 100644 --- a/src/components/Insights/ExcessiveAPICallsInsight/index.tsx +++ b/src/components/Insights/ExcessiveAPICallsInsight/index.tsx @@ -62,21 +62,23 @@ export const ExcessiveAPICallsInsight = ( {config.isJaegerEnabled && traceId && ( - - handleTraceButtonClick( - { - name: spanName, - id: traceId - }, - props.insight.type, - spanCodeObjectId - ) - } - > - Trace - + + + handleTraceButtonClick( + { + name: spanName, + id: traceId + }, + props.insight.type, + spanCodeObjectId + ) + } + > + Trace + + )} ); diff --git a/src/components/Insights/common/InsightCard/InsightHeader/AsyncTag/styles.ts b/src/components/Insights/common/InsightCard/InsightHeader/AsyncTag/styles.ts index c557d044a..d5c972b9d 100644 --- a/src/components/Insights/common/InsightCard/InsightHeader/AsyncTag/styles.ts +++ b/src/components/Insights/common/InsightCard/InsightHeader/AsyncTag/styles.ts @@ -1,8 +1,10 @@ import styled from "styled-components"; +import { footnoteRegularTypography } from "../../../../../common/App/typographies"; import { Tag as TagCommon } from "../../../../../common/v3/Tag"; export const AsyncTag = styled(TagCommon)` + ${footnoteRegularTypography} + color: ${({ theme }) => theme.colors.v3.text.primary}; background: ${({ theme }) => theme.colors.v3.surface.brandDark}; - font-size: 12px; `; diff --git a/src/components/Insights/common/InsightCard/PercentileViewModeToggle/PercentileViewModeToggle.stories.tsx b/src/components/Insights/common/InsightCard/PercentileViewModeToggle/PercentileViewModeToggle.stories.tsx new file mode 100644 index 000000000..5ffc91ca4 --- /dev/null +++ b/src/components/Insights/common/InsightCard/PercentileViewModeToggle/PercentileViewModeToggle.stories.tsx @@ -0,0 +1,22 @@ +import { Meta, StoryObj } from "@storybook/react"; +import { PercentileViewModeToggle } 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/PercentileViewModeToggle", + component: PercentileViewModeToggle, + 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 Default: Story = { + args: { + viewMode: 0.5 + } +}; diff --git a/src/components/Insights/common/InsightCard/PercentileViewModeToggle/index.tsx b/src/components/Insights/common/InsightCard/PercentileViewModeToggle/index.tsx new file mode 100644 index 000000000..20a22c17b --- /dev/null +++ b/src/components/Insights/common/InsightCard/PercentileViewModeToggle/index.tsx @@ -0,0 +1,17 @@ +import { PERCENTILES } from "../../../../../constants"; +import { Toggle } from "../../../../common/v3/Toggle"; +import { PercentileViewModeToggleProps } from "./types"; + +export const PercentileViewModeToggle = ({ + viewMode, + onChange +}: PercentileViewModeToggleProps) => ( + + options={PERCENTILES.map((percentile) => ({ + value: percentile.percentile, + label: percentile.label + }))} + value={viewMode} + onValueChange={onChange} + /> +); diff --git a/src/components/Insights/common/InsightCard/PercentileViewModeToggle/types.ts b/src/components/Insights/common/InsightCard/PercentileViewModeToggle/types.ts new file mode 100644 index 000000000..5ae5f64d3 --- /dev/null +++ b/src/components/Insights/common/InsightCard/PercentileViewModeToggle/types.ts @@ -0,0 +1,4 @@ +export interface PercentileViewModeToggleProps { + viewMode: number; + onChange: (viewMode: number) => void; +} diff --git a/src/components/Insights/common/InsightCard/index.tsx b/src/components/Insights/common/InsightCard/index.tsx index 1a8033724..28592a6a6 100644 --- a/src/components/Insights/common/InsightCard/index.tsx +++ b/src/components/Insights/common/InsightCard/index.tsx @@ -122,40 +122,50 @@ export const InsightCard = (props: InsightCardProps) => { {/* + ); + } + return ( + + + handleLinkClick(spanCodeObjectId)} + buttons={buttons} + /> + + + ); + })} + + ); + } + }; + + return ( + + + {props.insight.shortDisplayInfo.description} + + + + {props.insight.maxConcurrency} + + + {getDurationString(props.insight.minDuration)} -{" "} + {getDurationString(props.insight.maxDuration)} + + + {renderRootCause(props.insight.rootCauseSpans)} + {props.insight.affectedEndpoints.length > 0 && ( + + Affected endpoints: + {props.insight.affectedEndpoints.length > 0 && + pageItems.map((endpoint) => { + const endpointRoute = trimEndpointScheme(endpoint.route); + return ( + + + handleLinkClick(endpoint.spanCodeObjectId) + } + name={endpointRoute} + /> + + ); + })} + + + )} + + } + jiraTicketInfo={{ + ticketLink: props.insight.ticketLink, + isHintEnabled: props.isJiraHintEnabled, + spanCodeObjectId: props.insight.spanInfo?.spanCodeObjectId + }} + onJiraButtonClick={ + props.insight.rootCauseSpans.length == 0 + ? handleCreateJiraTicketButtonClick + : undefined + } + onOpenHistogram={ + props.insight.spanInfo ? props.onHistogramButtonClick : undefined + } + onRecalculate={props.onRecalculate} + onRefresh={props.onRefresh} + /> + ); +}; diff --git a/src/components/Insights/common/insights/ScalingIssueInsight/mockData.ts b/src/components/Insights/common/insights/ScalingIssueInsight/mockData.ts new file mode 100644 index 000000000..9b368dfc1 --- /dev/null +++ b/src/components/Insights/common/insights/ScalingIssueInsight/mockData.ts @@ -0,0 +1,183 @@ +import { + InsightCategory, + InsightScope, + InsightType, + SpanScalingBadlyInsight +} from "../../../types"; + +export const mockedSpanScalingInsight: SpanScalingBadlyInsight = { + sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId", + id: "90b55792-8262-4c5d-9628-7cce7979ad6d", + firstDetected: "2023-12-05T17:25:47.010Z", + lastDetected: "2024-01-05T13:14:47.010Z", + criticality: 0, + firstCommitId: "b3f7b3f", + lastCommitId: "a1b2c3d", + deactivatedCommitId: null, + reopenCount: 0, + ticketLink: null, + impact: 0, + name: "Scaling Issue Found", + type: InsightType.SpanScalingBadly, + category: InsightCategory.Performance, + specifity: 4, + importance: 2, + spanName: "WaitForLock", + spanInstrumentationLibrary: "SampleInsightsController", + turningPointConcurrency: 17, + maxConcurrency: 24, + minDuration: { + value: 100.67, + unit: "ms", + raw: 100671312.5 + }, + maxDuration: { + value: 7.22, + unit: "sec", + raw: 7222044625 + }, + rootCauseSpans: [], + affectedEndpoints: [], + scope: InsightScope.Span, + spanInfo: { + name: "WaitForLock", + displayName: "WaitForLock", + instrumentationLibrary: "SampleInsightsController", + spanCodeObjectId: "span:SampleInsightsController$_$WaitForLock", + methodCodeObjectId: null, + kind: "Internal", + codeObjectId: null + }, + shortDisplayInfo: { + title: "Scaling Issue Found", + targetDisplayName: "", + subtitle: "", + description: "Significant performance degradation at 17 executions/second" + }, + codeObjectId: "SampleInsightsController$_$WaitForLock", + decorators: [ + { + title: "Scaling badly", + description: + "This code experiences exponential grows in duration after 17 concurrent executions" + } + ], + environment: "BOB-LAPTOP[LOCAL]", + severity: 0, + isRecalculateEnabled: false, + prefixedCodeObjectId: "span:SampleInsightsController$_$WaitForLock", + customStartTime: null, + actualStartTime: "2023-06-24T00:00:00.000Z", + flowHash: null +}; + +export const ofEndpoint = { + codeObjectId: "SampleInsightsController$_$GetUsers", + spanInfo: { + name: "GetUsers", + displayName: "GetUsers", + instrumentationLibrary: "SampleInsightsController", + spanCodeObjectId: "span:SampleInsightsController$_$GetUsers", + methodCodeObjectId: null, + kind: "Server", + codeObjectId: null + } +}; + +export const ofDbSpan = { + codeObjectId: "UsersStorageService$_$QueryUsers", + spanInfo: { + name: "QueryUsers", + displayName: "QueryUsers", + instrumentationLibrary: "UsersStorageService", + spanCodeObjectId: "span:UsersStorageService$_$QueryUsers", + methodCodeObjectId: null, + kind: "Internal", + codeObjectId: null + } +}; + +export const withAffectedEndpoints = { + affectedEndpoints: [ + { + route: "epHTTP:HTTP GET SampleInsights/lock/{milisec}1", + serviceName: "Sample.MoneyTransfer.API", + sampleTraceId: "3E41E4197B696CA9BF1157AEB254DFE0", + flowHash: "2C8EE08C75056058690249E52382F5", + name: "HTTP GET SampleInsights/lock/{milisec}1", + displayName: "HTTP GET SampleInsights/lock/{milisec}1", + instrumentationLibrary: "OpenTelemetry.Instrumentation.AspNetCore", + spanCodeObjectId: + "span:OpenTelemetry.Instrumentation.AspNetCore$_$HTTP GET SampleInsights/lock/{milisec}", + methodCodeObjectId: + "Sample.MoneyTransfer.API.Controllers.SampleInsightsController$_$Lock(Double)", + kind: "Server", + codeObjectId: + "Sample.MoneyTransfer.API.Controllers.SampleInsightsController$_$Lock(Double)" + }, + { + route: "epHTTP:HTTP GET SampleInsights/lock/{milisec}2", + serviceName: "Sample.MoneyTransfer.API", + sampleTraceId: "3E41E4197B696CA9BF1157AEB254DFEd0dd", + flowHash: "2C8EE08C75056058690249E52382F5", + name: "HTTP GET SampleInsights/lock/{milisec}2", + displayName: "HTTP GET SampleInsights/lock/{milisec}2", + instrumentationLibrary: "OpenTelemetry.Instrumentation.AspNetCore", + spanCodeObjectId: + "span:OpenTelemetry.Instrumentation.AspNetCore$_$HTTP GET SampleInsights/lock/{milisec}2", + methodCodeObjectId: + "Sample.MoneyTransfer.API.Controllers.SampleInsightsController$_$Lock(Double)", + kind: "Server", + codeObjectId: + "Sample.MoneyTransfer.API.Controllers.SampleInsightsController$_$Lock(Double)" + }, + { + route: "epHTTP:HTTP GET SampleInsights/lock/{milisec}3", + serviceName: "Sample.MoneyTransfer.API", + sampleTraceId: "3E41E4197B696CA9BF1157AEB254DFE02", + flowHash: "2C8EE08C75056058690249E52382F5", + name: "HTTP GET SampleInsights/lock/{milisec}3", + displayName: "HTTP GET SampleInsights/lock/{milisec}3", + instrumentationLibrary: "OpenTelemetry.Instrumentation.AspNetCore", + spanCodeObjectId: + "span:OpenTelemetry.Instrumentation.AspNetCore$_$HTTP GET SampleInsights/lock/{milisec}3", + methodCodeObjectId: + "Sample.MoneyTransfer.API.Controllers.SampleInsightsController$_$Lock(Double)", + kind: "Server", + codeObjectId: + "Sample.MoneyTransfer.API.Controllers.SampleInsightsController$_$Lock(Double)" + }, + { + route: "epHTTP:HTTP GET SampleInsights/lock/{milisec}4", + serviceName: "Sample.MoneyTransfer.API", + sampleTraceId: "3E41E4197B696CA9BF1157AEB254DFE0", + flowHash: "2C8EE08C75056058690249E52382F5", + name: "HTTP GET SampleInsights/lock/{milisec}", + displayName: "HTTP GET SampleInsights/lock/{milisec}", + instrumentationLibrary: "OpenTelemetry.Instrumentation.AspNetCore", + spanCodeObjectId: + "span:OpenTelemetry.Instrumentation.AspNetCore$_$HTTP GET SampleInsights/lock/{milisec}4", + methodCodeObjectId: + "Sample.MoneyTransfer.API.Controllers.SampleInsightsController$_$Lock(Double)", + kind: "Server", + codeObjectId: + "Sample.MoneyTransfer.API.Controllers.SampleInsightsController$_$Lock(Double)" + } + ] +}; + +export const withRootCause = { + rootCauseSpans: [ + { + instrumentationLibrary: "io.opentelemetry.somedb-10.0", + name: "fc3425f345f4", + displayName: "SELECT * FROM users", + sampleTraceId: "3E41E4197B696CA9BF1157AEB254DFE0", + spanCodeObjectId: "span:io.opentelemetry.somedb-10.0$_$fc3425f345f4", + kind: "Client", + methodCodeObjectId: null, + flowHash: "2C8EE08C75056058690249E52382F5", + codeObjectId: null + } + ] +}; diff --git a/src/components/Insights/common/insights/ScalingIssueInsight/styles.ts b/src/components/Insights/common/insights/ScalingIssueInsight/styles.ts new file mode 100644 index 000000000..1c4a04419 --- /dev/null +++ b/src/components/Insights/common/insights/ScalingIssueInsight/styles.ts @@ -0,0 +1,23 @@ +import styled from "styled-components"; +import { footnoteRegularTypography } from "../../../../common/App/typographies"; +import { ListItem } from "../../InsightCard/ListItem"; + +export const InsightDescription = styled.span` + ${footnoteRegularTypography} +`; + +export const List = styled.div` + display: flex; + flex-direction: column; + gap: 4px; +`; + +export const RootCause = styled.div` + align-items: center; + justify-content: space-between; + gap: 4px; +`; + +export const EndpointListItem = styled(ListItem)` + padding: 4px 0; +`; diff --git a/src/components/Insights/common/insights/ScalingIssueInsight/types.ts b/src/components/Insights/common/insights/ScalingIssueInsight/types.ts new file mode 100644 index 000000000..8dd33ce69 --- /dev/null +++ b/src/components/Insights/common/insights/ScalingIssueInsight/types.ts @@ -0,0 +1,25 @@ +import { + InsightProps, + InsightType, + SpanScalingBadlyInsight, + Trace +} from "../../../types"; + +export interface ScalingIssueInsightProps extends InsightProps { + insight: SpanScalingBadlyInsight; + onAssetLinkClick: ( + spanCodeObjectId: string, + insightType: InsightType + ) => void; + onTraceButtonClick: ( + trace: Trace, + insightType: InsightType, + spanCodeObjectId: string + ) => void; + onHistogramButtonClick: ( + instrumentationLibrary: string, + name: string, + insightType: InsightType, + displayName: string + ) => void; +} From 6a25f23ece98a1fcd21931b4fac351c362461074 Mon Sep 17 00:00:00 2001 From: Kyrylo Shmidt <119138536+kshmidt-digma@users.noreply.github.com> Date: Fri, 1 Mar 2024 12:57:29 +0100 Subject: [PATCH 13/56] Add Top Usage Insight (#571) * Add Top Usage insight * Update insight card --- .../Insights/InsightsPage/index.tsx | 2 +- .../PerformanceAtScaleInsight/styles.ts | 6 +- .../RequestBreakdownInsight/styles.ts | 4 +- .../Insights/common/InsightCard/index.tsx | 2 +- .../RequestBreakdownInsight/styles.ts | 4 +- .../insights/SessionInViewInsight/index.tsx | 31 +-- .../insights/SpanNPlusOneInsight/index.tsx | 2 +- .../TopUsageInsight.stories.tsx | 113 ++++++++ .../common/insights/TopUsageInsight/index.tsx | 255 ++++++++++++++++++ .../common/insights/TopUsageInsight/styles.ts | 108 ++++++++ .../common/insights/TopUsageInsight/types.ts | 24 ++ .../common/icons/ArrowDashedLineIcon.tsx | 35 +++ src/components/common/v3/Button/styles.ts | 8 +- src/components/common/v3/JiraButton/index.tsx | 80 +++--- src/components/common/v3/Tooltip/index.tsx | 2 +- src/components/common/v3/Tooltip/styles.ts | 5 +- src/components/common/v3/Tooltip/types.ts | 5 + 17 files changed, 619 insertions(+), 67 deletions(-) create mode 100644 src/components/Insights/common/insights/TopUsageInsight/TopUsageInsight.stories.tsx create mode 100644 src/components/Insights/common/insights/TopUsageInsight/index.tsx create mode 100644 src/components/Insights/common/insights/TopUsageInsight/styles.ts create mode 100644 src/components/Insights/common/insights/TopUsageInsight/types.ts create mode 100644 src/components/common/icons/ArrowDashedLineIcon.tsx diff --git a/src/components/Insights/InsightsPage/index.tsx b/src/components/Insights/InsightsPage/index.tsx index c2cec787c..ff03e4683 100644 --- a/src/components/Insights/InsightsPage/index.tsx +++ b/src/components/Insights/InsightsPage/index.tsx @@ -14,7 +14,6 @@ import { CardsIcon } from "../../common/icons/CardsIcon"; import { DurationBreakdownInsight } from "../DurationBreakdownInsight"; import { EndpointQueryOptimizationInsight } from "../EndpointQueryOptimizationInsight"; import { QueryOptimizationInsight } from "../QueryOptimizationInsight"; -import { TopUsageInsight } from "../TopUsageInsight"; import { actions } from "../actions"; import { DurationInsight } from "../common/insights/DurationInsight"; import { EndpointBottleneckInsight } from "../common/insights/EndpointBottleneckInsight"; @@ -29,6 +28,7 @@ import { SlowEndpointInsight } from "../common/insights/SlowEndpointInsight"; import { SpanEndpointBottleneckInsight } from "../common/insights/SpanEndpointBottleneckInsight"; import { SpanNPlusOneInsight } from "../common/insights/SpanNPlusOneInsight"; import { SpanNexusInsight } from "../common/insights/SpanNexusInsight"; +import { TopUsageInsight } from "../common/insights/TopUsageInsight"; import { TrafficInsight } from "../common/insights/TrafficInsight"; import { Description } from "../styles"; import { trackingEvents } from "../tracking"; diff --git a/src/components/Insights/PerformanceAtScaleInsight/styles.ts b/src/components/Insights/PerformanceAtScaleInsight/styles.ts index ad206066f..d260f5cc7 100644 --- a/src/components/Insights/PerformanceAtScaleInsight/styles.ts +++ b/src/components/Insights/PerformanceAtScaleInsight/styles.ts @@ -44,7 +44,7 @@ export const TableHeaderCell = styled.th` padding: 0; &:last-child { - text-align: right; + text-align: end; } `; @@ -57,11 +57,11 @@ export const TableBodyCell = styled.td` padding: 0; &:first-child { - text-align: left; + text-align: start; } &:last-child { - text-align: right; + text-align: end; } `; diff --git a/src/components/Insights/RequestBreakdownInsight/styles.ts b/src/components/Insights/RequestBreakdownInsight/styles.ts index d03eb11ed..976306801 100644 --- a/src/components/Insights/RequestBreakdownInsight/styles.ts +++ b/src/components/Insights/RequestBreakdownInsight/styles.ts @@ -97,7 +97,7 @@ export const TableHead = styled.thead` `; export const TableHeaderCell = styled.th` - text-align: left; + text-align: start; font-weight: 400; padding-left: 4px; padding-bottom: 8px; @@ -128,7 +128,7 @@ export const TableBodyCell = styled.td` &:last-child { padding: 4px 4px 4px 22px; - text-align: right; + text-align: end; } `; diff --git a/src/components/Insights/common/InsightCard/index.tsx b/src/components/Insights/common/InsightCard/index.tsx index 98b1a4a9e..05102e3a0 100644 --- a/src/components/Insights/common/InsightCard/index.tsx +++ b/src/components/Insights/common/InsightCard/index.tsx @@ -139,7 +139,7 @@ export const InsightCard = (props: InsightCardProps) => { )} {props.onJiraButtonClick && ( - + { const buttons = traceId && config.isJaegerEnabled ? [ - + /> ); } return ( - - - handleLinkClick(spanCodeObjectId)} - buttons={buttons} - /> - - + handleLinkClick(spanCodeObjectId)} + buttons={buttons} + /> ); })} @@ -132,15 +127,11 @@ export const ScalingIssueInsight = (props: ScalingIssueInsightProps) => { pageItems.map((endpoint) => { const endpointRoute = trimEndpointScheme(endpoint.route); return ( - - - handleLinkClick(endpoint.spanCodeObjectId) - } - name={endpointRoute} - /> - + handleLinkClick(endpoint.spanCodeObjectId)} + name={endpointRoute} + /> ); })} void -): { label: string; customContent: ReactNode; value: string }[] => { - return endpoints.map((x) => { +): { label: string; customContent: ReactNode; value: string }[] => + endpoints.map((x) => { const spanCodeObjectId = x.endpointInfo.spanCodeObjectId; const route = trimEndpointScheme(x.endpointInfo.route); return { @@ -27,17 +28,16 @@ const renderOptions = ( customContent: ( {x.endpointInfo.serviceName} - handleLinkClick(spanCodeObjectId)} - /> + + handleLinkClick(spanCodeObjectId)}> + {route} + + ), value: spanCodeObjectId }; }); -}; - export const SpanEndpointBottleneckInsight = ( props: SpanEndpointBottleneckInsightProps ) => { diff --git a/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/styles.ts b/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/styles.ts index 861aa220a..e8728151d 100644 --- a/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/styles.ts +++ b/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/styles.ts @@ -2,7 +2,9 @@ import styled from "styled-components"; import { footnoteRegularTypography } from "../../../../common/App/typographies"; export const SelectedItem = styled.div` + ${footnoteRegularTypography} + display: flex; + gap: 4px; align-items: center; - ${footnoteRegularTypography} `; diff --git a/src/components/Insights/common/insights/SpanNPlusOneInsight/index.tsx b/src/components/Insights/common/insights/SpanNPlusOneInsight/index.tsx index e6a274292..0e35409cd 100644 --- a/src/components/Insights/common/insights/SpanNPlusOneInsight/index.tsx +++ b/src/components/Insights/common/insights/SpanNPlusOneInsight/index.tsx @@ -3,13 +3,14 @@ import { getDurationString } from "../../../../../utils/getDurationString"; import { sendTrackingEvent } from "../../../../../utils/sendTrackingEvent"; import { trimEndpointScheme } from "../../../../../utils/trimEndpointScheme"; import { ConfigContext } from "../../../../common/App/ConfigContext"; +import { Link } from "../../../../common/v3/Link"; +import { Tooltip } from "../../../../common/v3/Tooltip"; import { trackingEvents } from "../../../tracking"; import { InsightType, NPlusOneEndpointInfo, Trace } from "../../../types"; import { Info } from "../../Info"; import { InsightCard } from "../../InsightCard"; import { ColumnsContainer } from "../../InsightCard/ColumnsContainer"; import { KeyValue } from "../../InsightCard/KeyValue"; -import { ListItem } from "../../InsightCard/ListItem"; import { Select } from "../../InsightCard/Select"; import { ContentContainer, Description, Details } from "../styles"; import * as s from "./styles"; @@ -18,8 +19,8 @@ import { SpanNPlusOneInsightProps } from "./types"; const renderOptions = ( endpoints: NPlusOneEndpointInfo[], handleLinkClick: (spanCodeObjectId?: string) => void -): { label: string; customContent: ReactNode; value: string }[] => { - return endpoints.map((x) => { +): { label: string; customContent: ReactNode; value: string }[] => + endpoints.map((x) => { const spanCodeObjectId = x.endpointInfo.entrySpanCodeObjectId; const route = trimEndpointScheme(x.endpointInfo.route); return { @@ -27,16 +28,16 @@ const renderOptions = ( customContent: ( {x.endpointInfo.serviceName} - handleLinkClick(spanCodeObjectId)} - /> + + handleLinkClick(spanCodeObjectId)}> + {route} + + ), value: spanCodeObjectId }; }); -}; export const SpanNPlusOneInsight = (props: SpanNPlusOneInsightProps) => { const { diff --git a/src/components/Insights/common/insights/SpanNPlusOneInsight/styles.ts b/src/components/Insights/common/insights/SpanNPlusOneInsight/styles.ts index 4a449a8e6..3c9bc32e3 100644 --- a/src/components/Insights/common/insights/SpanNPlusOneInsight/styles.ts +++ b/src/components/Insights/common/insights/SpanNPlusOneInsight/styles.ts @@ -8,7 +8,9 @@ export const InfoContainer = styled.div` `; export const SelectedItem = styled.div` + ${footnoteRegularTypography} + display: flex; + gap: 4px; align-items: center; - ${footnoteRegularTypography} `; diff --git a/src/components/common/App/typographies.ts b/src/components/common/App/typographies.ts index d2fd1abac..1c6374f38 100644 --- a/src/components/common/App/typographies.ts +++ b/src/components/common/App/typographies.ts @@ -83,6 +83,12 @@ export const subscriptRegularTypography = css` line-height: ${typographies.subscript.lineHeight}px; `; +export const subscriptSemiboldTypography = css` + font-size: ${typographies.subscript.fontSize}px; + font-weight: ${typographies.subscript.fontWeight.semibold}; + line-height: ${typographies.subscript.lineHeight}px; +`; + export const bodyRegularTypography = css` font-size: ${typographies.body.fontSize}px; font-weight: ${typographies.body.fontWeight.regular}; diff --git a/src/components/common/NewPopover/index.tsx b/src/components/common/NewPopover/index.tsx index 7da9f5a66..2bf485cdf 100644 --- a/src/components/common/NewPopover/index.tsx +++ b/src/components/common/NewPopover/index.tsx @@ -96,7 +96,7 @@ export const NewPopover = (props: PopoverProps) => { const dismiss = useDismiss(context); const { getReferenceProps, getFloatingProps } = useInteractions([ - click, + ...(props.useClickInteraction === false ? [] : [click]), dismiss ]); diff --git a/src/components/common/NewPopover/types.ts b/src/components/common/NewPopover/types.ts index af844a016..cb6235754 100644 --- a/src/components/common/NewPopover/types.ts +++ b/src/components/common/NewPopover/types.ts @@ -11,4 +11,5 @@ export interface PopoverProps { boundary?: HTMLElement; width?: number | string; sameWidth?: boolean; + useClickInteraction?: boolean; } diff --git a/src/components/common/v3/JiraButton/index.tsx b/src/components/common/v3/JiraButton/index.tsx index 9f40e5861..3bd98a9f9 100644 --- a/src/components/common/v3/JiraButton/index.tsx +++ b/src/components/common/v3/JiraButton/index.tsx @@ -108,11 +108,9 @@ export const JiraButtonComponent = ( You can now easily create a ticket using information from Digma openTicketInfo("try now button click")} - > - Try now - + label={"Try now"} + /> } isOpen={Boolean(isHintEnabled)} diff --git a/src/components/common/v3/JiraButton/styles.ts b/src/components/common/v3/JiraButton/styles.ts index 105905961..235525a1f 100644 --- a/src/components/common/v3/JiraButton/styles.ts +++ b/src/components/common/v3/JiraButton/styles.ts @@ -1,5 +1,6 @@ import styled from "styled-components"; -import { Button } from "../../Button"; +import { subscriptSemiboldTypography } from "../../App/typographies"; +import { Button } from "../../v3/Button"; export const HintContainer = styled.div` display: flex; @@ -7,21 +8,22 @@ export const HintContainer = styled.div` gap: 4px; padding: 4px; width: 235px; - color: ${({ theme }) => theme.colors.text.subtext}; + color: ${({ theme }) => theme.colors.v3.text.secondary}; word-break: keep-all; `; export const HintHeader = styled.div` + ${subscriptSemiboldTypography} + display: flex; gap: 4px; align-items: center; - font-weight: 500; - color: ${({ theme }) => theme.colors.text.base}; + color: ${({ theme }) => theme.colors.v3.text.primary}; `; export const HintIconContainer = styled.div` display: flex; - color: ${({ theme }) => theme.colors.icon.primary}; + color: ${({ theme }) => theme.colors.v3.icon.primary}; `; export const TryNowButton = styled(Button)` diff --git a/src/components/common/v3/Link/index.tsx b/src/components/common/v3/Link/index.tsx new file mode 100644 index 000000000..d0c7df5f8 --- /dev/null +++ b/src/components/common/v3/Link/index.tsx @@ -0,0 +1,32 @@ +import { ForwardedRef, MouseEvent, forwardRef } from "react"; +import * as s from "./styles"; +import { LinkProps } from "./types"; + +const LinkComponent = ( + props: LinkProps, + ref: ForwardedRef +) => { + const handleClick = (e: MouseEvent) => { + if (props.onClick) { + if (!props.href) { + e.preventDefault(); + } + props.onClick(e); + } + }; + + return ( + + {props.children} + + ); +}; + +export const Link = forwardRef(LinkComponent); diff --git a/src/components/common/v3/Link/styles.ts b/src/components/common/v3/Link/styles.ts new file mode 100644 index 000000000..01644c180 --- /dev/null +++ b/src/components/common/v3/Link/styles.ts @@ -0,0 +1,51 @@ +import styled from "styled-components"; +import { footnoteRegularTypography } from "../../App/typographies"; + +export const Link = styled.a` + ${footnoteRegularTypography} + + cursor: pointer; + text-decoration: none; + color: ${({ theme }) => theme.colors.v3.text.link}; + display: block; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + + &:hover, + &:focus { + color: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#002d61"; + case "dark": + case "dark-jetbrains": + return "#e2e7ff"; + } + }}; + } + + &:active { + color: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#002d61"; + case "dark": + case "dark-jetbrains": + return "#7891d0"; + } + }}; + } + + &:disabled { + color: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#b9c0d4"; + case "dark": + case "dark-jetbrains": + return "#49494d"; + } + }}; + } +`; diff --git a/src/components/common/v3/Link/types.ts b/src/components/common/v3/Link/types.ts new file mode 100644 index 000000000..774980b22 --- /dev/null +++ b/src/components/common/v3/Link/types.ts @@ -0,0 +1,11 @@ +import { MouseEvent, ReactNode } from "react"; + +export interface LinkProps { + href?: string; + target?: string; + rel?: string; + onClick?: (e: MouseEvent) => void; + disabled?: boolean; + children: ReactNode; + className?: string; +} From d52bc59ecf4f18d8ed62cb2fa9b4c8c173956d84 Mon Sep 17 00:00:00 2001 From: opoliarush <156646693+opoliarush@users.noreply.github.com> Date: Fri, 1 Mar 2024 19:18:55 +0200 Subject: [PATCH 21/56] Insight update (#577) * change override for btn * Change insights --- .../Insights/common/InsightCard/KeyValue/index.tsx | 10 ++++++++-- .../Insights/common/InsightCard/KeyValue/types.ts | 1 + src/components/Insights/common/InsightCard/index.tsx | 4 ++-- .../common/insights/SlowEndpointInsight/index.tsx | 5 ++--- .../common/insights/SlowEndpointInsight/styles.ts | 6 ++++++ .../Insights/common/insights/TrafficInsight/index.tsx | 4 +++- .../Insights/common/insights/TrafficInsight/styles.ts | 8 ++++---- 7 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/components/Insights/common/InsightCard/KeyValue/index.tsx b/src/components/Insights/common/InsightCard/KeyValue/index.tsx index 590d776db..fb4bb298e 100644 --- a/src/components/Insights/common/InsightCard/KeyValue/index.tsx +++ b/src/components/Insights/common/InsightCard/KeyValue/index.tsx @@ -1,11 +1,17 @@ +import { ForwardedRef, forwardRef } from "react"; import * as s from "./styles"; import { KeyValueProps } from "./types"; -export const KeyValue = (props: KeyValueProps) => { +const KeyValueComponent = ( + props: KeyValueProps, + ref: ForwardedRef +) => { return ( - + {props.label} {props.children} ); }; + +export const KeyValue = forwardRef(KeyValueComponent); diff --git a/src/components/Insights/common/InsightCard/KeyValue/types.ts b/src/components/Insights/common/InsightCard/KeyValue/types.ts index 76b1890e6..2903167c6 100644 --- a/src/components/Insights/common/InsightCard/KeyValue/types.ts +++ b/src/components/Insights/common/InsightCard/KeyValue/types.ts @@ -3,4 +3,5 @@ import { ReactNode } from "react"; export interface KeyValueProps { label: ReactNode; children: ReactNode; + className?: string; } diff --git a/src/components/Insights/common/InsightCard/index.tsx b/src/components/Insights/common/InsightCard/index.tsx index 31c12baee..319d6bb46 100644 --- a/src/components/Insights/common/InsightCard/index.tsx +++ b/src/components/Insights/common/InsightCard/index.tsx @@ -102,10 +102,10 @@ export const InsightCard = (props: InsightCardProps) => { tooltip: "Open Trace", button: (btnProps) => (