ydb-embedded-ui 6.10.2 → 6.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/dist/components/DeveloperUiLink/DeveloperUiLink.d.ts +8 -0
  2. package/dist/components/DeveloperUiLink/DeveloperUiLink.js +9 -0
  3. package/dist/components/DeveloperUiLink/DeveloperUiLink.scss +11 -0
  4. package/dist/components/NodeHostWrapper/NodeHostWrapper.js +9 -2
  5. package/dist/containers/Tablets/Tablets.js +5 -1
  6. package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.js +2 -3
  7. package/dist/containers/Tenant/Diagnostics/Overview/Overview.js +5 -10
  8. package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/TableInfo.d.ts +1 -3
  9. package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/TableInfo.js +3 -3
  10. package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/prepareTableInfo.d.ts +1 -2
  11. package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/prepareTableInfo.js +28 -57
  12. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +28 -3
  13. package/dist/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.js +5 -14
  14. package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.js +4 -14
  15. package/dist/containers/Tenant/Diagnostics/TopShards/getTopShardsColumns.js +5 -1
  16. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.js +4 -4
  17. package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.js +15 -5
  18. package/dist/containers/Tenant/Schema/SchemaViewer/SchemaViewer.js +2 -5
  19. package/dist/containers/Tenant/Tenant.js +2 -2
  20. package/dist/store/reducers/executeTopQueries/executeTopQueries.js +1 -0
  21. package/dist/store/reducers/schema/schema.d.ts +13 -2
  22. package/dist/store/reducers/schema/schema.js +36 -21
  23. package/dist/types/api/schema/schema.d.ts +21 -0
  24. package/dist/utils/diagnostics.d.ts +21 -17
  25. package/dist/utils/diagnostics.js +28 -7
  26. package/dist/utils/monaco/yql/yql.completionItemProvider.js +1 -1
  27. package/package.json +1 -1
  28. package/dist/store/reducers/olapStats.d.ts +0 -5
  29. package/dist/store/reducers/olapStats.js +0 -31
@@ -0,0 +1,8 @@
1
+ import './DeveloperUiLink.scss';
2
+ interface DeveloperUiLinkProps {
3
+ className?: string;
4
+ visible?: boolean;
5
+ href: string;
6
+ }
7
+ export declare function DeveloperUiLink({ href, visible, className }: DeveloperUiLinkProps): import("react/jsx-runtime").JSX.Element;
8
+ export {};
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { ArrowUpRightFromSquare } from '@gravity-ui/icons';
3
+ import { Button, Icon } from '@gravity-ui/uikit';
4
+ import { cn } from '../../utils/cn';
5
+ import './DeveloperUiLink.scss';
6
+ const b = cn('developer-ui-link');
7
+ export function DeveloperUiLink({ href, visible = false, className }) {
8
+ return (_jsx(Button, { size: "s", href: href, className: b({ visible }, className), target: "_blank", children: _jsx(Icon, { data: ArrowUpRightFromSquare }) }));
9
+ }
@@ -0,0 +1,11 @@
1
+ .developer-ui-link {
2
+ display: none;
3
+
4
+ &_visible {
5
+ display: inline-block;
6
+ }
7
+
8
+ .data-table__row:hover & {
9
+ display: inline-block;
10
+ }
11
+ }
@@ -3,6 +3,7 @@ import { ArrowUpRightFromSquare } from '@gravity-ui/icons';
3
3
  import { Button, Icon, PopoverBehavior } from '@gravity-ui/uikit';
4
4
  import { getDefaultNodePath } from '../../containers/Node/NodePages';
5
5
  import { cn } from '../../utils/cn';
6
+ import { createDeveloperUILinkWithNodeId } from '../../utils/developerUI/developerUI';
6
7
  import { isUnavailableNode } from '../../utils/nodes';
7
8
  import { CellWithPopover } from '../CellWithPopover/CellWithPopover';
8
9
  import { EntityStatus } from '../EntityStatus/EntityStatus';
@@ -14,12 +15,18 @@ export const NodeHostWrapper = ({ node, getNodeRef }) => {
14
15
  return _jsx("span", { children: "\u2014" });
15
16
  }
16
17
  const isNodeAvailable = !isUnavailableNode(node);
17
- const nodeRef = isNodeAvailable && getNodeRef ? getNodeRef(node) + 'internal' : undefined;
18
+ let nodeHref;
19
+ if (getNodeRef) {
20
+ nodeHref = getNodeRef(node) + 'internal';
21
+ }
22
+ else if (node.NodeId) {
23
+ nodeHref = createDeveloperUILinkWithNodeId(node.NodeId) + 'internal';
24
+ }
18
25
  const nodePath = isNodeAvailable
19
26
  ? getDefaultNodePath(node.NodeId, {
20
27
  tenantName: node.TenantName,
21
28
  })
22
29
  : undefined;
23
- const additionalControls = nodeRef ? (_jsx(Button, { size: "s", href: nodeRef, className: b('external-button'), target: "_blank", children: _jsx(Icon, { data: ArrowUpRightFromSquare }) })) : null;
30
+ const additionalControls = nodeHref ? (_jsx(Button, { size: "s", href: nodeHref, className: b('external-button'), target: "_blank", children: _jsx(Icon, { data: ArrowUpRightFromSquare }) })) : null;
24
31
  return (_jsx(CellWithPopover, { disabled: !isNodeAvailable, content: _jsx(NodeEndpointsTooltipContent, { data: node }), placement: ['top', 'bottom'], behavior: PopoverBehavior.Immediate, children: _jsx(EntityStatus, { name: node.Host, status: node.SystemState, path: nodePath, hasClipboardButton: true, additionalControls: additionalControls }) }));
25
32
  };
@@ -3,12 +3,14 @@ import { ArrowsRotateRight } from '@gravity-ui/icons';
3
3
  import { Icon, Label, Text } from '@gravity-ui/uikit';
4
4
  import { skipToken } from '@reduxjs/toolkit/query';
5
5
  import { ButtonWithConfirmDialog } from '../../components/ButtonWithConfirmDialog/ButtonWithConfirmDialog';
6
+ import { DeveloperUiLink } from '../../components/DeveloperUiLink/DeveloperUiLink';
6
7
  import { EntityStatus } from '../../components/EntityStatus/EntityStatus';
7
8
  import { ResponseError } from '../../components/Errors/ResponseError';
8
9
  import { InternalLink } from '../../components/InternalLink';
9
10
  import { ResizeableDataTable } from '../../components/ResizeableDataTable/ResizeableDataTable';
10
11
  import { TableSkeleton } from '../../components/TableSkeleton/TableSkeleton';
11
12
  import routes, { createHref } from '../../routes';
13
+ import { backend } from '../../store';
12
14
  import { selectTabletsWithFqdn, tabletsApi } from '../../store/reducers/tablets';
13
15
  import { ETabletState } from '../../types/api/tablet';
14
16
  import { cn } from '../../utils/cn';
@@ -31,13 +33,15 @@ const columns = [
31
33
  },
