diff --git a/frontend/src/components/CeleryTask/CeleryTaskDetail/CeleryTaskDetail.style.scss b/frontend/src/components/CeleryTask/CeleryTaskDetail/CeleryTaskDetail.style.scss
index 28168f71c6..7275b00cfb 100644
--- a/frontend/src/components/CeleryTask/CeleryTaskDetail/CeleryTaskDetail.style.scss
+++ b/frontend/src/components/CeleryTask/CeleryTaskDetail/CeleryTaskDetail.style.scss
@@ -1,5 +1,74 @@
.celery-task-detail-drawer {
+ .ant-drawer-wrapper-body {
+ background: var(--bg-ink-500);
+ border: 1px solid var(--bg-ink-300);
+ }
+
.ant-drawer-body {
padding: 0px;
+
+ .ant-card {
+ border: none;
+ .ant-card-body {
+ height: 100%;
+ background: var(--bg-ink-500);
+
+ .ant-table {
+ background: var(--bg-ink-500);
+ }
+ }
+ }
+ }
+
+ .ant-drawer-header {
+ border-bottom: 1px solid var(--bg-ink-300);
+ .ant-drawer-header-title {
+ .ant-drawer-close {
+ position: absolute;
+ right: 0;
+ }
+
+ button > svg {
+ color: var(--bg-vanilla-100);
+ }
+
+ .ant-drawer-title {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+
+ .title {
+ color: var(--bg-vanilla-100);
+ font-family: Inter;
+ font-size: 18px;
+ font-style: normal;
+ font-weight: 600;
+ line-height: 18px;
+ letter-spacing: -0.45px;
+ }
+
+ .subtitle {
+ color: var(--bg-vanilla-400);
+ font-family: Inter;
+ font-size: 12px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 20px;
+ }
+ }
+ }
+ }
+
+ .ant-drawer-footer {
+ border-top: 1px solid var(--bg-ink-300);
+
+ .footer-text {
+ color: var(--bg-vanilla-400);
+ font-family: Inter;
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 20px;
+ }
}
}
diff --git a/frontend/src/components/CeleryTask/CeleryTaskDetail/CeleryTaskDetail.tsx b/frontend/src/components/CeleryTask/CeleryTaskDetail/CeleryTaskDetail.tsx
index 253b12d118..7d3e47e4e4 100644
--- a/frontend/src/components/CeleryTask/CeleryTaskDetail/CeleryTaskDetail.tsx
+++ b/frontend/src/components/CeleryTask/CeleryTaskDetail/CeleryTaskDetail.tsx
@@ -2,43 +2,126 @@ import './CeleryTaskDetail.style.scss';
import { Color, Spacing } from '@signozhq/design-tokens';
import { Divider, Drawer, Typography } from 'antd';
+import { QueryParams } from 'constants/query';
+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 { Widgets } from 'types/api/dashboard/getAll';
+import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
+import { GlobalReducer } from 'types/reducer/globalTime';
import CeleryTaskGraph from '../CeleryTaskGraph/CeleryTaskGraph';
-import { celerySlowestTasksTableWidgetData } from '../CeleryTaskGraph/CeleryTaskGraphUtils';
export type CeleryTaskData = {
- taskName: string;
- taskId: string;
- taskStatus: string;
- taskCreatedAt: string;
- taskCompletedAt: string;
+ entity: string;
+ value: string | number;
+ timeRange: [number, number];
};
export type CeleryTaskDetailProps = {
- task: CeleryTaskData | null;
onClose: () => void;
+ mainTitle: string;
+ widgetData: Widgets;
+ taskData: CeleryTaskData;
+ drawerOpen: boolean;
};
export default function CeleryTaskDetail({
- task,
+ mainTitle,
+ widgetData,
+ taskData,
onClose,
+ drawerOpen,
}: CeleryTaskDetailProps): JSX.Element {
const isDarkMode = useIsDarkMode();
+ const shouldShowDrawer =
+ !!taskData.entity && !!taskData.timeRange[0] && drawerOpen;
+
+ const formatTimestamp = (timestamp: number): string =>
+ dayjs(timestamp * 1000).format('MM-DD-YYYY hh:mm A');
+
+ const [totalTask, setTotalTask] = useState(0);
+
+ const getGraphData = (graphData?: MetricRangePayloadProps['data']): void => {
+ console.log(graphData);
+ 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, maxTime]));
+ urlQuery.set(QueryParams.startTime, minTime.toString());
+ urlQuery.set(QueryParams.endTime, maxTime.toString());
+ }
+
+ const generatedUrl = `${location.pathname}?${urlQuery.toString()}`;
+ history.replace(generatedUrl);
+ };
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
return (
-
- {task?.taskName}
- >
+
+
{mainTitle}
+
+
+ {`${formatTimestamp(taskData.timeRange[0])} ${
+ taskData.timeRange[1]
+ ? `- ${formatTimestamp(taskData.timeRange[1])}`
+ : ''
+ }`}
+
+
+
task-details
+
+
}
placement="right"
onClose={onClose}
- open={!!task}
+ open={shouldShowDrawer}
style={{
overscrollBehavior: 'contain',
background: isDarkMode ? Color.BG_INK_400 : Color.BG_VANILLA_100,
@@ -46,13 +129,16 @@ export default function CeleryTaskDetail({
className="celery-task-detail-drawer"
destroyOnClose
closeIcon={}
+ footer={
+ {`Total Task: ${totalTask}`}
+ }
>
- {task && (
- {}}
- />
- )}
+ {}}
+ getGraphData={getGraphData}
+ queryEnabled
+ />
);
}
diff --git a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraph.style.scss b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraph.style.scss
index c2851fe269..9d86eb5e35 100644
--- a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraph.style.scss
+++ b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraph.style.scss
@@ -8,7 +8,7 @@
.celery-task-graph-grid {
display: grid;
- grid-template-columns: repeat(2, 1fr);
+ grid-template-columns: 60% 40%;
align-items: flex-start;
gap: 10px;
width: 100%;
@@ -23,8 +23,29 @@
height: calc(100% - 24px);
.widget-graph-container {
- &.bar {
- height: calc(100% - 116px);
+ &.histogram {
+ height: calc(100% - 85px);
+ }
+ }
+ }
+ }
+
+ .celery-task-graph-histogram {
+ height: 380px !important;
+ width: 100%;
+ box-sizing: border-box;
+
+ .celery-task-graph-grid-content {
+ padding: 6px;
+ height: 100%;
+ }
+
+ .ant-card-body {
+ height: calc(100% - 18px);
+
+ .widget-graph-container {
+ &.histogram {
+ height: calc(100% - 85px);
}
}
}
diff --git a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraph.tsx b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraph.tsx
index 754015e351..09a84a9baf 100644
--- a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraph.tsx
+++ b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraph.tsx
@@ -10,16 +10,20 @@ import { useDispatch } from 'react-redux';
import { useHistory, useLocation } from 'react-router-dom';
import { UpdateTimeInterval } from 'store/actions';
import { Widgets } from 'types/api/dashboard/getAll';
+import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
import { CeleryTaskData } from '../CeleryTaskDetail/CeleryTaskDetail';
-import { CeleryTaskGraphStates } from './CeleryTaskGraphStates';
function CeleryTaskGraph({
widgetData,
onClick,
+ getGraphData,
+ queryEnabled,
}: {
widgetData: Widgets;
onClick: (task: CeleryTaskData) => void;
+ getGraphData?: (graphData?: MetricRangePayloadProps['data']) => void;
+ queryEnabled: boolean;
}): JSX.Element {
const history = useHistory();
const { pathname } = useLocation();
@@ -50,7 +54,6 @@ function CeleryTaskGraph({
$panelType={PANEL_TYPES.TIME_SERIES}
className="celery-task-graph"
>
- {widgetData.title === 'All' && }
);
}
+CeleryTaskGraph.defaultProps = {
+ getGraphData: undefined,
+};
+
export default CeleryTaskGraph;
diff --git a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphGrid.tsx b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphGrid.tsx
index 803880e7ce..1ad8a299e4 100644
--- a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphGrid.tsx
+++ b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphGrid.tsx
@@ -4,26 +4,21 @@ import { CeleryTaskData } from '../CeleryTaskDetail/CeleryTaskDetail';
import CeleryTaskGraph from './CeleryTaskGraph';
import {
celeryActiveTasksWidgetData,
- celeryAllStateWidgetData,
celeryErrorByWorkerWidgetData,
celeryLatencyByWorkerWidgetData,
celeryTaskLatencyWidgetData,
celeryTasksByWorkerWidgetData,
celeryWorkerOnlineWidgetData,
} from './CeleryTaskGraphUtils';
+import CeleryTaskHistogram from './CeleryTaskHistogram';
export default function CeleryTaskGraphGrid({
onClick,
+ queryEnabled,
}: {
onClick: (task: CeleryTaskData) => void;
+ queryEnabled: boolean;
}): JSX.Element {
- const widgetData = [
- celeryActiveTasksWidgetData,
- celeryWorkerOnlineWidgetData,
- celeryAllStateWidgetData,
- celeryTaskLatencyWidgetData,
- ];
-
const bottomWidgetData = [
celeryTasksByWorkerWidgetData,
celeryErrorByWorkerWidgetData,
@@ -33,13 +28,36 @@ export default function CeleryTaskGraphGrid({
return (
- {widgetData.map((widget) => (
-
- ))}
+
+
+
+
+
+
- {bottomWidgetData.map((widget) => (
-
+ {bottomWidgetData.map((widgetData) => (
+
))}
diff --git a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphStates.tsx b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphStates.tsx
deleted file mode 100644
index dadfb82f3c..0000000000
--- a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphStates.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import './CeleryTaskGraph.style.scss';
-
-import { Col, Row } from 'antd';
-import { useState } from 'react';
-
-interface TabData {
- label: string;
- value: number;
- key: string;
-}
-
-function CeleryTaskGraphStates(): JSX.Element {
- const [selectedTab, setSelectedTab] = useState('all');
-
- const tabs: TabData[] = [
- { label: 'All Tasks', value: 1097, key: 'all' },
- { label: 'Failed', value: 11, key: 'failed' },
- { label: 'Pending', value: 59, key: 'pending' },
- { label: 'Successful', value: 1027, key: 'successful' },
- ];
-
- const handleTabClick = (key: string): void => {
- setSelectedTab(key);
- };
-
- return (
-
- {tabs.map((tab, index) => (
- handleTabClick(tab.key)}
- className={`celery-task-states__tab ${
- tab.key === selectedTab ? 'celery-task-states__tab--selected' : ''
- }`}
- data-last-tab={index === tabs.length - 1}
- >
-
-
- {tab.key === selectedTab && (
-
- )}
-
- ))}
-
- );
-}
-
-export { CeleryTaskGraphStates };
diff --git a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphUtils.ts b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphUtils.ts
index b10cd8c60e..5d275475c6 100644
--- a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphUtils.ts
+++ b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphUtils.ts
@@ -1,10 +1,14 @@
/* eslint-disable sonarjs/no-duplicate-string */
import { PANEL_TYPES } from 'constants/queryBuilder';
import { getWidgetQueryBuilder } from 'container/MetricsApplication/MetricsApplication.factory';
+// import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
import { getWidgetQuery } from 'pages/MessagingQueues/MQDetails/MetricPage/MetricPageUtil';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
+// import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
+// import { v4 as uuidv4 } from 'uuid';
+// State Graphs
export const celeryAllStateWidgetData = getWidgetQueryBuilder(
getWidgetQuery({
queryData: [
@@ -64,7 +68,192 @@ export const celeryAllStateWidgetData = getWidgetQueryBuilder(
title: 'All',
description:
'Represents all states of task, including success, failed, and retry.',
- panelTypes: PANEL_TYPES.BAR, // todo-sagar: ask shivanshu if BAR or Histogram
+ panelTypes: PANEL_TYPES.HISTOGRAM,
+ }),
+);
+
+export const celeryRetryStateWidgetData = getWidgetQueryBuilder(
+ getWidgetQuery({
+ title: 'Retry',
+ description: 'Represents the number of retry tasks.',
+ panelTypes: PANEL_TYPES.HISTOGRAM,
+ queryData: [
+ {
+ aggregateAttribute: {
+ dataType: DataTypes.String,
+ id: '------false',
+ isColumn: false,
+ key: '',
+ type: '',
+ },
+ aggregateOperator: 'count',
+ dataSource: DataSource.TRACES,
+ disabled: false,
+ expression: 'A',
+ filters: {
+ items: [
+ {
+ id: '6d97eed3',
+ key: {
+ dataType: DataTypes.String,
+ id: 'celery.state--string--tag--false',
+ isColumn: false,
+ isJSON: false,
+ key: 'celery.state',
+ type: 'tag',
+ },
+ op: '=',
+ value: 'RETRY',
+ },
+ ],
+ op: 'AND',
+ },
+ functions: [],
+ groupBy: [
+ {
+ dataType: DataTypes.String,
+ id: 'celery.hostname--string--tag--false',
+ isColumn: false,
+ isJSON: false,
+ key: 'celery.hostname',
+ type: 'tag',
+ },
+ ],
+ having: [],
+ legend: '',
+ limit: null,
+ orderBy: [],
+ queryName: 'A',
+ reduceTo: 'avg',
+ spaceAggregation: 'sum',
+ stepInterval: 60,
+ timeAggregation: 'count',
+ },
+ ],
+ }),
+);
+
+export const celeryFailedStateWidgetData = getWidgetQueryBuilder(
+ getWidgetQuery({
+ title: 'Failed',
+ description: 'Represents the number of failed tasks.',
+ panelTypes: PANEL_TYPES.HISTOGRAM,
+ queryData: [
+ {
+ aggregateAttribute: {
+ dataType: DataTypes.String,
+ id: '------false',
+ isColumn: false,
+ isJSON: false,
+ key: '',
+ type: '',
+ },
+ aggregateOperator: 'count',
+ dataSource: DataSource.TRACES,
+ disabled: false,
+ expression: 'A',
+ filters: {
+ items: [
+ {
+ id: '5983eae2',
+ key: {
+ dataType: DataTypes.String,
+ id: 'celery.state--string--tag--false',
+ isColumn: false,
+ isJSON: false,
+ key: 'celery.state',
+ type: 'tag',
+ },
+ op: '=',
+ value: 'FAILURE',
+ },
+ ],
+ op: 'AND',
+ },
+ functions: [],
+ groupBy: [
+ {
+ dataType: DataTypes.String,
+ id: 'celery.hostname--string--tag--false',
+ isColumn: false,
+ isJSON: false,
+ key: 'celery.hostname',
+ type: 'tag',
+ },
+ ],
+ having: [],
+ legend: '',
+ limit: null,
+ orderBy: [],
+ queryName: 'A',
+ reduceTo: 'avg',
+ spaceAggregation: 'sum',
+ stepInterval: 60,
+ timeAggregation: 'rate',
+ },
+ ],
+ }),
+);
+
+export const celerySuccessStateWidgetData = getWidgetQueryBuilder(
+ getWidgetQuery({
+ title: 'Success',
+ description: 'Represents the number of successful tasks.',
+ panelTypes: PANEL_TYPES.HISTOGRAM,
+ queryData: [
+ {
+ aggregateAttribute: {
+ dataType: DataTypes.String,
+ id: '------false',
+ isColumn: false,
+ isJSON: false,
+ key: '',
+ type: '',
+ },
+ aggregateOperator: 'count',
+ dataSource: DataSource.TRACES,
+ disabled: false,
+ expression: 'A',
+ filters: {
+ items: [
+ {
+ id: '000c5a93',
+ key: {
+ dataType: DataTypes.String,
+ id: 'celery.state--string--tag--false',
+ isColumn: false,
+ isJSON: false,
+ key: 'celery.state',
+ type: 'tag',
+ },
+ op: '=',
+ value: 'SUCCESS',
+ },
+ ],
+ op: 'AND',
+ },
+ functions: [],
+ groupBy: [
+ {
+ dataType: DataTypes.String,
+ id: 'celery.hostname--string--tag--false',
+ isColumn: false,
+ isJSON: false,
+ key: 'celery.hostname',
+ type: 'tag',
+ },
+ ],
+ having: [],
+ legend: '',
+ limit: null,
+ orderBy: [],
+ queryName: 'A',
+ reduceTo: 'avg',
+ spaceAggregation: 'sum',
+ stepInterval: 60,
+ timeAggregation: 'rate',
+ },
+ ],
}),
);
@@ -408,3 +597,228 @@ export const celerySlowestTasksTableWidgetData = getWidgetQueryBuilder(
],
}),
);
+
+export const celeryRetryTasksTableWidgetData = getWidgetQueryBuilder(
+ getWidgetQuery({
+ title: 'Top 10 tasks in retry state',
+ description: 'Represents the top 10 tasks in retry state.',
+ panelTypes: PANEL_TYPES.TABLE,
+ queryData: [
+ {
+ aggregateAttribute: {
+ dataType: DataTypes.Float64,
+ id: 'duration_nano--float64----true',
+ isColumn: true,
+ isJSON: false,
+ key: 'duration_nano',
+ type: '',
+ },
+ aggregateOperator: 'avg',
+ dataSource: DataSource.TRACES,
+ disabled: false,
+ expression: 'A',
+ filters: {
+ items: [
+ {
+ id: '9e09c9ed',
+ key: {
+ dataType: DataTypes.String,
+ id: 'celery.state--string--tag--false',
+ isColumn: false,
+ isJSON: false,
+ key: 'celery.state',
+ type: 'tag',
+ },
+ op: '=',
+ value: 'RETRY',
+ },
+ ],
+ op: 'AND',
+ },
+ functions: [],
+ groupBy: [
+ {
+ dataType: DataTypes.String,
+ id: 'celery.task_name--string--tag--false',
+ isColumn: false,
+ isJSON: false,
+ key: 'celery.task_name',
+ type: 'tag',
+ },
+ ],
+ having: [],
+ legend: '',
+ limit: 10,
+ orderBy: [
+ {
+ columnName: '#SIGNOZ_VALUE',
+ order: 'desc',
+ },
+ ],
+ queryName: 'A',
+ reduceTo: 'avg',
+ spaceAggregation: 'sum',
+ stepInterval: 60,
+ timeAggregation: 'avg',
+ },
+ ],
+ }),
+);
+
+export const celeryFailedTasksTableWidgetData = getWidgetQueryBuilder(
+ getWidgetQuery({
+ title: 'Top 10 tasks in FAILED state',
+ description: 'Represents the top 10 tasks in failed state.',
+ panelTypes: PANEL_TYPES.TABLE,
+ queryData: [
+ {
+ aggregateAttribute: {
+ dataType: DataTypes.Float64,
+ id: 'duration_nano--float64----true',
+ isColumn: true,
+ isJSON: false,
+ key: 'duration_nano',
+ type: '',
+ },
+ aggregateOperator: 'avg',
+ dataSource: DataSource.TRACES,
+ disabled: false,
+ expression: 'A',
+ filters: {
+ items: [
+ {
+ id: '2330f906',
+ key: {
+ dataType: DataTypes.String,
+ id: 'celery.state--string--tag--false',
+ isColumn: false,
+ isJSON: false,
+ key: 'celery.state',
+ type: 'tag',
+ },
+ op: '=',
+ value: 'FAILURE',
+ },
+ ],
+ op: 'AND',
+ },
+ functions: [],
+ groupBy: [
+ {
+ dataType: DataTypes.String,
+ id: 'celery.task_name--string--tag--false',
+ isColumn: false,
+ isJSON: false,
+ key: 'celery.task_name',
+ type: 'tag',
+ },
+ ],
+ having: [],
+ legend: '',
+ limit: null,
+ orderBy: [
+ {
+ columnName: '#SIGNOZ_VALUE',
+ order: 'desc',
+ },
+ ],
+ queryName: 'A',
+ reduceTo: 'avg',
+ spaceAggregation: 'sum',
+ stepInterval: 60,
+ timeAggregation: 'avg',
+ },
+ ],
+ }),
+);
+
+export const celerySuccessTasksTableWidgetData = getWidgetQueryBuilder(
+ getWidgetQuery({
+ title: 'Top 10 tasks in SUCCESS state',
+ description: 'Represents the top 10 tasks in success state.',
+ panelTypes: PANEL_TYPES.TABLE,
+ queryData: [
+ {
+ aggregateAttribute: {
+ dataType: DataTypes.Float64,
+ id: 'duration_nano--float64----true',
+ isColumn: true,
+ isJSON: false,
+ key: 'duration_nano',
+ type: '',
+ },
+ aggregateOperator: 'avg',
+ dataSource: DataSource.TRACES,
+ disabled: false,
+ expression: 'A',
+ filters: {
+ items: [
+ {
+ id: 'ec3df7b7',
+ key: {
+ dataType: DataTypes.String,
+ id: 'celery.state--string--tag--false',
+ isColumn: false,
+ isJSON: false,
+ key: 'celery.state',
+ type: 'tag',
+ },
+ op: '=',
+ value: 'SUCCESS',
+ },
+ ],
+ op: 'AND',
+ },
+ functions: [],
+ groupBy: [
+ {
+ dataType: DataTypes.String,
+ id: 'celery.task_name--string--tag--false',
+ isColumn: false,
+ isJSON: false,
+ key: 'celery.task_name',
+ type: 'tag',
+ },
+ ],
+ having: [],
+ legend: '',
+ limit: null,
+ orderBy: [
+ {
+ columnName: '#SIGNOZ_VALUE',
+ order: 'desc',
+ },
+ ],
+ queryName: 'A',
+ reduceTo: 'avg',
+ spaceAggregation: 'sum',
+ stepInterval: 60,
+ timeAggregation: 'avg',
+ },
+ ],
+ }),
+);
+
+// export const getCeleryTaskStateQueryPayload = ({
+// start,
+// end,
+// }: {
+// start: number;
+// end: number;
+// }): GetQueryResultsProps[] => {
+// const widgetData = [
+// celeryRetryTasksTableWidgetData,
+// celeryFailedTasksTableWidgetData,
+// celerySuccessTasksTableWidgetData,
+// ];
+
+// return widgetData.map((widget) => ({
+// start,
+// end,
+// graphType: PANEL_TYPES.TABLE,
+// query: widget.query,
+// selectedTime: 'GLOBAL_TIME',
+// formatForWeb: true,
+// variables: {},
+// }));
+// };
diff --git a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskHistogram.tsx b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskHistogram.tsx
new file mode 100644
index 0000000000..1b1537de8f
--- /dev/null
+++ b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskHistogram.tsx
@@ -0,0 +1,132 @@
+import { QueryParams } from 'constants/query';
+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 { useIsDarkMode } from 'hooks/useDarkMode';
+import useUrlQuery from 'hooks/useUrlQuery';
+import { useCallback, useState } from 'react';
+import { useDispatch } from 'react-redux';
+import { useHistory, useLocation } from 'react-router-dom';
+import { UpdateTimeInterval } from 'store/actions';
+
+import { CeleryTaskData } from '../CeleryTaskDetail/CeleryTaskDetail';
+import {
+ celeryAllStateWidgetData,
+ celeryFailedStateWidgetData,
+ celeryRetryStateWidgetData,
+ celerySuccessStateWidgetData,
+} from './CeleryTaskGraphUtils';
+import {
+ CeleryTaskState,
+ CeleryTaskStateGraphConfig,
+} from './CeleryTaskStateGraphConfig';
+
+function CeleryTaskHistogram({
+ onClick,
+ queryEnabled,
+}: {
+ onClick: (task: CeleryTaskData) => void;
+
+ queryEnabled: boolean;
+}): JSX.Element {
+ const history = useHistory();
+ const { pathname } = useLocation();
+ const dispatch = useDispatch();
+ const urlQuery = useUrlQuery();
+ const isDarkMode = useIsDarkMode();
+
+ const onDragSelect = useCallback(
+ (start: number, end: number) => {
+ const startTimestamp = Math.trunc(start);
+ const endTimestamp = Math.trunc(end);
+
+ urlQuery.set(QueryParams.startTime, startTimestamp.toString());
+ urlQuery.set(QueryParams.endTime, endTimestamp.toString());
+ const generatedUrl = `${pathname}?${urlQuery.toString()}`;
+ history.push(generatedUrl);
+
+ if (startTimestamp !== endTimestamp) {
+ dispatch(UpdateTimeInterval('custom', [startTimestamp, endTimestamp]));
+ }
+ },
+ [dispatch, history, pathname, urlQuery],
+ );
+
+ const [histogramState, setHistogramState] = useState(
+ CeleryTaskState.All,
+ );
+
+ const getGraphData = (graphData: any): void => {
+ console.log('graphData', graphData);
+ };
+
+ return (
+
+
+
+ {histogramState === CeleryTaskState.All && (
+ {
+ console.log('clicked', arg);
+ onClick(arg as any);
+ }}
+ getGraphData={getGraphData}
+ isQueryEnabled={queryEnabled}
+ />
+ )}
+ {histogramState === CeleryTaskState.Failed && (
+ {
+ console.log('clicked', arg);
+ onClick(arg as any);
+ }}
+ getGraphData={getGraphData}
+ isQueryEnabled={queryEnabled}
+ />
+ )}
+ {histogramState === CeleryTaskState.Retry && (
+ {
+ console.log('clicked', arg);
+ onClick(arg as any);
+ }}
+ getGraphData={getGraphData}
+ isQueryEnabled={queryEnabled}
+ />
+ )}
+ {histogramState === CeleryTaskState.Successful && (
+ {
+ console.log('clicked', arg);
+ onClick(arg as any);
+ }}
+ getGraphData={getGraphData}
+ isQueryEnabled={queryEnabled}
+ />
+ )}
+
+
+ );
+}
+
+export default CeleryTaskHistogram;
diff --git a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskStateGraphConfig.tsx b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskStateGraphConfig.tsx
new file mode 100644
index 0000000000..33efc72ec1
--- /dev/null
+++ b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskStateGraphConfig.tsx
@@ -0,0 +1,96 @@
+import './CeleryTaskGraph.style.scss';
+
+import { Col, Row } from 'antd';
+// import { ENTITY_VERSION_V4 } from 'constants/app';
+// import { GetMetricQueryRange } from 'lib/dashboard/getQueryResults';
+import { Dispatch, SetStateAction } from 'react';
+// import { useQueries } from 'react-query';
+// import { useSelector } from 'react-redux';
+// import { AppState } from 'store/reducers';
+// import { SuccessResponse } from 'types/api';
+// import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
+// import { GlobalReducer } from 'types/reducer/globalTime';
+
+// import { getCeleryTaskStateQueryPayload } from './CeleryTaskGraphUtils';
+
+interface TabData {
+ label: string;
+ value: number;
+ key: string;
+}
+
+export enum CeleryTaskState {
+ All = 'all',
+ Failed = 'failed',
+ Retry = 'retry',
+ Successful = 'successful',
+}
+
+function CeleryTaskStateGraphConfig({
+ histogramState,
+ setHistogramState,
+}: {
+ setHistogramState: Dispatch>;
+ histogramState: CeleryTaskState;
+}): JSX.Element {
+ const tabs: TabData[] = [
+ { label: 'All Tasks', value: 1097, key: CeleryTaskState.All },
+ { label: 'Failed', value: 11, key: CeleryTaskState.Failed },
+ { label: 'Retry', value: 59, key: CeleryTaskState.Retry },
+ { label: 'Successful', value: 1027, key: CeleryTaskState.Successful },
+ ];
+
+ // const { maxTime, minTime } = useSelector(
+ // (state) => state.globalTime,
+ // );
+
+ const handleTabClick = (key: CeleryTaskState): void => {
+ setHistogramState(key as CeleryTaskState);
+ };
+
+ // // get task count from api
+ // const queryPayloads = useMemo(
+ // () =>
+ // getCeleryTaskStateQueryPayload({
+ // start: Math.floor(minTime / 1000000000),
+ // end: Math.floor(maxTime / 1000000000),
+ // }),
+ // [minTime, maxTime],
+ // );
+
+ // const queries = useQueries(
+ // queryPayloads.map((payload) => ({
+ // queryKey: ['host-metrics', payload, ENTITY_VERSION_V4, 'HOST'],
+ // queryFn: (): Promise> =>
+ // GetMetricQueryRange(payload, ENTITY_VERSION_V4),
+ // enabled: !!payload,
+ // })),
+ // );
+
+ return (
+
+ {tabs.map((tab, index) => (
+ handleTabClick(tab.key as CeleryTaskState)}
+ className={`celery-task-states__tab ${
+ tab.key === histogramState ? 'celery-task-states__tab--selected' : ''
+ }`}
+ data-last-tab={index === tabs.length - 1}
+ >
+
+ {/* */}
+ {tab.key === histogramState && (
+
+ )}
+
+ ))}
+
+ );
+}
+
+export { CeleryTaskStateGraphConfig };
diff --git a/frontend/src/container/GridCardLayout/GridCard/index.tsx b/frontend/src/container/GridCardLayout/GridCard/index.tsx
index 09b6b65e1a..82fc498c43 100644
--- a/frontend/src/container/GridCardLayout/GridCard/index.tsx
+++ b/frontend/src/container/GridCardLayout/GridCard/index.tsx
@@ -37,6 +37,7 @@ function GridCardGraph({
onDragSelect,
customTooltipElement,
dataAvailable,
+ getGraphData,
}: GridCardGraphProps): JSX.Element {
const dispatch = useDispatch();
const [errorMessage, setErrorMessage] = useState();
@@ -209,6 +210,7 @@ function GridCardGraph({
dataAvailable?.(
isDataAvailableByPanelType(data?.payload?.data, widget?.panelTypes),
);
+ getGraphData?.(data?.payload?.data);
setDashboardQueryRangeCalled(true);
},
},
diff --git a/frontend/src/container/GridCardLayout/GridCard/types.ts b/frontend/src/container/GridCardLayout/GridCard/types.ts
index 05d3368096..2c2071900f 100644
--- a/frontend/src/container/GridCardLayout/GridCard/types.ts
+++ b/frontend/src/container/GridCardLayout/GridCard/types.ts
@@ -45,6 +45,7 @@ export interface GridCardGraphProps {
onDragSelect: (start: number, end: number) => void;
customTooltipElement?: HTMLDivElement;
dataAvailable?: (isDataAvailable: boolean) => void;
+ getGraphData?: (graphData?: MetricRangePayloadProps['data']) => void;
}
export interface GetGraphVisibilityStateOnLegendClickProps {
diff --git a/frontend/src/pages/Celery/CeleryTask/CeleryTask.tsx b/frontend/src/pages/Celery/CeleryTask/CeleryTask.tsx
index e09c47f33e..3c3008fb01 100644
--- a/frontend/src/pages/Celery/CeleryTask/CeleryTask.tsx
+++ b/frontend/src/pages/Celery/CeleryTask/CeleryTask.tsx
@@ -5,6 +5,7 @@ import CeleryTaskDetail, {
CeleryTaskData,
} from 'components/CeleryTask/CeleryTaskDetail/CeleryTaskDetail';
import CeleryTaskGraphGrid from 'components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphGrid';
+import { celerySlowestTasksTableWidgetData } from 'components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphUtils';
import DateTimeSelectionV2 from 'container/TopNav/DateTimeSelectionV2';
import { ListMinus } from 'lucide-react';
import { useState } from 'react';
@@ -28,14 +29,23 @@ export default function CeleryTask(): JSX.Element {
-
+
- {
- setTask(null);
- }}
- />
+ {!!task && (
+ {
+ setTask(null);
+ }}
+ mainTitle="Celery Task"
+ widgetData={celerySlowestTasksTableWidgetData}
+ taskData={{
+ entity: 'task',
+ value: 'task',
+ timeRange: [1737569089000, 1737570889000],
+ }}
+ drawerOpen={!!task}
+ />
+ )}
);
}