From 0562b0cf8c2b949ad80a765a2b7bce407b100c4a Mon Sep 17 00:00:00 2001 From: kungurtsev Date: Fri, 16 Aug 2024 17:30:16 +0200 Subject: [PATCH 1/6] feat(diagnostics): render bloom filter better (#1165) --- .../Overview/TableInfo/prepareTableInfo.tsx | 35 +++++++++++++------ src/containers/Tenant/utils/queryTemplates.ts | 11 +++--- src/types/api/schema/table.ts | 2 ++ 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/containers/Tenant/Diagnostics/Overview/TableInfo/prepareTableInfo.tsx b/src/containers/Tenant/Diagnostics/Overview/TableInfo/prepareTableInfo.tsx index 51b3b19de..b96e78fef 100644 --- a/src/containers/Tenant/Diagnostics/Overview/TableInfo/prepareTableInfo.tsx +++ b/src/containers/Tenant/Diagnostics/Overview/TableInfo/prepareTableInfo.tsx @@ -1,6 +1,7 @@ import {Text} from '@gravity-ui/uikit'; import omit from 'lodash/omit'; +import {toFormattedSize} from '../../../../../components/FormattedBytes/utils'; import type {InfoViewerItem} from '../../../../../components/InfoViewer'; import {formatObject} from '../../../../../components/InfoViewer'; import { @@ -17,8 +18,10 @@ import type { TTTLSettings, } from '../../../../../types/api/schema'; import {EPathType} from '../../../../../types/api/schema'; +import {valueIsDefined} from '../../../../../utils'; import {formatBytes, formatNumber} from '../../../../../utils/dataFormatters/dataFormatters'; import {formatDurationToShortTimeFormat} from '../../../../../utils/timeParsers'; +import {isNumeric} from '../../../../../utils/utils'; import i18n from './i18n'; @@ -126,10 +129,12 @@ const prepareTableGeneralInfo = (PartitionConfig: TPartitionConfig, TTLSettings? } } - generalTableInfo.push({ - label: i18n('label.bloom-filter'), - value: EnableFilterByKey ? i18n('enabled') : i18n('disabled'), - }); + if (valueIsDefined(EnableFilterByKey)) { + generalTableInfo.push({ + label: i18n('label.bloom-filter'), + value: EnableFilterByKey ? i18n('enabled') : i18n('disabled'), + }); + } return generalTableInfo; }; @@ -154,6 +159,7 @@ export const prepareTableInfo = (data?: TEvDescribeSchemeResult, type?: EPathTyp RowCount, DataSize, IndexSize, + ByKeyFilterSize, LastAccessTime, LastUpdateTime, @@ -187,13 +193,22 @@ export const prepareTableInfo = (data?: TEvDescribeSchemeResult, type?: EPathTyp } } + const generalStats = formatObject(formatTableStatsItem, { + PartCount, + RowCount, + DataSize, + IndexSize, + }); + + if ( + isNumeric(ByKeyFilterSize) && + (PartitionConfig.EnableFilterByKey || Number(ByKeyFilterSize) > 0) + ) { + generalStats.push({label: 'BloomFilterSize', value: toFormattedSize(ByKeyFilterSize)}); + } + const tableStatsInfo = [ - formatObject(formatTableStatsItem, { - PartCount, - RowCount, - DataSize, - IndexSize, - }), + generalStats, formatObject(formatTableStatsItem, { LastAccessTime, LastUpdateTime, diff --git a/src/containers/Tenant/utils/queryTemplates.ts b/src/containers/Tenant/utils/queryTemplates.ts index 7b367bc38..33b6bafb6 100644 --- a/src/containers/Tenant/utils/queryTemplates.ts +++ b/src/containers/Tenant/utils/queryTemplates.ts @@ -17,16 +17,17 @@ WITH ( AUTO_PARTITIONING_PARTITION_SIZE_MB = 2048, AUTO_PARTITIONING_BY_LOAD = ENABLED, AUTO_PARTITIONING_MIN_PARTITIONS_COUNT = 4, - AUTO_PARTITIONING_MAX_PARTITIONS_COUNT = 1024, + AUTO_PARTITIONING_MAX_PARTITIONS_COUNT = 1024 -- uncomment to create a table with predefined partitions - -- UNIFORM_PARTITIONS = 4, -- The number of partitions for uniform initial table partitioning. + -- , UNIFORM_PARTITIONS = 4 -- The number of partitions for uniform initial table partitioning. -- The primary key's first column must have type Uint64 or Uint32. -- A created table is immediately divided into the specified number of partitions -- uncomment to launch read only replicas in every AZ - -- READ_REPLICAS_SETTINGS = 'PER_AZ:1', -- Enable read replicas for stale read, launch one replica in every availability zone + -- , READ_REPLICAS_SETTINGS = 'PER_AZ:1' -- Enable read replicas for stale read, launch one replica in every availability zone -- uncomment to enable ttl - -- TTL = Interval("PT1H") ON expire_at, -- Enable background deletion of expired rows https://ydb.tech/en/docs/concepts/ttl - KEY_BLOOM_FILTER = ENABLED -- With a Bloom filter, you can more efficiently determine + -- , TTL = Interval("PT1H") ON expire_at -- Enable background deletion of expired rows https://ydb.tech/en/docs/concepts/ttl + -- uncomment to create a table with a bloom filter + -- , KEY_BLOOM_FILTER = ENABLED -- With a Bloom filter, you can more efficiently determine -- if some keys are missing in a table when making multiple single queries by the primary key. )`; }; diff --git a/src/types/api/schema/table.ts b/src/types/api/schema/table.ts index 86ec247b4..c1c79e82b 100644 --- a/src/types/api/schema/table.ts +++ b/src/types/api/schema/table.ts @@ -164,6 +164,8 @@ export interface TTableStats { /** uint64 */ IndexSize?: string; /** uint64 */ + ByKeyFilterSize?: string; + /** uint64 */ InMemSize?: string; /** From c8a4d3a05f396578ffe443550462fc3c74006817 Mon Sep 17 00:00:00 2001 From: Hellen Date: Sat, 17 Aug 2024 10:09:30 +0300 Subject: [PATCH 2/6] chore(SimplifiedPlan): remove redundant state (#1173) --- .../SimplifiedPlan/SimplifiedPlan.tsx | 7 +- .../SimplifiedPlan/__tests__/utils.test.ts | 82 +------------------ .../components/SimplifiedPlan/utils.ts | 27 ------ 3 files changed, 3 insertions(+), 113 deletions(-) diff --git a/src/containers/Tenant/Query/ExplainResult/components/SimplifiedPlan/SimplifiedPlan.tsx b/src/containers/Tenant/Query/ExplainResult/components/SimplifiedPlan/SimplifiedPlan.tsx index 23935cdbc..2ab729d61 100644 --- a/src/containers/Tenant/Query/ExplainResult/components/SimplifiedPlan/SimplifiedPlan.tsx +++ b/src/containers/Tenant/Query/ExplainResult/components/SimplifiedPlan/SimplifiedPlan.tsx @@ -11,7 +11,7 @@ import {toExponential} from '../../../../../../utils/utils'; import {MetricsCell} from './MetricsCell'; import {OperationCell} from './OperationCell'; import type {ExtendedSimplifiesPlanItem} from './types'; -import {block, getExtendedTreeNodes, getTreeNodesCoordinates} from './utils'; +import {block, getExtendedTreeNodes} from './utils'; import './SimplifiedPlan.scss'; @@ -100,10 +100,7 @@ interface SimplifiedPlanProps { export function SimplifiedPlan({plan}: SimplifiedPlanProps) { const planWithLinesInfo = React.useMemo(() => getExtendedTreeNodes(plan), [plan]); - const [expanded, setExpanded] = React.useState(() => { - const coordinates = getTreeNodesCoordinates(plan); - return Object.fromEntries(coordinates.map((id) => [id, true])); - }); + const [expanded, setExpanded] = React.useState(true); const table = useTable({ columns, diff --git a/src/containers/Tenant/Query/ExplainResult/components/SimplifiedPlan/__tests__/utils.test.ts b/src/containers/Tenant/Query/ExplainResult/components/SimplifiedPlan/__tests__/utils.test.ts index c05186b96..43079b3dc 100644 --- a/src/containers/Tenant/Query/ExplainResult/components/SimplifiedPlan/__tests__/utils.test.ts +++ b/src/containers/Tenant/Query/ExplainResult/components/SimplifiedPlan/__tests__/utils.test.ts @@ -1,86 +1,6 @@ import type {SimplifiedPlanItem} from '../../../../../../../store/reducers/explainQuery/types'; import type {ExtendedSimplifiesPlanItem} from '../types'; -import {getExtendedTreeNodes, getTreeNodesCoordinates} from '../utils'; - -describe('getTreeNodesCoordinates', () => { - test('should handle empty input', () => { - const result = getTreeNodesCoordinates(); - expect(result).toEqual([]); - }); - - test('should handle single node without children', () => { - const items: SimplifiedPlanItem[] = [ - { - name: 'TestNode', - operationParams: {}, - children: [], - }, - ]; - - const expected = ['0']; - - const result = getTreeNodesCoordinates(items); - expect(result).toEqual(expected); - }); - - test('should handle nested nodes', () => { - const items: SimplifiedPlanItem[] = [ - { - name: 'RootNode', - operationParams: {}, - children: [ - { - name: 'ChildNode1', - operationParams: {}, - children: [], - }, - { - name: 'ChildNode2', - operationParams: {}, - children: [ - { - name: 'GrandChildNode', - operationParams: {}, - children: [], - }, - ], - }, - ], - }, - ]; - - const expected = ['0', '0.0', '0.1', '0.1.0']; - - const result = getTreeNodesCoordinates(items); - expect(result).toEqual(expected); - }); - - test('should handle multiple root nodes', () => { - const items: SimplifiedPlanItem[] = [ - { - name: 'RootNode1', - operationParams: {}, - children: [], - }, - { - name: 'RootNode2', - operationParams: {}, - children: [ - { - name: 'ChildNode', - operationParams: {}, - children: [], - }, - ], - }, - ]; - - const expected = ['0', '1', '1.0']; - - const result = getTreeNodesCoordinates(items); - expect(result).toEqual(expected); - }); -}); +import {getExtendedTreeNodes} from '../utils'; describe('getExtendedTreeNodes', () => { test('should handle empty input', () => { diff --git a/src/containers/Tenant/Query/ExplainResult/components/SimplifiedPlan/utils.ts b/src/containers/Tenant/Query/ExplainResult/components/SimplifiedPlan/utils.ts index 788611e6c..b79f31605 100644 --- a/src/containers/Tenant/Query/ExplainResult/components/SimplifiedPlan/utils.ts +++ b/src/containers/Tenant/Query/ExplainResult/components/SimplifiedPlan/utils.ts @@ -5,33 +5,6 @@ import type {ExtendedSimplifiesPlanItem} from './types'; export const block = cn('ydb-query-explain-simplified-plan'); -export function getTreeNodesCoordinates(items?: SimplifiedPlanItem[], prefix = '') { - const result: string[] = []; - const stack: {items?: SimplifiedPlanItem[]; prefix: string}[] = []; - - if (items) { - stack.push({items, prefix}); - } - - while (stack.length > 0) { - const {items, prefix} = stack.pop()!; - - items?.forEach((item, index) => { - let newPrefix = `${prefix}.${index}`; - if (!prefix) { - newPrefix = String(index); - } - result.push(newPrefix); - - if (item.children) { - stack.push({items: item.children, prefix: newPrefix}); - } - }); - } - - return result; -} - export function getExtendedTreeNodes( items?: SimplifiedPlanItem[], prefix = '', From 73a790520f99276321ff72806757afdc384bb7f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9C=D1=83=D1=84=D0=B0?= =?UTF-8?q?=D0=B7=D0=B0=D0=BB=D0=BE=D0=B2?= <67755036+artemmufazalov@users.noreply.github.com> Date: Mon, 19 Aug 2024 12:12:31 +0300 Subject: [PATCH 3/6] chore: remove local commit message check (#1181) --- .husky/commit-msg | 1 - 1 file changed, 1 deletion(-) delete mode 100755 .husky/commit-msg diff --git a/.husky/commit-msg b/.husky/commit-msg deleted file mode 100755 index a78cc751d..000000000 --- a/.husky/commit-msg +++ /dev/null @@ -1 +0,0 @@ -npx commitlint --edit $1 From 7d544b72415ff753677ab7afe8d2f44ccb44acf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9C=D1=83=D1=84=D0=B0?= =?UTF-8?q?=D0=B7=D0=B0=D0=BB=D0=BE=D0=B2?= <67755036+artemmufazalov@users.noreply.github.com> Date: Mon, 19 Aug 2024 13:13:07 +0300 Subject: [PATCH 4/6] refactor: use direct imports instead of lib imports (#1182) --- src/.eslintrc | 13 ++++++++++++- src/components/ElapsedTime/ElapsedTime.tsx | 3 ++- .../QuerySettingsDialog/QuerySettingsDialog.tsx | 2 +- .../Tenant/Query/utils/useSavedQueries.tsx | 3 ++- src/index.tsx | 1 + src/store/reducers/tenants/selectors.ts | 2 +- 6 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/.eslintrc b/src/.eslintrc index b328248ce..40a800ed4 100644 --- a/src/.eslintrc +++ b/src/.eslintrc @@ -19,6 +19,17 @@ "selector": "ImportDeclaration[source.value='axios'] :matches(ImportSpecifier[imported.name='isAxiosError'])", "message": "Please use isAxiosError from utils/response instead of axios", }, - ], + ], + "no-restricted-imports": [ + "error", + { + "patterns": [ + { + "group": [".*/**/lib"], + "message": "Please use direct imports instead", + }, + ], + }, + ], }, } diff --git a/src/components/ElapsedTime/ElapsedTime.tsx b/src/components/ElapsedTime/ElapsedTime.tsx index 42c7cf48c..b0301231b 100644 --- a/src/components/ElapsedTime/ElapsedTime.tsx +++ b/src/components/ElapsedTime/ElapsedTime.tsx @@ -3,7 +3,8 @@ import React from 'react'; import {duration} from '@gravity-ui/date-utils'; import {Label} from '@gravity-ui/uikit'; -import {HOUR_IN_SECONDS, SECOND_IN_MS, cn} from '../../lib'; +import {cn} from '../../utils/cn'; +import {HOUR_IN_SECONDS, SECOND_IN_MS} from '../../utils/constants'; const b = cn('ydb-query-elapsed-time'); diff --git a/src/containers/Tenant/Query/QuerySettingsDialog/QuerySettingsDialog.tsx b/src/containers/Tenant/Query/QuerySettingsDialog/QuerySettingsDialog.tsx index 3c33446fd..7af6d08ea 100644 --- a/src/containers/Tenant/Query/QuerySettingsDialog/QuerySettingsDialog.tsx +++ b/src/containers/Tenant/Query/QuerySettingsDialog/QuerySettingsDialog.tsx @@ -3,13 +3,13 @@ import React from 'react'; import {Dialog, Link as ExternalLink, Flex, TextInput} from '@gravity-ui/uikit'; import {Controller, useForm} from 'react-hook-form'; -import {ENABLE_TRACING_LEVEL_KEY} from '../../../../lib'; import { selectQueryAction, setQueryAction, } from '../../../../store/reducers/queryActions/queryActions'; import type {QuerySettings} from '../../../../types/store/query'; import {cn} from '../../../../utils/cn'; +import {ENABLE_TRACING_LEVEL_KEY} from '../../../../utils/constants'; import { useQueryExecutionSettings, useSetting, diff --git a/src/containers/Tenant/Query/utils/useSavedQueries.tsx b/src/containers/Tenant/Query/utils/useSavedQueries.tsx index 636f1a6df..17baf5c04 100644 --- a/src/containers/Tenant/Query/utils/useSavedQueries.tsx +++ b/src/containers/Tenant/Query/utils/useSavedQueries.tsx @@ -1,6 +1,7 @@ -import {SAVED_QUERIES_KEY, useSetting, useTypedSelector} from '../../../../lib'; import {selectSavedQueriesFilter} from '../../../../store/reducers/queryActions/queryActions'; import type {SavedQuery} from '../../../../types/store/query'; +import {SAVED_QUERIES_KEY} from '../../../../utils/constants'; +import {useSetting, useTypedSelector} from '../../../../utils/hooks'; export function useSavedQueries() { const [savedQueries] = useSetting(SAVED_QUERIES_KEY, []); diff --git a/src/index.tsx b/src/index.tsx index 5a8402071..ba02628f1 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,3 +1,4 @@ +/* eslint-disable no-restricted-imports */ /* eslint-disable import/order */ import ReactDOM from 'react-dom/client'; diff --git a/src/store/reducers/tenants/selectors.ts b/src/store/reducers/tenants/selectors.ts index d64fa1864..a591e37a0 100644 --- a/src/store/reducers/tenants/selectors.ts +++ b/src/store/reducers/tenants/selectors.ts @@ -2,8 +2,8 @@ import {createSelector} from '@reduxjs/toolkit'; import escapeRegExp from 'lodash/escapeRegExp'; import type {RootState} from '../..'; -import {SHOW_DOMAIN_DATABASE_KEY} from '../../../lib'; import {EFlag} from '../../../types/api/enums'; +import {SHOW_DOMAIN_DATABASE_KEY} from '../../../utils/constants'; import {ProblemFilterValues, getSettingValue, selectProblemFilter} from '../settings/settings'; import type {ProblemFilterValue} from '../settings/types'; From f1ab08c3146135b6fef039ce541311bf2ca73fba Mon Sep 17 00:00:00 2001 From: Anton Standrik Date: Mon, 19 Aug 2024 15:44:19 +0300 Subject: [PATCH 5/6] feat: [query settings] display trace level selector (#1170) --- src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx | 4 ++-- .../Query/QuerySettingsDialog/QuerySettingsDialog.tsx | 5 ++--- src/containers/UserSettings/i18n/en.json | 3 --- src/containers/UserSettings/settings.tsx | 9 +-------- src/services/settings.ts | 2 -- src/store/reducers/capabilities/hooks.ts | 4 ++++ src/types/api/capabilities.ts | 2 +- src/utils/constants.ts | 2 -- src/utils/hooks/useQueryExecutionSettings.ts | 9 +++------ 9 files changed, 13 insertions(+), 27 deletions(-) diff --git a/src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx b/src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx index 7c61be48a..6b98f9835 100644 --- a/src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx +++ b/src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx @@ -10,6 +10,7 @@ import {MonacoEditor} from '../../../../components/MonacoEditor/MonacoEditor'; import SplitPane from '../../../../components/SplitPane'; import type {RootState} from '../../../../store'; import {cancelQueryApi} from '../../../../store/reducers/cancelQuery'; +import {useTracingLevelOptionAvailable} from '../../../../store/reducers/capabilities/hooks'; import { executeQueryApi, goToNextQuery, @@ -29,7 +30,6 @@ import {cn} from '../../../../utils/cn'; import { DEFAULT_IS_QUERY_RESULT_COLLAPSED, DEFAULT_SIZE_RESULT_PANE_KEY, - ENABLE_TRACING_LEVEL_KEY, LAST_USED_QUERY_ACTION_KEY, QUERY_USE_MULTI_SCHEMA_KEY, } from '../../../../utils/constants'; @@ -103,7 +103,7 @@ function QueryEditor(props: QueryEditorProps) { const [resultType, setResultType] = React.useState>(); const [isResultLoaded, setIsResultLoaded] = React.useState(false); const [querySettings] = useQueryExecutionSettings(); - const [enableTracingLevel] = useSetting(ENABLE_TRACING_LEVEL_KEY); + const enableTracingLevel = useTracingLevelOptionAvailable(); const [lastQueryExecutionSettings, setLastQueryExecutionSettings] = useLastQueryExecutionSettings(); const {resetBanner} = useChangedQuerySettings(); diff --git a/src/containers/Tenant/Query/QuerySettingsDialog/QuerySettingsDialog.tsx b/src/containers/Tenant/Query/QuerySettingsDialog/QuerySettingsDialog.tsx index 7af6d08ea..f32b63316 100644 --- a/src/containers/Tenant/Query/QuerySettingsDialog/QuerySettingsDialog.tsx +++ b/src/containers/Tenant/Query/QuerySettingsDialog/QuerySettingsDialog.tsx @@ -3,16 +3,15 @@ import React from 'react'; import {Dialog, Link as ExternalLink, Flex, TextInput} from '@gravity-ui/uikit'; import {Controller, useForm} from 'react-hook-form'; +import {useTracingLevelOptionAvailable} from '../../../../store/reducers/capabilities/hooks'; import { selectQueryAction, setQueryAction, } from '../../../../store/reducers/queryActions/queryActions'; import type {QuerySettings} from '../../../../types/store/query'; import {cn} from '../../../../utils/cn'; -import {ENABLE_TRACING_LEVEL_KEY} from '../../../../utils/constants'; import { useQueryExecutionSettings, - useSetting, useTypedDispatch, useTypedSelector, } from '../../../../utils/hooks'; @@ -71,7 +70,7 @@ function QuerySettingsForm({initialValues, onSubmit, onClose}: QuerySettingsForm defaultValues: initialValues, }); - const [enableTracingLevel] = useSetting(ENABLE_TRACING_LEVEL_KEY); + const enableTracingLevel = useTracingLevelOptionAvailable(); return (
diff --git a/src/containers/UserSettings/i18n/en.json b/src/containers/UserSettings/i18n/en.json index 48034eeed..84d1cdbfd 100644 --- a/src/containers/UserSettings/i18n/en.json +++ b/src/containers/UserSettings/i18n/en.json @@ -39,9 +39,6 @@ "settings.showDomainDatabase.title": "Show domain database", - "settings.enableTracingLevel.title": "Enable tracing level select", - "settings.enableTracingLevel.description": "Caution: Enabling this setting may break running of queries", - "settings.queryUseMultiSchema.title": "Allow queries with multiple result sets", "settings.queryUseMultiSchema.description": "Use 'multi' schema for queries. It enables queries with multiple result sets. It returns nothing on versions 23-3 and older", diff --git a/src/containers/UserSettings/settings.tsx b/src/containers/UserSettings/settings.tsx index 90dc2220c..015e56545 100644 --- a/src/containers/UserSettings/settings.tsx +++ b/src/containers/UserSettings/settings.tsx @@ -6,7 +6,6 @@ import { AUTOCOMPLETE_ON_ENTER, BINARY_DATA_IN_PLAIN_TEXT_DISPLAY, ENABLE_AUTOCOMPLETE, - ENABLE_TRACING_LEVEL_KEY, INVERTED_DISKS_KEY, LANGUAGE_KEY, QUERY_USE_MULTI_SCHEMA_KEY, @@ -113,12 +112,6 @@ export const showDomainDatabase: SettingProps = { title: i18n('settings.showDomainDatabase.title'), }; -export const enableTracingLevel: SettingProps = { - settingKey: ENABLE_TRACING_LEVEL_KEY, - title: i18n('settings.enableTracingLevel.title'), - description: i18n('settings.enableTracingLevel.description'), -}; - export const queryUseMultiSchemaSetting: SettingProps = { settingKey: QUERY_USE_MULTI_SCHEMA_KEY, title: i18n('settings.queryUseMultiSchema.title'), @@ -167,7 +160,7 @@ export const experimentsSection: SettingsSection = { export const devSettingsSection: SettingsSection = { id: 'devSettingsSection', title: i18n('section.dev-setting'), - settings: [enableAutocompleteSetting, autocompleteOnEnterSetting, enableTracingLevel], + settings: [enableAutocompleteSetting, autocompleteOnEnterSetting], }; export const aboutSettingsSection: SettingsSection = { diff --git a/src/services/settings.ts b/src/services/settings.ts index 3191c8e50..bfe6b777f 100644 --- a/src/services/settings.ts +++ b/src/services/settings.ts @@ -6,7 +6,6 @@ import { BINARY_DATA_IN_PLAIN_TEXT_DISPLAY, DEFAULT_QUERY_SETTINGS, ENABLE_AUTOCOMPLETE, - ENABLE_TRACING_LEVEL_KEY, INVERTED_DISKS_KEY, IS_HOTKEYS_HELP_HIDDEN_KEY, LANGUAGE_KEY, @@ -48,7 +47,6 @@ export const DEFAULT_USER_SETTINGS = { [AUTOCOMPLETE_ON_ENTER]: true, [IS_HOTKEYS_HELP_HIDDEN_KEY]: false, [AUTO_REFRESH_INTERVAL]: 0, - [ENABLE_TRACING_LEVEL_KEY]: false, [SHOW_DOMAIN_DATABASE_KEY]: false, [LAST_QUERY_EXECUTION_SETTINGS_KEY]: undefined, [QUERY_SETTINGS_BANNER_LAST_CLOSED_KEY]: undefined, diff --git a/src/store/reducers/capabilities/hooks.ts b/src/store/reducers/capabilities/hooks.ts index 6df63b997..4abb49f43 100644 --- a/src/store/reducers/capabilities/hooks.ts +++ b/src/store/reducers/capabilities/hooks.ts @@ -16,3 +16,7 @@ export const useDiskPagesAvailable = () => { // It's enough to check only pdisk handler return useGetFeatureVersion('/pdisk/info') > 0; }; + +export const useTracingLevelOptionAvailable = () => { + return useGetFeatureVersion('/viewer/query') > 2; +}; diff --git a/src/types/api/capabilities.ts b/src/types/api/capabilities.ts index 297d11e6b..6fc70dbfc 100644 --- a/src/types/api/capabilities.ts +++ b/src/types/api/capabilities.ts @@ -6,4 +6,4 @@ export interface CapabilitiesResponse { } // Add feature name before using it -export type Capability = '/pdisk/info' | '/scheme/directory'; +export type Capability = '/pdisk/info' | '/scheme/directory' | '/viewer/query'; diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 04c409805..842af39f7 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -159,5 +159,3 @@ export const ENABLE_AUTOCOMPLETE = 'enableAutocomplete'; export const AUTOCOMPLETE_ON_ENTER = 'autocompleteOnEnter'; export const IS_HOTKEYS_HELP_HIDDEN_KEY = 'isHotKeysHelpHidden'; - -export const ENABLE_TRACING_LEVEL_KEY = 'enableTracingLevel'; diff --git a/src/utils/hooks/useQueryExecutionSettings.ts b/src/utils/hooks/useQueryExecutionSettings.ts index 5bba35824..0425b87a1 100644 --- a/src/utils/hooks/useQueryExecutionSettings.ts +++ b/src/utils/hooks/useQueryExecutionSettings.ts @@ -1,14 +1,11 @@ +import {useTracingLevelOptionAvailable} from '../../store/reducers/capabilities/hooks'; import type {QuerySettings} from '../../types/store/query'; -import { - DEFAULT_QUERY_SETTINGS, - ENABLE_TRACING_LEVEL_KEY, - QUERY_EXECUTION_SETTINGS_KEY, -} from '../constants'; +import {DEFAULT_QUERY_SETTINGS, QUERY_EXECUTION_SETTINGS_KEY} from '../constants'; import {useSetting} from './useSetting'; export const useQueryExecutionSettings = () => { - const [enableTracingLevel] = useSetting(ENABLE_TRACING_LEVEL_KEY); + const enableTracingLevel = useTracingLevelOptionAvailable(); const [setting, setSetting] = useSetting(QUERY_EXECUTION_SETTINGS_KEY); return [ From 5b80904e22ca80383d2e7e0e52d6775da384e2b1 Mon Sep 17 00:00:00 2001 From: Anton Standrik Date: Mon, 19 Aug 2024 18:27:54 +0300 Subject: [PATCH 6/6] fix: preview hides when opening query settings (#1187) --- .../Tenant/Query/QueryEditor/QueryEditor.tsx | 1 - tests/suites/nodes/nodes.test.ts | 6 +-- tests/suites/storage/storage.test.ts | 6 +-- .../suites/tenant/queryEditor/QueryEditor.ts | 34 ++++++++++++- .../tenant/queryEditor/queryEditor.test.ts | 4 +- tests/suites/tenant/summary/ObjectSummary.ts | 45 +++++++++++++++++ .../tenant/summary/objectSummary.test.ts | 50 +++++++++++++++++++ tests/utils/constants.ts | 2 + 8 files changed, 138 insertions(+), 10 deletions(-) create mode 100644 tests/suites/tenant/summary/ObjectSummary.ts create mode 100644 tests/suites/tenant/summary/objectSummary.test.ts diff --git a/src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx b/src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx index 6b98f9835..68632cc89 100644 --- a/src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx +++ b/src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx @@ -187,7 +187,6 @@ function QueryEditor(props: QueryEditorProps) { const handleSettingsClick = () => { props.setQueryAction('settings'); - props.setShowPreview(false); }; const handleGetExplainQueryClick = useEventHandler(() => { diff --git a/tests/suites/nodes/nodes.test.ts b/tests/suites/nodes/nodes.test.ts index 89797c3d7..3ebb4ff90 100644 --- a/tests/suites/nodes/nodes.test.ts +++ b/tests/suites/nodes/nodes.test.ts @@ -24,7 +24,7 @@ test.describe('Test Nodes page', async () => { test.describe('Test Nodes Paginated Table', async () => { test.beforeEach(async ({page}) => { const nodesPage = new NodesPage(page); - let response = await nodesPage.goto(); + const response = await nodesPage.goto(); expect(response?.ok()).toBe(true); // Wil be removed since it's an experiment @@ -32,8 +32,8 @@ test.describe('Test Nodes Paginated Table', async () => { localStorage.setItem('useBackendParamsForTables', 'true'); location.reload(); }); - response = await nodesPage.goto(); - expect(response?.ok()).toBe(true); + + await page.waitForLoadState('networkidle'); }); test('Table loads and displays data', async ({page}) => { diff --git a/tests/suites/storage/storage.test.ts b/tests/suites/storage/storage.test.ts index d10c044bb..57a2665f4 100644 --- a/tests/suites/storage/storage.test.ts +++ b/tests/suites/storage/storage.test.ts @@ -35,7 +35,7 @@ test.describe('Test Storage page', async () => { test.describe('Test Storage Paginated Table', async () => { test.beforeEach(async ({page}) => { const nodesPage = new StoragePage(page); - let response = await nodesPage.goto(); + const response = await nodesPage.goto(); expect(response?.ok()).toBe(true); // Wil be removed since it's an experiment @@ -43,8 +43,8 @@ test.describe('Test Storage Paginated Table', async () => { localStorage.setItem('useBackendParamsForTables', 'true'); location.reload(); }); - response = await nodesPage.goto(); - expect(response?.ok()).toBe(true); + + await page.waitForLoadState('networkidle'); }); test('Table loads and displays data', async ({page}) => { diff --git a/tests/suites/tenant/queryEditor/QueryEditor.ts b/tests/suites/tenant/queryEditor/QueryEditor.ts index 4dbb500e3..ccd5688b0 100644 --- a/tests/suites/tenant/queryEditor/QueryEditor.ts +++ b/tests/suites/tenant/queryEditor/QueryEditor.ts @@ -82,9 +82,11 @@ export class SettingsDialog { export class ResultTable { private table: Locator; + private preview: Locator; constructor(selector: Locator) { this.table = selector.locator('.ydb-query-execute-result__result'); + this.preview = selector.locator('.kv-preview__result'); } async isVisible() { @@ -97,6 +99,16 @@ export class ResultTable { return true; } + async isPreviewVisible() { + await this.preview.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT}); + return true; + } + + async isPreviewHidden() { + await this.preview.waitFor({state: 'hidden', timeout: VISIBILITY_TIMEOUT}); + return true; + } + async getRowCount() { const rows = this.table.locator('tr'); return rows.count(); @@ -110,8 +122,8 @@ export class ResultTable { export class QueryEditor { settingsDialog: SettingsDialog; - resultTable: ResultTable; + private resultTable: ResultTable; private page: Page; private selector: Locator; private editorTextArea: Locator; @@ -211,6 +223,10 @@ export class QueryEditor { await this.editorTextArea.focus(); } + async closeSettingsDialog() { + await this.settingsDialog.clickButton(ButtonNames.Cancel); + } + async clickGearButton() { await this.gearButton.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT}); await this.gearButton.click(); @@ -248,6 +264,22 @@ export class QueryEditor { return true; } + async isResultTableVisible() { + return await this.resultTable.isVisible(); + } + + async isResultTableHidden() { + return await this.resultTable.isHidden(); + } + + async isPreviewVisible() { + return await this.resultTable.isPreviewVisible(); + } + + async isPreviewHidden() { + return await this.resultTable.isPreviewHidden(); + } + async isStopButtonVisible() { await this.stopButton.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT}); return true; diff --git a/tests/suites/tenant/queryEditor/queryEditor.test.ts b/tests/suites/tenant/queryEditor/queryEditor.test.ts index 084cf8ff8..89ad235aa 100644 --- a/tests/suites/tenant/queryEditor/queryEditor.test.ts +++ b/tests/suites/tenant/queryEditor/queryEditor.test.ts @@ -53,14 +53,14 @@ test.describe('Test Query Editor', async () => { const queryEditor = new QueryEditor(page); await queryEditor.run(testQuery, QueryMode.YQLScript); - await expect(queryEditor.resultTable.isVisible()).resolves.toBe(true); + await expect(queryEditor.isResultTableVisible()).resolves.toBe(true); }); test('Run button executes Scan', async ({page}) => { const queryEditor = new QueryEditor(page); await queryEditor.run(testQuery, QueryMode.Scan); - await expect(queryEditor.resultTable.isVisible()).resolves.toBe(true); + await expect(queryEditor.isResultTableVisible()).resolves.toBe(true); }); test('Explain button executes YQL script explanation', async ({page}) => { diff --git a/tests/suites/tenant/summary/ObjectSummary.ts b/tests/suites/tenant/summary/ObjectSummary.ts new file mode 100644 index 000000000..b9cdc0666 --- /dev/null +++ b/tests/suites/tenant/summary/ObjectSummary.ts @@ -0,0 +1,45 @@ +import type {Locator, Page} from '@playwright/test'; + +export const VISIBILITY_TIMEOUT = 5000; + +export class ObjectSummary { + private tree: Locator; + private treeRows: Locator; + + constructor(page: Page) { + this.tree = page.locator('.object-summary__tree'); + this.treeRows = page.locator('.ydb-tree-view'); + } + + async isTreeVisible() { + await this.tree.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT}); + return true; + } + + async isTreeHidden() { + await this.tree.waitFor({state: 'hidden', timeout: VISIBILITY_TIMEOUT}); + return true; + } + + async isOpenPreviewIconVisibleOnHover(text: string): Promise { + const treeItem = this.treeRows.filter({hasText: text}).first(); + await treeItem.hover(); + + const openPreviewIcon = treeItem.locator('button[title="Open preview"]'); + + try { + await openPreviewIcon.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT}); + return true; + } catch (error) { + return false; + } + } + + async clickPreviewButton(text: string): Promise { + const treeItem = this.treeRows.filter({hasText: text}).first(); + await treeItem.hover(); + + const openPreviewIcon = treeItem.locator('button[title="Open preview"]'); + await openPreviewIcon.click(); + } +} diff --git a/tests/suites/tenant/summary/objectSummary.test.ts b/tests/suites/tenant/summary/objectSummary.test.ts new file mode 100644 index 000000000..8a13249b9 --- /dev/null +++ b/tests/suites/tenant/summary/objectSummary.test.ts @@ -0,0 +1,50 @@ +import {expect, test} from '@playwright/test'; + +import {dsVslotsSchema, dsVslotsTableName, tenantName} from '../../../utils/constants'; +import {TenantPage} from '../TenantPage'; +import {QueryEditor} from '../queryEditor/QueryEditor'; + +import {ObjectSummary} from './ObjectSummary'; + +test.describe('Object Summary', async () => { + test.beforeEach(async ({page}) => { + const pageQueryParams = { + schema: dsVslotsSchema, + name: tenantName, + general: 'query', + }; + const tenantPage = new TenantPage(page); + await tenantPage.goto(pageQueryParams); + }); + + test('Open Preview icon appears on hover for "test" tree item', async ({page}) => { + const objectSummary = new ObjectSummary(page); + await expect(objectSummary.isTreeVisible()).resolves.toBe(true); + + const isPreviewIconVisible = + await objectSummary.isOpenPreviewIconVisibleOnHover(dsVslotsTableName); + expect(isPreviewIconVisible).toBe(true); + }); + + test('On Open Preview icon click table with results appear', async ({page}) => { + const objectSummary = new ObjectSummary(page); + const queryEditor = new QueryEditor(page); + + await expect(objectSummary.isTreeVisible()).resolves.toBe(true); + await expect(queryEditor.isResultTableHidden()).resolves.toBe(true); + + await objectSummary.clickPreviewButton(dsVslotsTableName); + await expect(queryEditor.isPreviewVisible()).resolves.toBe(true); + }); + + test('Preview table is still present after settings dialog was opened', async ({page}) => { + const objectSummary = new ObjectSummary(page); + const queryEditor = new QueryEditor(page); + + await objectSummary.clickPreviewButton(dsVslotsTableName); + await queryEditor.clickGearButton(); + await queryEditor.closeSettingsDialog(); + + await expect(queryEditor.isPreviewVisible()).resolves.toBe(true); + }); +}); diff --git a/tests/utils/constants.ts b/tests/utils/constants.ts index 48af8fb14..c8af86810 100644 --- a/tests/utils/constants.ts +++ b/tests/utils/constants.ts @@ -8,6 +8,8 @@ export const tenantPage = 'tenant'; // Entities export const tenantName = '/local'; +export const dsVslotsSchema = '/local/.sys/ds_vslots'; +export const dsVslotsTableName = 'ds_vslots'; // URLs export const backend = process.env.PLAYWRIGHT_APP_BACKEND || 'http://localhost:8765';