ydb-embedded-ui 6.10.2 → 6.11.0

Sign up to get free protection for your applications and to get access to all the features.
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
- });