mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 05:49:03 +08:00
feat: celery - misc feedback fixes (#7019)
* feat: celery - misc feedback fixes * feat: enabled better sharing and auto-refresh * feat: made task name filter more visible
This commit is contained in:
parent
3b550c485d
commit
cf95b15ba1
@ -1,7 +1,6 @@
|
||||
import './CeleryOverviewConfigOptions.styles.scss';
|
||||
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import { Button, Row, Select, Spin, Tooltip } from 'antd';
|
||||
import { Row, Select, Spin } from 'antd';
|
||||
import {
|
||||
getValuesFromQueryParams,
|
||||
setQueryParamsFromOptions,
|
||||
@ -10,10 +9,7 @@ import { useCeleryFilterOptions } from 'components/CeleryTask/useCeleryFilterOpt
|
||||
import { SelectMaxTagPlaceholder } from 'components/MessagingQueues/MQCommon/MQCommon';
|
||||
import { QueryParams } from 'constants/query';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { Check, Share2 } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
import { useHistory, useLocation } from 'react-router-dom';
|
||||
import { useCopyToClipboard } from 'react-use';
|
||||
|
||||
interface SelectOptionConfig {
|
||||
placeholder: string;
|
||||
@ -66,10 +62,6 @@ function FilterSelect({
|
||||
}
|
||||
|
||||
function CeleryOverviewConfigOptions(): JSX.Element {
|
||||
const [isURLCopied, setIsURLCopied] = useState(false);
|
||||
|
||||
const [, handleCopyToClipboard] = useCopyToClipboard();
|
||||
|
||||
const selectConfigs: SelectOptionConfig[] = [
|
||||
{
|
||||
placeholder: 'Service Name',
|
||||
@ -98,14 +90,6 @@ function CeleryOverviewConfigOptions(): JSX.Element {
|
||||
},
|
||||
];
|
||||
|
||||
const handleShareURL = (): void => {
|
||||
handleCopyToClipboard(window.location.href);
|
||||
setIsURLCopied(true);
|
||||
setTimeout(() => {
|
||||
setIsURLCopied(false);
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="celery-overview-filters">
|
||||
<Row className="celery-filters">
|
||||
@ -118,19 +102,6 @@ function CeleryOverviewConfigOptions(): JSX.Element {
|
||||
/>
|
||||
))}
|
||||
</Row>
|
||||
<Tooltip title="Share this" arrow={false}>
|
||||
<Button
|
||||
className="periscope-btn copy-url-btn"
|
||||
onClick={handleShareURL}
|
||||
icon={
|
||||
isURLCopied ? (
|
||||
<Check size={14} color={Color.BG_FOREST_500} />
|
||||
) : (
|
||||
<Share2 size={14} />
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -37,7 +37,6 @@
|
||||
font-weight: 600;
|
||||
line-height: 18px; /* 163.636% */
|
||||
letter-spacing: 0.44px;
|
||||
text-transform: uppercase;
|
||||
|
||||
&::before {
|
||||
background-color: transparent;
|
||||
|
@ -218,20 +218,26 @@ function getColumns(data: RowData[]): TableColumnsType<RowData> {
|
||||
showTitle: false,
|
||||
},
|
||||
width: 200,
|
||||
sorter: (a: RowData, b: RowData): number =>
|
||||
String(a.error_percentage).localeCompare(String(b.error_percentage)),
|
||||
sorter: (a: RowData, b: RowData): number => {
|
||||
const aValue = Number(a.error_percentage);
|
||||
const bValue = Number(b.error_percentage);
|
||||
return aValue - bValue;
|
||||
},
|
||||
render: ProgressRender,
|
||||
},
|
||||
{
|
||||
title: 'LATENCY (P95)',
|
||||
title: 'LATENCY (P95) in ms',
|
||||
dataIndex: 'p95_latency',
|
||||
key: 'p95_latency',
|
||||
ellipsis: {
|
||||
showTitle: false,
|
||||
},
|
||||
width: 100,
|
||||
sorter: (a: RowData, b: RowData): number =>
|
||||
String(a.p95_latency).localeCompare(String(b.p95_latency)),
|
||||
sorter: (a: RowData, b: RowData): number => {
|
||||
const aValue = Number(a.p95_latency);
|
||||
const bValue = Number(b.p95_latency);
|
||||
return aValue - bValue;
|
||||
},
|
||||
render: (value: number | string): string => {
|
||||
if (!isNumber(value)) return value.toString();
|
||||
return (typeof value === 'string' ? parseFloat(value) : value).toFixed(3);
|
||||
@ -245,8 +251,11 @@ function getColumns(data: RowData[]): TableColumnsType<RowData> {
|
||||
showTitle: false,
|
||||
},
|
||||
width: 100,
|
||||
sorter: (a: RowData, b: RowData): number =>
|
||||
String(a.throughput).localeCompare(String(b.throughput)),
|
||||
sorter: (a: RowData, b: RowData): number => {
|
||||
const aValue = Number(a.throughput);
|
||||
const bValue = Number(b.throughput);
|
||||
return aValue - bValue;
|
||||
},
|
||||
render: (value: number | string): string => {
|
||||
if (!isNumber(value)) return value.toString();
|
||||
return (typeof value === 'string' ? parseFloat(value) : value).toFixed(3);
|
||||
|
@ -2,24 +2,16 @@ import './CeleryTaskDetail.style.scss';
|
||||
|
||||
import { Color, Spacing } from '@signozhq/design-tokens';
|
||||
import { Divider, Drawer, Typography } from 'antd';
|
||||
import { QueryParams } from 'constants/query';
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import dayjs from 'dayjs';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { X } from 'lucide-react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useHistory, useLocation } from 'react-router-dom';
|
||||
import { UpdateTimeInterval } from 'store/actions';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { useState } from 'react';
|
||||
import { Widgets } from 'types/api/dashboard/getAll';
|
||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import CeleryTaskGraph from '../CeleryTaskGraph/CeleryTaskGraph';
|
||||
import { createFiltersFromData } from '../CeleryUtils';
|
||||
import { useNavigateToTraces } from '../useNavigateToTraces';
|
||||
|
||||
export type CeleryTaskData = {
|
||||
@ -39,40 +31,6 @@ export type CeleryTaskDetailProps = {
|
||||
drawerOpen: boolean;
|
||||
};
|
||||
|
||||
const createFiltersFromData = (
|
||||
data: Record<string, any>,
|
||||
): Array<{
|
||||
id: string;
|
||||
key: {
|
||||
key: string;
|
||||
dataType: DataTypes;
|
||||
type: string;
|
||||
isColumn: boolean;
|
||||
isJSON: boolean;
|
||||
id: string;
|
||||
};
|
||||
op: string;
|
||||
value: string;
|
||||
}> => {
|
||||
const excludeKeys = ['A', 'A_without_unit'];
|
||||
|
||||
return Object.entries(data)
|
||||
.filter(([key]) => !excludeKeys.includes(key))
|
||||
.map(([key, value]) => ({
|
||||
id: uuidv4(),
|
||||
key: {
|
||||
key,
|
||||
dataType: DataTypes.String,
|
||||
type: 'tag',
|
||||
isColumn: false,
|
||||
isJSON: false,
|
||||
id: `${key}--string--tag--false`,
|
||||
},
|
||||
op: '=',
|
||||
value: value.toString(),
|
||||
}));
|
||||
};
|
||||
|
||||
export default function CeleryTaskDetail({
|
||||
widgetData,
|
||||
taskData,
|
||||
@ -85,7 +43,7 @@ export default function CeleryTaskDetail({
|
||||
!!taskData.entity && !!taskData.timeRange[0] && drawerOpen;
|
||||
|
||||
const formatTimestamp = (timestamp: number): string =>
|
||||
dayjs(timestamp * 1000).format('MM-DD-YYYY hh:mm A');
|
||||
dayjs(timestamp).format('DD-MM-YYYY hh:mm A');
|
||||
|
||||
const [totalTask, setTotalTask] = useState(0);
|
||||
|
||||
@ -93,52 +51,9 @@ export default function CeleryTaskDetail({
|
||||
setTotalTask((graphData?.result?.[0] as any)?.table?.rows.length);
|
||||
};
|
||||
|
||||
// set time range
|
||||
const { minTime, maxTime, selectedTime } = useSelector<
|
||||
AppState,
|
||||
GlobalReducer
|
||||
>((state) => state.globalTime);
|
||||
|
||||
const startTime = taskData.timeRange[0];
|
||||
const endTime = taskData.timeRange[1];
|
||||
|
||||
const urlQuery = useUrlQuery();
|
||||
const location = useLocation();
|
||||
const history = useHistory();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
urlQuery.delete(QueryParams.relativeTime);
|
||||
urlQuery.set(QueryParams.startTime, startTime.toString());
|
||||
urlQuery.set(QueryParams.endTime, endTime.toString());
|
||||
|
||||
const generatedUrl = `${location.pathname}?${urlQuery.toString()}`;
|
||||
history.replace(generatedUrl);
|
||||
|
||||
if (startTime !== endTime) {
|
||||
dispatch(UpdateTimeInterval('custom', [startTime, endTime]));
|
||||
}
|
||||
|
||||
return (): void => {
|
||||
urlQuery.delete(QueryParams.relativeTime);
|
||||
urlQuery.delete(QueryParams.startTime);
|
||||
urlQuery.delete(QueryParams.endTime);
|
||||
|
||||
if (selectedTime !== 'custom') {
|
||||
dispatch(UpdateTimeInterval(selectedTime));
|
||||
urlQuery.set(QueryParams.relativeTime, selectedTime);
|
||||
} else {
|
||||
dispatch(UpdateTimeInterval('custom', [minTime / 1e6, maxTime / 1e6]));
|
||||
urlQuery.set(QueryParams.startTime, Math.floor(minTime / 1e6).toString());
|
||||
urlQuery.set(QueryParams.endTime, Math.floor(maxTime / 1e6).toString());
|
||||
}
|
||||
|
||||
const generatedUrl = `${location.pathname}?${urlQuery.toString()}`;
|
||||
history.replace(generatedUrl);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const navigateToTrace = useNavigateToTraces();
|
||||
|
||||
return (
|
||||
@ -149,10 +64,8 @@ export default function CeleryTaskDetail({
|
||||
<Typography.Text className="title">{`Details - ${taskData.entity}`}</Typography.Text>
|
||||
<div>
|
||||
<Typography.Text className="subtitle">
|
||||
{`${formatTimestamp(taskData.timeRange[0])} ${
|
||||
taskData.timeRange[1]
|
||||
? `- ${formatTimestamp(taskData.timeRange[1])}`
|
||||
: ''
|
||||
{`${formatTimestamp(startTime)} ${
|
||||
endTime ? `- ${formatTimestamp(endTime)}` : ''
|
||||
}`}
|
||||
</Typography.Text>
|
||||
<Divider type="vertical" />
|
||||
@ -185,8 +98,10 @@ export default function CeleryTaskDetail({
|
||||
...rowData,
|
||||
[taskData.entity]: taskData.value,
|
||||
});
|
||||
navigateToTrace(filters);
|
||||
navigateToTrace(filters, startTime, endTime);
|
||||
}}
|
||||
start={startTime}
|
||||
end={endTime}
|
||||
/>
|
||||
</Drawer>
|
||||
);
|
||||
|
@ -19,6 +19,10 @@ import { Widgets } from 'types/api/dashboard/getAll';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
|
||||
import { CaptureDataProps } from '../CeleryTaskDetail/CeleryTaskDetail';
|
||||
import {
|
||||
applyCeleryFilterOnWidgetData,
|
||||
getFiltersFromQueryParams,
|
||||
} from '../CeleryUtils';
|
||||
import { useGetGraphCustomSeries } from '../useGetGraphCustomSeries';
|
||||
import {
|
||||
celeryAllStateWidgetData,
|
||||
@ -72,26 +76,60 @@ function CeleryTaskBar({
|
||||
|
||||
const [barState, setBarState] = useState<CeleryTaskState>(CeleryTaskState.All);
|
||||
|
||||
const selectedFilters = useMemo(
|
||||
() =>
|
||||
getFiltersFromQueryParams(
|
||||
QueryParams.taskName,
|
||||
urlQuery,
|
||||
'celery.task_name',
|
||||
),
|
||||
[urlQuery],
|
||||
);
|
||||
|
||||
const celeryAllStateData = useMemo(
|
||||
() => celeryAllStateWidgetData(minTime, maxTime),
|
||||
[minTime, maxTime],
|
||||
);
|
||||
|
||||
const celeryAllStateFilteredData = useMemo(
|
||||
() =>
|
||||
applyCeleryFilterOnWidgetData(selectedFilters || [], celeryAllStateData),
|
||||
[selectedFilters, celeryAllStateData],
|
||||
);
|
||||
|
||||
const celeryFailedStateData = useMemo(
|
||||
() => celeryFailedStateWidgetData(minTime, maxTime),
|
||||
[minTime, maxTime],
|
||||
);
|
||||
|
||||
const celeryFailedStateFilteredData = useMemo(
|
||||
() =>
|
||||
applyCeleryFilterOnWidgetData(selectedFilters || [], celeryFailedStateData),
|
||||
[selectedFilters, celeryFailedStateData],
|
||||
);
|
||||
|
||||
const celeryRetryStateData = useMemo(
|
||||
() => celeryRetryStateWidgetData(minTime, maxTime),
|
||||
[minTime, maxTime],
|
||||
);
|
||||
|
||||
const celeryRetryStateFilteredData = useMemo(
|
||||
() =>
|
||||
applyCeleryFilterOnWidgetData(selectedFilters || [], celeryRetryStateData),
|
||||
[selectedFilters, celeryRetryStateData],
|
||||
);
|
||||
|
||||
const celerySuccessStateData = useMemo(
|
||||
() => celerySuccessStateWidgetData(minTime, maxTime),
|
||||
[minTime, maxTime],
|
||||
);
|
||||
|
||||
const celerySuccessStateFilteredData = useMemo(
|
||||
() =>
|
||||
applyCeleryFilterOnWidgetData(selectedFilters || [], celerySuccessStateData),
|
||||
[selectedFilters, celerySuccessStateData],
|
||||
);
|
||||
|
||||
const onGraphClick = (
|
||||
widgetData: Widgets,
|
||||
xValue: number,
|
||||
@ -141,7 +179,7 @@ function CeleryTaskBar({
|
||||
<div className="celery-task-graph-grid-content">
|
||||
{barState === CeleryTaskState.All && (
|
||||
<GridCard
|
||||
widget={celeryAllStateData}
|
||||
widget={celeryAllStateFilteredData}
|
||||
headerMenuList={[...ViewMenuAction]}
|
||||
onDragSelect={onDragSelect}
|
||||
isQueryEnabled={queryEnabled}
|
||||
@ -153,7 +191,7 @@ function CeleryTaskBar({
|
||||
)}
|
||||
{barState === CeleryTaskState.Failed && (
|
||||
<GridCard
|
||||
widget={celeryFailedStateData}
|
||||
widget={celeryFailedStateFilteredData}
|
||||
headerMenuList={[...ViewMenuAction]}
|
||||
onDragSelect={onDragSelect}
|
||||
isQueryEnabled={queryEnabled}
|
||||
@ -165,7 +203,7 @@ function CeleryTaskBar({
|
||||
)}
|
||||
{barState === CeleryTaskState.Retry && (
|
||||
<GridCard
|
||||
widget={celeryRetryStateData}
|
||||
widget={celeryRetryStateFilteredData}
|
||||
headerMenuList={[...ViewMenuAction]}
|
||||
onDragSelect={onDragSelect}
|
||||
isQueryEnabled={queryEnabled}
|
||||
@ -177,7 +215,7 @@ function CeleryTaskBar({
|
||||
)}
|
||||
{barState === CeleryTaskState.Successful && (
|
||||
<GridCard
|
||||
widget={celerySuccessStateData}
|
||||
widget={celerySuccessStateFilteredData}
|
||||
headerMenuList={[...ViewMenuAction]}
|
||||
onDragSelect={onDragSelect}
|
||||
isQueryEnabled={queryEnabled}
|
||||
|
@ -117,7 +117,7 @@
|
||||
|
||||
.metric-page-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 50% 50%;
|
||||
grid-template-columns: 30% 19%;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
width: 100%;
|
||||
@ -144,6 +144,11 @@
|
||||
gap: 16px;
|
||||
align-items: center;
|
||||
|
||||
border: 1px dashed var(--bg-slate-50);
|
||||
border-radius: 4px;
|
||||
padding: 6px 24px 6px 12px;
|
||||
width: max-content;
|
||||
|
||||
.configure-option-Info-text {
|
||||
color: var(--bg-vanilla-400);
|
||||
font-size: 12px;
|
||||
@ -241,11 +246,13 @@
|
||||
|
||||
.lightMode {
|
||||
.celery-task-graph-grid-container {
|
||||
.celery-task-graph-grid {
|
||||
.celery-task-graph-worker-count {
|
||||
border: 1px solid var(--bg-vanilla-300);
|
||||
background: unset;
|
||||
}
|
||||
.celery-task-graph-worker-count {
|
||||
border: 1px solid var(--bg-vanilla-300);
|
||||
background: unset;
|
||||
}
|
||||
|
||||
.row-panel .row-panel-section .section-title {
|
||||
color: var(--bg-ink-400);
|
||||
}
|
||||
}
|
||||
|
||||
@ -274,4 +281,8 @@
|
||||
background-color: var(--bg-ink-400);
|
||||
}
|
||||
}
|
||||
|
||||
.configure-option-Info {
|
||||
border: 1px dashed var(--bg-robin-400);
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,9 @@ function CeleryTaskGraph({
|
||||
openTracesButton,
|
||||
onOpenTraceBtnClick,
|
||||
applyCeleryTaskFilter,
|
||||
customErrorMessage,
|
||||
start,
|
||||
end,
|
||||
}: {
|
||||
widgetData: Widgets;
|
||||
onClick?: (task: CaptureDataProps) => void;
|
||||
@ -42,6 +45,9 @@ function CeleryTaskGraph({
|
||||
openTracesButton?: boolean;
|
||||
onOpenTraceBtnClick?: (record: RowData) => void;
|
||||
applyCeleryTaskFilter?: boolean;
|
||||
customErrorMessage?: string;
|
||||
start?: number;
|
||||
end?: number;
|
||||
}): JSX.Element {
|
||||
const history = useHistory();
|
||||
const { pathname } = useLocation();
|
||||
@ -116,6 +122,9 @@ function CeleryTaskGraph({
|
||||
openTracesButton={openTracesButton}
|
||||
onOpenTraceBtnClick={onOpenTraceBtnClick}
|
||||
version={ENTITY_VERSION_V4}
|
||||
customErrorMessage={customErrorMessage}
|
||||
start={start}
|
||||
end={end}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
@ -129,6 +138,9 @@ CeleryTaskGraph.defaultProps = {
|
||||
openTracesButton: false,
|
||||
onOpenTraceBtnClick: undefined,
|
||||
applyCeleryTaskFilter: false,
|
||||
customErrorMessage: undefined,
|
||||
start: undefined,
|
||||
end: undefined,
|
||||
};
|
||||
|
||||
export default CeleryTaskGraph;
|
||||
|
@ -123,11 +123,12 @@ export default function CeleryTaskGraphGrid({
|
||||
key={celeryActiveTasksData.id}
|
||||
widgetData={celeryActiveTasksData}
|
||||
queryEnabled={queryEnabled}
|
||||
customErrorMessage="Enable Flower metrics to view this graph"
|
||||
/>
|
||||
<Card className="celery-task-graph-worker-count">
|
||||
<div className="worker-count-header">
|
||||
<Typography.Text className="worker-count-header-text">
|
||||
Worker Count
|
||||
Worker Online
|
||||
</Typography.Text>
|
||||
</div>
|
||||
<div className="worker-count-text-container">
|
||||
@ -173,7 +174,7 @@ export default function CeleryTaskGraphGrid({
|
||||
{!collapsedSections.traceBasedGraphs && (
|
||||
<>
|
||||
<CeleryTaskBar queryEnabled={queryEnabled} onClick={onClick} />
|
||||
<CeleryTaskLatencyGraph onClick={onClick} queryEnabled={queryEnabled} />
|
||||
<CeleryTaskLatencyGraph queryEnabled={queryEnabled} />
|
||||
<div className="celery-task-graph-grid-bottom">
|
||||
{bottomWidgetData.map((widgetData, index) => (
|
||||
<CeleryTaskGraph
|
||||
|
@ -42,21 +42,7 @@ export const celeryAllStateWidgetData = (
|
||||
disabled: false,
|
||||
expression: 'A',
|
||||
filters: {
|
||||
items: [
|
||||
{
|
||||
id: uuidv4(),
|
||||
key: {
|
||||
dataType: DataTypes.String,
|
||||
id: 'celery.task_name--string--tag--false',
|
||||
isColumn: false,
|
||||
isJSON: false,
|
||||
key: 'celery.task_name',
|
||||
type: 'tag',
|
||||
},
|
||||
op: '=',
|
||||
value: 'tasks.tasks.divide',
|
||||
},
|
||||
],
|
||||
items: [],
|
||||
op: 'AND',
|
||||
},
|
||||
functions: [],
|
||||
@ -113,7 +99,7 @@ export const celeryRetryStateWidgetData = (
|
||||
filters: {
|
||||
items: [
|
||||
{
|
||||
id: '6d97eed3',
|
||||
id: uuidv4(),
|
||||
key: {
|
||||
dataType: DataTypes.String,
|
||||
id: 'celery.state--string--tag--false',
|
||||
@ -179,7 +165,7 @@ export const celeryFailedStateWidgetData = (
|
||||
filters: {
|
||||
items: [
|
||||
{
|
||||
id: '5983eae2',
|
||||
id: uuidv4(),
|
||||
key: {
|
||||
dataType: DataTypes.String,
|
||||
id: 'celery.state--string--tag--false',
|
||||
@ -245,7 +231,7 @@ export const celerySuccessStateWidgetData = (
|
||||
filters: {
|
||||
items: [
|
||||
{
|
||||
id: '000c5a93',
|
||||
id: uuidv4(),
|
||||
key: {
|
||||
dataType: DataTypes.String,
|
||||
id: 'celery.state--string--tag--false',
|
||||
@ -602,7 +588,7 @@ export const celeryTaskLatencyWidgetData = (
|
||||
reduceTo: 'avg',
|
||||
spaceAggregation: 'sum',
|
||||
stepInterval: getStepInterval(startTime, endTime),
|
||||
timeAggregation: 'p99',
|
||||
timeAggregation: type || 'p99',
|
||||
},
|
||||
],
|
||||
yAxisUnit: 'ns',
|
||||
@ -686,7 +672,7 @@ export const celeryRetryTasksTableWidgetData = getWidgetQueryBuilder(
|
||||
filters: {
|
||||
items: [
|
||||
{
|
||||
id: '9e09c9ed',
|
||||
id: uuidv4(),
|
||||
key: {
|
||||
dataType: DataTypes.String,
|
||||
id: 'celery.state--string--tag--false',
|
||||
@ -755,7 +741,7 @@ export const celeryFailedTasksTableWidgetData = getWidgetQueryBuilder(
|
||||
filters: {
|
||||
items: [
|
||||
{
|
||||
id: '2330f906',
|
||||
id: uuidv4(),
|
||||
key: {
|
||||
dataType: DataTypes.String,
|
||||
id: 'celery.state--string--tag--false',
|
||||
@ -822,7 +808,7 @@ export const celerySuccessTasksTableWidgetData = getWidgetQueryBuilder(
|
||||
filters: {
|
||||
items: [
|
||||
{
|
||||
id: 'ec3df7b7',
|
||||
id: uuidv4(),
|
||||
key: {
|
||||
dataType: DataTypes.String,
|
||||
id: 'celery.state--string--tag--false',
|
||||
@ -945,33 +931,19 @@ export const celeryAllStateCountWidgetData = getWidgetQueryBuilder(
|
||||
queryData: [
|
||||
{
|
||||
aggregateAttribute: {
|
||||
dataType: DataTypes.EMPTY,
|
||||
id: '------false',
|
||||
isColumn: false,
|
||||
dataType: DataTypes.String,
|
||||
id: 'span_id--string----true',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
key: '',
|
||||
key: 'span_id',
|
||||
type: '',
|
||||
},
|
||||
aggregateOperator: 'count',
|
||||
aggregateOperator: 'count_distinct',
|
||||
dataSource: DataSource.TRACES,
|
||||
disabled: false,
|
||||
expression: 'A',
|
||||
filters: {
|
||||
items: [
|
||||
{
|
||||
id: uuidv4(),
|
||||
key: {
|
||||
dataType: DataTypes.String,
|
||||
id: 'celery.task_name--string--tag--false',
|
||||
isColumn: false,
|
||||
isJSON: false,
|
||||
key: 'celery.task_name',
|
||||
type: 'tag',
|
||||
},
|
||||
op: '=',
|
||||
value: 'tasks.tasks.divide',
|
||||
},
|
||||
],
|
||||
items: [],
|
||||
op: 'AND',
|
||||
},
|
||||
functions: [],
|
||||
@ -981,10 +953,10 @@ export const celeryAllStateCountWidgetData = getWidgetQueryBuilder(
|
||||
limit: null,
|
||||
orderBy: [],
|
||||
queryName: 'A',
|
||||
reduceTo: 'avg',
|
||||
reduceTo: 'last',
|
||||
spaceAggregation: 'sum',
|
||||
stepInterval: 60,
|
||||
timeAggregation: 'rate',
|
||||
timeAggregation: 'count_distinct',
|
||||
},
|
||||
],
|
||||
}),
|
||||
@ -998,14 +970,14 @@ export const celerySuccessStateCountWidgetData = getWidgetQueryBuilder(
|
||||
queryData: [
|
||||
{
|
||||
aggregateAttribute: {
|
||||
dataType: DataTypes.EMPTY,
|
||||
id: '------false',
|
||||
isColumn: false,
|
||||
dataType: DataTypes.String,
|
||||
id: 'span_id--string----true',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
key: '',
|
||||
key: 'span_id',
|
||||
type: '',
|
||||
},
|
||||
aggregateOperator: 'count',
|
||||
aggregateOperator: 'count_distinct',
|
||||
dataSource: DataSource.TRACES,
|
||||
disabled: false,
|
||||
expression: 'A',
|
||||
@ -1034,10 +1006,10 @@ export const celerySuccessStateCountWidgetData = getWidgetQueryBuilder(
|
||||
limit: null,
|
||||
orderBy: [],
|
||||
queryName: 'A',
|
||||
reduceTo: 'avg',
|
||||
reduceTo: 'last',
|
||||
spaceAggregation: 'sum',
|
||||
stepInterval: 60,
|
||||
timeAggregation: 'rate',
|
||||
timeAggregation: 'count_distinct',
|
||||
},
|
||||
],
|
||||
}),
|
||||
@ -1051,14 +1023,14 @@ export const celeryFailedStateCountWidgetData = getWidgetQueryBuilder(
|
||||
queryData: [
|
||||
{
|
||||
aggregateAttribute: {
|
||||
dataType: DataTypes.EMPTY,
|
||||
id: '------false',
|
||||
isColumn: false,
|
||||
dataType: DataTypes.String,
|
||||
id: 'span_id--string----true',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
key: '',
|
||||
key: 'span_id',
|
||||
type: '',
|
||||
},
|
||||
aggregateOperator: 'count',
|
||||
aggregateOperator: 'count_distinct',
|
||||
dataSource: DataSource.TRACES,
|
||||
disabled: false,
|
||||
expression: 'A',
|
||||
@ -1087,10 +1059,10 @@ export const celeryFailedStateCountWidgetData = getWidgetQueryBuilder(
|
||||
limit: null,
|
||||
orderBy: [],
|
||||
queryName: 'A',
|
||||
reduceTo: 'avg',
|
||||
reduceTo: 'last',
|
||||
spaceAggregation: 'sum',
|
||||
stepInterval: 60,
|
||||
timeAggregation: 'rate',
|
||||
timeAggregation: 'count_distinct',
|
||||
},
|
||||
],
|
||||
}),
|
||||
@ -1104,13 +1076,13 @@ export const celeryRetryStateCountWidgetData = getWidgetQueryBuilder(
|
||||
queryData: [
|
||||
{
|
||||
aggregateAttribute: {
|
||||
dataType: DataTypes.EMPTY,
|
||||
id: '------false',
|
||||
isColumn: false,
|
||||
key: '',
|
||||
dataType: DataTypes.String,
|
||||
id: 'span_id--string----true',
|
||||
isColumn: true,
|
||||
key: 'span_id',
|
||||
type: '',
|
||||
},
|
||||
aggregateOperator: 'count',
|
||||
aggregateOperator: 'count_distinct',
|
||||
dataSource: DataSource.TRACES,
|
||||
disabled: false,
|
||||
expression: 'A',
|
||||
@ -1139,10 +1111,10 @@ export const celeryRetryStateCountWidgetData = getWidgetQueryBuilder(
|
||||
limit: null,
|
||||
orderBy: [],
|
||||
queryName: 'A',
|
||||
reduceTo: 'avg',
|
||||
reduceTo: 'last',
|
||||
spaceAggregation: 'sum',
|
||||
stepInterval: 60,
|
||||
timeAggregation: 'rate',
|
||||
timeAggregation: 'count_distinct',
|
||||
},
|
||||
],
|
||||
}),
|
||||
|
@ -6,8 +6,11 @@ import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { ViewMenuAction } from 'container/GridCardLayout/config';
|
||||
import GridCard from 'container/GridCardLayout/GridCard';
|
||||
import { Card } from 'container/GridCardLayout/styles';
|
||||
import { Button } from 'container/MetricsApplication/Tabs/styles';
|
||||
import { onGraphClickHandler } from 'container/MetricsApplication/Tabs/util';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { OnClickPluginOpts } from 'lib/uPlotLib/plugins/onClickPlugin';
|
||||
import { getStartAndEndTimesInMilliseconds } from 'pages/MessagingQueues/MessagingQueuesUtils';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
@ -16,15 +19,13 @@ import { UpdateTimeInterval } from 'store/actions';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
|
||||
import { CaptureDataProps } from '../CeleryTaskDetail/CeleryTaskDetail';
|
||||
import {
|
||||
applyCeleryFilterOnWidgetData,
|
||||
createFiltersFromData,
|
||||
getFiltersFromQueryParams,
|
||||
} from '../CeleryUtils';
|
||||
import {
|
||||
celeryTaskLatencyWidgetData,
|
||||
celeryTimeSeriesTablesWidgetData,
|
||||
} from './CeleryTaskGraphUtils';
|
||||
import { useNavigateToTraces } from '../useNavigateToTraces';
|
||||
import { celeryTaskLatencyWidgetData } from './CeleryTaskGraphUtils';
|
||||
|
||||
interface TabData {
|
||||
label: string;
|
||||
@ -38,10 +39,8 @@ export enum CeleryTaskGraphState {
|
||||
}
|
||||
|
||||
function CeleryTaskLatencyGraph({
|
||||
onClick,
|
||||
queryEnabled,
|
||||
}: {
|
||||
onClick: (task: CaptureDataProps) => void;
|
||||
queryEnabled: boolean;
|
||||
}): JSX.Element {
|
||||
const history = useHistory();
|
||||
@ -106,31 +105,51 @@ function CeleryTaskLatencyGraph({
|
||||
[celeryTaskLatencyData, selectedFilters],
|
||||
);
|
||||
|
||||
const onGraphClick = (
|
||||
xValue: number,
|
||||
_yValue: number,
|
||||
_mouseX: number,
|
||||
_mouseY: number,
|
||||
data?: {
|
||||
[key: string]: string;
|
||||
const [selectedTimeStamp, setSelectedTimeStamp] = useState<number>(0);
|
||||
const [entityData, setEntityData] = useState<{
|
||||
entity: string;
|
||||
value: string;
|
||||
}>();
|
||||
|
||||
const handleSetTimeStamp = useCallback((selectTime: number) => {
|
||||
setSelectedTimeStamp(selectTime);
|
||||
}, []);
|
||||
|
||||
const onGraphClick = useCallback(
|
||||
(type: string): OnClickPluginOpts['onClick'] => (
|
||||
xValue,
|
||||
yValue,
|
||||
mouseX,
|
||||
mouseY,
|
||||
data,
|
||||
): Promise<void> => {
|
||||
const [firstDataPoint] = Object.entries(data || {});
|
||||
const [entity, value] = firstDataPoint;
|
||||
setEntityData({
|
||||
entity,
|
||||
value,
|
||||
});
|
||||
|
||||
return onGraphClickHandler(handleSetTimeStamp)(
|
||||
xValue,
|
||||
yValue,
|
||||
mouseX,
|
||||
mouseY,
|
||||
type,
|
||||
);
|
||||
},
|
||||
): void => {
|
||||
const { start, end } = getStartAndEndTimesInMilliseconds(xValue);
|
||||
[handleSetTimeStamp],
|
||||
);
|
||||
|
||||
// Extract entity and value from data
|
||||
const [firstDataPoint] = Object.entries(data || {});
|
||||
const [entity, value] = (firstDataPoint || ([] as unknown)) as [
|
||||
string,
|
||||
string,
|
||||
];
|
||||
const navigateToTraces = useNavigateToTraces();
|
||||
|
||||
onClick?.({
|
||||
entity,
|
||||
value,
|
||||
timeRange: [start, end],
|
||||
widgetData: celeryTimeSeriesTablesWidgetData(entity, value, 'Task Latency'),
|
||||
const goToTraces = useCallback(() => {
|
||||
const { start, end } = getStartAndEndTimesInMilliseconds(selectedTimeStamp);
|
||||
const filters = createFiltersFromData({
|
||||
[entityData?.entity as string]: entityData?.value,
|
||||
});
|
||||
};
|
||||
navigateToTraces(filters, start, end, true);
|
||||
}, [entityData, navigateToTraces, selectedTimeStamp]);
|
||||
|
||||
return (
|
||||
<Card
|
||||
@ -161,32 +180,62 @@ function CeleryTaskLatencyGraph({
|
||||
</Row>
|
||||
<div className="celery-task-graph-grid-content">
|
||||
{graphState === CeleryTaskGraphState.P99 && (
|
||||
<GridCard
|
||||
widget={updatedWidgetData}
|
||||
headerMenuList={[...ViewMenuAction]}
|
||||
onDragSelect={onDragSelect}
|
||||
onClickHandler={onGraphClick}
|
||||
isQueryEnabled={queryEnabled}
|
||||
/>
|
||||
<>
|
||||
<Button
|
||||
type="default"
|
||||
size="small"
|
||||
id="Celery_p99_latency_button"
|
||||
onClick={goToTraces}
|
||||
>
|
||||
View Traces
|
||||
</Button>
|
||||
<GridCard
|
||||
widget={updatedWidgetData}
|
||||
headerMenuList={[...ViewMenuAction]}
|
||||
onDragSelect={onDragSelect}
|
||||
onClickHandler={onGraphClick('Celery_p99_latency')}
|
||||
isQueryEnabled={queryEnabled}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{graphState === CeleryTaskGraphState.P95 && (
|
||||
<GridCard
|
||||
widget={updatedWidgetData}
|
||||
headerMenuList={[...ViewMenuAction]}
|
||||
onDragSelect={onDragSelect}
|
||||
onClickHandler={onGraphClick}
|
||||
isQueryEnabled={queryEnabled}
|
||||
/>
|
||||
<>
|
||||
<Button
|
||||
type="default"
|
||||
size="small"
|
||||
id="Celery_p95_latency_button"
|
||||
onClick={goToTraces}
|
||||
>
|
||||
View Traces
|
||||
</Button>
|
||||
<GridCard
|
||||
widget={updatedWidgetData}
|
||||
headerMenuList={[...ViewMenuAction]}
|
||||
onDragSelect={onDragSelect}
|
||||
onClickHandler={onGraphClick('Celery_p95_latency')}
|
||||
isQueryEnabled={queryEnabled}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{graphState === CeleryTaskGraphState.P90 && (
|
||||
<GridCard
|
||||
widget={updatedWidgetData}
|
||||
headerMenuList={[...ViewMenuAction]}
|
||||
onDragSelect={onDragSelect}
|
||||
onClickHandler={onGraphClick}
|
||||
isQueryEnabled={queryEnabled}
|
||||
/>
|
||||
<>
|
||||
<Button
|
||||
type="default"
|
||||
size="small"
|
||||
id="Celery_p90_latency_button"
|
||||
onClick={goToTraces}
|
||||
>
|
||||
View Traces
|
||||
</Button>
|
||||
<GridCard
|
||||
widget={updatedWidgetData}
|
||||
headerMenuList={[...ViewMenuAction]}
|
||||
onDragSelect={onDragSelect}
|
||||
onClickHandler={onGraphClick('Celery_p90_latency')}
|
||||
isQueryEnabled={queryEnabled}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
|
@ -2,8 +2,14 @@
|
||||
import './CeleryTaskGraph.style.scss';
|
||||
|
||||
import { Col, Row } from 'antd';
|
||||
import { Dispatch, SetStateAction } from 'react';
|
||||
import { QueryParams } from 'constants/query';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { Dispatch, SetStateAction, useMemo } from 'react';
|
||||
|
||||
import {
|
||||
applyCeleryFilterOnWidgetData,
|
||||
getFiltersFromQueryParams,
|
||||
} from '../CeleryUtils';
|
||||
import {
|
||||
celeryAllStateCountWidgetData,
|
||||
celeryFailedStateCountWidgetData,
|
||||
@ -42,16 +48,29 @@ function CeleryTaskStateGraphConfig({
|
||||
setBarState(key as CeleryTaskState);
|
||||
};
|
||||
|
||||
const { values, isLoading, isError } = useGetValueFromWidget(
|
||||
[
|
||||
celeryAllStateCountWidgetData,
|
||||
celeryFailedStateCountWidgetData,
|
||||
celeryRetryStateCountWidgetData,
|
||||
celerySuccessStateCountWidgetData,
|
||||
],
|
||||
['celery-task-states'],
|
||||
const urlQuery = useUrlQuery();
|
||||
|
||||
const selectedFilters = useMemo(
|
||||
() =>
|
||||
getFiltersFromQueryParams(
|
||||
QueryParams.taskName,
|
||||
urlQuery,
|
||||
'celery.task_name',
|
||||
),
|
||||
[urlQuery],
|
||||
);
|
||||
|
||||
const widgetData = [
|
||||
celeryAllStateCountWidgetData,
|
||||
celeryFailedStateCountWidgetData,
|
||||
celeryRetryStateCountWidgetData,
|
||||
celerySuccessStateCountWidgetData,
|
||||
].map((data) => applyCeleryFilterOnWidgetData(selectedFilters || [], data));
|
||||
|
||||
const { values, isLoading, isError } = useGetValueFromWidget(widgetData, [
|
||||
'celery-task-states',
|
||||
]);
|
||||
|
||||
return (
|
||||
<Row className="celery-task-states">
|
||||
{tabs.map((tab, index) => (
|
||||
@ -66,7 +85,13 @@ function CeleryTaskStateGraphConfig({
|
||||
<div className="celery-task-states__label-wrapper">
|
||||
<div className="celery-task-states__label">{tab.label}</div>
|
||||
<div className="celery-task-states__value">
|
||||
{isLoading ? '-' : isError ? '-' : values[index]}
|
||||
{isLoading
|
||||
? '-'
|
||||
: isError
|
||||
? '-'
|
||||
: Number.isNaN(values[index])
|
||||
? '-'
|
||||
: Math.round(Number(values[index]))}
|
||||
</div>
|
||||
</div>
|
||||
{tab.key === barState && <div className="celery-task-states__indicator" />}
|
||||
|
@ -90,3 +90,40 @@ export const paths = (
|
||||
|
||||
return renderer(u, seriesIdx, idx0, idx1, extendGap, buildClip);
|
||||
};
|
||||
|
||||
export const createFiltersFromData = (
|
||||
data: Record<string, any>,
|
||||
): Array<{
|
||||
id: string;
|
||||
key: {
|
||||
key: string;
|
||||
dataType: DataTypes;
|
||||
type: string;
|
||||
isColumn: boolean;
|
||||
isJSON: boolean;
|
||||
id: string;
|
||||
};
|
||||
op: string;
|
||||
value: string;
|
||||
}> => {
|
||||
const excludeKeys = ['A', 'A_without_unit'];
|
||||
|
||||
return (
|
||||
Object.entries(data)
|
||||
.filter(([key]) => !excludeKeys.includes(key))
|
||||
// eslint-disable-next-line sonarjs/no-identical-functions
|
||||
.map(([key, value]) => ({
|
||||
id: uuidv4(),
|
||||
key: {
|
||||
key,
|
||||
dataType: DataTypes.String,
|
||||
type: 'tag',
|
||||
isColumn: false,
|
||||
isJSON: false,
|
||||
id: `${key}--string--tag--false`,
|
||||
},
|
||||
op: '=',
|
||||
value: value.toString(),
|
||||
}))
|
||||
);
|
||||
};
|
||||
|
@ -12,6 +12,7 @@ export function useNavigateToTraces(): (
|
||||
filters: TagFilterItem[],
|
||||
startTime?: number,
|
||||
endTime?: number,
|
||||
sameTab?: boolean,
|
||||
) => void {
|
||||
const { currentQuery } = useQueryBuilder();
|
||||
const { minTime, maxTime } = useSelector<AppState, GlobalReducer>(
|
||||
@ -38,7 +39,12 @@ export function useNavigateToTraces(): (
|
||||
);
|
||||
|
||||
return useCallback(
|
||||
(filters: TagFilterItem[], startTime?: number, endTime?: number): void => {
|
||||
(
|
||||
filters: TagFilterItem[],
|
||||
startTime?: number,
|
||||
endTime?: number,
|
||||
sameTab?: boolean,
|
||||
): void => {
|
||||
const urlParams = new URLSearchParams();
|
||||
if (startTime && endTime) {
|
||||
urlParams.set(QueryParams.startTime, startTime.toString());
|
||||
@ -58,7 +64,7 @@ export function useNavigateToTraces(): (
|
||||
QueryParams.compositeQuery
|
||||
}=${JSONCompositeQuery}`;
|
||||
|
||||
window.open(newTraceExplorerPath, '_blank');
|
||||
window.open(newTraceExplorerPath, sameTab ? '_self' : '_blank');
|
||||
},
|
||||
[minTime, maxTime, prepareQuery],
|
||||
);
|
||||
|
@ -48,6 +48,7 @@ function WidgetGraphComponent({
|
||||
openTracesButton,
|
||||
onOpenTraceBtnClick,
|
||||
customSeries,
|
||||
customErrorMessage,
|
||||
}: WidgetGraphComponentProps): JSX.Element {
|
||||
const [deleteModal, setDeleteModal] = useState(false);
|
||||
const [hovered, setHovered] = useState(false);
|
||||
@ -317,6 +318,13 @@ function WidgetGraphComponent({
|
||||
setSearchTerm={setSearchTerm}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{queryResponse.error && customErrorMessage && (
|
||||
<div className="error-message-container">
|
||||
<Typography.Text type="warning">{customErrorMessage}</Typography.Text>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{queryResponse.isLoading && widget.panelTypes !== PANEL_TYPES.LIST && (
|
||||
<Skeleton />
|
||||
)}
|
||||
|
@ -41,9 +41,15 @@ function GridCardGraph({
|
||||
openTracesButton,
|
||||
onOpenTraceBtnClick,
|
||||
customSeries,
|
||||
customErrorMessage,
|
||||
start,
|
||||
end,
|
||||
}: GridCardGraphProps): JSX.Element {
|
||||
const dispatch = useDispatch();
|
||||
const [errorMessage, setErrorMessage] = useState<string>();
|
||||
const [isInternalServerError, setIsInternalServerError] = useState<boolean>(
|
||||
false,
|
||||
);
|
||||
const {
|
||||
toScrollWidgetId,
|
||||
setToScrollWidgetId,
|
||||
@ -178,6 +184,8 @@ function GridCardGraph({
|
||||
variables: getDashboardVariables(variables),
|
||||
selectedTime: widget.timePreferance || 'GLOBAL_TIME',
|
||||
globalSelectedInterval,
|
||||
start,
|
||||
end,
|
||||
},
|
||||
version || DEFAULT_ENTITY_VERSION,
|
||||
{
|
||||
@ -207,6 +215,11 @@ function GridCardGraph({
|
||||
refetchOnMount: false,
|
||||
onError: (error) => {
|
||||
setErrorMessage(error.message);
|
||||
if (customErrorMessage) {
|
||||
setIsInternalServerError(
|
||||
String(error.message).includes('API responded with 500'),
|
||||
);
|
||||
}
|
||||
setDashboardQueryRangeCalled(true);
|
||||
},
|
||||
onSettled: (data) => {
|
||||
@ -256,6 +269,7 @@ function GridCardGraph({
|
||||
openTracesButton={openTracesButton}
|
||||
onOpenTraceBtnClick={onOpenTraceBtnClick}
|
||||
customSeries={customSeries}
|
||||
customErrorMessage={isInternalServerError ? customErrorMessage : undefined}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
@ -37,6 +37,7 @@ export interface WidgetGraphComponentProps {
|
||||
openTracesButton?: boolean;
|
||||
onOpenTraceBtnClick?: (record: RowData) => void;
|
||||
customSeries?: (data: QueryData[]) => uPlot.Series[];
|
||||
customErrorMessage?: string;
|
||||
}
|
||||
|
||||
export interface GridCardGraphProps {
|
||||
@ -54,6 +55,9 @@ export interface GridCardGraphProps {
|
||||
openTracesButton?: boolean;
|
||||
onOpenTraceBtnClick?: (record: RowData) => void;
|
||||
customSeries?: (data: QueryData[]) => uPlot.Series[];
|
||||
customErrorMessage?: string;
|
||||
start?: number;
|
||||
end?: number;
|
||||
}
|
||||
|
||||
export interface GetGraphVisibilityStateOnLegendClickProps {
|
||||
|
@ -106,6 +106,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
.error-message-container {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-top: 0;
|
||||
padding-bottom: 32px;
|
||||
}
|
||||
|
||||
.row-settings {
|
||||
.ant-popover-inner {
|
||||
width: 191px;
|
||||
|
@ -23,7 +23,7 @@ export default function CeleryOverview(): JSX.Element {
|
||||
<p className="celery-overview-content-header-title">
|
||||
Messaging Queue Overview
|
||||
</p>
|
||||
<DateTimeSelectionV2 showAutoRefresh={false} hideShareModal />
|
||||
<DateTimeSelectionV2 showAutoRefresh hideShareModal={false} />
|
||||
</div>
|
||||
<CeleryOverviewConfigOptions />
|
||||
<CeleryOverviewTable onRowClick={onRowClick} />
|
||||
|
@ -1,16 +1,12 @@
|
||||
import './CeleryTask.styles.scss';
|
||||
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import { Button, Tooltip } from 'antd';
|
||||
import CeleryTaskConfigOptions from 'components/CeleryTask/CeleryTaskConfigOptions/CeleryTaskConfigOptions';
|
||||
import CeleryTaskDetail, {
|
||||
CaptureDataProps,
|
||||
} from 'components/CeleryTask/CeleryTaskDetail/CeleryTaskDetail';
|
||||
import CeleryTaskGraphGrid from 'components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphGrid';
|
||||
import DateTimeSelectionV2 from 'container/TopNav/DateTimeSelectionV2';
|
||||
import { Check, Share2 } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
import { useCopyToClipboard } from 'react-use';
|
||||
|
||||
export default function CeleryTask(): JSX.Element {
|
||||
const [task, setTask] = useState<CaptureDataProps | null>(null);
|
||||
@ -19,36 +15,13 @@ export default function CeleryTask(): JSX.Element {
|
||||
setTask(captureData);
|
||||
};
|
||||
|
||||
const [isURLCopied, setIsURLCopied] = useState(false);
|
||||
|
||||
const [, handleCopyToClipboard] = useCopyToClipboard();
|
||||
|
||||
return (
|
||||
<div className="celery-task-container">
|
||||
<div className="celery-content">
|
||||
<div className="celery-content-header">
|
||||
<p className="celery-content-header-title">Celery</p>
|
||||
<div className="celery-content-header-right">
|
||||
<DateTimeSelectionV2 showAutoRefresh={false} hideShareModal />
|
||||
<Tooltip title="Share this" arrow={false}>
|
||||
<Button
|
||||
className="periscope-btn copy-url-btn"
|
||||
onClick={(): void => {
|
||||
handleCopyToClipboard(window.location.href);
|
||||
setIsURLCopied(true);
|
||||
setTimeout(() => {
|
||||
setIsURLCopied(false);
|
||||
}, 1000);
|
||||
}}
|
||||
icon={
|
||||
isURLCopied ? (
|
||||
<Check size={14} color={Color.BG_FOREST_500} />
|
||||
) : (
|
||||
<Share2 size={14} />
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
<DateTimeSelectionV2 showAutoRefresh hideShareModal={false} />
|
||||
</div>
|
||||
</div>
|
||||
<CeleryTaskGraphGrid
|
||||
|
Loading…
x
Reference in New Issue
Block a user