ydb-embedded-ui 3.3.2 → 3.3.3
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.
- package/CHANGELOG.md +18 -0
- package/dist/components/Errors/ResponseError/ResponseError.tsx +17 -0
- package/dist/components/Errors/ResponseError/index.ts +1 -0
- package/dist/components/Errors/i18n/en.json +2 -1
- package/dist/components/Errors/i18n/ru.json +2 -1
- package/dist/components/FullGroupViewer/FullGroupViewer.js +1 -1
- package/dist/components/InfoViewer/InfoViewer.scss +1 -1
- package/dist/components/InfoViewer/InfoViewer.tsx +29 -21
- package/dist/components/InfoViewer/formatters/index.ts +1 -0
- package/dist/components/InfoViewer/formatters/table.ts +40 -0
- package/dist/components/QueryExecutionStatus/QueryExecutionStatus.tsx +26 -8
- package/dist/components/QueryExecutionStatus/index.ts +1 -0
- package/dist/components/QueryResultTable/QueryResultTable.tsx +2 -2
- package/dist/containers/App/Content.js +12 -5
- package/dist/containers/AsideNavigation/AsideNavigation.tsx +10 -13
- package/dist/containers/Authentication/Authentication.scss +6 -0
- package/dist/containers/Authentication/Authentication.tsx +34 -15
- package/dist/containers/Node/NodeStructure/Pdisk.tsx +7 -10
- package/dist/containers/Nodes/Nodes.tsx +1 -1
- package/dist/containers/Nodes/getNodesColumns.tsx +4 -4
- package/dist/containers/Storage/PDisk/PDisk.tsx +25 -17
- package/dist/containers/Storage/PDisk/__tests__/colors.tsx +64 -1
- package/dist/containers/Storage/Storage.js +1 -1
- package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +4 -3
- package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +1 -1
- package/dist/containers/Storage/utils/index.ts +26 -10
- package/dist/containers/Tablet/Tablet.js +1 -1
- package/dist/containers/Tenant/Acl/Acl.js +1 -1
- package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.tsx +2 -2
- package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.js +1 -1
- package/dist/containers/Tenant/Diagnostics/OverloadedShards/OverloadedShards.tsx +6 -1
- package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +10 -21
- package/dist/containers/Tenant/{Schema/SchemaInfoViewer/SchemaInfoViewer.scss → Diagnostics/Overview/TableInfo/TableInfo.scss} +8 -10
- package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/TableInfo.tsx +71 -0
- package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/i18n/en.json +5 -0
- package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/i18n/index.ts +11 -0
- package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/i18n/ru.json +5 -0
- package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/prepareTableInfo.ts +96 -0
- package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +7 -1
- package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +3 -1
- package/dist/containers/Tenant/QueryEditor/QueryExplain/QueryExplain.js +16 -11
- package/dist/containers/Tenant/QueryEditor/QueryResult/QueryResult.js +37 -23
- package/dist/containers/Tenant/QueryEditor/QueryResult/QueryResult.scss +4 -0
- package/dist/containers/Tenant/Schema/SchemaViewer/SchemaViewer.js +1 -1
- package/dist/containers/Tenants/Tenants.js +4 -3
- package/dist/routes.ts +1 -0
- package/dist/services/api.js +4 -1
- package/dist/store/reducers/shardsWorkload.ts +2 -1
- package/dist/store/reducers/storage.js +1 -1
- package/dist/utils/constants.ts +1 -1
- package/dist/utils/index.js +3 -1
- package/dist/utils/prepareQueryExplain.ts +1 -1
- package/package.json +5 -3
- package/dist/containers/Tenant/Diagnostics/Overview/Overview.scss +0 -13
- package/dist/containers/Tenant/Schema/SchemaInfoViewer/SchemaInfoViewer.js +0 -201
@@ -7,7 +7,7 @@ import {TPDiskState} from '../../../../types/api/pdisk';
|
|
7
7
|
import {PDisk} from '../PDisk';
|
8
8
|
|
9
9
|
describe('PDisk state', () => {
|
10
|
-
it('Should determine severity based on State', () => {
|
10
|
+
it('Should determine severity based on State if space severity is OK', () => {
|
11
11
|
const {getAllByRole} = renderWithStore(
|
12
12
|
<MemoryRouter>
|
13
13
|
<PDisk nodeId={1} data={{State: TPDiskState.Normal}} />
|
@@ -20,6 +20,55 @@ describe('PDisk state', () => {
|
|
20
20
|
expect(normalDisk.className).not.toBe(erroredDisk.className);
|
21
21
|
});
|
22
22
|
|
23
|
+
it('Should determine severity based on space utilization if state severity is OK', () => {
|
24
|
+
const {getAllByRole} = renderWithStore(
|
25
|
+
<MemoryRouter>
|
26
|
+
<PDisk
|
27
|
+
nodeId={1}
|
28
|
+
data={{State: TPDiskState.Normal, AvailableSize: '100', TotalSize: '100'}}
|
29
|
+
/>
|
30
|
+
<PDisk
|
31
|
+
nodeId={2}
|
32
|
+
data={{State: TPDiskState.Normal, AvailableSize: '14', TotalSize: '100'}}
|
33
|
+
/>
|
34
|
+
<PDisk
|
35
|
+
nodeId={3}
|
36
|
+
data={{State: TPDiskState.Normal, AvailableSize: '4', TotalSize: '100'}}
|
37
|
+
/>
|
38
|
+
</MemoryRouter>,
|
39
|
+
);
|
40
|
+
|
41
|
+
const [disk1, disk2, disk3] = getAllByRole('meter');
|
42
|
+
|
43
|
+
expect(disk1.className).toMatch(/_green\b/i);
|
44
|
+
expect(disk2.className).toMatch(/_yellow\b/i);
|
45
|
+
expect(disk3.className).toMatch(/_red\b/i);
|
46
|
+
});
|
47
|
+
|
48
|
+
it('Should determine severity based on max severity of state and space utilization ', () => {
|
49
|
+
const {getAllByRole} = renderWithStore(
|
50
|
+
<MemoryRouter>
|
51
|
+
<PDisk
|
52
|
+
nodeId={1}
|
53
|
+
data={{
|
54
|
+
State: TPDiskState.ChunkQuotaError,
|
55
|
+
AvailableSize: '100',
|
56
|
+
TotalSize: '100',
|
57
|
+
}}
|
58
|
+
/>
|
59
|
+
<PDisk
|
60
|
+
nodeId={2}
|
61
|
+
data={{State: TPDiskState.Normal, AvailableSize: '4', TotalSize: '100'}}
|
62
|
+
/>
|
63
|
+
</MemoryRouter>,
|
64
|
+
);
|
65
|
+
|
66
|
+
const [disk1, disk2] = getAllByRole('meter');
|
67
|
+
|
68
|
+
expect(disk1.className).toMatch(/_red\b/i);
|
69
|
+
expect(disk2.className).toMatch(/_red\b/i);
|
70
|
+
});
|
71
|
+
|
23
72
|
it('Should display as unavailabe when no State is provided', () => {
|
24
73
|
const {getAllByRole} = renderWithStore(
|
25
74
|
<MemoryRouter>
|
@@ -34,4 +83,18 @@ describe('PDisk state', () => {
|
|
34
83
|
expect(disk1.className).toMatch(/_grey\b/i);
|
35
84
|
expect(disk2.className).not.toMatch(/_grey\b/i);
|
36
85
|
});
|
86
|
+
|
87
|
+
it('Should display as unavailabe when no State is provided event if space severity is not OK', () => {
|
88
|
+
const {getAllByRole} = renderWithStore(
|
89
|
+
<MemoryRouter>
|
90
|
+
<PDisk nodeId={1} data={{AvailableSize: '14', TotalSize: '100'}} />
|
91
|
+
<PDisk nodeId={2} data={{AvailableSize: '4', TotalSize: '100'}} />
|
92
|
+
</MemoryRouter>,
|
93
|
+
);
|
94
|
+
|
95
|
+
const [disk1, disk2] = getAllByRole('meter');
|
96
|
+
|
97
|
+
expect(disk1.className).toMatch(/_grey\b/i);
|
98
|
+
expect(disk2.className).toMatch(/_grey\b/i);
|
99
|
+
});
|
37
100
|
});
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
3
3
|
import {connect} from 'react-redux';
|
4
4
|
import cn from 'bem-cn-lite';
|
5
|
-
import DataTable from '@
|
5
|
+
import DataTable from '@gravity-ui/react-data-table';
|
6
6
|
import {RadioButton} from '@gravity-ui/uikit';
|
7
7
|
|
8
8
|
import {Search} from '../../components/Search';
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import _ from 'lodash';
|
2
2
|
import cn from 'bem-cn-lite';
|
3
|
-
import DataTable, {Column, Settings, SortOrder} from '@
|
3
|
+
import DataTable, {Column, Settings, SortOrder} from '@gravity-ui/react-data-table';
|
4
4
|
import {Icon, Label, Popover, PopoverBehavior} from '@gravity-ui/uikit';
|
5
5
|
|
6
6
|
import shieldIcon from '../../../assets/icons/shield.svg';
|
@@ -20,7 +20,7 @@ import {getUsage, isFullDonorData} from '../../../utils/storage';
|
|
20
20
|
|
21
21
|
import {EmptyFilter} from '../EmptyFilter/EmptyFilter';
|
22
22
|
import {VDisk} from '../VDisk';
|
23
|
-
import {getDegradedSeverity,
|
23
|
+
import {getDegradedSeverity, getUsageSeverityForStorageGroup} from '../utils';
|
24
24
|
|
25
25
|
import i18n from './i18n';
|
26
26
|
import './StorageGroups.scss';
|
@@ -127,6 +127,7 @@ function StorageGroups({
|
|
127
127
|
{
|
128
128
|
name: TableColumnsIds.Type,
|
129
129
|
header: tableColumnsNames[TableColumnsIds.Type],
|
130
|
+
// prettier-ignore
|
130
131
|
render: ({value, row}) => (
|
131
132
|
<>
|
132
133
|
<Label>{(value as string) || '—'}</Label>
|
@@ -164,7 +165,7 @@ function StorageGroups({
|
|
164
165
|
// but the absence of a value is more clear
|
165
166
|
return row.Limit ? (
|
166
167
|
<Label
|
167
|
-
theme={
|
168
|
+
theme={getUsageSeverityForStorageGroup(usage)}
|
168
169
|
className={b('usage-label', {overload: usage >= 90})}
|
169
170
|
>
|
170
171
|
{usage}%
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import _ from 'lodash';
|
2
2
|
import cn from 'bem-cn-lite';
|
3
3
|
|
4
|
-
import DataTable, {Column, Settings, SortOrder} from '@
|
4
|
+
import DataTable, {Column, Settings, SortOrder} from '@gravity-ui/react-data-table';
|
5
5
|
import {Popover, PopoverBehavior} from '@gravity-ui/uikit';
|
6
6
|
|
7
7
|
import {VisibleEntities} from '../../../store/reducers/storage';
|
@@ -1,12 +1,14 @@
|
|
1
1
|
import type {IStoragePoolGroup} from '../../../types/store/storage';
|
2
|
+
import {EFlag} from '../../../types/api/enums';
|
2
3
|
|
3
4
|
export * from './constants';
|
4
5
|
|
5
|
-
const generateEvaluator =
|
6
|
-
OkLevel extends string,
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
const generateEvaluator =
|
7
|
+
<OkLevel extends string, WarnLevel extends string, CritLevel extends string>(
|
8
|
+
warn: number,
|
9
|
+
crit: number,
|
10
|
+
levels: [OkLevel, WarnLevel, CritLevel],
|
11
|
+
) =>
|
10
12
|
(value: number) => {
|
11
13
|
if (0 <= value && value < warn) {
|
12
14
|
return levels[0];
|
@@ -34,12 +36,26 @@ const canEvaluateErasureSpecies = (value?: string): value is keyof typeof degrad
|
|
34
36
|
value !== undefined && value in degradationEvaluators;
|
35
37
|
|
36
38
|
export const getDegradedSeverity = (group: IStoragePoolGroup) => {
|
37
|
-
const evaluate = canEvaluateErasureSpecies(group.ErasureSpecies)
|
38
|
-
degradationEvaluators[group.ErasureSpecies]
|
39
|
-
defaultDegradationEvaluator;
|
39
|
+
const evaluate = canEvaluateErasureSpecies(group.ErasureSpecies)
|
40
|
+
? degradationEvaluators[group.ErasureSpecies]
|
41
|
+
: defaultDegradationEvaluator;
|
40
42
|
|
41
43
|
return evaluate(group.Missing);
|
42
44
|
};
|
43
45
|
|
44
|
-
export const
|
45
|
-
|
46
|
+
export const getUsageSeverityForStorageGroup = generateEvaluator(80, 85, [
|
47
|
+
'success',
|
48
|
+
'warning',
|
49
|
+
'danger',
|
50
|
+
]);
|
51
|
+
export const getUsageSeverityForEntityStatus = generateEvaluator(80, 85, [
|
52
|
+
'Green',
|
53
|
+
'Yellow',
|
54
|
+
'Red',
|
55
|
+
]);
|
56
|
+
|
57
|
+
export const getUsageSeverityForPDisk = generateEvaluator(85, 95, [
|
58
|
+
EFlag.Green,
|
59
|
+
EFlag.Yellow,
|
60
|
+
EFlag.Red,
|
61
|
+
]);
|
@@ -16,7 +16,7 @@ import {Tag} from '../../components/Tag/Tag';
|
|
16
16
|
import Icon from '../../components/Icon/Icon';
|
17
17
|
import EmptyState from '../../components/EmptyState/EmptyState';
|
18
18
|
import {Link as ExternalLink, Button, Loader} from '@gravity-ui/uikit';
|
19
|
-
import DataTable from '@
|
19
|
+
import DataTable from '@gravity-ui/react-data-table';
|
20
20
|
import CriticalActionDialog from '../../components/CriticalActionDialog/CriticalActionDialog';
|
21
21
|
import routes, {createHref} from '../../routes';
|
22
22
|
import {getDefaultNodePath} from '../Node/NodePages';
|
@@ -4,7 +4,7 @@ import cn from 'bem-cn-lite';
|
|
4
4
|
import _ from 'lodash';
|
5
5
|
import {connect} from 'react-redux';
|
6
6
|
import {Loader} from '@gravity-ui/uikit';
|
7
|
-
import DataTable from '@
|
7
|
+
import DataTable from '@gravity-ui/react-data-table';
|
8
8
|
import {DEFAULT_TABLE_SETTINGS} from '../../../utils/constants';
|
9
9
|
|
10
10
|
import './Acl.scss';
|
@@ -1,9 +1,9 @@
|
|
1
1
|
import {useCallback, useEffect, useState} from 'react';
|
2
2
|
import {useDispatch} from 'react-redux';
|
3
3
|
import block from 'bem-cn-lite';
|
4
|
-
import {
|
4
|
+
import {escapeRegExp} from 'lodash/fp';
|
5
5
|
|
6
|
-
import DataTable, {Column} from '@
|
6
|
+
import DataTable, {Column} from '@gravity-ui/react-data-table';
|
7
7
|
|
8
8
|
import type {EPathType} from '../../../../types/api/schema';
|
9
9
|
import {Loader} from '../../../../components/Loader';
|
@@ -2,7 +2,7 @@ import {useEffect, useMemo} from 'react';
|
|
2
2
|
import cn from 'bem-cn-lite';
|
3
3
|
import {connect} from 'react-redux';
|
4
4
|
import {Loader} from '@gravity-ui/uikit';
|
5
|
-
import DataTable from '@
|
5
|
+
import DataTable from '@gravity-ui/react-data-table';
|
6
6
|
|
7
7
|
import Icon from '../../../../components/Icon/Icon';
|
8
8
|
|
@@ -2,7 +2,7 @@ import {useState, useContext, useEffect, useMemo} from 'react';
|
|
2
2
|
import {useDispatch} from 'react-redux';
|
3
3
|
import cn from 'bem-cn-lite';
|
4
4
|
|
5
|
-
import DataTable, {Column, Settings, SortOrder} from '@
|
5
|
+
import DataTable, {Column, Settings, SortOrder} from '@gravity-ui/react-data-table';
|
6
6
|
import {Loader} from '@gravity-ui/uikit';
|
7
7
|
|
8
8
|
import {DateRange, DateRangeValues} from '../../../../components/DateRange';
|
@@ -53,6 +53,7 @@ const tableColumnsNames = {
|
|
53
53
|
NodeId: 'NodeId',
|
54
54
|
PeakTime: 'PeakTime',
|
55
55
|
InFlightTxCount: 'InFlightTxCount',
|
56
|
+
IntervalEnd: 'IntervalEnd',
|
56
57
|
};
|
57
58
|
|
58
59
|
function prepareCPUWorkloadValue(value: string) {
|
@@ -227,6 +228,10 @@ export const OverloadedShards = ({tenantPath, type}: OverloadedShardsProps) => {
|
|
227
228
|
align: DataTable.RIGHT,
|
228
229
|
sortable: false,
|
229
230
|
},
|
231
|
+
{
|
232
|
+
name: tableColumnsNames.IntervalEnd,
|
233
|
+
render: ({value}) => formatDateTime(new Date(value as string).getTime()),
|
234
|
+
}
|
230
235
|
];
|
231
236
|
}, [dispatch, history, tenantPath]);
|
232
237
|
|
@@ -1,15 +1,15 @@
|
|
1
1
|
import {ReactNode, useCallback, useMemo} from 'react';
|
2
2
|
import {shallowEqual, useDispatch, useSelector} from 'react-redux';
|
3
|
-
import cn from 'bem-cn-lite';
|
4
3
|
|
5
|
-
import {Loader} from '
|
4
|
+
import {Loader} from '../../../../components/Loader';
|
6
5
|
|
7
6
|
//@ts-ignore
|
8
|
-
import SchemaInfoViewer from '../../Schema/SchemaInfoViewer/SchemaInfoViewer';
|
9
7
|
import {TableIndexInfo} from '../../../../components/InfoViewer/schemaInfo';
|
8
|
+
import {ResponseError} from '../../../../components/Errors/ResponseError';
|
10
9
|
|
11
10
|
import {TopicInfo} from './TopicInfo';
|
12
11
|
import {ChangefeedInfo} from './ChangefeedInfo';
|
12
|
+
import {TableInfo} from './TableInfo';
|
13
13
|
|
14
14
|
import {EPathType, TEvDescribeSchemeResult} from '../../../../types/api/schema';
|
15
15
|
import {
|
@@ -33,8 +33,6 @@ import {
|
|
33
33
|
} from '../../../../store/reducers/olapStats';
|
34
34
|
import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
|
35
35
|
|
36
|
-
import './Overview.scss';
|
37
|
-
|
38
36
|
function prepareOlapTableGeneral(item?: TEvDescribeSchemeResult, olapStats?: any[]) {
|
39
37
|
const tableData = item?.PathDescription?.ColumnTableDescription;
|
40
38
|
|
@@ -70,8 +68,6 @@ interface OverviewProps {
|
|
70
68
|
tenantName?: string;
|
71
69
|
}
|
72
70
|
|
73
|
-
const b = cn('kv-tenant-overview');
|
74
|
-
|
75
71
|
function Overview({type, tenantName, className}: OverviewProps) {
|
76
72
|
const dispatch = useDispatch();
|
77
73
|
|
@@ -81,6 +77,7 @@ function Overview({type, tenantName, className}: OverviewProps) {
|
|
81
77
|
wasLoaded,
|
82
78
|
autorefresh,
|
83
79
|
currentSchemaPath,
|
80
|
+
error,
|
84
81
|
} = useSelector((state: any) => state.schema);
|
85
82
|
|
86
83
|
const {data: {result: olapStats} = {result: undefined}, loading: olapStatsLoading} =
|
@@ -144,14 +141,6 @@ function Overview({type, tenantName, className}: OverviewProps) {
|
|
144
141
|
: currentItem;
|
145
142
|
}, [type, olapStats, currentItem]);
|
146
143
|
|
147
|
-
const renderLoader = () => {
|
148
|
-
return (
|
149
|
-
<div className={b('loader')}>
|
150
|
-
<Loader size="m" />
|
151
|
-
</div>
|
152
|
-
);
|
153
|
-
};
|
154
|
-
|
155
144
|
const renderContent = () => {
|
156
145
|
// verbose mapping to guarantee a correct render for new path types
|
157
146
|
// TS will error when a new type is added but not mapped here
|
@@ -170,15 +159,15 @@ function Overview({type, tenantName, className}: OverviewProps) {
|
|
170
159
|
[EPathType.EPathTypePersQueueGroup]: () => <TopicInfo data={schemaData} />,
|
171
160
|
};
|
172
161
|
|
173
|
-
return (
|
174
|
-
(type && pathTypeToComponent[type]?.()) || (
|
175
|
-
<SchemaInfoViewer fullPath={currentItem.Path} data={schemaData} />
|
176
|
-
)
|
177
|
-
);
|
162
|
+
return (type && pathTypeToComponent[type]?.()) || <TableInfo data={schemaData} />;
|
178
163
|
};
|
179
164
|
|
180
165
|
if ((loading && !wasLoaded) || (isEntityWithMergedImpl && !mergedChildrenPaths)) {
|
181
|
-
return
|
166
|
+
return <Loader size="m" />;
|
167
|
+
}
|
168
|
+
|
169
|
+
if (error) {
|
170
|
+
return <ResponseError error={error} />;
|
182
171
|
}
|
183
172
|
|
184
173
|
return <div className={className}>{renderContent()}</div>;
|
@@ -1,6 +1,12 @@
|
|
1
|
-
.
|
1
|
+
@import '../../../../../styles/mixins.scss';
|
2
|
+
|
3
|
+
.ydb-diagnostics-table-info {
|
2
4
|
overflow: auto;
|
3
5
|
|
6
|
+
&__title {
|
7
|
+
@include info-viewer-title();
|
8
|
+
}
|
9
|
+
|
4
10
|
&__row {
|
5
11
|
display: flex;
|
6
12
|
flex-wrap: wrap;
|
@@ -19,19 +25,11 @@
|
|
19
25
|
}
|
20
26
|
}
|
21
27
|
|
22
|
-
&
|
28
|
+
&__info-block {
|
23
29
|
margin-bottom: 20px;
|
24
30
|
|
25
31
|
.info-viewer__items {
|
26
32
|
grid-template-columns: minmax(max-content, 280px);
|
27
33
|
}
|
28
34
|
}
|
29
|
-
|
30
|
-
&__title {
|
31
|
-
margin: 15px 0 10px;
|
32
|
-
|
33
|
-
font-size: var(--yc-text-body-2-font-size);
|
34
|
-
font-weight: 600;
|
35
|
-
line-height: var(--yc-text-body-2-line-height);
|
36
|
-
}
|
37
35
|
}
|
@@ -0,0 +1,71 @@
|
|
1
|
+
import {useMemo} from 'react';
|
2
|
+
import cn from 'bem-cn-lite';
|
3
|
+
|
4
|
+
import type {TEvDescribeSchemeResult} from '../../../../../types/api/schema';
|
5
|
+
|
6
|
+
import {InfoViewer} from '../../../../../components/InfoViewer';
|
7
|
+
|
8
|
+
import {getEntityName} from '../../../utils';
|
9
|
+
|
10
|
+
import {prepareTableInfo} from './prepareTableInfo';
|
11
|
+
|
12
|
+
import i18n from './i18n';
|
13
|
+
|
14
|
+
import './TableInfo.scss';
|
15
|
+
|
16
|
+
const b = cn('ydb-diagnostics-table-info');
|
17
|
+
|
18
|
+
interface TableInfoProps {
|
19
|
+
data?: TEvDescribeSchemeResult;
|
20
|
+
}
|
21
|
+
|
22
|
+
export const TableInfo = ({data}: TableInfoProps) => {
|
23
|
+
const entityName = getEntityName(data?.PathDescription);
|
24
|
+
|
25
|
+
const {
|
26
|
+
generalTableInfo = [],
|
27
|
+
tableStatsInfo = [],
|
28
|
+
tabletMetricsInfo = [],
|
29
|
+
partitionConfigInfo = [],
|
30
|
+
} = useMemo(() => prepareTableInfo(data), [data]);
|
31
|
+
|
32
|
+
return (
|
33
|
+
<div className={b()}>
|
34
|
+
<InfoViewer
|
35
|
+
info={generalTableInfo}
|
36
|
+
title={entityName}
|
37
|
+
className={b('info-block')}
|
38
|
+
renderEmptyState={() => <div className={b('title')}>{entityName}</div>}
|
39
|
+
/>
|
40
|
+
<div className={b('row')}>
|
41
|
+
{tabletMetricsInfo.length > 0 || partitionConfigInfo.length > 0 ? (
|
42
|
+
<div className={b('col')}>
|
43
|
+
<InfoViewer
|
44
|
+
info={tabletMetricsInfo}
|
45
|
+
title={i18n('tabletMetrics')}
|
46
|
+
className={b('info-block')}
|
47
|
+
renderEmptyState={() => null}
|
48
|
+
/>
|
49
|
+
<InfoViewer
|
50
|
+
info={partitionConfigInfo}
|
51
|
+
title={i18n('partitionConfig')}
|
52
|
+
className={b('info-block')}
|
53
|
+
renderEmptyState={() => null}
|
54
|
+
/>
|
55
|
+
</div>
|
56
|
+
) : null}
|
57
|
+
<div className={b('col')}>
|
58
|
+
{tableStatsInfo.map((info, index) => (
|
59
|
+
<InfoViewer
|
60
|
+
key={index}
|
61
|
+
info={info}
|
62
|
+
title={index === 0 ? i18n('tableStats') : undefined}
|
63
|
+
className={b('info-block')}
|
64
|
+
renderEmptyState={() => null}
|
65
|
+
/>
|
66
|
+
))}
|
67
|
+
</div>
|
68
|
+
</div>
|
69
|
+
</div>
|
70
|
+
);
|
71
|
+
};
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import {i18n, Lang} from '../../../../../../utils/i18n';
|
2
|
+
|
3
|
+
import en from './en.json';
|
4
|
+
import ru from './ru.json';
|
5
|
+
|
6
|
+
const COMPONENT = 'ydb-diagnostics-overview-table-info';
|
7
|
+
|
8
|
+
i18n.registerKeyset(Lang.En, COMPONENT, en);
|
9
|
+
i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
|
10
|
+
|
11
|
+
export default i18n.keyset(COMPONENT);
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from './TableInfo';
|
@@ -0,0 +1,96 @@
|
|
1
|
+
import type {TEvDescribeSchemeResult} from '../../../../../types/api/schema';
|
2
|
+
|
3
|
+
import {formatObject} from '../../../../../components/InfoViewer';
|
4
|
+
import {
|
5
|
+
formatFollowerGroupItem,
|
6
|
+
formatPartitionConfigItem,
|
7
|
+
formatTableStatsItem,
|
8
|
+
formatTabletMetricsItem,
|
9
|
+
} from '../../../../../components/InfoViewer/formatters';
|
10
|
+
|
11
|
+
export const prepareTableInfo = (data?: TEvDescribeSchemeResult) => {
|
12
|
+
if (!data) {
|
13
|
+
return {};
|
14
|
+
}
|
15
|
+
|
16
|
+
const {PathDescription = {}} = data;
|
17
|
+
|
18
|
+
const {
|
19
|
+
TableStats = {},
|
20
|
+
TabletMetrics = {},
|
21
|
+
Table: {PartitionConfig = {}} = {},
|
22
|
+
} = PathDescription;
|
23
|
+
|
24
|
+
const {
|
25
|
+
PartCount,
|
26
|
+
RowCount,
|
27
|
+
DataSize,
|
28
|
+
IndexSize,
|
29
|
+
|
30
|
+
LastAccessTime,
|
31
|
+
LastUpdateTime,
|
32
|
+
|
33
|
+
ImmediateTxCompleted,
|
34
|
+
PlannedTxCompleted,
|
35
|
+
TxRejectedByOverload,
|
36
|
+
TxRejectedBySpace,
|
37
|
+
TxCompleteLagMsec,
|
38
|
+
InFlightTxCount,
|
39
|
+
|
40
|
+
RowUpdates,
|
41
|
+
RowDeletes,
|
42
|
+
RowReads,
|
43
|
+
RangeReads,
|
44
|
+
RangeReadRows,
|
45
|
+
|
46
|
+
...restTableStats
|
47
|
+
} = TableStats;
|
48
|
+
|
49
|
+
const {FollowerGroups, FollowerCount, CrossDataCenterFollowerCount} = PartitionConfig;
|
50
|
+
|
51
|
+
const generalTableInfo = formatObject(formatTableStatsItem, {
|
52
|
+
PartCount,
|
53
|
+
RowCount,
|
54
|
+
DataSize,
|
55
|
+
IndexSize,
|
56
|
+
...restTableStats,
|
57
|
+
});
|
58
|
+
|
59
|
+
const tableStatsInfo = [
|
60
|
+
formatObject(formatTableStatsItem, {
|
61
|
+
LastAccessTime,
|
62
|
+
LastUpdateTime,
|
63
|
+
}),
|
64
|
+
formatObject(formatTableStatsItem, {
|
65
|
+
ImmediateTxCompleted,
|
66
|
+
PlannedTxCompleted,
|
67
|
+
TxRejectedByOverload,
|
68
|
+
TxRejectedBySpace,
|
69
|
+
TxCompleteLagMsec,
|
70
|
+
InFlightTxCount,
|
71
|
+
}),
|
72
|
+
formatObject(formatTableStatsItem, {
|
73
|
+
RowUpdates,
|
74
|
+
RowDeletes,
|
75
|
+
RowReads,
|
76
|
+
RangeReads,
|
77
|
+
RangeReadRows,
|
78
|
+
}),
|
79
|
+
];
|
80
|
+
|
81
|
+
const tabletMetricsInfo = formatObject(formatTabletMetricsItem, TabletMetrics);
|
82
|
+
|
83
|
+
let partitionConfigInfo = [];
|
84
|
+
|
85
|
+
if (Array.isArray(FollowerGroups) && FollowerGroups.length > 0) {
|
86
|
+
partitionConfigInfo = formatObject(formatFollowerGroupItem, FollowerGroups[0]);
|
87
|
+
} else if (FollowerCount !== undefined) {
|
88
|
+
partitionConfigInfo.push(formatPartitionConfigItem('FollowerCount', FollowerCount));
|
89
|
+
} else if (CrossDataCenterFollowerCount !== undefined) {
|
90
|
+
partitionConfigInfo.push(
|
91
|
+
formatPartitionConfigItem('CrossDataCenterFollowerCount', CrossDataCenterFollowerCount),
|
92
|
+
);
|
93
|
+
}
|
94
|
+
|
95
|
+
return {generalTableInfo, tableStatsInfo, tabletMetricsInfo, partitionConfigInfo};
|
96
|
+
};
|
@@ -2,7 +2,7 @@ import {useCallback, useEffect, useRef, useState} from 'react';
|
|
2
2
|
import {useDispatch} from 'react-redux';
|
3
3
|
import cn from 'bem-cn-lite';
|
4
4
|
|
5
|
-
import DataTable, {Column, Settings} from '@
|
5
|
+
import DataTable, {Column, Settings} from '@gravity-ui/react-data-table';
|
6
6
|
import {Loader} from '@gravity-ui/uikit';
|
7
7
|
|
8
8
|
import {DateRange, DateRangeValues} from '../../../../components/DateRange';
|
@@ -21,6 +21,7 @@ import type {EPathType} from '../../../../types/api/schema';
|
|
21
21
|
import type {ITopQueriesFilters} from '../../../../types/store/executeTopQueries';
|
22
22
|
import type {IQueryResult} from '../../../../types/store/query';
|
23
23
|
|
24
|
+
import {formatDateTime} from '../../../../utils';
|
24
25
|
import {DEFAULT_TABLE_SETTINGS, HOUR_IN_SECONDS} from '../../../../utils/constants';
|
25
26
|
import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
|
26
27
|
import {prepareQueryError} from '../../../../utils/query';
|
@@ -51,6 +52,11 @@ const COLUMNS: Column<KeyValueRow>[] = [
|
|
51
52
|
sortable: false,
|
52
53
|
render: ({value}) => <TruncatedQuery value={value} maxQueryHeight={MAX_QUERY_HEIGHT} />,
|
53
54
|
},
|
55
|
+
{
|
56
|
+
name: 'IntervalEnd',
|
57
|
+
width: 140,
|
58
|
+
render: ({value}) => formatDateTime(new Date(value as string).getTime()),
|
59
|
+
},
|
54
60
|
];
|
55
61
|
|
56
62
|
interface TopQueriesProps {
|
@@ -26,6 +26,8 @@ import {
|
|
26
26
|
TColumnTableDescription,
|
27
27
|
TDirEntry,
|
28
28
|
} from '../../../types/api/schema';
|
29
|
+
|
30
|
+
import {formatDateTime} from '../../../utils';
|
29
31
|
import {isColumnEntityType, isIndexTable, isTableType} from '../utils/schema';
|
30
32
|
|
31
33
|
import {
|
@@ -201,7 +203,7 @@ function ObjectSummary(props: ObjectSummaryProps) {
|
|
201
203
|
const startTimeInMilliseconds = Number(currentSchemaData?.CreateStep);
|
202
204
|
let createTime = '';
|
203
205
|
if (startTimeInMilliseconds) {
|
204
|
-
createTime =
|
206
|
+
createTime = formatDateTime(startTimeInMilliseconds);
|
205
207
|
}
|
206
208
|
|
207
209
|
component = <InfoViewer info={[{label: 'Create time', value: createTime}]} />;
|