@odigos/ui-kit 0.0.49 → 0.0.50
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 +12 -0
- package/lib/components/data-card/data-card-fields/index.d.ts +1 -5
- package/lib/components/data-card/data-card.stories.d.ts +4 -4
- package/lib/components/data-finger/data-finger.stories.d.ts +9 -0
- package/lib/components/data-finger/index.d.ts +12 -0
- package/lib/components/icon-button/index.d.ts +2 -0
- package/lib/components/index.d.ts +5 -0
- package/lib/components/popup/index.d.ts +17 -0
- package/lib/components/popup/popup.stories.d.ts +9 -0
- package/lib/components/popup-form/index.d.ts +18 -0
- package/lib/components/popup-form/popup-form.stories.d.ts +10 -0
- package/lib/components/tag/index.d.ts +8 -0
- package/lib/components/tag/tag.stories.d.ts +13 -0
- package/lib/components.js +8 -8
- package/lib/constants.js +1 -1
- package/lib/containers/service-map/helpers/generate-dag-positions.d.ts +5 -0
- package/lib/containers/service-map/helpers/generate-spiral-grid-position.d.ts +2 -0
- package/lib/containers/service-map/index.d.ts +2 -2
- package/lib/containers/system-overview/describe/index.d.ts +1 -1
- package/lib/containers.js +262 -368
- package/lib/functions/has-unhealthy-instances/index.d.ts +2 -0
- package/lib/functions/index.d.ts +1 -0
- package/lib/functions.js +5 -5
- package/lib/hooks/index.d.ts +1 -0
- package/lib/hooks/usePopup.d.ts +17 -0
- package/lib/hooks.js +3 -3
- package/lib/icons/common/avatar-icon/avatar-icon.stories.d.ts +8 -0
- package/lib/icons/common/avatar-icon/index.d.ts +2 -0
- package/lib/icons/common/index.d.ts +2 -0
- package/lib/icons/common/user-group-icon/index.d.ts +2 -0
- package/lib/icons/common/user-group-icon/user-group-icon.stories.d.ts +8 -0
- package/lib/icons/math/index.d.ts +2 -0
- package/lib/icons/math/minus-circled-icon/index.d.ts +2 -0
- package/lib/icons/math/minus-circled-icon/minus-circled-icon.stories.d.ts +8 -0
- package/lib/icons/math/plus-circled-icon/index.d.ts +2 -0
- package/lib/icons/math/plus-circled-icon/plus-circled-icon.stories.d.ts +8 -0
- package/lib/icons.js +35 -7
- package/lib/{index-Bw7RE2T2.js → index-BC03UmY5.js} +8 -1
- package/lib/{index-ZTzxu5fz.js → index-CMsBAVAn.js} +2 -2
- package/lib/{index-w9lkC6fb.js → index-CPMIZB66.js} +12 -4
- package/lib/{index-C1V7D2ey.js → index-CgdNGqvh.js} +2270 -2205
- package/lib/{index-CkTdd3MS.js → index-CyHOJpMl.js} +1 -1
- package/lib/{index-DsEoqSQn.js → index-Dbs7YARA.js} +2 -2
- package/lib/{index-DOU0EdZP.js → index-DnhO-nLH.js} +2 -2
- package/lib/{index-DxR7e2Cq.js → index-H8TwBQHm.js} +1 -1
- package/lib/{index-CeDmxXUE.js → index-LgzkJ05H.js} +2 -2
- package/lib/{index-CeBxw8J4.js → index-r72g3gV5.js} +4 -4
- package/lib/snippets/copy-text/index.d.ts +6 -0
- package/lib/snippets/index.d.ts +5 -2
- package/lib/snippets/pod-container/index.d.ts +5 -0
- package/lib/snippets/source-container/index.d.ts +7 -0
- package/lib/snippets.js +7 -7
- package/lib/store/index.d.ts +1 -0
- package/lib/store/useActiveNodeStore.d.ts +11 -0
- package/lib/store.js +1 -1
- package/lib/theme.js +1 -1
- package/lib/types/describe/index.d.ts +2 -2
- package/lib/types/sources/index.d.ts +10 -9
- package/lib/{useSourceSelectionFormData-C5VMfWEf.js → useSourceSelectionFormData-CwggurLH.js} +2 -2
- package/lib/{useTransition-mupXsbop.js → useTransition-DmHfJSEP.js} +38 -6
- package/package.json +1 -1
- package/lib/containers/data-flow-actions-menu/search/recent-searches/index.d.ts +0 -2
- /package/lib/{components/data-card/data-card-fields → snippets/source-container}/override-runtime.d.ts +0 -0
package/lib/containers.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import React, { useState, useEffect, forwardRef, useRef, useImperativeHandle, useMemo, Fragment, useCallback } from 'react';
|
|
1
|
+
import React, { useState, useEffect, forwardRef, useRef, useImperativeHandle, useMemo, Fragment, useCallback, Children } from 'react';
|
|
2
2
|
import styled, { css } from 'styled-components';
|
|
3
|
-
import {
|
|
3
|
+
import { m as DISPLAY_TITLES, T as Theme, i as usePendingStore, h as useNotificationStore, c as useDrawerStore, B as BUTTON_TEXTS, d as useEntityStore, A as ACTION_OPTIONS, n as getActionIcon, g as useModalStore, F as FORM_ALERTS, e as useFilterStore, M as MONITORS_OPTIONS, p as getInstrumentationRuleIcon, b as useDataStreamStore, f as useInstrumentStore, o as getEntityId, S as STORAGE_KEYS, l as DEFAULT_DATA_STREAM_NAME, k as useSetupStore, I as INSTRUMENTATION_RULE_OPTIONS, j as useSelectedStore, v as ImageErrorIcon, a as useDarkMode } from './index-BC03UmY5.js';
|
|
4
4
|
import { ActionType, ActionKeyTypes, InputTypes, FieldTypes, EntityTypes, StatusType, Crud, OtherStatus, NodeTypes, EdgeTypes, AddNodeTypes, SignalType, HeadersCollectionKeyTypes, CustomInstrumentationsKeyTypes, CodeAttributesKeyTypes, PayloadCollectionKeyTypes, InstrumentationRuleType, K8sResourceKind } from './types.js';
|
|
5
|
-
import {
|
|
5
|
+
import { l as DataCardFieldTypes, z as FieldLabel, h as Checkbox, y as FieldError, U as Input, W as InputTable, Y as KeyValueInputsList, V as InputList, ad as Text, a7 as Segment, a6 as SectionTitle, r as DocsButton, _ as MonitorsCheckboxes, ae as TextArea, s as Drawer, j as ConditionDetails, D as DataCard, ak as FlexColumn, Z as Modal, a0 as NavigationButtons, ao as ModalBody, a2 as NotificationNote, f as AutocompleteInput, q as Divider, aa as Status, aj as FlexRow, ag as Tooltip, O as IconWrapped, $ as MonitorsIcons, ap as TableContainer, aq as TableTitleWrap, K as IconTitleBadge, ar as TableWrap, X as InteractiveTable, al as CenterThis, a1 as NoDataFound, ah as TraceLoader, g as Badge, w as ExtendArrow, am as VerticalScroll, a8 as SelectionButton, e as Button, v as Dropdown, n as nodeConfig, as as useNodesState, at as useEdgesState, F as Flow, au as applyNodeChanges, a3 as Popup, af as Toggle, I as IconButton, A as AddButton, x as FadeLoader, o as DataTab, ab as Stepper, k as DataCardFields, av as MarkerType, Q as IconsNav, C as CopyText, p as DescribeRow, P as PodContainer, d as SourceContainer, J as IconGroup, a4 as PopupForm } from './index-CgdNGqvh.js';
|
|
6
6
|
import { i as isEmpty, s as safeJsonParse } from './index-BnvrwbRB.js';
|
|
7
|
-
import { C as CheckCircledIcon, O as OdigosLogo } from './index-
|
|
8
|
-
import { C as CrossCircledIcon, O as OdigosLogoText, a as OverviewIcon, F as FilterIcon, D as DataStreamsIcon, R as RetryIcon, N as NotificationIcon, U as UserIcon, S as SlackLogo, K as KeyIcon, T as TerminalIcon } from './index-
|
|
9
|
-
import { u as useActionFormData, d as useSessionStorage, b as useDataStreamFormData, c as useDestinationFormData, a as useClickNotification, e as useSourceFormData, f as useSourceSelectionFormData } from './useSourceSelectionFormData-
|
|
10
|
-
import { e as useKeyDown, f as useOnClickOutside, a as useContainerSize, u as useClickNode, d as useInstrumentationRuleFormData,
|
|
11
|
-
import { E as EditIcon, T as TrashIcon, S as SearchIcon, h as CheckIcon, A as ArrowIcon, P as PlusIcon, a as CopyIcon
|
|
12
|
-
import { D as DeleteWarning, C as CancelWarning } from './index-
|
|
13
|
-
import { g as getConditionsBooleans, m as mapConditions, b as getStatusIcon, c as capitalizeFirstLetter } from './index-
|
|
14
|
-
import { f as filterActions, m as getEntityLabel, l as getEntityIcon,
|
|
7
|
+
import { C as CheckCircledIcon, O as OdigosLogo } from './index-H8TwBQHm.js';
|
|
8
|
+
import { C as CrossCircledIcon, O as OdigosLogoText, a as OverviewIcon, F as FilterIcon, D as DataStreamsIcon, R as RetryIcon, N as NotificationIcon, U as UserIcon, S as SlackLogo, K as KeyIcon, T as TerminalIcon } from './index-LgzkJ05H.js';
|
|
9
|
+
import { u as useActionFormData, d as useSessionStorage, b as useDataStreamFormData, c as useDestinationFormData, a as useClickNotification, e as useSourceFormData, f as useSourceSelectionFormData } from './useSourceSelectionFormData-CwggurLH.js';
|
|
10
|
+
import { e as useKeyDown, f as useOnClickOutside, a as useContainerSize, u as useClickNode, g as usePopup, d as useInstrumentationRuleFormData, i as useTransition, h as useTimeAgo, b as useCopy, c as useGenericForm } from './useTransition-DmHfJSEP.js';
|
|
11
|
+
import { E as EditIcon, T as TrashIcon, S as SearchIcon, h as CheckIcon, A as ArrowIcon, P as PlusIcon, a as CopyIcon } from './index-CyHOJpMl.js';
|
|
12
|
+
import { D as DeleteWarning, C as CancelWarning } from './index-DnhO-nLH.js';
|
|
13
|
+
import { g as getConditionsBooleans, m as mapConditions, b as getStatusIcon, c as capitalizeFirstLetter, p as parseBooleanFromString } from './index-Dbs7YARA.js';
|
|
14
|
+
import { f as filterActions, m as getEntityLabel, l as getEntityIcon, w as sleep, o as getPlatformIcon, p as getPlatformLabel, h as formatBytes, j as getContainersIcons, q as getValueForRange, k as getDestinationIcon, g as filterSourcesByStream, e as filterSources, b as filterDestinationsByStream, a as filterDestinations, v as mapDestinationFieldsForDisplay, c as compareCondition, s as getYamlFieldsForDestination, d as deepClone, n as getMetricForEntity, r as getWorkloadId, t as hasUnhealthyInstances, i as getContainersInstrumentedCount, u as isOverTime } from './index-CPMIZB66.js';
|
|
15
15
|
import { m as mapExportedSignals } from './index-BlZKWuxe.js';
|
|
16
|
-
import { N as NoteBackToSummary, E as EditButton } from './index-
|
|
16
|
+
import { N as NoteBackToSummary, E as EditButton } from './index-r72g3gV5.js';
|
|
17
17
|
import { D as DESTINATION_CATEGORIES } from './index-Dqief9td.js';
|
|
18
|
-
import { a6 as RulesIcon, a7 as SourcesIcon, a3 as ActionsIcon, a4 as DestinationsIcon } from './index-
|
|
18
|
+
import { a6 as RulesIcon, a7 as SourcesIcon, a3 as ActionsIcon, a4 as DestinationsIcon } from './index-CMsBAVAn.js';
|
|
19
19
|
import 'react-dom';
|
|
20
20
|
|
|
21
21
|
const buildCard$3 = (action) => {
|
|
@@ -1032,7 +1032,7 @@ const PushToEnd$1 = styled.div `
|
|
|
1032
1032
|
const RelativeContainer$3 = styled.div `
|
|
1033
1033
|
position: relative;
|
|
1034
1034
|
`;
|
|
1035
|
-
const AbsoluteContainer
|
|
1035
|
+
const AbsoluteContainer = styled.div `
|
|
1036
1036
|
position: absolute;
|
|
1037
1037
|
top: calc(100% + 8px);
|
|
1038
1038
|
left: 0;
|
|
@@ -1070,7 +1070,7 @@ const ComputePlatformSelect = ({ connections, selected, onSelect, onViewAll }) =
|
|
|
1070
1070
|
React.createElement(Title$2, null, selected?.name || selected?.id || 'no platform'),
|
|
1071
1071
|
withSelect && (React.createElement(PushToEnd$1, null,
|
|
1072
1072
|
React.createElement(ExtendArrow, { extend: isOpen, align: 'right' })))),
|
|
1073
|
-
isOpen && withSelect && (React.createElement(AbsoluteContainer
|
|
1073
|
+
isOpen && withSelect && (React.createElement(AbsoluteContainer, null,
|
|
1074
1074
|
React.createElement(HeadWrap, null,
|
|
1075
1075
|
React.createElement(Input, { placeholder: 'Search...', icon: SearchIcon, value: searchText, onChange: (e) => setSearchText(e.target.value.toLowerCase()) })),
|
|
1076
1076
|
React.createElement(VerticalScroll, { style: { maxHeight: '240px' } }, filtered.map(({ id, type, name, status }, idx) => (React.createElement(SelectionButton, { key: `platform-${id}`, icon: () => getPlatformIcon(type)({ fill: status === StatusType.Success ? theme.text.success : theme.text.error }), label: `${!!name ? name : getPlatformLabel(type)} (${id})`, isSelected: selected?.id === id, onClick: () => {
|
|
@@ -1873,7 +1873,7 @@ const RelativeContainer$2 = styled.div `
|
|
|
1873
1873
|
position: relative;
|
|
1874
1874
|
max-width: 200px;
|
|
1875
1875
|
`;
|
|
1876
|
-
|
|
1876
|
+
styled.div `
|
|
1877
1877
|
position: absolute;
|
|
1878
1878
|
top: calc(100% + 8px);
|
|
1879
1879
|
left: 0;
|
|
@@ -1947,8 +1947,6 @@ const buildSearchResults = ({ instrumentationRules, sources, actions, destinatio
|
|
|
1947
1947
|
const HorizontalScroll = styled.div `
|
|
1948
1948
|
display: flex;
|
|
1949
1949
|
align-items: center;
|
|
1950
|
-
padding: 12px;
|
|
1951
|
-
border-bottom: ${({ theme }) => `1px solid ${theme.colors.border}`};
|
|
1952
1950
|
overflow-x: scroll;
|
|
1953
1951
|
`;
|
|
1954
1952
|
const SearchResults = ({ searchText, onClose }) => {
|
|
@@ -1956,6 +1954,13 @@ const SearchResults = ({ searchText, onClose }) => {
|
|
|
1956
1954
|
const { onClickNode } = useClickNode();
|
|
1957
1955
|
const { selectedStreamName } = useDataStreamStore();
|
|
1958
1956
|
const { sources, destinations, actions, instrumentationRules } = useEntityStore();
|
|
1957
|
+
const { popupRef, popupOpen, setPopupOpen, popupPosition, handlePosition } = usePopup();
|
|
1958
|
+
useEffect(() => {
|
|
1959
|
+
if (!popupOpen) {
|
|
1960
|
+
handlePosition(0, 50);
|
|
1961
|
+
setPopupOpen(true);
|
|
1962
|
+
}
|
|
1963
|
+
}, [popupOpen]);
|
|
1959
1964
|
const [selectedCategory, setSelectedCategory] = useState('all');
|
|
1960
1965
|
const { categories, searchResults } = useMemo(() => buildSearchResults({
|
|
1961
1966
|
instrumentationRules,
|
|
@@ -1966,21 +1971,19 @@ const SearchResults = ({ searchText, onClose }) => {
|
|
|
1966
1971
|
selectedCategory,
|
|
1967
1972
|
}), [instrumentationRules, sources, actions, destinations, selectedStreamName, searchText, selectedCategory]);
|
|
1968
1973
|
if (!searchResults.length) {
|
|
1969
|
-
return (React.createElement(
|
|
1974
|
+
return (React.createElement(Popup, { ref: popupRef, isOpen: popupOpen, top: popupPosition.top, left: popupPosition.left },
|
|
1970
1975
|
React.createElement(NoDataFound, null)));
|
|
1971
1976
|
}
|
|
1972
|
-
return (React.createElement(
|
|
1973
|
-
React.createElement(
|
|
1974
|
-
|
|
1975
|
-
React.createElement(
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
}, style: { width: '100%', justifyContent: 'flex-start' }, color: 'transparent' })))),
|
|
1983
|
-
React.createElement(Divider, { thickness: catIdx === searchResults.length - 1 ? 0 : 1, length: '90%', margin: '8px auto' }))))));
|
|
1977
|
+
return (React.createElement(Popup, { ref: popupRef, isOpen: popupOpen, top: popupPosition.top, left: popupPosition.left, maxWidth: '420px', header: React.createElement(HorizontalScroll, null, categories.map(({ category, label, count }) => !!count && (React.createElement(SelectionButton, { key: `category-select-${category}`, label: label, badgeLabel: count, isSelected: selectedCategory === category, onClick: () => setSelectedCategory(category) })))) }, searchResults.map(({ category, label, entities }, catIdx) => !!entities.length && (React.createElement(Fragment, { key: `category-list-${category}` },
|
|
1978
|
+
React.createElement(VerticalScroll, { style: { maxHeight: selectedCategory !== 'all' ? '240px' : '140px', padding: '12px 0' } },
|
|
1979
|
+
React.createElement(Text, { size: 12, family: 'secondary', color: theme.text.darker_grey, style: { marginLeft: '16px' } }, label),
|
|
1980
|
+
entities.map((item, entIdx) => (React.createElement(SelectionButton, { key: `entity-${catIdx}-${entIdx}`, icon: getEntityIcon(category), label: getEntityLabel(item, category, { extended: true }), onClick: () => {
|
|
1981
|
+
const id = getEntityId(item);
|
|
1982
|
+
// @ts-expect-error - expects an event, but we don't need it, so null is fine, also expects full node, we only need the given values
|
|
1983
|
+
onClickNode(null, { data: { type: category, id } });
|
|
1984
|
+
onClose();
|
|
1985
|
+
}, style: { width: '100%', justifyContent: 'flex-start' }, color: 'transparent' })))),
|
|
1986
|
+
React.createElement(Divider, { thickness: catIdx === searchResults.length - 1 ? 0 : 1, length: '90%', margin: '8px auto' }))))));
|
|
1984
1987
|
};
|
|
1985
1988
|
|
|
1986
1989
|
const Search = () => {
|
|
@@ -2007,12 +2010,6 @@ const FormWrapper = styled.div `
|
|
|
2007
2010
|
const ToggleWrapper = styled.div `
|
|
2008
2011
|
padding: 12px 6px 6px 6px;
|
|
2009
2012
|
`;
|
|
2010
|
-
const Actions = styled.div `
|
|
2011
|
-
display: flex;
|
|
2012
|
-
align-items: center;
|
|
2013
|
-
padding: 12px;
|
|
2014
|
-
border-top: ${({ theme }) => `1px solid ${theme.colors.border}`};
|
|
2015
|
-
`;
|
|
2016
2013
|
const ActionButton$1 = styled(Button) `
|
|
2017
2014
|
font-size: 14px;
|
|
2018
2015
|
${({ $color }) => `color: ${$color};`}
|
|
@@ -2037,45 +2034,51 @@ const Filters$1 = () => {
|
|
|
2037
2034
|
const { selectedStreamName } = useDataStreamStore();
|
|
2038
2035
|
const { getItemSS, setItemSS, removeItemSS } = useSessionStorage();
|
|
2039
2036
|
const { namespaces: namespaceFilters, kinds, monitors, languages, errors, onlyErrors, setAll, clearAll, getEmptyState } = useFilterStore();
|
|
2037
|
+
const { popupRef, popupOpen, setPopupOpen, popupPosition, handlePosition } = usePopup();
|
|
2040
2038
|
const sourcesByStream = useMemo(() => filterSourcesByStream(sources, selectedStreamName), [sources, selectedStreamName]);
|
|
2041
2039
|
// We need local state, because we want to keep the filters in the store only when the user clicks on apply
|
|
2042
2040
|
const [filters, setFilters] = useState({ namespaces: namespaceFilters, kinds, monitors, languages, errors, onlyErrors });
|
|
2043
2041
|
const [filterCount, setFilterCount] = useState(getFilterCount(filters));
|
|
2044
|
-
const [focused, setFocused] = useState(false);
|
|
2045
|
-
const toggleFocused = () => setFocused((prev) => !prev);
|
|
2046
2042
|
useEffect(() => {
|
|
2047
2043
|
const storedFilters = getItemSS(STORAGE_KEYS.OVERVIEW_FILTERS, getEmptyState());
|
|
2048
2044
|
setAll(storedFilters);
|
|
2049
2045
|
}, []);
|
|
2050
2046
|
useEffect(() => {
|
|
2051
|
-
if (!
|
|
2047
|
+
if (!popupOpen) {
|
|
2052
2048
|
const payload = { namespaces: namespaceFilters, kinds, monitors, languages, errors, onlyErrors };
|
|
2053
2049
|
setFilters(payload);
|
|
2054
2050
|
setFilterCount(getFilterCount(payload));
|
|
2055
2051
|
}
|
|
2056
|
-
}, [
|
|
2052
|
+
}, [popupOpen, namespaceFilters, kinds, monitors, errors, onlyErrors]);
|
|
2057
2053
|
const onApply = () => {
|
|
2058
2054
|
setItemSS(STORAGE_KEYS.OVERVIEW_FILTERS, filters);
|
|
2059
2055
|
setAll(filters);
|
|
2060
2056
|
setFilterCount(getFilterCount(filters));
|
|
2061
|
-
|
|
2057
|
+
setPopupOpen(false);
|
|
2062
2058
|
};
|
|
2063
2059
|
const onReset = () => {
|
|
2064
2060
|
removeItemSS(STORAGE_KEYS.OVERVIEW_FILTERS);
|
|
2065
2061
|
clearAll();
|
|
2066
2062
|
setFilters(getEmptyState());
|
|
2067
2063
|
setFilterCount(0);
|
|
2068
|
-
|
|
2064
|
+
setPopupOpen(false);
|
|
2069
2065
|
};
|
|
2070
2066
|
const onCancel = () => {
|
|
2071
|
-
|
|
2067
|
+
setPopupOpen(false);
|
|
2072
2068
|
};
|
|
2073
2069
|
const ref = useRef(null);
|
|
2074
2070
|
useOnClickOutside(ref, onCancel);
|
|
2075
|
-
useKeyDown({ key: 'Escape', active:
|
|
2071
|
+
useKeyDown({ key: 'Escape', active: popupOpen }, onCancel);
|
|
2076
2072
|
return (React.createElement(RelativeContainer$2, { ref: ref },
|
|
2077
|
-
React.createElement(SelectionButton, { label: 'Filters', icon: FilterIcon, badgeLabel: filterCount, badgeFilled: !!filterCount, withBorder: true, color: 'transparent', onClick:
|
|
2078
|
-
|
|
2073
|
+
React.createElement(SelectionButton, { label: 'Filters', icon: FilterIcon, badgeLabel: filterCount, badgeFilled: !!filterCount, withBorder: true, color: 'transparent', onClick: () => {
|
|
2074
|
+
handlePosition(0, 50);
|
|
2075
|
+
setPopupOpen(true);
|
|
2076
|
+
} }),
|
|
2077
|
+
React.createElement(Popup, { ref: popupRef, isOpen: popupOpen, top: popupPosition.top, left: popupPosition.left, width: '420px', footer: React.createElement(FlexRow, null,
|
|
2078
|
+
React.createElement(ActionButton$1, { variant: 'primary', onClick: onApply }, "Apply"),
|
|
2079
|
+
React.createElement(ActionButton$1, { variant: 'secondary', onClick: onCancel }, "Cancel"),
|
|
2080
|
+
React.createElement(PushRight, null,
|
|
2081
|
+
React.createElement(ActionButton$1, { variant: 'tertiary', onClick: onReset, "$color": theme.text.error }, "Reset"))) },
|
|
2079
2082
|
React.createElement(FormWrapper, null,
|
|
2080
2083
|
React.createElement(NamespaceDropdown, { namespaces: namespaces, value: filters['namespaces'], onSelect: (val) => setFilters((prev) => ({ ...prev, namespaces: [...(prev.namespaces || []), val] })), onDeselect: (val) => setFilters((prev) => ({ ...prev, namespaces: (prev.namespaces || []).filter((opt) => opt.id !== val.id) })), showSearch: true, required: true, isMulti: true }),
|
|
2081
2084
|
React.createElement(KindDropdown, { sources: sourcesByStream, value: filters['kinds'], onSelect: (val) => setFilters((prev) => ({ ...prev, kinds: [...(prev.kinds || []), val] })), onDeselect: (val) => setFilters((prev) => ({ ...prev, kinds: (prev.kinds || []).filter((opt) => opt.id !== val.id) })), showSearch: true, required: true, isMulti: true }),
|
|
@@ -2083,12 +2086,7 @@ const Filters$1 = () => {
|
|
|
2083
2086
|
React.createElement(MonitorDropdown, { value: filters['monitors'], onSelect: (val) => setFilters((prev) => ({ ...prev, monitors: [...(prev.monitors || []), val] })), onDeselect: (val) => setFilters((prev) => ({ ...prev, monitors: (prev.monitors || []).filter((opt) => opt.id !== val.id) })), showSearch: true, required: true, isMulti: true }),
|
|
2084
2087
|
React.createElement(ToggleWrapper, null,
|
|
2085
2088
|
React.createElement(Toggle, { title: 'Show only sources with errors', initialValue: filters['onlyErrors'], onChange: (bool) => setFilters((prev) => ({ ...prev, errors: [], onlyErrors: bool })) })),
|
|
2086
|
-
React.createElement(ErrorDropdown, { sources: sourcesByStream, value: filters['errors'], onSelect: (val) => setFilters((prev) => ({ ...prev, errors: [...(prev.errors || []), val] })), onDeselect: (val) => setFilters((prev) => ({ ...prev, errors: (prev.errors || []).filter((opt) => opt.id !== val.id) })), disabled: !filters['onlyErrors'], showSearch: true, required: true, isMulti: true }))
|
|
2087
|
-
React.createElement(Actions, null,
|
|
2088
|
-
React.createElement(ActionButton$1, { variant: 'primary', onClick: onApply }, "Apply"),
|
|
2089
|
-
React.createElement(ActionButton$1, { variant: 'secondary', onClick: onCancel }, "Cancel"),
|
|
2090
|
-
React.createElement(PushRight, null,
|
|
2091
|
-
React.createElement(ActionButton$1, { variant: 'tertiary', onClick: onReset, "$color": theme.text.error }, "Reset"))))));
|
|
2089
|
+
React.createElement(ErrorDropdown, { sources: sourcesByStream, value: filters['errors'], onSelect: (val) => setFilters((prev) => ({ ...prev, errors: [...(prev.errors || []), val] })), onDeselect: (val) => setFilters((prev) => ({ ...prev, errors: (prev.errors || []).filter((opt) => opt.id !== val.id) })), disabled: !filters['onlyErrors'], showSearch: true, required: true, isMulti: true })))));
|
|
2092
2090
|
};
|
|
2093
2091
|
|
|
2094
2092
|
const Container$e = styled.div `
|
|
@@ -2162,22 +2160,9 @@ const Container$d = styled(FlexRow) `
|
|
|
2162
2160
|
const Title = styled(Text) `
|
|
2163
2161
|
text-wrap: nowrap;
|
|
2164
2162
|
`;
|
|
2165
|
-
const
|
|
2166
|
-
position: absolute;
|
|
2167
|
-
top: calc(100% + 8px);
|
|
2168
|
-
left: 0;
|
|
2169
|
-
z-index: 1;
|
|
2170
|
-
background-color: ${({ theme }) => theme.colors.dropdown_bg};
|
|
2171
|
-
border: ${({ theme }) => `1px solid ${theme.colors.border}`};
|
|
2172
|
-
border-radius: 24px;
|
|
2173
|
-
width: 420px;
|
|
2174
|
-
`;
|
|
2175
|
-
const SelectionMenuHeader = styled.div `
|
|
2176
|
-
border-bottom: ${({ theme }) => `1px solid ${theme.colors.border}`};
|
|
2177
|
-
padding: 12px;
|
|
2178
|
-
`;
|
|
2179
|
-
const SelectionContent = styled(VerticalScroll) `
|
|
2163
|
+
const PopupBody$1 = styled(VerticalScroll) `
|
|
2180
2164
|
max-height: 240px;
|
|
2165
|
+
padding: 0px !important;
|
|
2181
2166
|
`;
|
|
2182
2167
|
const SelectionRow = styled(FlexRow) `
|
|
2183
2168
|
width: 100%;
|
|
@@ -2188,9 +2173,7 @@ const Stretch = styled.div `
|
|
|
2188
2173
|
const DataStreamSelect = ({ onClickNewDataStream, updateDataStream, deleteDataStream }) => {
|
|
2189
2174
|
const theme = Theme.useTheme();
|
|
2190
2175
|
const { dataStreams, selectedStreamName, setSelectedStreamName } = useDataStreamStore();
|
|
2191
|
-
const
|
|
2192
|
-
const containerRef = useRef(null);
|
|
2193
|
-
useOnClickOutside(containerRef, () => setPopupOpen(false));
|
|
2176
|
+
const { popupRef, popupOpen, setPopupOpen, popupPosition, handlePosition } = usePopup();
|
|
2194
2177
|
const [editOpenForDataStreamName, setEditOpenForDataStreamName] = useState('');
|
|
2195
2178
|
const [deleteOpenForDataStreamName, setDeleteOpenForDataStreamName] = useState('');
|
|
2196
2179
|
const [searchText, setSearchText] = useState('');
|
|
@@ -2209,7 +2192,10 @@ const DataStreamSelect = ({ onClickNewDataStream, updateDataStream, deleteDataSt
|
|
|
2209
2192
|
return (React.createElement(React.Fragment, null,
|
|
2210
2193
|
React.createElement(RelativeContainer$1, null,
|
|
2211
2194
|
React.createElement(Container$d, { "$gap": 0 },
|
|
2212
|
-
React.createElement(Button, { variant: 'tertiary', onClick: () =>
|
|
2195
|
+
React.createElement(Button, { variant: 'tertiary', onClick: () => {
|
|
2196
|
+
handlePosition(0, 50);
|
|
2197
|
+
setPopupOpen((prev) => !prev);
|
|
2198
|
+
} },
|
|
2213
2199
|
React.createElement(DataStreamsIcon, { fill: theme.text.info }),
|
|
2214
2200
|
React.createElement(Title, null,
|
|
2215
2201
|
"Data Stream: ",
|
|
@@ -2221,10 +2207,8 @@ const DataStreamSelect = ({ onClickNewDataStream, updateDataStream, deleteDataSt
|
|
|
2221
2207
|
setSelectedStreamName('');
|
|
2222
2208
|
onClickNewDataStream();
|
|
2223
2209
|
}, label: BUTTON_TEXTS.NEW })),
|
|
2224
|
-
popupOpen
|
|
2225
|
-
React.createElement(
|
|
2226
|
-
React.createElement(Input, { placeholder: 'Search...', icon: SearchIcon, value: searchText, onChange: (e) => setSearchText(e.target.value) })),
|
|
2227
|
-
React.createElement(SelectionContent, null, rows)))),
|
|
2210
|
+
React.createElement(Popup, { ref: popupRef, isOpen: popupOpen, top: popupPosition.top, left: popupPosition.left, header: React.createElement(Input, { placeholder: 'Search...', icon: SearchIcon, value: searchText, onChange: (e) => setSearchText(e.target.value) }) },
|
|
2211
|
+
React.createElement(PopupBody$1, null, rows))),
|
|
2228
2212
|
React.createElement(DeleteWarning, { isOpen: deleteOpenForDataStreamName !== '', name: deleteOpenForDataStreamName, onApprove: () => {
|
|
2229
2213
|
deleteDataStream(deleteOpenForDataStreamName);
|
|
2230
2214
|
setDeleteOpenForDataStreamName('');
|
|
@@ -3612,32 +3596,13 @@ const RelativeContainer = styled.div `
|
|
|
3612
3596
|
position: relative;
|
|
3613
3597
|
width: fit-content;
|
|
3614
3598
|
`;
|
|
3615
|
-
const
|
|
3616
|
-
position: absolute;
|
|
3617
|
-
top: 40px;
|
|
3618
|
-
left: ${({ $left }) => $left}px;
|
|
3619
|
-
z-index: 1;
|
|
3620
|
-
width: 370px;
|
|
3621
|
-
height: 400px;
|
|
3622
|
-
background-color: ${({ theme }) => theme.colors.dropdown_bg};
|
|
3623
|
-
border: 1px solid ${({ theme }) => theme.colors.border};
|
|
3624
|
-
border-radius: 24px;
|
|
3625
|
-
box-shadow: 0px 10px 15px -3px ${({ theme }) => theme.colors.primary}, 0px 4px 6px -2px ${({ theme }) => theme.colors.primary};
|
|
3626
|
-
`;
|
|
3627
|
-
const PopupHeader = styled.div `
|
|
3628
|
-
display: flex;
|
|
3629
|
-
align-items: center;
|
|
3599
|
+
const PopupHeader = styled(FlexRow) `
|
|
3630
3600
|
gap: 12px;
|
|
3631
|
-
padding: 12px
|
|
3632
|
-
border-bottom: 1px solid ${({ theme }) => theme.colors.border};
|
|
3601
|
+
padding: 0 12px;
|
|
3633
3602
|
`;
|
|
3634
|
-
const PopupBody = styled
|
|
3635
|
-
display: flex;
|
|
3636
|
-
flex-direction: column;
|
|
3603
|
+
const PopupBody = styled(FlexColumn) `
|
|
3637
3604
|
gap: 12px;
|
|
3638
|
-
|
|
3639
|
-
height: calc(100% - 74px);
|
|
3640
|
-
border-radius: 24px;
|
|
3605
|
+
max-height: 400px;
|
|
3641
3606
|
overflow-y: auto;
|
|
3642
3607
|
`;
|
|
3643
3608
|
const PopupShadow = styled.div `
|
|
@@ -3663,36 +3628,29 @@ const NotificationManager = () => {
|
|
|
3663
3628
|
const notifications = n.filter(({ hideFromHistory }) => !hideFromHistory);
|
|
3664
3629
|
const unseen = notifications.filter(({ seen }) => !seen);
|
|
3665
3630
|
const unseenCount = unseen.length;
|
|
3666
|
-
const
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
setIsOpen(false);
|
|
3672
|
-
if (!!unseenCount)
|
|
3631
|
+
const { popupRef, popupOpen, setPopupOpen, popupPosition, handlePosition } = usePopup({
|
|
3632
|
+
defaultClientHeight: 420,
|
|
3633
|
+
defaultClientwidth: 400,
|
|
3634
|
+
onClickOutside: () => {
|
|
3635
|
+
if (unseenCount)
|
|
3673
3636
|
unseen.forEach(({ id }) => markAsSeen(id));
|
|
3674
|
-
}
|
|
3637
|
+
},
|
|
3675
3638
|
});
|
|
3676
3639
|
const toggleOpen = (e) => {
|
|
3677
|
-
const { clientX } = e;
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
if (clientX >= innerWidth / 2)
|
|
3681
|
-
left = -350;
|
|
3682
|
-
setPopupPosition({ left });
|
|
3683
|
-
setIsOpen((prev) => !prev);
|
|
3640
|
+
const { clientX, clientY } = e;
|
|
3641
|
+
handlePosition(clientX, clientY);
|
|
3642
|
+
setPopupOpen((prev) => !prev);
|
|
3684
3643
|
};
|
|
3685
|
-
return (React.createElement(RelativeContainer,
|
|
3686
|
-
React.createElement(IconButton, {
|
|
3644
|
+
return (React.createElement(RelativeContainer, null,
|
|
3645
|
+
React.createElement(IconButton, { onClick: toggleOpen, tooltip: 'Notifications', withPing: !!unseenCount, pingColor: theme.colors.orange_og },
|
|
3687
3646
|
React.createElement(NotificationIcon, { size: 18 })),
|
|
3688
|
-
|
|
3689
|
-
React.createElement(PopupHeader, null,
|
|
3647
|
+
React.createElement(Popup, { ref: popupRef, isOpen: popupOpen, asPortal: true, left: popupPosition.left, maxWidth: '400px', header: React.createElement(PopupHeader, null,
|
|
3690
3648
|
React.createElement(Text, { size: 20 }, "Notifications"),
|
|
3691
3649
|
!!unseenCount && (React.createElement(NewCount, { size: 12, family: 'secondary' },
|
|
3692
3650
|
unseenCount,
|
|
3693
|
-
" new"))),
|
|
3694
|
-
React.createElement(PopupBody, null, !notifications.length ? (React.createElement(NoDataFound, { title: 'No notifications', subTitle: '' })) : (notifications.map((notif) => React.createElement(NotificationListItem, { key: `notification-${notif.id}`, ...notif, onClick: () =>
|
|
3695
|
-
React.createElement(PopupShadow, null))))
|
|
3651
|
+
" new"))) },
|
|
3652
|
+
React.createElement(PopupBody, null, !notifications.length ? (React.createElement(NoDataFound, { title: 'No notifications', subTitle: '' })) : (notifications.map((notif) => React.createElement(NotificationListItem, { key: `notification-${notif.id}`, ...notif, onClick: () => setPopupOpen(false) })))),
|
|
3653
|
+
React.createElement(PopupShadow, null))));
|
|
3696
3654
|
};
|
|
3697
3655
|
const NotifCard = styled.div `
|
|
3698
3656
|
display: flex;
|
|
@@ -3779,117 +3737,131 @@ const buildEdges = ({ theme, nodes, serviceMap }) => {
|
|
|
3779
3737
|
return edges;
|
|
3780
3738
|
};
|
|
3781
3739
|
|
|
3782
|
-
const
|
|
3783
|
-
const
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3740
|
+
const generateDAGPositions = (serviceMap, containerWidth, containerHeight) => {
|
|
3741
|
+
const positions = new Map();
|
|
3742
|
+
const nodeSpacing = 150; // Vertical spacing between nodes
|
|
3743
|
+
const layerSpacing = 200; // Horizontal spacing between layers
|
|
3744
|
+
const padding = 100; // Padding from container edges
|
|
3745
|
+
// Build adjacency list and calculate in-degrees for topological sorting
|
|
3746
|
+
const adjacencyList = new Map();
|
|
3747
|
+
const inDegrees = new Map();
|
|
3748
|
+
const allServices = new Set();
|
|
3749
|
+
// Initialize all services
|
|
3750
|
+
serviceMap.forEach((entry) => {
|
|
3751
|
+
allServices.add(entry.serviceName);
|
|
3752
|
+
entry.services.forEach((target) => {
|
|
3753
|
+
allServices.add(target.serviceName);
|
|
3754
|
+
});
|
|
3755
|
+
});
|
|
3756
|
+
// Initialize adjacency list and in-degrees
|
|
3757
|
+
allServices.forEach((service) => {
|
|
3758
|
+
adjacencyList.set(service, []);
|
|
3759
|
+
inDegrees.set(service, 0);
|
|
3760
|
+
});
|
|
3761
|
+
// Build the graph
|
|
3762
|
+
serviceMap.forEach((entry) => {
|
|
3763
|
+
entry.services.forEach((target) => {
|
|
3764
|
+
adjacencyList.get(entry.serviceName)?.push(target.serviceName);
|
|
3765
|
+
const currentInDegree = inDegrees.get(target.serviceName) || 0;
|
|
3766
|
+
inDegrees.set(target.serviceName, currentInDegree + 1);
|
|
3767
|
+
});
|
|
3768
|
+
});
|
|
3769
|
+
// Topological sort to determine layers
|
|
3770
|
+
const layers = [];
|
|
3771
|
+
const queue = [];
|
|
3772
|
+
// Add all nodes with in-degree 0 to the queue
|
|
3773
|
+
allServices.forEach((service) => {
|
|
3774
|
+
if ((inDegrees.get(service) || 0) === 0) {
|
|
3775
|
+
queue.push(service);
|
|
3776
|
+
}
|
|
3777
|
+
});
|
|
3778
|
+
// Process nodes in topological order
|
|
3779
|
+
while (queue.length > 0) {
|
|
3780
|
+
const currentLayer = [];
|
|
3781
|
+
const layerSize = queue.length;
|
|
3782
|
+
for (let i = 0; i < layerSize; i++) {
|
|
3783
|
+
const current = queue.shift();
|
|
3784
|
+
currentLayer.push(current);
|
|
3785
|
+
// Process neighbors
|
|
3786
|
+
adjacencyList.get(current)?.forEach((neighbor) => {
|
|
3787
|
+
const neighborInDegree = inDegrees.get(neighbor) || 0;
|
|
3788
|
+
inDegrees.set(neighbor, neighborInDegree - 1);
|
|
3789
|
+
if (neighborInDegree - 1 === 0) {
|
|
3790
|
+
queue.push(neighbor);
|
|
3819
3791
|
}
|
|
3820
|
-
}
|
|
3792
|
+
});
|
|
3821
3793
|
}
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
// Build a set of all possible grid positions within the container
|
|
3825
|
-
const maxGridX = Math.floor((containerWidth / 2 - padding) / spacing);
|
|
3826
|
-
const maxGridY = Math.floor((containerHeight / 2 - padding) / spacing);
|
|
3827
|
-
const inBoundsPositions = new Set();
|
|
3828
|
-
for (let gx = -maxGridX; gx <= maxGridX; gx++) {
|
|
3829
|
-
for (let gy = -maxGridY; gy <= maxGridY; gy++) {
|
|
3830
|
-
const x = centerX + gx * spacing;
|
|
3831
|
-
const y = centerY + gy * spacing;
|
|
3832
|
-
if (x >= padding && x <= containerWidth - padding && y >= padding && y <= containerHeight - padding) {
|
|
3833
|
-
inBoundsPositions.add(`${gx},${gy}`);
|
|
3834
|
-
}
|
|
3794
|
+
if (currentLayer.length > 0) {
|
|
3795
|
+
layers.push(currentLayer);
|
|
3835
3796
|
}
|
|
3836
3797
|
}
|
|
3837
|
-
//
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
const y = centerY + gridY * spacing;
|
|
3846
|
-
if (inBoundsPositions.has(key) && !usedPositions.has(key)) {
|
|
3847
|
-
return { x, y };
|
|
3848
|
-
}
|
|
3849
|
-
n++;
|
|
3850
|
-
// If we've exhausted all in-bounds positions, allow out-of-bounds placement
|
|
3851
|
-
if (n > inBoundsPositions.size + 100) {
|
|
3852
|
-
// Find the next unused spiral position, even if out of bounds
|
|
3853
|
-
let m = n;
|
|
3854
|
-
while (true) {
|
|
3855
|
-
const { gridX: outGridX, gridY: outGridY } = getTrueSpiralGridOffset(m);
|
|
3856
|
-
const outKey = `${outGridX},${outGridY}`;
|
|
3857
|
-
const outX = centerX + outGridX * spacing;
|
|
3858
|
-
const outY = centerY + outGridY * spacing;
|
|
3859
|
-
if (!usedPositions.has(outKey)) {
|
|
3860
|
-
return { x: outX, y: outY };
|
|
3861
|
-
}
|
|
3862
|
-
m++;
|
|
3798
|
+
// Handle any remaining nodes (cycles or isolated nodes)
|
|
3799
|
+
allServices.forEach((service) => {
|
|
3800
|
+
if (!layers.flat().includes(service)) {
|
|
3801
|
+
if (layers.length === 0) {
|
|
3802
|
+
layers.push([service]);
|
|
3803
|
+
}
|
|
3804
|
+
else {
|
|
3805
|
+
layers[layers.length - 1].push(service);
|
|
3863
3806
|
}
|
|
3864
3807
|
}
|
|
3865
|
-
}
|
|
3808
|
+
});
|
|
3809
|
+
// Calculate positions for each layer
|
|
3810
|
+
layers.forEach((layer, layerIndex) => {
|
|
3811
|
+
const layerX = padding + layerIndex * layerSpacing;
|
|
3812
|
+
const layerHeight = (layer.length - 1) * nodeSpacing;
|
|
3813
|
+
const layerStartY = (containerHeight - layerHeight) / 2;
|
|
3814
|
+
layer.forEach((service, serviceIndex) => {
|
|
3815
|
+
const x = layerX;
|
|
3816
|
+
const y = layerStartY + serviceIndex * nodeSpacing;
|
|
3817
|
+
positions.set(service, { x, y });
|
|
3818
|
+
});
|
|
3819
|
+
});
|
|
3820
|
+
return positions;
|
|
3866
3821
|
};
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
name
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3822
|
+
|
|
3823
|
+
const mapToNodeData = (serviceMapEntry, source, isUserSource) => {
|
|
3824
|
+
const serviceName = serviceMapEntry?.serviceName || source?.otelServiceName || source?.name;
|
|
3825
|
+
const icons = isUserSource ? [UserIcon] : getContainersIcons(source?.containers || []);
|
|
3826
|
+
const { priorotizedStatus } = getConditionsBooleans(source?.conditions || []);
|
|
3827
|
+
return {
|
|
3828
|
+
id: serviceName,
|
|
3829
|
+
title: serviceName,
|
|
3830
|
+
icons: icons.length ? icons : [ImageErrorIcon],
|
|
3831
|
+
status: priorotizedStatus,
|
|
3832
|
+
serviceMapEntry,
|
|
3833
|
+
};
|
|
3877
3834
|
};
|
|
3878
3835
|
const buildMapNodes = ({ sources, serviceMap, containerHeight, containerWidth }) => {
|
|
3879
3836
|
const nodes = [];
|
|
3880
|
-
const
|
|
3881
|
-
if (sources.length) {
|
|
3882
|
-
|
|
3883
|
-
|
|
3837
|
+
const dagPositions = generateDAGPositions(serviceMap, containerWidth, containerHeight);
|
|
3838
|
+
if (serviceMap.length && sources.length) {
|
|
3839
|
+
// first we map the service map nodes (to include services traced, but not instrumented by Odigos)
|
|
3840
|
+
serviceMap.forEach((serviceMapEntry) => {
|
|
3841
|
+
const source = sources.find((src) => serviceMapEntry.serviceName === src.otelServiceName || serviceMapEntry.serviceName === src.name);
|
|
3842
|
+
const isUserSource = source?.otelServiceName === 'user' && !source?.namespace && !source?.name && !source?.kind;
|
|
3843
|
+
nodes.push({
|
|
3844
|
+
id: `${EntityTypes.Source}-${serviceMapEntry.serviceName}-${NodeTypes.MapItem}`,
|
|
3845
|
+
type: NodeTypes.MapItem,
|
|
3846
|
+
position: dagPositions.get(serviceMapEntry.serviceName),
|
|
3847
|
+
data: mapToNodeData(serviceMapEntry, source, isUserSource),
|
|
3848
|
+
});
|
|
3849
|
+
});
|
|
3850
|
+
// then we look for any sources that are not in the service map (to include services not traced)
|
|
3851
|
+
let currentX = 10;
|
|
3852
|
+
sources.forEach((source) => {
|
|
3853
|
+
const serviceName = source.otelServiceName || source.name;
|
|
3884
3854
|
const isUserSource = source.otelServiceName === 'user' && !source.namespace && !source.name && !source.kind;
|
|
3885
|
-
const
|
|
3886
|
-
|
|
3855
|
+
const foundNode = nodes.find((n) => n.id === `${EntityTypes.Source}-${serviceName}-${NodeTypes.MapItem}`);
|
|
3856
|
+
if (foundNode)
|
|
3857
|
+
return;
|
|
3887
3858
|
nodes.push({
|
|
3888
|
-
id: `${EntityTypes.Source}-${
|
|
3859
|
+
id: `${EntityTypes.Source}-${serviceName}-${NodeTypes.MapItem}`,
|
|
3889
3860
|
type: NodeTypes.MapItem,
|
|
3890
|
-
position,
|
|
3891
|
-
data: mapToNodeData(
|
|
3861
|
+
position: { x: currentX, y: 10 },
|
|
3862
|
+
data: mapToNodeData(undefined, source, isUserSource),
|
|
3892
3863
|
});
|
|
3864
|
+
currentX += 120;
|
|
3893
3865
|
});
|
|
3894
3866
|
}
|
|
3895
3867
|
// else if (sourcesLoading) {
|
|
@@ -3904,7 +3876,7 @@ const buildMapNodes = ({ sources, serviceMap, containerHeight, containerWidth })
|
|
|
3904
3876
|
y: containerHeight / 2 - 50,
|
|
3905
3877
|
},
|
|
3906
3878
|
data: {
|
|
3907
|
-
subTitle: 'Are your services instrumented?',
|
|
3879
|
+
subTitle: 'Are your services instrumented & producing traces?',
|
|
3908
3880
|
},
|
|
3909
3881
|
});
|
|
3910
3882
|
}
|
|
@@ -3916,18 +3888,42 @@ const Container$5 = styled.div `
|
|
|
3916
3888
|
height: ${({ $heightToRemove }) => `calc(100vh - ${$heightToRemove})`};
|
|
3917
3889
|
position: relative;
|
|
3918
3890
|
`;
|
|
3891
|
+
const userSource = {
|
|
3892
|
+
namespace: '',
|
|
3893
|
+
name: '',
|
|
3894
|
+
kind: '',
|
|
3895
|
+
otelServiceName: 'user',
|
|
3896
|
+
selected: true,
|
|
3897
|
+
numberOfInstances: 0,
|
|
3898
|
+
dataStreamNames: [],
|
|
3899
|
+
containers: [],
|
|
3900
|
+
conditions: [],
|
|
3901
|
+
};
|
|
3919
3902
|
const ServiceMap = ({ heightToRemove, serviceMap }) => {
|
|
3920
3903
|
const theme = Theme.useTheme();
|
|
3921
3904
|
const { sources, sourcesLoading } = useEntityStore();
|
|
3922
3905
|
const { containerRef, containerHeight, containerWidth } = useContainerSize();
|
|
3923
3906
|
const [nodes, setNodes, onNodesChange] = useNodesState([]);
|
|
3924
3907
|
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
|
3908
|
+
const handleNodesChanged = (currNodes) => {
|
|
3909
|
+
setNodes((prevNodes) => applyNodeChanges(currNodes.map((cn) => ({
|
|
3910
|
+
id: cn.id,
|
|
3911
|
+
item: cn,
|
|
3912
|
+
type: prevNodes.find((pn) => pn.id === cn.id) ? 'replace' : 'add',
|
|
3913
|
+
})), prevNodes));
|
|
3914
|
+
};
|
|
3915
|
+
useEffect(() => {
|
|
3916
|
+
const newNodes = buildMapNodes({ serviceMap, sources: [userSource].concat(sources), containerHeight, containerWidth });
|
|
3917
|
+
if (nodes.length) {
|
|
3918
|
+
handleNodesChanged(newNodes);
|
|
3919
|
+
}
|
|
3920
|
+
else {
|
|
3921
|
+
setNodes(newNodes);
|
|
3922
|
+
}
|
|
3923
|
+
}, [serviceMap, sources, sourcesLoading, containerHeight, containerWidth]);
|
|
3925
3924
|
useEffect(() => {
|
|
3926
3925
|
setEdges(buildEdges({ theme, nodes, serviceMap }));
|
|
3927
3926
|
}, [theme, nodes, serviceMap]);
|
|
3928
|
-
useEffect(() => {
|
|
3929
|
-
setNodes(buildMapNodes({ sources, serviceMap, containerHeight, containerWidth }));
|
|
3930
|
-
}, [sources, sourcesLoading, serviceMap, containerHeight, containerWidth]);
|
|
3931
3927
|
return (React.createElement(Container$5, { ref: containerRef, "$heightToRemove": heightToRemove },
|
|
3932
3928
|
React.createElement(Flow, { nodes: nodes, edges: edges, onNodesChange: onNodesChange, onEdgesChange: onEdgesChange, zoomOnScroll: true })));
|
|
3933
3929
|
};
|
|
@@ -4164,95 +4160,37 @@ const Describe$1 = ({ source, fetchDescribeSource }) => {
|
|
|
4164
4160
|
}
|
|
4165
4161
|
return (React.createElement(FlexColumn, { "$gap": 12 }, !describe.pods?.length ? (React.createElement(CenterThis, null,
|
|
4166
4162
|
React.createElement(NoDataFound, { subTitle: 'Check if you have any running pods and try again' }))) : (describe.pods.map(({ podName, nodeName, phase, agentInjected, runningLatestWorkloadRevision, containers }) => {
|
|
4167
|
-
const podHasErrors = phase.status !== StatusType.Success ||
|
|
4168
|
-
containers.findIndex(({ instrumentationInstances }) => instrumentationInstances.findIndex(({ healthy }) => healthy.status !== StatusType.Success) !== -1) !== -1;
|
|
4163
|
+
const podHasErrors = phase.status !== StatusType.Success || hasUnhealthyInstances(containers);
|
|
4169
4164
|
const podStatus = podHasErrors ? StatusType.Error : StatusType.Success;
|
|
4170
|
-
const
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
})
|
|
4187
|
-
});
|
|
4188
|
-
data.push(divider);
|
|
4189
|
-
data.push({
|
|
4190
|
-
type: DataCardFieldTypes.DescribeRow,
|
|
4191
|
-
value: JSON.stringify({
|
|
4192
|
-
title: phase.name,
|
|
4193
|
-
tooltip: phase.explain,
|
|
4194
|
-
value: {
|
|
4195
|
-
text: phase.value,
|
|
4196
|
-
status: phase.status,
|
|
4197
|
-
},
|
|
4198
|
-
}),
|
|
4199
|
-
});
|
|
4200
|
-
data.push(divider);
|
|
4201
|
-
data.push({
|
|
4202
|
-
type: DataCardFieldTypes.DescribeRow,
|
|
4203
|
-
value: JSON.stringify({
|
|
4204
|
-
title: agentInjected.name,
|
|
4205
|
-
tooltip: agentInjected.explain,
|
|
4206
|
-
value: {
|
|
4207
|
-
text: agentInjected.value,
|
|
4208
|
-
status: agentInjected.status,
|
|
4209
|
-
},
|
|
4210
|
-
}),
|
|
4211
|
-
});
|
|
4212
|
-
data.push(divider);
|
|
4165
|
+
const cardChildren = [];
|
|
4166
|
+
cardChildren.push(React.createElement(CopyText, { value: `kubectl get pod ${podName.value} -n ${describe?.namespace?.value || source.namespace}`.toLowerCase() }));
|
|
4167
|
+
cardChildren.push(React.createElement(Divider, { length: '100%', margin: '0' }));
|
|
4168
|
+
cardChildren.push(React.createElement(DescribeRow, { title: nodeName.name, tooltip: nodeName.explain || '', value: {
|
|
4169
|
+
status: nodeName.status || undefined,
|
|
4170
|
+
text: nodeName.value,
|
|
4171
|
+
} }));
|
|
4172
|
+
cardChildren.push(React.createElement(Divider, { length: '100%', margin: '0' }));
|
|
4173
|
+
cardChildren.push(React.createElement(DescribeRow, { title: phase.name, tooltip: phase.explain || '', value: {
|
|
4174
|
+
status: phase.status || undefined,
|
|
4175
|
+
text: phase.value,
|
|
4176
|
+
} }));
|
|
4177
|
+
cardChildren.push(React.createElement(Divider, { length: '100%', margin: '0' }));
|
|
4178
|
+
cardChildren.push(React.createElement(DescribeRow, { title: agentInjected.name, tooltip: agentInjected.explain || '', value: {
|
|
4179
|
+
status: agentInjected.status || undefined,
|
|
4180
|
+
text: agentInjected.value,
|
|
4181
|
+
} }));
|
|
4182
|
+
cardChildren.push(React.createElement(Divider, { length: '100%', margin: '0' }));
|
|
4213
4183
|
if (runningLatestWorkloadRevision?.name) {
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
value: {
|
|
4220
|
-
text: runningLatestWorkloadRevision?.value || '',
|
|
4221
|
-
status: runningLatestWorkloadRevision?.status || '',
|
|
4222
|
-
},
|
|
4223
|
-
}),
|
|
4224
|
-
});
|
|
4225
|
-
data.push(divider);
|
|
4184
|
+
cardChildren.push(React.createElement(DescribeRow, { title: runningLatestWorkloadRevision.name, tooltip: runningLatestWorkloadRevision.explain || undefined, value: {
|
|
4185
|
+
status: runningLatestWorkloadRevision.status || undefined,
|
|
4186
|
+
text: runningLatestWorkloadRevision.value,
|
|
4187
|
+
} }));
|
|
4188
|
+
cardChildren.push(React.createElement(Divider, { length: '100%', margin: '0' }));
|
|
4226
4189
|
}
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
containerName: container.containerName.value,
|
|
4232
|
-
actualDevice: {
|
|
4233
|
-
title: container.actualDevices.name,
|
|
4234
|
-
subTitle: container.actualDevices.value,
|
|
4235
|
-
tooltip: container.actualDevices.explain,
|
|
4236
|
-
},
|
|
4237
|
-
started: {
|
|
4238
|
-
title: container.started?.name || '',
|
|
4239
|
-
subTitle: container.started?.value || '',
|
|
4240
|
-
tooltip: container.started?.explain || '',
|
|
4241
|
-
},
|
|
4242
|
-
ready: {
|
|
4243
|
-
title: container.ready?.name || '',
|
|
4244
|
-
subTitle: container.ready?.value || '',
|
|
4245
|
-
tooltip: container.ready?.explain || '',
|
|
4246
|
-
},
|
|
4247
|
-
processes: container.instrumentationInstances.map((instance) => ({
|
|
4248
|
-
health: instance.healthy.status,
|
|
4249
|
-
message: instance.message?.value || '',
|
|
4250
|
-
identifyingAttributes: instance.identifyingAttributes || [],
|
|
4251
|
-
})),
|
|
4252
|
-
}),
|
|
4253
|
-
};
|
|
4254
|
-
}));
|
|
4255
|
-
return React.createElement(DataCard, { key: `pod-${podName.value}`, title: `Pod: ${podName.value}`, withExtend: true, action: () => React.createElement(Status, { status: podStatus, title: podStatus, withIcon: true, withBorder: true }), data: data });
|
|
4190
|
+
containers.forEach((container) => {
|
|
4191
|
+
cardChildren.push(React.createElement(PodContainer, { ...container }));
|
|
4192
|
+
});
|
|
4193
|
+
return (React.createElement(DataCard, { key: `pod-${podName.value}`, title: `Pod: ${podName.value}`, withExtend: true, action: () => React.createElement(Status, { status: podStatus, title: podStatus, withIcon: true, withBorder: true }) }, Children.toArray(cardChildren)));
|
|
4256
4194
|
}))));
|
|
4257
4195
|
};
|
|
4258
4196
|
|
|
@@ -4319,18 +4257,13 @@ const SourceDrawer = ({ persistSources, updateSource, fetchDescribeSource, resta
|
|
|
4319
4257
|
return found;
|
|
4320
4258
|
}, [isOpen, drawerEntityId, sourcesByStream]);
|
|
4321
4259
|
const containersData = useMemo(() => {
|
|
4322
|
-
const mappedContainers = thisItem?.containers?.map((container) => ({
|
|
4323
|
-
type: DataCardFieldTypes.SourceContainer,
|
|
4324
|
-
value: JSON.stringify(container),
|
|
4325
|
-
callback: async (payload) => await updateSource(drawerEntityId, payload),
|
|
4326
|
-
})) || [];
|
|
4327
4260
|
const runtimeCondition = thisItem?.conditions?.find(({ type }) => type === 'RuntimeDetection');
|
|
4328
4261
|
return {
|
|
4329
4262
|
description: runtimeCondition?.message,
|
|
4330
4263
|
isLoading: runtimeCondition?.status === OtherStatus.Loading,
|
|
4331
|
-
|
|
4264
|
+
containers: thisItem?.containers || [],
|
|
4332
4265
|
};
|
|
4333
|
-
}, [thisItem
|
|
4266
|
+
}, [thisItem]);
|
|
4334
4267
|
const tabs = useMemo(() => {
|
|
4335
4268
|
const arr = [
|
|
4336
4269
|
{
|
|
@@ -4391,7 +4324,7 @@ const SourceDrawer = ({ persistSources, updateSource, fetchDescribeSource, resta
|
|
|
4391
4324
|
} }))) : (React.createElement(DataContainer$1, null,
|
|
4392
4325
|
React.createElement(ConditionDetails, { conditions: thisItem.conditions || [] }),
|
|
4393
4326
|
React.createElement(DataCard, { title: DISPLAY_TITLES.SOURCE_DETAILS, data: !!thisItem ? buildCard(thisItem) : [] }),
|
|
4394
|
-
React.createElement(DataCard, { title: DISPLAY_TITLES.DETECTED_CONTAINERS, titleBadge: containersData.isLoading ? OtherStatus.Loading : containersData.
|
|
4327
|
+
React.createElement(DataCard, { title: DISPLAY_TITLES.DETECTED_CONTAINERS, titleBadge: containersData.isLoading ? OtherStatus.Loading : containersData.containers.length, description: containersData.description || DISPLAY_TITLES.DETECTED_CONTAINERS_DESCRIPTION }, containersData.containers.map((container) => (React.createElement(SourceContainer, { key: `source-container-${container.containerName}`, ...container, callbackRuntimeOverride: async (payload) => await updateSource(drawerEntityId, payload) }))))))) : (React.createElement(Describe$1, { source: thisItem, fetchDescribeSource: fetchDescribeSource }))));
|
|
4395
4328
|
};
|
|
4396
4329
|
|
|
4397
4330
|
const ActionsRow = styled(FlexRow) `
|
|
@@ -4621,59 +4554,30 @@ const ExpiresAt = ({ expiresAt }) => {
|
|
|
4621
4554
|
const Relative = styled.div `
|
|
4622
4555
|
position: relative;
|
|
4623
4556
|
`;
|
|
4624
|
-
const TokenPopover = styled(FlexColumn) `
|
|
4625
|
-
position: absolute;
|
|
4626
|
-
bottom: 32px;
|
|
4627
|
-
right: 0;
|
|
4628
|
-
z-index: 1;
|
|
4629
|
-
gap: 8px;
|
|
4630
|
-
padding: 24px;
|
|
4631
|
-
background-color: ${({ theme }) => theme.colors.info};
|
|
4632
|
-
border: 1px solid ${({ theme }) => theme.colors.border};
|
|
4633
|
-
border-radius: 24px;
|
|
4634
|
-
`;
|
|
4635
|
-
const PopoverFormWrapper = styled(FlexRow) `
|
|
4636
|
-
width: 100%;
|
|
4637
|
-
gap: 12px;
|
|
4638
|
-
`;
|
|
4639
|
-
const PopoverFormButton = styled(Button) `
|
|
4640
|
-
width: 36px;
|
|
4641
|
-
padding: 0;
|
|
4642
|
-
`;
|
|
4643
4557
|
const TokenActions = ({ token, saveToken }) => {
|
|
4644
4558
|
const theme = Theme.useTheme();
|
|
4645
4559
|
const { isCopied, clickCopy } = useCopy();
|
|
4560
|
+
const { formData, handleFormChange, resetFormData } = useGenericForm({ token });
|
|
4646
4561
|
const [isEdit, setIsEdit] = useState(false);
|
|
4647
|
-
const [inputValue, setInputValue] = useState(token);
|
|
4648
|
-
const popupRef = useRef(null);
|
|
4649
4562
|
const onSave = () => {
|
|
4650
|
-
saveToken(
|
|
4563
|
+
saveToken(formData.token).then(onCloseEdit);
|
|
4651
4564
|
};
|
|
4652
4565
|
const onOpenEdit = () => {
|
|
4653
4566
|
setIsEdit(true);
|
|
4654
4567
|
};
|
|
4655
4568
|
const onCloseEdit = () => {
|
|
4656
4569
|
setIsEdit(false);
|
|
4657
|
-
|
|
4570
|
+
resetFormData();
|
|
4658
4571
|
};
|
|
4659
4572
|
const SuccessIcon = getStatusIcon(StatusType.Success, theme);
|
|
4660
|
-
useOnClickOutside(popupRef, onCloseEdit);
|
|
4661
4573
|
return (React.createElement(FlexRow, { "$gap": 0 },
|
|
4662
4574
|
React.createElement(IconButton, { size: 32, onClick: () => clickCopy(token) }, isCopied ? React.createElement(SuccessIcon, null) : React.createElement(CopyIcon, null)),
|
|
4663
4575
|
React.createElement(Divider, { orientation: 'vertical', length: '12px' }),
|
|
4664
4576
|
React.createElement(Relative, null,
|
|
4665
4577
|
React.createElement(IconButton, { size: 32, onClick: onOpenEdit },
|
|
4666
4578
|
React.createElement(EditIcon, null)),
|
|
4667
|
-
isEdit && (React.createElement(
|
|
4668
|
-
React.createElement(
|
|
4669
|
-
React.createElement(Text, { size: 14, style: { lineHeight: '20px', display: 'flex' } }, "Enter a new API Token:")),
|
|
4670
|
-
React.createElement(PopoverFormWrapper, null,
|
|
4671
|
-
React.createElement(Input, { placeholder: 'API Token', type: 'password', value: inputValue, onChange: (e) => setInputValue(e.target.value) }),
|
|
4672
|
-
React.createElement(FlexRow, null,
|
|
4673
|
-
React.createElement(PopoverFormButton, { variant: 'primary', onClick: onSave },
|
|
4674
|
-
React.createElement(CheckIcon, { fill: theme.text.primary })),
|
|
4675
|
-
React.createElement(PopoverFormButton, { variant: 'secondary', onClick: onCloseEdit },
|
|
4676
|
-
React.createElement(CrossIcon, null)))))))));
|
|
4579
|
+
isEdit && (React.createElement(PopupForm, { flipX: true, clientX: 36, isOpen: isEdit, onClose: onCloseEdit, onSave: onSave, title: 'Enter a new API Token', titleTooltip: 'Contact us to generate a new one' },
|
|
4580
|
+
React.createElement(Input, { placeholder: 'API Token', type: 'password', value: formData.token, onChange: (e) => handleFormChange('token', e.target.value) }))))));
|
|
4677
4581
|
};
|
|
4678
4582
|
|
|
4679
4583
|
const Tokens = ({ tokens, saveToken }) => {
|
|
@@ -4719,19 +4623,13 @@ const Describe = ({ fetchDescribeOdigos }) => {
|
|
|
4719
4623
|
return (React.createElement(CenterThis, null,
|
|
4720
4624
|
React.createElement(FadeLoader, null)));
|
|
4721
4625
|
}
|
|
4722
|
-
const
|
|
4626
|
+
const mapObjectToCardChildren = (obj) => !!obj?.name
|
|
4723
4627
|
? [
|
|
4724
|
-
{
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
value: JSON.stringify({
|
|
4730
|
-
title: obj.name,
|
|
4731
|
-
subTitle: obj.explain,
|
|
4732
|
-
value: { text: obj.value, status: obj.status },
|
|
4733
|
-
}),
|
|
4734
|
-
},
|
|
4628
|
+
React.createElement(Divider, { key: `divider-${obj.name}` }),
|
|
4629
|
+
React.createElement(DescribeRow, { key: `describe-row-${obj.name}`, title: obj.name, subTitle: obj.explain || undefined, value: {
|
|
4630
|
+
status: obj.status || parseBooleanFromString(obj.value) ? StatusType.Success : StatusType.Error,
|
|
4631
|
+
text: obj.value,
|
|
4632
|
+
} }),
|
|
4735
4633
|
]
|
|
4736
4634
|
: [];
|
|
4737
4635
|
return (React.createElement(React.Fragment, null,
|
|
@@ -4743,12 +4641,8 @@ const Describe = ({ fetchDescribeOdigos }) => {
|
|
|
4743
4641
|
{ title: '# of sources', value: describe?.numberOfSources?.toString() },
|
|
4744
4642
|
{ title: '# of destinations', value: describe?.numberOfDestinations?.toString() },
|
|
4745
4643
|
] }),
|
|
4746
|
-
React.createElement(DataCard, { title: 'Cluster Collector', withExtend: true,
|
|
4747
|
-
|
|
4748
|
-
.flat() }),
|
|
4749
|
-
React.createElement(DataCard, { title: 'Node Collector', withExtend: true, data: Object.values(describe?.nodeCollector || {})
|
|
4750
|
-
.map(mapObjectToCardFields)
|
|
4751
|
-
.flat() })));
|
|
4644
|
+
React.createElement(DataCard, { title: 'Cluster Collector', withExtend: true }, Object.values(describe?.clusterCollector || {}).map(mapObjectToCardChildren)),
|
|
4645
|
+
React.createElement(DataCard, { title: 'Node Collector', withExtend: true }, Object.values(describe?.nodeCollector || {}).map(mapObjectToCardChildren))));
|
|
4752
4646
|
};
|
|
4753
4647
|
|
|
4754
4648
|
const DataContainer = styled.div `
|