diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 000000000..25bf17fc5 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +18 \ No newline at end of file diff --git a/src/components/common/AssetEntry/AssetEntry.stories.tsx b/src/components/Assets/AssetList/AssetEntry/AssetEntry.stories.tsx similarity index 100% rename from src/components/common/AssetEntry/AssetEntry.stories.tsx rename to src/components/Assets/AssetList/AssetEntry/AssetEntry.stories.tsx diff --git a/src/components/common/AssetEntry/index.tsx b/src/components/Assets/AssetList/AssetEntry/index.tsx similarity index 71% rename from src/components/common/AssetEntry/index.tsx rename to src/components/Assets/AssetList/AssetEntry/index.tsx index 209863461..90c06135c 100644 --- a/src/components/common/AssetEntry/index.tsx +++ b/src/components/Assets/AssetList/AssetEntry/index.tsx @@ -1,8 +1,9 @@ import { useTheme } from "styled-components"; -import { getInsightImportanceColor } from "../../../utils/getInsightImportanceColor"; -import { getInsightTypeInfo } from "../../../utils/getInsightTypeInfo"; -import { timeAgo } from "../../../utils/timeAgo"; -import { OpenTelemetryLogoIcon } from "../icons/OpenTelemetryLogoIcon"; +import { getInsightImportanceColor } from "../../../../utils/getInsightImportanceColor"; +import { getInsightTypeInfo } from "../../../../utils/getInsightTypeInfo"; +import { getInsightTypeOrderPriority } from "../../../../utils/getInsightTypeOrderPriority"; +import { timeAgo } from "../../../../utils/timeAgo"; +import { getAssetTypeInfo } from "../../utils"; import * as s from "./styles"; import { AssetEntryProps } from "./types"; @@ -23,17 +24,27 @@ export const AssetEntry = (props: AssetEntryProps) => { const lastSeenDateTime = props.entry.lastSpanInstanceInfo.startTime; + const sortedInsights = [...props.entry.insights].sort( + (a, b) => + a.importance - b.importance || + getInsightTypeOrderPriority(a.type) - getInsightTypeOrderPriority(b.type) + ); + + const assetTypeInfo = getAssetTypeInfo(props.entry.assetType); + return ( - - - + {assetTypeInfo?.icon && ( + + + + )} handleLinkClick()} title={name}> {name} - {props.entry.insights.map((insight) => { + {sortedInsights.map((insight) => { const insightTypeInfo = getInsightTypeInfo(insight.type); const insightIconColor = getInsightImportanceColor( insight.importance, @@ -57,7 +68,9 @@ export const AssetEntry = (props: AssetEntryProps) => { Services - {props.entry.serviceName} + + {props.entry.serviceName} + {otherServices.length > 0 && ( +{otherServices.length} diff --git a/src/components/common/AssetEntry/styles.ts b/src/components/Assets/AssetList/AssetEntry/styles.ts similarity index 91% rename from src/components/common/AssetEntry/styles.ts rename to src/components/Assets/AssetList/AssetEntry/styles.ts index 2ac2b6fa6..d69c446c9 100644 --- a/src/components/common/AssetEntry/styles.ts +++ b/src/components/Assets/AssetList/AssetEntry/styles.ts @@ -17,7 +17,7 @@ export const Header = styled.div` align-items: center; `; -export const OpenTelemetryIconContainer = styled.div` +export const AssetTypeIconContainer = styled.div` display: flex; justify-content: center; width: 20px; @@ -43,7 +43,7 @@ export const InsightIconsContainer = styled.div` margin-left: auto; `; -export const InsightIconContainer = styled(OpenTelemetryIconContainer)` +export const InsightIconContainer = styled(AssetTypeIconContainer)` background: #2e2e2e; border-radius: 4px; `; @@ -83,8 +83,9 @@ export const ServiceName = styled.div` padding: 4px 6px; background: #2e2e2e; border-radius: 23px; - width: fit-content; line-height: 8px; + overflow: hidden; + text-overflow: ellipsis; `; export const ValueContainer = styled.div` diff --git a/src/components/common/AssetEntry/types.ts b/src/components/Assets/AssetList/AssetEntry/types.ts similarity index 65% rename from src/components/common/AssetEntry/types.ts rename to src/components/Assets/AssetList/AssetEntry/types.ts index b64b9a849..24b6de7be 100644 --- a/src/components/common/AssetEntry/types.ts +++ b/src/components/Assets/AssetList/AssetEntry/types.ts @@ -1,4 +1,4 @@ -import { ExtendedAssetEntryWithServices } from "../../Assets/AssetList/types"; +import { ExtendedAssetEntryWithServices } from "../types"; export interface AssetEntryProps { entry: ExtendedAssetEntryWithServices; diff --git a/src/components/Assets/AssetList/index.tsx b/src/components/Assets/AssetList/index.tsx index bba38d661..9deacf1f6 100644 --- a/src/components/Assets/AssetList/index.tsx +++ b/src/components/Assets/AssetList/index.tsx @@ -1,5 +1,4 @@ import { useMemo, useState } from "react"; -import { AssetEntry as AssetEntryComponent } from "../../common/AssetEntry"; import { Menu } from "../../common/Menu"; import { Popover } from "../../common/Popover"; import { PopoverContent } from "../../common/Popover/PopoverContent"; @@ -7,20 +6,15 @@ import { PopoverTrigger } from "../../common/Popover/PopoverTrigger"; import { ChevronIcon } from "../../common/icons/ChevronIcon"; import { Direction } from "../../common/icons/types"; import { getAssetTypeInfo } from "../utils"; +import { AssetEntry as AssetEntryComponent } from "./AssetEntry"; import * as s from "./styles"; import { AssetListProps, ExtendedAssetEntryWithServices, + SORTING_CRITERION, Sorting } from "./types"; -const SORTING_CRITERION = [ - "Critical insights", - "Performance", - "Latest", - "Name" -]; - const sortEntries = ( entries: ExtendedAssetEntryWithServices[], sorting: Sorting @@ -29,26 +23,43 @@ const sortEntries = ( const sortByName = ( a: ExtendedAssetEntryWithServices, - b: ExtendedAssetEntryWithServices - ) => a.span.displayName.localeCompare(b.span.displayName); + b: ExtendedAssetEntryWithServices, + isDesc: boolean + ) => + isDesc + ? b.span.displayName.localeCompare(a.span.displayName) + : a.span.displayName.localeCompare(b.span.displayName); switch (sorting.criterion) { - case "Critical insights": + case SORTING_CRITERION.CRITICAL_INSIGHTS: return entries.sort((a, b) => { - const aCriticalInsights = a.insights.filter( - (x) => x.importance < 3 + const aHighestImportance = + a.insights.length > 0 + ? Math.min(...a.insights.map((x) => x.importance)) + : Infinity; + const bHighestImportance = + b.insights.length > 0 + ? Math.min(...b.insights.map((x) => x.importance)) + : Infinity; + + const aMostImportantInsightCount = a.insights.filter( + (x) => x.importance === aHighestImportance ).length; - const bCriticalInsights = b.insights.filter( - (x) => x.importance < 3 + const bMostImportantInsightCount = b.insights.filter( + (x) => x.importance === bHighestImportance ).length; return ( (sorting.isDesc - ? bCriticalInsights - aCriticalInsights - : aCriticalInsights - bCriticalInsights) || sortByName(a, b) + ? aHighestImportance - bHighestImportance + : bHighestImportance - aHighestImportance) || + (sorting.isDesc + ? bMostImportantInsightCount - aMostImportantInsightCount + : aMostImportantInsightCount - bMostImportantInsightCount) || + sortByName(a, b, sorting.isDesc) ); }); - case "Performance": + case SORTING_CRITERION.PERFORMANCE: return entries.sort((a, b) => { const aDuration = a.durationPercentiles.find( (duration) => duration.percentile === 0.5 @@ -62,7 +73,7 @@ const sortEntries = ( } if (!aDuration) { - return sorting.isDesc ? -1 : 1; + return sorting.isDesc ? 1 : -1; } if (!bDuration) { @@ -71,22 +82,24 @@ const sortEntries = ( return ( (sorting.isDesc ? bDuration - aDuration : aDuration - bDuration) || - sortByName(a, b) + sortByName(a, b, sorting.isDesc) ); }); - case "Latest": + case SORTING_CRITERION.LATEST: return entries.sort((a, b) => { const aDateTime = new Date(a.lastSpanInstanceInfo.startTime).valueOf(); const bDateTime = new Date(b.lastSpanInstanceInfo.startTime).valueOf(); return ( (sorting.isDesc ? bDateTime - aDateTime : aDateTime - bDateTime) || - sortByName(a, b) + sortByName(a, b, sorting.isDesc) ); }); - case "Name": + case SORTING_CRITERION.NAME: return entries.sort((a, b) => - sorting.isDesc ? sortByName(b, a) : sortByName(a, b) + sorting.isDesc + ? sortByName(b, a, sorting.isDesc) + : sortByName(a, b, sorting.isDesc) ); default: return entries; @@ -95,10 +108,10 @@ const sortEntries = ( export const AssetList = (props: AssetListProps) => { const [sorting, setSorting] = useState<{ - criterion: string; + criterion: SORTING_CRITERION; isDesc: boolean; }>({ - criterion: "Critical insights", + criterion: SORTING_CRITERION.CRITICAL_INSIGHTS, isDesc: true }); const [isSortingMenuOpen, setIsSortingMenuOpen] = useState(false); @@ -123,7 +136,7 @@ export const AssetList = (props: AssetListProps) => { }); } else { setSorting({ - criterion: value, + criterion: value as SORTING_CRITERION, isDesc: false }); } @@ -186,7 +199,10 @@ export const AssetList = (props: AssetListProps) => { ({ value: x, label: x }))} + items={Object.values(SORTING_CRITERION).map((x) => ({ + value: x, + label: x + }))} onSelect={handleSortingMenuItemSelect} /> diff --git a/src/components/Assets/AssetList/types.ts b/src/components/Assets/AssetList/types.ts index 2606334f7..dc9ffc16f 100644 --- a/src/components/Assets/AssetList/types.ts +++ b/src/components/Assets/AssetList/types.ts @@ -11,7 +11,14 @@ export interface AssetListProps { onAssetLinkClick: (entry: ExtendedAssetEntryWithServices) => void; } +export enum SORTING_CRITERION { + CRITICAL_INSIGHTS = "Critical insights", + PERFORMANCE = "Performance", + LATEST = "Latest", + NAME = "Name" +} + export interface Sorting { - criterion: string; + criterion: SORTING_CRITERION; isDesc: boolean; } diff --git a/src/components/Assets/AssetTypeList/AssetTypeListItem/styles.ts b/src/components/Assets/AssetTypeList/AssetTypeListItem/styles.ts index 39cc8f914..cc41a3c02 100644 --- a/src/components/Assets/AssetTypeList/AssetTypeListItem/styles.ts +++ b/src/components/Assets/AssetTypeList/AssetTypeListItem/styles.ts @@ -4,6 +4,7 @@ export const ListItem = styled.li` display: flex; flex-direction: column; background: #3d3f41; + cursor: pointer; `; export const AssetType = styled.span`