@odigos/ui-kit 0.0.90 → 0.0.92

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.0.92](https://github.com/odigos-io/ui-kit/compare/ui-kit-v0.0.91...ui-kit-v0.0.92) (2025-08-25)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **trace-view:** more visual fixes ([#347](https://github.com/odigos-io/ui-kit/issues/347)) ([defa80c](https://github.com/odigos-io/ui-kit/commit/defa80c9f45a668a365d6b8754ace78444b8ab42))
9
+
10
+ ## [0.0.91](https://github.com/odigos-io/ui-kit/compare/ui-kit-v0.0.90...ui-kit-v0.0.91) (2025-08-24)
11
+
12
+
13
+ ### Features
14
+
15
+ * **trace-view:** add error indicator ([#346](https://github.com/odigos-io/ui-kit/issues/346)) ([554ec47](https://github.com/odigos-io/ui-kit/commit/554ec47c946d2faeaba739f75f48dfd080b0e066))
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * trace-view visual fixes ([#344](https://github.com/odigos-io/ui-kit/issues/344)) ([8eec6ee](https://github.com/odigos-io/ui-kit/commit/8eec6eea76972440656e5cb5891be7df56e26c04))
21
+
3
22
  ## [0.0.90](https://github.com/odigos-io/ui-kit/compare/ui-kit-v0.0.89...ui-kit-v0.0.90) (2025-08-24)
4
23
 
5
24
 
@@ -6,6 +6,7 @@ interface DividerProps {
6
6
  thickness?: number;
7
7
  length?: string;
8
8
  margin?: string;
9
+ opacity?: number;
9
10
  }
10
11
  declare const Divider: FC<DividerProps>;
11
12
  export { Divider, type DividerProps };
package/lib/components.js CHANGED
@@ -1,6 +1,6 @@
1
- import { B as Button } from './index-651d36f3.js';
2
- export { A as AutocompleteInput, a as Badge, a9 as CenterThis, C as Checkbox, b as Code, c as ConditionDetails, D as DataCard, e as DataCardFieldTypes, d as DataCardFields, f as DataFinger, g as DataTab, h as DescribeRow, i as Divider, j as DocsButton, k as Drawer, m as DrawerFooter, l as DrawerHeader, n as Dropdown, E as ExtendArrow, F as FadeLoader, o as FieldError, p as FieldLabel, a8 as FlexColumn, a7 as FlexRow, H as Header, I as IconButton, q as IconGroup, r as IconTitleBadge, s as IconWrapped, t as IconsNav, u as ImageControlled, v as Input, w as InputList, x as InputTable, y as InteractiveTable, K as KeyValueInputsList, M as Modal, ac as ModalBody, z as MonitorsCheckboxes, G as MonitorsIcons, N as NavigationButtons, J as NoDataFound, L as NotificationNote, ab as Overlay, P as Popup, O as PopupForm, S as ScrollX, Q as SectionTitle, R as Segment, U as SelectionButton, V as SkeletonLoader, W as Status, X as Stepper, Y as TabList, ad as TableContainer, ae as TableTitleWrap, af as TableWrap, Z as Tag, _ as Text, a2 as TextArea, a3 as Toggle, T as ToggleCodeComponent, a4 as Tooltip, a5 as TraceLoader, aa as VerticalScroll, a6 as WarningModal, $ as getLinksFromText, a0 as getStrongsFromText, a1 as renderText } from './index-651d36f3.js';
3
- export { C as CancelWarning, D as DeleteWarning } from './index-41bb44dd.js';
1
+ import { B as Button } from './index-c616d2a7.js';
2
+ export { A as AutocompleteInput, a as Badge, a9 as CenterThis, C as Checkbox, b as Code, c as ConditionDetails, D as DataCard, e as DataCardFieldTypes, d as DataCardFields, f as DataFinger, g as DataTab, h as DescribeRow, i as Divider, j as DocsButton, k as Drawer, m as DrawerFooter, l as DrawerHeader, n as Dropdown, E as ExtendArrow, F as FadeLoader, o as FieldError, p as FieldLabel, a8 as FlexColumn, a7 as FlexRow, H as Header, I as IconButton, q as IconGroup, r as IconTitleBadge, s as IconWrapped, t as IconsNav, u as ImageControlled, v as Input, w as InputList, x as InputTable, y as InteractiveTable, K as KeyValueInputsList, M as Modal, ac as ModalBody, z as MonitorsCheckboxes, G as MonitorsIcons, N as NavigationButtons, J as NoDataFound, L as NotificationNote, ab as Overlay, P as Popup, O as PopupForm, S as ScrollX, Q as SectionTitle, R as Segment, U as SelectionButton, V as SkeletonLoader, W as Status, X as Stepper, Y as TabList, ad as TableContainer, ae as TableTitleWrap, af as TableWrap, Z as Tag, _ as Text, a2 as TextArea, a3 as Toggle, T as ToggleCodeComponent, a4 as Tooltip, a5 as TraceLoader, aa as VerticalScroll, a6 as WarningModal, $ as getLinksFromText, a0 as getStrongsFromText, a1 as renderText } from './index-c616d2a7.js';
3
+ export { C as CancelWarning, D as DeleteWarning } from './index-941ea41c.js';
4
4
  import React, { createContext, Component, createElement } from 'react';
5
5
  import { T as Theme } from './index-40dfa720.js';
6
6
  import 'styled-components';
@@ -1,7 +1,7 @@
1
- import React, { CSSProperties } from 'react';
1
+ import React from 'react';
2
2
  import { type Metrics } from '@/types';
3
3
  interface DataFlowProps {
4
- heightToRemove: CSSProperties['height'];
4
+ heightToRemove: number;
5
5
  metrics: Metrics;
6
6
  }
7
7
  declare const DataFlow: React.FC<DataFlowProps>;
@@ -1,7 +1,7 @@
1
- import React, { type CSSProperties } from 'react';
1
+ import React from 'react';
2
2
  import { type ServiceMapSources } from '@/types';
3
3
  interface ServiceMapProps {
4
- heightToRemove: CSSProperties['height'];
4
+ heightToRemove: number;
5
5
  serviceMap: ServiceMapSources;
6
6
  }
7
7
  declare const ServiceMap: React.FC<ServiceMapProps>;
@@ -1,8 +1,7 @@
1
1
  import { type FC } from 'react';
2
2
  import type { Trace } from '@/types';
3
- import { CSSProperties } from 'styled-components';
4
3
  interface TraceViewProps {
5
- heightToRemove: CSSProperties['height'];
4
+ heightToRemove: number;
6
5
  traces: Trace[];
7
6
  }
8
7
  declare const TraceView: FC<TraceViewProps>;
@@ -1,21 +1,33 @@
1
1
  import React, { type FC } from 'react';
2
- import type { TraceSpan } from '@/types';
2
+ import { type TraceLog, type TraceSpan } from '@/types';
3
+ import { TooltipProps } from '@/components';
3
4
  interface SpanProps {
5
+ span: TraceSpan;
6
+ depth: number;
7
+ indexInMatrix: number;
8
+ maxDuration: number;
9
+ minStartTime: number;
10
+ maxEndTime: number;
11
+ withErrors?: boolean;
12
+ errorTooltip?: TooltipProps;
13
+ isOpen?: boolean;
14
+ withToggle?: boolean;
15
+ onToggleOpen?: () => void;
16
+ }
17
+ interface RecursiveSpansProps {
18
+ spans: TraceSpan[];
19
+ logs: TraceLog[];
4
20
  depth: number;
5
21
  indexInMatrix: number;
6
- isHidden: boolean;
7
- isOpen: boolean;
8
- onToggleOpen: () => void;
9
- withToggle: boolean;
10
- span: TraceSpan;
11
22
  maxDuration: number;
12
23
  minStartTime: number;
13
24
  maxEndTime: number;
25
+ openSpanIdsState: {
26
+ value: string[];
27
+ set: React.Dispatch<React.SetStateAction<string[]>>;
28
+ };
14
29
  }
15
30
  export declare const LEFT_MAX_WIDTH = 370;
16
31
  declare const Span: FC<SpanProps>;
17
- declare const renderSpans: (spans: TraceSpan[], indexInMatrix: number, depth: number, minStartTime: number, maxEndTime: number, maxDuration: number, openSpanIdsState: {
18
- value: string[];
19
- set: React.Dispatch<React.SetStateAction<string[]>>;
20
- }) => React.JSX.Element[];
21
- export { Span, type SpanProps, renderSpans };
32
+ declare const RecursiveSpans: FC<RecursiveSpansProps>;
33
+ export { Span, type SpanProps, RecursiveSpans };
package/lib/containers.js CHANGED
@@ -2,16 +2,16 @@ import React, { useState, useEffect, forwardRef, useRef, useImperativeHandle, us
2
2
  import styled, { css } from 'styled-components';
3
3
  import { b as DISPLAY_TITLES, T as Theme, V as usePendingStore, W as useNotificationStore, Q as useDrawerStore, B as BUTTON_TEXTS, X as useEntityStore, A as ACTION_OPTIONS, g as getActionIcon, O as useModalStore, F as FORM_ALERTS, Y as useFilterStore, e as getInstrumentationRuleIcon, Z as useDataStreamStore, _ as useInstrumentStore, d as getEntityId, D as DISPLAY_LANGUAGES, M as MONITORS_OPTIONS, S as STORAGE_KEYS, a as DEFAULT_DATA_STREAM_NAME, c as compareCondition, $ as useSetupStore, f as getProgrammingLanguageIcon, I as INSTRUMENTATION_RULE_OPTIONS, a0 as useSelectedStore, l as ImageErrorIcon, a1 as useDarkMode } from './index-40dfa720.js';
4
4
  import { ActionType, ActionKeyTypes, InputTypes, FieldTypes, EntityTypes, StatusType, Crud, OtherStatus, NodeTypes, EdgeTypes, AddNodeTypes, SignalType, HeadersCollectionKeyTypes, CustomInstrumentationsKeyTypes, CodeAttributesKeyTypes, PayloadCollectionKeyTypes, InstrumentationRuleType, K8sResourceKind, ProgrammingLanguages, MountMethod, AgentEnvVarsInjectionMethod, Profile, InstallationMethod } from './types.js';
5
- import { e as DataCardFieldTypes, p as FieldLabel, C as Checkbox, o as FieldError, v as Input, x as InputTable, a3 as Toggle, K as KeyValueInputsList, w as InputList, _ as Text, R as Segment, Q as SectionTitle, j as DocsButton, z as MonitorsCheckboxes, a2 as TextArea, k as Drawer, c as ConditionDetails, D as DataCard, a8 as FlexColumn, M as Modal, N as NavigationButtons, ac as ModalBody, L as NotificationNote, A as AutocompleteInput, i as Divider, W as Status, a7 as FlexRow, a4 as Tooltip, s as IconWrapped, G as MonitorsIcons, ad as TableContainer, ae as TableTitleWrap, r as IconTitleBadge, af as TableWrap, y as InteractiveTable, a9 as CenterThis, J as NoDataFound, a5 as TraceLoader, a as Badge, ag as nodeConfig, ah as useNodesState, ai as useEdgesState, aj as Flow, ak as applyNodeChanges, P as Popup, U as SelectionButton, aa as VerticalScroll, n as Dropdown, B as Button, I as IconButton, E as ExtendArrow, al as AddButton, F as FadeLoader, g as DataTab, X as Stepper, d as DataCardFields, Z as Tag, am as MarkerType, t as IconsNav, an as CopyText, h as DescribeRow, ao as PodContainer, ap as SourceContainer, q as IconGroup, O as PopupForm } from './index-651d36f3.js';
5
+ import { e as DataCardFieldTypes, p as FieldLabel, C as Checkbox, o as FieldError, v as Input, x as InputTable, a3 as Toggle, K as KeyValueInputsList, w as InputList, _ as Text, R as Segment, Q as SectionTitle, j as DocsButton, z as MonitorsCheckboxes, a2 as TextArea, k as Drawer, c as ConditionDetails, D as DataCard, a8 as FlexColumn, M as Modal, N as NavigationButtons, ac as ModalBody, L as NotificationNote, A as AutocompleteInput, i as Divider, W as Status, a7 as FlexRow, a4 as Tooltip, s as IconWrapped, G as MonitorsIcons, ad as TableContainer, ae as TableTitleWrap, r as IconTitleBadge, af as TableWrap, y as InteractiveTable, a9 as CenterThis, J as NoDataFound, a5 as TraceLoader, a as Badge, ag as nodeConfig, ah as useNodesState, ai as useEdgesState, aj as Flow, ak as applyNodeChanges, P as Popup, U as SelectionButton, aa as VerticalScroll, n as Dropdown, B as Button, I as IconButton, E as ExtendArrow, al as AddButton, F as FadeLoader, g as DataTab, X as Stepper, d as DataCardFields, Z as Tag, am as MarkerType, t as IconsNav, an as CopyText, h as DescribeRow, ao as PodContainer, ap as SourceContainer, q as IconGroup, O as PopupForm, S as ScrollX } from './index-c616d2a7.js';
6
6
  import { i as isEmpty, s as safeJsonParse, d as deepClone } from './index-5e5f7bda.js';
7
- import { C as CheckCircledIcon, O as OdigosLogo } from './index-eff01b3d.js';
7
+ import { C as CheckCircledIcon, O as OdigosLogo, E as ErrorTriangleIcon } from './index-eff01b3d.js';
8
8
  import { C as CrossCircledIcon, O as OdigosLogoText, F as FilterIcon, D as DataStreamsIcon, A as ArrowIcon, R as RefreshLeftArrowIcon, N as NotificationIcon, U as UserIcon, a as OverviewIcon, S as SlackLogo, K as KeyIcon, T as TerminalIcon, G as GearIcon } from './index-a53852b3.js';
9
9
  import { useActionFormData, useSessionStorage, useDataStreamFormData, useDestinationFormData, useClickNotification, useSourceFormData, useSourceSelectionFormData } from './hooks.js';
10
10
  import { u as useKeyDown, a as useContainerSize, b as useClickNode, c as usePopup, d as useOnClickOutside, e as useInstrumentationRuleFormData, f as useTransition, g as useTimeAgo, h as useCopy, i as useGenericForm } from './useTransition-2df374a9.js';
11
11
  import { E as EditIcon, T as TrashIcon, S as SearchIcon, h as CheckIcon, P as PlusIcon, a as CopyIcon } from './index-1bc2b507.js';
12
- import { D as DeleteWarning, C as CancelWarning } from './index-41bb44dd.js';
12
+ import { D as DeleteWarning, C as CancelWarning } from './index-941ea41c.js';
13
13
  import { g as getConditionsBooleans, m as mapConditions, b as getStatusIcon, h as splitCamelString, c as capitalizeFirstLetter, i as isStringABoolean, p as parseBooleanFromString } from './index-d92ef50b.js';
14
- import { f as filterActions, l as getEntityLabel, k as getEntityIcon, t as sleep, e as formatBytes, i as getContainersIcons, n as getValueForRange, j as getDestinationIcon, d as filterSourcesByStream, c as filterSources, b as filterDestinationsByStream, a as filterDestinations, s as mapDestinationFieldsForDisplay, p as getYamlFieldsForDestination, m as getMetricForEntity, o as getWorkloadId, q as hasUnhealthyInstances, h as getContainersInstrumentedCount, r as isOverTime, g as formatDuration } from './index-e21ce984.js';
14
+ import { f as filterActions, l as getEntityLabel, k as getEntityIcon, u as sleep, e as formatBytes, i as getContainersIcons, o as getValueForRange, j as getDestinationIcon, d as filterSourcesByStream, c as filterSources, b as filterDestinationsByStream, a as filterDestinations, t as mapDestinationFieldsForDisplay, q as getYamlFieldsForDestination, m as getMetricForEntity, p as getWorkloadId, r as hasUnhealthyInstances, h as getContainersInstrumentedCount, s as isOverTime, n as getRecursiveValues, g as formatDuration } from './index-9e75254d.js';
15
15
  import { m as mapExportedSignals } from './index-6a6bea6e.js';
16
16
  import { NoteBackToSummary, EditButton } from './snippets.js';
17
17
  import { D as DESTINATION_CATEGORIES } from './index-1cb4f9e2.js';
@@ -1614,7 +1614,7 @@ const buildDestinationNodes = ({ loading, entities, positions, unfilteredCount,
1614
1614
 
1615
1615
  const Container$h = styled.div `
1616
1616
  width: 100%;
1617
- height: ${({ $heightToRemove }) => `calc(100vh - ${$heightToRemove})`};
1617
+ height: ${({ $heightToRemove }) => `calc(100vh - ${$heightToRemove}px)`};
1618
1618
  position: relative;
1619
1619
  `;
1620
1620
  const DataFlow = ({ heightToRemove, metrics }) => {
@@ -3821,7 +3821,7 @@ const buildMapNodes = ({ sources, serviceMap, containerHeight, containerWidth })
3821
3821
 
3822
3822
  const Container$7 = styled.div `
3823
3823
  width: 100%;
3824
- height: ${({ $heightToRemove }) => `calc(100vh - ${$heightToRemove})`};
3824
+ height: ${({ $heightToRemove }) => `calc(100vh - ${$heightToRemove}px)`};
3825
3825
  position: relative;
3826
3826
  `;
3827
3827
  const userSource = {
@@ -5230,16 +5230,15 @@ const Container$1 = styled.div `
5230
5230
  display: flex;
5231
5231
  align-items: center;
5232
5232
  width: ${LEFT_MAX_WIDTH}px;
5233
- background-color: ${({ theme }) => theme.colors.dark_grey};
5234
- border-right: 1px solid ${({ theme }) => theme.colors.dropdown_bg_2};
5233
+ background-color: ${({ $withErrors, theme }) => ($withErrors ? theme.colors.error + Theme.opacity.hex['042'] : theme.colors.dark_grey)};
5235
5234
  `;
5236
5235
  const Left = styled(FlexRow) `
5237
5236
  align-items: center;
5237
+ justify-content: space-between;
5238
5238
  gap: 4px;
5239
- padding: 12px 0;
5240
- padding-left: ${({ $depth }) => $depth * 12 || 4}px;
5239
+ padding: 12px;
5240
+ padding-left: ${({ $depth }) => $depth * 12 || 12}px;
5241
5241
  width: calc(${LEFT_MAX_WIDTH}px - ${({ $depth }) => $depth * 12}px);
5242
- overflow: auto;
5243
5242
  `;
5244
5243
  const Right = styled(FlexRow) `
5245
5244
  position: absolute;
@@ -5263,57 +5262,69 @@ const DurationText = styled(Text) `
5263
5262
  font-family: ${({ theme }) => theme.font_family.secondary};
5264
5263
  white-space: nowrap;
5265
5264
  `;
5266
- const Span = ({ depth, indexInMatrix, isHidden, isOpen, onToggleOpen, withToggle, span, maxDuration, minStartTime, maxEndTime }) => {
5265
+ const Span = ({ span, depth, indexInMatrix, maxDuration, minStartTime, maxEndTime, withErrors, errorTooltip, isOpen, withToggle, onToggleOpen }) => {
5267
5266
  const theme = Theme.useTheme();
5268
- if (isHidden)
5269
- return null;
5270
- return (React.createElement(Container$1, { className: 'span-container' },
5267
+ const textMaxWidth = LEFT_MAX_WIDTH -
5268
+ // 12px times depth is the left padding, 12px is the right padding
5269
+ 12 * depth -
5270
+ // 24px is the width of the toggle icon, 4px is the gap between the toggle icon and the text
5271
+ (24 - 4) -
5272
+ // 16px is the width of the error icon, 4px is the gap between the text and the error icon
5273
+ (withErrors ? 16 - 4 : 0);
5274
+ const withErrorIcon = withErrors && (depth === 1 || span.logs.length > 0);
5275
+ return (React.createElement(Container$1, { className: 'span-container', "$withErrors": withErrors },
5271
5276
  React.createElement(Left, { "$depth": depth, className: 'span-left' },
5272
- withToggle ? (React.createElement(IconButton, { onClick: onToggleOpen, size: 24 },
5273
- React.createElement(ExtendArrow, { extend: isOpen }))) : (React.createElement("div", { style: { width: '24px' } })),
5274
- React.createElement(Text, null, span.processID),
5275
- React.createElement(Text, { size: 12, color: theme.text.darker_grey }, span.operationName)),
5277
+ React.createElement(FlexRow, { "$gap": 4, "$alignItems": 'center' },
5278
+ withToggle ? (React.createElement(IconButton, { onClick: onToggleOpen, size: 24 },
5279
+ React.createElement(ExtendArrow, { extend: isOpen ?? false }))) : (React.createElement("div", { style: { width: '24px' } })),
5280
+ React.createElement(ScrollX, { maxWidth: textMaxWidth / 2, text: span.processID, textSize: 14 }),
5281
+ React.createElement(Text, { size: 12, color: theme.text.darker_grey }, "\u2022"),
5282
+ React.createElement(ScrollX, { maxWidth: textMaxWidth / 2, text: span.operationName, textSize: 12, textColor: theme.text.darker_grey })),
5283
+ withErrors &&
5284
+ (withErrorIcon ? (React.createElement(Tooltip, { ...errorTooltip },
5285
+ React.createElement(ErrorTriangleIcon, { fill: theme.text.error }))) : (React.createElement("div", { style: { position: 'relative' } },
5286
+ React.createElement("div", { style: { position: 'absolute', top: '-24px', right: '8px' } },
5287
+ React.createElement(Divider, { type: StatusType.Error, orientation: 'vertical', thickness: 1, length: '48px', margin: '0', opacity: 0.5 })))))),
5276
5288
  React.createElement(Right, { className: 'span-right' },
5277
5289
  React.createElement(DurationBar, { "$indexInMatrix": indexInMatrix, "$duration": span.duration, "$maxDuration": maxDuration, "$startTime": span.startTime, "$minStartTime": minStartTime, "$maxEndTime": maxEndTime },
5278
5290
  React.createElement(DurationText, null, formatDuration(span.duration))))));
5279
5291
  };
5280
- const getChildSpanIds = (span) => {
5281
- return span.spans?.map((s) => [s.spanID, ...getChildSpanIds(s)]).flat() ?? [];
5282
- };
5283
- const renderSpans = (spans, indexInMatrix, depth, minStartTime, maxEndTime, maxDuration, openSpanIdsState) => {
5284
- if (!minStartTime) {
5285
- // is equal left: 0%;
5286
- minStartTime = spans.reduce((min, span) => Math.min(min, span.startTime), Number.MAX_SAFE_INTEGER);
5287
- }
5288
- if (!maxEndTime) {
5289
- // is equal left: 100%;
5290
- maxEndTime = spans.reduce((max, span) => Math.max(max, span.startTime + span.duration), 0);
5291
- }
5292
+ const RecursiveSpans = ({ spans, logs, depth, indexInMatrix, maxDuration, minStartTime, maxEndTime, openSpanIdsState }) => {
5293
+ const theme = Theme.useTheme();
5292
5294
  return spans.map((span, i) => {
5293
5295
  const id = span.spanID;
5294
5296
  const isOpen = openSpanIdsState.value.includes(id);
5295
5297
  const hasChildSpans = !!(span.spans?.length ?? 0);
5296
- return (React.createElement(Fragment, { key: id },
5297
- React.createElement(Span, { depth: depth, indexInMatrix: indexInMatrix + i + depth, isHidden: false, isOpen: isOpen, withToggle: hasChildSpans, onToggleOpen: () => openSpanIdsState.set((prev) => {
5298
+ const allLogs = logs.length ? logs : getRecursiveValues(span, 'spans', 'logs');
5299
+ const withErrors = allLogs.length > 0;
5300
+ const errorTitle = withErrors ? (allLogs.length > 1 ? `(${allLogs.length}) errors` : allLogs[0].fields.find((field) => field.key === 'exception.message')?.value) : undefined;
5301
+ const errorMessage = withErrors ? (allLogs.length > 1 ? undefined : allLogs[0].fields.find((field) => field.key === 'exception.stacktrace')?.value) : undefined;
5302
+ return (React.createElement("div", { key: `span-${id}`, style: { borderBottom: depth === 1 ? `1px dotted ${theme.colors.border}` : 'none' } },
5303
+ React.createElement(Span, { span: span, depth: depth, indexInMatrix: indexInMatrix + i + depth, maxDuration: maxDuration, minStartTime: minStartTime, maxEndTime: maxEndTime, withErrors: withErrors, errorTooltip: {
5304
+ titleIcon: ErrorTriangleIcon,
5305
+ title: errorTitle,
5306
+ text: errorMessage,
5307
+ }, isOpen: isOpen, withToggle: hasChildSpans, onToggleOpen: () => openSpanIdsState.set((prev) => {
5298
5308
  const alreadyOpen = prev.some((st) => st === id);
5299
5309
  if (alreadyOpen)
5300
5310
  return prev.filter((st) => st != id);
5301
- return [...prev, id, ...getChildSpanIds(span)];
5302
- }), span: span, maxDuration: maxDuration, minStartTime: minStartTime, maxEndTime: maxEndTime }),
5303
- isOpen && hasChildSpans ? renderSpans(span.spans || [], indexInMatrix + i, depth + 1, minStartTime, maxEndTime, maxDuration, openSpanIdsState) : null));
5311
+ return [...prev, id, ...getRecursiveValues(span, 'spans', 'spanID')];
5312
+ }) }),
5313
+ isOpen && hasChildSpans ? (React.createElement(RecursiveSpans, { spans: span.spans || [], logs: allLogs, depth: depth + 1, indexInMatrix: indexInMatrix + i, maxDuration: maxDuration, minStartTime: minStartTime, maxEndTime: maxEndTime, openSpanIdsState: openSpanIdsState })) : null));
5304
5314
  });
5305
5315
  };
5306
5316
 
5307
5317
  const Container = styled.div `
5308
5318
  width: 100%;
5309
- height: ${({ $heightToRemove }) => `calc(100vh - ${$heightToRemove})`};
5310
5319
  `;
5311
5320
  const ContainSpans = styled.div `
5321
+ max-height: ${({ $heightToRemove }) => `calc(100vh - ${$heightToRemove}px + 2px)`};
5322
+ overflow: auto;
5323
+
5312
5324
  display: flex;
5313
5325
  flex-direction: column;
5314
- gap: 0;
5326
+
5315
5327
  border-radius: 24px;
5316
- overflow: hidden;
5317
5328
  border: 1px solid ${({ theme }) => theme.colors.dropdown_bg_2};
5318
5329
  position: relative;
5319
5330
  `;
@@ -5325,10 +5336,11 @@ const ContainTitle = styled.div `
5325
5336
  const NUM_OF_DURATION_DIVIDERS = 5;
5326
5337
  const DurationDivider = styled.div `
5327
5338
  width: 1px;
5328
- height: 100%;
5329
- border-left: 1px dashed ${({ theme }) => theme.colors.dropdown_bg_2};
5330
- position: absolute;
5331
- left: calc(${LEFT_MAX_WIDTH}px + ((100% - ${LEFT_MAX_WIDTH}px) / ${NUM_OF_DURATION_DIVIDERS}) * ${({ index }) => index});
5339
+ height: ${({ $heightToRemove }) => `calc(100vh - ${$heightToRemove}px + 2px)`};
5340
+ background: ${({ theme }) => `linear-gradient(to bottom, ${theme.colors.border}, transparent)`};
5341
+
5342
+ position: fixed;
5343
+ left: calc(${LEFT_MAX_WIDTH + 18}px + ((100% - ${LEFT_MAX_WIDTH}px) / ${NUM_OF_DURATION_DIVIDERS}) * ${({ index }) => index});
5332
5344
  z-index: -1;
5333
5345
  `;
5334
5346
  const DurationTitle = styled(Text) `
@@ -5351,14 +5363,21 @@ const TraceView = ({ heightToRemove, traces }) => {
5351
5363
  return Math.max(max, trace.spans.reduce((max, span) => max + span.duration, 0));
5352
5364
  }, 0);
5353
5365
  }, [finalTraces]);
5354
- return (React.createElement(Container, { "$heightToRemove": heightToRemove }, finalTraces.length ? (React.createElement(ContainSpans, null,
5366
+ return (React.createElement(Container, { "$heightToRemove": heightToRemove }, finalTraces.length ? (React.createElement(ContainSpans, { "$heightToRemove": heightToRemove },
5355
5367
  React.createElement(ContainTitle, null,
5356
5368
  React.createElement(Text, null, "Service & operation")),
5357
- finalTraces.map((trace, i) => renderSpans(trace.spans, i, 0, 0, 0, maxDuration, {
5358
- value: openSpanIds,
5359
- set: setOpenSpanIds,
5360
- })),
5361
- new Array(NUM_OF_DURATION_DIVIDERS).fill(null).map((_, i) => (React.createElement(DurationDivider, { key: `${i}-divider`, index: i },
5369
+ finalTraces.map((trace, i) => {
5370
+ const { spans } = trace;
5371
+ // is equal CSS left: 0%;
5372
+ const minStartTime = spans.reduce((min, span) => Math.min(min, span.startTime), Number.MAX_SAFE_INTEGER);
5373
+ // is equal CSS left: 100%;
5374
+ const maxEndTime = spans.reduce((max, span) => Math.max(max, span.startTime + span.duration), 0);
5375
+ return (React.createElement(RecursiveSpans, { key: `recursive-spans-${trace.traceID}`, spans: spans, logs: [], depth: 1, indexInMatrix: i, maxDuration: maxDuration, minStartTime: minStartTime, maxEndTime: maxEndTime, openSpanIdsState: {
5376
+ value: openSpanIds,
5377
+ set: setOpenSpanIds,
5378
+ } }));
5379
+ }),
5380
+ new Array(NUM_OF_DURATION_DIVIDERS).fill(null).map((_, i) => (React.createElement(DurationDivider, { key: `${i}-divider`, "$heightToRemove": heightToRemove, index: i },
5362
5381
  React.createElement(DurationTitle, null, formatDuration((maxDuration / NUM_OF_DURATION_DIVIDERS) * i))))))) : (React.createElement(CenterThis, { "$height": '50vh' },
5363
5382
  React.createElement(NoDataFound, { title: DISPLAY_TITLES.NO_TRACES_FOUND, subTitle: DISPLAY_TITLES.ARE_SERVICES_INSTRUMENTED_AND_PRODUCING_TRAFFIC })))));
5364
5383
  };
@@ -0,0 +1,4 @@
1
+ type RecrusiveObject = Record<string, RecrusiveObject[]>;
2
+ type ReturnObject = Record<string, unknown>;
3
+ export declare const getRecursiveValues: <RootItem = RecrusiveObject, ReturnItem = ReturnObject>(obj: RootItem, childrenKey: keyof RootItem, returnKey: keyof RootItem) => ReturnItem[];
4
+ export {};
@@ -26,6 +26,7 @@ export * from './get-monitor-icon';
26
26
  export * from './get-platform-icon';
27
27
  export * from './get-platform-label';
28
28
  export * from './get-programming-language-icon';
29
+ export * from './get-recursive-values';
29
30
  export * from './get-sse-target-from-id';
30
31
  export * from './get-status-icon';
31
32
  export * from './get-value-for-range';
package/lib/functions.js CHANGED
@@ -2,7 +2,7 @@ export { c as capitalizeFirstLetter, f as flattenObjectKeys, g as getConditionsB
2
2
  import { K as K8sLogo } from './index-40dfa720.js';
3
3
  export { c as compareCondition, g as getActionIcon, d as getEntityId, e as getInstrumentationRuleIcon, f as getProgrammingLanguageIcon } from './index-40dfa720.js';
4
4
  export { d as deepClone, i as isEmpty, s as safeJsonParse } from './index-5e5f7bda.js';
5
- export { f as filterActions, a as filterDestinations, b as filterDestinationsByStream, c as filterSources, d as filterSourcesByStream, e as formatBytes, g as formatDuration, i as getContainersIcons, h as getContainersInstrumentedCount, j as getDestinationIcon, k as getEntityIcon, l as getEntityLabel, m as getMetricForEntity, n as getValueForRange, o as getWorkloadId, p as getYamlFieldsForDestination, q as hasUnhealthyInstances, r as isOverTime, s as mapDestinationFieldsForDisplay, t as sleep } from './index-e21ce984.js';
5
+ export { f as filterActions, a as filterDestinations, b as filterDestinationsByStream, c as filterSources, d as filterSourcesByStream, e as formatBytes, g as formatDuration, i as getContainersIcons, h as getContainersInstrumentedCount, j as getDestinationIcon, k as getEntityIcon, l as getEntityLabel, m as getMetricForEntity, n as getRecursiveValues, o as getValueForRange, p as getWorkloadId, q as getYamlFieldsForDestination, r as hasUnhealthyInstances, s as isOverTime, t as mapDestinationFieldsForDisplay, u as sleep } from './index-9e75254d.js';
6
6
  export { g as getIdFromSseTarget, i as isLegalK8sLabel, m as mapExportedSignals } from './index-6a6bea6e.js';
7
7
  import { ProgrammingLanguages, PlatformType, EntityTypes } from './types.js';
8
8
  import 'react';
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { a6 as WarningModal } from './index-651d36f3.js';
2
+ import { a6 as WarningModal } from './index-c616d2a7.js';
3
3
  import { StatusType, EntityTypes } from './types.js';
4
4
  import './index-40dfa720.js';
5
5
  import 'styled-components';
@@ -250,6 +250,26 @@ const getMetricForEntity = (metrics, entityType, entityId) => {
250
250
  return metric || { throughput: 0 };
251
251
  };
252
252
 
253
+ const getRecursiveValues = (obj, childrenKey, returnKey) => {
254
+ const children = obj[childrenKey];
255
+ if (!children)
256
+ return [];
257
+ return children.flatMap((item) => {
258
+ const values = item[returnKey];
259
+ const result = [];
260
+ if (values !== undefined) {
261
+ if (Array.isArray(values)) {
262
+ result.push(...values);
263
+ }
264
+ else {
265
+ result.push(values);
266
+ }
267
+ }
268
+ result.push(...getRecursiveValues(item, childrenKey, returnKey));
269
+ return result;
270
+ });
271
+ };
272
+
253
273
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
254
274
  const getValueForRange = (current, matrix) => {
255
275
  // CURRENT: represents the current value (such as window width)
@@ -317,4 +337,4 @@ const mapDestinationFieldsForDisplay = (destination, yamlFields) => {
317
337
 
318
338
  const sleep = async (ms = 1000) => new Promise((resolve) => setTimeout(resolve, ms));
319
339
 
320
- export { filterDestinations as a, filterDestinationsByStream as b, filterSources as c, filterSourcesByStream as d, formatBytes as e, filterActions as f, formatDuration as g, getContainersInstrumentedCount as h, getContainersIcons as i, getDestinationIcon as j, getEntityIcon as k, getEntityLabel as l, getMetricForEntity as m, getValueForRange as n, getWorkloadId as o, getYamlFieldsForDestination as p, hasUnhealthyInstances as q, isOverTime as r, mapDestinationFieldsForDisplay as s, sleep as t };
340
+ export { filterDestinations as a, filterDestinationsByStream as b, filterSources as c, filterSourcesByStream as d, formatBytes as e, filterActions as f, formatDuration as g, getContainersInstrumentedCount as h, getContainersIcons as i, getDestinationIcon as j, getEntityIcon as k, getEntityLabel as l, getMetricForEntity as m, getRecursiveValues as n, getValueForRange as o, getWorkloadId as p, getYamlFieldsForDestination as q, hasUnhealthyInstances as r, isOverTime as s, mapDestinationFieldsForDisplay as t, sleep as u };
@@ -556,14 +556,11 @@ const Tooltip = ({ withIcon, titleIcon: TitleIcon, title, text, timestamp, child
556
556
  children,
557
557
  withIcon && React.createElement(InfoIcon, null),
558
558
  React.createElement(Popup, { ref: popupRef, isOpen: popupOpen, top: popupPosition.top, left: popupPosition.left, asPortal: true, withPointerEvents: hasLinks, onMouseEnter: hasLinks ? handleMouseEvent : undefined, maxWidth: '270px', borderRadius: '16px', padding: '8px 12px' },
559
- React.createElement(Text, { size: 12, color: theme.text.secondary },
560
- (!!TitleIcon || !!title) && (React.createElement(FlexRow, { style: { marginBottom: '4px' }, "$gap": 4 },
561
- TitleIcon && React.createElement(TitleIcon, { fill: theme.text.secondary, size: 12 }),
562
- title && React.createElement(React.Fragment, null,
563
- title,
564
- "\u00A0-\u00A0"))),
565
- React.createElement(TextBreakWord, { size: 12, color: theme.text.info }, text),
566
- !!timestamp && (React.createElement(Text, { size: 10, color: theme.text.darker_grey, family: 'secondary', style: { marginTop: '8px' } }, new Date(timestamp).toLocaleString()))))));
559
+ (!!TitleIcon || !!title) && (React.createElement(FlexRow, { style: { marginBottom: '4px' }, "$gap": 4 },
560
+ TitleIcon && React.createElement(TitleIcon, { size: 12, fill: theme.text.secondary }),
561
+ title && (React.createElement(Text, { size: 12, color: theme.text.secondary }, title)))),
562
+ React.createElement(TextBreakWord, { size: 12, color: theme.text.info }, text),
563
+ !!timestamp && (React.createElement(Text, { size: 10, color: theme.text.darker_grey, family: 'secondary', style: { marginTop: '8px' } }, new Date(timestamp).toLocaleString())))));
567
564
  };
568
565
 
569
566
  const Container$F = styled.div `
@@ -4147,9 +4144,10 @@ const StyledDivider = styled.div `
4147
4144
  height: ${({ $orientation, $thickness, $length }) => ($orientation === 'horizontal' ? `${$thickness}px` : $length || '100%')};
4148
4145
  margin: ${({ $orientation, $margin }) => $margin || ($orientation === 'horizontal' ? '8px 0' : '0 8px')};
4149
4146
  background-color: ${({ $type, theme }) => (!!$type ? theme.text[$type] : theme.colors.border) + Theme.opacity.hex['050']};
4147
+ opacity: ${({ $opacity }) => $opacity || 1};
4150
4148
  `;
4151
- const Divider = ({ orientation = 'horizontal', type, thickness = 1, length, margin }) => {
4152
- return React.createElement(StyledDivider, { "$orientation": orientation, "$type": type, "$thickness": thickness, "$length": length, "$margin": margin });
4149
+ const Divider = ({ orientation = 'horizontal', type, thickness = 1, length, margin, opacity }) => {
4150
+ return React.createElement(StyledDivider, { "$orientation": orientation, "$type": type, "$thickness": thickness, "$length": length, "$margin": margin, "$opacity": opacity });
4153
4151
  };
4154
4152
 
4155
4153
  const Container$B = styled.div `
package/lib/snippets.js CHANGED
@@ -1,5 +1,5 @@
1
- import { B as Button, _ as Text, L as NotificationNote } from './index-651d36f3.js';
2
- export { al as AddButton, aq as AddNode, ar as BaseNode, an as CopyText, as as EdgedNode, aj as Flow, at as FrameNode, au as HeaderNode, az as LabeledEdge, av as MapItemNode, aw as NoDataNode, ao as PodContainer, ax as ScrollNode, ay as SkeletonNode, ap as SourceContainer, ag as nodeConfig } from './index-651d36f3.js';
1
+ import { B as Button, _ as Text, L as NotificationNote } from './index-c616d2a7.js';
2
+ export { al as AddButton, aq as AddNode, ar as BaseNode, an as CopyText, as as EdgedNode, aj as Flow, at as FrameNode, au as HeaderNode, az as LabeledEdge, av as MapItemNode, aw as NoDataNode, ao as PodContainer, ax as ScrollNode, ay as SkeletonNode, ap as SourceContainer, ag as nodeConfig } from './index-c616d2a7.js';
3
3
  import React from 'react';
4
4
  import { T as Theme, B as BUTTON_TEXTS, b as DISPLAY_TITLES } from './index-40dfa720.js';
5
5
  import { E as EditIcon } from './index-1bc2b507.js';
@@ -8,7 +8,7 @@ interface TraceReference {
8
8
  traceID: string;
9
9
  spanID: string;
10
10
  }
11
- interface TraceLog {
11
+ export interface TraceLog {
12
12
  timestamp: number;
13
13
  fields: TraceTag[];
14
14
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@odigos/ui-kit",
3
- "version": "0.0.90",
3
+ "version": "0.0.92",
4
4
  "author": "Odigos",
5
5
  "repository": {
6
6
  "type": "git",