diff --git a/src/actions.ts b/src/actions.ts index c1d401e44..2795a686f 100644 --- a/src/actions.ts +++ b/src/actions.ts @@ -38,5 +38,8 @@ export const actions = addPrefix(ACTION_PREFIX, { SET_STATE: "SET_STATE", GET_STATE: "GET_STATE", UPDATE_STATE: "UPDATE_STATE", - CHANGE_VIEW: "CHANGE_VIEW" + CHANGE_VIEW: "CHANGE_VIEW", + GET_INSIGHT_STATS: "GET_INSIGHT_STATS", + SET_INSIGHT_STATS: "SET_INSIGHT_STATS", + CHANGE_ENVIRONMENT: "CHANGE_ENVIRONMENT" }); diff --git a/src/components/Insights/InsightCard/index.tsx b/src/components/Insights/InsightCard/index.tsx index 44c67eb67..825549c62 100644 --- a/src/components/Insights/InsightCard/index.tsx +++ b/src/components/Insights/InsightCard/index.tsx @@ -3,10 +3,10 @@ import { useTheme } from "styled-components"; import { actions } from "../../../actions"; import { PERCENTILES } from "../../../constants"; import { isString } from "../../../typeGuards/isString"; +import { ChangeScopePayload } from "../../../types"; import { formatTimeDistance } from "../../../utils/formatTimeDistance"; import { getInsightImportanceColor } from "../../../utils/getInsightImportanceColor"; import { getInsightTypeInfo } from "../../../utils/getInsightTypeInfo"; -import { ChangeScopePayload } from "../../Navigation/types"; import { ConfigContext } from "../../common/App/ConfigContext"; import { Badge } from "../../common/Badge"; import { Card } from "../../common/Card"; diff --git a/src/components/Insights/InsightList/index.tsx b/src/components/Insights/InsightList/index.tsx index 6f4a20b2d..eb84889f2 100644 --- a/src/components/Insights/InsightList/index.tsx +++ b/src/components/Insights/InsightList/index.tsx @@ -4,11 +4,10 @@ import { actions as globalActions } from "../../../actions"; import { usePersistence } from "../../../hooks/usePersistence"; import { trackingEvents as globalTrackingEvents } from "../../../trackingEvents"; import { isUndefined } from "../../../typeGuards/isUndefined"; -import { InsightType } from "../../../types"; +import { ChangeScopePayload, InsightType } from "../../../types"; import { getInsightTypeInfo } from "../../../utils/getInsightTypeInfo"; import { getInsightTypeOrderPriority } from "../../../utils/getInsightTypeOrderPriority"; import { sendTrackingEvent } from "../../../utils/sendTrackingEvent"; -import { ChangeScopePayload } from "../../Navigation/types"; import { Card } from "../../common/Card"; import { Tooltip } from "../../common/Tooltip"; import { EndpointIcon } from "../../common/icons/EndpointIcon"; diff --git a/src/components/Insights/InsightsCatalog/index.tsx b/src/components/Insights/InsightsCatalog/index.tsx index 108953049..05004b195 100644 --- a/src/components/Insights/InsightsCatalog/index.tsx +++ b/src/components/Insights/InsightsCatalog/index.tsx @@ -7,9 +7,9 @@ import { useDebounce } from "../../../hooks/useDebounce"; import { isNumber } from "../../../typeGuards/isNumber"; import { isString } from "../../../typeGuards/isString"; import { isUndefined } from "../../../typeGuards/isUndefined"; +import { GetInsightStatsPayload } from "../../../types"; import { formatUnit } from "../../../utils/formatUnit"; import { sendTrackingEvent } from "../../../utils/sendTrackingEvent"; -import { ChangeScopePayload } from "../../Navigation/types"; import { ConfigContext } from "../../common/App/ConfigContext"; import { Pagination } from "../../common/Pagination"; import { SearchInput } from "../../common/SearchInput"; @@ -117,13 +117,14 @@ export const InsightsCatalog = (props: InsightsCatalogProps) => { if (previousIsMarkingAllAsReadInProgress && !isMarkingAllAsReadInProgress) { refreshData(); - // Trigger SET_SCOPE response message from the plugin with actual unread insights count - window.sendMessageToDigma({ - action: globalActions.CHANGE_SCOPE, + window.sendMessageToDigma({ + action: globalActions.GET_INSIGHT_STATS, payload: { - span: config.scope?.span + scope: config.scope?.span ? { - spanCodeObjectId: config.scope.span.spanCodeObjectId + span: { + spanCodeObjectId: config.scope.span.spanCodeObjectId + } } : null } diff --git a/src/components/Insights/InsightsPage/index.tsx b/src/components/Insights/InsightsPage/index.tsx index 0f5d4ed95..2fbee8bb7 100644 --- a/src/components/Insights/InsightsPage/index.tsx +++ b/src/components/Insights/InsightsPage/index.tsx @@ -5,9 +5,12 @@ import { usePrevious } from "../../../hooks/usePrevious"; import { trackingEvents as globalTrackingEvents } from "../../../trackingEvents"; import { isNumber } from "../../../typeGuards/isNumber"; import { isUndefined } from "../../../typeGuards/isUndefined"; -import { InsightType } from "../../../types"; +import { + ChangeScopePayload, + ChangeViewPayload, + InsightType +} from "../../../types"; import { sendTrackingEvent } from "../../../utils/sendTrackingEvent"; -import { ChangeScopePayload, ChangeViewPayload } from "../../Navigation/types"; import { ConfigContext } from "../../common/App/ConfigContext"; import { EmptyState } from "../../common/EmptyState"; import { CardsIcon } from "../../common/icons/CardsIcon"; diff --git a/src/components/Insights/common/InsightCard/index.tsx b/src/components/Insights/common/InsightCard/index.tsx index f98820996..9fa90d68c 100644 --- a/src/components/Insights/common/InsightCard/index.tsx +++ b/src/components/Insights/common/InsightCard/index.tsx @@ -3,10 +3,9 @@ import { actions as globalActions } from "../../../../actions"; import { getFeatureFlagValue } from "../../../../featureFlags"; import { usePrevious } from "../../../../hooks/usePrevious"; import { isString } from "../../../../typeGuards/isString"; -import { FeatureFlag } from "../../../../types"; +import { FeatureFlag, GetInsightStatsPayload } from "../../../../types"; import { sendTrackingEvent } from "../../../../utils/sendTrackingEvent"; import { Spinner } from "../../../Navigation/CodeButtonMenu/Spinner"; -import { ChangeScopePayload } from "../../../Navigation/types"; import { ConfigContext } from "../../../common/App/ConfigContext"; import { CheckmarkCircleIcon } from "../../../common/icons/12px/CheckmarkCircleIcon"; import { TraceIcon } from "../../../common/icons/12px/TraceIcon"; @@ -60,13 +59,14 @@ export const InsightCard = (props: InsightCardProps) => { if (previousIsOperationInProgress && !isOperationInProgress) { props.onRefresh(props.insight.type); - // Trigger SET_SCOPE response message from the plugin with actual unread insights count - window.sendMessageToDigma({ - action: globalActions.CHANGE_SCOPE, + window.sendMessageToDigma({ + action: globalActions.GET_INSIGHT_STATS, payload: { - span: config.scope?.span + scope: config.scope?.span ? { - spanCodeObjectId: config.scope.span.spanCodeObjectId + span: { + spanCodeObjectId: config.scope.span.spanCodeObjectId + } } : null } diff --git a/src/components/Navigation/ScopeBar/index.tsx b/src/components/Navigation/ScopeBar/index.tsx index 52460ac24..ab0befd55 100644 --- a/src/components/Navigation/ScopeBar/index.tsx +++ b/src/components/Navigation/ScopeBar/index.tsx @@ -1,4 +1,6 @@ import { useEffect, useState } from "react"; +import { actions as globalActions } from "../../../actions"; +import { ChangeScopePayload } from "../../../types"; import { sendTrackingEvent } from "../../../utils/sendTrackingEvent"; import { CodeDetails, Scope } from "../../common/App/types"; import { NewPopover } from "../../common/NewPopover"; @@ -8,11 +10,7 @@ import { Tooltip } from "../../common/v3/Tooltip"; import { actions } from "../actions"; import { Popup } from "../common/Popup"; import { trackingEvents } from "../tracking"; -import { - ChangeScopePayload, - CodeContext, - GoToCodeLocationPayload -} from "../types"; +import { CodeContext, GoToCodeLocationPayload } from "../types"; import { TargetButtonMenu } from "./TargetButtonMenu"; import * as s from "./styles"; import { ScopeBarProps } from "./types"; @@ -90,7 +88,7 @@ export const ScopeBar = (props: ScopeBarProps) => { const handleHomeButtonClick = () => { sendTrackingEvent(trackingEvents.HOME_BUTTON_CLICKED); window.sendMessageToDigma({ - action: actions.CHANGE_SCOPE, + action: globalActions.CHANGE_SCOPE, payload: { span: null } diff --git a/src/components/Navigation/ScopeNavigation/index.tsx b/src/components/Navigation/ScopeNavigation/index.tsx index b7dc59cbb..1c7375f4a 100644 --- a/src/components/Navigation/ScopeNavigation/index.tsx +++ b/src/components/Navigation/ScopeNavigation/index.tsx @@ -1,16 +1,15 @@ import { useContext, useEffect, useState } from "react"; -import { actions } from "../../../actions"; +import { actions as globalActions } from "../../../actions"; import { dispatcher } from "../../../dispatcher"; import { usePrevious } from "../../../hooks/usePrevious"; -import { HistoryManager } from "../../../utils/HistoryManager"; -import { ConfigContext } from "../../common/App/ConfigContext"; -import { Scope } from "../../common/App/types"; import { ChangeEnvironmentPayload, ChangeScopePayload, ChangeViewPayload -} from "../types"; -import { actions as globalActions } from "./../actions"; +} from "../../../types"; +import { HistoryManager } from "../../../utils/HistoryManager"; +import { ConfigContext } from "../../common/App/ConfigContext"; +import { Scope } from "../../common/App/types"; import { HistoryNavigationPanel } from "./HistoryNavigationPanel"; import { ScopeNavigationProps } from "./types"; @@ -103,10 +102,10 @@ export const ScopeNavigation = (props: ScopeNavigationProps) => { } }; - dispatcher.addActionListener(actions.SET_SCOPE, handleSetScope); + dispatcher.addActionListener(globalActions.SET_SCOPE, handleSetScope); return () => { - dispatcher.removeActionListener(actions.SET_SCOPE, handleSetScope); + dispatcher.removeActionListener(globalActions.SET_SCOPE, handleSetScope); }; }, [environment, props.currentTabId, historyManager]); diff --git a/src/components/Navigation/Tabs/index.tsx b/src/components/Navigation/Tabs/index.tsx index 0d7dc2d52..a9b5d06cb 100644 --- a/src/components/Navigation/Tabs/index.tsx +++ b/src/components/Navigation/Tabs/index.tsx @@ -59,10 +59,16 @@ export const Tabs = (props: TabsProps) => { const isDisabled = getIsTabDisabled(tab, config.scope); const isNewIndicatorVisible = tab.hasNewData || - (tab.id === "insights" && - config.scope && - isNumber(config.scope.unreadInsightsCount) && - config.scope.unreadInsightsCount > 0); + (tab.id === "insights" + ? config.insightStats && + config.scope?.span?.spanCodeObjectId === + config.insightStats.scope?.span.spanCodeObjectId + ? config.insightStats && + config.insightStats.unreadInsightsCount > 0 + : config.scope && + isNumber(config.scope.unreadInsightsCount) && + config.scope.unreadInsightsCount > 0 + : false); return ( { } window.sendMessageToDigma({ - action: actions.CHANGE_ENVIRONMENT, + action: globalActions.CHANGE_ENVIRONMENT, payload: { environment: environmentToChange } @@ -284,7 +286,7 @@ export const Navigation = () => { const changeTab = (tabId: string) => { setCurrentTab(tabId); window.sendMessageToDigma({ - action: actions.CHANGE_VIEW, + action: globalActions.CHANGE_VIEW, payload: { view: tabId } @@ -313,7 +315,7 @@ export const Navigation = () => { const changeScope = (spanCodeObjectId: string) => { window.sendMessageToDigma({ - action: actions.CHANGE_SCOPE, + action: globalActions.CHANGE_SCOPE, payload: { span: { spanCodeObjectId diff --git a/src/components/Navigation/types.ts b/src/components/Navigation/types.ts index 2f74e9c61..ce6c50047 100644 --- a/src/components/Navigation/types.ts +++ b/src/components/Navigation/types.ts @@ -19,24 +19,10 @@ export interface OpenDashboardPayload { environment?: Environment | null; } -export interface ChangeScopePayload { - span: { - spanCodeObjectId: string; - } | null; -} - export interface GoToCodeLocationPayload { codeDetails: CodeDetails; } -export interface ChangeEnvironmentPayload { - environment: Environment; -} - -export interface ChangeViewPayload { - view: string; -} - export interface SetViewsPayload { views: TabData[]; isTriggeredByJcef: boolean; diff --git a/src/components/RecentActivity/index.tsx b/src/components/RecentActivity/index.tsx index bf093a932..d0b9dbb7f 100644 --- a/src/components/RecentActivity/index.tsx +++ b/src/components/RecentActivity/index.tsx @@ -6,6 +6,7 @@ import { actions as globalActions } from "../../actions"; import { dispatcher } from "../../dispatcher"; import { usePrevious } from "../../hooks/usePrevious"; import { trackingEvents as globalTrackingEvents } from "../../trackingEvents"; +import { ChangeEnvironmentPayload } from "../../types"; import { groupBy } from "../../utils/groupBy"; import { sendTrackingEvent } from "../../utils/sendTrackingEvent"; import { ConfigContext } from "../common/App/ConfigContext"; @@ -94,6 +95,7 @@ export const RecentActivity = (props: RecentActivityProps) => { const previousUserRegistrationEmail = usePrevious( config.userRegistrationEmail ); + const previousEnvironment = usePrevious(config.environment); const { observe, entry } = useDimensions(); const environmentActivities = useMemo( @@ -201,8 +203,35 @@ export const RecentActivity = (props: RecentActivityProps) => { previousUserRegistrationEmail ]); + useEffect(() => { + const environmentToSelect = environments.find( + (x) => x.originalName === config.environment?.originalName + ); + + if ( + config.environment && + previousEnvironment?.originalName !== config.environment.originalName && + environmentToSelect + ) { + setSelectedEnvironment(environmentToSelect); + } + }, [config.environment, previousEnvironment, environments]); + const handleEnvironmentSelect = (environment: ExtendedEnvironment) => { setSelectedEnvironment(environment); + + const environmentToSelect = config.environments?.find( + (x) => x.originalName === environment.originalName + ); + + if (environmentToSelect) { + window.sendMessageToDigma({ + action: globalActions.CHANGE_ENVIRONMENT, + payload: { + environment: environmentToSelect + } + }); + } }; const handleSpanLinkClick = (span: EntrySpan) => { diff --git a/src/components/common/App/ConfigContext.ts b/src/components/common/App/ConfigContext.ts index c700cff58..01aeb6906 100644 --- a/src/components/common/App/ConfigContext.ts +++ b/src/components/common/App/ConfigContext.ts @@ -27,7 +27,8 @@ export const initialState = { environments: undefined, scope: undefined, isMicrometerProject: window.isMicrometerProject === true, - state: undefined + state: undefined, + insightStats: undefined }; export const ConfigContext = createContext(initialState); diff --git a/src/components/common/App/index.tsx b/src/components/common/App/index.tsx index 982236640..12ca1fef9 100644 --- a/src/components/common/App/index.tsx +++ b/src/components/common/App/index.tsx @@ -17,6 +17,7 @@ import { DigmaStatus, Environment, GlobalState, + InsightStats, Scope } from "./types"; @@ -221,6 +222,13 @@ export const App = (props: AppProps) => { })); }; + const handleSetInsightStats = (data: unknown) => { + setConfig((config) => ({ + ...config, + insightStats: data as InsightStats + })); + }; + const handleSetState = (data: unknown) => { setConfig((config) => ({ ...config, @@ -283,6 +291,10 @@ export const App = (props: AppProps) => { handleSetIsMicrometerProject ); dispatcher.addActionListener(actions.SET_SCOPE, handleSetScope); + dispatcher.addActionListener( + actions.SET_INSIGHT_STATS, + handleSetInsightStats + ); return () => { dispatcher.removeActionListener(actions.SET_THEME, handleSetTheme); @@ -346,6 +358,10 @@ export const App = (props: AppProps) => { handleSetIsMicrometerProject ); dispatcher.removeActionListener(actions.SET_SCOPE, handleSetScope); + dispatcher.removeActionListener( + actions.SET_INSIGHT_STATS, + handleSetInsightStats + ); }; }, []); diff --git a/src/components/common/App/types.ts b/src/components/common/App/types.ts index 8c8147e87..dceae5331 100644 --- a/src/components/common/App/types.ts +++ b/src/components/common/App/types.ts @@ -86,7 +86,7 @@ export interface GlobalState { export interface ConfigContextData { digmaApiUrl: string; digmaApiProxyPrefix: string; - digmaStatus: DigmaStatus | undefined; + digmaStatus?: DigmaStatus; isObservabilityEnabled: boolean; jaegerURL: string; isJaegerEnabled: boolean; @@ -97,9 +97,21 @@ export interface ConfigContextData { userEmail: string; userRegistrationEmail: string; environment?: Environment | null; - backendInfo: BackendInfo | undefined; - environments: Environment[] | undefined; - scope: Scope | undefined; + backendInfo?: BackendInfo; + environments?: Environment[]; + scope?: Scope; isMicrometerProject: boolean; state?: GlobalState; + insightStats?: InsightStats; +} + +export interface InsightStats { + scope: { + span: { + spanCodeObjectId: string; + }; + } | null; + issuesInsightsCount: number; + analyticsInsightsCount: number; + unreadInsightsCount: number; } diff --git a/src/types.ts b/src/types.ts index 45ccc0269..a4080a4bd 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,3 +1,4 @@ +import { Environment } from "./components/common/App/types"; import { Duration } from "./globals"; export enum FeatureFlag { @@ -75,3 +76,25 @@ export interface SetObservabilityPayload { export interface OpenInstallationWizardPayload { skipInstallationStep: boolean; } + +export interface GetInsightStatsPayload { + scope: { + span: { + spanCodeObjectId: string; + }; + } | null; +} + +export interface ChangeEnvironmentPayload { + environment: Environment; +} + +export interface ChangeScopePayload { + span: { + spanCodeObjectId: string; + } | null; +} + +export interface ChangeViewPayload { + view: string; +}