Skip to content

Commit 420e3c4

Browse files
committed
Move Recent Activity content to the separate component, refetch data on reconnect
1 parent 10d900e commit 420e3c4

File tree

15 files changed

+358
-319
lines changed

15 files changed

+358
-319
lines changed

src/components/Assets/AssetList/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,8 @@ export const AssetList = ({
154154

155155
const { data } = useGetAssetsQuery(payload, {
156156
skip: !environmentId,
157-
pollingInterval: REFRESH_INTERVAL
157+
pollingInterval: REFRESH_INTERVAL,
158+
refetchOnReconnect: true
158159
});
159160

160161
const filteredCount = data?.filteredCount ?? 0;

src/components/Assets/AssetTypeList/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ export const AssetTypeList = ({
5656

5757
const { data } = useGetAssetsCategoriesQuery(payload, {
5858
skip: !environmentId,
59-
pollingInterval: REFRESH_INTERVAL
59+
pollingInterval: REFRESH_INTERVAL,
60+
refetchOnReconnect: true
6061
});
6162

6263
const previousData = usePrevious(data);

src/components/Insights/InsightsCatalog/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,8 @@ export const InsightsCatalog = ({
187187
{ spanCodeObjectId: scopeSpanCodeObjectId ?? "" },
188188
{
189189
skip: !areSpanEnvironmentsEnabled || !scopeSpanCodeObjectId,
190-
pollingInterval: REFRESH_INTERVAL
190+
pollingInterval: REFRESH_INTERVAL,
191+
refetchOnReconnect: true
191192
}
192193
);
193194

src/components/Insights/hooks/useInsightsData.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ export const useInsightsData = () => {
128128
},
129129
{
130130
skip: !isAppReadyToGetData || isIssuesQueryActive,
131-
pollingInterval: REFRESH_INTERVAL
131+
pollingInterval: REFRESH_INTERVAL,
132+
refetchOnReconnect: true
132133
}
133134
);
134135

@@ -161,7 +162,8 @@ export const useInsightsData = () => {
161162
},
162163
{
163164
skip: !isAppReadyToGetData || !isIssuesQueryActive,
164-
pollingInterval: REFRESH_INTERVAL
165+
pollingInterval: REFRESH_INTERVAL,
166+
refetchOnReconnect: true
165167
}
166168
);
167169

@@ -175,7 +177,8 @@ export const useInsightsData = () => {
175177
!isAppReadyToGetData ||
176178
!spanCodeObjectId ||
177179
!areSpanEnvironmentsEnabled,
178-
pollingInterval: REFRESH_INTERVAL
180+
pollingInterval: REFRESH_INTERVAL,
181+
refetchOnReconnect: true
179182
}
180183
);
181184

src/components/Insights/hooks/useInsightsStats.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ export const useInsightsStats = ({
5959
},
6060
{
6161
skip: !environmentId,
62-
pollingInterval: REFRESH_INTERVAL
62+
pollingInterval: REFRESH_INTERVAL,
63+
refetchOnReconnect: true
6364
}
6465
);
6566

src/components/RecentActivity/EnvironmentInstructionsPanel/EnvironmentVariableCode/index.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import type { ReactNode } from "react";
2-
import { Fragment } from "react";
2+
import { Fragment, useContext } from "react";
33
import { getFeatureFlagValue } from "../../../../featureFlags";
4-
import { useConfigSelector } from "../../../../store/config/useConfigSelector";
54
import { isString } from "../../../../typeGuards/isString";
65
import { FeatureFlag } from "../../../../types";
76
import { intersperse } from "../../../../utils/intersperse";
7+
import { ConfigContext } from "../../../common/App/ConfigContext";
88
import { HighlightedCode } from "../styles";
99
import type { DigmaAttribute } from "./types";
1010

@@ -90,7 +90,7 @@ const renderEnvironmentVariables = (
9090

9191
export const EnvironmentVariableCode = () => {
9292
const { environment, backendInfo, userInfo, runConfig, isMicrometerProject } =
93-
useConfigSelector();
93+
useContext(ConfigContext);
9494
const isMicrometerProjectValue = isMicrometerProject ?? false;
9595
const userId = userInfo?.id;
9696

src/components/RecentActivity/EnvironmentInstructionsPanel/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import type { ExtendedEnvironment } from "../types";
1+
import type { Environment } from "../../../redux/services/types";
22

33
export interface EnvironmentInstructionsPanelProps {
4-
environment: ExtendedEnvironment;
4+
environment: Environment;
55
onAddEnvironmentToRunConfig?: (environment: string) => void;
66
onClose?: () => void;
77
}
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
import { useContext, useEffect, useMemo, useState } from "react";
2+
import { useGetRecentActivityQuery } from "../../../redux/services/digma";
3+
import type { SlimEntrySpanData } from "../../../redux/services/types";
4+
import { isUndefined } from "../../../typeGuards/isUndefined";
5+
import { ScopeChangeEvent } from "../../../types";
6+
import { changeScope } from "../../../utils/actions/changeScope";
7+
import { ConfigContext } from "../../common/App/ConfigContext";
8+
import { actions } from "../actions";
9+
import { EnvironmentInstructionsPanel } from "../EnvironmentInstructionsPanel";
10+
import type { ViewMode } from "../EnvironmentPanel/types";
11+
import { NoData } from "../NoData";
12+
import { RecentActivityTable } from "../RecentActivityTable";
13+
import { RecentActivityHeader } from "../RecentActivityToolbar";
14+
import * as s from "./styles";
15+
import type { RecentActivityContentProps } from "./types";
16+
17+
const REFRESH_INTERVAL = 10 * 1000; // in milliseconds
18+
19+
export const RecentActivityContent = ({
20+
environment,
21+
environmentInstructionsVisibility,
22+
headerHeight,
23+
clearDataTimestamp,
24+
onEnvironmentSetupInstructionsClose
25+
}: RecentActivityContentProps) => {
26+
const [viewMode, setViewMode] = useState<ViewMode>("table");
27+
const { isJaegerEnabled, backendInfo, userInfo } = useContext(ConfigContext);
28+
29+
const { data, isLoading } = useGetRecentActivityQuery(
30+
{
31+
environments: environment ? [environment.id] : []
32+
},
33+
{
34+
skip: !userInfo?.id || !backendInfo || !environment,
35+
pollingInterval: REFRESH_INTERVAL,
36+
refetchOnMountOrArgChange: true,
37+
refetchOnReconnect: true
38+
}
39+
);
40+
41+
const filteredEntries = useMemo(
42+
() =>
43+
data?.entries.filter((entry) =>
44+
clearDataTimestamp
45+
? new Date(entry.latestTraceTimestamp).valueOf() >
46+
new Date(clearDataTimestamp).valueOf()
47+
: true
48+
) ?? [],
49+
[data?.entries, clearDataTimestamp]
50+
);
51+
52+
const handleViewModeChange = (mode: ViewMode) => {
53+
setViewMode(mode);
54+
};
55+
56+
const handleSpanLinkClick = (span: SlimEntrySpanData) => {
57+
if (environment) {
58+
changeScope({
59+
span: {
60+
spanCodeObjectId: span.spanCodeObjectId
61+
},
62+
context: {
63+
event: ScopeChangeEvent.RecentActivitySpanLinkClicked
64+
}
65+
});
66+
}
67+
};
68+
69+
const handleTraceButtonClick = (traceId: string, span: SlimEntrySpanData) => {
70+
window.sendMessageToDigma({
71+
action: actions.GO_TO_TRACE,
72+
payload: {
73+
traceId,
74+
span: {
75+
scopeId: span.scopeId,
76+
displayText: span.displayText
77+
}
78+
}
79+
});
80+
};
81+
82+
const handleEnvironmentSetupInstructionsClose = () => {
83+
onEnvironmentSetupInstructionsClose();
84+
};
85+
86+
// Close the environment setup instructions panel if data exist and the panel is open by the user
87+
useEffect(() => {
88+
if (
89+
environment &&
90+
filteredEntries &&
91+
environmentInstructionsVisibility.isOpen &&
92+
!environmentInstructionsVisibility.keepOpen
93+
) {
94+
onEnvironmentSetupInstructionsClose();
95+
}
96+
}, [
97+
filteredEntries,
98+
environmentInstructionsVisibility,
99+
environment,
100+
onEnvironmentSetupInstructionsClose
101+
]);
102+
103+
if (environment && environmentInstructionsVisibility.isOpen) {
104+
return (
105+
<EnvironmentInstructionsPanel
106+
environment={environment}
107+
onClose={
108+
environmentInstructionsVisibility.keepOpen
109+
? handleEnvironmentSetupInstructionsClose
110+
: undefined
111+
}
112+
/>
113+
);
114+
}
115+
116+
if (isUndefined(data) && isLoading) {
117+
return (
118+
<>
119+
<s.NoDataRecentActivityContainerBackground>
120+
<s.NoDataRecentActivityContainerBackgroundGradient />
121+
</s.NoDataRecentActivityContainerBackground>
122+
<s.LoadingContainer>
123+
<s.Spinner size={32} />
124+
</s.LoadingContainer>
125+
</>
126+
);
127+
}
128+
129+
if (!environment || filteredEntries.length === 0) {
130+
return (
131+
<>
132+
<s.NoDataRecentActivityContainerBackground>
133+
<s.NoDataRecentActivityContainerBackgroundGradient />
134+
</s.NoDataRecentActivityContainerBackground>
135+
{environment && (
136+
<s.NoDataRecentActivityHeader
137+
viewMode={viewMode}
138+
onViewModeChange={handleViewModeChange}
139+
environment={environment}
140+
/>
141+
)}
142+
<s.NoDataContainer>
143+
<NoData />
144+
</s.NoDataContainer>
145+
</>
146+
);
147+
}
148+
149+
return (
150+
<>
151+
<RecentActivityHeader
152+
showToolbar={true}
153+
viewMode={viewMode}
154+
onViewModeChange={handleViewModeChange}
155+
environment={environment}
156+
/>
157+
<RecentActivityTable
158+
viewMode={viewMode}
159+
data={filteredEntries}
160+
onSpanLinkClick={handleSpanLinkClick}
161+
onTraceButtonClick={handleTraceButtonClick}
162+
isTraceButtonVisible={Boolean(isJaegerEnabled)}
163+
headerHeight={headerHeight}
164+
/>
165+
</>
166+
);
167+
};
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import styled from "styled-components";
2+
import { Spinner as CommonSpinner } from "../../common/v3/Spinner";
3+
import { RecentActivityHeader } from "../RecentActivityToolbar";
4+
5+
const RECENT_ACTIVITY_NO_DATA_PADDING_TOP = 39; // in pixels
6+
7+
export const NoDataContainer = styled.div`
8+
position: relative;
9+
padding-top: ${RECENT_ACTIVITY_NO_DATA_PADDING_TOP}px;
10+
`;
11+
12+
export const NoDataRecentActivityContainerBackground = styled.div`
13+
position: absolute;
14+
inset: 0;
15+
overflow: hidden;
16+
`;
17+
18+
export const NoDataRecentActivityContainerBackgroundGradient = styled.div`
19+
position: absolute;
20+
left: 0;
21+
right: 0;
22+
margin: auto;
23+
top: ${RECENT_ACTIVITY_NO_DATA_PADDING_TOP}px;
24+
height: 454.5%;
25+
width: 80.41%;
26+
border-radius: 100%;
27+
opacity: 0.7;
28+
background: radial-gradient(
29+
50% 50% at 50% 50%,
30+
rgb(79 93 163 / 60%) 0%,
31+
rgb(79 93 163 / 0%) 100%
32+
);
33+
filter: blur(5px);
34+
`;
35+
36+
export const NoDataRecentActivityHeader = styled(RecentActivityHeader)`
37+
position: relative;
38+
`;
39+
40+
export const LoadingContainer = styled.div`
41+
display: flex;
42+
align-items: center;
43+
justify-content: center;
44+
padding-top: 60px;
45+
`;
46+
47+
export const Spinner = styled(CommonSpinner)`
48+
color: ${({ theme }) => theme.colors.v3.surface.gray};
49+
`;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import type { Environment } from "../../../redux/services/types";
2+
import type { EnvironmentInstructionsVisibility } from "../types";
3+
4+
export interface RecentActivityContentProps {
5+
environment?: Environment;
6+
environmentInstructionsVisibility: EnvironmentInstructionsVisibility;
7+
headerHeight: number;
8+
clearDataTimestamp: string | undefined;
9+
onEnvironmentSetupInstructionsClose: () => void;
10+
}

0 commit comments

Comments
 (0)