From cb913a262e35b5d61174c187d3d6abcd1c9ffd8b Mon Sep 17 00:00:00 2001 From: Kyrylo Shmidt Date: Fri, 2 Aug 2024 17:17:40 +0200 Subject: [PATCH 1/2] Show only environments where span exists in --- .../EnvironmentChip.stories.tsx | 36 ++++++++++++ .../EnvironmentChip/index.tsx | 8 ++- .../EnvironmentChip/styles.ts | 40 +++++++++++-- .../EnvironmentChip/types.ts | 18 +++++- .../getMostCriticalIssueCount.ts | 35 ++++++++++++ .../EnvironmentSelector/index.tsx | 57 ++++++++++++++----- .../EnvironmentSelector/types.ts | 9 ++- .../Insights/InsightsCatalog/index.tsx | 19 +++++-- .../Insights/InsightsCatalog/styles.ts | 1 + .../insightTickets/common/useLoading.ts | 7 ++- src/components/Insights/useInsightsData.ts | 3 +- src/components/common/App/types.ts | 12 ++++ src/featureFlags.ts | 3 +- src/hooks/useFetchData.ts | 3 +- src/types.ts | 3 +- 15 files changed, 219 insertions(+), 35 deletions(-) create mode 100644 src/components/Insights/InsightsCatalog/EnvironmentSelector/getMostCriticalIssueCount.ts diff --git a/src/components/Insights/InsightsCatalog/EnvironmentSelector/EnvironmentChip/EnvironmentChip.stories.tsx b/src/components/Insights/InsightsCatalog/EnvironmentSelector/EnvironmentChip/EnvironmentChip.stories.tsx index ff268d8c7..d907a0cdf 100644 --- a/src/components/Insights/InsightsCatalog/EnvironmentSelector/EnvironmentChip/EnvironmentChip.stories.tsx +++ b/src/components/Insights/InsightsCatalog/EnvironmentSelector/EnvironmentChip/EnvironmentChip.stories.tsx @@ -37,3 +37,39 @@ export const Active: Story = { isActive: true } }; + +export const WithHighCriticalIssues: Story = { + args: { + environment: mockedEnvironment, + isActive: false, + issueCounts: { + highCriticality: 1, + mediumCriticality: 2, + lowCriticality: 3 + } + } +}; + +export const WithMediumCriticalIssues: Story = { + args: { + environment: mockedEnvironment, + isActive: false, + issueCounts: { + highCriticality: 0, + mediumCriticality: 2, + lowCriticality: 3 + } + } +}; + +export const WithLowCriticalIssues: Story = { + args: { + environment: mockedEnvironment, + isActive: false, + issueCounts: { + highCriticality: 0, + mediumCriticality: 0, + lowCriticality: 3 + } + } +}; diff --git a/src/components/Insights/InsightsCatalog/EnvironmentSelector/EnvironmentChip/index.tsx b/src/components/Insights/InsightsCatalog/EnvironmentSelector/EnvironmentChip/index.tsx index 2c799fc5d..1f4fb4da1 100644 --- a/src/components/Insights/InsightsCatalog/EnvironmentSelector/EnvironmentChip/index.tsx +++ b/src/components/Insights/InsightsCatalog/EnvironmentSelector/EnvironmentChip/index.tsx @@ -1,10 +1,12 @@ import { EnvironmentIcon } from "../../../../common/EnvironmentIcon"; import { Tooltip } from "../../../../common/v3/Tooltip"; +import { getMostCriticalIssueCount } from "../getMostCriticalIssueCount"; import * as s from "./styles"; import { EnvironmentChipProps } from "./types"; export const EnvironmentChip = ({ environment, + issueCounts, onClick, isActive }: EnvironmentChipProps) => { @@ -15,14 +17,18 @@ export const EnvironmentChip = ({ }; const environmentName = environment.name; + const count = getMostCriticalIssueCount(issueCounts); return ( - + {environmentName} + {count && ( + {count.count} + )} ); diff --git a/src/components/Insights/InsightsCatalog/EnvironmentSelector/EnvironmentChip/styles.ts b/src/components/Insights/InsightsCatalog/EnvironmentSelector/EnvironmentChip/styles.ts index 6dccb6ea0..2eb8df3dc 100644 --- a/src/components/Insights/InsightsCatalog/EnvironmentSelector/EnvironmentChip/styles.ts +++ b/src/components/Insights/InsightsCatalog/EnvironmentSelector/EnvironmentChip/styles.ts @@ -1,13 +1,15 @@ import styled, { css } from "styled-components"; +import { footnoteRegularTypography } from "../../../../common/App/typographies"; import { Chip } from "../../../../common/Chip"; import { activeStyles } from "../../../../common/Chip/styles"; -import { StyledChipProps } from "./types"; +import { CounterProps, ISSUE_CRITICALITY, StyledChipProps } from "./types"; + export const StyledChip = styled(Chip)` gap: 4px; - ${({ isActive }) => (isActive ? activeStyles : "")} - ${({ isActive }) => - isActive + ${({ $isActive }) => ($isActive ? activeStyles : "")} + ${({ $isActive }) => + $isActive ? css` cursor: initial; ` @@ -25,3 +27,33 @@ export const Name = styled.span` white-space: nowrap; text-overflow: ellipsis; `; + +export const Counter = styled.div` + ${footnoteRegularTypography} + + height: 16px; + display: flex; + justify-content: center; + padding: 0 4px; + color: ${({ theme }) => theme.colors.v3.text.white}; + border-radius: 2px; + margin-left: auto; + + ${({ $criticality }) => { + switch ($criticality) { + case ISSUE_CRITICALITY.HIGH: + return css` + background: ${({ theme }) => theme.colors.v3.status.high}; + `; + case ISSUE_CRITICALITY.MEDIUM: + return css` + background: ${({ theme }) => theme.colors.v3.status.medium}; + `; + case ISSUE_CRITICALITY.LOW: + default: + return css` + background: ${({ theme }) => theme.colors.v3.status.low}; + `; + } + }} +`; diff --git a/src/components/Insights/InsightsCatalog/EnvironmentSelector/EnvironmentChip/types.ts b/src/components/Insights/InsightsCatalog/EnvironmentSelector/EnvironmentChip/types.ts index f97888d8a..9b84265e8 100644 --- a/src/components/Insights/InsightsCatalog/EnvironmentSelector/EnvironmentChip/types.ts +++ b/src/components/Insights/InsightsCatalog/EnvironmentSelector/EnvironmentChip/types.ts @@ -1,11 +1,25 @@ -import { Environment } from "../../../../common/App/types"; +import { + Environment, + EnvironmentIssueCounts +} from "../../../../common/App/types"; + +export enum ISSUE_CRITICALITY { + LOW = 1, + MEDIUM = 2, + HIGH = 3 +} export interface EnvironmentChipProps { environment: Environment; onClick: (environment: string) => void; isActive: boolean; + issueCounts?: EnvironmentIssueCounts; } export interface StyledChipProps { - isActive: boolean; + $isActive: boolean; +} + +export interface CounterProps { + $criticality: ISSUE_CRITICALITY; } diff --git a/src/components/Insights/InsightsCatalog/EnvironmentSelector/getMostCriticalIssueCount.ts b/src/components/Insights/InsightsCatalog/EnvironmentSelector/getMostCriticalIssueCount.ts new file mode 100644 index 000000000..0f7d6fe02 --- /dev/null +++ b/src/components/Insights/InsightsCatalog/EnvironmentSelector/getMostCriticalIssueCount.ts @@ -0,0 +1,35 @@ +import { EnvironmentIssueCounts } from "../../../common/App/types"; +import { ISSUE_CRITICALITY } from "./EnvironmentChip/types"; + +export const getMostCriticalIssueCount = ( + counts?: EnvironmentIssueCounts +): + | { + count: number; + criticality: ISSUE_CRITICALITY; + } + | undefined => { + if (!counts) { + return undefined; + } + + if (counts.highCriticality) { + return { + count: counts.highCriticality, + criticality: ISSUE_CRITICALITY.HIGH + }; + } + + if (counts.mediumCriticality) { + return { + count: counts.mediumCriticality, + criticality: ISSUE_CRITICALITY.MEDIUM + }; + } + + if (counts.lowCriticality) { + return { count: counts.lowCriticality, criticality: ISSUE_CRITICALITY.LOW }; + } + + return undefined; +}; diff --git a/src/components/Insights/InsightsCatalog/EnvironmentSelector/index.tsx b/src/components/Insights/InsightsCatalog/EnvironmentSelector/index.tsx index 66fb0122e..4346bee27 100644 --- a/src/components/Insights/InsightsCatalog/EnvironmentSelector/index.tsx +++ b/src/components/Insights/InsightsCatalog/EnvironmentSelector/index.tsx @@ -9,8 +9,9 @@ import { NewButton } from "../../../common/v3/NewButton"; import { EnvironmentMenu } from "../../../Navigation/EnvironmentBar/EnvironmentMenu"; import { trackingEvents } from "../../tracking"; import { EnvironmentChip } from "./EnvironmentChip"; +import { getMostCriticalIssueCount } from "./getMostCriticalIssueCount"; import * as s from "./styles"; -import { EnvironmentSelectorProps } from "./types"; +import { EnvironmentSelectorProps, SelectorEnvironment } from "./types"; const ENVIRONMENT_CHIP_COUNT = 3; @@ -26,6 +27,32 @@ const getSlidingWindow = (arr: T[], start: number, length: number) => { return result; }; +const sortEnvironmentsByCriticalIssues = ( + a: SelectorEnvironment, + b: SelectorEnvironment +) => { + const aCount = getMostCriticalIssueCount(a.issueCounts); + const bCount = getMostCriticalIssueCount(b.issueCounts); + + if (aCount && !bCount) { + return -1; + } + + if (!aCount && bCount) { + return 1; + } + + if (aCount && bCount) { + if (aCount.criticality === bCount.criticality) { + return bCount.count - aCount.count; + } + + return bCount.criticality - aCount.criticality; + } + + return 0; +}; + export const EnvironmentSelector = ({ environments }: EnvironmentSelectorProps) => { @@ -33,8 +60,11 @@ export const EnvironmentSelector = ({ const environment = useGlobalStore.use.environment(); const [isMenuOpen, setIsMenuOpen] = useState(false); const { observe, width } = useDimensions(); + const sortedEnvironments = environments.sort( + sortEnvironmentsByCriticalIssues + ); - if (environments.length < 2) { + if (sortedEnvironments.length < 2) { return null; } @@ -70,24 +100,24 @@ export const EnvironmentSelector = ({ setIsMenuOpen(!isMenuOpen); }; - const environmentIndex = environments.findIndex( - (x) => x.id === environment?.id + const environmentIndex = sortedEnvironments.findIndex( + (x) => x.environment.id === environment?.id ); const environmentsWithChips = - environments.length > ENVIRONMENT_CHIP_COUNT + sortedEnvironments.length > ENVIRONMENT_CHIP_COUNT ? getSlidingWindow( - environments, + sortedEnvironments, environmentIndex - 1, ENVIRONMENT_CHIP_COUNT ) - : environments; + : sortedEnvironments; const renderEnvironmentMenuButton = () => ( ); @@ -96,21 +126,22 @@ export const EnvironmentSelector = ({ {environmentsWithChips.map((x) => ( ))} - {environments.length > ENVIRONMENT_CHIP_COUNT && ( + {sortedEnvironments.length > ENVIRONMENT_CHIP_COUNT && ( <> {/* // TODO: refactor this to use only popover */} {isMenuOpen ? ( x.environment)} onMenuItemClick={handleMenuItemClick} /> } diff --git a/src/components/Insights/InsightsCatalog/EnvironmentSelector/types.ts b/src/components/Insights/InsightsCatalog/EnvironmentSelector/types.ts index 51a8eb487..53a5eea5e 100644 --- a/src/components/Insights/InsightsCatalog/EnvironmentSelector/types.ts +++ b/src/components/Insights/InsightsCatalog/EnvironmentSelector/types.ts @@ -1,5 +1,10 @@ -import { Environment } from "../../../common/App/types"; +import { Environment, EnvironmentIssueCounts } from "../../../common/App/types"; + +export interface SelectorEnvironment { + environment: Environment; + issueCounts?: EnvironmentIssueCounts; +} export interface EnvironmentSelectorProps { - environments: Environment[]; + environments: SelectorEnvironment[]; } diff --git a/src/components/Insights/InsightsCatalog/index.tsx b/src/components/Insights/InsightsCatalog/index.tsx index b379b4872..af25f3f32 100644 --- a/src/components/Insights/InsightsCatalog/index.tsx +++ b/src/components/Insights/InsightsCatalog/index.tsx @@ -31,6 +31,7 @@ import { Tooltip } from "../../common/v3/Tooltip"; import { IssuesFilter } from "../Issues/IssuesFilter"; import { trackingEvents } from "../tracking"; import { EnvironmentSelector } from "./EnvironmentSelector"; +import { SelectorEnvironment } from "./EnvironmentSelector/types"; import { FilterButton } from "./FilterButton"; import { FilterPanel } from "./FilterPanel"; import { InsightsPage } from "./InsightsPage"; @@ -112,6 +113,17 @@ export const InsightsCatalog = ({ "application" ); + const appliedFilterCount = + filters.length + (filteredInsightTypes.length > 0 ? 1 : 0); + + const areSpanEnvironmentsEnabled = getFeatureFlagValue( + backendInfo, + FeatureFlag.ARE_SPAN_ENVIRONMENTS_ENABLED + ); + const selectorEnvironments: SelectorEnvironment[] = areSpanEnvironmentsEnabled + ? insightStats?.spanEnvironments ?? [] + : environments?.map((x) => ({ environment: x })) ?? []; + const handleRegistrationComplete = () => { sendUserActionTrackingEvent( mainTrackingEvents.PROMOTION_REGISTRATION_FORM_SUBMITTED @@ -245,15 +257,12 @@ export const InsightsCatalog = ({ ); }; - const appliedFilterCount = - filters.length + (filteredInsightTypes.length > 0 ? 1 : 0); - return ( <> - {isAtSpan && environments && environments.length > 1 && ( - + {isAtSpan && selectorEnvironments.length > 1 && ( + )} {!isAtSpan && renderFilterPanel()} diff --git a/src/components/Insights/InsightsCatalog/styles.ts b/src/components/Insights/InsightsCatalog/styles.ts index 65e03eff3..ccdf32114 100644 --- a/src/components/Insights/InsightsCatalog/styles.ts +++ b/src/components/Insights/InsightsCatalog/styles.ts @@ -113,4 +113,5 @@ export const ToolbarButtonsContainer = styled.div` display: flex; gap: 4px; align-items: center; + margin-left: auto; `; diff --git a/src/components/Insights/insightTickets/common/useLoading.ts b/src/components/Insights/insightTickets/common/useLoading.ts index b77d0e505..8c71e4070 100644 --- a/src/components/Insights/insightTickets/common/useLoading.ts +++ b/src/components/Insights/insightTickets/common/useLoading.ts @@ -11,9 +11,12 @@ export const useLoading = ( return; } - const timerId = setTimeout(() => setIsLoading(false), cancelTimeoutMs); + const timerId = window.setTimeout( + () => setIsLoading(false), + cancelTimeoutMs + ); return () => { - clearTimeout(timerId); + window.clearTimeout(timerId); }; }, []); diff --git a/src/components/Insights/useInsightsData.ts b/src/components/Insights/useInsightsData.ts index 11004db56..ad61817be 100644 --- a/src/components/Insights/useInsightsData.ts +++ b/src/components/Insights/useInsightsData.ts @@ -204,9 +204,8 @@ export const useInsightsData = ({ }, [getDataListParams, getStatsParams, setIsLoading, isAppReadyToGetData]); useEffect(() => { - const timerId = refreshTimerId.current; return () => { - window.clearTimeout(timerId); + window.clearTimeout(refreshTimerId.current); }; }, []); diff --git a/src/components/common/App/types.ts b/src/components/common/App/types.ts index 167b1043e..be476acde 100644 --- a/src/components/common/App/types.ts +++ b/src/components/common/App/types.ts @@ -54,6 +54,17 @@ export interface ScopeSpan { role: "Entry" | "Internal" | "Unknown" | null; } +export interface EnvironmentIssueCounts { + highCriticality: number; + mediumCriticality: number; + lowCriticality: number; +} + +export interface SpanEnvironment { + environment: Environment; + issueCounts: EnvironmentIssueCounts; +} + export interface Scope { span: ScopeSpan | null; code: { @@ -163,6 +174,7 @@ export interface InsightStats { unreadInsightsCount: number; criticalInsightsCount?: number; allIssuesCount?: number; + spanEnvironments?: SpanEnvironment[]; } export interface UserInfo { diff --git a/src/featureFlags.ts b/src/featureFlags.ts index 213f235f8..17cc4a76c 100644 --- a/src/featureFlags.ts +++ b/src/featureFlags.ts @@ -9,7 +9,8 @@ export const featureFlagMinBackendVersions: Record = { [FeatureFlag.IS_HIGHLIGHTS_SCALING_ENABLED]: "0.3.17", [FeatureFlag.IS_HIGHLIGHTS_SPAN_INFO_ENABLED]: "0.3.19", [FeatureFlag.IS_DURATION_BREAKDOWN_QUANTITY_ENABLED]: "0.3.34", - [FeatureFlag.ARE_ISSUES_FILTERS_ENABLED]: "0.3.72" + [FeatureFlag.ARE_ISSUES_FILTERS_ENABLED]: "0.3.72", + [FeatureFlag.ARE_SPAN_ENVIRONMENTS_ENABLED]: "0.3.95" }; export const getFeatureFlagValue = ( diff --git a/src/hooks/useFetchData.ts b/src/hooks/useFetchData.ts index ec3e1eefe..909aa555f 100644 --- a/src/hooks/useFetchData.ts +++ b/src/hooks/useFetchData.ts @@ -96,7 +96,6 @@ export const useFetchData = ( ]); useEffect(() => { - const timerId = refreshTimerId.current; const handleData = (data: unknown, timeStamp: number) => { if (isInProgress) { if (handleResponse) { @@ -111,7 +110,7 @@ export const useFetchData = ( return () => { dispatcher.removeActionListener(responseAction, handleData); - window.clearTimeout(timerId); + window.clearTimeout(refreshTimerId.current); }; }, [responseAction, isInProgress, handleResponse]); diff --git a/src/types.ts b/src/types.ts index 4ecf05e2c..366d75f23 100644 --- a/src/types.ts +++ b/src/types.ts @@ -11,7 +11,8 @@ export enum FeatureFlag { IS_HIGHLIGHTS_SPAN_INFO_ENABLED, ARE_NEW_INSTRUMENTATION_ATTRIBUTES_ENABLED, IS_DURATION_BREAKDOWN_QUANTITY_ENABLED, - ARE_ISSUES_FILTERS_ENABLED + ARE_ISSUES_FILTERS_ENABLED, + ARE_SPAN_ENVIRONMENTS_ENABLED } export enum InsightType { From 9993524409dec58c9dbd2cf93a95aaf1c10e895e Mon Sep 17 00:00:00 2001 From: Kyrylo Shmidt Date: Fri, 2 Aug 2024 17:23:23 +0200 Subject: [PATCH 2/2] Improve sorting --- .../Insights/InsightsCatalog/EnvironmentSelector/index.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/Insights/InsightsCatalog/EnvironmentSelector/index.tsx b/src/components/Insights/InsightsCatalog/EnvironmentSelector/index.tsx index 4346bee27..6e25f73d7 100644 --- a/src/components/Insights/InsightsCatalog/EnvironmentSelector/index.tsx +++ b/src/components/Insights/InsightsCatalog/EnvironmentSelector/index.tsx @@ -44,7 +44,10 @@ const sortEnvironmentsByCriticalIssues = ( if (aCount && bCount) { if (aCount.criticality === bCount.criticality) { - return bCount.count - aCount.count; + return ( + bCount.count - aCount.count || + a.environment.name.localeCompare(b.environment.name) + ); } return bCount.criticality - aCount.criticality;