diff --git a/src/components/EntityStatus/EntityStatus.scss b/src/components/EntityStatus/EntityStatus.scss index 8af099ae5c..d1cfc99b0a 100644 --- a/src/components/EntityStatus/EntityStatus.scss +++ b/src/components/EntityStatus/EntityStatus.scss @@ -142,8 +142,4 @@ color: var(--ydb-color-status-red); } } - - &__info-popover { - padding: var(--g-spacing-4); - } } diff --git a/src/components/EntityStatus/EntityStatus.tsx b/src/components/EntityStatus/EntityStatus.tsx index 66c3926bb7..0c3ec929f3 100644 --- a/src/components/EntityStatus/EntityStatus.tsx +++ b/src/components/EntityStatus/EntityStatus.tsx @@ -5,6 +5,7 @@ import {Button, ClipboardButton, Icon, Popover, Link as UIKitLink} from '@gravit import {EFlag} from '../../types/api/enums'; import {cn} from '../../utils/cn'; +import {YDB_POPOVER_CLASS_NAME} from '../../utils/constants'; import {InternalLink} from '../InternalLink/InternalLink'; import {StatusIcon} from '../StatusIcon/StatusIcon'; import type {StatusIconMode, StatusIconSize} from '../StatusIcon/StatusIcon'; @@ -120,7 +121,7 @@ export function EntityStatus({ > {infoPopoverContent && ( setInfoIconHovered(visible)} diff --git a/src/components/HoverPopup/HoverPopup.scss b/src/components/HoverPopup/HoverPopup.scss deleted file mode 100644 index 97f17f7e00..0000000000 --- a/src/components/HoverPopup/HoverPopup.scss +++ /dev/null @@ -1,3 +0,0 @@ -.ydb-hover-popup { - padding: var(--g-spacing-4); -} diff --git a/src/components/HoverPopup/HoverPopup.tsx b/src/components/HoverPopup/HoverPopup.tsx index 460c17e06d..b78b0f63ab 100644 --- a/src/components/HoverPopup/HoverPopup.tsx +++ b/src/components/HoverPopup/HoverPopup.tsx @@ -4,14 +4,10 @@ import type {PopupProps} from '@gravity-ui/uikit'; import {Popup} from '@gravity-ui/uikit'; import debounce from 'lodash/debounce'; -import {cn} from '../../utils/cn'; - -import './HoverPopup.scss'; +import {YDB_POPOVER_CLASS_NAME} from '../../utils/constants'; const DEBOUNCE_TIMEOUT = 100; -const b = cn('ydb-hover-popup'); - type HoverPopupProps = { children: React.ReactNode; renderPopupContent: () => React.ReactNode; @@ -112,7 +108,7 @@ export const HoverPopup = ({ // bigger offset for easier switching to neighbour nodes // matches the default offset for popup with arrow out of a sense of beauty offset={offset || {mainAxis: 12, crossAxis: 0}} - className={b()} + className={YDB_POPOVER_CLASS_NAME} >
( -
+ {'\u00a0'} {row.Encryption && ( - + )} -
+ ), sortable: false, }; diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TenantMemory.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TenantMemory.tsx index 56daba04b9..ec39172ac0 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TenantMemory.tsx +++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TenantMemory.tsx @@ -1,8 +1,12 @@ import {InfoViewer} from '../../../../../components/InfoViewer/InfoViewer'; import {ProgressWrapper} from '../../../../../components/ProgressWrapper'; +import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../../../store/reducers/tenant/constants'; import type {TMemoryStats} from '../../../../../types/api/nodes'; import {cn} from '../../../../../utils/cn'; import {formatStorageValuesToGb} from '../../../../../utils/dataFormatters/dataFormatters'; +import {useSearchQuery} from '../../../../../utils/hooks'; +import {TenantTabsGroups, getTenantPath} from '../../../TenantPages'; +import {StatsWrapper} from '../StatsWrapper/StatsWrapper'; import {TenantDashboard} from '../TenantDashboard/TenantDashboard'; import i18n from '../i18n'; @@ -27,6 +31,7 @@ export function TenantMemory({ memoryUsed, memoryLimit, }: TenantMemoryProps) { + const query = useSearchQuery(); const renderMemoryDetails = () => { if (memoryStats) { return ; @@ -61,7 +66,16 @@ export function TenantMemory({
{renderMemoryDetails()} - + + + +
); } diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TopNodesByMemory.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TopNodesByMemory.tsx index 659df30a52..754f8dddb2 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TopNodesByMemory.tsx +++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TopNodesByMemory.tsx @@ -17,18 +17,15 @@ import { import type {GetNodesColumnsParams} from '../../../../../components/nodesColumns/types'; import {nodesApi} from '../../../../../store/reducers/nodes/nodes'; import type {NodesPreparedEntity} from '../../../../../store/reducers/nodes/types'; -import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../../../store/reducers/tenant/constants'; import type {AdditionalNodesProps} from '../../../../../types/additionalProps'; import type {NodesRequiredField} from '../../../../../types/api/nodes'; import { TENANT_OVERVIEW_TABLES_LIMIT, TENANT_OVERVIEW_TABLES_SETTINGS, } from '../../../../../utils/constants'; -import {useAutoRefreshInterval, useSearchQuery} from '../../../../../utils/hooks'; +import {useAutoRefreshInterval} from '../../../../../utils/hooks'; import {getRequiredDataFields} from '../../../../../utils/tableUtils/getRequiredDataFields'; -import {TenantTabsGroups, getTenantPath} from '../../../TenantPages'; import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout'; -import {getSectionTitle} from '../getSectionTitle'; import i18n from '../i18n'; function getTopNodesByMemoryColumns( @@ -56,8 +53,6 @@ interface TopNodesByMemoryProps { } export function TopNodesByMemory({tenantName, additionalNodesProps}: TopNodesByMemoryProps) { - const query = useSearchQuery(); - const [autoRefreshInterval] = useAutoRefreshInterval(); const [columns, fieldsRequired] = getTopNodesByMemoryColumns({ getNodeRef: additionalNodesProps?.getNodeRef, @@ -80,22 +75,8 @@ export function TopNodesByMemory({tenantName, additionalNodesProps}: TopNodesByM const topNodes = currentData?.Nodes || []; - const title = getSectionTitle({ - entity: i18n('nodes'), - postfix: i18n('by-memory'), - link: getTenantPath({ - ...query, - [TenantTabsGroups.diagnosticsTab]: TENANT_DIAGNOSTICS_TABS_IDS.nodes, - }), - }); - return ( - + { - switch (networkTab) { - case TENANT_NETWORK_TABS_IDS.ping: { - return ( - - ); - } - case TENANT_NETWORK_TABS_IDS.skew: { - return ( - - ); - } - default: { - return null; - } - } - }; + const allNodesLink = getTenantPath({ + ...query, + ...tab, + }); return ( - - - - {networkTabs.map(({id, title}) => { - return ( - handleNetworkTabChange(id)}> - {title} - - ); - })} - - - - - {renderTabContent()} - - + + + + + + ); } diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantNetwork/TopNodesByPing.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantNetwork/TopNodesByPing.tsx index b0e4dd6baa..48edb030a0 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantNetwork/TopNodesByPing.tsx +++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantNetwork/TopNodesByPing.tsx @@ -1,16 +1,13 @@ import {ResizeableDataTable} from '../../../../../components/ResizeableDataTable/ResizeableDataTable'; import {NODES_COLUMNS_WIDTH_LS_KEY} from '../../../../../components/nodesColumns/constants'; import {nodesApi} from '../../../../../store/reducers/nodes/nodes'; -import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../../../store/reducers/tenant/constants'; import type {AdditionalNodesProps} from '../../../../../types/additionalProps'; import { TENANT_OVERVIEW_TABLES_LIMIT, TENANT_OVERVIEW_TABLES_SETTINGS, } from '../../../../../utils/constants'; -import {useAutoRefreshInterval, useSearchQuery} from '../../../../../utils/hooks'; -import {TenantTabsGroups, getTenantPath} from '../../../TenantPages'; +import {useAutoRefreshInterval} from '../../../../../utils/hooks'; import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout'; -import {getSectionTitle} from '../getSectionTitle'; import i18n from '../i18n'; import {getTopNodesByPingColumns} from './columns'; @@ -21,7 +18,6 @@ interface TopNodesByPingProps { } export function TopNodesByPing({tenantName, additionalNodesProps}: TopNodesByPingProps) { - const query = useSearchQuery(); const [autoRefreshInterval] = useAutoRefreshInterval(); const [columns, fieldsRequired] = getTopNodesByPingColumns({ getNodeRef: additionalNodesProps?.getNodeRef, @@ -43,22 +39,8 @@ export function TopNodesByPing({tenantName, additionalNodesProps}: TopNodesByPin const loading = isFetching && currentData === undefined; const topNodes = currentData?.Nodes || []; - const title = getSectionTitle({ - entity: i18n('nodes'), - postfix: i18n('by-ping'), - link: getTenantPath({ - ...query, - [TenantTabsGroups.diagnosticsTab]: TENANT_DIAGNOSTICS_TABS_IDS.nodes, - }), - }); - return ( - + + { - if (!queryParams.networkTab) { - return TENANT_NETWORK_TABS_IDS.ping; - } - const validTabs = Object.values(TENANT_NETWORK_TABS_IDS) as string[]; - return validTabs.includes(queryParams.networkTab) - ? (queryParams.networkTab as TenantNetworkTab) - : TENANT_NETWORK_TABS_IDS.ping; - })(); - - const handleNetworkTabChange = (value: TenantNetworkTab) => { - setQueryParams({networkTab: value}, 'replaceIn'); - }; - - return { - networkTab, - handleNetworkTabChange, - }; -} diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.scss b/src/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.scss deleted file mode 100644 index d84d6f5f99..0000000000 --- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.scss +++ /dev/null @@ -1,9 +0,0 @@ -.tenant-storage { - &__tabs-container { - margin-top: var(--g-spacing-3); - } - - &__tab-content { - margin-top: var(--g-spacing-3); - } -} diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.tsx index fe438cc7ef..4df7995609 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.tsx +++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.tsx @@ -1,29 +1,19 @@ -import React from 'react'; - -import {Tab, TabList, TabProvider} from '@gravity-ui/uikit'; +import {Flex} from '@gravity-ui/uikit'; import {InfoViewer} from '../../../../../components/InfoViewer/InfoViewer'; import {LabelWithPopover} from '../../../../../components/LabelWithPopover'; import {ProgressWrapper} from '../../../../../components/ProgressWrapper'; -import {TENANT_STORAGE_TABS_IDS} from '../../../../../store/reducers/tenant/constants'; -import {cn} from '../../../../../utils/cn'; +import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../../../store/reducers/tenant/constants'; import {formatStorageValues} from '../../../../../utils/dataFormatters/dataFormatters'; +import {useSearchQuery} from '../../../../../utils/hooks'; +import {TenantTabsGroups, getTenantPath} from '../../../TenantPages'; +import {StatsWrapper} from '../StatsWrapper/StatsWrapper'; import {TenantDashboard} from '../TenantDashboard/TenantDashboard'; import i18n from '../i18n'; import {TopGroups} from './TopGroups'; import {TopTables} from './TopTables'; import {storageDashboardConfig} from './storageDashboardConfig'; -import {useTenantStorageQueryParams} from './useTenantStorageQueryParams'; - -import './TenantStorage.scss'; - -const tenantStorageCn = cn('tenant-storage'); - -const storageTabs = [ - {id: TENANT_STORAGE_TABS_IDS.tables, title: i18n('title_top-tables-by-size')}, - {id: TENANT_STORAGE_TABS_IDS.groups, title: i18n('title_top-groups-by-usage')}, -]; export interface TenantStorageMetrics { blobStorageUsed?: number; @@ -38,20 +28,8 @@ interface TenantStorageProps { } export function TenantStorage({tenantName, metrics}: TenantStorageProps) { - const {storageTab, handleStorageTabChange} = useTenantStorageQueryParams(); - const {blobStorageUsed, tabletStorageUsed, blobStorageLimit, tabletStorageLimit} = metrics; - - const renderTabContent = () => { - switch (storageTab) { - case TENANT_STORAGE_TABS_IDS.tables: - return ; - case TENANT_STORAGE_TABS_IDS.groups: - return ; - default: - return null; - } - }; + const query = useSearchQuery(); const info = [ { @@ -89,25 +67,21 @@ export function TenantStorage({tenantName, metrics}: TenantStorageProps) { ]; return ( - + - -
- - - {storageTabs.map(({id, title}) => { - return ( - handleStorageTabChange(id)}> - {title} - - ); - })} - - - -
{renderTabContent()}
-
-
+ + + + + + + ); } diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopGroups.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopGroups.tsx index 3cfbe19641..73d0b02a48 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopGroups.tsx +++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopGroups.tsx @@ -4,13 +4,12 @@ import { useStorageGroupsHandlerAvailable, } from '../../../../../store/reducers/capabilities/hooks'; import {storageApi} from '../../../../../store/reducers/storage/storage'; -import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../../../store/reducers/tenant/constants'; import type {GroupsRequiredField} from '../../../../../types/api/storage'; import { TENANT_OVERVIEW_TABLES_LIMIT, TENANT_OVERVIEW_TABLES_SETTINGS, } from '../../../../../utils/constants'; -import {useAutoRefreshInterval, useSearchQuery} from '../../../../../utils/hooks'; +import {useAutoRefreshInterval} from '../../../../../utils/hooks'; import {getRequiredDataFields} from '../../../../../utils/tableUtils/getRequiredDataFields'; import {getStorageTopGroupsColumns} from '../../../../Storage/PaginatedStorageGroupsTable/columns/columns'; import { @@ -18,10 +17,7 @@ import { STORAGE_GROUPS_COLUMNS_WIDTH_LS_KEY, } from '../../../../Storage/PaginatedStorageGroupsTable/columns/constants'; import type {StorageGroupsColumn} from '../../../../Storage/PaginatedStorageGroupsTable/columns/types'; -import {TenantTabsGroups, getTenantPath} from '../../../TenantPages'; import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout'; -import {getSectionTitle} from '../getSectionTitle'; -import i18n from '../i18n'; function getColumns(): [StorageGroupsColumn[], GroupsRequiredField[]] { const preparedColumns = getStorageTopGroupsColumns(); @@ -37,8 +33,6 @@ interface TopGroupsProps { } export function TopGroups({tenant}: TopGroupsProps) { - const query = useSearchQuery(); - const capabilitiesLoaded = useCapabilitiesLoaded(); const groupsHandlerAvailable = useStorageGroupsHandlerAvailable(); const [autoRefreshInterval] = useAutoRefreshInterval(); @@ -64,18 +58,8 @@ export function TopGroups({tenant}: TopGroupsProps) { const groups = currentData?.groups || []; - const title = getSectionTitle({ - entity: i18n('groups'), - postfix: i18n('by-usage'), - link: getTenantPath({ - ...query, - [TenantTabsGroups.diagnosticsTab]: TENANT_DIAGNOSTICS_TABS_IDS.storage, - }), - }); - return ( { - const size = getBytesSizeUnit(data?.length ? Number(data[0].Size) : 0); - - return formatBytes({value, size, precision: 1}); - }; - +function getColumns(size: ReturnType) { const columns: Column[] = [ { name: 'Size', width: 100, - render: ({row}) => formatSize(Number(row.Size)), + render: ({row}) => formatBytes({value: Number(row.Size), size, precision: 1}), align: DataTable.RIGHT, }, { @@ -55,6 +39,22 @@ export function TopTables({database}: TopTablesProps) { ) : null, }, ]; + return columns; +} + +export function TopTables({database}: TopTablesProps) { + const [autoRefreshInterval] = useAutoRefreshInterval(); + + const {currentData, error, isFetching} = topTablesApi.useGetTopTablesQuery( + {database}, + {pollingInterval: autoRefreshInterval}, + ); + const loading = isFetching && currentData === undefined; + + const data = currentData?.resultSets?.[0]?.result || []; + const size = getBytesSizeUnit(data?.length ? Number(data[0].Size) : 0); + const columns = React.useMemo(() => getColumns(size), [size]); + return ( { - setQueryParams({storageTab: value}, 'replaceIn'); - }; - - return { - storageTab, - handleStorageTabChange, - }; -} diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/getSectionTitle.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/getSectionTitle.tsx deleted file mode 100644 index d2fa500352..0000000000 --- a/src/containers/Tenant/Diagnostics/TenantOverview/getSectionTitle.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react'; - -import {InternalLink} from '../../../../components/InternalLink/InternalLink'; - -import i18n from './i18n'; - -interface GetSectionTitleParams { - entity: string; - postfix: string; - prefix?: string; - link?: string; - onClick?: () => void; -} - -// Titles are formed by the principle "Top entities by parameter" -export const getSectionTitle = ({ - prefix = i18n('top'), - entity, - postfix, - link, - onClick, -}: GetSectionTitleParams) => { - if (link) { - return ( - - {prefix}{' '} - - {entity} - {' '} - {postfix} - - ); - } - - return `${prefix} ${entity} ${postfix}`; -}; diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json b/src/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json index 292498fec3..44fe1650f5 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json +++ b/src/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json @@ -1,12 +1,5 @@ { "top-nodes.empty-data": "No such nodes", - "top": "Top", - "nodes": "nodes", - "groups": "groups", - "by-memory": "by memory", - "by-ping": "by ping time", - "by-skew": "by clock skew", - "by-usage": "by usage", "title_top-nodes-load": "Top nodes by load", "title_top-nodes-pool": "Top nodes by pools usage", "cards.cpu-label": "CPU load", @@ -35,12 +28,11 @@ "storage.db-storage-description": "Size of data stored in distributed storage with all overheads for redundancy", "title_top-shards": "Top shards by CPU usage", "title_top-queries": "Top queries by CPU usage", - "title_top-tables-by-size": "Top Tables By Size", - "title_top-groups-by-usage": "Top Groups By Usage", - "title_nodes-by-ping": "Nodes By Ping Time", - "title_nodes-by-skew": "Nodes By Clock Skew", - "action_by-load": "By Load", - "action_by-pool-usage": "By Pool Usage", + "title_top-tables-by-size": "Top tables by size", + "title_top-groups-by-usage": "Top groups by usage", + "title_top-nodes-by-memory": "Top nodes by memory", + "title_nodes-by-ping": "Top nodes by ping time", + "title_nodes-by-skew": "Top nodes by clock skew", "title_memory-details": "Memory Details", "field_memory-usage": "Memory usage", "context_capacity-usage": "{{value}} of {{capacity}}", diff --git a/src/store/reducers/tenant/constants.ts b/src/store/reducers/tenant/constants.ts index 73ff9f79b9..c54a78a147 100644 --- a/src/store/reducers/tenant/constants.ts +++ b/src/store/reducers/tenant/constants.ts @@ -44,13 +44,3 @@ export const TENANT_METRICS_TABS_IDS = { memory: 'memory', network: 'network', } as const; - -export const TENANT_STORAGE_TABS_IDS = { - tables: 'tables', - groups: 'groups', -} as const; - -export const TENANT_NETWORK_TABS_IDS = { - ping: 'ping', - skew: 'skew', -} as const; diff --git a/src/store/reducers/tenant/types.ts b/src/store/reducers/tenant/types.ts index eb4df29063..4ad67475aa 100644 --- a/src/store/reducers/tenant/types.ts +++ b/src/store/reducers/tenant/types.ts @@ -2,11 +2,10 @@ import {z} from 'zod'; import type {ValueOf} from '../../../types/common'; -import {TENANT_PAGES_IDS, TENANT_STORAGE_TABS_IDS} from './constants'; +import {TENANT_PAGES_IDS} from './constants'; import type { TENANT_DIAGNOSTICS_TABS_IDS, TENANT_METRICS_TABS_IDS, - TENANT_NETWORK_TABS_IDS, TENANT_QUERY_TABS_ID, TENANT_SUMMARY_TABS_IDS, } from './constants'; @@ -14,18 +13,11 @@ import type { export const tenantPageSchema = z.nativeEnum(TENANT_PAGES_IDS); export type TenantPage = z.infer; -export const tenantStorageTabSchema = z - .nativeEnum(TENANT_STORAGE_TABS_IDS) - .catch(TENANT_STORAGE_TABS_IDS.tables); - export type TenantQueryTab = ValueOf; export type TenantDiagnosticsTab = ValueOf; export type TenantSummaryTab = ValueOf; export type TenantMetricsTab = ValueOf; -export type TenantStorageTab = ValueOf; -export type TenantNetworkTab = ValueOf; - export interface TenantState { tenantPage: TenantPage; queryTab?: TenantQueryTab; diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 2192fd15fe..c4ae821be0 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -200,3 +200,5 @@ export enum AclSyntax { Ydb = 'ydb', Yql = 'yql', } + +export const YDB_POPOVER_CLASS_NAME = 'ydb-popover';