From acf93896f68aef35f09faaefc57e221d4e279265 Mon Sep 17 00:00:00 2001 From: opoliarush Date: Mon, 7 Oct 2024 23:28:07 +0300 Subject: [PATCH 1/2] Added linked endpoints --- .../LinkedEndpointsMenu.stories.tsx | 32 ++++++++++++ .../ScopeBar/LinkedEndpointsMenu/index.tsx | 37 ++++++++++++++ .../ScopeBar/LinkedEndpointsMenu/styles.ts | 34 +++++++++++++ .../ScopeBar/LinkedEndpointsMenu/types.ts | 6 +++ .../Navigation/ScopeBar/ScopeBar.stories.tsx | 31 +++++++++-- src/components/Navigation/ScopeBar/index.tsx | 51 ++++++++++++++++++- src/components/Navigation/ScopeBar/styles.ts | 5 ++ src/components/Navigation/ScopeBar/types.ts | 2 + src/components/Navigation/SpanInfo/types.ts | 7 +++ src/components/Navigation/index.tsx | 1 + src/components/Navigation/tracking.ts | 1 + .../common/icons/14px/ChainIcon.tsx | 18 +++++++ 12 files changed, 221 insertions(+), 4 deletions(-) create mode 100644 src/components/Navigation/ScopeBar/LinkedEndpointsMenu/LinkedEndpointsMenu.stories.tsx create mode 100644 src/components/Navigation/ScopeBar/LinkedEndpointsMenu/index.tsx create mode 100644 src/components/Navigation/ScopeBar/LinkedEndpointsMenu/styles.ts create mode 100644 src/components/Navigation/ScopeBar/LinkedEndpointsMenu/types.ts create mode 100644 src/components/common/icons/14px/ChainIcon.tsx diff --git a/src/components/Navigation/ScopeBar/LinkedEndpointsMenu/LinkedEndpointsMenu.stories.tsx b/src/components/Navigation/ScopeBar/LinkedEndpointsMenu/LinkedEndpointsMenu.stories.tsx new file mode 100644 index 000000000..388c31460 --- /dev/null +++ b/src/components/Navigation/ScopeBar/LinkedEndpointsMenu/LinkedEndpointsMenu.stories.tsx @@ -0,0 +1,32 @@ +import { Meta, StoryObj } from "@storybook/react"; + +import { LinkedEndpointsMenu } from "."; + +// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction +const meta: Meta = { + title: "Navigation/ScopeBar/LinkedEndpointsMenu", + component: LinkedEndpointsMenu, + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/react/configure/story-layout + layout: "fullscreen" + } +}; + +export default meta; + +export const Default: StoryObj = { + args: { + endpoints: [ + { + spanCodeObjectId: "span:codeObject", + displayName: "testMethodCall", + environment: "TEST" + }, + { + spanCodeObjectId: "span:codeObject2", + displayName: "restMethodCall", + environment: "local" + } + ] + } +}; diff --git a/src/components/Navigation/ScopeBar/LinkedEndpointsMenu/index.tsx b/src/components/Navigation/ScopeBar/LinkedEndpointsMenu/index.tsx new file mode 100644 index 000000000..0eeccb422 --- /dev/null +++ b/src/components/Navigation/ScopeBar/LinkedEndpointsMenu/index.tsx @@ -0,0 +1,37 @@ +import { sendUserActionTrackingEvent } from "../../../../utils/actions/sendUserActionTrackingEvent"; +import { HTTPClientIcon } from "../../../common/icons/HTTPClientIcon"; +import { MenuList } from "../../common/MenuList"; +import { LinkedEndpoint } from "../../SpanInfo/types"; +import { trackingEvents } from "../../tracking"; +import * as s from "./styles"; +import { LinkedEndpointsMenuProps } from "./types"; + +export const LinkedEndpointsMenu = ({ + endpoints, + onEndpointsClick +}: LinkedEndpointsMenuProps) => { + const handleMenuItemClick = (endpoint: LinkedEndpoint) => { + sendUserActionTrackingEvent(trackingEvents.CODE_LOCATION_SELECTED); + onEndpointsClick(endpoint); + }; + + return ( + + This client assets calls the following endpoint: + ({ + id: x.spanCodeObjectId, + customContent: ( + handleMenuItemClick(x)}> + + {x.displayName} + + ), + disabled: false + })) + ]} + /> + + ); +}; diff --git a/src/components/Navigation/ScopeBar/LinkedEndpointsMenu/styles.ts b/src/components/Navigation/ScopeBar/LinkedEndpointsMenu/styles.ts new file mode 100644 index 000000000..0f250e712 --- /dev/null +++ b/src/components/Navigation/ScopeBar/LinkedEndpointsMenu/styles.ts @@ -0,0 +1,34 @@ +import styled from "styled-components"; +import { + bodyRegularTypography, + footnoteRegularTypography +} from "../../../common/App/typographies"; + +export const Container = styled.div` + display: flex; + flex-direction: column; + gap: 4px; +`; + +export const MenuItem = styled.div` + display: flex; + flex-direction: 4px; + padding: 0 8px; + gap: 4px; + align-items: center; + color: ${({ theme }) => theme.colors.v3.icon.brandSecondary}; + cursor: pointer; + ${bodyRegularTypography} + + &:hover { + text-decoration: underline; + } +`; + +export const Title = styled.div` + ${footnoteRegularTypography} + color: ${({ theme }) => theme.colors.v3.text.tertiary}; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; +`; diff --git a/src/components/Navigation/ScopeBar/LinkedEndpointsMenu/types.ts b/src/components/Navigation/ScopeBar/LinkedEndpointsMenu/types.ts new file mode 100644 index 000000000..64195706a --- /dev/null +++ b/src/components/Navigation/ScopeBar/LinkedEndpointsMenu/types.ts @@ -0,0 +1,6 @@ +import { LinkedEndpoint } from "../../SpanInfo/types"; + +export interface LinkedEndpointsMenuProps { + endpoints: LinkedEndpoint[]; + onEndpointsClick: (endpoint: LinkedEndpoint) => void; +} diff --git a/src/components/Navigation/ScopeBar/ScopeBar.stories.tsx b/src/components/Navigation/ScopeBar/ScopeBar.stories.tsx index f225ffd09..d7d4bdb24 100644 --- a/src/components/Navigation/ScopeBar/ScopeBar.stories.tsx +++ b/src/components/Navigation/ScopeBar/ScopeBar.stories.tsx @@ -68,7 +68,19 @@ const mockedCodeContext: CodeContext = { export const Default: Story = { args: { scope: mockedScope, - codeContext: mockedCodeContext + codeContext: mockedCodeContext, + linkedEndpoints: [ + { + spanCodeObjectId: "span:codeObject", + displayName: "testMethodCall", + environment: "TEST" + }, + { + spanCodeObjectId: "span:codeObject2", + displayName: "restMethodCall", + environment: "local" + } + ] } }; @@ -94,7 +106,19 @@ export const HasMultipleCodeLocations: Story = { ] } }, - codeContext: mockedCodeContext + codeContext: mockedCodeContext, + linkedEndpoints: [ + { + spanCodeObjectId: "span:codeObject", + displayName: "testMethodCall", + environment: "TEST" + }, + { + spanCodeObjectId: "span:codeObject2", + displayName: "restMethodCall", + environment: "local" + } + ] } }; @@ -104,6 +128,7 @@ export const AlreadyAtCode: Story = { codeContext: { ...mockedCodeContext, methodId: mockedScope.span?.methodId ?? null - } + }, + linkedEndpoints: [] } }; diff --git a/src/components/Navigation/ScopeBar/index.tsx b/src/components/Navigation/ScopeBar/index.tsx index 489a09f84..afd8c859c 100644 --- a/src/components/Navigation/ScopeBar/index.tsx +++ b/src/components/Navigation/ScopeBar/index.tsx @@ -1,20 +1,24 @@ import { useEffect, useState } from "react"; import { history } from "../../../containers/Main/history"; import { isString } from "../../../typeGuards/isString"; +import { changeScope } from "../../../utils/actions/changeScope"; import { sendUserActionTrackingEvent } from "../../../utils/actions/sendUserActionTrackingEvent"; import { trackingEvents as mainTrackingEvents } from "../../Main/tracking"; import { CodeDetails, Scope } from "../../common/App/types"; import { NewPopover } from "../../common/NewPopover"; +import { ChainIcon } from "../../common/icons/14px/ChainIcon"; import { CrosshairIcon } from "../../common/icons/16px/CrosshairIcon"; import { MaximizeIcon } from "../../common/icons/16px/MaximizeIcon"; import { MinimizeIcon } from "../../common/icons/16px/MinimizeIcon"; import { EndpointIcon } from "../../common/icons/EndpointIcon"; import { NewIconButton } from "../../common/v3/NewIconButton"; import { Tooltip } from "../../common/v3/Tooltip"; +import { LinkedEndpoint } from "../SpanInfo/types"; import { actions } from "../actions"; import { Popup } from "../common/Popup"; import { trackingEvents } from "../tracking"; import { CodeContext, GoToCodeLocationPayload } from "../types"; +import { LinkedEndpointsMenu } from "./LinkedEndpointsMenu"; import { TargetButtonMenu } from "./TargetButtonMenu"; import * as s from "./styles"; import { ScopeBarProps } from "./types"; @@ -60,9 +64,12 @@ export const ScopeBar = ({ codeContext, isExpanded, onExpandCollapseChange, - isSpanInfoEnabled + isSpanInfoEnabled, + linkedEndpoints }: ScopeBarProps) => { const [isTargetButtonMenuOpen, setIsTargetButtonMenuOpen] = useState(false); + const [isLinkedEndpointsMenuOpen, setIsLinkedEndpointsMenuOpen] = + useState(false); const location = history.getCurrentLocation(); const spanDisplayName = scope?.span?.displayName; @@ -94,6 +101,8 @@ export const ScopeBar = ({ (scope.code.codeDetailsList.length > 1 || scope.code.relatedCodeDetailsList.length > 0); + const isLinkedEndpointsButtonEnabled = linkedEndpoints.length > 0; + useEffect(() => { setIsTargetButtonMenuOpen(false); }, [scope]); @@ -108,6 +117,15 @@ export const ScopeBar = ({ setIsTargetButtonMenuOpen(false); }; + const handleLinkedEndpointsClick = (endpoint: LinkedEndpoint) => { + changeScope({ + span: { + spanCodeObjectId: endpoint.spanCodeObjectId + } + }); + setIsLinkedEndpointsMenuOpen(true); + }; + const handleExpandCollapseButtonClick = () => { if (isExpanded) { sendUserActionTrackingEvent( @@ -121,6 +139,11 @@ export const ScopeBar = ({ onExpandCollapseChange(!isExpanded); }; + const handleLinkedEndpointsButtonClick = () => { + sendUserActionTrackingEvent(trackingEvents.LINKED_ENDPOINTS_BUTTON_CLICKED); + setIsLinkedEndpointsMenuOpen(!isLinkedEndpointsMenuOpen); + }; + const handleTargetButtonClick = () => { sendUserActionTrackingEvent(trackingEvents.TARGET_BUTTON_CLICKED); if (scope && scope.code.codeDetailsList.length === 1) { @@ -160,6 +183,32 @@ export const ScopeBar = ({ ) : null} + {isLinkedEndpointsButtonEnabled && ( + + + + } + onOpenChange={setIsLinkedEndpointsMenuOpen} + isOpen={isLinkedEndpointsMenuOpen} + placement={"bottom-start"} + width={"100%"} + > +
+ + + +
+
+ )} {isSpanInfoEnabled && ( theme.colors.v3.icon.primary}; } `; + +export const LinkedEndpointsPopup = styled(Popup)` + margin: 4px 8px; +`; diff --git a/src/components/Navigation/ScopeBar/types.ts b/src/components/Navigation/ScopeBar/types.ts index a7cb39a18..1d66fcdaa 100644 --- a/src/components/Navigation/ScopeBar/types.ts +++ b/src/components/Navigation/ScopeBar/types.ts @@ -1,4 +1,5 @@ import { Scope } from "../../common/App/types"; +import { LinkedEndpoint } from "../SpanInfo/types"; import { CodeContext } from "../types"; export interface ScopeBarProps { @@ -7,4 +8,5 @@ export interface ScopeBarProps { isExpanded: boolean; onExpandCollapseChange: (isExpanded: boolean) => void; isSpanInfoEnabled: boolean; + linkedEndpoints: LinkedEndpoint[]; } diff --git a/src/components/Navigation/SpanInfo/types.ts b/src/components/Navigation/SpanInfo/types.ts index c9a43a668..f0bd9662b 100644 --- a/src/components/Navigation/SpanInfo/types.ts +++ b/src/components/Navigation/SpanInfo/types.ts @@ -11,6 +11,12 @@ export interface GetHighlightsSpanInfoDataPayload { }; } +export interface LinkedEndpoint { + spanCodeObjectId: string; + displayName: string; + environment: string; +} + export interface SpanInfoData { displayName: string; services: string[]; @@ -18,4 +24,5 @@ export interface SpanInfoData { assetTypeId: string; firstSeen?: string; lastSeen?: string; + linkedEndpoints?: LinkedEndpoint[]; } diff --git a/src/components/Navigation/index.tsx b/src/components/Navigation/index.tsx index 29f0ae3e2..07d8749f3 100644 --- a/src/components/Navigation/index.tsx +++ b/src/components/Navigation/index.tsx @@ -395,6 +395,7 @@ export const Navigation = () => { isExpanded={isSpanInfoVisible} onExpandCollapseChange={handleScopeDisplayNameExpandCollapseChange} isSpanInfoEnabled={isSpanInfoEnabled} + linkedEndpoints={spanInfo?.linkedEndpoints ?? []} /> ) : ( { + const { size, color } = useIconProps(props); + + return ( + + + + + + + ); +}; + +export const ChainIcon = React.memo(ChainIconComponent); From eae211e7d6107b11bc6010e6f67f51494c8dab74 Mon Sep 17 00:00:00 2001 From: opoliarush Date: Tue, 8 Oct 2024 12:46:25 +0300 Subject: [PATCH 2/2] Fixed styles --- .../LinkedEndpointsMenu.stories.tsx | 3 ++- .../ScopeBar/LinkedEndpointsMenu/index.tsx | 22 +++++++++---------- .../ScopeBar/LinkedEndpointsMenu/styles.ts | 7 ++++++ .../Navigation/ScopeBar/ScopeBar.stories.tsx | 5 +++-- src/components/Navigation/index.tsx | 6 ++++- 5 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/components/Navigation/ScopeBar/LinkedEndpointsMenu/LinkedEndpointsMenu.stories.tsx b/src/components/Navigation/ScopeBar/LinkedEndpointsMenu/LinkedEndpointsMenu.stories.tsx index 388c31460..2972a370a 100644 --- a/src/components/Navigation/ScopeBar/LinkedEndpointsMenu/LinkedEndpointsMenu.stories.tsx +++ b/src/components/Navigation/ScopeBar/LinkedEndpointsMenu/LinkedEndpointsMenu.stories.tsx @@ -19,7 +19,8 @@ export const Default: StoryObj = { endpoints: [ { spanCodeObjectId: "span:codeObject", - displayName: "testMethodCall", + displayName: + "testMethodCallasdasdsadsadasdasdasdasdasdasdasdsadasdsads", environment: "TEST" }, { diff --git a/src/components/Navigation/ScopeBar/LinkedEndpointsMenu/index.tsx b/src/components/Navigation/ScopeBar/LinkedEndpointsMenu/index.tsx index 0eeccb422..01fce27f9 100644 --- a/src/components/Navigation/ScopeBar/LinkedEndpointsMenu/index.tsx +++ b/src/components/Navigation/ScopeBar/LinkedEndpointsMenu/index.tsx @@ -19,18 +19,16 @@ export const LinkedEndpointsMenu = ({ This client assets calls the following endpoint: ({ - id: x.spanCodeObjectId, - customContent: ( - handleMenuItemClick(x)}> - - {x.displayName} - - ), - disabled: false - })) - ]} + items={endpoints.map((x) => ({ + id: x.spanCodeObjectId, + customContent: ( + handleMenuItemClick(x)}> + + {x.displayName} + + ), + disabled: false + }))} /> ); diff --git a/src/components/Navigation/ScopeBar/LinkedEndpointsMenu/styles.ts b/src/components/Navigation/ScopeBar/LinkedEndpointsMenu/styles.ts index 0f250e712..f47d844c3 100644 --- a/src/components/Navigation/ScopeBar/LinkedEndpointsMenu/styles.ts +++ b/src/components/Navigation/ScopeBar/LinkedEndpointsMenu/styles.ts @@ -18,11 +18,18 @@ export const MenuItem = styled.div` align-items: center; color: ${({ theme }) => theme.colors.v3.icon.brandSecondary}; cursor: pointer; + ${bodyRegularTypography} &:hover { text-decoration: underline; } + + span { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + } `; export const Title = styled.div` diff --git a/src/components/Navigation/ScopeBar/ScopeBar.stories.tsx b/src/components/Navigation/ScopeBar/ScopeBar.stories.tsx index d7d4bdb24..01a958022 100644 --- a/src/components/Navigation/ScopeBar/ScopeBar.stories.tsx +++ b/src/components/Navigation/ScopeBar/ScopeBar.stories.tsx @@ -71,7 +71,8 @@ export const Default: Story = { codeContext: mockedCodeContext, linkedEndpoints: [ { - spanCodeObjectId: "span:codeObject", + spanCodeObjectId: + "span:codeObjectasdasdasdsadasdassadasdasdasdsadasdasdasdasdasdasdasdsadsadasdasd", displayName: "testMethodCall", environment: "TEST" }, @@ -110,7 +111,7 @@ export const HasMultipleCodeLocations: Story = { linkedEndpoints: [ { spanCodeObjectId: "span:codeObject", - displayName: "testMethodCall", + displayName: "testMethodCallasdasdasdasdadasdsadasdsadsadasdasdsads", environment: "TEST" }, { diff --git a/src/components/Navigation/index.tsx b/src/components/Navigation/index.tsx index 07d8749f3..28198ba01 100644 --- a/src/components/Navigation/index.tsx +++ b/src/components/Navigation/index.tsx @@ -395,7 +395,11 @@ export const Navigation = () => { isExpanded={isSpanInfoVisible} onExpandCollapseChange={handleScopeDisplayNameExpandCollapseChange} isSpanInfoEnabled={isSpanInfoEnabled} - linkedEndpoints={spanInfo?.linkedEndpoints ?? []} + linkedEndpoints={ + spanInfo?.linkedEndpoints?.filter( + (x) => x.environment === environment?.id + ) ?? [] + } /> ) : (