mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-13 20:05:58 +08:00
feat: added custom cell rendering in gridcard, added new table view in all endpoints
This commit is contained in:
parent
552b103e8b
commit
d6e4e3c5ed
@ -1,34 +1,12 @@
|
||||
import { LoadingOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
Select,
|
||||
Spin,
|
||||
Table,
|
||||
TablePaginationConfig,
|
||||
TableProps,
|
||||
Typography,
|
||||
} from 'antd';
|
||||
import { SorterResult } from 'antd/lib/table/interface';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { ENTITY_VERSION_V4 } from 'constants/app';
|
||||
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
||||
import {
|
||||
EndPointsTableRowData,
|
||||
formatEndPointsDataForTable,
|
||||
getEndPointsColumnsConfig,
|
||||
getEndPointsQueryPayload,
|
||||
} from 'container/ApiMonitoring/utils';
|
||||
import { Select } from 'antd';
|
||||
import { getAllEndpointsWidgetData } from 'container/ApiMonitoring/utils';
|
||||
import GridCard from 'container/GridCardLayout/GridCard';
|
||||
import { useGetAggregateKeys } from 'hooks/queryBuilder/useGetAggregateKeys';
|
||||
import { GetMetricQueryRange } from 'lib/dashboard/getQueryResults';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useQueries } from 'react-query';
|
||||
import { SuccessResponse } from 'types/api';
|
||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
import ErrorState from './components/ErrorState';
|
||||
import ExpandedRow from './components/ExpandedRow';
|
||||
import { VIEW_TYPES, VIEWS } from './constants';
|
||||
import { VIEWS } from './constants';
|
||||
|
||||
function AllEndPoints({
|
||||
domainName,
|
||||
@ -63,13 +41,6 @@ function AllEndPoints({
|
||||
{ value: string; label: string }[]
|
||||
>([]);
|
||||
|
||||
const [orderBy, setOrderBy] = useState<{
|
||||
columnName: string;
|
||||
order: 'asc' | 'desc';
|
||||
} | null>(null);
|
||||
|
||||
const [expandedRowKeys, setExpandedRowKeys] = useState<React.Key[]>([]);
|
||||
|
||||
const handleGroupByChange = useCallback(
|
||||
(value: IBuilderQuery['groupBy']) => {
|
||||
const groupBy = [];
|
||||
@ -101,109 +72,11 @@ function AllEndPoints({
|
||||
}
|
||||
}, [groupByFiltersData]);
|
||||
|
||||
const { startTime: minTime, endTime: maxTime } = timeRange;
|
||||
|
||||
const queryPayloads = useMemo(
|
||||
() => getEndPointsQueryPayload(groupBy, domainName, minTime, maxTime),
|
||||
[groupBy, domainName, minTime, maxTime],
|
||||
const allEndpointsWidgetData = useMemo(
|
||||
() => getAllEndpointsWidgetData(groupBy, domainName),
|
||||
[groupBy, domainName],
|
||||
);
|
||||
|
||||
// Since only one query here
|
||||
const endPointsDataQueries = useQueries(
|
||||
queryPayloads.map((payload) => ({
|
||||
queryKey: [
|
||||
REACT_QUERY_KEY.GET_ENDPOINTS_LIST_BY_DOMAIN,
|
||||
payload,
|
||||
ENTITY_VERSION_V4,
|
||||
groupBy,
|
||||
],
|
||||
queryFn: (): Promise<SuccessResponse<MetricRangePayloadProps>> =>
|
||||
GetMetricQueryRange(payload, ENTITY_VERSION_V4),
|
||||
enabled: !!payload,
|
||||
staleTime: 60 * 1000, // 1 minute stale time : optimize this part
|
||||
})),
|
||||
);
|
||||
|
||||
const endPointsDataQuery = endPointsDataQueries[0];
|
||||
const {
|
||||
data: allEndPointsData,
|
||||
isLoading,
|
||||
isRefetching,
|
||||
isError,
|
||||
refetch,
|
||||
} = endPointsDataQuery;
|
||||
|
||||
const endPointsColumnsConfig = useMemo(
|
||||
() => getEndPointsColumnsConfig(groupBy.length > 0, expandedRowKeys),
|
||||
[groupBy.length, expandedRowKeys],
|
||||
);
|
||||
|
||||
const expandedRowRender = (record: EndPointsTableRowData): JSX.Element => (
|
||||
<ExpandedRow
|
||||
domainName={domainName}
|
||||
selectedRowData={record}
|
||||
setSelectedEndPointName={setSelectedEndPointName}
|
||||
setSelectedView={setSelectedView}
|
||||
orderBy={orderBy}
|
||||
/>
|
||||
);
|
||||
|
||||
const handleGroupByRowClick = (record: EndPointsTableRowData): void => {
|
||||
if (expandedRowKeys.includes(record.key)) {
|
||||
setExpandedRowKeys(expandedRowKeys.filter((key) => key !== record.key));
|
||||
} else {
|
||||
setExpandedRowKeys((expandedRowKeys) => [...expandedRowKeys, record.key]);
|
||||
}
|
||||
};
|
||||
|
||||
const handleRowClick = (record: EndPointsTableRowData): void => {
|
||||
if (groupBy.length === 0) {
|
||||
setSelectedEndPointName(record.endpointName); // this will open up the endpoint details tab
|
||||
setSelectedView(VIEW_TYPES.ENDPOINT_STATS);
|
||||
logEvent('API Monitoring: Endpoint name row clicked', {});
|
||||
} else {
|
||||
handleGroupByRowClick(record); // this will prepare the nested query payload
|
||||
}
|
||||
};
|
||||
|
||||
const handleTableChange: TableProps<EndPointsTableRowData>['onChange'] = useCallback(
|
||||
(
|
||||
_pagination: TablePaginationConfig,
|
||||
_filters: Record<string, (string | number | boolean)[] | null>,
|
||||
sorter:
|
||||
| SorterResult<EndPointsTableRowData>
|
||||
| SorterResult<EndPointsTableRowData>[],
|
||||
): void => {
|
||||
if ('field' in sorter && sorter.order) {
|
||||
setOrderBy({
|
||||
columnName: sorter.field as string,
|
||||
order: sorter.order === 'ascend' ? 'asc' : 'desc',
|
||||
});
|
||||
} else {
|
||||
setOrderBy(null);
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const formattedEndPointsData = useMemo(
|
||||
() =>
|
||||
formatEndPointsDataForTable(
|
||||
allEndPointsData?.payload?.data?.result[0]?.table?.rows,
|
||||
groupBy,
|
||||
orderBy,
|
||||
),
|
||||
[groupBy, allEndPointsData, orderBy],
|
||||
);
|
||||
|
||||
if (isError) {
|
||||
return (
|
||||
<div className="all-endpoints-error-state-wrapper">
|
||||
<ErrorState refetch={refetch} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="all-endpoints-container">
|
||||
<div className="group-by-container">
|
||||
@ -221,47 +94,16 @@ function AllEndPoints({
|
||||
/>{' '}
|
||||
</div>
|
||||
<div className="endpoints-table-container">
|
||||
<div className="endpoints-table-header">Endpoint overview</div>
|
||||
<Table
|
||||
columns={endPointsColumnsConfig}
|
||||
loading={{
|
||||
spinning: isLoading || isRefetching,
|
||||
indicator: <Spin indicator={<LoadingOutlined size={14} spin />} />,
|
||||
<GridCard
|
||||
widget={allEndpointsWidgetData}
|
||||
isQueryEnabled
|
||||
onDragSelect={(): void => {}}
|
||||
customOnDragSelect={(): void => {}}
|
||||
customTimeRange={timeRange}
|
||||
customOnRowClick={(props): void => {
|
||||
setSelectedEndPointName(props['http.url'] as string);
|
||||
setSelectedView(VIEWS.ENDPOINT_STATS);
|
||||
}}
|
||||
dataSource={isLoading || isRefetching ? [] : formattedEndPointsData}
|
||||
locale={{
|
||||
emptyText:
|
||||
isLoading || isRefetching ? null : (
|
||||
<div className="no-filtered-endpoints-message-container">
|
||||
<div className="no-filtered-endpoints-message-content">
|
||||
<img
|
||||
src="/Icons/emptyState.svg"
|
||||
alt="thinking-emoji"
|
||||
className="empty-state-svg"
|
||||
/>
|
||||
|
||||
<Typography.Text className="no-filtered-endpoints-message">
|
||||
This query had no results. Edit your query and try again!
|
||||
</Typography.Text>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
scroll={{ x: true }}
|
||||
tableLayout="fixed"
|
||||
onRow={(record): { onClick: () => void; className: string } => ({
|
||||
onClick: (): void => handleRowClick(record),
|
||||
className: 'clickable-row',
|
||||
})}
|
||||
expandable={{
|
||||
expandedRowRender: groupBy.length > 0 ? expandedRowRender : undefined,
|
||||
expandedRowKeys,
|
||||
expandIconColumnIndex: -1,
|
||||
}}
|
||||
rowClassName={(_, index): string =>
|
||||
index % 2 === 0 ? 'table-row-dark' : 'table-row-light'
|
||||
}
|
||||
onChange={handleTableChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -3276,6 +3276,329 @@ export const END_POINT_DETAILS_QUERY_KEYS_ARRAY = [
|
||||
REACT_QUERY_KEY.GET_ENDPOINT_STATUS_CODE_LATENCY_BAR_CHARTS_DATA,
|
||||
];
|
||||
|
||||
export const getAllEndpointsWidgetData = (
|
||||
groupBy: BaseAutocompleteData[],
|
||||
domainName: string,
|
||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||
): Widgets => {
|
||||
const isGroupedByAttribute = groupBy.length > 0;
|
||||
|
||||
const widget = getWidgetQueryBuilder(
|
||||
getWidgetQuery({
|
||||
title: 'Endpoint Overview',
|
||||
description: 'Endpoint Overview',
|
||||
panelTypes: PANEL_TYPES.TABLE,
|
||||
queryData: [
|
||||
{
|
||||
aggregateAttribute: {
|
||||
dataType: DataTypes.String,
|
||||
id: 'span_id--string----true',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
key: 'span_id',
|
||||
type: '',
|
||||
},
|
||||
aggregateOperator: 'count',
|
||||
dataSource: DataSource.TRACES,
|
||||
disabled: false,
|
||||
expression: 'A',
|
||||
filters: {
|
||||
items: [
|
||||
{
|
||||
id: 'ec316e57',
|
||||
key: {
|
||||
dataType: DataTypes.String,
|
||||
id: 'net.peer.name--string--tag--false',
|
||||
isColumn: false,
|
||||
isJSON: false,
|
||||
key: 'net.peer.name',
|
||||
type: 'tag',
|
||||
},
|
||||
op: '=',
|
||||
value: domainName,
|
||||
},
|
||||
{
|
||||
id: '212678b9',
|
||||
key: {
|
||||
key: 'kind_string',
|
||||
dataType: DataTypes.String,
|
||||
type: '',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
id: 'kind_string--string----true',
|
||||
},
|
||||
op: '=',
|
||||
value: 'Client',
|
||||
},
|
||||
],
|
||||
op: 'AND',
|
||||
},
|
||||
functions: [],
|
||||
groupBy: isGroupedByAttribute
|
||||
? [...defaultGroupBy, ...groupBy]
|
||||
: defaultGroupBy,
|
||||
having: [],
|
||||
legend: 'Num of Calls',
|
||||
limit: 1000,
|
||||
orderBy: [],
|
||||
queryName: 'A',
|
||||
reduceTo: 'avg',
|
||||
spaceAggregation: 'sum',
|
||||
stepInterval: 60,
|
||||
timeAggregation: 'count',
|
||||
},
|
||||
{
|
||||
aggregateAttribute: {
|
||||
dataType: DataTypes.Float64,
|
||||
id: 'duration_nano--float64----true',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
key: 'duration_nano',
|
||||
type: '',
|
||||
},
|
||||
aggregateOperator: 'p99',
|
||||
dataSource: DataSource.TRACES,
|
||||
disabled: false,
|
||||
expression: 'B',
|
||||
filters: {
|
||||
items: [
|
||||
{
|
||||
id: '46d57857',
|
||||
key: {
|
||||
dataType: DataTypes.String,
|
||||
id: 'net.peer.name--string--tag--false',
|
||||
isColumn: false,
|
||||
isJSON: false,
|
||||
key: 'net.peer.name',
|
||||
type: 'tag',
|
||||
},
|
||||
op: '=',
|
||||
value: domainName,
|
||||
},
|
||||
{
|
||||
id: '212678b9',
|
||||
key: {
|
||||
key: 'kind_string',
|
||||
dataType: DataTypes.String,
|
||||
type: '',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
id: 'kind_string--string----true',
|
||||
},
|
||||
op: '=',
|
||||
value: 'Client',
|
||||
},
|
||||
],
|
||||
op: 'AND',
|
||||
},
|
||||
functions: [],
|
||||
groupBy: isGroupedByAttribute
|
||||
? [...defaultGroupBy, ...groupBy]
|
||||
: defaultGroupBy,
|
||||
having: [],
|
||||
legend: 'Latency (ms)',
|
||||
limit: 1000,
|
||||
orderBy: [],
|
||||
queryName: 'B',
|
||||
reduceTo: 'avg',
|
||||
spaceAggregation: 'sum',
|
||||
stepInterval: 60,
|
||||
timeAggregation: 'p99',
|
||||
},
|
||||
{
|
||||
aggregateAttribute: {
|
||||
dataType: DataTypes.String,
|
||||
id: 'timestamp------false',
|
||||
isColumn: false,
|
||||
key: 'timestamp',
|
||||
type: '',
|
||||
},
|
||||
aggregateOperator: 'max',
|
||||
dataSource: DataSource.TRACES,
|
||||
disabled: false,
|
||||
expression: 'C',
|
||||
filters: {
|
||||
items: [
|
||||
{
|
||||
id: '4a237616',
|
||||
key: {
|
||||
dataType: DataTypes.String,
|
||||
id: 'net.peer.name--string--tag--false',
|
||||
isColumn: false,
|
||||
isJSON: false,
|
||||
key: 'net.peer.name',
|
||||
type: 'tag',
|
||||
},
|
||||
op: '=',
|
||||
value: domainName,
|
||||
},
|
||||
{
|
||||
id: '212678b9',
|
||||
key: {
|
||||
key: 'kind_string',
|
||||
dataType: DataTypes.String,
|
||||
type: '',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
id: 'kind_string--string----true',
|
||||
},
|
||||
op: '=',
|
||||
value: 'Client',
|
||||
},
|
||||
],
|
||||
op: 'AND',
|
||||
},
|
||||
functions: [],
|
||||
groupBy: isGroupedByAttribute
|
||||
? [...defaultGroupBy, ...groupBy]
|
||||
: defaultGroupBy,
|
||||
having: [],
|
||||
legend: 'Last Used',
|
||||
limit: 1000,
|
||||
orderBy: [],
|
||||
queryName: 'C',
|
||||
reduceTo: 'avg',
|
||||
spaceAggregation: 'sum',
|
||||
stepInterval: 60,
|
||||
timeAggregation: 'max',
|
||||
},
|
||||
{
|
||||
aggregateAttribute: {
|
||||
dataType: DataTypes.String,
|
||||
id: 'span_id--string----true',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
key: 'span_id',
|
||||
type: '',
|
||||
},
|
||||
aggregateOperator: 'count',
|
||||
dataSource: DataSource.TRACES,
|
||||
disabled: true,
|
||||
expression: 'D',
|
||||
filters: {
|
||||
items: [
|
||||
{
|
||||
id: 'f162de1e',
|
||||
key: {
|
||||
dataType: DataTypes.String,
|
||||
id: 'net.peer.name--string--tag--false',
|
||||
isColumn: false,
|
||||
isJSON: false,
|
||||
key: 'net.peer.name',
|
||||
type: 'tag',
|
||||
},
|
||||
op: '=',
|
||||
value: domainName,
|
||||
},
|
||||
{
|
||||
id: '3df0ac1d',
|
||||
key: {
|
||||
dataType: DataTypes.bool,
|
||||
id: 'has_error--bool----true',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
key: 'has_error',
|
||||
type: '',
|
||||
},
|
||||
op: '=',
|
||||
value: 'true',
|
||||
},
|
||||
{
|
||||
id: '212678b9',
|
||||
key: {
|
||||
key: 'kind_string',
|
||||
dataType: DataTypes.String,
|
||||
type: '',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
id: 'kind_string--string----true',
|
||||
},
|
||||
op: '=',
|
||||
value: 'Client',
|
||||
},
|
||||
],
|
||||
op: 'AND',
|
||||
},
|
||||
functions: [],
|
||||
groupBy: isGroupedByAttribute
|
||||
? [...defaultGroupBy, ...groupBy]
|
||||
: defaultGroupBy,
|
||||
having: [],
|
||||
legend: '',
|
||||
limit: 1000,
|
||||
orderBy: [],
|
||||
queryName: 'D',
|
||||
reduceTo: 'avg',
|
||||
spaceAggregation: 'sum',
|
||||
stepInterval: 60,
|
||||
timeAggregation: 'count',
|
||||
},
|
||||
],
|
||||
queryFormulas: [
|
||||
{
|
||||
queryName: 'F1',
|
||||
expression: '(D/A)*100',
|
||||
disabled: false,
|
||||
legend: 'error percentage',
|
||||
},
|
||||
],
|
||||
yAxisUnit: 'ops/s',
|
||||
}),
|
||||
);
|
||||
|
||||
widget.renderColumnCell = {
|
||||
A: (numOfCalls: any): ReactNode => (
|
||||
<span>
|
||||
{numOfCalls === 'n/a' || numOfCalls === undefined ? '-' : numOfCalls}
|
||||
</span>
|
||||
),
|
||||
B: (latency: any): ReactNode => (
|
||||
<span>
|
||||
{latency === 'n/a' || latency === undefined
|
||||
? '-'
|
||||
: `${Math.round(Number(latency) / 1000000)} ms`}
|
||||
</span>
|
||||
),
|
||||
C: (lastUsed: any): ReactNode => (
|
||||
<span>
|
||||
{lastUsed === 'n/a' || lastUsed === undefined
|
||||
? '-'
|
||||
: getLastUsedRelativeTime(
|
||||
new Date(
|
||||
new Date(Math.floor(Number(lastUsed) / 1000000)).toISOString(),
|
||||
).getTime(),
|
||||
)}
|
||||
</span>
|
||||
),
|
||||
F1: (errorRate: any): ReactNode => (
|
||||
<Progress
|
||||
status="active"
|
||||
percent={Number(
|
||||
((errorRate === 'n/a' || errorRate === '-'
|
||||
? 0
|
||||
: errorRate) as number).toFixed(1),
|
||||
)}
|
||||
strokeLinecap="butt"
|
||||
size="small"
|
||||
strokeColor={((): // eslint-disable-next-line sonarjs/no-identical-functions
|
||||
string => {
|
||||
const errorRatePercent = Number(
|
||||
((errorRate === 'n/a' || errorRate === '-'
|
||||
? 0
|
||||
: errorRate) as number).toFixed(1),
|
||||
);
|
||||
if (errorRatePercent >= 90) return Color.BG_SAKURA_500;
|
||||
if (errorRatePercent >= 60) return Color.BG_AMBER_500;
|
||||
return Color.BG_FOREST_500;
|
||||
})()}
|
||||
className="progress-bar error-rate"
|
||||
/>
|
||||
),
|
||||
};
|
||||
|
||||
return widget;
|
||||
};
|
||||
|
||||
export const getRateOverTimeWidgetData = (
|
||||
domainName: string,
|
||||
endPointName: string,
|
||||
|
@ -56,6 +56,7 @@ function WidgetGraphComponent({
|
||||
onOpenTraceBtnClick,
|
||||
customSeries,
|
||||
customErrorMessage,
|
||||
customOnRowClick,
|
||||
}: WidgetGraphComponentProps): JSX.Element {
|
||||
const { safeNavigate } = useSafeNavigate();
|
||||
const [deleteModal, setDeleteModal] = useState(false);
|
||||
@ -380,6 +381,7 @@ function WidgetGraphComponent({
|
||||
openTracesButton={openTracesButton}
|
||||
onOpenTraceBtnClick={onOpenTraceBtnClick}
|
||||
customSeries={customSeries}
|
||||
customOnRowClick={customOnRowClick}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
@ -48,6 +48,7 @@ function GridCardGraph({
|
||||
end,
|
||||
analyticsEvent,
|
||||
customTimeRange,
|
||||
customOnRowClick,
|
||||
}: GridCardGraphProps): JSX.Element {
|
||||
const dispatch = useDispatch();
|
||||
const [errorMessage, setErrorMessage] = useState<string>();
|
||||
@ -287,6 +288,7 @@ function GridCardGraph({
|
||||
onOpenTraceBtnClick={onOpenTraceBtnClick}
|
||||
customSeries={customSeries}
|
||||
customErrorMessage={isInternalServerError ? customErrorMessage : undefined}
|
||||
customOnRowClick={customOnRowClick}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
@ -39,6 +39,7 @@ export interface WidgetGraphComponentProps {
|
||||
onOpenTraceBtnClick?: (record: RowData) => void;
|
||||
customSeries?: (data: QueryData[]) => uPlot.Series[];
|
||||
customErrorMessage?: string;
|
||||
customOnRowClick?: (record: RowData) => void;
|
||||
}
|
||||
|
||||
export interface GridCardGraphProps {
|
||||
@ -65,6 +66,7 @@ export interface GridCardGraphProps {
|
||||
startTime: number;
|
||||
endTime: number;
|
||||
};
|
||||
customOnRowClick?: (record: RowData) => void;
|
||||
}
|
||||
|
||||
export interface GetGraphVisibilityStateOnLegendClickProps {
|
||||
|
@ -43,6 +43,7 @@ function GridTableComponent({
|
||||
sticky,
|
||||
openTracesButton,
|
||||
onOpenTraceBtnClick,
|
||||
customOnRowClick,
|
||||
widgetId,
|
||||
...props
|
||||
}: GridTableComponentProps): JSX.Element {
|
||||
@ -214,6 +215,18 @@ function GridTableComponent({
|
||||
[newColumnData],
|
||||
);
|
||||
|
||||
const newColumnsWithRenderColumnCell = useMemo(
|
||||
() =>
|
||||
newColumnData.map((column) => ({
|
||||
...column,
|
||||
...('dataIndex' in column &&
|
||||
props.renderColumnCell?.[column.dataIndex as string]
|
||||
? { render: props.renderColumnCell[column.dataIndex as string] }
|
||||
: {}),
|
||||
})),
|
||||
[newColumnData, props.renderColumnCell],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
eventEmitter.emit(Events.TABLE_COLUMNS_DATA, {
|
||||
columns: newColumnData,
|
||||
@ -227,15 +240,22 @@ function GridTableComponent({
|
||||
query={query}
|
||||
queryTableData={data}
|
||||
loading={false}
|
||||
columns={openTracesButton ? columnDataWithOpenTracesButton : newColumnData}
|
||||
columns={
|
||||
openTracesButton
|
||||
? columnDataWithOpenTracesButton
|
||||
: newColumnsWithRenderColumnCell
|
||||
}
|
||||
dataSource={dataSource}
|
||||
sticky={sticky}
|
||||
widgetId={widgetId}
|
||||
onRow={
|
||||
openTracesButton
|
||||
openTracesButton || customOnRowClick
|
||||
? (record): React.HTMLAttributes<HTMLElement> => ({
|
||||
onClick: (): void => {
|
||||
if (openTracesButton) {
|
||||
onOpenTraceBtnClick?.(record);
|
||||
}
|
||||
customOnRowClick?.(record);
|
||||
},
|
||||
})
|
||||
: undefined
|
||||
|
@ -4,6 +4,7 @@ import {
|
||||
ThresholdOperators,
|
||||
ThresholdProps,
|
||||
} from 'container/NewWidget/RightContainer/Threshold/types';
|
||||
import { QueryTableProps } from 'container/QueryTable/QueryTable.intefaces';
|
||||
import { RowData } from 'lib/query/createTableColumnsFromQuery';
|
||||
import { ColumnUnit } from 'types/api/dashboard/getAll';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
@ -17,7 +18,9 @@ export type GridTableComponentProps = {
|
||||
searchTerm?: string;
|
||||
openTracesButton?: boolean;
|
||||
onOpenTraceBtnClick?: (record: RowData) => void;
|
||||
customOnRowClick?: (record: RowData) => void;
|
||||
widgetId?: string;
|
||||
renderColumnCell?: QueryTableProps['renderColumnCell'];
|
||||
} & Pick<LogsExplorerTableProps, 'data'> &
|
||||
Omit<TableProps<RowData>, 'columns' | 'dataSource'>;
|
||||
|
||||
|
@ -20,6 +20,7 @@ function PanelWrapper({
|
||||
openTracesButton,
|
||||
onOpenTraceBtnClick,
|
||||
customSeries,
|
||||
customOnRowClick,
|
||||
}: PanelWrapperProps): JSX.Element {
|
||||
const Component = PanelTypeVsPanelWrapper[
|
||||
selectedGraph || widget.panelTypes
|
||||
@ -46,6 +47,7 @@ function PanelWrapper({
|
||||
searchTerm={searchTerm}
|
||||
openTracesButton={openTracesButton}
|
||||
onOpenTraceBtnClick={onOpenTraceBtnClick}
|
||||
customOnRowClick={customOnRowClick}
|
||||
customSeries={customSeries}
|
||||
/>
|
||||
);
|
||||
|
@ -11,6 +11,7 @@ function TablePanelWrapper({
|
||||
searchTerm,
|
||||
openTracesButton,
|
||||
onOpenTraceBtnClick,
|
||||
customOnRowClick,
|
||||
}: PanelWrapperProps): JSX.Element {
|
||||
const panelData =
|
||||
(queryResponse.data?.payload?.data?.result?.[0] as any)?.table || [];
|
||||
@ -26,7 +27,9 @@ function TablePanelWrapper({
|
||||
searchTerm={searchTerm}
|
||||
openTracesButton={openTracesButton}
|
||||
onOpenTraceBtnClick={onOpenTraceBtnClick}
|
||||
customOnRowClick={customOnRowClick}
|
||||
widgetId={widget.id}
|
||||
renderColumnCell={widget.renderColumnCell}
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
{...GRID_TABLE_CONFIG}
|
||||
/>
|
||||
|
@ -28,6 +28,7 @@ export type PanelWrapperProps = {
|
||||
customTooltipElement?: HTMLDivElement;
|
||||
openTracesButton?: boolean;
|
||||
onOpenTraceBtnClick?: (record: RowData) => void;
|
||||
customOnRowClick?: (record: RowData) => void;
|
||||
customSeries?: (data: QueryData[]) => uPlot.Series[];
|
||||
};
|
||||
|
||||
|
@ -3,7 +3,10 @@ import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { GetWidgetQueryBuilderProps } from 'container/MetricsApplication/types';
|
||||
import { Widgets } from 'types/api/dashboard/getAll';
|
||||
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import {
|
||||
IBuilderFormula,
|
||||
IBuilderQuery,
|
||||
} from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
@ -12,6 +15,7 @@ interface GetWidgetQueryProps {
|
||||
title: string;
|
||||
description: string;
|
||||
queryData: IBuilderQuery[];
|
||||
queryFormulas?: IBuilderFormula[];
|
||||
panelTypes?: PANEL_TYPES;
|
||||
yAxisUnit?: string;
|
||||
columnUnits?: Record<string, string>;
|
||||
@ -67,7 +71,7 @@ export function getWidgetQuery(
|
||||
promql: [],
|
||||
builder: {
|
||||
queryData: props.queryData,
|
||||
queryFormulas: [],
|
||||
queryFormulas: (props.queryFormulas as IBuilderFormula[]) || [],
|
||||
},
|
||||
clickhouse_sql: [],
|
||||
id: uuid(),
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { PANEL_GROUP_TYPES, PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { ThresholdProps } from 'container/NewWidget/RightContainer/Threshold/types';
|
||||
import { timePreferenceType } from 'container/NewWidget/RightContainer/timeItems';
|
||||
import { QueryTableProps } from 'container/QueryTable/QueryTable.intefaces';
|
||||
import { ReactNode } from 'react';
|
||||
import { Layout } from 'react-grid-layout';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
@ -113,6 +114,7 @@ export interface IBaseWidget {
|
||||
}
|
||||
export interface Widgets extends IBaseWidget {
|
||||
query: Query;
|
||||
renderColumnCell?: QueryTableProps['renderColumnCell'];
|
||||
}
|
||||
|
||||
export interface PromQLWidgets extends IBaseWidget {
|
||||
|
Loading…
x
Reference in New Issue
Block a user