From 8ce2e91f74297e1f8e2c9995c009965a423f6e09 Mon Sep 17 00:00:00 2001 From: KROSY Date: Thu, 19 Oct 2023 14:01:56 +0300 Subject: [PATCH 1/6] fix: fix top queries table row height --- .../TopQueriesTruncatedQuery.tsx | 20 +++++++++++++++++++ .../TruncatedQuery/TruncatedQuery.scss | 8 ++++++++ .../TenantOverview/TenantCpu/TopQueries.tsx | 6 ++---- .../Diagnostics/TopQueries/TopQueries.tsx | 8 +++++++- .../TopQueries/getTopQueriesColumns.tsx | 10 +++++++++- src/utils/diagnostics.ts | 16 +++++++++++++-- 6 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 src/components/TruncatedQuery/TopQueriesTruncatedQuery.tsx diff --git a/src/components/TruncatedQuery/TopQueriesTruncatedQuery.tsx b/src/components/TruncatedQuery/TopQueriesTruncatedQuery.tsx new file mode 100644 index 000000000..01a0e50ec --- /dev/null +++ b/src/components/TruncatedQuery/TopQueriesTruncatedQuery.tsx @@ -0,0 +1,20 @@ +import cn from 'bem-cn-lite'; + +import {CellWithPopover} from '../CellWithPopover/CellWithPopover'; + +import './TruncatedQuery.scss'; + +const b = cn('kv-truncated-query'); + +interface TopQueriesTruncatedQueryProps { + value: string | undefined; +} + +export const TopQueriesTruncatedQuery = ({value = ''}: TopQueriesTruncatedQueryProps) => { + const content = value.split('\n').slice(0, 5).join('\n'); + return ( + + {value} + + ); +}; diff --git a/src/components/TruncatedQuery/TruncatedQuery.scss b/src/components/TruncatedQuery/TruncatedQuery.scss index a34563f4d..6dcf7c6b5 100644 --- a/src/components/TruncatedQuery/TruncatedQuery.scss +++ b/src/components/TruncatedQuery/TruncatedQuery.scss @@ -14,4 +14,12 @@ } } } + + &__popover-content { + overflow: hidden; + + max-width: 600px; + + white-space: pre; + } } diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopQueries.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopQueries.tsx index 254bc697c..48914048d 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopQueries.tsx +++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopQueries.tsx @@ -1,4 +1,3 @@ -import qs from 'qs'; import {useDispatch} from 'react-redux'; import {useHistory, useLocation} from 'react-router'; import {useCallback} from 'react'; @@ -14,6 +13,7 @@ import { } from '../../../../../store/reducers/tenantOverview/topQueries/tenantOverviewTopQueries'; import {changeUserInput} from '../../../../../store/reducers/executeQuery'; import {useAutofetcher, useTypedSelector} from '../../../../../utils/hooks'; +import {parseQuery} from '../../../../../routes'; import {TenantTabsGroups, getTenantPath} from '../../../TenantPages'; import {getTenantOverviewTopQueriesColumns} from '../../TopQueries/getTopQueriesColumns'; import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout'; @@ -55,9 +55,7 @@ export function TopQueries({path}: TopQueriesProps) { dispatch(changeUserInput({input})); - const queryParams = qs.parse(location.search, { - ignoreQueryPrefix: true, - }); + const queryParams = parseQuery(location); const queryPath = getTenantPath({ ...queryParams, diff --git a/src/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx b/src/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx index 027ce98fd..241aaa191 100644 --- a/src/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +++ b/src/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx @@ -30,6 +30,7 @@ import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks'; import {prepareQueryError} from '../../../../utils/query'; import {parseQuery} from '../../../../routes'; import {QUERY_TABLE_SETTINGS} from '../../utils/constants'; +import {isSortableTopQueriesProperty} from '../../../../utils/diagnostics'; import {isColumnEntityType} from '../../utils/schema'; import {TenantTabsGroups, getTenantPath} from '../../TenantPages'; import {getTopQueriesColumns} from './getTopQueriesColumns'; @@ -58,7 +59,7 @@ export const TopQueries = ({path, type}: TopQueriesProps) => { data: {result: data = undefined} = {}, filters: storeFilters, } = useTypedSelector((state) => state.executeTopQueries); - const columns = getTopQueriesColumns(); + const rawColumns = getTopQueriesColumns(); const preventFetch = useRef(false); @@ -71,6 +72,11 @@ export const TopQueries = ({path, type}: TopQueriesProps) => { dispatch(setTopQueriesFilters(filters)); }, [dispatch, filters]); + const columns = rawColumns.map((column) => ({ + ...column, + sortable: isSortableTopQueriesProperty(column.name), + })); + const setDefaultFiltersFromResponse = (responseData?: IQueryResult) => { const intervalEnd = responseData?.result?.[0]?.IntervalEnd; diff --git a/src/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx b/src/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx index 7e3ee97d0..a77cc30d1 100644 --- a/src/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx +++ b/src/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx @@ -5,6 +5,7 @@ import DataTable, {type Column} from '@gravity-ui/react-data-table'; import type {KeyValueRow} from '../../../../types/api/query'; import {formatDateTime, formatNumber} from '../../../../utils/dataFormatters/dataFormatters'; import {TruncatedQuery} from '../../../../components/TruncatedQuery/TruncatedQuery'; +import {TopQueriesTruncatedQuery} from '../../../../components/TruncatedQuery/TopQueriesTruncatedQuery'; import {MAX_QUERY_HEIGHT} from '../../utils/constants'; import './TopQueries.scss'; @@ -18,6 +19,7 @@ const TOP_QUERIES_COLUMNS_IDS = { ReadRows: 'ReadRows', ReadBytes: 'ReadBytes', UserSID: 'UserSID', + TopQueriesQueryText: 'TopQueriesQueryText', }; const cpuTimeUsColumn: Column = { @@ -66,6 +68,12 @@ const userSIDColumn: Column = { align: DataTable.LEFT, }; +const topQueriesQueryTextColumn: Column = { + name: TOP_QUERIES_COLUMNS_IDS.TopQueriesQueryText, + render: ({row}) => , + sortable: false, +}; + export const getTopQueriesColumns = (): Column[] => { return [ cpuTimeUsColumn, @@ -78,5 +86,5 @@ export const getTopQueriesColumns = (): Column[] => { }; export const getTenantOverviewTopQueriesColumns = (): Column[] => { - return [queryTextColumn, cpuTimeUsColumn]; + return [topQueriesQueryTextColumn, cpuTimeUsColumn]; }; diff --git a/src/utils/diagnostics.ts b/src/utils/diagnostics.ts index 410127d94..44c634d53 100644 --- a/src/utils/diagnostics.ts +++ b/src/utils/diagnostics.ts @@ -1,11 +1,23 @@ import {ValueOf} from '../types/common'; -export const TOP_SHARDS_SORT_VALUES = { +const TOP_SHARDS_SORT_VALUES = { CPUCores: 'CPUCores', DataSize: 'DataSize', } as const; -export type TopShardsSortValue = ValueOf; +const TOP_QUERIES_SORT_VALUES = { + CPUTimeUs: 'CPUTimeUs', + EndTime: 'EndTime', + ReadRows: 'ReadRows', + ReadBytes: 'ReadBytes', + UserSID: 'UserSID', +} as const; + +type TopShardsSortValue = ValueOf; +type TopQueriesSortValue = ValueOf; export const isSortableTopShardsProperty = (value: string): value is TopShardsSortValue => Object.values(TOP_SHARDS_SORT_VALUES).includes(value as TopShardsSortValue); + +export const isSortableTopQueriesProperty = (value: string): value is TopQueriesSortValue => + Object.values(TOP_QUERIES_SORT_VALUES).includes(value as TopQueriesSortValue); From efbf5384f4a5531bdc4e1c2c1df0f9e56cf39d8a Mon Sep 17 00:00:00 2001 From: KROSY Date: Mon, 23 Oct 2023 12:03:09 +0300 Subject: [PATCH 2/6] fixup! fix: fix top queries table row height --- .../TopQueriesTruncatedQuery.tsx | 20 ------------------- .../TruncatedQuery/TruncatedQuery.tsx | 16 ++++++++++++++- .../TopQueries/getTopQueriesColumns.tsx | 8 +++++--- 3 files changed, 20 insertions(+), 24 deletions(-) delete mode 100644 src/components/TruncatedQuery/TopQueriesTruncatedQuery.tsx diff --git a/src/components/TruncatedQuery/TopQueriesTruncatedQuery.tsx b/src/components/TruncatedQuery/TopQueriesTruncatedQuery.tsx deleted file mode 100644 index 01a0e50ec..000000000 --- a/src/components/TruncatedQuery/TopQueriesTruncatedQuery.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import cn from 'bem-cn-lite'; - -import {CellWithPopover} from '../CellWithPopover/CellWithPopover'; - -import './TruncatedQuery.scss'; - -const b = cn('kv-truncated-query'); - -interface TopQueriesTruncatedQueryProps { - value: string | undefined; -} - -export const TopQueriesTruncatedQuery = ({value = ''}: TopQueriesTruncatedQueryProps) => { - const content = value.split('\n').slice(0, 5).join('\n'); - return ( - - {value} - - ); -}; diff --git a/src/components/TruncatedQuery/TruncatedQuery.tsx b/src/components/TruncatedQuery/TruncatedQuery.tsx index 98851b862..bedc8977d 100644 --- a/src/components/TruncatedQuery/TruncatedQuery.tsx +++ b/src/components/TruncatedQuery/TruncatedQuery.tsx @@ -1,11 +1,13 @@ import cn from 'bem-cn-lite'; +import {CellWithPopover} from '../CellWithPopover/CellWithPopover'; + import './TruncatedQuery.scss'; const b = cn('kv-truncated-query'); interface TruncatedQueryProps { - value: string | undefined; + value?: string; maxQueryHeight?: number; } @@ -26,3 +28,15 @@ export const TruncatedQuery = ({value = '', maxQueryHeight = 6}: TruncatedQueryP } return <>{value}; }; + +interface OneLineQueryWithPopoverProps { + value?: string; +} + +export const OneLineQueryWithPopover = ({value = ''}: OneLineQueryWithPopoverProps) => { + return ( + + {value} + + ); +}; diff --git a/src/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx b/src/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx index a77cc30d1..ff3da49d5 100644 --- a/src/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx +++ b/src/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx @@ -4,8 +4,10 @@ import DataTable, {type Column} from '@gravity-ui/react-data-table'; import type {KeyValueRow} from '../../../../types/api/query'; import {formatDateTime, formatNumber} from '../../../../utils/dataFormatters/dataFormatters'; -import {TruncatedQuery} from '../../../../components/TruncatedQuery/TruncatedQuery'; -import {TopQueriesTruncatedQuery} from '../../../../components/TruncatedQuery/TopQueriesTruncatedQuery'; +import { + TruncatedQuery, + OneLineQueryWithPopover, +} from '../../../../components/TruncatedQuery/TruncatedQuery'; import {MAX_QUERY_HEIGHT} from '../../utils/constants'; import './TopQueries.scss'; @@ -70,7 +72,7 @@ const userSIDColumn: Column = { const topQueriesQueryTextColumn: Column = { name: TOP_QUERIES_COLUMNS_IDS.TopQueriesQueryText, - render: ({row}) => , + render: ({row}) => , sortable: false, }; From 02202c52ba6983f97af9cf46dbdd9590f414ee21 Mon Sep 17 00:00:00 2001 From: KROSY Date: Mon, 23 Oct 2023 13:09:21 +0300 Subject: [PATCH 3/6] fix: add query id --- package-lock.json | 5 ++++ package.json | 1 + .../TopQueries/getTopQueriesColumns.tsx | 26 ++++++++++++++++++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 15c5b2a34..d72a85cb4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9686,6 +9686,11 @@ "yaml": "^1.10.0" } }, + "crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==" + }, "create-react-class": { "version": "15.7.0", "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.7.0.tgz", diff --git a/package.json b/package.json index 0413c952b..6a5fc46e7 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "axios": "0.19.2", "bem-cn-lite": "4.0.0", "copy-to-clipboard": "^3.3.3", + "crc-32": "^1.2.2", "history": "4.10.1", "js-cookie": "2.2.1", "lodash": "4.17.11", diff --git a/src/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx b/src/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx index ff3da49d5..cff466e28 100644 --- a/src/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx +++ b/src/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx @@ -1,8 +1,10 @@ +import crc32 from 'crc-32'; import cn from 'bem-cn-lite'; import DataTable, {type Column} from '@gravity-ui/react-data-table'; import type {KeyValueRow} from '../../../../types/api/query'; +import type {ValueOf} from '../../../../types/common'; import {formatDateTime, formatNumber} from '../../../../utils/dataFormatters/dataFormatters'; import { TruncatedQuery, @@ -22,6 +24,20 @@ const TOP_QUERIES_COLUMNS_IDS = { ReadBytes: 'ReadBytes', UserSID: 'UserSID', TopQueriesQueryText: 'TopQueriesQueryText', + QueryId: 'QueryId', +}; + +type QueryColumns = ValueOf; + +const tableColumnsNames: Record = { + CPUTimeUs: 'CPUTimeUs', + QueryText: 'QueryText', + EndTime: 'EndTime', + ReadRows: 'ReadRows', + ReadBytes: 'ReadBytes', + UserSID: 'UserSID', + TopQueriesQueryText: 'QueryText', + QueryId: 'QueryId', }; const cpuTimeUsColumn: Column = { @@ -72,10 +88,18 @@ const userSIDColumn: Column = { const topQueriesQueryTextColumn: Column = { name: TOP_QUERIES_COLUMNS_IDS.TopQueriesQueryText, + header: tableColumnsNames[TOP_QUERIES_COLUMNS_IDS.TopQueriesQueryText], render: ({row}) => , sortable: false, }; +const queryIdColumn: Column = { + name: TOP_QUERIES_COLUMNS_IDS.QueryId, + render: ({row}) => String(crc32.str(String(row.QueryText))), + width: 130, + sortable: false, +}; + export const getTopQueriesColumns = (): Column[] => { return [ cpuTimeUsColumn, @@ -88,5 +112,5 @@ export const getTopQueriesColumns = (): Column[] => { }; export const getTenantOverviewTopQueriesColumns = (): Column[] => { - return [topQueriesQueryTextColumn, cpuTimeUsColumn]; + return [queryIdColumn, topQueriesQueryTextColumn, cpuTimeUsColumn]; }; From dc9db993e0e30d928bc27d661a19caaa9ccbcb0b Mon Sep 17 00:00:00 2001 From: KROSY Date: Mon, 23 Oct 2023 14:19:17 +0300 Subject: [PATCH 4/6] fixup! fix: add query id --- .../TopQueries/getTopQueriesColumns.tsx | 30 +++++-------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/src/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx b/src/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx index cff466e28..456681018 100644 --- a/src/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx +++ b/src/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx @@ -4,7 +4,6 @@ import cn from 'bem-cn-lite'; import DataTable, {type Column} from '@gravity-ui/react-data-table'; import type {KeyValueRow} from '../../../../types/api/query'; -import type {ValueOf} from '../../../../types/common'; import {formatDateTime, formatNumber} from '../../../../utils/dataFormatters/dataFormatters'; import { TruncatedQuery, @@ -23,21 +22,8 @@ const TOP_QUERIES_COLUMNS_IDS = { ReadRows: 'ReadRows', ReadBytes: 'ReadBytes', UserSID: 'UserSID', - TopQueriesQueryText: 'TopQueriesQueryText', - QueryId: 'QueryId', -}; - -type QueryColumns = ValueOf; - -const tableColumnsNames: Record = { - CPUTimeUs: 'CPUTimeUs', - QueryText: 'QueryText', - EndTime: 'EndTime', - ReadRows: 'ReadRows', - ReadBytes: 'ReadBytes', - UserSID: 'UserSID', - TopQueriesQueryText: 'QueryText', - QueryId: 'QueryId', + OneLineQueryText: 'OneLineQueryText', + QueryHash: 'QueryHash', }; const cpuTimeUsColumn: Column = { @@ -86,15 +72,15 @@ const userSIDColumn: Column = { align: DataTable.LEFT, }; -const topQueriesQueryTextColumn: Column = { - name: TOP_QUERIES_COLUMNS_IDS.TopQueriesQueryText, - header: tableColumnsNames[TOP_QUERIES_COLUMNS_IDS.TopQueriesQueryText], +const oneLineQueryTextColumn: Column = { + name: TOP_QUERIES_COLUMNS_IDS.OneLineQueryText, + header: 'QueryText', render: ({row}) => , sortable: false, }; -const queryIdColumn: Column = { - name: TOP_QUERIES_COLUMNS_IDS.QueryId, +const queryHashColumn: Column = { + name: TOP_QUERIES_COLUMNS_IDS.QueryHash, render: ({row}) => String(crc32.str(String(row.QueryText))), width: 130, sortable: false, @@ -112,5 +98,5 @@ export const getTopQueriesColumns = (): Column[] => { }; export const getTenantOverviewTopQueriesColumns = (): Column[] => { - return [queryIdColumn, topQueriesQueryTextColumn, cpuTimeUsColumn]; + return [queryHashColumn, oneLineQueryTextColumn, cpuTimeUsColumn]; }; From 490bd75ae950af9520813c68c77c0daaaa5208cb Mon Sep 17 00:00:00 2001 From: KROSY Date: Mon, 23 Oct 2023 15:31:00 +0300 Subject: [PATCH 5/6] fix: convert hash to hex --- .../Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx b/src/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx index 456681018..c1124bf8a 100644 --- a/src/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx +++ b/src/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx @@ -81,7 +81,10 @@ const oneLineQueryTextColumn: Column = { const queryHashColumn: Column = { name: TOP_QUERIES_COLUMNS_IDS.QueryHash, - render: ({row}) => String(crc32.str(String(row.QueryText))), + render: ({row}) => + // We use unsigned right shift operator (>>>) to avoid negative values + // eslint-disable-next-line no-bitwise + (crc32.str(String(row.QueryText)) >>> 0).toString(16).toUpperCase().padStart(8, '0'), width: 130, sortable: false, }; From 699230d0199a231333457ca010d89536963274d9 Mon Sep 17 00:00:00 2001 From: KROSY Date: Mon, 23 Oct 2023 17:17:44 +0300 Subject: [PATCH 6/6] fix: move generateHash to utils --- .../Diagnostics/TopQueries/getTopQueriesColumns.tsx | 7 ++----- src/utils/generateHash.ts | 11 +++++++++++ 2 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 src/utils/generateHash.ts diff --git a/src/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx b/src/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx index c1124bf8a..64b8386c8 100644 --- a/src/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx +++ b/src/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx @@ -1,10 +1,10 @@ -import crc32 from 'crc-32'; import cn from 'bem-cn-lite'; import DataTable, {type Column} from '@gravity-ui/react-data-table'; import type {KeyValueRow} from '../../../../types/api/query'; import {formatDateTime, formatNumber} from '../../../../utils/dataFormatters/dataFormatters'; +import {generateHash} from '../../../../utils/generateHash'; import { TruncatedQuery, OneLineQueryWithPopover, @@ -81,10 +81,7 @@ const oneLineQueryTextColumn: Column = { const queryHashColumn: Column = { name: TOP_QUERIES_COLUMNS_IDS.QueryHash, - render: ({row}) => - // We use unsigned right shift operator (>>>) to avoid negative values - // eslint-disable-next-line no-bitwise - (crc32.str(String(row.QueryText)) >>> 0).toString(16).toUpperCase().padStart(8, '0'), + render: ({row}) => generateHash(String(row.QueryText)), width: 130, sortable: false, }; diff --git a/src/utils/generateHash.ts b/src/utils/generateHash.ts new file mode 100644 index 000000000..cf20d6e5b --- /dev/null +++ b/src/utils/generateHash.ts @@ -0,0 +1,11 @@ +import crc32 from 'crc-32'; + +export const generateHash = (value: string) => { + // 1. crc32.str(value) - generate crc32 hash + // 2. (>>>) - use unsigned right shift operator (>>>) to avoid negative values + // 3. toString(16) - convert hash to hex format + // 4. toUpperCase() - convert hash to uppercase + // 5. padStart(8, '0') - fill hash with leading zeros if hash length < 8 + // eslint-disable-next-line no-bitwise + return (crc32.str(value) >>> 0).toString(16).toUpperCase().padStart(8, '0'); +};