diff --git a/src/components/Insights/common/InsightCard/KeyValue/styles.ts b/src/components/Insights/common/InsightCard/KeyValue/styles.ts index 08b90f906..4ee1589f7 100644 --- a/src/components/Insights/common/InsightCard/KeyValue/styles.ts +++ b/src/components/Insights/common/InsightCard/KeyValue/styles.ts @@ -1,5 +1,8 @@ import styled from "styled-components"; -import { caption1RegularTypography } from "../../../../common/App/typographies"; +import { + footnoteRegularTypography, + subscriptRegularTypography +} from "../../../../common/App/typographies"; export const Container = styled.div` display: flex; @@ -8,10 +11,13 @@ export const Container = styled.div` `; export const Key = styled.div` + ${footnoteRegularTypography} + color: ${({ theme }) => theme.colors.v3.text.secondary}; - ${caption1RegularTypography} `; export const Value = styled.div` + ${subscriptRegularTypography} + color: ${({ theme }) => theme.colors.v3.text.primary}; `; diff --git a/src/components/Insights/common/InsightCard/ListItem/index.tsx b/src/components/Insights/common/InsightCard/ListItem/index.tsx index d15c480b0..59d8b3888 100644 --- a/src/components/Insights/common/InsightCard/ListItem/index.tsx +++ b/src/components/Insights/common/InsightCard/ListItem/index.tsx @@ -1,4 +1,5 @@ import { ForwardedRef, MouseEvent, forwardRef } from "react"; +import { Link } from "../../../../common/v3/Link"; import { Tooltip } from "../../../../common/v3/Tooltip"; import * as s from "./styles"; import { ListItemProps } from "./types"; @@ -13,11 +14,9 @@ const ListItemComponent = ( }; return ( - + - - {name} - + {name} {buttons && {buttons}} diff --git a/src/components/Insights/common/InsightCard/ListItem/styles.ts b/src/components/Insights/common/InsightCard/ListItem/styles.ts index 16aa8bf4c..39dc20c96 100644 --- a/src/components/Insights/common/InsightCard/ListItem/styles.ts +++ b/src/components/Insights/common/InsightCard/ListItem/styles.ts @@ -1,5 +1,4 @@ import styled from "styled-components"; -import { footnoteRegularTypography } from "../../../../common/App/typographies"; export const Container = styled.div` display: flex; @@ -9,18 +8,8 @@ export const Container = styled.div` padding: 4px; border-radius: 4px; background: ${({ theme }) => theme.colors.v3.surface.primary}; -`; - -export const Link = styled.a` - ${footnoteRegularTypography} - - cursor: pointer; - color: ${({ theme }) => theme.colors.v3.text.link}; - text-decoration: none; - display: block; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; + height: 28px; + box-sizing: border-box; `; export const ButtonsContainer = styled.div` diff --git a/src/components/Insights/common/InsightCard/Select/index.tsx b/src/components/Insights/common/InsightCard/Select/index.tsx index c7ff6160d..0346d7a5d 100644 --- a/src/components/Insights/common/InsightCard/Select/index.tsx +++ b/src/components/Insights/common/InsightCard/Select/index.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { MouseEvent, useState } from "react"; import { MenuList } from "../../../../Navigation/common/MenuList"; import { Popup } from "../../../../Navigation/common/Popup"; import { NewPopover } from "../../../../common/NewPopover"; @@ -18,7 +18,12 @@ export const Select = (props: SelectProps) => { props.onChange(option.value); }; - const handleExpandButtonClick = () => { + const handleSelectBarClick = (e: MouseEvent) => { + // Prevent the dropdown from opening when clicking on a link inside the selected item + if ((e.target as HTMLElement).tagName === "A") { + return; + } + setIsOpen(!isOpen); }; @@ -36,11 +41,16 @@ export const Select = (props: SelectProps) => { /> } - onOpenChange={props.isDisabled || !isOpen ? undefined : setIsOpen} + onOpenChange={props.isDisabled ? undefined : setIsOpen} + useClickInteraction={false} isOpen={props.isDisabled ? false : isOpen} placement={"bottom-start"} > - + {selectedOption ? ( {selectedOption.customContent ? ( @@ -53,7 +63,7 @@ export const Select = (props: SelectProps) => { props.placeholder )} - + ` @@ -27,6 +23,7 @@ export const SelectBar = styled.div` display: flex; align-items: center; box-shadow: 1 1 4px 0 rgb(0 0 0 / 25%); + cursor: ${({ $isDisabled }) => ($isDisabled ? "initial" : "pointer")}; border: 1px solid ${({ theme, $isOpen }) => $isOpen diff --git a/src/components/Insights/common/insights/EndpointBottleneckInsight/styles.ts b/src/components/Insights/common/insights/EndpointBottleneckInsight/styles.ts index 39395a748..3dd35f6c9 100644 --- a/src/components/Insights/common/insights/EndpointBottleneckInsight/styles.ts +++ b/src/components/Insights/common/insights/EndpointBottleneckInsight/styles.ts @@ -2,5 +2,5 @@ import styled from "styled-components"; import { ListItem } from "../../InsightCard/ListItem"; export const SpanListItem = styled(ListItem)` - padding: 4px; + height: 32px; `; diff --git a/src/components/Insights/common/insights/EndpointNPlusOneInsight/styles.ts b/src/components/Insights/common/insights/EndpointNPlusOneInsight/styles.ts index f1cafeb5a..8759cc921 100644 --- a/src/components/Insights/common/insights/EndpointNPlusOneInsight/styles.ts +++ b/src/components/Insights/common/insights/EndpointNPlusOneInsight/styles.ts @@ -8,5 +8,5 @@ export const InfoContainer = styled.div` `; export const SpanListItem = styled(ListItem)` - padding: 4px; + height: 32px; `; diff --git a/src/components/Insights/common/insights/EndpointQueryOptimizationInsight/index.tsx b/src/components/Insights/common/insights/EndpointQueryOptimizationInsight/index.tsx index 3ca5ffd19..ccc537c3b 100644 --- a/src/components/Insights/common/insights/EndpointQueryOptimizationInsight/index.tsx +++ b/src/components/Insights/common/insights/EndpointQueryOptimizationInsight/index.tsx @@ -2,6 +2,8 @@ import { ReactNode, useContext, useState } from "react"; import { getDurationString } from "../../../../../utils/getDurationString"; import { sendTrackingEvent } from "../../../../../utils/sendTrackingEvent"; import { ConfigContext } from "../../../../common/App/ConfigContext"; +import { Link } from "../../../../common/v3/Link"; +import { Tooltip } from "../../../../common/v3/Tooltip"; import { trackingEvents } from "../../../tracking"; import { EndpointQueryOptimizationSpan, @@ -11,7 +13,6 @@ import { import { InsightCard } from "../../InsightCard"; import { ColumnsContainer } from "../../InsightCard/ColumnsContainer"; import { KeyValue } from "../../InsightCard/KeyValue"; -import { ListItem } from "../../InsightCard/ListItem"; import { Select } from "../../InsightCard/Select"; import { ContentContainer, Description, Details } from "../styles"; import * as s from "./styles"; @@ -20,23 +21,25 @@ import { EndpointQueryOptimizationInsightProps } from "./types"; const renderOptions = ( spans: EndpointQueryOptimizationSpan[], handleLinkClick: (spanCodeObjectId: string) => void -): { label: string; customContent: ReactNode; value: string }[] => { - return spans.map((x) => { +): { label: string; customContent: ReactNode; value: string }[] => + spans.map((x) => { const spanCodeObjectId = x.spanInfo.spanCodeObjectId; + const name = x.spanInfo.displayName; + return { - label: x.spanInfo.displayName, + label: name, customContent: ( - handleLinkClick(spanCodeObjectId)} - /> + + handleLinkClick(spanCodeObjectId)}> + {name} + + ), value: spanCodeObjectId }; }); -}; export const EndpointQueryOptimizationInsight = ( props: EndpointQueryOptimizationInsightProps diff --git a/src/components/Insights/common/insights/EndpointQueryOptimizationInsight/styles.ts b/src/components/Insights/common/insights/EndpointQueryOptimizationInsight/styles.ts index 861aa220a..0812e9ff7 100644 --- a/src/components/Insights/common/insights/EndpointQueryOptimizationInsight/styles.ts +++ b/src/components/Insights/common/insights/EndpointQueryOptimizationInsight/styles.ts @@ -2,7 +2,8 @@ import styled from "styled-components"; import { footnoteRegularTypography } from "../../../../common/App/typographies"; export const SelectedItem = styled.div` + ${footnoteRegularTypography} + display: flex; align-items: center; - ${footnoteRegularTypography} `; diff --git a/src/components/Insights/common/insights/ExcessiveAPICallsInsight/index.tsx b/src/components/Insights/common/insights/ExcessiveAPICallsInsight/index.tsx index d228fe104..246dc1834 100644 --- a/src/components/Insights/common/insights/ExcessiveAPICallsInsight/index.tsx +++ b/src/components/Insights/common/insights/ExcessiveAPICallsInsight/index.tsx @@ -4,6 +4,7 @@ import { ConfigContext } from "../../../../common/App/ConfigContext"; import { TargetIcon } from "../../../../common/icons/12px/TargetIcon"; import { Button } from "../../../../common/v3/Button"; import { Pagination } from "../../../../common/v3/Pagination"; +import { Tooltip } from "../../../../common/v3/Tooltip"; import { InsightType, Trace } from "../../../types"; import { InsightCard } from "../../InsightCard"; import { ContentContainer, Description, ListContainer } from "../styles"; @@ -56,20 +57,22 @@ export const ExcessiveAPICallsInsight = ( onClick={() => handleLinkClick(spanCodeObjectId)} buttons={[ config.isJaegerEnabled && traceId && ( - + /> ); } return ( - - - handleLinkClick(spanCodeObjectId)} - buttons={buttons} - /> - - + handleLinkClick(spanCodeObjectId)} + buttons={buttons} + /> ); })} @@ -132,15 +127,11 @@ export const ScalingIssueInsight = (props: ScalingIssueInsightProps) => { pageItems.map((endpoint) => { const endpointRoute = trimEndpointScheme(endpoint.route); return ( - - - handleLinkClick(endpoint.spanCodeObjectId) - } - name={endpointRoute} - /> - + handleLinkClick(endpoint.spanCodeObjectId)} + name={endpointRoute} + /> ); })} void -): { label: string; customContent: ReactNode; value: string }[] => { - return endpoints.map((x) => { +): { label: string; customContent: ReactNode; value: string }[] => + endpoints.map((x) => { const spanCodeObjectId = x.endpointInfo.spanCodeObjectId; const route = trimEndpointScheme(x.endpointInfo.route); return { @@ -27,17 +28,16 @@ const renderOptions = ( customContent: ( {x.endpointInfo.serviceName} - handleLinkClick(spanCodeObjectId)} - /> + + handleLinkClick(spanCodeObjectId)}> + {route} + + ), value: spanCodeObjectId }; }); -}; - export const SpanEndpointBottleneckInsight = ( props: SpanEndpointBottleneckInsightProps ) => { diff --git a/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/styles.ts b/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/styles.ts index 861aa220a..e8728151d 100644 --- a/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/styles.ts +++ b/src/components/Insights/common/insights/SpanEndpointBottleneckInsight/styles.ts @@ -2,7 +2,9 @@ import styled from "styled-components"; import { footnoteRegularTypography } from "../../../../common/App/typographies"; export const SelectedItem = styled.div` + ${footnoteRegularTypography} + display: flex; + gap: 4px; align-items: center; - ${footnoteRegularTypography} `; diff --git a/src/components/Insights/common/insights/SpanNPlusOneInsight/index.tsx b/src/components/Insights/common/insights/SpanNPlusOneInsight/index.tsx index e6a274292..0e35409cd 100644 --- a/src/components/Insights/common/insights/SpanNPlusOneInsight/index.tsx +++ b/src/components/Insights/common/insights/SpanNPlusOneInsight/index.tsx @@ -3,13 +3,14 @@ import { getDurationString } from "../../../../../utils/getDurationString"; import { sendTrackingEvent } from "../../../../../utils/sendTrackingEvent"; import { trimEndpointScheme } from "../../../../../utils/trimEndpointScheme"; import { ConfigContext } from "../../../../common/App/ConfigContext"; +import { Link } from "../../../../common/v3/Link"; +import { Tooltip } from "../../../../common/v3/Tooltip"; import { trackingEvents } from "../../../tracking"; import { InsightType, NPlusOneEndpointInfo, Trace } from "../../../types"; import { Info } from "../../Info"; import { InsightCard } from "../../InsightCard"; import { ColumnsContainer } from "../../InsightCard/ColumnsContainer"; import { KeyValue } from "../../InsightCard/KeyValue"; -import { ListItem } from "../../InsightCard/ListItem"; import { Select } from "../../InsightCard/Select"; import { ContentContainer, Description, Details } from "../styles"; import * as s from "./styles"; @@ -18,8 +19,8 @@ import { SpanNPlusOneInsightProps } from "./types"; const renderOptions = ( endpoints: NPlusOneEndpointInfo[], handleLinkClick: (spanCodeObjectId?: string) => void -): { label: string; customContent: ReactNode; value: string }[] => { - return endpoints.map((x) => { +): { label: string; customContent: ReactNode; value: string }[] => + endpoints.map((x) => { const spanCodeObjectId = x.endpointInfo.entrySpanCodeObjectId; const route = trimEndpointScheme(x.endpointInfo.route); return { @@ -27,16 +28,16 @@ const renderOptions = ( customContent: ( {x.endpointInfo.serviceName} - handleLinkClick(spanCodeObjectId)} - /> + + handleLinkClick(spanCodeObjectId)}> + {route} + + ), value: spanCodeObjectId }; }); -}; export const SpanNPlusOneInsight = (props: SpanNPlusOneInsightProps) => { const { diff --git a/src/components/Insights/common/insights/SpanNPlusOneInsight/styles.ts b/src/components/Insights/common/insights/SpanNPlusOneInsight/styles.ts index 4a449a8e6..3c9bc32e3 100644 --- a/src/components/Insights/common/insights/SpanNPlusOneInsight/styles.ts +++ b/src/components/Insights/common/insights/SpanNPlusOneInsight/styles.ts @@ -8,7 +8,9 @@ export const InfoContainer = styled.div` `; export const SelectedItem = styled.div` + ${footnoteRegularTypography} + display: flex; + gap: 4px; align-items: center; - ${footnoteRegularTypography} `; diff --git a/src/components/common/App/typographies.ts b/src/components/common/App/typographies.ts index d2fd1abac..1c6374f38 100644 --- a/src/components/common/App/typographies.ts +++ b/src/components/common/App/typographies.ts @@ -83,6 +83,12 @@ export const subscriptRegularTypography = css` line-height: ${typographies.subscript.lineHeight}px; `; +export const subscriptSemiboldTypography = css` + font-size: ${typographies.subscript.fontSize}px; + font-weight: ${typographies.subscript.fontWeight.semibold}; + line-height: ${typographies.subscript.lineHeight}px; +`; + export const bodyRegularTypography = css` font-size: ${typographies.body.fontSize}px; font-weight: ${typographies.body.fontWeight.regular}; diff --git a/src/components/common/NewPopover/index.tsx b/src/components/common/NewPopover/index.tsx index 7da9f5a66..2bf485cdf 100644 --- a/src/components/common/NewPopover/index.tsx +++ b/src/components/common/NewPopover/index.tsx @@ -96,7 +96,7 @@ export const NewPopover = (props: PopoverProps) => { const dismiss = useDismiss(context); const { getReferenceProps, getFloatingProps } = useInteractions([ - click, + ...(props.useClickInteraction === false ? [] : [click]), dismiss ]); diff --git a/src/components/common/NewPopover/types.ts b/src/components/common/NewPopover/types.ts index af844a016..cb6235754 100644 --- a/src/components/common/NewPopover/types.ts +++ b/src/components/common/NewPopover/types.ts @@ -11,4 +11,5 @@ export interface PopoverProps { boundary?: HTMLElement; width?: number | string; sameWidth?: boolean; + useClickInteraction?: boolean; } diff --git a/src/components/common/v3/JiraButton/index.tsx b/src/components/common/v3/JiraButton/index.tsx index 07c376f67..c4948a451 100644 --- a/src/components/common/v3/JiraButton/index.tsx +++ b/src/components/common/v3/JiraButton/index.tsx @@ -104,11 +104,9 @@ export const JiraButtonComponent = ( You can now easily create a ticket using information from Digma openTicketInfo("try now button click")} - > - Try now - + label={"Try now"} + /> } isOpen={Boolean(isHintEnabled)} diff --git a/src/components/common/v3/JiraButton/styles.ts b/src/components/common/v3/JiraButton/styles.ts index 105905961..235525a1f 100644 --- a/src/components/common/v3/JiraButton/styles.ts +++ b/src/components/common/v3/JiraButton/styles.ts @@ -1,5 +1,6 @@ import styled from "styled-components"; -import { Button } from "../../Button"; +import { subscriptSemiboldTypography } from "../../App/typographies"; +import { Button } from "../../v3/Button"; export const HintContainer = styled.div` display: flex; @@ -7,21 +8,22 @@ export const HintContainer = styled.div` gap: 4px; padding: 4px; width: 235px; - color: ${({ theme }) => theme.colors.text.subtext}; + color: ${({ theme }) => theme.colors.v3.text.secondary}; word-break: keep-all; `; export const HintHeader = styled.div` + ${subscriptSemiboldTypography} + display: flex; gap: 4px; align-items: center; - font-weight: 500; - color: ${({ theme }) => theme.colors.text.base}; + color: ${({ theme }) => theme.colors.v3.text.primary}; `; export const HintIconContainer = styled.div` display: flex; - color: ${({ theme }) => theme.colors.icon.primary}; + color: ${({ theme }) => theme.colors.v3.icon.primary}; `; export const TryNowButton = styled(Button)` diff --git a/src/components/common/v3/Link/index.tsx b/src/components/common/v3/Link/index.tsx new file mode 100644 index 000000000..d0c7df5f8 --- /dev/null +++ b/src/components/common/v3/Link/index.tsx @@ -0,0 +1,32 @@ +import { ForwardedRef, MouseEvent, forwardRef } from "react"; +import * as s from "./styles"; +import { LinkProps } from "./types"; + +const LinkComponent = ( + props: LinkProps, + ref: ForwardedRef +) => { + const handleClick = (e: MouseEvent) => { + if (props.onClick) { + if (!props.href) { + e.preventDefault(); + } + props.onClick(e); + } + }; + + return ( + + {props.children} + + ); +}; + +export const Link = forwardRef(LinkComponent); diff --git a/src/components/common/v3/Link/styles.ts b/src/components/common/v3/Link/styles.ts new file mode 100644 index 000000000..01644c180 --- /dev/null +++ b/src/components/common/v3/Link/styles.ts @@ -0,0 +1,51 @@ +import styled from "styled-components"; +import { footnoteRegularTypography } from "../../App/typographies"; + +export const Link = styled.a` + ${footnoteRegularTypography} + + cursor: pointer; + text-decoration: none; + color: ${({ theme }) => theme.colors.v3.text.link}; + display: block; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + + &:hover, + &:focus { + color: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#002d61"; + case "dark": + case "dark-jetbrains": + return "#e2e7ff"; + } + }}; + } + + &:active { + color: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#002d61"; + case "dark": + case "dark-jetbrains": + return "#7891d0"; + } + }}; + } + + &:disabled { + color: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#b9c0d4"; + case "dark": + case "dark-jetbrains": + return "#49494d"; + } + }}; + } +`; diff --git a/src/components/common/v3/Link/types.ts b/src/components/common/v3/Link/types.ts new file mode 100644 index 000000000..774980b22 --- /dev/null +++ b/src/components/common/v3/Link/types.ts @@ -0,0 +1,11 @@ +import { MouseEvent, ReactNode } from "react"; + +export interface LinkProps { + href?: string; + target?: string; + rel?: string; + onClick?: (e: MouseEvent) => void; + disabled?: boolean; + children: ReactNode; + className?: string; +}