Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@
"react-syntax-highlighter": "^15.5.0",
"react-transition-group": "^4.4.5",
"recharts": "^2.6.2",
"redux-remember": "^5.2.0",
"semver": "^7.5.4",
"squarify": "^1.1.0",
"styled-components": "^6.1.13",
Expand Down
8 changes: 0 additions & 8 deletions src/components/Admin/Reports/CodeIssues/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ import {
useAdminDispatch,
useAdminSelector
} from "../../../../containers/Admin/hooks";
import { useMount } from "../../../../hooks/useMount";
import type { IssueCriticality } from "../../../../redux/services/types";
import {
clear,
setCriticalityLevels,
setPeriodInDays,
setSelectedEndpoints,
Expand Down Expand Up @@ -61,12 +59,6 @@ export const CodeIssues = () => {

const dispatch = useAdminDispatch();

useMount(() => {
return () => {
dispatch(clear());
};
});

const handleTileTitleClick = (
viewLevel: IssuesReportViewLevel,
target: TargetScope
Expand Down
4 changes: 3 additions & 1 deletion src/components/Admin/Sidebar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useEffect } from "react";
import { useTheme } from "styled-components";
import { useAdminDispatch } from "../../../containers/Admin/hooks";
import { useLogoutMutation } from "../../../redux/services/auth";
import { getThemeKind } from "../../common/App/styles";
import { LogoutIcon } from "../../common/icons/16px/LogoutIcon";
Expand All @@ -10,6 +11,7 @@ export const Sidebar = () => {
const theme = useTheme();
const themeKind = getThemeKind(theme);
const [logout, result] = useLogoutMutation();
const dispatch = useAdminDispatch();

const handleLogoutButtonClick = () => {
void logout();
Expand All @@ -29,7 +31,7 @@ export const Sidebar = () => {
window.clearTimeout(timeoutId);
}
};
}, [result.isSuccess]);
}, [result.isSuccess, dispatch]);

