ydb-embedded-ui 6.10.3 → 6.11.0
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/components/DeveloperUiLink/DeveloperUiLink.d.ts +8 -0
- package/dist/components/DeveloperUiLink/DeveloperUiLink.js +9 -0
- package/dist/components/DeveloperUiLink/DeveloperUiLink.scss +11 -0
- package/dist/components/NodeHostWrapper/NodeHostWrapper.js +9 -2
- package/dist/containers/Tablets/Tablets.js +5 -1
- package/dist/containers/Tenant/Diagnostics/Overview/Overview.js +1 -13
- package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/TableInfo.d.ts +1 -3
- package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/TableInfo.js +2 -2
- package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/prepareTableInfo.d.ts +2 -3
- package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/prepareTableInfo.js +28 -59
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +28 -3
- package/dist/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.js +5 -14
- package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.js +4 -14
- package/dist/containers/Tenant/Diagnostics/TopShards/getTopShardsColumns.js +5 -1
- package/dist/store/reducers/executeTopQueries/executeTopQueries.js +1 -0
- package/dist/types/api/schema/schema.d.ts +21 -0
- package/dist/utils/diagnostics.d.ts +21 -17
- package/dist/utils/diagnostics.js +28 -7
- package/dist/utils/monaco/yql/yql.completionItemProvider.js +1 -1
- package/package.json +1 -1
- package/dist/store/reducers/olapStats.d.ts +0 -5
- 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
|
+
}
|
@@ -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
|
-
|
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 =
|
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(
|
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
|
{
|
@@ -18,17 +18,6 @@ import { TableInfo } from './TableInfo';
|
|
18
18
|
import { TopicInfo } from './TopicInfo';
|
19
19
|
function Overview({ type, path }) {
|
20
20
|
const [autoRefreshInterval] = useAutoRefreshInterval();
|
21
|
-
// FIXME: The request is too heavy, stats table may have millions of items
|
22
|
-
// Disabled until fixed
|
23
|
-
// https://github.com/ydb-platform/ydb-embedded-ui/issues/907
|
24
|
-
// https://github.com/ydb-platform/ydb-embedded-ui/issues/908
|
25
|
-
// const olapParams = isTableType(type) && isColumnEntityType(type) ? {path} : skipToken;
|
26
|
-
// const {currentData: olapData, isFetching: olapIsFetching} = olapApi.useGetOlapStatsQuery(
|
27
|
-
// olapParams,
|
28
|
-
// {pollingInterval: autoRefreshInterval},
|
29
|
-
// );
|
30
|
-
// const olapStatsLoading = olapIsFetching && olapData === undefined;
|
31
|
-
// const {result: olapStats} = olapData || {result: undefined};
|
32
21
|
const isEntityWithMergedImpl = isEntityWithMergedImplementation(type);
|
33
22
|
// shallowEqual prevents rerenders when new schema data is loaded
|
34
23
|
const mergedChildrenPaths = useTypedSelector((state) => selectSchemaMergedChildrenPaths(state, path, type), shallowEqual);
|
@@ -45,7 +34,6 @@ function Overview({ type, path }) {
|
|
45
34
|
const overviewLoading = isFetching && currentData === undefined;
|
46
35
|
const { data: rawData, additionalData } = currentData || {};
|
47
36
|
const { error: schemaError } = useGetSchemaQuery({ path });
|
48
|
-
// overviewLoading || olapStatsLoading
|
49
37
|
const entityLoading = overviewLoading;
|
50
38
|
const entityNotReady = isEntityWithMergedImpl && !mergedChildrenPaths;
|
51
39
|
const renderContent = () => {
|
@@ -72,7 +60,7 @@ function Overview({ type, path }) {
|
|
72
60
|
[EPathType.EPathTypeView]: () => _jsx(ViewInfo, { data: data }),
|
73
61
|
[EPathType.EPathTypeReplication]: () => _jsx(AsyncReplicationInfo, { data: data }),
|
74
62
|
};
|
75
|
-
return (
|
63
|
+
return (type && ((_a = pathTypeToComponent[type]) === null || _a === void 0 ? void 0 : _a.call(pathTypeToComponent))) || _jsx(TableInfo, { data: data, type: type });
|
76
64
|
};
|
77
65
|
if (entityLoading || entityNotReady) {
|
78
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
|
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
|
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
|
12
|
+
const { generalInfo, tableStatsInfo, tabletMetricsInfo = [], partitionConfigInfo = [], } = React.useMemo(() => prepareTableInfo(data, type), [data, type]);
|
13
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,16 +1,15 @@
|
|
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
|
5
|
+
export declare const prepareTableInfo: (data?: TEvDescribeSchemeResult, type?: EPathType) => {
|
7
6
|
generalInfo?: undefined;
|
8
7
|
tableStatsInfo?: undefined;
|
9
8
|
tabletMetricsInfo?: undefined;
|
10
9
|
partitionConfigInfo?: undefined;
|
11
10
|
} | {
|
12
11
|
generalInfo: InfoViewerItem[];
|
13
|
-
tableStatsInfo: InfoViewerItem[][]
|
12
|
+
tableStatsInfo: InfoViewerItem[][];
|
14
13
|
tabletMetricsInfo: InfoViewerItem[];
|
15
14
|
partitionConfigInfo: InfoViewerItem[];
|
16
15
|
};
|
@@ -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
|
79
|
+
export const prepareTableInfo = (data, type) => {
|
101
80
|
if (!data) {
|
102
81
|
return {};
|
103
82
|
}
|
@@ -116,43 +95,33 @@ export const prepareTableInfo = (data, type, olapStats) => {
|
|
116
95
|
break;
|
117
96
|
}
|
118
97
|
}
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
}
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
}),
|
147
|
-
formatObject(formatTableStatsItem, {
|
148
|
-
RowUpdates,
|
149
|
-
RowDeletes,
|
150
|
-
RowReads,
|
151
|
-
RangeReads,
|
152
|
-
RangeReadRows,
|
153
|
-
}),
|
154
|
-
];
|
155
|
-
}
|
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
|
+
];
|
156
125
|
//@ts-expect-error
|
157
126
|
const tabletMetricsInfo = formatObject(formatTabletMetricsItem, TabletMetrics);
|
158
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
|
-
|
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(), (
|
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
|
82
|
-
render: ({ row }) => { var _a; return
|
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(
|
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:
|
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:
|
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(
|
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,
|
@@ -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
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
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
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
16
|
-
|
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
|
2
|
-
|
3
|
-
|
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,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
|
-
});
|