@odigos/ui-kit 0.0.90 → 0.0.91

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,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.0.91](https://github.com/odigos-io/ui-kit/compare/ui-kit-v0.0.90...ui-kit-v0.0.91) (2025-08-24)
4
+
5
+
6
+ ### Features
7
+
8
+ * **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))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * trace-view visual fixes ([#344](https://github.com/odigos-io/ui-kit/issues/344)) ([8eec6ee](https://github.com/odigos-io/ui-kit/commit/8eec6eea76972440656e5cb5891be7df56e26c04))
14
+
3
15
  ## [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
16
 
5
17
 
@@ -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,20 +1,22 @@
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;
4
6
  depth: number;
5
7
  indexInMatrix: number;
6
- isHidden: boolean;
7
- isOpen: boolean;
8
- onToggleOpen: () => void;
9
- withToggle: boolean;
10
- span: TraceSpan;
11
8
  maxDuration: number;
12
9
  minStartTime: number;
13
10
  maxEndTime: number;
11
+ withErrors?: boolean;
12
+ errorTooltip?: TooltipProps;
13
+ isOpen?: boolean;
14
+ withToggle?: boolean;
15
+ onToggleOpen?: () => void;
14
16
  }
15
17
  export declare const LEFT_MAX_WIDTH = 370;
16
18
  declare const Span: FC<SpanProps>;
17
- declare const renderSpans: (spans: TraceSpan[], indexInMatrix: number, depth: number, minStartTime: number, maxEndTime: number, maxDuration: number, openSpanIdsState: {
19
+ declare const renderSpans: (spans: TraceSpan[], logs: TraceLog[], depth: number, indexInMatrix: number, maxDuration: number, minStartTime: number, maxEndTime: number, openSpanIdsState: {
18
20
  value: string[];
19
21
  set: React.Dispatch<React.SetStateAction<string[]>>;
20
22
  }) => React.JSX.Element[];
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';
@@ -5230,14 +5230,14 @@ 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
5242
  overflow: auto;
5243
5243
  `;
@@ -5263,57 +5263,68 @@ const DurationText = styled(Text) `
5263
5263
  font-family: ${({ theme }) => theme.font_family.secondary};
5264
5264
  white-space: nowrap;
5265
5265
  `;
5266
- const Span = ({ depth, indexInMatrix, isHidden, isOpen, onToggleOpen, withToggle, span, maxDuration, minStartTime, maxEndTime }) => {
5266
+ const Span = ({ span, depth, indexInMatrix, maxDuration, minStartTime, maxEndTime, withErrors, errorTooltip, isOpen, withToggle, onToggleOpen }) => {
5267
5267
  const theme = Theme.useTheme();
5268
- if (isHidden)
5269
- return null;
5270
- return (React.createElement(Container$1, { className: 'span-container' },
5268
+ const textMaxWidth = LEFT_MAX_WIDTH -
5269
+ // 24px is the width of the toggle icon, 4px is the gap between the toggle icon and the text
5270
+ (withToggle ? 24 - 4 : 0) -
5271
+ // 16px is the width of the error icon, 4px is the gap between the text and the error icon
5272
+ (withErrors ? 16 - 4 : 0) -
5273
+ // 12px times depth is the left padding, 12px is the right padding
5274
+ 12 * depth;
5275
+ const withErrorIcon = withErrors && (depth === 1 || span.logs.length > 0);
5276
+ return (React.createElement(Container$1, { className: 'span-container', "$withErrors": withErrors },
5271
5277
  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)),
5278
+ React.createElement(FlexRow, { "$gap": 4, "$alignItems": 'center' },
5279
+ withToggle ? (React.createElement(IconButton, { onClick: onToggleOpen, size: 24 },
5280
+ React.createElement(ExtendArrow, { extend: isOpen ?? false }))) : (React.createElement("div", { style: { width: '24px' } })),
5281
+ React.createElement(ScrollX, { maxWidth: textMaxWidth / 2, text: span.processID, textSize: 14 }),
5282
+ React.createElement(Text, { size: 12, color: theme.text.darker_grey }, "\u2022"),
5283
+ React.createElement(ScrollX, { maxWidth: textMaxWidth / 2, text: span.operationName, textSize: 12, textColor: theme.text.darker_grey })),
5284
+ withErrors &&
5285
+ (withErrorIcon ? (React.createElement(Tooltip, { ...errorTooltip },
5286
+ React.createElement(ErrorTriangleIcon, { fill: theme.text.error }))) : (React.createElement("div", { style: { position: 'relative' } },
5287
+ React.createElement("div", { style: { position: 'absolute', top: '-32px', right: '8px' } },
5288
+ React.createElement(Divider, { type: StatusType.Error, orientation: 'vertical', thickness: 1, length: '64px', margin: '0', opacity: 0.5 })))))),
5276
5289
  React.createElement(Right, { className: 'span-right' },
5277
5290
  React.createElement(DurationBar, { "$indexInMatrix": indexInMatrix, "$duration": span.duration, "$maxDuration": maxDuration, "$startTime": span.startTime, "$minStartTime": minStartTime, "$maxEndTime": maxEndTime },
5278
5291
  React.createElement(DurationText, null, formatDuration(span.duration))))));
5279
5292
  };
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
- }
5293
+ const renderSpans = (spans, logs, depth, indexInMatrix, maxDuration, minStartTime, maxEndTime, openSpanIdsState) => {
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);
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;
5296
5302
  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) => {
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 ? renderSpans(span.spans || [], allLogs, depth + 1, indexInMatrix + i, maxDuration, minStartTime, maxEndTime, 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} + 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,10 @@ 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%;
5339
+ height: ${({ $heightToRemove }) => `calc(100vh - ${$heightToRemove} + 2px)`};
5329
5340
  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});
5341
+ position: fixed;
5342
+ left: calc(${LEFT_MAX_WIDTH + 18}px + ((100% - ${LEFT_MAX_WIDTH}px) / ${NUM_OF_DURATION_DIVIDERS}) * ${({ index }) => index});
5332
5343
  z-index: -1;
5333
5344
  `;
5334
5345
  const DurationTitle = styled(Text) `
@@ -5351,14 +5362,21 @@ const TraceView = ({ heightToRemove, traces }) => {
5351
5362
  return Math.max(max, trace.spans.reduce((max, span) => max + span.duration, 0));
5352
5363
  }, 0);
5353
5364
  }, [finalTraces]);
5354
- return (React.createElement(Container, { "$heightToRemove": heightToRemove }, finalTraces.length ? (React.createElement(ContainSpans, null,
5365
+ return (React.createElement(Container, { "$heightToRemove": heightToRemove }, finalTraces.length ? (React.createElement(ContainSpans, { "$heightToRemove": heightToRemove },
5355
5366
  React.createElement(ContainTitle, null,
5356
5367
  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 },
5368
+ finalTraces.map((trace, i) => {
5369
+ const { spans } = trace;
5370
+ // is equal CSS left: 0%;
5371
+ const minStartTime = spans.reduce((min, span) => Math.min(min, span.startTime), Number.MAX_SAFE_INTEGER);
5372
+ // is equal CSS left: 100%;
5373
+ const maxEndTime = spans.reduce((max, span) => Math.max(max, span.startTime + span.duration), 0);
5374
+ return renderSpans(spans, [], 1, i, maxDuration, minStartTime, maxEndTime, {
5375
+ value: openSpanIds,
5376
+ set: setOpenSpanIds,
5377
+ });
5378
+ }),
5379
+ new Array(NUM_OF_DURATION_DIVIDERS).fill(null).map((_, i) => (React.createElement(DurationDivider, { key: `${i}-divider`, "$heightToRemove": heightToRemove, index: i },
5362
5380
  React.createElement(DurationTitle, null, formatDuration((maxDuration / NUM_OF_DURATION_DIVIDERS) * i))))))) : (React.createElement(CenterThis, { "$height": '50vh' },
5363
5381
  React.createElement(NoDataFound, { title: DISPLAY_TITLES.NO_TRACES_FOUND, subTitle: DISPLAY_TITLES.ARE_SERVICES_INSTRUMENTED_AND_PRODUCING_TRAFFIC })))));
5364
5382
  };
@@ -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.91",
4
4
  "author": "Odigos",
5
5
  "repository": {
6
6
  "type": "git",