32
34
  {
33
35
  name: 'TabletId',
36
+ width: 230,
34
37
  get header() {
35
38
  return i18n('Tablet');
36
39
  },
37
40
  render: ({ row }) => {
41
+ var _a;
38
42
  const tabletPath = row.TabletId &&
39
43
  createHref(routes.tablet, { id: row.TabletId }, { nodeId: row.NodeId, type: row.Type });
40
- return _jsx(InternalLink, { to: tabletPath, children: row.TabletId });
44
+ return (_jsx(EntityStatus, { name: (_a = row.TabletId) === null || _a === void 0 ? void 0 : _a.toString(), path: tabletPath, hasClipboardButton: true, showStatus: false, additionalControls: _jsx(DeveloperUiLink, { href: `${backend}/tablets?TabletID=${row.TabletId}` }) }));
41
45
  },
42
46
  },
43
47
  {
@@ -6,7 +6,7 @@ import { Button, Card, Icon } from '@gravity-ui/uikit';
6
6
  import { ResponseError } from '../../../../components/Errors/ResponseError';
7
7
  import { ResizeableDataTable } from '../../../../components/ResizeableDataTable/ResizeableDataTable';
8
8
  import { hotKeysApi } from '../../../../store/reducers/hotKeys/hotKeys';
9
- import { schemaApi } from '../../../../store/reducers/schema/schema';
9
+ import { useGetSchemaQuery } from '../../../../store/reducers/schema/schema';
10
10
  import { cn } from '../../../../utils/cn';
11
11
  import { DEFAULT_TABLE_SETTINGS, IS_HOTKEYS_HELP_HIDDEN_KEY } from '../../../../utils/constants';
12
12
  import { useSetting } from '../../../../utils/hooks';
@@ -41,8 +41,7 @@ export function HotKeys({ path }) {
41
41
  var _a, _b;
42
42
  const { currentData: data, isFetching, error } = hotKeysApi.useGetHotKeysQuery({ path });
43
43
  const loading = isFetching && data === undefined;
44
- const { currentData: schemaData, isFetching: schemaIsFetching } = schemaApi.endpoints.getSchema.useQueryState({ path });
45
- const schemaLoading = schemaIsFetching && schemaData === undefined;
44
+ const { data: schemaData, isLoading: schemaLoading } = useGetSchemaQuery({ path });
46
45
  const keyColumnsIds = (_b = (_a = schemaData === null || schemaData === void 0 ? void 0 : schemaData.PathDescription) === null || _a === void 0 ? void 0 : _a.Table) === null || _b === void 0 ? void 0 : _b.KeyColumnNames;
47
46
  const tableColumns = React.useMemo(() => {
48
47
  return getHotKeysColumns(keyColumnsIds);
@@ -4,25 +4,20 @@ import { shallowEqual } from 'react-redux';
4
4
  import { ResponseError } from '../../../../components/Errors/ResponseError';
5
5
  import { TableIndexInfo } from '../../../../components/InfoViewer/schemaInfo';
6
6
  import { Loader } from '../../../../components/Loader';
7
- import { olapApi } from '../../../../store/reducers/olapStats';
8
7
  import { overviewApi } from '../../../../store/reducers/overview/overview';
9
- import { schemaApi, selectSchemaMergedChildrenPaths } from '../../../../store/reducers/schema/schema';
8
+ import { selectSchemaMergedChildrenPaths, useGetSchemaQuery, } from '../../../../store/reducers/schema/schema';
10
9
  import { EPathType } from '../../../../types/api/schema';
11
10
  import { useAutoRefreshInterval, useTypedSelector } from '../../../../utils/hooks';
12
11
  import { ExternalDataSourceInfo } from '../../Info/ExternalDataSource/ExternalDataSource';
13
12
  import { ExternalTableInfo } from '../../Info/ExternalTable/ExternalTable';
14
13
  import { ViewInfo } from '../../Info/View/View';
15
- import { isColumnEntityType, isEntityWithMergedImplementation, isTableType, } from '../../utils/schema';
14
+ import { isEntityWithMergedImplementation } from '../../utils/schema';
16
15
  import { AsyncReplicationInfo } from './AsyncReplicationInfo';
17
16
  import { ChangefeedInfo } from './ChangefeedInfo';
18
17
  import { TableInfo } from './TableInfo';
19
18
  import { TopicInfo } from './TopicInfo';
20
19
  function Overview({ type, path }) {
21
20
  const [autoRefreshInterval] = useAutoRefreshInterval();
22
- const olapParams = isTableType(type) && isColumnEntityType(type) ? { path } : skipToken;
23
- const { currentData: olapData, isFetching: olapIsFetching } = olapApi.useGetOlapStatsQuery(olapParams, { pollingInterval: autoRefreshInterval });
24
- const olapStatsLoading = olapIsFetching && olapData === undefined;
25
- const { result: olapStats } = olapData || { result: undefined };
26
21
  const isEntityWithMergedImpl = isEntityWithMergedImplementation(type);
27
22
  // shallowEqual prevents rerenders when new schema data is loaded
28
23
  const mergedChildrenPaths = useTypedSelector((state) => selectSchemaMergedChildrenPaths(state, path, type), shallowEqual);
@@ -38,8 +33,8 @@ function Overview({ type, path }) {
38
33
  });
39
34
  const overviewLoading = isFetching && currentData === undefined;
40
35
  const { data: rawData, additionalData } = currentData || {};
41
- const { error: schemaError } = schemaApi.endpoints.getSchema.useQueryState({ path });
42
- const entityLoading = overviewLoading || olapStatsLoading;
36
+ const { error: schemaError } = useGetSchemaQuery({ path });
37
+ const entityLoading = overviewLoading;
43
38
  const entityNotReady = isEntityWithMergedImpl && !mergedChildrenPaths;
44
39
  const renderContent = () => {
45
40
  var _a;
@@ -65,7 +60,7 @@ function Overview({ type, path }) {
65
60
  [EPathType.EPathTypeView]: () => _jsx(ViewInfo, { data: data }),
66
61
  [EPathType.EPathTypeReplication]: () => _jsx(AsyncReplicationInfo, { data: data }),
67
62
  };
68
- return ((type && ((_a = pathTypeToComponent[type]) === null || _a === void 0 ? void 0 : _a.call(pathTypeToComponent))) || (_jsx(TableInfo, { data: data, type: type, olapStats: olapStats })));
63
+ return (type && ((_a = pathTypeToComponent[type]) === null || _a === void 0 ? void 0 : _a.call(pathTypeToComponent))) || _jsx(TableInfo, { data: data, type: type });
69
64
  };
70
65
  if (entityLoading || entityNotReady) {
71
66
  return _jsx(Loader, { size: "m" });
@@ -1,10 +1,8 @@
1
- import type { KeyValueRow } from '../../../../../types/api/query';
2
1
  import type { EPathType, TEvDescribeSchemeResult } from '../../../../../types/api/schema';
3
2
  import './TableInfo.scss';
4
3
  interface TableInfoProps {
5
4
  data?: TEvDescribeSchemeResult;
6
5
  type?: EPathType;
7
- olapStats?: KeyValueRow[];
8
6
  }
9
- export declare const TableInfo: ({ data, type, olapStats }: TableInfoProps) => import("react/jsx-runtime").JSX.Element;
7
+ export declare const TableInfo: ({ data, type }: TableInfoProps) => import("react/jsx-runtime").JSX.Element;
10
8
  export {};
@@ -7,8 +7,8 @@ import i18n from './i18n';
7
7
  import { prepareTableInfo } from './prepareTableInfo';
8
8
  import './TableInfo.scss';
9
9
  const b = cn('ydb-diagnostics-table-info');
10
- export const TableInfo = ({ data, type, olapStats }) => {
10
+ export const TableInfo = ({ data, type }) => {
11
11
  const title = _jsx(EntityTitle, { data: data === null || data === void 0 ? void 0 : data.PathDescription });
12
- const { generalInfo = [], tableStatsInfo = [], tabletMetricsInfo = [], partitionConfigInfo = [], } = React.useMemo(() => prepareTableInfo(data, type, olapStats), [data, type, olapStats]);
13
- return (_jsxs("div", { className: b(), children: [_jsx(InfoViewer, { info: generalInfo, title: title, className: b('info-block'), renderEmptyState: () => _jsx("div", { className: b('title'), children: title }) }), _jsxs("div", { className: b('row'), children: [_jsx("div", { className: b('col'), children: tableStatsInfo.map((info, index) => (_jsx(InfoViewer, { info: info, title: index === 0 ? i18n('tableStats') : undefined, className: b('info-block'), renderEmptyState: () => null }, index))) }), tabletMetricsInfo.length > 0 || partitionConfigInfo.length > 0 ? (_jsxs("div", { className: b('col'), children: [_jsx(InfoViewer, { info: tabletMetricsInfo, title: i18n('tabletMetrics'), className: b('info-block'), renderEmptyState: () => null }), _jsx(InfoViewer, { info: partitionConfigInfo, title: i18n('partitionConfig'), className: b('info-block'), renderEmptyState: () => null })] })) : null] })] }));
12
+ const { generalInfo, tableStatsInfo, tabletMetricsInfo = [], partitionConfigInfo = [], } = React.useMemo(() => prepareTableInfo(data, type), [data, type]);
13
+ return (_jsxs("div", { className: b(), children: [_jsx(InfoViewer, { info: generalInfo, title: title, className: b('info-block'), renderEmptyState: () => _jsx("div", { className: b('title'), children: title }) }), _jsxs("div", { className: b('row'), children: [tableStatsInfo ? (_jsx("div", { className: b('col'), children: tableStatsInfo.map((info, index) => (_jsx(InfoViewer, { info: info, title: index === 0 ? i18n('tableStats') : undefined, className: b('info-block'), renderEmptyState: () => null }, index))) })) : null, tabletMetricsInfo.length > 0 || partitionConfigInfo.length > 0 ? (_jsxs("div", { className: b('col'), children: [_jsx(InfoViewer, { info: tabletMetricsInfo, title: i18n('tabletMetrics'), className: b('info-block'), renderEmptyState: () => null }), _jsx(InfoViewer, { info: partitionConfigInfo, title: i18n('partitionConfig'), className: b('info-block'), renderEmptyState: () => null })] })) : null] })] }));
14
14
  };
@@ -1,9 +1,8 @@
1
1
  import type { InfoViewerItem } from '../../../../../components/InfoViewer';
2
- import type { KeyValueRow } from '../../../../../types/api/query';
3
2
  import type { TEvDescribeSchemeResult } from '../../../../../types/api/schema';
4
3
  import { EPathType } from '../../../../../types/api/schema';
5
4
  /** Prepares data for Table, ColumnTable and ColumnStore */
6
- export declare const prepareTableInfo: (data?: TEvDescribeSchemeResult, type?: EPathType, olapStats?: KeyValueRow[]) => {
5
+ export declare const prepareTableInfo: (data?: TEvDescribeSchemeResult, type?: EPathType) => {
7
6
  generalInfo?: undefined;
8
7
  tableStatsInfo?: undefined;
9
8
  tabletMetricsInfo?: undefined;
@@ -3,31 +3,10 @@ import { formatFollowerGroupItem, formatPartitionConfigItem, formatTableStatsIte
3
3
  import { EPathType } from '../../../../../types/api/schema';
4
4
  import { formatBytes, formatNumber } from '../../../../../utils/dataFormatters/dataFormatters';
5
5
  import { formatDurationToShortTimeFormat } from '../../../../../utils/timeParsers';
6
- import { isNumeric } from '../../../../../utils/utils';
7
6
  const isInStoreColumnTable = (table) => {
8
7
  // SchemaPresetId could be 0
9
8
  return table.SchemaPresetName && table.SchemaPresetId !== undefined;
10
9
  };
11
- const prepareOlapStats = (olapStats) => {
12
- var _a, _b, _c;
13
- const Bytes = olapStats === null || olapStats === void 0 ? void 0 : olapStats.reduce((acc, el) => {
14
- const value = isNumeric(el.Bytes) ? Number(el.Bytes) : 0;
15
- return acc + value;
16
- }, 0);
17
- const Rows = olapStats === null || olapStats === void 0 ? void 0 : olapStats.reduce((acc, el) => {
18
- const value = isNumeric(el.Rows) ? Number(el.Rows) : 0;
19
- return acc + value;
20
- }, 0);
21
- const tabletIds = olapStats === null || olapStats === void 0 ? void 0 : olapStats.reduce((acc, el) => {
22
- acc.add(el.TabletId);
23
- return acc;
24
- }, new Set());
25
- return [
26
- { label: 'PartCount', value: (_a = tabletIds === null || tabletIds === void 0 ? void 0 : tabletIds.size) !== null && _a !== void 0 ? _a : 0 },
27
- { label: 'RowCount', value: (_b = formatNumber(Rows)) !== null && _b !== void 0 ? _b : 0 },
28
- { label: 'DataSize', value: (_c = formatBytes(Bytes)) !== null && _c !== void 0 ? _c : 0 },
29
- ];
30
- };
31
10
  const prepareTTL = (ttl) => {
32
11
  // ExpireAfterSeconds could be 0
33
12
  if (ttl.Enabled && ttl.Enabled.ColumnName && ttl.Enabled.ExpireAfterSeconds !== undefined) {
@@ -97,7 +76,7 @@ const prepareTableGeneralInfo = (PartitionConfig, TTLSettings) => {
97
76
  return generalTableInfo;
98
77
  };
99
78
  /** Prepares data for Table, ColumnTable and ColumnStore */
100
- export const prepareTableInfo = (data, type, olapStats) => {
79
+ export const prepareTableInfo = (data, type) => {
101
80
  if (!data) {
102
81
  return {};
103
82
  }
@@ -116,41 +95,33 @@ export const prepareTableInfo = (data, type, olapStats) => {
116
95
  break;
117
96
  }
118
97
  }
119
- let tableStatsInfo;
120
- // There is no TableStats and TabletMetrics for ColumnTables inside ColumnStore
121
- // Therefore we parse olapStats
122
- if (type === EPathType.EPathTypeColumnTable && isInStoreColumnTable(ColumnTableDescription)) {
123
- tableStatsInfo = [prepareOlapStats(olapStats)];
124
- }
125
- else {
126
- tableStatsInfo = [
127
- formatObject(formatTableStatsItem, {
128
- PartCount,
129
- RowCount,
130
- DataSize,
131
- IndexSize,
132
- }),
133
- formatObject(formatTableStatsItem, {
134
- LastAccessTime,
135
- LastUpdateTime,
136
- }),
137
- formatObject(formatTableStatsItem, {
138
- ImmediateTxCompleted,
139
- PlannedTxCompleted,
140
- TxRejectedByOverload,
141
- TxRejectedBySpace,
142
- TxCompleteLagMsec,
143
- InFlightTxCount,
144
- }),
145
- formatObject(formatTableStatsItem, {
146
- RowUpdates,
147
- RowDeletes,
148
- RowReads,
149
- RangeReads,
150
- RangeReadRows,
151
- }),
152
- ];
153
- }
98
+ const tableStatsInfo = [
99
+ formatObject(formatTableStatsItem, {
100
+ PartCount,
101
+ RowCount,
102
+ DataSize,
103
+ IndexSize,
104
+ }),
105
+ formatObject(formatTableStatsItem, {
106
+ LastAccessTime,
107
+ LastUpdateTime,
108
+ }),
109
+ formatObject(formatTableStatsItem, {
110
+ ImmediateTxCompleted,
111
+ PlannedTxCompleted,
112
+ TxRejectedByOverload,
113
+ TxRejectedBySpace,
114
+ TxCompleteLagMsec,
115
+ InFlightTxCount,
116
+ }),
117
+ formatObject(formatTableStatsItem, {
118
+ RowUpdates,
119
+ RowDeletes,
120
+ RowReads,
121
+ RangeReads,
122
+ RangeReadRows,
123
+ }),
124
+ ];
154
125
  //@ts-expect-error
155
126
  const tabletMetricsInfo = formatObject(formatTabletMetricsItem, TabletMetrics);
156
127
  let partitionConfigInfo = [];
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Loader } from '@gravity-ui/uikit';
3
3
  import { EntityStatus } from '../../../../components/EntityStatus/EntityStatus';
4
+ import { useGetSchemaQuery } from '../../../../store/reducers/schema/schema';
4
5
  import { TENANT_METRICS_TABS_IDS } from '../../../../store/reducers/tenant/constants';
5
6
  import { tenantApi } from '../../../../store/reducers/tenant/tenant';
6
7
  import { calculateTenantMetrics } from '../../../../store/reducers/tenants/utils';
@@ -16,7 +17,7 @@ import { TenantStorage } from './TenantStorage/TenantStorage';
16
17
  import { b } from './utils';
17
18
  import './TenantOverview.scss';
18
19
  export function TenantOverview({ tenantName, additionalTenantProps, additionalNodesProps, }) {
19
- var _a;
20
+ var _a, _b, _c;
20
21
  const { metricsTab } = useTypedSelector((state) => state.tenant);
21
22
  const [autoRefreshInterval] = useAutoRefreshInterval();
22
23
  const { currentData: tenant, isFetching } = tenantApi.useGetTenantInfoQuery({ path: tenantName }, {
@@ -25,7 +26,31 @@ export function TenantOverview({ tenantName, additionalTenantProps, additionalNo
25
26
  const tenantLoading = isFetching && tenant === undefined;
26
27
  const { Name, Type, Overall } = tenant || {};
27
28
  const tenantType = mapDatabaseTypeToDBName(Type);
28
- const { blobStorage, tabletStorage, blobStorageLimit, tabletStorageLimit, poolsStats, memoryStats, blobStorageStats, tabletStorageStats, } = calculateTenantMetrics(tenant !== null && tenant !== void 0 ? tenant : undefined);
29
+ // FIXME: remove after correct data is added to tenantInfo
30
+ const { data: tenantSchemaData } = useGetSchemaQuery({ path: tenantName });
31
+ const { Tables, Topics } = ((_b = (_a = tenantSchemaData === null || tenantSchemaData === void 0 ? void 0 : tenantSchemaData.PathDescription) === null || _a === void 0 ? void 0 : _a.DomainDescription) === null || _b === void 0 ? void 0 : _b.DiskSpaceUsage) || {};
32
+ const usedTabletStorage = [
33
+ Tables === null || Tables === void 0 ? void 0 : Tables.TotalSize,
34
+ Topics === null || Topics === void 0 ? void 0 : Topics.AccountSize,
35
+ Topics === null || Topics === void 0 ? void 0 : Topics.DataSize,
36
+ Topics === null || Topics === void 0 ? void 0 : Topics.ReserveSize,
37
+ Topics === null || Topics === void 0 ? void 0 : Topics.UsedReserveSize,
38
+ ].reduce((sum, current) => {
39
+ if (current) {
40
+ return sum + Number(current);
41
+ }
42
+ return sum;
43
+ }, 0);
44
+ const tenantData = {
45
+ ...tenant,
46
+ Metrics: {
47
+ ...tenant === null || tenant === void 0 ? void 0 : tenant.Metrics,
48
+ // Replace incorrect tenant metric with correct value
49
+ Storage: String(usedTabletStorage),
50
+ },
51
+ };
52
+ // === === ===
53
+ const { blobStorage, tabletStorage, blobStorageLimit, tabletStorageLimit, poolsStats, memoryStats, blobStorageStats, tabletStorageStats, } = calculateTenantMetrics(tenantData);
29
54
  const storageMetrics = {
30
55
  blobStorageUsed: blobStorage,
31
56
  blobStorageLimit,
@@ -57,5 +82,5 @@ export function TenantOverview({ tenantName, additionalTenantProps, additionalNo
57
82
  if (tenantLoading) {
58
83
  return (_jsx("div", { className: b('loader'), children: _jsx(Loader, { size: "m" }) }));
59
84
  }
60
- return (_jsxs("div", { className: b(), children: [_jsxs("div", { className: b('info'), children: [_jsx("div", { className: b('top-label'), children: tenantType }), _jsxs("div", { className: b('top'), children: [renderName(), (_a = additionalTenantProps === null || additionalTenantProps === void 0 ? void 0 : additionalTenantProps.getMonitoringLink) === null || _a === void 0 ? void 0 : _a.call(additionalTenantProps, Name, Type)] }), _jsx(MetricsCards, { poolsCpuStats: poolsStats, memoryStats: memoryStats, blobStorageStats: blobStorageStats, tabletStorageStats: tabletStorageStats, tenantName: tenantName })] }), renderTabContent()] }));
85
+ return (_jsxs("div", { className: b(), children: [_jsxs("div", { className: b('info'), children: [_jsx("div", { className: b('top-label'), children: tenantType }), _jsxs("div", { className: b('top'), children: [renderName(), (_c = additionalTenantProps === null || additionalTenantProps === void 0 ? void 0 : additionalTenantProps.getMonitoringLink) === null || _c === void 0 ? void 0 : _c.call(additionalTenantProps, Name, Type)] }), _jsx(MetricsCards, { poolsCpuStats: poolsStats, memoryStats: memoryStats, blobStorageStats: blobStorageStats, tabletStorageStats: tabletStorageStats, tenantName: tenantName })] }), renderTabContent()] }));
61
86
  }
@@ -3,26 +3,17 @@ import DataTable from '@gravity-ui/react-data-table';
3
3
  import { OneLineQueryWithPopover, TruncatedQuery, } from '../../../../components/TruncatedQuery/TruncatedQuery';
4
4
  import { cn } from '../../../../utils/cn';
5
5
  import { formatDateTime, formatNumber } from '../../../../utils/dataFormatters/dataFormatters';
6
+ import { TOP_QUERIES_COLUMNS_IDS } from '../../../../utils/diagnostics';
6
7
  import { generateHash } from '../../../../utils/generateHash';
7
- import { parseUsToMs } from '../../../../utils/timeParsers';
8
+ import { formatToMs, parseUsToMs } from '../../../../utils/timeParsers';
8
9
  import { MAX_QUERY_HEIGHT } from '../../utils/constants';
9
10
  import './TopQueries.scss';
10
11
  const b = cn('kv-top-queries');
11
12
  export const TOP_QUERIES_COLUMNS_WIDTH_LS_KEY = 'topQueriesColumnsWidth';
12
- const TOP_QUERIES_COLUMNS_IDS = {
13
- CPUTimeUs: 'CPUTimeUs',
14
- QueryText: 'QueryText',
15
- EndTime: 'EndTime',
16
- ReadRows: 'ReadRows',
17
- ReadBytes: 'ReadBytes',
18
- UserSID: 'UserSID',
19
- OneLineQueryText: 'OneLineQueryText',
20
- QueryHash: 'QueryHash',
21
- Duration: 'Duration',
22
- };
23
13
  const cpuTimeUsColumn = {
24
14
  name: TOP_QUERIES_COLUMNS_IDS.CPUTimeUs,
25
15
  sortAccessor: (row) => Number(row.CPUTimeUs),
16
+ render: ({ row }) => { var _a; return formatToMs(parseUsToMs((_a = row.CPUTimeUs) !== null && _a !== void 0 ? _a : undefined)); },
26
17
  width: 120,
27
18
  align: DataTable.RIGHT,
28
19
  sortable: false,
@@ -78,8 +69,8 @@ const queryHashColumn = {
78
69
  };
79
70
  const durationColumn = {
80
71
  name: TOP_QUERIES_COLUMNS_IDS.Duration,
81
- header: 'Duration, ms',
82
- render: ({ row }) => { var _a; return formatNumber(parseUsToMs((_a = row.Duration) !== null && _a !== void 0 ? _a : undefined)); },
72
+ header: 'Duration',
73
+ render: ({ row }) => { var _a; return formatToMs(parseUsToMs((_a = row.Duration) !== null && _a !== void 0 ? _a : undefined)); },
83
74
  sortAccessor: (row) => Number(row.Duration),
84
75
  align: DataTable.RIGHT,
85
76
  width: 150,
@@ -9,7 +9,7 @@ import { EShardsWorkloadMode } from '../../../../store/reducers/shardsWorkload/t
9
9
  import { cn } from '../../../../utils/cn';
10
10
  import { DEFAULT_TABLE_SETTINGS, HOUR_IN_SECONDS } from '../../../../utils/constants';
11
11
  import { formatDateTime } from '../../../../utils/dataFormatters/dataFormatters';
12
- import { isSortableTopShardsProperty } from '../../../../utils/diagnostics';
12
+ import { TOP_SHARD_COLUMNS_IDS, isSortableTopShardsProperty } from '../../../../utils/diagnostics';
13
13
  import { useAutoRefreshInterval, useTypedDispatch, useTypedSelector } from '../../../../utils/hooks';
14
14
  import { parseQueryErrorToString } from '../../../../utils/query';
15
15
  import { isColumnEntityType } from '../../utils/schema';
@@ -25,16 +25,6 @@ const TABLE_SETTINGS = {
25
25
  disableSortReset: true,
26
26
  defaultOrder: DataTable.DESCENDING,
27
27
  };
28
- const tableColumnsNames = {
29
- TabletId: 'TabletId',
30
- CPUCores: 'CPUCores',
31
- DataSize: 'DataSize',
32
- Path: 'Path',
33
- NodeId: 'NodeId',
34
- PeakTime: 'PeakTime',
35
- InFlightTxCount: 'InFlightTxCount',
36
- IntervalEnd: 'IntervalEnd',
37
- };
38
28
  function prepareDateTimeValue(value) {
39
29
  if (!value) {
40
30
  return '–';
@@ -83,7 +73,7 @@ export const TopShards = ({ tenantName, path, type }) => {
83
73
  }
84
74
  return defaultValue;
85
75
  });
86
- const [sortOrder, setSortOrder] = React.useState(tableColumnsNames.CPUCores);
76
+ const [sortOrder, setSortOrder] = React.useState(TOP_SHARD_COLUMNS_IDS.CPUCores);
87
77
  const { data: result, isFetching, error, } = shardApi.useSendShardQueryQuery({
88
78
  database: tenantName,
89
79
  path: path,
@@ -124,14 +114,14 @@ export const TopShards = ({ tenantName, path, type }) => {
124
114
  if (filters.mode === EShardsWorkloadMode.History) {
125
115
  // after NodeId
126
116
  columns.splice(5, 0, {
127
- name: tableColumnsNames.PeakTime,
117
+ name: TOP_SHARD_COLUMNS_IDS.PeakTime,
128
118
  render: ({ row }) => {
129
119
  return prepareDateTimeValue(row.PeakTime);
130
120
  },
131
121
  sortable: false,
132
122
  });
133
123
  columns.push({
134
- name: tableColumnsNames.IntervalEnd,
124
+ name: TOP_SHARD_COLUMNS_IDS.IntervalEnd,
135
125
  render: ({ row }) => {
136
126
  return prepareDateTimeValue(row.IntervalEnd);
137
127
  },
@@ -1,9 +1,12 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import DataTable from '@gravity-ui/react-data-table';
3
+ import { DeveloperUiLink } from '../../../../components/DeveloperUiLink/DeveloperUiLink';
4
+ import { EntityStatus } from '../../../../components/EntityStatus/EntityStatus';
3
5
  import { InternalLink } from '../../../../components/InternalLink';
4
6
  import { LinkToSchemaObject } from '../../../../components/LinkToSchemaObject/LinkToSchemaObject';
5
7
  import { UsageLabel } from '../../../../components/UsageLabel/UsageLabel';
6
8
  import routes, { createHref } from '../../../../routes';
9
+ import { backend } from '../../../../store';
7
10
  import { getLoadSeverityForShard } from '../../../../store/reducers/tenantOverview/topShards/utils';
8
11
  import { formatNumber, roundToPrecision } from '../../../../utils/dataFormatters/dataFormatters';
9
12
  import { getDefaultNodePath } from '../../../Node/NodePages';
@@ -61,10 +64,11 @@ const tabletIdColumn = {
61
64
  name: TOP_SHARDS_COLUMNS_IDS.TabletId,
62
65
  header: tableColumnsNames[TOP_SHARDS_COLUMNS_IDS.TabletId],
63
66
  render: ({ row }) => {
67
+ var _a;
64
68
  if (!row.TabletId) {
65
69
  return '–';
66
70
  }
67
- return (_jsx(InternalLink, { to: createHref(routes.tablet, { id: row.TabletId }), children: row.TabletId }));
71
+ return (_jsx(EntityStatus, { name: (_a = row.TabletId) === null || _a === void 0 ? void 0 : _a.toString(), path: createHref(routes.tablet, { id: row.TabletId }), hasClipboardButton: true, showStatus: false, additionalControls: _jsx(DeveloperUiLink, { href: `${backend}/tablets?TabletID=${row.TabletId}` }) }));
68
72
  },
69
73
  sortable: false,
70
74
  width: 190,
@@ -13,7 +13,7 @@ import { LinkWithIcon } from '../../../components/LinkWithIcon/LinkWithIcon';
13
13
  import { Loader } from '../../../components/Loader';
14
14
  import SplitPane from '../../../components/SplitPane';
15
15
  import routes, { createExternalUILink, createHref } from '../../../routes';
16
- import { schemaApi, setShowPreview } from '../../../store/reducers/schema/schema';
16
+ import { setShowPreview, useGetSchemaQuery } from '../../../store/reducers/schema/schema';
17
17
  import { TENANT_PAGES_IDS, TENANT_QUERY_TABS_ID, TENANT_SUMMARY_TABS_IDS, } from '../../../store/reducers/tenant/constants';
18
18
  import { setQueryTab, setSummaryTab, setTenantPage } from '../../../store/reducers/tenant/tenant';
19
19
  import { EPathSubType, EPathType } from '../../../types/api/schema';
@@ -48,7 +48,7 @@ export function ObjectSummary({ type, subType, tenantName, path, onCollapseSumma
48
48
  const queryParams = qs.parse(location.search, {
49
49
  ignoreQueryPrefix: true,
50
50
  });
51
- const { currentData: currentObjectData } = schemaApi.endpoints.getSchema.useQueryState({ path });
51
+ const { data: currentObjectData } = useGetSchemaQuery({ path });
52
52
  const currentSchemaData = (_a = currentObjectData === null || currentObjectData === void 0 ? void 0 : currentObjectData.PathDescription) === null || _a === void 0 ? void 0 : _a.Self;
53
53
  React.useEffect(() => {
54
54
  const isTable = isTableType(type);
@@ -255,12 +255,12 @@ export function ObjectSummary({ type, subType, tenantName, path, onCollapseSumma
255
255
  }
256
256
  function ObjectTree({ tenantName, path }) {
257
257
  var _a;
258
- const { currentData: tenantData = {}, isFetching } = schemaApi.useGetSchemaQuery({
258
+ const { data: tenantData = {}, isLoading } = useGetSchemaQuery({
259
259
  path: tenantName,
260
260
  });
261
261
  const pathData = (_a = tenantData === null || tenantData === void 0 ? void 0 : tenantData.PathDescription) === null || _a === void 0 ? void 0 : _a.Self;
262
262
  const [, setCurrentPath] = useQueryParam('schema', StringParam);
263
- if (!pathData && isFetching) {
263
+ if (!pathData && isLoading) {
264
264
  // If Loader isn't wrapped with div, SplitPane doesn't calculate panes height correctly
265
265
  return (_jsx("div", { children: _jsx(Loader, {}) }));
266
266
  }
@@ -20,13 +20,23 @@ export function SchemaTree(props) {
20
20
  const [parentPath, setParentPath] = React.useState('');
21
21
  const [schemaTreeKey, setSchemaTreeKey] = React.useState('');
22
22
  const fetchPath = async (path) => {
23
- const promise = dispatch(schemaApi.endpoints.getSchema.initiate({ path }, { forceRefetch: true }));
24
- const { data } = await promise;
25
- promise.unsubscribe();
26
- if (!data) {
23
+ let schemaData;
24
+ do {
25
+ const promise = dispatch(schemaApi.endpoints.getSchema.initiate({ path }, { forceRefetch: true }));
26
+ const { data, originalArgs } = await promise;
27
+ promise.unsubscribe();
28
+ // Check if the result from the current request is received. rtk-query may skip the current request and
29
+ // return data from a parallel request, due to the same cache key.
30
+ if ((originalArgs === null || originalArgs === void 0 ? void 0 : originalArgs.path) === path) {
31
+ schemaData = data === null || data === void 0 ? void 0 : data[path];
32
+ break;
33
+ }
34
+ // eslint-disable-next-line no-constant-condition
35
+ } while (true);
36
+ if (!schemaData) {
27
37
  throw new Error(`no describe data about path ${path}`);
28
38
  }
29
- const { PathDescription: { Children = [] } = {} } = data;
39
+ const { PathDescription: { Children = [] } = {} } = schemaData;
30
40
  const childItems = Children.map((childData) => {
31
41
  const { Name = '', PathType, PathSubType } = childData;
32
42
  return {
@@ -4,7 +4,7 @@ import DataTable from '@gravity-ui/react-data-table';
4
4
  import { skipToken } from '@reduxjs/toolkit/query';
5
5
  import { ResizeableDataTable } from '../../../../components/ResizeableDataTable/ResizeableDataTable';
6
6
  import { TableSkeleton } from '../../../../components/TableSkeleton/TableSkeleton';
7
- import { schemaApi } from '../../../../store/reducers/schema/schema';
7
+ import { useGetSchemaQuery } from '../../../../store/reducers/schema/schema';
8
8
  import { viewSchemaApi } from '../../../../store/reducers/viewSchema/viewSchema';
9
9
  import { DEFAULT_TABLE_SETTINGS } from '../../../../utils/constants';
10
10
  import { isColumnEntityType, isExternalTableType, isRowTableType, isViewType, } from '../../utils/schema';
@@ -13,10 +13,7 @@ import { prepareSchemaData, prepareViewSchema } from './prepareData';
13
13
  import { b } from './shared';
14
14
  import './SchemaViewer.scss';
15
15
  export const SchemaViewer = ({ type, path, tenantName, extended = false }) => {
16
- const { currentData: schemaData, isFetching } = schemaApi.endpoints.getSchema.useQueryState({
17
- path,
18
- });
19
- const loading = isFetching && schemaData === undefined;
16
+ const { data: schemaData, isLoading: loading } = useGetSchemaQuery({ path });
20
17
  const viewSchemaRequestParams = isViewType(type) ? { path, database: tenantName } : skipToken;
21
18
  const { data: viewColumnsData, isLoading: isViewSchemaLoading } = viewSchemaApi.useGetViewSchemaQuery(viewSchemaRequestParams);
22
19
  const tableData = React.useMemo(() => {
@@ -6,7 +6,7 @@ import { AccessDenied } from '../../components/Errors/403';
6
6
  import { Loader } from '../../components/Loader';
7
7
  import SplitPane from '../../components/SplitPane';
8
8
  import { setHeaderBreadcrumbs } from '../../store/reducers/header/header';
9
- import { schemaApi } from '../../store/reducers/schema/schema';
9
+ import { useGetSchemaQuery } from '../../store/reducers/schema/schema';
10
10
  import { cn } from '../../utils/cn';
11
11
  import { DEFAULT_IS_TENANT_SUMMARY_COLLAPSED, DEFAULT_SIZE_TENANT_KEY } from '../../utils/constants';
12
12
  import { useTypedDispatch } from '../../utils/hooks';
@@ -47,7 +47,7 @@ export function Tenant(props) {
47
47
  dispatch(setHeaderBreadcrumbs('tenant', { tenantName }));
48
48
  }, [tenantName, dispatch]);
49
49
  const path = schema !== null && schema !== void 0 ? schema : tenantName;
50
- const { currentData: currentItem, error, isLoading, } = schemaApi.useGetSchemaQuery({ path }, { refetchOnMountOrArgChange: true });
50
+ const { data: currentItem, error, isLoading } = useGetSchemaQuery({ path });
51
51
  const { PathType: currentPathType, PathSubType: currentPathSubType } = ((_a = currentItem === null || currentItem === void 0 ? void 0 : currentItem.PathDescription) === null || _a === void 0 ? void 0 : _a.Self) || {};
52
52
  let showBlockingError = false;
53
53
  if (error && typeof error === 'object' && 'status' in error) {
@@ -29,6 +29,7 @@ SELECT
29
29
  Duration
30
30
  FROM \`${path}/.sys/top_queries_by_cpu_time_one_hour\`
31
31
  WHERE ${filterConditions || 'true'}
32
+ ORDER BY CPUTimeUs DESC
32
33
  `;
33
34
  };
34
35
  export const topQueriesApi = api.injectEndpoints({
@@ -21,11 +21,22 @@ export declare const schemaApi: import("@reduxjs/toolkit/query").Api<import("@re
21
21
  }, import("@reduxjs/toolkit/query").BaseQueryFn<void, typeof import("../api")._NEVER, unknown, {}>, "All", unknown, "api">;
22
22
  getSchema: import("@reduxjs/toolkit/query").QueryDefinition<{
23
23
  path: string;
24
- }, import("@reduxjs/toolkit/query").BaseQueryFn<void, typeof import("../api")._NEVER, unknown, {}>, "All", TEvDescribeSchemeResult & {
25
- partial?: boolean;
24
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<void, typeof import("../api")._NEVER, unknown, {}>, "All", {
25
+ [path: string]: TEvDescribeSchemeResult & {
26
+ partial?: boolean;
27
+ };
26
28
  }, "api">;
27
29
  }, "api", "All", typeof import("@reduxjs/toolkit/query").coreModuleName | typeof import("@reduxjs/toolkit/query/react").reactHooksModuleName>;
28
30
  export declare const selectSchemaMergedChildrenPaths: Selector<RootState, string[] | undefined, [
29
31
  string | undefined,
30
32
  EPathType | undefined
31
33
  ]>;
34
+ export declare function useGetSchemaQuery({ path }: {
35
+ path: string;
36
+ }): {
37
+ data: (TEvDescribeSchemeResult & {
38
+ partial?: boolean;
39
+ }) | undefined;
40
+ isLoading: boolean;
41
+ error: unknown;
42
+ };
@@ -1,3 +1,4 @@
1
+ import React from 'react';
1
2
  import { createSelector } from '@reduxjs/toolkit';
2
3
  import { isEntityWithMergedImplementation } from '../../../containers/Tenant/utils/schema';
3
4
  import { api } from '../api';
@@ -44,42 +45,44 @@ export const schemaApi = api.injectEndpoints({
44
45
  queryFn: async ({ path }, { signal }) => {
45
46
  try {
46
47
  const data = await window.api.getSchema({ path }, { signal });
47
- return { data: data !== null && data !== void 0 ? data : {} };
48
+ return { data: data ? { [path]: data, ...getSchemaChildren(data) } : {} };
48
49
  }
49
50
  catch (error) {
50
51
  return { error };
51
52
  }
52
53
  },
53
54
  keepUnusedDataFor: Infinity,
54
- forceRefetch: ({ endpointState }) => {
55
- const data = endpointState === null || endpointState === void 0 ? void 0 : endpointState.data;
56
- if (data && typeof data === 'object' && 'partial' in data && data.partial) {
57
- return true;
58
- }
59
- return false;
55
+ serializeQueryArgs: ({ queryArgs: { path } }) => {
56
+ const parts = path.split('/');
57
+ return { path: parts[0] || parts[1] };
60
58
  },
61
- onQueryStarted: async ({ path }, { dispatch, getState, queryFulfilled }) => {
62
- const { data } = await queryFulfilled;
59
+ merge: (existing, incoming, { arg: { path } }) => {
60
+ const { [path]: data, ...children } = incoming;
63
61
  if (data) {
64
- const state = getState();
65
- const { PathDescription: { Children = [] } = {} } = data;
66
- for (const child of Children) {
67
- const { Name = '' } = child;
68
- const childPath = `${path}/${Name}`;
69
- const cachedData = schemaApi.endpoints.getSchema.select({ path: childPath })(state).data;
70
- if (!cachedData) {
71
- // not full data, but it contains PathType, which ensures seamless switch between nodes
72
- dispatch(schemaApi.util.upsertQueryData('getSchema', { path: childPath }, { PathDescription: { Self: child }, partial: true }));
73
- }
74
- }
62
+ return {
63
+ ...children,
64
+ ...existing,
65
+ [path]: data,
66
+ };
75
67
  }
68
+ return existing;
76
69
  },
77
70
  }),
78
71
  }),
79
72
  overrideExisting: 'throw',
80
73
  });
74
+ function getSchemaChildren(data) {
75
+ const children = {};
76
+ const { PathDescription: { Children = [] } = {}, Path: path } = data;
77
+ for (const child of Children) {
78
+ const { Name = '' } = child;
79
+ const childPath = `${path}/${Name}`;
80
+ children[childPath] = { PathDescription: { Self: child }, Path: childPath, partial: true };
81
+ }
82
+ return children;
83
+ }
81
84
  const getSchemaSelector = createSelector((path) => path, (path) => schemaApi.endpoints.getSchema.select({ path }));
82
- const selectGetSchema = createSelector((state) => state, (_state, path) => getSchemaSelector(path), (state, selectTabletsInfo) => selectTabletsInfo(state).data);
85
+ const selectGetSchema = createSelector((state) => state, (_state, path) => path, (_state, path) => getSchemaSelector(path), (state, path, selectTabletsInfo) => { var _a; return (_a = selectTabletsInfo(state).data) === null || _a === void 0 ? void 0 : _a[path]; });
83
86
  const selectSchemaChildren = (state, path) => { var _a, _b; return (_b = (_a = selectGetSchema(state, path)) === null || _a === void 0 ? void 0 : _a.PathDescription) === null || _b === void 0 ? void 0 : _b.Children; };
84
87
  export const selectSchemaMergedChildrenPaths = createSelector([
85
88
  (_, path) => path,
@@ -90,3 +93,15 @@ export const selectSchemaMergedChildrenPaths = createSelector([
90
93
  ? children === null || children === void 0 ? void 0 : children.map(({ Name }) => path + '/' + Name)
91
94
  : undefined;
92
95
  });
96
+ export function useGetSchemaQuery({ path }) {
97
+ const { currentData, isFetching, error, refetch } = schemaApi.useGetSchemaQuery({ path });
98
+ const data = currentData === null || currentData === void 0 ? void 0 : currentData[path];
99
+ const isLoading = isFetching && data === undefined;
100
+ const shouldLoad = !isLoading && ((!data && !error) || (data === null || data === void 0 ? void 0 : data.partial));
101
+ React.useEffect(() => {
102
+ if (shouldLoad) {
103
+ refetch();
104
+ }
105
+ }, [refetch, path, shouldLoad]);
106
+ return { data, isLoading, error };
107
+ }
@@ -148,6 +148,8 @@ interface TDomainState {
148
148
  }
149
149
  interface TDiskSpaceUsage {
150
150
  Tables?: TTables;
151
+ Topics?: TTopics;
152
+ TStoragePoolUsage?: TStoragePoolUsage[];
151
153
  }
152
154
  interface TTables {
153
155
  /** uint64 */
@@ -157,6 +159,25 @@ interface TTables {
157
159
  /** uint64 */
158
160
  IndexSize?: string;
159
161
  }
162
+ interface TTopics {
163
+ /** uint64 */
164
+ ReserveSize?: string;
165
+ /** uint64 */
166
+ AccountSize?: string;
167
+ /** uint64 */
168
+ DataSize?: string;
169
+ /** uint64 */
170
+ UsedReserveSize?: string;
171
+ }
172
+ interface TStoragePoolUsage {
173
+ PoolKind?: string;
174
+ /** uint64 */
175
+ TotalSize?: string;
176
+ /** uint64 */
177
+ DataSize?: string;
178
+ /** uint64 */
179
+ IndexSize?: string;
180
+ }
160
181
  interface TStoragePool {
161
182
  Name?: string;
162
183
  Kind?: string;
@@ -1,19 +1,23 @@
1
- import type { ValueOf } from '../types/common';
2
- declare const TOP_SHARDS_SORT_VALUES: {
3
- readonly CPUCores: "CPUCores";
4
- readonly DataSize: "DataSize";
5
- readonly InFlightTxCount: "InFlightTxCount";
1
+ export declare const TOP_QUERIES_COLUMNS_IDS: {
2
+ CPUTimeUs: string;
3
+ QueryText: string;
4
+ EndTime: string;
5
+ ReadRows: string;
6
+ ReadBytes: string;
7
+ UserSID: string;
8
+ OneLineQueryText: string;
9
+ QueryHash: string;
10
+ Duration: string;
6
11
  };
7
- declare const TOP_QUERIES_SORT_VALUES: {
8
- readonly CPUTimeUs: "CPUTimeUs";
9
- readonly EndTime: "EndTime";
10
- readonly ReadRows: "ReadRows";
11
- readonly ReadBytes: "ReadBytes";
12
- readonly UserSID: "UserSID";
13
- readonly Duration: "Duration";
12
+ export declare const TOP_SHARD_COLUMNS_IDS: {
13
+ TabletId: string;
14
+ CPUCores: string;
15
+ DataSize: string;
16
+ Path: string;
17
+ NodeId: string;
18
+ PeakTime: string;
19
+ InFlightTxCount: string;
20
+ IntervalEnd: string;
14
21
  };
15
- type TopShardsSortValue = ValueOf<typeof TOP_SHARDS_SORT_VALUES>;
16
- type TopQueriesSortValue = ValueOf<typeof TOP_QUERIES_SORT_VALUES>;
17
- export declare const isSortableTopShardsProperty: (value: string) => value is TopShardsSortValue;
18
- export declare const isSortableTopQueriesProperty: (value: string) => value is TopQueriesSortValue;
19
- export {};
22
+ export declare const isSortableTopShardsProperty: (value: string) => boolean;
23
+ export declare const isSortableTopQueriesProperty: (value: string) => boolean;
@@ -1,15 +1,36 @@
1
- const TOP_SHARDS_SORT_VALUES = {
2
- CPUCores: 'CPUCores',
3
- DataSize: 'DataSize',
4
- InFlightTxCount: 'InFlightTxCount',
5
- };
6
- const TOP_QUERIES_SORT_VALUES = {
7
- CPUTimeUs: 'CPUTimeUs',
1
+ export const TOP_QUERIES_COLUMNS_IDS = {
2
+ CPUTimeUs: 'CPUTime',
3
+ QueryText: 'QueryText',
8
4
  EndTime: 'EndTime',
9
5
  ReadRows: 'ReadRows',
10
6
  ReadBytes: 'ReadBytes',
11
7
  UserSID: 'UserSID',
8
+ OneLineQueryText: 'OneLineQueryText',
9
+ QueryHash: 'QueryHash',
12
10
  Duration: 'Duration',
13
11
  };
12
+ export const TOP_SHARD_COLUMNS_IDS = {
13
+ TabletId: 'TabletId',
14
+ CPUCores: 'CPUCores',
15
+ DataSize: 'DataSize',
16
+ Path: 'Path',
17
+ NodeId: 'NodeId',
18
+ PeakTime: 'PeakTime',
19
+ InFlightTxCount: 'InFlightTxCount',
20
+ IntervalEnd: 'IntervalEnd',
21
+ };
22
+ const TOP_SHARDS_SORT_VALUES = [
23
+ TOP_SHARD_COLUMNS_IDS.CPUCores,
24
+ TOP_SHARD_COLUMNS_IDS.DataSize,
25
+ TOP_SHARD_COLUMNS_IDS.InFlightTxCount,
26
+ ];
27
+ const TOP_QUERIES_SORT_VALUES = [
28
+ TOP_QUERIES_COLUMNS_IDS.CPUTimeUs,
29
+ TOP_QUERIES_COLUMNS_IDS.EndTime,
30
+ TOP_QUERIES_COLUMNS_IDS.ReadRows,
31
+ TOP_QUERIES_COLUMNS_IDS.ReadBytes,
32
+ TOP_QUERIES_COLUMNS_IDS.UserSID,
33
+ TOP_QUERIES_COLUMNS_IDS.Duration,
34
+ ];
14
35
  export const isSortableTopShardsProperty = (value) => Object.values(TOP_SHARDS_SORT_VALUES).includes(value);
15
36
  export const isSortableTopQueriesProperty = (value) => Object.values(TOP_QUERIES_SORT_VALUES).includes(value);
@@ -10,7 +10,7 @@ function disableCodeSuggestions() {
10
10
  export function registerYQLCompletionItemProvider(database) {
11
11
  disableCodeSuggestions();
12
12
  completionProvider = monaco.languages.registerCompletionItemProvider(LANGUAGE_YQL_ID, {
13
- triggerCharacters: [' ', '', ',', '.', '`', '(', '/'],
13
+ triggerCharacters: [' ', '.', '`', '(', '/'],
14
14
  provideCompletionItems: createProvideSuggestionsFunction(database),
15
15
  });
16
16
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ydb-embedded-ui",
3
- "version": "6.10.2",
3
+ "version": "6.11.0",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
@@ -1,5 +0,0 @@
1
- export declare const olapApi: import("@reduxjs/toolkit/query").Api<import("@reduxjs/toolkit/query").BaseQueryFn<void, typeof import("./api")._NEVER, unknown, {}>, {
2
- getOlapStats: import("@reduxjs/toolkit/query").QueryDefinition<{
3
- path?: string;
4
- } | undefined, import("@reduxjs/toolkit/query").BaseQueryFn<void, typeof import("./api")._NEVER, unknown, {}>, "All", import("../../types/store/query").IQueryResult | undefined, "api">;
5
- }, "api", "All", typeof import("@reduxjs/toolkit/query").coreModuleName | typeof import("@reduxjs/toolkit/query/react").reactHooksModuleName>;
@@ -1,31 +0,0 @@
1
- import { isQueryErrorResponse, parseQueryAPIExecuteResponse } from '../../utils/query';
2
- import { api } from './api';
3
- function createOlatStatsQuery(path) {
4
- return `SELECT * FROM \`${path}/.sys/primary_index_stats\``;
5
- }
6
- const queryAction = 'execute-scan';
7
- export const olapApi = api.injectEndpoints({
8
- endpoints: (build) => ({
9
- getOlapStats: build.query({
10
- queryFn: async ({ path = '' } = {}, { signal }) => {
11
- try {
12
- const response = await window.api.sendQuery({
13
- schema: 'modern',
14
- query: createOlatStatsQuery(path),
15
- database: path,
16
- action: queryAction,
17
- }, { signal });
18
- if (isQueryErrorResponse(response)) {
19
- return { error: response };
20
- }
21
- return { data: parseQueryAPIExecuteResponse(response) };
22
- }
23
- catch (error) {
24
- return { error: error || new Error('Unauthorized') };
25
- }
26
- },
27
- providesTags: ['All'],
28
- }),
29
- }),
30
- overrideExisting: 'throw',
31
- });