From bfc920a0a67624c4b08db61a32c1e5b8abc30bda Mon Sep 17 00:00:00 2001 From: SagarRajput-7 Date: Fri, 17 Jan 2025 08:51:03 +0530 Subject: [PATCH 01/14] feat: added celery task feature - with task garphs and details --- frontend/src/AppRoutes/pageComponents.ts | 7 + frontend/src/AppRoutes/routes.ts | 8 + .../CeleryTaskConfigOptions.styles.scss | 39 ++ .../CeleryTaskConfigOptions.tsx | 89 ++++ .../useGetCeleryFilters.ts | 49 +++ .../CeleryTaskDetail.style.scss | 5 + .../CeleryTaskDetail/CeleryTaskDetail.tsx | 59 +++ .../CeleryTaskGraph.style.scss | 36 ++ .../CeleryTaskGraph/CeleryTaskGraph.tsx | 65 +++ .../CeleryTaskGraph/CeleryTaskGraphGrid.tsx | 47 ++ .../CeleryTaskGraph/CeleryTaskGraphUtils.ts | 410 ++++++++++++++++++ .../src/components/CeleryTask/CeleryUtils.ts | 22 + .../CeleryTask/useCeleryFilterOptions.ts | 32 ++ frontend/src/constants/query.ts | 1 + frontend/src/constants/routes.ts | 1 + frontend/src/container/AppLayout/index.tsx | 4 +- frontend/src/container/SideNav/config.ts | 1 + .../TopNav/DateTimeSelectionV2/config.ts | 1 + .../Celery/CeleryTask/CeleryTask.styles.scss | 44 ++ .../pages/Celery/CeleryTask/CeleryTask.tsx | 41 ++ .../MQDetails/MetricPage/MetricPageUtil.ts | 5 +- frontend/src/utils/permission/index.ts | 1 + 22 files changed, 964 insertions(+), 3 deletions(-) create mode 100644 frontend/src/components/CeleryTask/CeleryTaskConfigOptions/CeleryTaskConfigOptions.styles.scss create mode 100644 frontend/src/components/CeleryTask/CeleryTaskConfigOptions/CeleryTaskConfigOptions.tsx create mode 100644 frontend/src/components/CeleryTask/CeleryTaskConfigOptions/useGetCeleryFilters.ts create mode 100644 frontend/src/components/CeleryTask/CeleryTaskDetail/CeleryTaskDetail.style.scss create mode 100644 frontend/src/components/CeleryTask/CeleryTaskDetail/CeleryTaskDetail.tsx create mode 100644 frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraph.style.scss create mode 100644 frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraph.tsx create mode 100644 frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphGrid.tsx create mode 100644 frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphUtils.ts create mode 100644 frontend/src/components/CeleryTask/CeleryUtils.ts create mode 100644 frontend/src/components/CeleryTask/useCeleryFilterOptions.ts create mode 100644 frontend/src/pages/Celery/CeleryTask/CeleryTask.styles.scss create mode 100644 frontend/src/pages/Celery/CeleryTask/CeleryTask.tsx diff --git a/frontend/src/AppRoutes/pageComponents.ts b/frontend/src/AppRoutes/pageComponents.ts index 0857ea4664..cafbbd2ba4 100644 --- a/frontend/src/AppRoutes/pageComponents.ts +++ b/frontend/src/AppRoutes/pageComponents.ts @@ -247,3 +247,10 @@ export const InfrastructureMonitoring = Loadable( /* webpackChunkName: "InfrastructureMonitoring" */ 'pages/InfrastructureMonitoring' ), ); + +export const CeleryTask = Loadable( + () => + import( + /* webpackChunkName: "CeleryTask" */ 'pages/Celery/CeleryTask/CeleryTask' + ), +); diff --git a/frontend/src/AppRoutes/routes.ts b/frontend/src/AppRoutes/routes.ts index dda546167f..998ba3e34a 100644 --- a/frontend/src/AppRoutes/routes.ts +++ b/frontend/src/AppRoutes/routes.ts @@ -8,6 +8,7 @@ import { AllErrors, APIKeys, BillingPage, + CeleryTask, CreateAlertChannelAlerts, CreateNewAlerts, CustomDomainSettings, @@ -401,6 +402,13 @@ const routes: AppRoutes[] = [ key: 'MESSAGING_QUEUES', isPrivate: true, }, + { + path: ROUTES.MESSAGING_QUEUES_CELERY_TASK, + exact: true, + component: CeleryTask, + key: 'MESSAGING_QUEUES_CELERY_TASK', + isPrivate: true, + }, { path: ROUTES.MESSAGING_QUEUES_DETAIL, exact: true, diff --git a/frontend/src/components/CeleryTask/CeleryTaskConfigOptions/CeleryTaskConfigOptions.styles.scss b/frontend/src/components/CeleryTask/CeleryTaskConfigOptions/CeleryTaskConfigOptions.styles.scss new file mode 100644 index 0000000000..1ffd4af3ff --- /dev/null +++ b/frontend/src/components/CeleryTask/CeleryTaskConfigOptions/CeleryTaskConfigOptions.styles.scss @@ -0,0 +1,39 @@ +.celery-task-filters { + display: flex; + justify-content: space-between; + width: 100%; + + .celery-filters { + display: flex; + align-items: center; + gap: 8px; + + .config-select-option { + width: 100%; + .ant-select-selector { + display: flex; + min-height: 32px; + align-items: center; + gap: 16px; + min-width: 164px; + + border-radius: 2px; + border: 1px solid var(--bg-slate-400); + background: var(--bg-ink-300); + } + } + } +} + +.lightMode { + .celery-task-filters { + .celery-filters { + .config-select-option { + .ant-select-selector { + border: 1px solid var(--bg-vanilla-300); + background: var(--bg-vanilla-100); + } + } + } + } +} diff --git a/frontend/src/components/CeleryTask/CeleryTaskConfigOptions/CeleryTaskConfigOptions.tsx b/frontend/src/components/CeleryTask/CeleryTaskConfigOptions/CeleryTaskConfigOptions.tsx new file mode 100644 index 0000000000..5088f9ea5f --- /dev/null +++ b/frontend/src/components/CeleryTask/CeleryTaskConfigOptions/CeleryTaskConfigOptions.tsx @@ -0,0 +1,89 @@ +import './CeleryTaskConfigOptions.styles.scss'; + +import { Color } from '@signozhq/design-tokens'; +import { Button, Select, Spin, Tooltip } from 'antd'; +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'; + +import { + getValuesFromQueryParams, + setQueryParamsFromOptions, +} from '../CeleryUtils'; +import { useCeleryFilterOptions } from '../useCeleryFilterOptions'; + +function CeleryTaskConfigOptions(): JSX.Element { + const { handleSearch, isFetching, options } = useCeleryFilterOptions( + 'celery.task_name', + ); + const history = useHistory(); + const location = useLocation(); + + const [isURLCopied, setIsURLCopied] = useState(false); + const urlQuery = useUrlQuery(); + + const [, handleCopyToClipboard] = useCopyToClipboard(); + + return ( +
+
+ void; @@ -35,6 +41,7 @@ function CeleryTaskGraph({ panelType?: PANEL_TYPES; openTracesButton?: boolean; onOpenTraceBtnClick?: (record: RowData) => void; + applyCeleryTaskFilter?: boolean; }): JSX.Element { const history = useHistory(); const { pathname } = useLocation(); @@ -42,6 +49,21 @@ function CeleryTaskGraph({ const urlQuery = useUrlQuery(); const isDarkMode = useIsDarkMode(); + const selectedFilters = useMemo( + () => + getFiltersFromQueryParams( + QueryParams.taskName, + urlQuery, + 'celery.task_name', + ), + [urlQuery], + ); + + const updatedWidgetData = useMemo( + () => applyCeleryFilterOnWidgetData(selectedFilters || [], widgetData), + [selectedFilters, widgetData], + ); + const onDragSelect = useCallback( (start: number, end: number) => { const startTimestamp = Math.trunc(start); @@ -66,7 +88,7 @@ function CeleryTaskGraph({ className="celery-task-graph" > { @@ -93,6 +115,7 @@ function CeleryTaskGraph({ isQueryEnabled={queryEnabled} openTracesButton={openTracesButton} onOpenTraceBtnClick={onOpenTraceBtnClick} + version={ENTITY_VERSION_V4} /> ); @@ -105,6 +128,7 @@ CeleryTaskGraph.defaultProps = { panelType: PANEL_TYPES.TIME_SERIES, openTracesButton: false, onOpenTraceBtnClick: undefined, + applyCeleryTaskFilter: false, }; export default CeleryTaskGraph; diff --git a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphGrid.tsx b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphGrid.tsx index d6dcfda13b..6a175d441e 100644 --- a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphGrid.tsx +++ b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphGrid.tsx @@ -57,6 +57,7 @@ export default function CeleryTaskGraphGrid({ onClick={onClick} queryEnabled={queryEnabled} rightPanelTitle={rightPanelTitle[index]} + applyCeleryTaskFilter /> ))}
diff --git a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphUtils.ts b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphUtils.ts index 23d4ba7e8c..165ab41504 100644 --- a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphUtils.ts +++ b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphUtils.ts @@ -449,17 +449,18 @@ export const celeryWorkerOnlineWidgetData = getWidgetQueryBuilder( getWidgetQuery({ title: 'Worker Online', description: 'Represents the number of workers online.', + panelTypes: PANEL_TYPES.VALUE, queryData: [ { aggregateAttribute: { dataType: DataTypes.Float64, - id: 'flower_worker_online--float64--Gauge--true', + id: 'flower_task_runtime_seconds_sum--float64--Sum--true', isColumn: true, isJSON: false, - key: 'flower_worker_online', - type: 'Gauge', + key: 'flower_task_runtime_seconds_sum', + type: 'Sum', }, - aggregateOperator: 'avg', + aggregateOperator: 'rate', dataSource: DataSource.METRICS, disabled: false, expression: 'A', @@ -468,25 +469,16 @@ export const celeryWorkerOnlineWidgetData = getWidgetQueryBuilder( op: 'AND', }, functions: [], - groupBy: [ - { - dataType: DataTypes.String, - id: 'worker--string--tag--false', - isColumn: false, - isJSON: false, - key: 'worker', - type: 'tag', - }, - ], + groupBy: [], having: [], legend: '', limit: null, orderBy: [], queryName: 'A', reduceTo: 'avg', - spaceAggregation: 'max', + spaceAggregation: 'sum', stepInterval: 60, - timeAggregation: 'avg', + timeAggregation: 'rate', }, ], }), diff --git a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskLatencyGraph.tsx b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskLatencyGraph.tsx index e135a1cfff..2cd638e170 100644 --- a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskLatencyGraph.tsx +++ b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskLatencyGraph.tsx @@ -9,12 +9,16 @@ import { Card } from 'container/GridCardLayout/styles'; import { useIsDarkMode } from 'hooks/useDarkMode'; import useUrlQuery from 'hooks/useUrlQuery'; import { getStartAndEndTimesInMilliseconds } from 'pages/MessagingQueues/MessagingQueuesUtils'; -import { useCallback, useState } from 'react'; +import { useCallback, useMemo, useState } from 'react'; import { useDispatch } from 'react-redux'; import { useHistory, useLocation } from 'react-router-dom'; import { UpdateTimeInterval } from 'store/actions'; import { CaptureDataProps } from '../CeleryTaskDetail/CeleryTaskDetail'; +import { + applyCeleryFilterOnWidgetData, + getFiltersFromQueryParams, +} from '../CeleryUtils'; import { celeryTaskLatencyWidgetData, celeryTimeSeriesTablesWidgetData, @@ -75,6 +79,25 @@ function CeleryTaskLatencyGraph({ [dispatch, history, pathname, urlQuery], ); + const selectedFilters = useMemo( + () => + getFiltersFromQueryParams( + QueryParams.taskName, + urlQuery, + 'celery.task_name', + ), + [urlQuery], + ); + + const updatedWidgetData = useMemo( + () => + applyCeleryFilterOnWidgetData( + selectedFilters || [], + celeryTaskLatencyWidgetData(graphState), + ), + [graphState, selectedFilters], + ); + const onGraphClick = ( xValue: number, _yValue: number, @@ -131,7 +154,7 @@ function CeleryTaskLatencyGraph({
{graphState === CeleryTaskGraphState.P99 && ( ({ + id: uuidv4(), + key: { + key, + dataType: DataTypes.String, + type: 'tag', + isColumn: false, + isJSON: false, + id: `${key}--string--tag--false`, + }, + op: '=', + value: value.toString(), + })); +} + +export function applyCeleryFilterOnWidgetData( + filters: TagFilterItem[], + widgetData: Widgets, +): Widgets { + console.log(filters, widgetData); + return { + ...widgetData, + query: { + ...widgetData.query, + builder: { + ...widgetData.query.builder, + queryData: widgetData.query.builder.queryData.map((queryItem, index) => + index === 0 + ? { + ...queryItem, + filters: { + ...queryItem.filters, + items: [...queryItem.filters.items, ...filters], + }, + } + : queryItem, + ), + }, + }, + }; +} From bf1102cdfc99b24891cab73c0a799c5bb4dfbd2f Mon Sep 17 00:00:00 2001 From: SagarRajput-7 Date: Sun, 26 Jan 2025 23:53:50 +0530 Subject: [PATCH 08/14] feat: added dynamic stepinterval based on timerange --- .../CeleryTaskGraph/CeleryTaskGraphGrid.tsx | 48 +- .../CeleryTaskGraph/CeleryTaskGraphUtils.ts | 923 ++++++++++-------- .../CeleryTaskGraph/CeleryTaskHistogram.tsx | 38 +- .../CeleryTaskLatencyGraph.tsx | 20 +- 4 files changed, 576 insertions(+), 453 deletions(-) diff --git a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphGrid.tsx b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphGrid.tsx index 6a175d441e..678f8b018f 100644 --- a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphGrid.tsx +++ b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphGrid.tsx @@ -1,5 +1,10 @@ import './CeleryTaskGraph.style.scss'; +import { useMemo } from 'react'; +import { useSelector } from 'react-redux'; +import { AppState } from 'store/reducers'; +import { GlobalReducer } from 'types/reducer/globalTime'; + import { CaptureDataProps } from '../CeleryTaskDetail/CeleryTaskDetail'; import CeleryTaskGraph from './CeleryTaskGraph'; import { @@ -19,10 +24,39 @@ export default function CeleryTaskGraphGrid({ onClick: (task: CaptureDataProps) => void; queryEnabled: boolean; }): JSX.Element { + const { minTime, maxTime } = useSelector( + (state) => state.globalTime, + ); + + const celeryWorkerOnlineData = useMemo( + () => celeryWorkerOnlineWidgetData(minTime, maxTime), + [minTime, maxTime], + ); + + const celeryActiveTasksData = useMemo( + () => celeryActiveTasksWidgetData(minTime, maxTime), + [minTime, maxTime], + ); + + const celeryErrorByWorkerData = useMemo( + () => celeryErrorByWorkerWidgetData(minTime, maxTime), + [minTime, maxTime], + ); + + const celeryLatencyByWorkerData = useMemo( + () => celeryLatencyByWorkerWidgetData(minTime, maxTime), + [minTime, maxTime], + ); + + const celeryTasksByWorkerData = useMemo( + () => celeryTasksByWorkerWidgetData(minTime, maxTime), + [minTime, maxTime], + ); + const bottomWidgetData = [ - celeryTasksByWorkerWidgetData, - celeryErrorByWorkerWidgetData, - celeryLatencyByWorkerWidgetData, + celeryTasksByWorkerData, + celeryErrorByWorkerData, + celeryLatencyByWorkerData, ]; const rightPanelTitle = [ @@ -36,16 +70,16 @@ export default function CeleryTaskGraphGrid({
diff --git a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphUtils.ts b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphUtils.ts index 165ab41504..948f317e0d 100644 --- a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphUtils.ts +++ b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphUtils.ts @@ -7,485 +7,540 @@ import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { DataSource } from 'types/common/queryBuilder'; import { v4 as uuidv4 } from 'uuid'; +// dynamic step interval +export const getStepInterval = (startTime: number, endTime: number): number => { + const diffInMinutes = (endTime - startTime) / 1000000 / (60 * 1000); // Convert to minutes + + console.log('startTime', startTime); + console.log('diffInMinutes', diffInMinutes); + + if (diffInMinutes <= 15) return 60; // 15 min or less + if (diffInMinutes <= 30) return 60; // 30 min or less + if (diffInMinutes <= 60) return 120; // 1 hour or less + if (diffInMinutes <= 360) return 520; // 6 hours or less + if (diffInMinutes <= 1440) return 2440; // 1 day or less + if (diffInMinutes <= 10080) return 10080; // 1 week or less + return 54000; // More than a week (use monthly interval) +}; + // State Graphs -export const celeryAllStateWidgetData = getWidgetQueryBuilder( - getWidgetQuery({ - 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: 'a163d71c', - 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', - }, - ], - op: 'AND', - }, - functions: [], - groupBy: [ - { +export const celeryAllStateWidgetData = ( + startTime: number, + endTime: number, +): Widgets => + getWidgetQueryBuilder( + getWidgetQuery({ + queryData: [ + { + aggregateAttribute: { dataType: DataTypes.String, - id: 'celery.state--string--tag--false', + id: '------false', isColumn: false, isJSON: false, - key: 'celery.state', - type: 'tag', + key: '', + type: '', }, - ], - having: [], - legend: '', - limit: null, - orderBy: [], - queryName: 'A', - reduceTo: 'avg', - spaceAggregation: 'sum', - stepInterval: 60, - timeAggregation: 'rate', - }, - ], - title: 'All', - description: - 'Represents all states of task, including success, failed, and retry.', - panelTypes: PANEL_TYPES.BAR, - }), -); - -export const celeryRetryStateWidgetData = getWidgetQueryBuilder( - getWidgetQuery({ - title: 'Retry', - description: 'Represents the number of retry tasks.', - panelTypes: PANEL_TYPES.BAR, - 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', + aggregateOperator: 'count', + 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', }, - op: '=', - value: 'RETRY', + ], + op: 'AND', + }, + functions: [], + groupBy: [ + { + dataType: DataTypes.String, + id: 'celery.state--string--tag--false', + isColumn: false, + isJSON: false, + key: 'celery.state', + type: 'tag', }, ], - op: 'AND', + having: [], + legend: '', + limit: null, + orderBy: [], + queryName: 'A', + reduceTo: 'avg', + spaceAggregation: 'sum', + stepInterval: getStepInterval(startTime, endTime), + timeAggregation: 'rate', }, - functions: [], - groupBy: [ - { + ], + title: 'All', + description: + 'Represents all states of task, including success, failed, and retry.', + panelTypes: PANEL_TYPES.BAR, + }), + ); + +export const celeryRetryStateWidgetData = ( + startTime: number, + endTime: number, +): Widgets => + getWidgetQueryBuilder( + getWidgetQuery({ + title: 'Retry', + description: 'Represents the number of retry tasks.', + panelTypes: PANEL_TYPES.BAR, + queryData: [ + { + aggregateAttribute: { dataType: DataTypes.String, - id: 'celery.hostname--string--tag--false', + id: '------false', isColumn: false, - isJSON: false, - key: 'celery.hostname', - type: 'tag', + key: '', + type: '', }, - ], - 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.BAR, - 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', + 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: '=', - value: 'FAILURE', + ], + op: 'AND', + }, + functions: [], + groupBy: [ + { + dataType: DataTypes.String, + id: 'celery.hostname--string--tag--false', + isColumn: false, + isJSON: false, + key: 'celery.hostname', + type: 'tag', }, ], - op: 'AND', + having: [], + legend: '', + limit: null, + orderBy: [], + queryName: 'A', + reduceTo: 'avg', + spaceAggregation: 'sum', + stepInterval: getStepInterval(startTime, endTime), + timeAggregation: 'count', }, - functions: [], - groupBy: [ - { + ], + }), + ); + +export const celeryFailedStateWidgetData = ( + startTime: number, + endTime: number, +): Widgets => + getWidgetQueryBuilder( + getWidgetQuery({ + title: 'Failed', + description: 'Represents the number of failed tasks.', + panelTypes: PANEL_TYPES.BAR, + queryData: [ + { + aggregateAttribute: { dataType: DataTypes.String, - id: 'celery.hostname--string--tag--false', + id: '------false', isColumn: false, isJSON: false, - key: 'celery.hostname', - type: 'tag', + key: '', + type: '', }, - ], - 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.BAR, - 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', + 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: '=', - value: 'SUCCESS', + ], + op: 'AND', + }, + functions: [], + groupBy: [ + { + dataType: DataTypes.String, + id: 'celery.hostname--string--tag--false', + isColumn: false, + isJSON: false, + key: 'celery.hostname', + type: 'tag', }, ], - op: 'AND', + having: [], + legend: '', + limit: null, + orderBy: [], + queryName: 'A', + reduceTo: 'avg', + spaceAggregation: 'sum', + stepInterval: getStepInterval(startTime, endTime), + timeAggregation: 'rate', }, - functions: [], - groupBy: [ - { + ], + }), + ); + +export const celerySuccessStateWidgetData = ( + startTime: number, + endTime: number, +): Widgets => + getWidgetQueryBuilder( + getWidgetQuery({ + title: 'Success', + description: 'Represents the number of successful tasks.', + panelTypes: PANEL_TYPES.BAR, + queryData: [ + { + aggregateAttribute: { dataType: DataTypes.String, - id: 'celery.hostname--string--tag--false', + id: '------false', isColumn: false, isJSON: false, - key: 'celery.hostname', - type: 'tag', + key: '', + type: '', }, - ], - having: [], - legend: '', - limit: null, - orderBy: [], - queryName: 'A', - reduceTo: 'avg', - spaceAggregation: 'sum', - stepInterval: 60, - timeAggregation: 'rate', - }, - ], - }), -); - -export const celeryTasksByWorkerWidgetData = getWidgetQueryBuilder( - getWidgetQuery({ - title: 'Tasks/s by worker', - description: 'Represents the number of tasks executed by each worker.', - queryData: [ - { - aggregateAttribute: { - dataType: DataTypes.String, - id: '------false', - isColumn: false, - key: '', - type: '', - }, - aggregateOperator: 'rate', - dataSource: DataSource.TRACES, - disabled: false, - expression: 'A', - filters: { - items: [], - op: 'AND', + 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: getStepInterval(startTime, endTime), + timeAggregation: 'rate', }, - functions: [], - groupBy: [ - { + ], + }), + ); + +export const celeryTasksByWorkerWidgetData = ( + startTime: number, + endTime: number, +): Widgets => + getWidgetQueryBuilder( + getWidgetQuery({ + title: 'Tasks/s by worker', + description: 'Represents the number of tasks executed by each worker.', + queryData: [ + { + aggregateAttribute: { dataType: DataTypes.String, - id: 'celery.hostname--string--tag--false', + id: '------false', isColumn: false, - isJSON: false, - key: 'celery.hostname', - type: 'tag', + key: '', + type: '', }, - ], - having: [], - legend: '', - limit: 10, - orderBy: [], - queryName: 'A', - reduceTo: 'avg', - spaceAggregation: 'sum', - stepInterval: 60, - timeAggregation: 'rate', - }, - ], - }), -); - -export const celeryErrorByWorkerWidgetData = getWidgetQueryBuilder( - getWidgetQuery({ - title: 'Error% by worker', - description: 'Represents the number of errors by each worker.', - queryData: [ - { - aggregateAttribute: { - dataType: DataTypes.String, - id: '------false', - isColumn: false, - isJSON: false, - key: '', - type: '', - }, - aggregateOperator: 'rate', - dataSource: DataSource.TRACES, - disabled: false, - expression: 'A', - filters: { - items: [], - op: 'AND', + aggregateOperator: 'rate', + dataSource: DataSource.TRACES, + disabled: false, + expression: 'A', + filters: { + items: [], + 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: 10, + orderBy: [], + queryName: 'A', + reduceTo: 'avg', + spaceAggregation: 'sum', + stepInterval: getStepInterval(startTime, endTime), + timeAggregation: 'rate', }, - functions: [], - groupBy: [ - { + ], + }), + ); + +export const celeryErrorByWorkerWidgetData = ( + startTime: number, + endTime: number, +): Widgets => + getWidgetQueryBuilder( + getWidgetQuery({ + title: 'Error% by worker', + description: 'Represents the number of errors by each worker.', + queryData: [ + { + aggregateAttribute: { dataType: DataTypes.String, - id: 'celery.hostname--string--tag--false', + id: '------false', isColumn: false, isJSON: false, - key: 'celery.hostname', - type: 'tag', + key: '', + type: '', }, - ], - having: [], - legend: '', - limit: 10, - orderBy: [], - queryName: 'A', - reduceTo: 'avg', - spaceAggregation: 'sum', - stepInterval: 60, - timeAggregation: 'rate', - }, - ], - }), -); - -export const celeryLatencyByWorkerWidgetData = getWidgetQueryBuilder( - getWidgetQuery({ - title: 'Latency by Worker', - description: 'Represents the latency of tasks by each worker.', - queryData: [ - { - 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: 'A', - filters: { - items: [], - op: 'AND', + aggregateOperator: 'rate', + dataSource: DataSource.TRACES, + disabled: false, + expression: 'A', + filters: { + items: [], + 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: 10, + orderBy: [], + queryName: 'A', + reduceTo: 'avg', + spaceAggregation: 'sum', + stepInterval: getStepInterval(startTime, endTime), + timeAggregation: 'rate', }, - functions: [], - groupBy: [ - { - dataType: DataTypes.String, - id: 'celery.hostname--string--tag--false', - isColumn: false, + ], + }), + ); + +export const celeryLatencyByWorkerWidgetData = ( + startTime: number, + endTime: number, +): Widgets => + getWidgetQueryBuilder( + getWidgetQuery({ + title: 'Latency by Worker', + description: 'Represents the latency of tasks by each worker.', + queryData: [ + { + aggregateAttribute: { + dataType: DataTypes.Float64, + id: 'duration_nano--float64----true', + isColumn: true, isJSON: false, - key: 'celery.hostname', - type: 'tag', + key: 'duration_nano', + type: '', }, - ], - having: [], - legend: '', - limit: 10, - orderBy: [], - queryName: 'A', - reduceTo: 'avg', - spaceAggregation: 'sum', - stepInterval: 60, - timeAggregation: 'p99', - }, - ], - yAxisUnit: 'ns', - }), -); - -export const celeryActiveTasksWidgetData = getWidgetQueryBuilder( - getWidgetQuery({ - title: 'Tasks/ worker (Active tasks)', - description: 'Represents the number of active tasks.', - queryData: [ - { - aggregateAttribute: { - dataType: DataTypes.Float64, - id: - 'flower_worker_number_of_currently_executing_tasks--float64--Gauge--true', - isColumn: true, - isJSON: false, - key: 'flower_worker_number_of_currently_executing_tasks', - type: 'Gauge', - }, - aggregateOperator: 'latest', - dataSource: DataSource.METRICS, - disabled: false, - expression: 'A', - filters: { - items: [], - op: 'AND', + aggregateOperator: 'p99', + dataSource: DataSource.TRACES, + disabled: false, + expression: 'A', + filters: { + items: [], + 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: 10, + orderBy: [], + queryName: 'A', + reduceTo: 'avg', + spaceAggregation: 'sum', + stepInterval: getStepInterval(startTime, endTime), + timeAggregation: 'p99', }, - functions: [], - groupBy: [ - { - dataType: DataTypes.String, - id: 'worker--string--tag--false', - isColumn: false, + ], + yAxisUnit: 'ns', + }), + ); + +export const celeryActiveTasksWidgetData = ( + startTime: number, + endTime: number, +): Widgets => + getWidgetQueryBuilder( + getWidgetQuery({ + title: 'Tasks/ worker (Active tasks)', + description: 'Represents the number of active tasks.', + queryData: [ + { + aggregateAttribute: { + dataType: DataTypes.Float64, + id: + 'flower_worker_number_of_currently_executing_tasks--float64--Gauge--true', + isColumn: true, isJSON: false, - key: 'worker', - type: 'tag', + key: 'flower_worker_number_of_currently_executing_tasks', + type: 'Gauge', }, - ], - having: [], - legend: '', - limit: null, - orderBy: [], - queryName: 'A', - reduceTo: 'avg', - spaceAggregation: 'avg', - stepInterval: 60, - timeAggregation: 'latest', - }, - ], - }), -); - -export const celeryWorkerOnlineWidgetData = getWidgetQueryBuilder( - getWidgetQuery({ - title: 'Worker Online', - description: 'Represents the number of workers online.', - panelTypes: PANEL_TYPES.VALUE, - queryData: [ - { - aggregateAttribute: { - dataType: DataTypes.Float64, - id: 'flower_task_runtime_seconds_sum--float64--Sum--true', - isColumn: true, - isJSON: false, - key: 'flower_task_runtime_seconds_sum', - type: 'Sum', + aggregateOperator: 'latest', + dataSource: DataSource.METRICS, + disabled: false, + expression: 'A', + filters: { + items: [], + op: 'AND', + }, + functions: [], + groupBy: [ + { + dataType: DataTypes.String, + id: 'worker--string--tag--false', + isColumn: false, + isJSON: false, + key: 'worker', + type: 'tag', + }, + ], + having: [], + legend: '', + limit: null, + orderBy: [], + queryName: 'A', + reduceTo: 'avg', + spaceAggregation: 'avg', + stepInterval: getStepInterval(startTime, endTime), + timeAggregation: 'latest', }, - aggregateOperator: 'rate', - dataSource: DataSource.METRICS, - disabled: false, - expression: 'A', - filters: { - items: [], - op: 'AND', + ], + }), + ); + +export const celeryWorkerOnlineWidgetData = ( + startTime: number, + endTime: number, +): Widgets => + getWidgetQueryBuilder( + getWidgetQuery({ + title: 'Worker Online', + description: 'Represents the number of workers online.', + panelTypes: PANEL_TYPES.VALUE, + queryData: [ + { + aggregateAttribute: { + dataType: DataTypes.Float64, + id: 'flower_task_runtime_seconds_sum--float64--Sum--true', + isColumn: true, + isJSON: false, + key: 'flower_task_runtime_seconds_sum', + type: 'Sum', + }, + aggregateOperator: 'rate', + dataSource: DataSource.METRICS, + disabled: false, + expression: 'A', + filters: { + items: [], + op: 'AND', + }, + functions: [], + groupBy: [], + having: [], + legend: '', + limit: null, + orderBy: [], + queryName: 'A', + reduceTo: 'avg', + spaceAggregation: 'sum', + stepInterval: getStepInterval(startTime, endTime), + timeAggregation: 'rate', }, - functions: [], - groupBy: [], - having: [], - legend: '', - limit: null, - orderBy: [], - queryName: 'A', - reduceTo: 'avg', - spaceAggregation: 'sum', - stepInterval: 60, - timeAggregation: 'rate', - }, - ], - }), -); + ], + }), + ); -// Task Latency -export const celeryTaskLatencyWidgetData = (type: string): Widgets => +export const celeryTaskLatencyWidgetData = ( + type: string, + startTime: number, + endTime: number, +): Widgets => getWidgetQueryBuilder( getWidgetQuery({ title: 'Task Latency', @@ -531,7 +586,7 @@ export const celeryTaskLatencyWidgetData = (type: string): Widgets => queryName: 'A', reduceTo: 'avg', spaceAggregation: 'sum', - stepInterval: 60, + stepInterval: getStepInterval(startTime, endTime), timeAggregation: 'p99', }, ], diff --git a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskHistogram.tsx b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskHistogram.tsx index a9efa42f2b..c348bd77ea 100644 --- a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskHistogram.tsx +++ b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskHistogram.tsx @@ -7,10 +7,12 @@ 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 { useCallback, useMemo, 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 { GlobalReducer } from 'types/reducer/globalTime'; // import { CaptureDataProps } from '../CeleryTaskDetail/CeleryTaskDetail'; import { @@ -38,6 +40,10 @@ function CeleryTaskHistogram({ const urlQuery = useUrlQuery(); const isDarkMode = useIsDarkMode(); + const { minTime, maxTime } = useSelector( + (state) => state.globalTime, + ); + const onDragSelect = useCallback( (start: number, end: number) => { const startTimestamp = Math.trunc(start); @@ -59,6 +65,26 @@ function CeleryTaskHistogram({ CeleryTaskState.All, ); + const celeryAllStateData = useMemo( + () => celeryAllStateWidgetData(minTime, maxTime), + [minTime, maxTime], + ); + + const celeryFailedStateData = useMemo( + () => celeryFailedStateWidgetData(minTime, maxTime), + [minTime, maxTime], + ); + + const celeryRetryStateData = useMemo( + () => celeryRetryStateWidgetData(minTime, maxTime), + [minTime, maxTime], + ); + + const celerySuccessStateData = useMemo( + () => celerySuccessStateWidgetData(minTime, maxTime), + [minTime, maxTime], + ); + return ( {histogramState === CeleryTaskState.All && ( ( + (state) => state.globalTime, + ); + + const celeryTaskLatencyData = useMemo( + () => celeryTaskLatencyWidgetData(graphState, minTime, maxTime), + [graphState, minTime, maxTime], + ); + const updatedWidgetData = useMemo( () => - applyCeleryFilterOnWidgetData( - selectedFilters || [], - celeryTaskLatencyWidgetData(graphState), - ), - [graphState, selectedFilters], + applyCeleryFilterOnWidgetData(selectedFilters || [], celeryTaskLatencyData), + [celeryTaskLatencyData, selectedFilters], ); const onGraphClick = ( From 42f9afd3aacf51bac67057eaa686d3cdd822b307 Mon Sep 17 00:00:00 2001 From: SagarRajput-7 Date: Sun, 26 Jan 2025 23:58:55 +0530 Subject: [PATCH 09/14] feat: changed histogram occurences to bar --- ...eryTaskHistogram.tsx => CeleryTaskBar.tsx} | 25 ++++++++----------- .../CeleryTaskGraph.style.scss | 2 +- .../CeleryTaskGraph/CeleryTaskGraphGrid.tsx | 4 +-- .../CeleryTaskStateGraphConfig.tsx | 16 ++++++------ 4 files changed, 20 insertions(+), 27 deletions(-) rename frontend/src/components/CeleryTask/CeleryTaskGraph/{CeleryTaskHistogram.tsx => CeleryTaskBar.tsx} (85%) diff --git a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskHistogram.tsx b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskBar.tsx similarity index 85% rename from frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskHistogram.tsx rename to frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskBar.tsx index c348bd77ea..ab7bb42d84 100644 --- a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskHistogram.tsx +++ b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskBar.tsx @@ -26,7 +26,7 @@ import { CeleryTaskStateGraphConfig, } from './CeleryTaskStateGraphConfig'; -function CeleryTaskHistogram({ +function CeleryTaskBar({ // onClick, queryEnabled, }: { @@ -61,9 +61,7 @@ function CeleryTaskHistogram({ [dispatch, history, pathname, urlQuery], ); - const [histogramState, setHistogramState] = useState( - CeleryTaskState.All, - ); + const [barState, setBarState] = useState(CeleryTaskState.All); const celeryAllStateData = useMemo( () => celeryAllStateWidgetData(minTime, maxTime), @@ -88,15 +86,12 @@ function CeleryTaskHistogram({ return ( - +
- {histogramState === CeleryTaskState.All && ( + {barState === CeleryTaskState.All && ( )} - {histogramState === CeleryTaskState.Failed && ( + {barState === CeleryTaskState.Failed && ( )} - {histogramState === CeleryTaskState.Retry && ( + {barState === CeleryTaskState.Retry && ( )} - {histogramState === CeleryTaskState.Successful && ( + {barState === CeleryTaskState.Successful && (
- + >; - histogramState: CeleryTaskState; + setBarState: Dispatch>; + barState: CeleryTaskState; }): JSX.Element { const tabs: TabData[] = [ { label: 'All Tasks', key: CeleryTaskState.All }, @@ -30,7 +30,7 @@ function CeleryTaskStateGraphConfig({ ]; const handleTabClick = (key: CeleryTaskState): void => { - setHistogramState(key as CeleryTaskState); + setBarState(key as CeleryTaskState); }; return ( @@ -40,16 +40,14 @@ function CeleryTaskStateGraphConfig({ key={tab.key} onClick={(): void => handleTabClick(tab.key as CeleryTaskState)} className={`celery-task-states__tab ${ - tab.key === histogramState ? 'celery-task-states__tab--selected' : '' + tab.key === barState ? 'celery-task-states__tab--selected' : '' }`} data-last-tab={index === tabs.length - 1} >
{tab.label}
- {tab.key === histogramState && ( -
- )} + {tab.key === barState &&
} ))} From ac9f2cf2f0661823cc1f1e783ca9399a0fc13aad Mon Sep 17 00:00:00 2001 From: SagarRajput-7 Date: Mon, 27 Jan 2025 03:29:01 +0530 Subject: [PATCH 10/14] feat: onclick right panels for celery state bar graphs --- .../CeleryTaskGraph/CeleryTaskBar.tsx | 55 ++++++++++++++++++- .../CeleryTaskGraph/CeleryTaskGraphGrid.tsx | 2 +- .../CeleryTaskGraph/CeleryTaskGraphUtils.ts | 18 +++--- .../GridCard/WidgetGraphComponent.tsx | 2 + .../GridCardLayout/GridCard/index.tsx | 2 + .../GridCardLayout/GridCard/types.ts | 2 + .../container/PanelWrapper/PanelWrapper.tsx | 2 + .../PanelWrapper/UplotPanelWrapper.tsx | 3 + .../PanelWrapper/panelWrapper.types.ts | 1 + .../src/lib/uPlotLib/getUplotChartOptions.ts | 46 +++++++++++----- .../src/lib/uPlotLib/utils/generateColor.ts | 13 +++++ .../src/lib/uPlotLib/utils/getSeriesData.ts | 2 +- 12 files changed, 121 insertions(+), 27 deletions(-) diff --git a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskBar.tsx b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskBar.tsx index ab7bb42d84..0b8b7f131f 100644 --- a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskBar.tsx +++ b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskBar.tsx @@ -7,19 +7,25 @@ import GridCard from 'container/GridCardLayout/GridCard'; import { Card } from 'container/GridCardLayout/styles'; import { useIsDarkMode } from 'hooks/useDarkMode'; import useUrlQuery from 'hooks/useUrlQuery'; +import { getStartAndEndTimesInMilliseconds } from 'pages/MessagingQueues/MessagingQueuesUtils'; import { useCallback, useMemo, 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 { GlobalReducer } from 'types/reducer/globalTime'; -// import { CaptureDataProps } from '../CeleryTaskDetail/CeleryTaskDetail'; +import { CaptureDataProps } from '../CeleryTaskDetail/CeleryTaskDetail'; import { celeryAllStateWidgetData, celeryFailedStateWidgetData, + celeryFailedTasksTableWidgetData, celeryRetryStateWidgetData, + celeryRetryTasksTableWidgetData, + celerySlowestTasksTableWidgetData, celerySuccessStateWidgetData, + celerySuccessTasksTableWidgetData, } from './CeleryTaskGraphUtils'; import { CeleryTaskState, @@ -27,10 +33,10 @@ import { } from './CeleryTaskStateGraphConfig'; function CeleryTaskBar({ - // onClick, + onClick, queryEnabled, }: { - // onClick?: (task: CaptureDataProps) => void; + onClick?: (task: CaptureDataProps) => void; queryEnabled: boolean; }): JSX.Element { @@ -83,6 +89,33 @@ function CeleryTaskBar({ [minTime, maxTime], ); + const onGraphClick = ( + widgetData: Widgets, + xValue: number, + _yValue: number, + _mouseX: number, + _mouseY: number, + data?: { + [key: string]: string; + }, + ): void => { + const { start, end } = getStartAndEndTimesInMilliseconds(xValue); + + // Extract entity and value from data + const [firstDataPoint] = Object.entries(data || {}); + const [entity, value] = (firstDataPoint || ([] as unknown)) as [ + string, + string, + ]; + + onClick?.({ + entity, + value, + timeRange: [start, end], + widgetData, + }); + }; + return ( + onGraphClick(celerySlowestTasksTableWidgetData, ...args) + } /> )} {barState === CeleryTaskState.Failed && ( @@ -105,6 +141,9 @@ function CeleryTaskBar({ headerMenuList={[...ViewMenuAction]} onDragSelect={onDragSelect} isQueryEnabled={queryEnabled} + onClickHandler={(...args): void => + onGraphClick(celeryFailedTasksTableWidgetData, ...args) + } /> )} {barState === CeleryTaskState.Retry && ( @@ -113,6 +152,9 @@ function CeleryTaskBar({ headerMenuList={[...ViewMenuAction]} onDragSelect={onDragSelect} isQueryEnabled={queryEnabled} + onClickHandler={(...args): void => + onGraphClick(celeryRetryTasksTableWidgetData, ...args) + } /> )} {barState === CeleryTaskState.Successful && ( @@ -121,6 +163,9 @@ function CeleryTaskBar({ headerMenuList={[...ViewMenuAction]} onDragSelect={onDragSelect} isQueryEnabled={queryEnabled} + onClickHandler={(...args): void => + onGraphClick(celerySuccessTasksTableWidgetData, ...args) + } /> )}
@@ -128,4 +173,8 @@ function CeleryTaskBar({ ); } +CeleryTaskBar.defaultProps = { + onClick: (): void => {}, +}; + export default CeleryTaskBar; diff --git a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphGrid.tsx b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphGrid.tsx index d01a5ae075..e4accd0d5a 100644 --- a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphGrid.tsx +++ b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphGrid.tsx @@ -68,7 +68,7 @@ export default function CeleryTaskGraphGrid({ return (
- +
)} diff --git a/frontend/src/container/GridCardLayout/GridCard/index.tsx b/frontend/src/container/GridCardLayout/GridCard/index.tsx index 4bb0694ea0..86a4d81fe8 100644 --- a/frontend/src/container/GridCardLayout/GridCard/index.tsx +++ b/frontend/src/container/GridCardLayout/GridCard/index.tsx @@ -40,6 +40,7 @@ function GridCardGraph({ getGraphData, openTracesButton, onOpenTraceBtnClick, + customSeries, }: GridCardGraphProps): JSX.Element { const dispatch = useDispatch(); const [errorMessage, setErrorMessage] = useState(); @@ -254,6 +255,7 @@ function GridCardGraph({ customTooltipElement={customTooltipElement} openTracesButton={openTracesButton} onOpenTraceBtnClick={onOpenTraceBtnClick} + customSeries={customSeries} /> )}
diff --git a/frontend/src/container/GridCardLayout/GridCard/types.ts b/frontend/src/container/GridCardLayout/GridCard/types.ts index 63ff2b566b..181946bc32 100644 --- a/frontend/src/container/GridCardLayout/GridCard/types.ts +++ b/frontend/src/container/GridCardLayout/GridCard/types.ts @@ -35,6 +35,7 @@ export interface WidgetGraphComponentProps { customTooltipElement?: HTMLDivElement; openTracesButton?: boolean; onOpenTraceBtnClick?: (record: RowData) => void; + customSeries?: uPlot.Series[]; } export interface GridCardGraphProps { @@ -51,6 +52,7 @@ export interface GridCardGraphProps { getGraphData?: (graphData?: MetricRangePayloadProps['data']) => void; openTracesButton?: boolean; onOpenTraceBtnClick?: (record: RowData) => void; + customSeries?: uPlot.Series[]; } export interface GetGraphVisibilityStateOnLegendClickProps { diff --git a/frontend/src/container/PanelWrapper/PanelWrapper.tsx b/frontend/src/container/PanelWrapper/PanelWrapper.tsx index 646cff6f43..99a1f23e8d 100644 --- a/frontend/src/container/PanelWrapper/PanelWrapper.tsx +++ b/frontend/src/container/PanelWrapper/PanelWrapper.tsx @@ -19,6 +19,7 @@ function PanelWrapper({ searchTerm, openTracesButton, onOpenTraceBtnClick, + customSeries, }: PanelWrapperProps): JSX.Element { const Component = PanelTypeVsPanelWrapper[ selectedGraph || widget.panelTypes @@ -45,6 +46,7 @@ function PanelWrapper({ searchTerm={searchTerm} openTracesButton={openTracesButton} onOpenTraceBtnClick={onOpenTraceBtnClick} + customSeries={customSeries} /> ); } diff --git a/frontend/src/container/PanelWrapper/UplotPanelWrapper.tsx b/frontend/src/container/PanelWrapper/UplotPanelWrapper.tsx index b297668cc4..07589af9e9 100644 --- a/frontend/src/container/PanelWrapper/UplotPanelWrapper.tsx +++ b/frontend/src/container/PanelWrapper/UplotPanelWrapper.tsx @@ -33,6 +33,7 @@ function UplotPanelWrapper({ onDragSelect, selectedGraph, customTooltipElement, + customSeries, }: PanelWrapperProps): JSX.Element { const { toScrollWidgetId, setToScrollWidgetId } = useDashboard(); const isDarkMode = useIsDarkMode(); @@ -135,6 +136,7 @@ function UplotPanelWrapper({ tzDate: (timestamp: number) => uPlot.tzDate(new Date(timestamp * 1e3), timezone.value), timezone: timezone.value, + customSeries, }), [ widget?.id, @@ -158,6 +160,7 @@ function UplotPanelWrapper({ hiddenGraph, customTooltipElement, timezone.value, + customSeries, ], ); diff --git a/frontend/src/container/PanelWrapper/panelWrapper.types.ts b/frontend/src/container/PanelWrapper/panelWrapper.types.ts index 9c2ca0d7da..b1869108ee 100644 --- a/frontend/src/container/PanelWrapper/panelWrapper.types.ts +++ b/frontend/src/container/PanelWrapper/panelWrapper.types.ts @@ -27,6 +27,7 @@ export type PanelWrapperProps = { customTooltipElement?: HTMLDivElement; openTracesButton?: boolean; onOpenTraceBtnClick?: (record: RowData) => void; + customSeries?: uPlot.Series[]; }; export type TooltipData = { diff --git a/frontend/src/lib/uPlotLib/getUplotChartOptions.ts b/frontend/src/lib/uPlotLib/getUplotChartOptions.ts index ad8bf682e7..2fd6ccb1b0 100644 --- a/frontend/src/lib/uPlotLib/getUplotChartOptions.ts +++ b/frontend/src/lib/uPlotLib/getUplotChartOptions.ts @@ -57,6 +57,7 @@ export interface GetUPlotChartOptions { verticalLineTimestamp?: number; tzDate?: (timestamp: number) => Date; timezone?: string; + customSeries?: uPlot.Series[]; } /** the function converts series A , series B , series C to @@ -162,6 +163,7 @@ export const getUPlotChartOptions = ({ verticalLineTimestamp, tzDate, timezone, + customSeries, }: GetUPlotChartOptions): uPlot.Options => { const timeScaleProps = getXAxisScale(minTimeScale, maxTimeScale); @@ -174,6 +176,22 @@ export const getUPlotChartOptions = ({ const bands = stackBarChart ? getBands(series) : null; + console.log( + getSeries({ + series: + stackBarChart && isUndefined(hiddenGraph) + ? series + : apiResponse?.data?.result, + widgetMetaData: apiResponse?.data.result, + graphsVisibilityStates, + panelType, + currentQuery, + stackBarChart, + hiddenGraph, + isDarkMode, + }), + ); + return { id, width: dimensions.width, @@ -370,19 +388,21 @@ export const getUPlotChartOptions = ({ }, ], }, - series: getSeries({ - series: - stackBarChart && isUndefined(hiddenGraph) - ? series - : apiResponse?.data?.result, - widgetMetaData: apiResponse?.data.result, - graphsVisibilityStates, - panelType, - currentQuery, - stackBarChart, - hiddenGraph, - isDarkMode, - }), + series: Array.isArray(customSeries) + ? customSeries + : getSeries({ + series: + stackBarChart && isUndefined(hiddenGraph) + ? series || [] + : apiResponse?.data?.result || [], + widgetMetaData: apiResponse?.data?.result || [], + graphsVisibilityStates, + panelType, + currentQuery, + stackBarChart, + hiddenGraph, + isDarkMode, + }), axes: getAxes(isDarkMode, yAxisUnit), }; }; diff --git a/frontend/src/lib/uPlotLib/utils/generateColor.ts b/frontend/src/lib/uPlotLib/utils/generateColor.ts index c58fde4e62..9f102fca13 100644 --- a/frontend/src/lib/uPlotLib/utils/generateColor.ts +++ b/frontend/src/lib/uPlotLib/utils/generateColor.ts @@ -1,3 +1,5 @@ +import { Color } from '@signozhq/design-tokens'; + /* eslint-disable no-bitwise */ export function hashFn(str: string): number { let hash = 5381; @@ -12,6 +14,17 @@ export function generateColor( key: string, colorMap: Record, ): string { + if (key === 'SUCCESS') { + return Color.BG_FOREST_500; + } + if (key === 'FAILURE') { + return Color.BG_CHERRY_500; + } + + if (key === 'RETRY') { + return Color.BG_AMBER_400; + } + const hashValue = hashFn(key); const keys = Object.keys(colorMap); const colorIndex = hashValue % keys.length; diff --git a/frontend/src/lib/uPlotLib/utils/getSeriesData.ts b/frontend/src/lib/uPlotLib/utils/getSeriesData.ts index 5de1f6d207..18743c005e 100644 --- a/frontend/src/lib/uPlotLib/utils/getSeriesData.ts +++ b/frontend/src/lib/uPlotLib/utils/getSeriesData.ts @@ -77,7 +77,7 @@ const getSeries = ({ ? hiddenGraph[i] : true, label, - fill: panelType && panelType === PANEL_TYPES.BAR ? `${color}40` : undefined, + fill: panelType && panelType === PANEL_TYPES.BAR ? `${color}80` : undefined, stroke: color, width: 2, spanGaps: true, From b3dc0dc98c64a966d0c8591c6669ee48a6419cc2 Mon Sep 17 00:00:00 2001 From: SagarRajput-7 Date: Mon, 27 Jan 2025 03:53:03 +0530 Subject: [PATCH 11/14] feat: pagesetup and tabs with kafka setup --- frontend/src/AppRoutes/pageComponents.ts | 2 +- frontend/src/AppRoutes/routes.ts | 5 +- .../MessagingQueuesMainPage.styles.scss | 52 +++++++++++++++++++ .../MessagingQueuesMainPage.tsx | 45 ++++++++++++++++ frontend/src/pages/MessagingQueues/index.tsx | 4 +- 5 files changed, 102 insertions(+), 6 deletions(-) create mode 100644 frontend/src/pages/MessagingQueues/MessagingQueuesMainPage.styles.scss create mode 100644 frontend/src/pages/MessagingQueues/MessagingQueuesMainPage.tsx diff --git a/frontend/src/AppRoutes/pageComponents.ts b/frontend/src/AppRoutes/pageComponents.ts index cafbbd2ba4..55edfc54a7 100644 --- a/frontend/src/AppRoutes/pageComponents.ts +++ b/frontend/src/AppRoutes/pageComponents.ts @@ -229,7 +229,7 @@ export const InstalledIntegrations = Loadable( ), ); -export const MessagingQueues = Loadable( +export const MessagingQueuesMainPage = Loadable( () => import(/* webpackChunkName: "MessagingQueues" */ 'pages/MessagingQueues'), ); diff --git a/frontend/src/AppRoutes/routes.ts b/frontend/src/AppRoutes/routes.ts index 998ba3e34a..5a259e3968 100644 --- a/frontend/src/AppRoutes/routes.ts +++ b/frontend/src/AppRoutes/routes.ts @@ -1,4 +1,5 @@ import ROUTES from 'constants/routes'; +import MessagingQueues from 'pages/MessagingQueues'; import { RouteProps } from 'react-router-dom'; import { @@ -8,7 +9,6 @@ import { AllErrors, APIKeys, BillingPage, - CeleryTask, CreateAlertChannelAlerts, CreateNewAlerts, CustomDomainSettings, @@ -28,7 +28,6 @@ import { LogsExplorer, LogsIndexToFields, LogsSaveViews, - MessagingQueues, MQDetailPage, MySettings, NewDashboardPage, @@ -405,7 +404,7 @@ const routes: AppRoutes[] = [ { path: ROUTES.MESSAGING_QUEUES_CELERY_TASK, exact: true, - component: CeleryTask, + component: MessagingQueues, key: 'MESSAGING_QUEUES_CELERY_TASK', isPrivate: true, }, diff --git a/frontend/src/pages/MessagingQueues/MessagingQueuesMainPage.styles.scss b/frontend/src/pages/MessagingQueues/MessagingQueuesMainPage.styles.scss new file mode 100644 index 0000000000..e1cda241d6 --- /dev/null +++ b/frontend/src/pages/MessagingQueues/MessagingQueuesMainPage.styles.scss @@ -0,0 +1,52 @@ +.messaging-queues-module-container { + flex: 1; + display: flex; + flex-direction: column; + height: 100%; + + .ant-tabs { + height: 100%; + } + + .ant-tabs-nav { + padding: 0 8px; + margin-bottom: 0px; + + &::before { + border-bottom: 1px solid var(--bg-slate-400) !important; + } + } + + .ant-tabs-content-holder { + display: flex; + + .ant-tabs-content { + flex: 1; + display: flex; + flex-direction: column; + + .ant-tabs-tabpane { + flex: 1; + display: flex; + flex-direction: column; + } + } + } + + .tab-item { + display: flex; + justify-content: center; + align-items: center; + gap: 8px; + } +} + +.lightMode { + .messaging-queues-module-container { + .ant-tabs-nav { + &::before { + border-bottom: 1px solid var(--bg-vanilla-300) !important; + } + } + } +} diff --git a/frontend/src/pages/MessagingQueues/MessagingQueuesMainPage.tsx b/frontend/src/pages/MessagingQueues/MessagingQueuesMainPage.tsx new file mode 100644 index 0000000000..2e437391a7 --- /dev/null +++ b/frontend/src/pages/MessagingQueues/MessagingQueuesMainPage.tsx @@ -0,0 +1,45 @@ +import './MessagingQueuesMainPage.styles.scss'; + +import RouteTab from 'components/RouteTab'; +import { TabRoutes } from 'components/RouteTab/types'; +import ROUTES from 'constants/routes'; +import history from 'lib/history'; +import { Inbox } from 'lucide-react'; +import { useLocation } from 'react-use'; + +import CeleryTask from '../Celery/CeleryTask/CeleryTask'; +import MessagingQueues from './MessagingQueues'; + +export const Kafka: TabRoutes = { + Component: MessagingQueues, + name: ( +
+ Kafka +
+ ), + route: ROUTES.MESSAGING_QUEUES, + key: ROUTES.MESSAGING_QUEUES, +}; + +export const Celery: TabRoutes = { + Component: CeleryTask, + name: ( +
+ Celery Task +
+ ), + route: ROUTES.MESSAGING_QUEUES_CELERY_TASK, + key: ROUTES.MESSAGING_QUEUES_CELERY_TASK, +}; + +export default function MessagingQueuesMainPage(): JSX.Element { + const { pathname } = useLocation(); + + const routes: TabRoutes[] = [Kafka, Celery]; + + return ( +
+ +
+ ); +} diff --git a/frontend/src/pages/MessagingQueues/index.tsx b/frontend/src/pages/MessagingQueues/index.tsx index cc59152b17..fbde0ac648 100644 --- a/frontend/src/pages/MessagingQueues/index.tsx +++ b/frontend/src/pages/MessagingQueues/index.tsx @@ -1,3 +1,3 @@ -import MessagingQueues from './MessagingQueues'; +import MessagingQueuesMainPage from './MessagingQueuesMainPage'; -export default MessagingQueues; +export default MessagingQueuesMainPage; From 0bf2a84235268daaae0385da8245e351f7110e8e Mon Sep 17 00:00:00 2001 From: SagarRajput-7 Date: Mon, 27 Jan 2025 04:25:09 +0530 Subject: [PATCH 12/14] feat: custom series for bar for color generation --- .../CeleryTaskGraph/CeleryTaskBar.tsx | 55 +++++++++++++++++++ .../CeleryTaskGraph.style.scss | 1 + .../CeleryTaskGraph/CeleryTaskGraphUtils.ts | 3 - .../src/components/CeleryTask/CeleryUtils.ts | 19 ++++++- .../GridCardLayout/GridCard/types.ts | 5 +- .../PanelWrapper/panelWrapper.types.ts | 3 +- .../src/lib/uPlotLib/getUplotChartOptions.ts | 22 +------- .../src/lib/uPlotLib/utils/generateColor.ts | 14 +---- .../pages/Celery/CeleryTask/CeleryTask.tsx | 6 -- .../pages/MessagingQueues/MessagingQueues.tsx | 5 -- .../MessagingQueuesMainPage.tsx | 6 +- 11 files changed, 86 insertions(+), 53 deletions(-) diff --git a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskBar.tsx b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskBar.tsx index 0b8b7f131f..278cb31494 100644 --- a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskBar.tsx +++ b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskBar.tsx @@ -1,12 +1,16 @@ import './CeleryTaskGraph.style.scss'; +import { Color } from '@signozhq/design-tokens'; import { QueryParams } from 'constants/query'; import { PANEL_TYPES } from 'constants/queryBuilder'; +import { themeColors } from 'constants/theme'; 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 getLabelName from 'lib/getLabelName'; +import { generateColor } from 'lib/uPlotLib/utils/generateColor'; import { getStartAndEndTimesInMilliseconds } from 'pages/MessagingQueues/MessagingQueuesUtils'; import { useCallback, useMemo, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; @@ -14,9 +18,11 @@ 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 { QueryData } from 'types/api/widgets/getQuery'; import { GlobalReducer } from 'types/reducer/globalTime'; import { CaptureDataProps } from '../CeleryTaskDetail/CeleryTaskDetail'; +import { paths } from '../CeleryUtils'; import { celeryAllStateWidgetData, celeryFailedStateWidgetData, @@ -116,6 +122,51 @@ function CeleryTaskBar({ }); }; + const getGraphSeries = (color: string, label: string): any => ({ + drawStyle: 'bars', + paths, + lineInterpolation: 'spline', + show: true, + label, + fill: `${color}90`, + stroke: color, + width: 2, + spanGaps: true, + points: { + size: 5, + show: false, + stroke: color, + }, + }); + + const customSeries = (data: QueryData[]): uPlot.Series[] => { + console.log(data); + const configurations: uPlot.Series[] = [ + { label: 'Timestamp', stroke: 'purple' }, + ]; + for (let i = 0; i < data.length; i += 1) { + const { metric = {}, queryName = '', legend = '' } = data[i] || {}; + const label = getLabelName(metric, queryName || '', legend || ''); + let color = generateColor( + label, + isDarkMode ? themeColors.chartcolors : themeColors.lightModeColor, + ); + if (label === 'SUCCESS') { + color = Color.BG_FOREST_500; + } + if (label === 'FAILURE') { + color = Color.BG_CHERRY_500; + } + + if (label === 'RETRY') { + color = Color.BG_AMBER_400; + } + const series = getGraphSeries(color, label); + configurations.push(series); + } + return configurations; + }; + return ( onGraphClick(celerySlowestTasksTableWidgetData, ...args) } + customSeries={customSeries} /> )} {barState === CeleryTaskState.Failed && ( @@ -144,6 +196,7 @@ function CeleryTaskBar({ onClickHandler={(...args): void => onGraphClick(celeryFailedTasksTableWidgetData, ...args) } + customSeries={customSeries} /> )} {barState === CeleryTaskState.Retry && ( @@ -155,6 +208,7 @@ function CeleryTaskBar({ onClickHandler={(...args): void => onGraphClick(celeryRetryTasksTableWidgetData, ...args) } + customSeries={customSeries} /> )} {barState === CeleryTaskState.Successful && ( @@ -166,6 +220,7 @@ function CeleryTaskBar({ onClickHandler={(...args): void => onGraphClick(celerySuccessTasksTableWidgetData, ...args) } + customSeries={customSeries} /> )}
diff --git a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraph.style.scss b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraph.style.scss index 4b4d882d15..dfb66e2f49 100644 --- a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraph.style.scss +++ b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraph.style.scss @@ -101,6 +101,7 @@ font-size: 14px; color: var(--bg-vanilla-400); line-height: 20px; + font-weight: 500; } &__value { diff --git a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphUtils.ts b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphUtils.ts index 988a0639be..2e963c9740 100644 --- a/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphUtils.ts +++ b/frontend/src/components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphUtils.ts @@ -11,9 +11,6 @@ import { v4 as uuidv4 } from 'uuid'; export const getStepInterval = (startTime: number, endTime: number): number => { const diffInMinutes = (endTime - startTime) / 1000000 / (60 * 1000); // Convert to minutes - console.log('startTime', startTime); - console.log('diffInMinutes', diffInMinutes); - if (diffInMinutes <= 15) return 60; // 15 min or less if (diffInMinutes <= 30) return 60; // 30 min or less if (diffInMinutes <= 60) return 120; // 1 hour or less diff --git a/frontend/src/components/CeleryTask/CeleryUtils.ts b/frontend/src/components/CeleryTask/CeleryUtils.ts index a6d27a796b..93f1ef7629 100644 --- a/frontend/src/components/CeleryTask/CeleryUtils.ts +++ b/frontend/src/components/CeleryTask/CeleryUtils.ts @@ -1,5 +1,6 @@ import { QueryParams } from 'constants/query'; import { History, Location } from 'history'; +import getRenderer from 'lib/uPlotLib/utils/getRenderer'; import { Widgets } from 'types/api/dashboard/getAll'; import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData'; @@ -51,7 +52,6 @@ export function applyCeleryFilterOnWidgetData( filters: TagFilterItem[], widgetData: Widgets, ): Widgets { - console.log(filters, widgetData); return { ...widgetData, query: { @@ -73,3 +73,20 @@ export function applyCeleryFilterOnWidgetData( }, }; } + +export const paths = ( + u: any, + seriesIdx: number, + idx0: number, + idx1: number, + extendGap: boolean, + buildClip: boolean, +): uPlot.Series.PathBuilder => { + const s = u.series[seriesIdx]; + const style = s.drawStyle; + const interp = s.lineInterpolation; + + const renderer = getRenderer(style, interp); + + return renderer(u, seriesIdx, idx0, idx1, extendGap, buildClip); +}; diff --git a/frontend/src/container/GridCardLayout/GridCard/types.ts b/frontend/src/container/GridCardLayout/GridCard/types.ts index 181946bc32..54c9d44c1c 100644 --- a/frontend/src/container/GridCardLayout/GridCard/types.ts +++ b/frontend/src/container/GridCardLayout/GridCard/types.ts @@ -7,6 +7,7 @@ import { UseQueryResult } from 'react-query'; import { SuccessResponse } from 'types/api'; import { Dashboard, Widgets } from 'types/api/dashboard/getAll'; import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange'; +import { QueryData } from 'types/api/widgets/getQuery'; import uPlot from 'uplot'; import { MenuItemKeys } from '../WidgetHeader/contants'; @@ -35,7 +36,7 @@ export interface WidgetGraphComponentProps { customTooltipElement?: HTMLDivElement; openTracesButton?: boolean; onOpenTraceBtnClick?: (record: RowData) => void; - customSeries?: uPlot.Series[]; + customSeries?: (data: QueryData[]) => uPlot.Series[]; } export interface GridCardGraphProps { @@ -52,7 +53,7 @@ export interface GridCardGraphProps { getGraphData?: (graphData?: MetricRangePayloadProps['data']) => void; openTracesButton?: boolean; onOpenTraceBtnClick?: (record: RowData) => void; - customSeries?: uPlot.Series[]; + customSeries?: (data: QueryData[]) => uPlot.Series[]; } export interface GetGraphVisibilityStateOnLegendClickProps { diff --git a/frontend/src/container/PanelWrapper/panelWrapper.types.ts b/frontend/src/container/PanelWrapper/panelWrapper.types.ts index b1869108ee..e1983a5b69 100644 --- a/frontend/src/container/PanelWrapper/panelWrapper.types.ts +++ b/frontend/src/container/PanelWrapper/panelWrapper.types.ts @@ -7,6 +7,7 @@ import { UseQueryResult } from 'react-query'; import { SuccessResponse } from 'types/api'; import { Widgets } from 'types/api/dashboard/getAll'; import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange'; +import { QueryData } from 'types/api/widgets/getQuery'; export type PanelWrapperProps = { queryResponse: UseQueryResult< @@ -27,7 +28,7 @@ export type PanelWrapperProps = { customTooltipElement?: HTMLDivElement; openTracesButton?: boolean; onOpenTraceBtnClick?: (record: RowData) => void; - customSeries?: uPlot.Series[]; + customSeries?: (data: QueryData[]) => uPlot.Series[]; }; export type TooltipData = { diff --git a/frontend/src/lib/uPlotLib/getUplotChartOptions.ts b/frontend/src/lib/uPlotLib/getUplotChartOptions.ts index 2fd6ccb1b0..df7d6547e3 100644 --- a/frontend/src/lib/uPlotLib/getUplotChartOptions.ts +++ b/frontend/src/lib/uPlotLib/getUplotChartOptions.ts @@ -57,7 +57,7 @@ export interface GetUPlotChartOptions { verticalLineTimestamp?: number; tzDate?: (timestamp: number) => Date; timezone?: string; - customSeries?: uPlot.Series[]; + customSeries?: (data: QueryData[]) => uPlot.Series[]; } /** the function converts series A , series B , series C to @@ -176,22 +176,6 @@ export const getUPlotChartOptions = ({ const bands = stackBarChart ? getBands(series) : null; - console.log( - getSeries({ - series: - stackBarChart && isUndefined(hiddenGraph) - ? series - : apiResponse?.data?.result, - widgetMetaData: apiResponse?.data.result, - graphsVisibilityStates, - panelType, - currentQuery, - stackBarChart, - hiddenGraph, - isDarkMode, - }), - ); - return { id, width: dimensions.width, @@ -388,8 +372,8 @@ export const getUPlotChartOptions = ({ }, ], }, - series: Array.isArray(customSeries) - ? customSeries + series: customSeries + ? customSeries(apiResponse?.data?.result || []) : getSeries({ series: stackBarChart && isUndefined(hiddenGraph) diff --git a/frontend/src/lib/uPlotLib/utils/generateColor.ts b/frontend/src/lib/uPlotLib/utils/generateColor.ts index 9f102fca13..8e7b96997d 100644 --- a/frontend/src/lib/uPlotLib/utils/generateColor.ts +++ b/frontend/src/lib/uPlotLib/utils/generateColor.ts @@ -1,6 +1,5 @@ -import { Color } from '@signozhq/design-tokens'; - /* eslint-disable no-bitwise */ + export function hashFn(str: string): number { let hash = 5381; for (let i = 0; i < str.length; i++) { @@ -14,17 +13,6 @@ export function generateColor( key: string, colorMap: Record, ): string { - if (key === 'SUCCESS') { - return Color.BG_FOREST_500; - } - if (key === 'FAILURE') { - return Color.BG_CHERRY_500; - } - - if (key === 'RETRY') { - return Color.BG_AMBER_400; - } - const hashValue = hashFn(key); const keys = Object.keys(colorMap); const colorIndex = hashValue % keys.length; diff --git a/frontend/src/pages/Celery/CeleryTask/CeleryTask.tsx b/frontend/src/pages/Celery/CeleryTask/CeleryTask.tsx index b33040ced1..fccd934a61 100644 --- a/frontend/src/pages/Celery/CeleryTask/CeleryTask.tsx +++ b/frontend/src/pages/Celery/CeleryTask/CeleryTask.tsx @@ -6,7 +6,6 @@ import CeleryTaskDetail, { } from 'components/CeleryTask/CeleryTaskDetail/CeleryTaskDetail'; import CeleryTaskGraphGrid from 'components/CeleryTask/CeleryTaskGraph/CeleryTaskGraphGrid'; import DateTimeSelectionV2 from 'container/TopNav/DateTimeSelectionV2'; -import { ListMinus } from 'lucide-react'; import { useState } from 'react'; export default function CeleryTask(): JSX.Element { @@ -14,15 +13,10 @@ export default function CeleryTask(): JSX.Element { const onTaskClick = (captureData: CaptureDataProps): void => { setTask(captureData); - console.log(captureData); }; return (
-
- - Messaging Queues / Celery Task -

Celery Task

diff --git a/frontend/src/pages/MessagingQueues/MessagingQueues.tsx b/frontend/src/pages/MessagingQueues/MessagingQueues.tsx index a7e8681e9c..9829ffc6e3 100644 --- a/frontend/src/pages/MessagingQueues/MessagingQueues.tsx +++ b/frontend/src/pages/MessagingQueues/MessagingQueues.tsx @@ -8,7 +8,6 @@ import MessagingQueueHealthCheck from 'components/MessagingQueueHealthCheck/Mess import { QueryParams } from 'constants/query'; import ROUTES from 'constants/routes'; import DateTimeSelectionV2 from 'container/TopNav/DateTimeSelectionV2'; -import { ListMinus } from 'lucide-react'; import { useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { useHistory } from 'react-router-dom'; @@ -55,10 +54,6 @@ function MessagingQueues(): JSX.Element { return (
-
- - {t('breadcrumb')} -
{t('header')} / diff --git a/frontend/src/pages/MessagingQueues/MessagingQueuesMainPage.tsx b/frontend/src/pages/MessagingQueues/MessagingQueuesMainPage.tsx index 2e437391a7..8fe5976318 100644 --- a/frontend/src/pages/MessagingQueues/MessagingQueuesMainPage.tsx +++ b/frontend/src/pages/MessagingQueues/MessagingQueuesMainPage.tsx @@ -4,7 +4,7 @@ import RouteTab from 'components/RouteTab'; import { TabRoutes } from 'components/RouteTab/types'; import ROUTES from 'constants/routes'; import history from 'lib/history'; -import { Inbox } from 'lucide-react'; +import { ListMinus, Rows3 } from 'lucide-react'; import { useLocation } from 'react-use'; import CeleryTask from '../Celery/CeleryTask/CeleryTask'; @@ -14,7 +14,7 @@ export const Kafka: TabRoutes = { Component: MessagingQueues, name: (
- Kafka + Kafka
), route: ROUTES.MESSAGING_QUEUES, @@ -25,7 +25,7 @@ export const Celery: TabRoutes = { Component: CeleryTask, name: (
- Celery Task + Celery Task
), route: ROUTES.MESSAGING_QUEUES_CELERY_TASK, From 10812f57e3b62543e7e48c1d53f05cf03c6f5f6c Mon Sep 17 00:00:00 2001 From: SagarRajput-7 Date: Mon, 27 Jan 2025 04:32:21 +0530 Subject: [PATCH 13/14] feat: fixed test cases --- frontend/src/lib/uPlotLib/utils/getSeriesData.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/lib/uPlotLib/utils/getSeriesData.ts b/frontend/src/lib/uPlotLib/utils/getSeriesData.ts index 18743c005e..5de1f6d207 100644 --- a/frontend/src/lib/uPlotLib/utils/getSeriesData.ts +++ b/frontend/src/lib/uPlotLib/utils/getSeriesData.ts @@ -77,7 +77,7 @@ const getSeries = ({ ? hiddenGraph[i] : true, label, - fill: panelType && panelType === PANEL_TYPES.BAR ? `${color}80` : undefined, + fill: panelType && panelType === PANEL_TYPES.BAR ? `${color}40` : undefined, stroke: color, width: 2, spanGaps: true, From acb2731e7fab65adf1ab25e5e664a3d1c5e10435 Mon Sep 17 00:00:00 2001 From: SagarRajput-7 Date: Mon, 27 Jan 2025 04:42:48 +0530 Subject: [PATCH 14/14] feat: update styles --- frontend/src/pages/MessagingQueues/MessagingQueues.styles.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/pages/MessagingQueues/MessagingQueues.styles.scss b/frontend/src/pages/MessagingQueues/MessagingQueues.styles.scss index 9edcd928a3..6a37ed959b 100644 --- a/frontend/src/pages/MessagingQueues/MessagingQueues.styles.scss +++ b/frontend/src/pages/MessagingQueues/MessagingQueues.styles.scss @@ -93,7 +93,7 @@ } .mq-graph { - height: 420px; + height: 420px !important; padding: 24px 24px 0 24px; }