return (
<s.Sidebar>
Expand Down
66 changes: 51 additions & 15 deletions src/components/Admin/index.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,57 @@
import { useEffect } from "react";
import { Helmet } from "react-helmet";
import { Outlet } from "react-router-dom";
import {
useAdminDispatch,
useAdminSelector
} from "../../containers/Admin/hooks";
import { globalClear } from "../../redux/actions";
import { useGetUserProfileQuery } from "../../redux/services/digma";
import { setIsInitialized } from "../../redux/slices/appSlice";
import { setEmail } from "../../redux/slices/authSlice";
import { Spinner } from "../common/v3/Spinner";
import { Header } from "./Header";
import { Sidebar } from "./Sidebar";
import * as s from "./styles";

export const Admin = () => (
<s.Container>
<Helmet>
<title>Digma admin panel</title>
<meta name={"viewport"} content={"width=device-width"} />
</Helmet>
<Sidebar />
<s.ContentContainer>
<Header />
<s.MainContainer>
<Outlet />
</s.MainContainer>
</s.ContentContainer>
</s.Container>
);
export const Admin = () => {
const { data: userProfile } = useGetUserProfileQuery();
const dispatch = useAdminDispatch();
const currentEmail = useAdminSelector((state) => state.auth.email);
const isInitialized = useAdminSelector((state) => state.app.isInitialized);

// Clear issues report state when user changes
useEffect(() => {
if (userProfile?.email) {
if (currentEmail !== userProfile.email) {
dispatch(globalClear());
}
dispatch(setEmail(userProfile.email));
dispatch(setIsInitialized(true));
}
}, [dispatch, currentEmail, userProfile?.email]);

return (
<s.Container>
<Helmet>
<title>Digma admin panel</title>
<meta name={"viewport"} content={"width=device-width"} />
</Helmet>
{isInitialized ? (
<>
<Sidebar />
<s.ContentContainer>
<Header />
<s.MainContainer>
<Outlet />
</s.MainContainer>
</s.ContentContainer>
</>
) : (
<s.LoadingContainer>
<Spinner size={50} />
</s.LoadingContainer>
)}
</s.Container>
);
};
7 changes: 7 additions & 0 deletions src/components/Admin/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,10 @@ export const MainContainer = styled.main`
height: 100%;
overflow: auto;
`;

export const LoadingContainer = styled.div`
display: flex;
align-items: center;
justify-content: center;
flex-grow: 1;
`;
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@ import { ContentContainer, Description, Details } from "../styles";
import * as s from "./styles";
import type { SpaNPlusOneInsightCardProps } from "./types";

const getSelectorOption = (endpoint: NPlusOneEndpointInfo): Option => ({
const getSelectorOption = (endpoint: NPlusOneEndpointInfo): Option<number> => ({
route: endpoint.endpointInfo.route,
serviceName: endpoint.endpointInfo.serviceName,
spanCodeObjectId: endpoint.endpointInfo.entrySpanCodeObjectId,
duration: endpoint.duration
metric: {
value: endpoint.occurrences,
label: "Repeats"
}
});

export const SpaNPlusOneInsightCard = ({
Expand All @@ -41,21 +44,21 @@ export const SpaNPlusOneInsightCard = ({
viewMode,
onDismissalChange
}: SpaNPlusOneInsightCardProps) => {
const endpoints = useMemo(() => insight.endpoints ?? [], [insight.endpoints]);
const selectorOptions = useMemo(
const endpoints = useMemo(
() =>
endpoints
.map(getSelectorOption)
.sort((a, b) =>
a.duration && b.duration ? b.duration.raw - a.duration.raw : 0
),
[endpoints]
(insight.endpoints ?? []).sort((a, b) => b.occurrences - a.occurrences),
[insight.endpoints]
);
const endpointWithMaxDuration = endpoints.reduce(
(acc, cur) => (acc.duration.raw >= cur.duration.raw ? acc : cur),
endpoints[0]

const selectorOptions = useMemo(
() => endpoints.map(getSelectorOption),
[endpoints]
);
const maxDurationString = getDurationString(endpointWithMaxDuration.duration);
const endpointWithMaxDuration =
endpoints.length > 0 ? endpoints[0] : undefined;
const maxDurationString = endpointWithMaxDuration
? getDurationString(endpointWithMaxDuration.duration)
: undefined;
const { isJaegerEnabled } = useConfigSelector();
const [selectedEndpointKey, setSelectedEndpointKey] = useState<
string | undefined
Expand Down Expand Up @@ -192,9 +195,11 @@ export const SpaNPlusOneInsightCard = ({
isMarkAsReadButtonEnabled={isMarkAsReadButtonEnabled}
viewMode={viewMode}
mainMetric={
<Tooltip title={maxDurationString}>
<span>{maxDurationString}</span>
</Tooltip>
maxDurationString ? (
<Tooltip title={maxDurationString}>
<span>{maxDurationString}</span>
</Tooltip>
) : undefined
}
onDismissalChange={onDismissalChange}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,16 @@ import { ContentContainer, Description, Details } from "../styles";
import * as s from "./styles";
import type { SpanEndpointBottleneckInsightCardProps } from "./types";

const getSelectorOption = (endpoint: BottleneckEndpointInfo): Option => ({
const getSelectorOption = (
endpoint: BottleneckEndpointInfo
): Option<string> => ({
route: trimEndpointScheme(endpoint.endpointInfo.route),
serviceName: endpoint.endpointInfo.serviceName,
spanCodeObjectId: endpoint.endpointInfo.spanCodeObjectId,
duration: endpoint.avgDurationWhenBeingBottleneck
metric: {
value: getDurationString(endpoint.avgDurationWhenBeingBottleneck),
label: "Duration"
}
});

export const SpanEndpointBottleneckInsightCard = ({
Expand All @@ -45,30 +50,21 @@ export const SpanEndpointBottleneckInsightCard = ({
}: SpanEndpointBottleneckInsightCardProps) => {
const { isJaegerEnabled } = useConfigSelector();
const slowEndpoints = useMemo(
() => insight.slowEndpoints ?? [],
() =>
(insight.slowEndpoints ?? []).sort(
(a, b) =>
b.avgDurationWhenBeingBottleneck.raw -
a.avgDurationWhenBeingBottleneck.raw
),
[insight.slowEndpoints]
);
const selectorOptions: Option[] = useMemo(
() =>
slowEndpoints
.map(getSelectorOption)
.sort((a, b) =>
a.duration && b.duration ? b.duration.raw - a.duration.raw : 0
),
const selectorOptions: Option<string>[] = useMemo(
() => slowEndpoints.map(getSelectorOption),
[slowEndpoints]
);

const endpointWithMaxDuration =
slowEndpoints.length > 0
? slowEndpoints.reduce(
(acc, cur) =>
acc.avgDurationWhenBeingBottleneck.raw >=
cur.avgDurationWhenBeingBottleneck.raw
? acc
: cur,
slowEndpoints[0]
)
: undefined;
slowEndpoints.length > 0 ? slowEndpoints[0] : undefined;
const maxDurationString = endpointWithMaxDuration
? getDurationString(endpointWithMaxDuration.avgDurationWhenBeingBottleneck)
: undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,30 @@ export const Default: Story = {
route: "test",
serviceName:
"someasasdasdasdasdasdasdawerereasdsadsadsadsadsadasdsadasdsadsdhfkjdhskjfgdf;lgjhdfhglkdfhgklhsdklfghkhgdfgkdfklghrthysdfhsbfheslkbyieryiobyrieuytirosynoiuybioyustest2",
spanCodeObjectId: "spanCodeObjectId1"
spanCodeObjectId: "spanCodeObjectId1",
metric: {
value: 100,
label: "100 ms"
}
},
{
route:
"someasasdasdasdasdasdasdawerereasdsadsadsadsadsadasdsadasdsadsdhfkjdhskjfgdf;lgjhdfhglkdfhgklhsdklfghkhgdfgkdfklghrthysdfhsbfheslkbyieryiobyrieuytirosynoiuybioyustest",
serviceName: "test1",
spanCodeObjectId: "spanCodeObjectId2"
spanCodeObjectId: "spanCodeObjectId2",
metric: {
value: 200,
label: "200 ms"
}
},
{
route: "test",
serviceName: "test1",
spanCodeObjectId: "spanCodeObjectId2"
spanCodeObjectId: "spanCodeObjectId2",
metric: {
value: 300,
label: "300 ms"
}
}
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ import { Tooltip } from "../../v3/Tooltip";
import * as s from "./styles";
import type { EndpointOptionProps } from "./types";

export const EndpointOption = ({
export const EndpointOption = <T,>({
serviceName,
route,
spanCodeObjectId,
onSpanLinkClick,
selected,
hideCopyIcon,
onClick,
duration,
hideDuration
}: EndpointOptionProps) => {
metric,
isHeader
}: EndpointOptionProps<T>) => {
const title = `${serviceName} ${route}`;

return (
Expand All @@ -34,8 +34,10 @@ export const EndpointOption = ({
)}
</s.Route>
{!hideCopyIcon && <s.StyledCopyButton text={route} />}
{!selected && !hideDuration && duration && (
<s.Duration>{duration}</s.Duration>
{!selected && metric && (
<s.Duration>
{isHeader ? metric.label : String(metric.value)}
</s.Duration>
)}
</s.EndpointName>
</Tooltip>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
export interface EndpointOptionProps {
export interface EndpointOptionProps<T> {
serviceName: string;
route: string;
spanCodeObjectId?: string;
selected?: boolean;
onSpanLinkClick?: (spanCodeObjectId: string) => void;
hideCopyIcon?: boolean;
onClick?: ((spanCodeObjectId?: string) => void) | null;
duration?: string;
hideDuration?: boolean;
metric?: {
value: T;
label: string;
};
isHeader?: boolean;
}

export interface EndpointNameProps {
Expand Down
Loading
Loading