From cb1cd3555b3b63bdb441512dacdebf2599db67d7 Mon Sep 17 00:00:00 2001 From: SagarRajput-7 <162284829+SagarRajput-7@users.noreply.github.com> Date: Fri, 20 Sep 2024 16:36:35 +0530 Subject: [PATCH] feat: added global search on table panel (#5893) * feat: added global search on table panel * feat: added global search on table panel * feat: added global search conditionally and with new design * feat: removed state from datasource * feat: added global search in full view * feat: added lightMode styles * feat: added test cases for querytable and widgetHeader - global search --- .../FullView/WidgetFullView.styles.scss | 19 + .../GridCard/FullView/index.tsx | 25 +- .../GridCard/WidgetGraphComponent.tsx | 4 + .../WidgetHeader/WidgetHeader.styles.scss | 23 +- .../GridCardLayout/WidgetHeader/index.tsx | 124 ++- .../src/container/GridTableComponent/types.ts | 1 + .../container/PanelWrapper/PanelWrapper.tsx | 2 + .../PanelWrapper/TablePanelWrapper.tsx | 2 + .../PanelWrapper/panelWrapper.types.ts | 1 + .../QueryTable/QueryTable.intefaces.ts | 1 + .../src/container/QueryTable/QueryTable.tsx | 31 +- .../QueryTable/__test__/QueryTable.test.tsx | 73 ++ .../container/QueryTable/__test__/mocks.ts | 797 ++++++++++++++++++ 13 files changed, 1056 insertions(+), 47 deletions(-) create mode 100644 frontend/src/container/QueryTable/__test__/QueryTable.test.tsx create mode 100644 frontend/src/container/QueryTable/__test__/mocks.ts diff --git a/frontend/src/container/GridCardLayout/GridCard/FullView/WidgetFullView.styles.scss b/frontend/src/container/GridCardLayout/GridCard/FullView/WidgetFullView.styles.scss index 29d578f096..78c4459929 100644 --- a/frontend/src/container/GridCardLayout/GridCard/FullView/WidgetFullView.styles.scss +++ b/frontend/src/container/GridCardLayout/GridCard/FullView/WidgetFullView.styles.scss @@ -15,6 +15,13 @@ box-sizing: border-box; margin: 16px 0; border-radius: 3px; + + .global-search { + .ant-input-group-addon { + border: none; + background-color: var(--bg-ink-300); + } + } } .height-widget { @@ -55,3 +62,15 @@ } } } + +.lightMode { + .full-view-container { + .graph-container { + .global-search { + .ant-input-group-addon { + background-color: var(--bg-vanilla-200); + } + } + } + } +} diff --git a/frontend/src/container/GridCardLayout/GridCard/FullView/index.tsx b/frontend/src/container/GridCardLayout/GridCard/FullView/index.tsx index 974a35a39c..d682af12a8 100644 --- a/frontend/src/container/GridCardLayout/GridCard/FullView/index.tsx +++ b/frontend/src/container/GridCardLayout/GridCard/FullView/index.tsx @@ -1,7 +1,11 @@ import './WidgetFullView.styles.scss'; -import { LoadingOutlined, SyncOutlined } from '@ant-design/icons'; -import { Button, Spin } from 'antd'; +import { + LoadingOutlined, + SearchOutlined, + SyncOutlined, +} from '@ant-design/icons'; +import { Button, Input, Spin } from 'antd'; import cx from 'classnames'; import { ToggleGraphProps } from 'components/Graph/types'; import Spinner from 'components/Spinner'; @@ -172,6 +176,10 @@ function FullView({ const isListView = widget.panelTypes === PANEL_TYPES.LIST; + const isTablePanel = widget.panelTypes === PANEL_TYPES.TABLE; + + const [searchTerm, setSearchTerm] = useState(''); + if (response.isLoading && widget.panelTypes !== PANEL_TYPES.LIST) { return ; } @@ -216,6 +224,18 @@ function FullView({ }} isGraphLegendToggleAvailable={canModifyChart} > + {isTablePanel && ( + } + className="global-search" + placeholder="Search..." + allowClear + key={widget.id} + onChange={(e): void => { + setSearchTerm(e.target.value || ''); + }} + /> + )} diff --git a/frontend/src/container/GridCardLayout/GridCard/WidgetGraphComponent.tsx b/frontend/src/container/GridCardLayout/GridCard/WidgetGraphComponent.tsx index b76c7c9f73..4d5c7fa94c 100644 --- a/frontend/src/container/GridCardLayout/GridCard/WidgetGraphComponent.tsx +++ b/frontend/src/container/GridCardLayout/GridCard/WidgetGraphComponent.tsx @@ -234,6 +234,8 @@ function WidgetGraphComponent({ }); }; + const [searchTerm, setSearchTerm] = useState(''); + const loadingState = (queryResponse.isLoading || queryResponse.status === 'idle') && widget.panelTypes !== PANEL_TYPES.LIST; @@ -317,6 +319,7 @@ function WidgetGraphComponent({ isWarning={isWarning} isFetchingResponse={isFetchingResponse} tableProcessedDataRef={tableProcessedDataRef} + setSearchTerm={setSearchTerm} /> {queryResponse.isLoading && widget.panelTypes !== PANEL_TYPES.LIST && ( @@ -337,6 +340,7 @@ function WidgetGraphComponent({ onDragSelect={onDragSelect} tableProcessedDataRef={tableProcessedDataRef} customTooltipElement={customTooltipElement} + searchTerm={searchTerm} /> )} diff --git a/frontend/src/container/GridCardLayout/WidgetHeader/WidgetHeader.styles.scss b/frontend/src/container/GridCardLayout/WidgetHeader/WidgetHeader.styles.scss index 2fcb3e8e6f..11659e9a3e 100644 --- a/frontend/src/container/GridCardLayout/WidgetHeader/WidgetHeader.styles.scss +++ b/frontend/src/container/GridCardLayout/WidgetHeader/WidgetHeader.styles.scss @@ -2,7 +2,7 @@ display: flex; justify-content: space-between; align-items: center; - height: 30px; + height: 36px; width: 100%; padding: 0.5rem; box-sizing: border-box; @@ -10,6 +10,14 @@ font-weight: 600; cursor: move; + + .ant-input-group-addon { + border: none; + background-color: var(--bg-ink-500); + } + .search-header-icons { + cursor: pointer; + } } .widget-header-title { @@ -19,6 +27,7 @@ .widget-header-actions { display: flex; align-items: center; + gap: 8px; } .widget-header-more-options { visibility: hidden; @@ -30,6 +39,10 @@ padding: 8px; } +.widget-header-more-options-visible { + visibility: visible; +} + .widget-header-hover { visibility: visible; } @@ -37,3 +50,11 @@ .widget-api-actions { padding-right: 0.25rem; } + +.lightMode { + .widget-header-container { + .ant-input-group-addon { + background-color: inherit; + } + } +} diff --git a/frontend/src/container/GridCardLayout/WidgetHeader/index.tsx b/frontend/src/container/GridCardLayout/WidgetHeader/index.tsx index 7daa4e553d..d4aa6a4c09 100644 --- a/frontend/src/container/GridCardLayout/WidgetHeader/index.tsx +++ b/frontend/src/container/GridCardLayout/WidgetHeader/index.tsx @@ -9,9 +9,10 @@ import { ExclamationCircleOutlined, FullscreenOutlined, MoreOutlined, + SearchOutlined, WarningOutlined, } from '@ant-design/icons'; -import { Dropdown, MenuProps, Tooltip, Typography } from 'antd'; +import { Dropdown, Input, MenuProps, Tooltip, Typography } from 'antd'; import Spinner from 'components/Spinner'; import { QueryParams } from 'constants/query'; import { PANEL_TYPES } from 'constants/queryBuilder'; @@ -20,8 +21,9 @@ import useComponentPermission from 'hooks/useComponentPermission'; import history from 'lib/history'; import { RowData } from 'lib/query/createTableColumnsFromQuery'; import { isEmpty } from 'lodash-es'; +import { X } from 'lucide-react'; import { unparse } from 'papaparse'; -import { ReactNode, useCallback, useMemo } from 'react'; +import { ReactNode, useCallback, useMemo, useState } from 'react'; import { UseQueryResult } from 'react-query'; import { useSelector } from 'react-redux'; import { AppState } from 'store/reducers'; @@ -51,6 +53,7 @@ interface IWidgetHeaderProps { isWarning: boolean; isFetchingResponse: boolean; tableProcessedDataRef: React.MutableRefObject; + setSearchTerm: React.Dispatch>; } function WidgetHeader({ @@ -67,6 +70,7 @@ function WidgetHeader({ isWarning, isFetchingResponse, tableProcessedDataRef, + setSearchTerm, }: IWidgetHeaderProps): JSX.Element | null { const onEditHandler = useCallback((): void => { const widgetId = widget.id; @@ -187,6 +191,10 @@ function WidgetHeader({ const updatedMenuList = useMemo(() => generateMenuList(actions), [actions]); + const [showGlobalSearch, setShowGlobalSearch] = useState(false); + + const globalSearchAvailable = widget.panelTypes === PANEL_TYPES.TABLE; + const menu = useMemo( () => ({ items: updatedMenuList, @@ -201,46 +209,80 @@ function WidgetHeader({ return (
- - {title} - -
-
{threshold}
- {isFetchingResponse && !queryResponse.isError && ( - - )} - {queryResponse.isError && ( - } + placeholder="Search..." + bordered={false} + data-testid="widget-header-search-input" + autoFocus + addonAfter={ + { + e.stopPropagation(); + e.preventDefault(); + setShowGlobalSearch(false); + }} + className="search-header-icons" + /> + } + key={widget.id} + onChange={(e): void => { + setSearchTerm(e.target.value || ''); + }} + /> + ) : ( + <> + - - - )} - - {isWarning && ( - - - - )} - - - -
+ {title} + +
+
{threshold}
+ {isFetchingResponse && !queryResponse.isError && ( + + )} + {queryResponse.isError && ( + + + + )} + + {isWarning && ( + + + + )} + {globalSearchAvailable && ( + setShowGlobalSearch(true)} + data-testid="widget-header-search" + /> + )} + + + +
+ + )}
); } diff --git a/frontend/src/container/GridTableComponent/types.ts b/frontend/src/container/GridTableComponent/types.ts index 6088f9dcb8..883e280b38 100644 --- a/frontend/src/container/GridTableComponent/types.ts +++ b/frontend/src/container/GridTableComponent/types.ts @@ -14,6 +14,7 @@ export type GridTableComponentProps = { columnUnits?: ColumnUnit; tableProcessedDataRef?: React.MutableRefObject; sticky?: TableProps['sticky']; + searchTerm?: string; } & Pick & Omit, 'columns' | 'dataSource'>; diff --git a/frontend/src/container/PanelWrapper/PanelWrapper.tsx b/frontend/src/container/PanelWrapper/PanelWrapper.tsx index ed105b3948..2f5b35485e 100644 --- a/frontend/src/container/PanelWrapper/PanelWrapper.tsx +++ b/frontend/src/container/PanelWrapper/PanelWrapper.tsx @@ -16,6 +16,7 @@ function PanelWrapper({ selectedGraph, tableProcessedDataRef, customTooltipElement, + searchTerm, }: PanelWrapperProps): JSX.Element { const Component = PanelTypeVsPanelWrapper[ selectedGraph || widget.panelTypes @@ -39,6 +40,7 @@ function PanelWrapper({ selectedGraph={selectedGraph} tableProcessedDataRef={tableProcessedDataRef} customTooltipElement={customTooltipElement} + searchTerm={searchTerm} /> ); } diff --git a/frontend/src/container/PanelWrapper/TablePanelWrapper.tsx b/frontend/src/container/PanelWrapper/TablePanelWrapper.tsx index 0eab4143a2..c5222e8d53 100644 --- a/frontend/src/container/PanelWrapper/TablePanelWrapper.tsx +++ b/frontend/src/container/PanelWrapper/TablePanelWrapper.tsx @@ -8,6 +8,7 @@ function TablePanelWrapper({ widget, queryResponse, tableProcessedDataRef, + searchTerm, }: PanelWrapperProps): JSX.Element { const panelData = (queryResponse.data?.payload?.data?.result?.[0] as any)?.table || []; @@ -20,6 +21,7 @@ function TablePanelWrapper({ columnUnits={widget.columnUnits} tableProcessedDataRef={tableProcessedDataRef} sticky={widget.panelTypes === PANEL_TYPES.TABLE} + searchTerm={searchTerm} // eslint-disable-next-line react/jsx-props-no-spreading {...GRID_TABLE_CONFIG} /> diff --git a/frontend/src/container/PanelWrapper/panelWrapper.types.ts b/frontend/src/container/PanelWrapper/panelWrapper.types.ts index 7d5e3122e8..4778ffdb97 100644 --- a/frontend/src/container/PanelWrapper/panelWrapper.types.ts +++ b/frontend/src/container/PanelWrapper/panelWrapper.types.ts @@ -23,6 +23,7 @@ export type PanelWrapperProps = { onDragSelect: (start: number, end: number) => void; selectedGraph?: PANEL_TYPES; tableProcessedDataRef?: React.MutableRefObject; + searchTerm?: string; customTooltipElement?: HTMLDivElement; }; diff --git a/frontend/src/container/QueryTable/QueryTable.intefaces.ts b/frontend/src/container/QueryTable/QueryTable.intefaces.ts index 7576d796ec..254e4885e7 100644 --- a/frontend/src/container/QueryTable/QueryTable.intefaces.ts +++ b/frontend/src/container/QueryTable/QueryTable.intefaces.ts @@ -19,4 +19,5 @@ export type QueryTableProps = Omit< columns?: ColumnsType; dataSource?: RowData[]; sticky?: TableProps['sticky']; + searchTerm?: string; }; diff --git a/frontend/src/container/QueryTable/QueryTable.tsx b/frontend/src/container/QueryTable/QueryTable.tsx index 1786e5d4e3..e438070173 100644 --- a/frontend/src/container/QueryTable/QueryTable.tsx +++ b/frontend/src/container/QueryTable/QueryTable.tsx @@ -3,8 +3,11 @@ import './QueryTable.styles.scss'; import { ResizeTable } from 'components/ResizeTable'; import Download from 'container/Download/Download'; import { IServiceName } from 'container/MetricsApplication/Tabs/types'; -import { createTableColumnsFromQuery } from 'lib/query/createTableColumnsFromQuery'; -import { useMemo } from 'react'; +import { + createTableColumnsFromQuery, + RowData, +} from 'lib/query/createTableColumnsFromQuery'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import { useParams } from 'react-router-dom'; import { QueryTableProps } from './QueryTable.intefaces'; @@ -20,6 +23,7 @@ export function QueryTable({ columns, dataSource, sticky, + searchTerm, ...props }: QueryTableProps): JSX.Element { const { isDownloadEnabled = false, fileName = '' } = downloadOption || {}; @@ -55,6 +59,27 @@ export function QueryTable({ hideOnSinglePage: true, }; + const [filterTable, setFilterTable] = useState(null); + + const onTableSearch = useCallback( + (value?: string): void => { + const filterTable = newDataSource.filter((o) => + Object.keys(o).some((k) => + String(o[k]) + .toLowerCase() + .includes(value?.toLowerCase() || ''), + ), + ); + + setFilterTable(filterTable); + }, + [newDataSource], + ); + + useEffect(() => { + onTableSearch(searchTerm); + }, [newDataSource, onTableSearch, searchTerm]); + return (
{isDownloadEnabled && ( @@ -69,7 +94,7 @@ export function QueryTable({ ({ + ...jest.requireActual('react-router-dom'), + useLocation: (): { pathname: string } => ({ + pathname: ``, + }), +})); + +// Mock useDashabord hook +jest.mock('providers/Dashboard/Dashboard', () => ({ + useDashboard: (): any => ({ + selectedDashboard: { + data: { + variables: [], + }, + }, + }), +})); + +describe('QueryTable -', () => { + it('should render correctly with all the data rows', () => { + const { container } = render(); + const tableRows = container.querySelectorAll('tr.ant-table-row'); + expect(tableRows.length).toBe(QueryTableProps.queryTableData.rows.length); + }); + + it('should render correctly with searchTerm', () => { + const { container } = render( + , + ); + const tableRows = container.querySelectorAll('tr.ant-table-row'); + expect(tableRows.length).toBe(3); + }); +}); + +const setSearchTerm = jest.fn(); +describe('WidgetHeader -', () => { + it('global search option should be working', () => { + const { getByText, getByTestId } = render( + , + ); + expect(getByText('Table - Panel')).toBeInTheDocument(); + const searchWidget = getByTestId('widget-header-search'); + expect(searchWidget).toBeInTheDocument(); + // click and open the search input + fireEvent.click(searchWidget); + // check if input is opened + const searchInput = getByTestId('widget-header-search-input'); + expect(searchInput).toBeInTheDocument(); + + // enter search term + fireEvent.change(searchInput, { target: { value: 'frontend' } }); + // check if search term is set + expect(setSearchTerm).toHaveBeenCalledWith('frontend'); + expect(searchInput).toHaveValue('frontend'); + }); + + it('global search should not be present for non-table panel', () => { + const { queryByTestId } = render( + , + ); + expect(queryByTestId('widget-header-search')).not.toBeInTheDocument(); + }); +}); diff --git a/frontend/src/container/QueryTable/__test__/mocks.ts b/frontend/src/container/QueryTable/__test__/mocks.ts new file mode 100644 index 0000000000..abdb7bcfe3 --- /dev/null +++ b/frontend/src/container/QueryTable/__test__/mocks.ts @@ -0,0 +1,797 @@ +/* eslint-disable sonarjs/no-duplicate-string */ +export const QueryTableProps: any = { + props: { + loading: false, + size: 'small', + }, + queryTableData: { + columns: [ + { + name: 'resource_host_name', + queryName: '', + isValueColumn: false, + }, + { + name: 'service_name', + queryName: '', + isValueColumn: false, + }, + { + name: 'operation', + queryName: '', + isValueColumn: false, + }, + { + name: 'A', + queryName: 'A', + isValueColumn: true, + }, + ], + rows: [ + { + data: { + A: 11.5, + operation: 'GetDriver', + resource_host_name: 'test-hs-name', + service_name: 'redis', + }, + }, + { + data: { + A: 10.13, + operation: 'HTTP GET', + resource_host_name: 'test-hs-name', + service_name: 'frontend', + }, + }, + { + data: { + A: 9.21, + operation: 'HTTP GET /route', + resource_host_name: 'test-hs-name', + service_name: 'route', + }, + }, + { + data: { + A: 9.21, + operation: 'HTTP GET: /route', + resource_host_name: 'test-hs-name', + service_name: 'frontend', + }, + }, + { + data: { + A: 0.92, + operation: 'HTTP GET: /customer', + resource_host_name: 'test-hs-name', + service_name: 'frontend', + }, + }, + { + data: { + A: 0.92, + operation: 'SQL SELECT', + resource_host_name: 'test-hs-name', + service_name: 'mysql', + }, + }, + { + data: { + A: 0.92, + operation: 'HTTP GET /customer', + resource_host_name: 'test-hs-name', + service_name: 'customer', + }, + }, + ], + }, + query: { + builder: { + queryData: [ + { + aggregateAttribute: { + dataType: 'float64', + id: 'signoz_calls_total--float64--Sum--true', + isColumn: true, + isJSON: false, + key: 'signoz_calls_total', + type: 'Sum', + }, + aggregateOperator: 'rate', + dataSource: 'metrics', + disabled: false, + expression: 'A', + filters: { + items: [], + op: 'AND', + }, + functions: [], + groupBy: [ + { + dataType: 'string', + id: 'resource_host_name--string--tag--false', + isColumn: false, + isJSON: false, + key: 'resource_host_name', + type: 'tag', + }, + { + dataType: 'string', + id: 'service_name--string--tag--false', + isColumn: false, + isJSON: false, + key: 'service_name', + type: 'tag', + }, + { + dataType: 'string', + id: 'operation--string--tag--false', + isColumn: false, + isJSON: false, + key: 'operation', + type: 'tag', + }, + ], + having: [], + legend: '', + limit: null, + orderBy: [], + queryName: 'A', + reduceTo: 'avg', + spaceAggregation: 'sum', + stepInterval: 60, + timeAggregation: 'rate', + }, + ], + queryFormulas: [], + }, + clickhouse_sql: [ + { + disabled: false, + legend: '', + name: 'A', + query: '', + }, + ], + id: '1e08128f-c6a3-42ff-8033-4e38d291cf0a', + promql: [ + { + disabled: false, + legend: '', + name: 'A', + query: '', + }, + ], + queryType: 'builder', + }, + columns: [ + { + dataIndex: 'resource_host_name', + title: 'resource_host_name', + width: 145, + }, + { + dataIndex: 'service_name', + title: 'service_name', + width: 145, + }, + { + dataIndex: 'operation', + title: 'operation', + width: 145, + }, + { + dataIndex: 'A', + title: 'A', + width: 145, + }, + ], + dataSource: [ + { + A: 11.5, + operation: 'GetDriver', + resource_host_name: 'test-hs-name', + service_name: 'redis', + }, + { + A: 10.13, + operation: 'HTTP GET', + resource_host_name: 'test-hs-name', + service_name: 'frontend', + }, + { + A: 9.21, + operation: 'HTTP GET /route', + resource_host_name: 'test-hs-name', + service_name: 'route', + }, + { + A: 9.21, + operation: 'HTTP GET: /route', + resource_host_name: 'test-hs-name', + service_name: 'frontend', + }, + { + A: 0.92, + operation: 'HTTP GET: /customer', + resource_host_name: 'test-hs-name', + service_name: 'frontend', + }, + { + A: 0.92, + operation: 'SQL SELECT', + resource_host_name: 'test-hs-name', + service_name: 'mysql', + }, + { + A: 0.92, + operation: 'HTTP GET /customer', + resource_host_name: 'test-hs-name', + service_name: 'customer', + }, + ], + sticky: true, + searchTerm: '', +}; + +export const WidgetHeaderProps: any = { + title: 'Table - Panel', + widget: { + bucketCount: 30, + bucketWidth: 0, + columnUnits: {}, + description: '', + fillSpans: false, + id: 'add65f0d-7662-4024-af51-da567759235d', + isStacked: false, + mergeAllActiveQueries: false, + nullZeroValues: 'zero', + opacity: '1', + panelTypes: 'table', + query: { + builder: { + queryData: [ + { + aggregateAttribute: { + dataType: 'float64', + id: 'signoz_calls_total--float64--Sum--true', + isColumn: true, + isJSON: false, + key: 'signoz_calls_total', + type: 'Sum', + }, + aggregateOperator: 'rate', + dataSource: 'metrics', + disabled: false, + expression: 'A', + filters: { + items: [], + op: 'AND', + }, + functions: [], + groupBy: [ + { + dataType: 'string', + id: 'resource_host_name--string--tag--false', + isColumn: false, + isJSON: false, + key: 'resource_host_name', + type: 'tag', + }, + { + dataType: 'string', + id: 'service_name--string--tag--false', + isColumn: false, + isJSON: false, + key: 'service_name', + type: 'tag', + }, + { + dataType: 'string', + id: 'operation--string--tag--false', + isColumn: false, + isJSON: false, + key: 'operation', + type: 'tag', + }, + ], + having: [], + legend: '', + limit: null, + orderBy: [], + queryName: 'A', + reduceTo: 'avg', + spaceAggregation: 'sum', + stepInterval: 60, + timeAggregation: 'rate', + }, + ], + queryFormulas: [], + }, + clickhouse_sql: [ + { + disabled: false, + legend: '', + name: 'A', + query: '', + }, + ], + id: '1e08128f-c6a3-42ff-8033-4e38d291cf0a', + promql: [ + { + disabled: false, + legend: '', + name: 'A', + query: '', + }, + ], + queryType: 'builder', + }, + selectedLogFields: [ + { + dataType: 'string', + name: 'body', + type: '', + }, + { + dataType: 'string', + name: 'timestamp', + type: '', + }, + ], + selectedTracesFields: [ + { + dataType: 'string', + id: 'serviceName--string--tag--true', + isColumn: true, + isJSON: false, + key: 'serviceName', + type: 'tag', + }, + { + dataType: 'string', + id: 'name--string--tag--true', + isColumn: true, + isJSON: false, + key: 'name', + type: 'tag', + }, + { + dataType: 'float64', + id: 'durationNano--float64--tag--true', + isColumn: true, + isJSON: false, + key: 'durationNano', + type: 'tag', + }, + { + dataType: 'string', + id: 'httpMethod--string--tag--true', + isColumn: true, + isJSON: false, + key: 'httpMethod', + type: 'tag', + }, + { + dataType: 'string', + id: 'responseStatusCode--string--tag--true', + isColumn: true, + isJSON: false, + key: 'responseStatusCode', + type: 'tag', + }, + ], + softMax: 0, + softMin: 0, + stackedBarChart: false, + thresholds: [], + timePreferance: 'GLOBAL_TIME', + title: 'Table - Panel', + yAxisUnit: 'none', + }, + parentHover: false, + queryResponse: { + status: 'success', + isLoading: false, + isSuccess: true, + isError: false, + isIdle: false, + data: { + statusCode: 200, + error: null, + message: 'success', + payload: { + status: 'success', + data: { + resultType: '', + result: [ + { + table: { + columns: [ + { + name: 'resource_host_name', + queryName: '', + isValueColumn: false, + }, + { + name: 'service_name', + queryName: '', + isValueColumn: false, + }, + { + name: 'operation', + queryName: '', + isValueColumn: false, + }, + { + name: 'A', + queryName: 'A', + isValueColumn: true, + }, + ], + rows: [ + { + data: { + A: 11.67, + operation: 'GetDriver', + resource_host_name: '4f6ec470feea', + service_name: 'redis', + }, + }, + { + data: { + A: 10.26, + operation: 'HTTP GET', + resource_host_name: '4f6ec470feea', + service_name: 'frontend', + }, + }, + { + data: { + A: 9.33, + operation: 'HTTP GET: /route', + resource_host_name: '4f6ec470feea', + service_name: 'frontend', + }, + }, + { + data: { + A: 9.33, + operation: 'HTTP GET /route', + resource_host_name: '4f6ec470feea', + service_name: 'route', + }, + }, + { + data: { + A: 0.93, + operation: 'FindDriverIDs', + resource_host_name: '4f6ec470feea', + service_name: 'redis', + }, + }, + { + data: { + A: 0.93, + operation: 'HTTP GET: /customer', + resource_host_name: '4f6ec470feea', + service_name: 'frontend', + }, + }, + { + data: { + A: 0.93, + operation: '/driver.DriverService/FindNearest', + resource_host_name: '4f6ec470feea', + service_name: 'driver', + }, + }, + { + data: { + A: 0.93, + operation: '/driver.DriverService/FindNearest', + resource_host_name: '4f6ec470feea', + service_name: 'frontend', + }, + }, + { + data: { + A: 0.93, + operation: 'SQL SELECT', + resource_host_name: '4f6ec470feea', + service_name: 'mysql', + }, + }, + { + data: { + A: 0.93, + operation: 'HTTP GET /customer', + resource_host_name: '4f6ec470feea', + service_name: 'customer', + }, + }, + { + data: { + A: 0.93, + operation: 'HTTP GET /dispatch', + resource_host_name: '4f6ec470feea', + service_name: 'frontend', + }, + }, + { + data: { + A: 0.21, + operation: 'check_request limit', + resource_host_name: '', + service_name: 'demo-app', + }, + }, + { + data: { + A: 0.21, + operation: 'authenticate_check_cache', + resource_host_name: '', + service_name: 'demo-app', + }, + }, + { + data: { + A: 0.21, + operation: 'authenticate_check_db', + resource_host_name: '', + service_name: 'demo-app', + }, + }, + { + data: { + A: 0.21, + operation: 'authenticate', + resource_host_name: '', + service_name: 'demo-app', + }, + }, + { + data: { + A: 0.21, + operation: 'check cart in cache', + resource_host_name: '', + service_name: 'demo-app', + }, + }, + { + data: { + A: 0.2, + operation: 'get_cart', + resource_host_name: '', + service_name: 'demo-app', + }, + }, + { + data: { + A: 0.2, + operation: 'check cart in db', + resource_host_name: '', + service_name: 'demo-app', + }, + }, + { + data: { + A: 0.2, + operation: 'home', + resource_host_name: '', + service_name: 'demo-app', + }, + }, + ], + }, + }, + ], + }, + }, + params: { + start: 1726669030000, + end: 1726670830000, + step: 60, + variables: {}, + formatForWeb: true, + compositeQuery: { + queryType: 'builder', + panelType: 'table', + fillGaps: false, + builderQueries: { + A: { + aggregateAttribute: { + dataType: 'float64', + id: 'signoz_calls_total--float64--Sum--true', + isColumn: true, + isJSON: false, + key: 'signoz_calls_total', + type: 'Sum', + }, + aggregateOperator: 'rate', + dataSource: 'metrics', + disabled: false, + expression: 'A', + filters: { + items: [], + op: 'AND', + }, + functions: [], + groupBy: [ + { + dataType: 'string', + id: 'resource_host_name--string--tag--false', + isColumn: false, + isJSON: false, + key: 'resource_host_name', + type: 'tag', + }, + { + dataType: 'string', + id: 'service_name--string--tag--false', + isColumn: false, + isJSON: false, + key: 'service_name', + type: 'tag', + }, + { + dataType: 'string', + id: 'operation--string--tag--false', + isColumn: false, + isJSON: false, + key: 'operation', + type: 'tag', + }, + ], + having: [], + legend: '', + limit: null, + orderBy: [], + queryName: 'A', + reduceTo: 'avg', + spaceAggregation: 'sum', + stepInterval: 60, + timeAggregation: 'rate', + }, + }, + }, + }, + }, + dataUpdatedAt: 1726670830710, + error: null, + errorUpdatedAt: 0, + failureCount: 0, + errorUpdateCount: 0, + isFetched: true, + isFetchedAfterMount: true, + isFetching: false, + isRefetching: false, + isLoadingError: false, + isPlaceholderData: false, + isPreviousData: false, + isRefetchError: false, + isStale: true, + }, + headerMenuList: ['view', 'clone', 'delete', 'edit'], + isWarning: false, + isFetchingResponse: false, + tableProcessedDataRef: { + current: [ + { + resource_host_name: '4f6ec470feea', + service_name: 'redis', + operation: 'GetDriver', + A: 11.67, + }, + { + resource_host_name: '4f6ec470feea', + service_name: 'frontend', + operation: 'HTTP GET', + A: 10.26, + }, + { + resource_host_name: '4f6ec470feea', + service_name: 'frontend', + operation: 'HTTP GET: /route', + A: 9.33, + }, + { + resource_host_name: '4f6ec470feea', + service_name: 'route', + operation: 'HTTP GET /route', + A: 9.33, + }, + { + resource_host_name: '4f6ec470feea', + service_name: 'redis', + operation: 'FindDriverIDs', + A: 0.93, + }, + { + resource_host_name: '4f6ec470feea', + service_name: 'frontend', + operation: 'HTTP GET: /customer', + A: 0.93, + }, + { + resource_host_name: '4f6ec470feea', + service_name: 'driver', + operation: '/driver.DriverService/FindNearest', + A: 0.93, + }, + { + resource_host_name: '4f6ec470feea', + service_name: 'frontend', + operation: '/driver.DriverService/FindNearest', + A: 0.93, + }, + { + resource_host_name: '4f6ec470feea', + service_name: 'mysql', + operation: 'SQL SELECT', + A: 0.93, + }, + { + resource_host_name: '4f6ec470feea', + service_name: 'customer', + operation: 'HTTP GET /customer', + A: 0.93, + }, + { + resource_host_name: '4f6ec470feea', + service_name: 'frontend', + operation: 'HTTP GET /dispatch', + A: 0.93, + }, + { + resource_host_name: '', + service_name: 'demo-app', + operation: 'check_request limit', + A: 0.21, + }, + { + resource_host_name: '', + service_name: 'demo-app', + operation: 'authenticate_check_cache', + A: 0.21, + }, + { + resource_host_name: '', + service_name: 'demo-app', + operation: 'authenticate_check_db', + A: 0.21, + }, + { + resource_host_name: '', + service_name: 'demo-app', + operation: 'authenticate', + A: 0.21, + }, + { + resource_host_name: '', + service_name: 'demo-app', + operation: 'check cart in cache', + A: 0.21, + }, + { + resource_host_name: '', + service_name: 'demo-app', + operation: 'get_cart', + A: 0.2, + }, + { + resource_host_name: '', + service_name: 'demo-app', + operation: 'check cart in db', + A: 0.2, + }, + { + resource_host_name: '', + service_name: 'demo-app', + operation: 'home', + A: 0.2, + }, + ], + }, +};