From 5e8404e2f8269156422536c956902da900afaada Mon Sep 17 00:00:00 2001 From: Kyrylo Shmidt Date: Tue, 28 Jan 2025 12:45:31 +0100 Subject: [PATCH 1/2] Add Top issues widget --- .../overviewWidgetMetricsDivider_dark.svg | 3 + .../overviewWidgetMetricsDivider_light.svg | 3 + .../Admin/Header/EnvironmentSelect/index.tsx | 65 ++++++++ .../Admin/Header/EnvironmentSelect/styles.ts | 7 + src/components/Admin/Header/index.tsx | 8 +- src/components/Admin/Header/styles.ts | 7 + .../Home/Overview/OverviewWidget/styles.ts | 3 - .../Home/Overview/TopIssuesWidget/index.tsx | 93 +++++++++++ .../Home/Overview/TopIssuesWidget/styles.ts | 62 +++++++ .../Home/Overview/TopIssuesWidget/types.ts | 5 + src/components/Admin/Home/Overview/index.tsx | 21 ++- src/components/Admin/Home/Overview/types.ts | 5 + src/components/Admin/Home/index.tsx | 35 +++- .../Admin/Reports/CodeIssues/index.tsx | 157 +++++------------- .../SuggestionBar/SuggestionBar.stories.tsx | 0 .../IssuesSidebar/SuggestionBar/index.tsx | 2 +- .../IssuesSidebar/SuggestionBar/styles.ts | 0 .../IssuesSidebar/SuggestionBar/types.ts | 6 - .../IssuesSidebar/index.tsx | 80 +++++---- .../IssuesSidebar/styles.ts | 0 .../IssuesSidebar/types.ts | 11 +- .../common/IssuesSidebarOverlay/index.tsx | 155 +++++++++++++++++ .../common/IssuesSidebarOverlay/styles.ts | 60 +++++++ .../common/IssuesSidebarOverlay/types.ts | 24 +++ .../InsightCardRenderer/index.tsx | 4 +- .../SpanDurationsInsightCard/types.ts | 3 +- .../SpanScalingInsightCard/types.ts | 3 +- .../insightCards/common/InsightCard/index.tsx | 3 +- .../insightCards/common/InsightCard/types.ts | 3 +- .../InsightsPage/InsightCardRenderer/types.ts | 1 - .../InsightsCatalog/InsightsPage/index.tsx | 1 - .../Insights/InsightsCatalog/index.tsx | 42 +++-- src/components/common/App/typographies.ts | 5 + src/containers/Admin/store.ts | 2 + src/featureFlags.ts | 3 +- src/redux/services/types.ts | 7 +- src/redux/slices/persistSlice.ts | 2 +- src/redux/slices/scopeSlice.ts | 32 ++++ src/types.ts | 3 +- 39 files changed, 694 insertions(+), 232 deletions(-) create mode 100644 public/assets/images/admin/home/overviewWidgetMetricsDivider_dark.svg create mode 100644 public/assets/images/admin/home/overviewWidgetMetricsDivider_light.svg create mode 100644 src/components/Admin/Header/EnvironmentSelect/index.tsx create mode 100644 src/components/Admin/Header/EnvironmentSelect/styles.ts create mode 100644 src/components/Admin/Home/Overview/TopIssuesWidget/index.tsx create mode 100644 src/components/Admin/Home/Overview/TopIssuesWidget/styles.ts create mode 100644 src/components/Admin/Home/Overview/TopIssuesWidget/types.ts create mode 100644 src/components/Admin/Home/Overview/types.ts rename src/components/Admin/{Reports/CodeIssues => common/IssuesSidebarOverlay}/IssuesSidebar/SuggestionBar/SuggestionBar.stories.tsx (100%) rename src/components/Admin/{Reports/CodeIssues => common/IssuesSidebarOverlay}/IssuesSidebar/SuggestionBar/index.tsx (98%) rename src/components/Admin/{Reports/CodeIssues => common/IssuesSidebarOverlay}/IssuesSidebar/SuggestionBar/styles.ts (100%) rename src/components/Admin/{Reports/CodeIssues => common/IssuesSidebarOverlay}/IssuesSidebar/SuggestionBar/types.ts (60%) rename src/components/Admin/{Reports/CodeIssues => common/IssuesSidebarOverlay}/IssuesSidebar/index.tsx (84%) rename src/components/Admin/{Reports/CodeIssues => common/IssuesSidebarOverlay}/IssuesSidebar/styles.ts (100%) rename src/components/Admin/{Reports/CodeIssues => common/IssuesSidebarOverlay}/IssuesSidebar/types.ts (63%) create mode 100644 src/components/Admin/common/IssuesSidebarOverlay/index.tsx create mode 100644 src/components/Admin/common/IssuesSidebarOverlay/styles.ts create mode 100644 src/components/Admin/common/IssuesSidebarOverlay/types.ts create mode 100644 src/redux/slices/scopeSlice.ts diff --git a/public/assets/images/admin/home/overviewWidgetMetricsDivider_dark.svg b/public/assets/images/admin/home/overviewWidgetMetricsDivider_dark.svg new file mode 100644 index 000000000..d171f9f38 --- /dev/null +++ b/public/assets/images/admin/home/overviewWidgetMetricsDivider_dark.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/public/assets/images/admin/home/overviewWidgetMetricsDivider_light.svg b/public/assets/images/admin/home/overviewWidgetMetricsDivider_light.svg new file mode 100644 index 000000000..0d38740ae --- /dev/null +++ b/public/assets/images/admin/home/overviewWidgetMetricsDivider_light.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/components/Admin/Header/EnvironmentSelect/index.tsx b/src/components/Admin/Header/EnvironmentSelect/index.tsx new file mode 100644 index 000000000..cbd7e9a32 --- /dev/null +++ b/src/components/Admin/Header/EnvironmentSelect/index.tsx @@ -0,0 +1,65 @@ +import { useEffect, useMemo } from "react"; +import { + useAdminDispatch, + useAdminSelector +} from "../../../../containers/Admin/hooks"; +import { useGetEnvironmentsQuery } from "../../../../redux/services/digma"; +import { setEnvironmentId } from "../../../../redux/slices/scopeSlice"; +import { CodeIcon } from "../../../common/icons/12px/CodeIcon"; +import { InfinityIcon } from "../../../common/icons/InfinityIcon"; +import { sortEnvironments } from "../../../common/IssuesReport/utils"; +import * as s from "./styles"; + +export const EnvironmentSelect = () => { + const { data: environments } = useGetEnvironmentsQuery(); + const sortedEnvironments = useMemo( + () => sortEnvironments(environments ?? []), + [environments] + ); + const selectedEnvironmentId = useAdminSelector( + (state) => state.scope.environmentId + ); + const selectedEnvironment = useMemo( + () => + sortedEnvironments?.find((x) => x.id === selectedEnvironmentId) ?? null, + [selectedEnvironmentId, sortedEnvironments] + ); + const dispatch = useAdminDispatch(); + + const handleEnvironmentChanged = (option: string | string[]) => { + const newItem = Array.isArray(option) ? option[0] : option; + dispatch(setEnvironmentId(newItem)); + }; + + useEffect(() => { + if ( + sortedEnvironments && + sortedEnvironments.length > 0 && + !selectedEnvironmentId + ) { + dispatch(setEnvironmentId(sortedEnvironments[0].id)); + } + }, [dispatch, sortedEnvironments, selectedEnvironmentId]); + + return ( + ({ + label: x.name, + value: x.id, + enabled: true, + selected: x.id === selectedEnvironmentId + }))} + showSelectedState={true} + icon={(props) => + selectedEnvironment?.type === "Public" ? ( + + ) : ( + + ) + } + onChange={handleEnvironmentChanged} + placeholder={selectedEnvironment?.name ?? "Select Environments"} + disabled={sortedEnvironments.length === 0} + /> + ); +}; diff --git a/src/components/Admin/Header/EnvironmentSelect/styles.ts b/src/components/Admin/Header/EnvironmentSelect/styles.ts new file mode 100644 index 000000000..4aed449f6 --- /dev/null +++ b/src/components/Admin/Header/EnvironmentSelect/styles.ts @@ -0,0 +1,7 @@ +import styled from "styled-components"; + +import { Select as CommonSelect } from "../../../common/v3/Select"; + +export const Select = styled(CommonSelect)` + width: 180px; +`; diff --git a/src/components/Admin/Header/index.tsx b/src/components/Admin/Header/index.tsx index be8deb329..bcf698370 100644 --- a/src/components/Admin/Header/index.tsx +++ b/src/components/Admin/Header/index.tsx @@ -1,4 +1,5 @@ import { Route, Routes } from "react-router-dom"; +import { EnvironmentSelect } from "./EnvironmentSelect"; import { Greeting } from "./Greeting"; import * as s from "./styles"; @@ -7,7 +8,12 @@ export const Header = () => ( } + element={ + + + + + } /> Reports} /> diff --git a/src/components/Admin/Header/styles.ts b/src/components/Admin/Header/styles.ts index 4207558e2..8c64bcd1d 100644 --- a/src/components/Admin/Header/styles.ts +++ b/src/components/Admin/Header/styles.ts @@ -10,3 +10,10 @@ export const Header = styled.header` box-sizing: border-box; color: ${({ theme }) => theme.colors.v3.text.primary}; `; + +export const HomeHeader = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + gap: 8px; +`; diff --git a/src/components/Admin/Home/Overview/OverviewWidget/styles.ts b/src/components/Admin/Home/Overview/OverviewWidget/styles.ts index 2fa992d18..09e58d9e7 100644 --- a/src/components/Admin/Home/Overview/OverviewWidget/styles.ts +++ b/src/components/Admin/Home/Overview/OverviewWidget/styles.ts @@ -4,10 +4,7 @@ export const Container = styled.div` display: flex; flex-direction: column; padding: 16px; - gap: 8px; border-radius: 12px; - width: 279px; - height: 108px; border: 1px solid ${({ theme }) => theme.colors.v3.stroke.primary}; flex-shrink: 0; box-sizing: border-box; diff --git a/src/components/Admin/Home/Overview/TopIssuesWidget/index.tsx b/src/components/Admin/Home/Overview/TopIssuesWidget/index.tsx new file mode 100644 index 000000000..594128a7f --- /dev/null +++ b/src/components/Admin/Home/Overview/TopIssuesWidget/index.tsx @@ -0,0 +1,93 @@ +import { useTheme } from "styled-components"; +import { useAdminSelector } from "../../../../../containers/Admin/hooks"; +import { getFeatureFlagValue } from "../../../../../featureFlags"; +import { useGetAboutQuery } from "../../../../../redux/services/digma"; +import { FeatureFlag } from "../../../../../types"; +import { getThemeKind } from "../../../../common/App/styles"; +import { WarningTriangleIcon } from "../../../../common/icons/12px/WarningTriangleIcon"; +import { MeterHighIcon } from "../../../../common/icons/16px/MeterHighIcon"; +import { ChevronIcon } from "../../../../common/icons/20px/ChevronIcon"; +import { Direction } from "../../../../common/icons/types"; +import { OverviewWidget } from "../OverviewWidget"; +import * as s from "./styles"; +import type { TopIssuesWidgetProps } from "./types"; + +const ISSUES_LIMIT = 10; + +export const TopIssuesWidget = ({ onGetIssues }: TopIssuesWidgetProps) => { + const theme = useTheme(); + const themeKind = getThemeKind(theme); + const environmentId = useAdminSelector((state) => state.scope.environmentId); + + const handleByCriticalityButtonClick = () => { + onGetIssues({ + query: { + environment: environmentId ?? undefined + }, + limit: ISSUES_LIMIT + }); + }; + + const handleBySeverityButtonClick = () => { + onGetIssues({ + query: { + environment: environmentId ?? undefined, + sortBy: "severity" + }, + limit: ISSUES_LIMIT + }); + }; + + const { data: about } = useGetAboutQuery(); + + const isBySeverityButtonVisible = Boolean( + about && + getFeatureFlagValue( + about, + FeatureFlag.IS_INSIGHT_SEVERITY_SORTING_ENABLED + ) + ); + + return ( + + + Top 10 Issues + + + + + + By Criticality + + + + + {isBySeverityButtonVisible && ( + <> + + + + + + By Severity + + + + + + )} + + + + ); +}; diff --git a/src/components/Admin/Home/Overview/TopIssuesWidget/styles.ts b/src/components/Admin/Home/Overview/TopIssuesWidget/styles.ts new file mode 100644 index 000000000..f38762be7 --- /dev/null +++ b/src/components/Admin/Home/Overview/TopIssuesWidget/styles.ts @@ -0,0 +1,62 @@ +import styled from "styled-components"; +import { + subheading1MediumTypography, + subheading2RegularTypography +} from "../../../../common/App/typographies"; + +export const Container = styled.div` + display: flex; + flex-direction: column; + justify-content: space-between; + flex-grow: 1; +`; + +export const Title = styled.span` + ${subheading1MediumTypography} + color: ${({ theme }) => theme.colors.v3.text.primary}; +`; + +export const ButtonsContainer = styled.div` + display: flex; + align-items: flex-end; +`; + +export const IconContainer = styled.span` + height: 40px; + width: 40px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + background: ${({ theme }) => theme.colors.v3.surface.primary}; +`; + +export const Button = styled.button` + ${subheading2RegularTypography} + color: ${({ theme }) => theme.colors.v3.text.primary}; + display: flex; + align-items: center; + gap: 8px; + background: none; + border: none; + text-transform: capitalize; + padding: 0; + cursor: pointer; +`; + +export const ByCriticalityButton = styled(Button)` + padding-right: 10px; +`; + +export const BySeverityButton = styled(Button)` + padding-left: 23px; +`; + +export const ChevronIconContainer = styled.div` + color: ${({ theme }) => theme.colors.v3.icon.tertiary}; +`; + +export const Divider = styled.img` + width: 20px; + height: 69px; +`; diff --git a/src/components/Admin/Home/Overview/TopIssuesWidget/types.ts b/src/components/Admin/Home/Overview/TopIssuesWidget/types.ts new file mode 100644 index 000000000..4e9444436 --- /dev/null +++ b/src/components/Admin/Home/Overview/TopIssuesWidget/types.ts @@ -0,0 +1,5 @@ +import type { IssuesSidebarQuery } from "../../../common/IssuesSidebarOverlay/types"; + +export interface TopIssuesWidgetProps { + onGetIssues: (query: IssuesSidebarQuery) => void; +} diff --git a/src/components/Admin/Home/Overview/index.tsx b/src/components/Admin/Home/Overview/index.tsx index b0652b542..e1080c9ba 100644 --- a/src/components/Admin/Home/Overview/index.tsx +++ b/src/components/Admin/Home/Overview/index.tsx @@ -2,24 +2,23 @@ import { useTheme } from "styled-components"; import { getThemeKind } from "../../../common/App/styles"; import { HomeSection } from "../HomeSection"; import * as s from "./styles"; +import { TopIssuesWidget } from "./TopIssuesWidget"; +import type { OverviewProps } from "./types"; -export const Overview = () => { +export const Overview = ({ onGetIssues }: OverviewProps) => { const theme = useTheme(); const themeKind = getThemeKind(theme); return ( - {Array(4) - .fill(null) - .map((_, i) => ( - - ))} + + {[1, 2, 3].map((x) => ( + + ))} ); diff --git a/src/components/Admin/Home/Overview/types.ts b/src/components/Admin/Home/Overview/types.ts new file mode 100644 index 000000000..f35f206fd --- /dev/null +++ b/src/components/Admin/Home/Overview/types.ts @@ -0,0 +1,5 @@ +import type { IssuesSidebarQuery } from "../../common/IssuesSidebarOverlay/types"; + +export interface OverviewProps { + onGetIssues: (query: IssuesSidebarQuery) => void; +} diff --git a/src/components/Admin/Home/index.tsx b/src/components/Admin/Home/index.tsx index 620225cae..5b38cae18 100644 --- a/src/components/Admin/Home/index.tsx +++ b/src/components/Admin/Home/index.tsx @@ -1,12 +1,33 @@ +import { useState } from "react"; +import { IssuesSidebarOverlay } from "../common/IssuesSidebarOverlay"; +import type { IssuesSidebarQuery } from "../common/IssuesSidebarOverlay/types"; import { Environments } from "./Environments"; import { Overview } from "./Overview"; import { Reports } from "./Reports"; import * as s from "./styles"; -export const Home = () => ( - - - - - -); +export const Home = () => { + const [issuesSidebarQuery, setIssuesSidebarQuery] = + useState(); + + const handleIssuesSidebarClose = () => { + setIssuesSidebarQuery(undefined); + }; + + const handleGetIssues = (query: IssuesSidebarQuery) => { + setIssuesSidebarQuery(query); + }; + + return ( + + + + + + + ); +}; diff --git a/src/components/Admin/Reports/CodeIssues/index.tsx b/src/components/Admin/Reports/CodeIssues/index.tsx index 0c654a9c3..3d4ea04bf 100644 --- a/src/components/Admin/Reports/CodeIssues/index.tsx +++ b/src/components/Admin/Reports/CodeIssues/index.tsx @@ -1,10 +1,12 @@ -import { useEffect, useRef, useState } from "react"; -import { CSSTransition } from "react-transition-group"; +import { useMemo, useState } from "react"; import { useAdminDispatch, useAdminSelector } from "../../../../containers/Admin/hooks"; -import type { IssueCriticality } from "../../../../redux/services/types"; +import type { + GetIssuesPayload, + IssueCriticality +} from "../../../../redux/services/types"; import { setCriticalityLevels, setPeriodInDays, @@ -21,7 +23,7 @@ import { } from "../../../../redux/slices/issuesReportSlice"; import { IssuesReport } from "../../../common/IssuesReport"; import type { TargetScope } from "../../../common/IssuesReport/types"; -import { IssuesSidebar } from "./IssuesSidebar"; +import { IssuesSidebarOverlay } from "../../common/IssuesSidebarOverlay"; import * as s from "./styles"; export const MIN_SIDEBAR_WIDTH = 382; // in pixels @@ -43,21 +45,10 @@ export const getDefaultSidebarWidth = (windowWidth: number) => { export const CodeIssues = () => { const [isIssuesSidebarOpen, setIsIssuesSidebarOpen] = useState(false); - const [scope, setScope] = useState<{ value: string; displayName?: string }>(); + const [scope, setScope] = useState(); const [activeTileIds, setActiveTileIds] = useState( undefined ); - const sidebarContainerRef = useRef(null); - const overlayRef = useRef(null); - const [isIssuesSidebarTransitioning, setIsIssuesSidebarTransitioning] = - useState(false); - const [windowWidth, setWindowWidth] = useState(window.innerWidth); - const defaultSidebarWidth = getDefaultSidebarWidth(windowWidth); - const [isResizeHandlePressed, setIsResizeHandlePressed] = useState(false); - const [startX, setStartX] = useState(0); - const [left, setLeft] = useState(windowWidth - defaultSidebarWidth); - const [startLeft, setStartLeft] = useState(0); - const selectedEnvironmentId = useAdminSelector( (state) => state.codeIssuesReport.selectedEnvironmentId ); @@ -82,6 +73,30 @@ export const CodeIssues = () => { (state) => state.codeIssuesReport.selectedEndpoints ); + const query: Partial = useMemo( + () => ({ + environment: selectedEnvironmentId ?? undefined, + scopedSpanCodeObjectId: + viewLevel === "endpoints" ? scope?.value : undefined, + services: + viewLevel === "services" + ? scope?.value + ? [scope.value] + : [] + : viewLevel === "endpoints" && selectedService + ? [selectedService] + : [] + }), + [scope?.value, viewLevel, selectedEnvironmentId, selectedService] + ); + + const issuesSidebarQuery = useMemo( + () => ({ + query + }), + [query] + ); + const dispatch = useAdminDispatch(); const handleTileTitleClick = ( @@ -145,65 +160,6 @@ export const CodeIssues = () => { setActiveTileIds(undefined); }; - const handleIssuesSidebarTransitionStart = () => { - setIsIssuesSidebarTransitioning(true); - }; - - const handleIssuesSidebarTransitionEnd = () => { - setIsIssuesSidebarTransitioning(false); - }; - - const handleResizeHandleMouseDown = (e: React.MouseEvent) => { - setIsResizeHandlePressed(true); - setStartX(e.clientX); - setStartLeft(left); - }; - - const handleWindowResize = () => { - setWindowWidth(window.innerWidth); - }; - - useEffect(() => { - window.addEventListener("resize", handleWindowResize); - - return () => { - window.removeEventListener("resize", handleWindowResize); - }; - }, []); - - useEffect(() => { - const newLeft = windowWidth - getDefaultSidebarWidth(windowWidth); - setLeft(newLeft); - }, [windowWidth]); - - useEffect(() => { - if (!isResizeHandlePressed) { - return; - } - - const handleMouseMove = (e: MouseEvent) => { - const newLeft = startLeft + (e.clientX - startX); - if ( - newLeft >= windowWidth - MAX_SIDEBAR_WIDTH && - newLeft <= windowWidth - MIN_SIDEBAR_WIDTH - ) { - setLeft(newLeft); - } - }; - - const handleMouseUp = () => { - setIsResizeHandlePressed(false); - }; - - document.addEventListener("mousemove", handleMouseMove); - document.addEventListener("mouseup", handleMouseUp); - - return () => { - document.removeEventListener("mousemove", handleMouseMove); - document.removeEventListener("mouseup", handleMouseUp); - }; - }, [isResizeHandlePressed, windowWidth, startX, startLeft, left]); - return ( { onSelectedServiceChange={handleSelectedServiceChange} activeTileIds={activeTileIds} /> - - - - - - - - + ); }; diff --git a/src/components/Admin/Reports/CodeIssues/IssuesSidebar/SuggestionBar/SuggestionBar.stories.tsx b/src/components/Admin/common/IssuesSidebarOverlay/IssuesSidebar/SuggestionBar/SuggestionBar.stories.tsx similarity index 100% rename from src/components/Admin/Reports/CodeIssues/IssuesSidebar/SuggestionBar/SuggestionBar.stories.tsx rename to src/components/Admin/common/IssuesSidebarOverlay/IssuesSidebar/SuggestionBar/SuggestionBar.stories.tsx diff --git a/src/components/Admin/Reports/CodeIssues/IssuesSidebar/SuggestionBar/index.tsx b/src/components/Admin/common/IssuesSidebarOverlay/IssuesSidebar/SuggestionBar/index.tsx similarity index 98% rename from src/components/Admin/Reports/CodeIssues/IssuesSidebar/SuggestionBar/index.tsx rename to src/components/Admin/common/IssuesSidebarOverlay/IssuesSidebar/SuggestionBar/index.tsx index 562a1e606..1b79ced41 100644 --- a/src/components/Admin/Reports/CodeIssues/IssuesSidebar/SuggestionBar/index.tsx +++ b/src/components/Admin/common/IssuesSidebarOverlay/IssuesSidebar/SuggestionBar/index.tsx @@ -1,5 +1,6 @@ import { useEffect, useRef, useState } from "react"; import { useGetIssueRecommendationsQuery } from "../../../../../../redux/services/digma"; +import { RecommendationPriority } from "../../../../../../redux/services/types"; import { intersperse } from "../../../../../../utils/intersperse"; import { CrossIcon } from "../../../../../common/icons/16px/CrossIcon"; import { LightBulbWithScrewIcon } from "../../../../../common/icons/16px/LightBulbWithScrewIcon"; @@ -10,7 +11,6 @@ import { Toggle } from "../../../../../common/v3/Toggle"; import type { ToggleOption } from "../../../../../common/v3/Toggle/types"; import * as s from "./styles"; import type { AssetsViewMode, SuggestionBarProps } from "./types"; -import { RecommendationPriority } from "./types"; const assetsViewModeToggleOptions: ToggleOption[] = [ { label: "Action items", value: "actionItems" }, diff --git a/src/components/Admin/Reports/CodeIssues/IssuesSidebar/SuggestionBar/styles.ts b/src/components/Admin/common/IssuesSidebarOverlay/IssuesSidebar/SuggestionBar/styles.ts similarity index 100% rename from src/components/Admin/Reports/CodeIssues/IssuesSidebar/SuggestionBar/styles.ts rename to src/components/Admin/common/IssuesSidebarOverlay/IssuesSidebar/SuggestionBar/styles.ts diff --git a/src/components/Admin/Reports/CodeIssues/IssuesSidebar/SuggestionBar/types.ts b/src/components/Admin/common/IssuesSidebarOverlay/IssuesSidebar/SuggestionBar/types.ts similarity index 60% rename from src/components/Admin/Reports/CodeIssues/IssuesSidebar/SuggestionBar/types.ts rename to src/components/Admin/common/IssuesSidebarOverlay/IssuesSidebar/SuggestionBar/types.ts index 27903b2c9..c5cc51807 100644 --- a/src/components/Admin/Reports/CodeIssues/IssuesSidebar/SuggestionBar/types.ts +++ b/src/components/Admin/common/IssuesSidebarOverlay/IssuesSidebar/SuggestionBar/types.ts @@ -4,9 +4,3 @@ export interface SuggestionBarProps { } export type AssetsViewMode = "actionItems" | "code"; - -export enum RecommendationPriority { - Low = "low", - Medium = "medium", - High = "high" -} diff --git a/src/components/Admin/Reports/CodeIssues/IssuesSidebar/index.tsx b/src/components/Admin/common/IssuesSidebarOverlay/IssuesSidebar/index.tsx similarity index 84% rename from src/components/Admin/Reports/CodeIssues/IssuesSidebar/index.tsx rename to src/components/Admin/common/IssuesSidebarOverlay/IssuesSidebar/index.tsx index 2ddb09c89..6107fb2f5 100644 --- a/src/components/Admin/Reports/CodeIssues/IssuesSidebar/index.tsx +++ b/src/components/Admin/common/IssuesSidebarOverlay/IssuesSidebar/index.tsx @@ -53,12 +53,12 @@ const getInsightToShowJiraHint = (insights: CodeObjectInsight[]): number => { export const IssuesSidebar = ({ onClose, - scope, - environmentId, - viewLevel, isTransitioning, isResizing, - onResizeHandleMouseDown + onResizeHandleMouseDown, + query, + scopeDisplayName, + isPaginationEnabled = true }: IssuesSidebarProps) => { const [infoToOpenJiraTicket, setInfoToOpenJiraTicket] = useState>(); @@ -78,15 +78,12 @@ export const IssuesSidebar = ({ const theme = useTheme(); const { data, isFetching, refetch } = useGetIssuesQuery( { - environment: environmentId, - scopedSpanCodeObjectId: - viewLevel === "endpoints" && scope ? scope.value : undefined, showDismissed: viewMode === ViewMode.OnlyDismissed, - services: viewLevel === "services" && scope ? [scope.value] : undefined, sortBy: "criticalinsights", sortOrder: "desc", page, - pageSize: PAGE_SIZE + pageSize: PAGE_SIZE, + ...query }, { refetchOnMountOrArgChange: true @@ -178,8 +175,8 @@ export const IssuesSidebar = ({ const extendedScope: Scope = { span: { - displayName: scope?.displayName ?? scope?.value ?? "", - spanCodeObjectId: scope?.value ?? "", + displayName: scopeDisplayName ?? query?.scopedSpanCodeObjectId ?? "", + spanCodeObjectId: query?.scopedSpanCodeObjectId ?? "", methodId: null, serviceName: null, role: null @@ -205,13 +202,15 @@ export const IssuesSidebar = ({ onClick={handleSidebarCloseButtonClick} /> - + {scopeDisplayName && ( + + )} @@ -220,28 +219,26 @@ export const IssuesSidebar = ({ {data ? ( data.insights.length > 0 ? ( - {environmentId && - data.insights.map((insight, i) => ( - - ))} + {data.insights.map((insight, i) => ( + + ))} ) : ( - {totalCount > 0 && ( + {isPaginationEnabled && totalCount > 0 && ( <> diff --git a/src/components/Admin/Reports/CodeIssues/IssuesSidebar/styles.ts b/src/components/Admin/common/IssuesSidebarOverlay/IssuesSidebar/styles.ts similarity index 100% rename from src/components/Admin/Reports/CodeIssues/IssuesSidebar/styles.ts rename to src/components/Admin/common/IssuesSidebarOverlay/IssuesSidebar/styles.ts diff --git a/src/components/Admin/Reports/CodeIssues/IssuesSidebar/types.ts b/src/components/Admin/common/IssuesSidebarOverlay/IssuesSidebar/types.ts similarity index 63% rename from src/components/Admin/Reports/CodeIssues/IssuesSidebar/types.ts rename to src/components/Admin/common/IssuesSidebarOverlay/IssuesSidebar/types.ts index 23d558eb6..694078b1a 100644 --- a/src/components/Admin/Reports/CodeIssues/IssuesSidebar/types.ts +++ b/src/components/Admin/common/IssuesSidebarOverlay/IssuesSidebar/types.ts @@ -1,17 +1,14 @@ import type { MouseEvent } from "react"; -import type { IssuesReportViewLevel } from "../../../../../redux/slices/issuesReportSlice"; +import type { GetIssuesPayload } from "../../../../../redux/services/types"; export interface IssuesSidebarProps { onClose: () => void; - environmentId?: string; - scope?: { - value: string; - displayName?: string; - }; - viewLevel: IssuesReportViewLevel; + scopeDisplayName?: string; isTransitioning: boolean; isResizing?: boolean; onResizeHandleMouseDown: (e: MouseEvent) => void; + query?: Partial; + isPaginationEnabled?: boolean; } export interface DrawerContainerProps { diff --git a/src/components/Admin/common/IssuesSidebarOverlay/index.tsx b/src/components/Admin/common/IssuesSidebarOverlay/index.tsx new file mode 100644 index 000000000..8e4267680 --- /dev/null +++ b/src/components/Admin/common/IssuesSidebarOverlay/index.tsx @@ -0,0 +1,155 @@ +import { useEffect, useRef, useState } from "react"; +import { CSSTransition } from "react-transition-group"; +import { isUndefined } from "../../../../typeGuards/isUndefined"; +import { IssuesSidebar } from "./IssuesSidebar"; +import * as s from "./styles"; +import type { IssuesSidebarOverlayProps } from "./types"; + +export const MIN_SIDEBAR_WIDTH = 382; // in pixels +export const MAX_SIDEBAR_WIDTH = 640; // in pixels +export const DEFAULT_SIDEBAR_WIDTH_RATIO = 0.33; + +export const getDefaultSidebarWidth = (windowWidth: number) => { + const defaultWidth = windowWidth * DEFAULT_SIDEBAR_WIDTH_RATIO; + if (defaultWidth > MAX_SIDEBAR_WIDTH) { + return MAX_SIDEBAR_WIDTH; + } + + if (defaultWidth < MIN_SIDEBAR_WIDTH) { + return MIN_SIDEBAR_WIDTH; + } + + return defaultWidth; +}; + +export const IssuesSidebarOverlay = ({ + isSidebarOpen, + onSidebarClose, + issuesSidebarQuery, + scopeDisplayName +}: IssuesSidebarOverlayProps) => { + const sidebarContainerRef = useRef(null); + const overlayRef = useRef(null); + const [isIssuesSidebarTransitioning, setIsIssuesSidebarTransitioning] = + useState(false); + const [windowWidth, setWindowWidth] = useState(window.innerWidth); + const defaultSidebarWidth = getDefaultSidebarWidth(windowWidth); + const [isResizeHandlePressed, setIsResizeHandlePressed] = useState(false); + const [startX, setStartX] = useState(0); + const [left, setLeft] = useState(windowWidth - defaultSidebarWidth); + const [startLeft, setStartLeft] = useState(0); + const isPaginationEnabled = isUndefined(issuesSidebarQuery?.limit); + + const handleIssuesSidebarClose = () => { + onSidebarClose(); + }; + + const handleIssuesSidebarTransitionStart = () => { + setIsIssuesSidebarTransitioning(true); + }; + + const handleIssuesSidebarTransitionEnd = () => { + setIsIssuesSidebarTransitioning(false); + }; + + const handleResizeHandleMouseDown = (e: React.MouseEvent) => { + setIsResizeHandlePressed(true); + setStartX(e.clientX); + setStartLeft(left); + }; + + const handleWindowResize = () => { + setWindowWidth(window.innerWidth); + }; + + useEffect(() => { + window.addEventListener("resize", handleWindowResize); + + return () => { + window.removeEventListener("resize", handleWindowResize); + }; + }, []); + + useEffect(() => { + const newLeft = windowWidth - getDefaultSidebarWidth(windowWidth); + setLeft(newLeft); + }, [windowWidth]); + + useEffect(() => { + if (!isResizeHandlePressed) { + return; + } + + const handleMouseMove = (e: MouseEvent) => { + const newLeft = startLeft + (e.clientX - startX); + if ( + newLeft >= windowWidth - MAX_SIDEBAR_WIDTH && + newLeft <= windowWidth - MIN_SIDEBAR_WIDTH + ) { + setLeft(newLeft); + } + }; + + const handleMouseUp = () => { + setIsResizeHandlePressed(false); + }; + + document.addEventListener("mousemove", handleMouseMove); + document.addEventListener("mouseup", handleMouseUp); + + return () => { + document.removeEventListener("mousemove", handleMouseMove); + document.removeEventListener("mouseup", handleMouseUp); + }; + }, [isResizeHandlePressed, windowWidth, startX, startLeft, left]); + + return ( + <> + + + + + + + + + + ); +}; diff --git a/src/components/Admin/common/IssuesSidebarOverlay/styles.ts b/src/components/Admin/common/IssuesSidebarOverlay/styles.ts new file mode 100644 index 000000000..913c0b2bd --- /dev/null +++ b/src/components/Admin/common/IssuesSidebarOverlay/styles.ts @@ -0,0 +1,60 @@ +import styled from "styled-components"; +import type { IssuesSidebarContainerProps, OverlayProps } from "./types"; + +export const TRANSITION_DURATION = 300; +export const overlayTransitionClassName = "overlay"; +export const sidebarContainerTransitionClassName = "sidebarContainer"; + +export const Overlay = styled.div` + position: fixed; + inset: 0; + background: #000; + opacity: ${({ $isVisible }) => ($isVisible ? 0.6 : 0)}; + + ${({ $transitionClassName, $transitionDuration }) => ` + &.${$transitionClassName}-enter { + opacity: 0; + } + + &.${$transitionClassName}-enter-active { + opacity: 0.6; + transition: opacity ${$transitionDuration}ms ease-out; + } + + &.${$transitionClassName}-exit { + opacity: 0.6; + } + + &.${$transitionClassName}-exit-active { + opacity: 0; + transition: opacity ${$transitionDuration}ms ease-out; + } + `} +`; + +export const IssuesSidebarContainer = styled.div` + position: absolute; + right: 0; + top: 0; + bottom: 0; + + ${({ $transitionClassName, $transitionDuration }) => ` + &.${$transitionClassName}-enter { + transform: translateX(100%); + } + + &.${$transitionClassName}-enter-active { + transform: translateX(0); + transition: transform ${$transitionDuration}ms ease-out; + } + + &.${$transitionClassName}-exit { + transform: translateX(0); + } + + &.${$transitionClassName}-exit-active { + transform: translateX(100%); + transition: transform ${$transitionDuration}ms ease-out; + } + `} +`; diff --git a/src/components/Admin/common/IssuesSidebarOverlay/types.ts b/src/components/Admin/common/IssuesSidebarOverlay/types.ts new file mode 100644 index 000000000..0fdeaef49 --- /dev/null +++ b/src/components/Admin/common/IssuesSidebarOverlay/types.ts @@ -0,0 +1,24 @@ +import type { GetIssuesPayload } from "../../../../redux/services/types"; + +export interface IssuesSidebarQuery { + query?: GetIssuesPayload; + limit?: number; +} + +export interface IssuesSidebarOverlayProps { + isSidebarOpen: boolean; + onSidebarClose: () => void; + issuesSidebarQuery?: IssuesSidebarQuery; + scopeDisplayName?: string; +} + +export interface OverlayProps { + $transitionDuration: number; + $transitionClassName: string; + $isVisible: boolean; +} + +export interface IssuesSidebarContainerProps { + $transitionDuration: number; + $transitionClassName: string; +} diff --git a/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/index.tsx b/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/index.tsx index 15febd7bc..798af1b76 100644 --- a/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/index.tsx +++ b/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/index.tsx @@ -64,7 +64,6 @@ export const InsightCardRenderer = ({ onRefresh, isMarkAsReadButtonEnabled, viewMode, - environmentId, onDismissalChange, onOpenSuggestion, tooltipBoundaryRef @@ -75,7 +74,8 @@ export const InsightCardRenderer = ({ const handleHistogramButtonClick = ( spanCodeObjectId: string, insightType: InsightType, - displayName: string + displayName: string, + environmentId: string ) => { if (platform === "Web") { switch (insightType) { diff --git a/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/insightCards/SpanDurationsInsightCard/types.ts b/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/insightCards/SpanDurationsInsightCard/types.ts index 329faf0a1..4e0ae1a54 100644 --- a/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/insightCards/SpanDurationsInsightCard/types.ts +++ b/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/insightCards/SpanDurationsInsightCard/types.ts @@ -6,7 +6,8 @@ export interface SpanDurationsInsightCardProps extends InsightCardCommonProps { onHistogramButtonClick: ( spanCodeObjectId: string, insightType: InsightType, - displayName: string + displayName: string, + environmentId: string ) => void; onLiveButtonClick: (codeObjectId: string) => void; } diff --git a/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/insightCards/SpanScalingInsightCard/types.ts b/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/insightCards/SpanScalingInsightCard/types.ts index ab4d6df50..0799c8dc7 100644 --- a/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/insightCards/SpanScalingInsightCard/types.ts +++ b/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/insightCards/SpanScalingInsightCard/types.ts @@ -19,6 +19,7 @@ export interface SpanScalingInsightCardProps extends InsightCardCommonProps { onHistogramButtonClick: ( spanCodeObjectId: string, insightType: InsightType, - displayName: string + displayName: string, + environmentId: string ) => void; } diff --git a/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/insightCards/common/InsightCard/index.tsx b/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/insightCards/common/InsightCard/index.tsx index 17c962d39..9f9ed919f 100644 --- a/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/insightCards/common/InsightCard/index.tsx +++ b/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/insightCards/common/InsightCard/index.tsx @@ -133,7 +133,8 @@ export const InsightCard = ({ onOpenHistogram( insight.spanInfo.spanCodeObjectId, insight.type, - insight.spanInfo.displayName + insight.spanInfo.displayName, + insight.environment ); } }; diff --git a/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/insightCards/common/InsightCard/types.ts b/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/insightCards/common/InsightCard/types.ts index b6468872a..42f2c4cd3 100644 --- a/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/insightCards/common/InsightCard/types.ts +++ b/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/insightCards/common/InsightCard/types.ts @@ -16,7 +16,8 @@ export interface InsightCardProps { onOpenHistogram?: ( spanCodeObjectId: string, insightType: InsightType, - displayName: string + displayName: string, + environmentId: string ) => void; onRecalculate: (insightId: string) => void; onRefresh: (insightType: InsightType, spanCodeObjectId?: string) => void; diff --git a/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/types.ts b/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/types.ts index f3478c1ac..74a2cac56 100644 --- a/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/types.ts +++ b/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/types.ts @@ -13,7 +13,6 @@ export interface InsightCardRendererProps { onRefresh: () => void; isMarkAsReadButtonEnabled: boolean; viewMode: InsightCardViewMode; - environmentId: string; onDismissalChange: (action: string, insightId: string) => void; onOpenSuggestion?: (insightId: string) => void; tooltipBoundaryRef?: RefObject; diff --git a/src/components/Insights/InsightsCatalog/InsightsPage/index.tsx b/src/components/Insights/InsightsCatalog/InsightsPage/index.tsx index 8b8cb50db..21430fbbd 100644 --- a/src/components/Insights/InsightsCatalog/InsightsPage/index.tsx +++ b/src/components/Insights/InsightsCatalog/InsightsPage/index.tsx @@ -227,7 +227,6 @@ export const InsightsPage = ({ onRefresh={onRefresh} isMarkAsReadButtonEnabled={isMarkAsReadButtonEnabled} viewMode={isAtSpan ? "full" : "compact"} - environmentId={environment.id} onDismissalChange={handleDismissalChange} tooltipBoundaryRef={listRef} /> diff --git a/src/components/Insights/InsightsCatalog/index.tsx b/src/components/Insights/InsightsCatalog/index.tsx index 95a79a326..af37141b8 100644 --- a/src/components/Insights/InsightsCatalog/index.tsx +++ b/src/components/Insights/InsightsCatalog/index.tsx @@ -225,28 +225,26 @@ export const InsightsCatalog = ({ onChange={handleSearchInputChange} value={searchInputValue} /> - { - setSorting(val); - }} - options={[ - ...(isIssuesView - ? [ - { - value: SORTING_CRITERION.CRITICAL_INSIGHTS, - label: "Critical issues", - defaultOrder: SORTING_ORDER.DESC - } - ] - : []), - { - value: SORTING_CRITERION.LATEST, - label: "Latest", - defaultOrder: SORTING_ORDER.DESC - } - ]} - defaultSorting={sorting} - /> + {isIssuesView && ( + { + setSorting(val); + }} + options={[ + { + value: SORTING_CRITERION.CRITICAL_INSIGHTS, + label: "Critical issues", + defaultOrder: SORTING_ORDER.DESC + }, + { + value: SORTING_CRITERION.LATEST, + label: "Latest", + defaultOrder: SORTING_ORDER.DESC + } + ]} + defaultSorting={sorting} + /> + )} )} diff --git a/src/components/common/App/typographies.ts b/src/components/common/App/typographies.ts index 7de8878ae..7cbfcb7dd 100644 --- a/src/components/common/App/typographies.ts +++ b/src/components/common/App/typographies.ts @@ -220,6 +220,11 @@ export const subheading1RegularTypography = css` font-weight: ${typographies.subheading1.fontWeight.regular}; `; +export const subheading1MediumTypography = css` + font-size: ${typographies.subheading1.fontSize}px; + font-weight: ${typographies.subheading1.fontWeight.medium}; +`; + export const subheading1SemiboldTypography = css` font-size: ${typographies.subheading1.fontSize}px; font-weight: ${typographies.subheading1.fontWeight.semibold}; diff --git a/src/containers/Admin/store.ts b/src/containers/Admin/store.ts index 8227e5ab8..422899208 100644 --- a/src/containers/Admin/store.ts +++ b/src/containers/Admin/store.ts @@ -9,6 +9,7 @@ import { appSlice } from "../../redux/slices/appSlice"; import { authSlice } from "../../redux/slices/authSlice"; import issuesReportSlice from "../../redux/slices/issuesReportSlice"; import { persistSlice } from "../../redux/slices/persistSlice"; +import { scopeSlice } from "../../redux/slices/scopeSlice"; import { getRememberEnhancer } from "../../redux/utils/getRememberEnhancer"; import { APP_ID } from "./constants"; @@ -19,6 +20,7 @@ const persistPrefix = `${PERSIST_PREFIX}${APP_ID}-`; const reducer = rememberReducer({ app: appSlice.reducer, + scope: scopeSlice.reducer, auth: authSlice.reducer, codeIssuesReport: issuesReportSlice, persist: persistSlice.reducer, diff --git a/src/featureFlags.ts b/src/featureFlags.ts index a0a054c15..51224956f 100644 --- a/src/featureFlags.ts +++ b/src/featureFlags.ts @@ -29,7 +29,8 @@ export const featureFlagMinBackendVersions: Record = { [FeatureFlag.IS_GLOBAL_ERROR_PIN_ENABLED]: "0.3.147", [FeatureFlag.IS_GLOBAL_ERROR_DISMISS_ENABLED]: "0.3.148", [FeatureFlag.IS_GLOBAL_ERROR_LAST_DAYS_FILTER_ENABLED]: "0.3.149", - [FeatureFlag.IS_DURATION_BREAKDOWN_PERCENTAGE_OF_CALLS_ENABLED]: "0.3.193" + [FeatureFlag.IS_DURATION_BREAKDOWN_PERCENTAGE_OF_CALLS_ENABLED]: "0.3.193", + [FeatureFlag.IS_INSIGHT_SEVERITY_SORTING_ENABLED]: "0.3.204" }; export const getFeatureFlagValue = ( diff --git a/src/redux/services/types.ts b/src/redux/services/types.ts index e2c4fdb31..424244aaf 100644 --- a/src/redux/services/types.ts +++ b/src/redux/services/types.ts @@ -1,4 +1,3 @@ -import type { RecommendationPriority } from "../../components/Admin/Reports/CodeIssues/IssuesSidebar/SuggestionBar/types"; import type { DeploymentType, EnvironmentType @@ -217,6 +216,12 @@ export interface IssueRecommendationSource { url: string; } +export enum RecommendationPriority { + Low = "low", + Medium = "medium", + High = "high" +} + export interface IssueRecommendation { title: string; priority: RecommendationPriority; diff --git a/src/redux/slices/persistSlice.ts b/src/redux/slices/persistSlice.ts index 741833df3..0ab5d7ed0 100644 --- a/src/redux/slices/persistSlice.ts +++ b/src/redux/slices/persistSlice.ts @@ -13,7 +13,7 @@ const initialState: PersistState = { }; export const persistSlice = createSlice({ - name: "persistSlice", + name: "persist", initialState, reducers: { setIsInsightJiraTicketHintShown: ( diff --git a/src/redux/slices/scopeSlice.ts b/src/redux/slices/scopeSlice.ts new file mode 100644 index 000000000..7a67f197d --- /dev/null +++ b/src/redux/slices/scopeSlice.ts @@ -0,0 +1,32 @@ +import type { PayloadAction } from "@reduxjs/toolkit"; +import { createSlice } from "@reduxjs/toolkit"; +import { globalClear } from "../actions"; +import { STATE_VERSION } from "../constants"; +import type { BaseState } from "./types"; + +export interface ScopeState extends BaseState { + environmentId: string | null; +} + +const initialState: ScopeState = { + version: STATE_VERSION, + environmentId: null +}; + +export const scopeSlice = createSlice({ + name: "scope", + initialState, + reducers: { + setEnvironmentId: (state, action: PayloadAction) => { + state.environmentId = action.payload; + }, + clear: () => initialState + }, + extraReducers: (builder) => { + builder.addCase(globalClear, () => initialState); + } +}); + +export const { setEnvironmentId } = scopeSlice.actions; + +export default scopeSlice.reducer; diff --git a/src/types.ts b/src/types.ts index c098e8c86..db7696fc2 100644 --- a/src/types.ts +++ b/src/types.ts @@ -29,7 +29,8 @@ export enum FeatureFlag { IS_GLOBAL_ERROR_PIN_ENABLED, IS_GLOBAL_ERROR_DISMISS_ENABLED, IS_GLOBAL_ERROR_LAST_DAYS_FILTER_ENABLED, - IS_DURATION_BREAKDOWN_PERCENTAGE_OF_CALLS_ENABLED + IS_DURATION_BREAKDOWN_PERCENTAGE_OF_CALLS_ENABLED, + IS_INSIGHT_SEVERITY_SORTING_ENABLED } export enum InsightType { From 180033d08e4b578625dd1607d5ea80c59d83a693 Mon Sep 17 00:00:00 2001 From: Kyrylo Shmidt Date: Tue, 28 Jan 2025 12:46:31 +0100 Subject: [PATCH 2/2] Fix types --- .../Admin/common/IssuesSidebarOverlay/IssuesSidebar/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Admin/common/IssuesSidebarOverlay/IssuesSidebar/types.ts b/src/components/Admin/common/IssuesSidebarOverlay/IssuesSidebar/types.ts index 694078b1a..5df782c58 100644 --- a/src/components/Admin/common/IssuesSidebarOverlay/IssuesSidebar/types.ts +++ b/src/components/Admin/common/IssuesSidebarOverlay/IssuesSidebar/types.ts @@ -7,7 +7,7 @@ export interface IssuesSidebarProps { isTransitioning: boolean; isResizing?: boolean; onResizeHandleMouseDown: (e: MouseEvent) => void; - query?: Partial; + query?: GetIssuesPayload; isPaginationEnabled?: boolean; }