mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 02:19:02 +08:00
Merge branch 'develop' into fix/remove-fe-owner
This commit is contained in:
commit
a5e4336e18
@ -1,23 +1,40 @@
|
|||||||
/* eslint-disable react/no-unstable-nested-components */
|
import { grey } from '@ant-design/colors';
|
||||||
import { QuestionCircleFilled } from '@ant-design/icons';
|
import { QuestionCircleFilled } from '@ant-design/icons';
|
||||||
import { Tooltip } from 'antd';
|
import { Tooltip } from 'antd';
|
||||||
import React from 'react';
|
import { themeColors } from 'constants/theme';
|
||||||
|
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||||
|
import React, { useMemo } from 'react';
|
||||||
|
|
||||||
|
import { style } from './styles';
|
||||||
|
|
||||||
function TextToolTip({ text, url }: TextToolTipProps): JSX.Element {
|
function TextToolTip({ text, url }: TextToolTipProps): JSX.Element {
|
||||||
|
const isDarkMode = useIsDarkMode();
|
||||||
|
|
||||||
|
const overlay = useMemo(
|
||||||
|
() => (
|
||||||
|
<div>
|
||||||
|
{`${text} `}
|
||||||
|
{url && (
|
||||||
|
<a href={url} rel="noopener noreferrer" target="_blank">
|
||||||
|
here
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
[text, url],
|
||||||
|
);
|
||||||
|
|
||||||
|
const iconStyle = useMemo(
|
||||||
|
() => ({
|
||||||
|
...style,
|
||||||
|
color: isDarkMode ? themeColors.whiteCream : grey[0],
|
||||||
|
}),
|
||||||
|
[isDarkMode],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip
|
<Tooltip overlay={overlay}>
|
||||||
overlay={(): JSX.Element => (
|
<QuestionCircleFilled style={iconStyle} />
|
||||||
<div>
|
|
||||||
{`${text} `}
|
|
||||||
{url && (
|
|
||||||
<a href={url} rel="noopener noreferrer" target="_blank">
|
|
||||||
here
|
|
||||||
</a>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<QuestionCircleFilled style={{ fontSize: '1.3125rem' }} />
|
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
1
frontend/src/components/TextToolTip/styles.ts
Normal file
1
frontend/src/components/TextToolTip/styles.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const style = { fontSize: '1.3125rem' };
|
@ -10,7 +10,9 @@ import { v4 as uuid } from 'uuid';
|
|||||||
import QueryChip from './components/QueryChip';
|
import QueryChip from './components/QueryChip';
|
||||||
import { QueryChipItem, SearchContainer } from './styles';
|
import { QueryChipItem, SearchContainer } from './styles';
|
||||||
|
|
||||||
function ResourceAttributesFilter(): JSX.Element | null {
|
function ResourceAttributesFilter({
|
||||||
|
suffixIcon,
|
||||||
|
}: ResourceAttributesFilterProps): JSX.Element | null {
|
||||||
const {
|
const {
|
||||||
queries,
|
queries,
|
||||||
staging,
|
staging,
|
||||||
@ -49,14 +51,15 @@ function ResourceAttributesFilter(): JSX.Element | null {
|
|||||||
style={{ flex: 1 }}
|
style={{ flex: 1 }}
|
||||||
options={optionsData.options}
|
options={optionsData.options}
|
||||||
mode={optionsData?.mode}
|
mode={optionsData?.mode}
|
||||||
showArrow={false}
|
showArrow={!!suffixIcon}
|
||||||
onClick={handleFocus}
|
onClick={handleFocus}
|
||||||
onBlur={handleBlur}
|
onBlur={handleBlur}
|
||||||
onClear={handleClearAll}
|
onClear={handleClearAll}
|
||||||
|
suffixIcon={suffixIcon}
|
||||||
notFoundContent={
|
notFoundContent={
|
||||||
loading ? (
|
loading ? (
|
||||||
<span>
|
<span>
|
||||||
<Spin size="small" /> Loading...{' '}
|
<Spin size="small" /> Loading...
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<span>
|
<span>
|
||||||
@ -74,4 +77,12 @@ function ResourceAttributesFilter(): JSX.Element | null {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ResourceAttributesFilterProps {
|
||||||
|
suffixIcon?: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceAttributesFilter.defaultProps = {
|
||||||
|
suffixIcon: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
export default ResourceAttributesFilter;
|
export default ResourceAttributesFilter;
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import { useMachine } from '@xstate/react';
|
import { useMachine } from '@xstate/react';
|
||||||
|
import ROUTES from 'constants/routes';
|
||||||
import { encode } from 'js-base64';
|
import { encode } from 'js-base64';
|
||||||
import history from 'lib/history';
|
import history from 'lib/history';
|
||||||
import React, { useCallback, useMemo, useState } from 'react';
|
import React, { useCallback, useMemo, useState } from 'react';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { whilelistedKeys } from './config';
|
||||||
import { ResourceContext } from './context';
|
import { ResourceContext } from './context';
|
||||||
import { ResourceAttributesFilterMachine } from './machine';
|
import { ResourceAttributesFilterMachine } from './machine';
|
||||||
import {
|
import {
|
||||||
@ -16,6 +18,7 @@ import {
|
|||||||
getResourceAttributeQueriesFromURL,
|
getResourceAttributeQueriesFromURL,
|
||||||
GetTagKeys,
|
GetTagKeys,
|
||||||
GetTagValues,
|
GetTagValues,
|
||||||
|
mappingWithRoutesAndKeys,
|
||||||
OperatorSchema,
|
OperatorSchema,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
@ -59,7 +62,12 @@ function ResourceProvider({ children }: Props): JSX.Element {
|
|||||||
onSelectTagKey: () => {
|
onSelectTagKey: () => {
|
||||||
handleLoading(true);
|
handleLoading(true);
|
||||||
GetTagKeys()
|
GetTagKeys()
|
||||||
.then((tagKeys) => setOptionsData({ options: tagKeys, mode: undefined }))
|
.then((tagKeys) =>
|
||||||
|
setOptionsData({
|
||||||
|
options: mappingWithRoutesAndKeys(pathname, tagKeys),
|
||||||
|
mode: undefined,
|
||||||
|
}),
|
||||||
|
)
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
handleLoading(false);
|
handleLoading(false);
|
||||||
});
|
});
|
||||||
@ -134,9 +142,16 @@ function ResourceProvider({ children }: Props): JSX.Element {
|
|||||||
setOptionsData({ mode: undefined, options: [] });
|
setOptionsData({ mode: undefined, options: [] });
|
||||||
}, [dispatchQueries, send]);
|
}, [dispatchQueries, send]);
|
||||||
|
|
||||||
|
const getVisibleQueries = useMemo(() => {
|
||||||
|
if (pathname === ROUTES.SERVICE_MAP) {
|
||||||
|
return queries.filter((query) => whilelistedKeys.includes(query.tagKey));
|
||||||
|
}
|
||||||
|
return queries;
|
||||||
|
}, [queries, pathname]);
|
||||||
|
|
||||||
const value: IResourceAttributeProps = useMemo(
|
const value: IResourceAttributeProps = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
queries,
|
queries: getVisibleQueries,
|
||||||
staging,
|
staging,
|
||||||
handleClearAll,
|
handleClearAll,
|
||||||
handleClose,
|
handleClose,
|
||||||
@ -154,10 +169,10 @@ function ResourceProvider({ children }: Props): JSX.Element {
|
|||||||
handleClose,
|
handleClose,
|
||||||
handleFocus,
|
handleFocus,
|
||||||
loading,
|
loading,
|
||||||
queries,
|
|
||||||
staging,
|
staging,
|
||||||
selectedQuery,
|
selectedQuery,
|
||||||
optionsData,
|
optionsData,
|
||||||
|
getVisibleQueries,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
5
frontend/src/hooks/useResourceAttribute/config.ts
Normal file
5
frontend/src/hooks/useResourceAttribute/config.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export const whilelistedKeys = [
|
||||||
|
'resource_deployment_environment',
|
||||||
|
'resource_k8s_cluster_name',
|
||||||
|
'resource_k8s_cluster_namespace',
|
||||||
|
];
|
@ -1,37 +1,32 @@
|
|||||||
|
// This file was automatically generated. Edits will be overwritten
|
||||||
|
|
||||||
// This file was automatically generated. Edits will be overwritten
|
export interface Typegen0 {
|
||||||
|
'@@xstate/typegen': true;
|
||||||
export interface Typegen0 {
|
internalEvents: {
|
||||||
'@@xstate/typegen': true;
|
'xstate.init': { type: 'xstate.init' };
|
||||||
internalEvents: {
|
};
|
||||||
"xstate.init": { type: "xstate.init" };
|
invokeSrcNameMap: {};
|
||||||
};
|
missingImplementations: {
|
||||||
invokeSrcNameMap: {
|
actions:
|
||||||
|
| 'onBlurPurge'
|
||||||
};
|
| 'onSelectOperator'
|
||||||
missingImplementations: {
|
| 'onSelectTagKey'
|
||||||
actions: "onBlurPurge" | "onSelectOperator" | "onSelectTagKey" | "onSelectTagValue" | "onValidateQuery";
|
| 'onSelectTagValue'
|
||||||
delays: never;
|
| 'onValidateQuery';
|
||||||
guards: never;
|
delays: never;
|
||||||
services: never;
|
guards: never;
|
||||||
};
|
services: never;
|
||||||
eventsCausingActions: {
|
};
|
||||||
"onBlurPurge": "onBlur";
|
eventsCausingActions: {
|
||||||
"onSelectOperator": "NEXT";
|
onBlurPurge: 'onBlur';
|
||||||
"onSelectTagKey": "NEXT";
|
onSelectOperator: 'NEXT';
|
||||||
"onSelectTagValue": "NEXT";
|
onSelectTagKey: 'NEXT';
|
||||||
"onValidateQuery": "onBlur";
|
onSelectTagValue: 'NEXT';
|
||||||
};
|
onValidateQuery: 'onBlur';
|
||||||
eventsCausingDelays: {
|
};
|
||||||
|
eventsCausingDelays: {};
|
||||||
};
|
eventsCausingGuards: {};
|
||||||
eventsCausingGuards: {
|
eventsCausingServices: {};
|
||||||
|
matchesStates: 'Idle' | 'Operator' | 'TagKey' | 'TagValue';
|
||||||
};
|
tags: never;
|
||||||
eventsCausingServices: {
|
}
|
||||||
|
|
||||||
};
|
|
||||||
matchesStates: "Idle" | "Operator" | "TagKey" | "TagValue";
|
|
||||||
tags: never;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ import {
|
|||||||
getResourceAttributesTagValues,
|
getResourceAttributesTagValues,
|
||||||
} from 'api/metrics/getResourceAttributes';
|
} from 'api/metrics/getResourceAttributes';
|
||||||
import { OperatorConversions } from 'constants/resourceAttributes';
|
import { OperatorConversions } from 'constants/resourceAttributes';
|
||||||
|
import ROUTES from 'constants/routes';
|
||||||
import {
|
import {
|
||||||
IOption,
|
IOption,
|
||||||
IResourceAttribute,
|
IResourceAttribute,
|
||||||
@ -14,6 +15,8 @@ import { IQueryBuilderTagFilterItems } from 'types/api/dashboard/getAll';
|
|||||||
import { OperatorValues, Tags } from 'types/reducer/trace';
|
import { OperatorValues, Tags } from 'types/reducer/trace';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
|
import { whilelistedKeys } from './config';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* resource_x_y -> x.y
|
* resource_x_y -> x.y
|
||||||
*/
|
*/
|
||||||
@ -139,3 +142,13 @@ export const isResourceEmpty = (
|
|||||||
staging: IResourceAttributeProps['staging'],
|
staging: IResourceAttributeProps['staging'],
|
||||||
selectedQuery: IResourceAttributeProps['selectedQuery'],
|
selectedQuery: IResourceAttributeProps['selectedQuery'],
|
||||||
): boolean => !!(queries.length || staging.length || selectedQuery.length);
|
): boolean => !!(queries.length || staging.length || selectedQuery.length);
|
||||||
|
|
||||||
|
export const mappingWithRoutesAndKeys = (
|
||||||
|
pathname: string,
|
||||||
|
filters: IOption[],
|
||||||
|
): IOption[] => {
|
||||||
|
if (ROUTES.SERVICE_MAP === pathname) {
|
||||||
|
return filters.filter((filter) => whilelistedKeys.includes(filter.value));
|
||||||
|
}
|
||||||
|
return filters;
|
||||||
|
};
|
||||||
|
@ -6,7 +6,7 @@ import { ForceGraph2D } from 'react-force-graph';
|
|||||||
|
|
||||||
import { getGraphData, getTooltip, transformLabel } from './utils';
|
import { getGraphData, getTooltip, transformLabel } from './utils';
|
||||||
|
|
||||||
function Map({ fgRef, serviceMap }: any): JSX.Element {
|
function ServiceMap({ fgRef, serviceMap }: any): JSX.Element {
|
||||||
const isDarkMode = useIsDarkMode();
|
const isDarkMode = useIsDarkMode();
|
||||||
|
|
||||||
const { nodes, links } = getGraphData(serviceMap, isDarkMode);
|
const { nodes, links } = getGraphData(serviceMap, isDarkMode);
|
||||||
@ -53,4 +53,4 @@ function Map({ fgRef, serviceMap }: any): JSX.Element {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default memo(Map);
|
export default memo(ServiceMap);
|
||||||
|
@ -3,8 +3,10 @@
|
|||||||
|
|
||||||
import { Card } from 'antd';
|
import { Card } from 'antd';
|
||||||
import Spinner from 'components/Spinner';
|
import Spinner from 'components/Spinner';
|
||||||
|
import TextToolTip from 'components/TextToolTip';
|
||||||
import ResourceAttributesFilter from 'container/ResourceAttributesFilter';
|
import ResourceAttributesFilter from 'container/ResourceAttributesFilter';
|
||||||
import useResourceAttribute from 'hooks/useResourceAttribute';
|
import useResourceAttribute from 'hooks/useResourceAttribute';
|
||||||
|
import { whilelistedKeys } from 'hooks/useResourceAttribute/config';
|
||||||
import { IResourceAttribute } from 'hooks/useResourceAttribute/types';
|
import { IResourceAttribute } from 'hooks/useResourceAttribute/types';
|
||||||
import React, { useEffect, useRef } from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
@ -94,7 +96,18 @@ function ServiceMap(props: ServiceMapProps): JSX.Element {
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<ResourceAttributesFilter />
|
<ResourceAttributesFilter
|
||||||
|
suffixIcon={
|
||||||
|
<TextToolTip
|
||||||
|
{...{
|
||||||
|
text: `Currently, service map supports filtering of ${whilelistedKeys.join(
|
||||||
|
', ',
|
||||||
|
)} only, in resource attributes`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
<Map fgRef={fgRef} serviceMap={serviceMap} />
|
<Map fgRef={fgRef} serviceMap={serviceMap} />
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user