ydb-embedded-ui 4.19.2 → 4.20.0
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +24 -0
- package/dist/components/LinkToSchemaObject/LinkToSchemaObject.tsx +20 -0
- package/dist/components/ProgressViewer/ProgressViewer.tsx +2 -1
- package/dist/components/QueryExecutionStatus/QueryExecutionStatus.tsx +3 -2
- package/dist/components/UsageLabel/UsageLabel.scss +6 -0
- package/dist/components/UsageLabel/UsageLabel.tsx +22 -0
- package/dist/containers/AsideNavigation/AsideNavigation.tsx +13 -8
- package/dist/containers/AsideNavigation/i18n/en.json +13 -0
- package/dist/containers/AsideNavigation/i18n/index.ts +11 -0
- package/dist/containers/AsideNavigation/i18n/ru.json +13 -0
- package/dist/containers/Node/NodeStructure/Pdisk.tsx +74 -68
- package/dist/containers/Node/NodeStructure/Vdisk.tsx +9 -33
- package/dist/containers/Nodes/Nodes.tsx +10 -2
- package/dist/containers/Nodes/getNodesColumns.tsx +206 -122
- package/dist/containers/Storage/Storage.tsx +9 -2
- package/dist/containers/Storage/utils/index.ts +1 -22
- package/dist/containers/Tenant/Diagnostics/Describe/Describe.tsx +2 -3
- package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.scss +0 -1
- package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.tsx +4 -2
- package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +1 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckDetails.tsx +8 -1
- package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckPreview.tsx +11 -1
- package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/IssuesViewer/IssueTree.tsx +0 -1
- package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricsCards.tsx +3 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TenantCpu.tsx +21 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByCpu.tsx +53 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByLoad.tsx +53 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopQueries.tsx +85 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopShards.tsx +53 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TenantMemory.tsx +9 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TopNodesByMemory.tsx +55 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss +40 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx +35 -19
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverviewTableLayout.tsx +53 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopTables.tsx +15 -7
- package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json +3 -3
- package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/ru.json +3 -3
- package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.scss +0 -2
- package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +13 -61
- package/dist/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx +82 -0
- package/dist/containers/Tenant/Diagnostics/TopShards/Filters/Filters.tsx +2 -2
- package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.tsx +18 -97
- package/dist/containers/Tenant/Diagnostics/TopShards/getTopShardsColumns.tsx +138 -0
- package/dist/containers/Tenant/Info/ExternalTable/ExternalTable.tsx +2 -4
- package/dist/containers/Tenant/Query/ExecuteResult/{ExecuteResult.js → ExecuteResult.tsx} +51 -31
- package/dist/containers/Tenant/Query/Issues/Issues.tsx +4 -6
- package/dist/containers/Tenant/Query/QueryDuration/QueryDuration.tsx +1 -1
- package/dist/containers/Tenant/utils/paneVisibilityToggleHelpers.tsx +1 -1
- package/dist/routes.ts +6 -0
- package/dist/store/reducers/{executeTopQueries.ts → executeTopQueries/executeTopQueries.ts} +23 -75
- package/dist/{types/store/executeTopQueries.ts → store/reducers/executeTopQueries/types.ts} +3 -7
- package/dist/store/reducers/executeTopQueries/utils.ts +36 -0
- package/dist/store/reducers/index.ts +12 -2
- package/dist/store/reducers/nodes/types.ts +1 -0
- package/dist/store/reducers/nodes/utils.ts +16 -6
- package/dist/store/reducers/{shardsWorkload.ts → shardsWorkload/shardsWorkload.ts} +5 -11
- package/dist/{types/store/shardsWorkload.ts → store/reducers/shardsWorkload/types.ts} +3 -7
- package/dist/store/reducers/storage/storage.ts +1 -1
- package/dist/store/reducers/tenantOverview/topNodesByCpu/topNodesByCpu.ts +87 -0
- package/dist/store/reducers/tenantOverview/topNodesByCpu/types.ts +29 -0
- package/dist/store/reducers/tenantOverview/topNodesByLoad/topNodesByLoad.ts +87 -0
- package/dist/store/reducers/tenantOverview/topNodesByLoad/types.ts +29 -0
- package/dist/store/reducers/tenantOverview/topNodesByMemory/topNodesByMemory.ts +87 -0
- package/dist/store/reducers/tenantOverview/topNodesByMemory/types.ts +29 -0
- package/dist/store/reducers/tenantOverview/topQueries/tenantOverviewTopQueries.ts +93 -0
- package/dist/store/reducers/tenantOverview/topQueries/types.ts +14 -0
- package/dist/store/reducers/tenantOverview/topShards/tenantOverviewTopShards.ts +103 -0
- package/dist/store/reducers/tenantOverview/topShards/types.ts +14 -0
- package/dist/store/reducers/tenantOverview/topShards/utils.ts +3 -0
- package/dist/styles/mixins.scss +4 -0
- package/dist/types/additionalProps.ts +3 -1
- package/dist/types/api/compute.ts +1 -1
- package/dist/types/react-json-inspector.d.ts +21 -0
- package/dist/utils/diagnostics.ts +11 -0
- package/dist/utils/generateEvaluator.ts +21 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,29 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [4.20.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.19.3...v4.20.0) (2023-10-19)
|
4
|
+
|
5
|
+
|
6
|
+
### Features
|
7
|
+
|
8
|
+
* add top nodes by memory table ([#562](https://github.com/ydb-platform/ydb-embedded-ui/issues/562)) ([0d4ccf2](https://github.com/ydb-platform/ydb-embedded-ui/commit/0d4ccf2a85251fadad66182ab7d6ccd54a58e6cf))
|
9
|
+
* add top tables links ([#564](https://github.com/ydb-platform/ydb-embedded-ui/issues/564)) ([e9b918f](https://github.com/ydb-platform/ydb-embedded-ui/commit/e9b918f0abace890cfafd9d7b219be5b69cac820))
|
10
|
+
* **Storage:** hide nodes table for node page ([#557](https://github.com/ydb-platform/ydb-embedded-ui/issues/557)) ([9a25a00](https://github.com/ydb-platform/ydb-embedded-ui/commit/9a25a002b28824f7e616ac8143dbde12de0b0fb7))
|
11
|
+
* **TenantOverview:** add cpu tab to tenant diagnostics ([#550](https://github.com/ydb-platform/ydb-embedded-ui/issues/550)) ([3048f84](https://github.com/ydb-platform/ydb-embedded-ui/commit/3048f8478d97249da4f7b66c26ed55f6f21e0f81))
|
12
|
+
|
13
|
+
|
14
|
+
### Bug Fixes
|
15
|
+
|
16
|
+
* add loader for healthcheck ([#563](https://github.com/ydb-platform/ydb-embedded-ui/issues/563)) ([6caea3d](https://github.com/ydb-platform/ydb-embedded-ui/commit/6caea3dec8f901090b0f8f7c1796880d7dc90a99))
|
17
|
+
* **LinkToSchemaObject:** fix schema link ([#566](https://github.com/ydb-platform/ydb-embedded-ui/issues/566)) ([6ca8a70](https://github.com/ydb-platform/ydb-embedded-ui/commit/6ca8a705b6ddacb1f845aabb7761fd22c0c3b4e0))
|
18
|
+
|
19
|
+
## [4.19.3](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.19.2...v4.19.3) (2023-10-13)
|
20
|
+
|
21
|
+
|
22
|
+
### Bug Fixes
|
23
|
+
|
24
|
+
* fix ProgressViewer background ([#556](https://github.com/ydb-platform/ydb-embedded-ui/issues/556)) ([6234462](https://github.com/ydb-platform/ydb-embedded-ui/commit/62344629713059fdfb191d3b8a57742f864dad66))
|
25
|
+
* **Storage:** display all groups by default ([#554](https://github.com/ydb-platform/ydb-embedded-ui/issues/554)) ([1da83f1](https://github.com/ydb-platform/ydb-embedded-ui/commit/1da83f19661ed8e49dd7c8a0930ce89a7c8c0185))
|
26
|
+
|
3
27
|
## [4.19.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.19.1...v4.19.2) (2023-10-12)
|
4
28
|
|
5
29
|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import type {Location} from 'history';
|
2
|
+
|
3
|
+
import {Link, type LinkProps} from '@gravity-ui/uikit';
|
4
|
+
|
5
|
+
import {createExternalUILink, parseQuery} from '../../routes';
|
6
|
+
|
7
|
+
interface LinkToSchemaObjectProps extends LinkProps {
|
8
|
+
path: string;
|
9
|
+
location: Location;
|
10
|
+
}
|
11
|
+
|
12
|
+
export function LinkToSchemaObject({path, location, ...props}: LinkToSchemaObjectProps) {
|
13
|
+
const queryParams = parseQuery(location);
|
14
|
+
const pathToSchemaObject = createExternalUILink({
|
15
|
+
...queryParams,
|
16
|
+
schema: path,
|
17
|
+
});
|
18
|
+
|
19
|
+
return <Link view="normal" href={pathToSchemaObject} {...props} />;
|
20
|
+
}
|
@@ -66,7 +66,8 @@ export function ProgressViewer({
|
|
66
66
|
warningThreshold = 60,
|
67
67
|
dangerThreshold = 80,
|
68
68
|
}: ProgressViewerProps) {
|
69
|
-
let fillWidth =
|
69
|
+
let fillWidth =
|
70
|
+
Math.round((parseFloat(String(value)) / parseFloat(String(capacity))) * 100) || 0;
|
70
71
|
fillWidth = fillWidth > 100 ? 100 : fillWidth;
|
71
72
|
let valueText: number | string | undefined = value,
|
72
73
|
capacityText: number | string | undefined = capacity,
|
@@ -14,14 +14,15 @@ const b = cn('kv-query-execution-status');
|
|
14
14
|
|
15
15
|
interface QueryExecutionStatusProps {
|
16
16
|
className?: string;
|
17
|
-
|
17
|
+
// TODO: Remove Record<string, any> when ECONNABORTED error case is fully typed
|
18
|
+
error?: AxiosError | Record<string, any> | string;
|
18
19
|
}
|
19
20
|
|
20
21
|
export const QueryExecutionStatus = ({className, error}: QueryExecutionStatusProps) => {
|
21
22
|
let icon: ReactNode;
|
22
23
|
let label: string;
|
23
24
|
|
24
|
-
if (error?.code === 'ECONNABORTED') {
|
25
|
+
if (typeof error === 'object' && error?.code === 'ECONNABORTED') {
|
25
26
|
icon = <UiKitIcon data={questionIcon} size={16} />;
|
26
27
|
label = 'Connection aborted';
|
27
28
|
} else {
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import cn from 'bem-cn-lite';
|
2
|
+
|
3
|
+
import {Label, type LabelProps} from '@gravity-ui/uikit';
|
4
|
+
|
5
|
+
const b = cn('ydb-usage-label');
|
6
|
+
|
7
|
+
interface UsageLabelProps extends LabelProps {
|
8
|
+
value: number | string;
|
9
|
+
overloadThreshold?: number;
|
10
|
+
}
|
11
|
+
|
12
|
+
export function UsageLabel({value, overloadThreshold = 90, theme, ...props}: UsageLabelProps) {
|
13
|
+
return (
|
14
|
+
<Label
|
15
|
+
theme={theme}
|
16
|
+
className={b({overload: Number(value) >= overloadThreshold})}
|
17
|
+
{...props}
|
18
|
+
>
|
19
|
+
{value || 0}%
|
20
|
+
</Label>
|
21
|
+
);
|
22
|
+
}
|
@@ -28,6 +28,7 @@ import {ASIDE_HEADER_COMPACT_KEY, TENANT_INITIAL_PAGE_KEY} from '../../utils/con
|
|
28
28
|
import {getTenantPath} from '../Tenant/TenantPages';
|
29
29
|
import {UserSettings} from '../UserSettings/UserSettings';
|
30
30
|
|
31
|
+
import i18n from './i18n';
|
31
32
|
import './AsideNavigation.scss';
|
32
33
|
|
33
34
|
const b = cn('kv-navigation');
|
@@ -58,15 +59,19 @@ function YbdInternalUser({ydbUser, logout}: YbdInternalUserProps) {
|
|
58
59
|
return (
|
59
60
|
<div className={b('internal-user')}>
|
60
61
|
<div className={b('user-info-wrapper')}>
|
61
|
-
<div className={b('ydb-internal-user-title')}>
|
62
|
+
<div className={b('ydb-internal-user-title')}>{i18n('account.user')}</div>
|
62
63
|
{ydbUser && <div className={b('username')}>{ydbUser}</div>}
|
63
64
|
</div>
|
64
65
|
{ydbUser ? (
|
65
|
-
<Button view="flat-secondary"
|
66
|
+
<Button view="flat-secondary" title={i18n('account.logout')} onClick={logout}>
|
66
67
|
<Icon data={signOutIcon} size={16} />
|
67
68
|
</Button>
|
68
69
|
) : (
|
69
|
-
<Button
|
70
|
+
<Button
|
71
|
+
view="flat-secondary"
|
72
|
+
title={i18n('account.login')}
|
73
|
+
onClick={handleLoginClick}
|
74
|
+
>
|
70
75
|
<Icon data={signInIcon} size={16} />
|
71
76
|
</Button>
|
72
77
|
)}
|
@@ -91,7 +96,7 @@ function YdbUserDropdown({isCompact, popupAnchor, ydbUser}: YdbUserDropdownProps
|
|
91
96
|
compact={isCompact}
|
92
97
|
item={{
|
93
98
|
id: 'user-popup',
|
94
|
-
title: ydbUser?.login ?? '
|
99
|
+
title: ydbUser?.login ?? i18n('navigation-item.account'),
|
95
100
|
current: isUserDropdownVisible,
|
96
101
|
icon: iconData,
|
97
102
|
iconSize: 22,
|
@@ -142,7 +147,7 @@ export const useGetLeftNavigationItems = () => {
|
|
142
147
|
const items: MenuItem[] = [
|
143
148
|
{
|
144
149
|
id: TENANT_PAGES_IDS.query,
|
145
|
-
title: '
|
150
|
+
title: i18n('pages.query'),
|
146
151
|
icon: terminalIcon,
|
147
152
|
iconSize: 20,
|
148
153
|
location: getTenantPath({
|
@@ -152,7 +157,7 @@ export const useGetLeftNavigationItems = () => {
|
|
152
157
|
},
|
153
158
|
{
|
154
159
|
id: TENANT_PAGES_IDS.diagnostics,
|
155
|
-
title: '
|
160
|
+
title: i18n('pages.diagnostics'),
|
156
161
|
icon: pulseIcon,
|
157
162
|
iconSize: 20,
|
158
163
|
location: getTenantPath({
|
@@ -212,7 +217,7 @@ function AsideNavigation(props: AsideNavigationProps) {
|
|
212
217
|
compact={compact}
|
213
218
|
item={{
|
214
219
|
id: 'documentation',
|
215
|
-
title: '
|
220
|
+
title: i18n('navigation-item.documentation'),
|
216
221
|
icon: supportIcon,
|
217
222
|
iconSize: 24,
|
218
223
|
onItemClick: () => {
|
@@ -224,7 +229,7 @@ function AsideNavigation(props: AsideNavigationProps) {
|
|
224
229
|
<FooterItem
|
225
230
|
item={{
|
226
231
|
id: 'user-settings',
|
227
|
-
title: '
|
232
|
+
title: i18n('navigation-item.settings'),
|
228
233
|
icon: settingsIcon,
|
229
234
|
iconSize: 24,
|
230
235
|
current: visiblePanel === Panel.UserSettings,
|
@@ -0,0 +1,13 @@
|
|
1
|
+
{
|
2
|
+
"pages.query": "Query",
|
3
|
+
"pages.diagnostics": "Diagnostics",
|
4
|
+
|
5
|
+
"navigation-item.documentation": "Documentation",
|
6
|
+
"navigation-item.settings": "Settings",
|
7
|
+
"navigation-item.account": "Account",
|
8
|
+
|
9
|
+
"account.user": "YDB User",
|
10
|
+
|
11
|
+
"account.login": "Login",
|
12
|
+
"account.logout": "Logout"
|
13
|
+
}
|
@@ -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-aside-navigation';
|
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,13 @@
|
|
1
|
+
{
|
2
|
+
"pages.query": "Редактор запросов",
|
3
|
+
"pages.diagnostics": "Диагностика",
|
4
|
+
|
5
|
+
"navigation-item.documentation": "Документация",
|
6
|
+
"navigation-item.settings": "Настройки",
|
7
|
+
"navigation-item.account": "Аккаунт",
|
8
|
+
|
9
|
+
"account.user": "Пользователь YDB",
|
10
|
+
|
11
|
+
"account.login": "Войти",
|
12
|
+
"account.logout": "Выйти"
|
13
|
+
}
|
@@ -1,29 +1,34 @@
|
|
1
1
|
import {useState} from 'react';
|
2
2
|
import cn from 'bem-cn-lite';
|
3
|
-
import
|
3
|
+
import {isEmpty} from 'lodash/fp';
|
4
4
|
|
5
5
|
import {ArrowToggle, Button, Popover} from '@gravity-ui/uikit';
|
6
6
|
|
7
|
-
import DataTable, {Column
|
8
|
-
|
9
|
-
import EntityStatus from '../../../components/EntityStatus/EntityStatus';
|
10
|
-
import InfoViewer from '../../../components/InfoViewer/InfoViewer';
|
11
|
-
import {ProgressViewer} from '../../../components/ProgressViewer/ProgressViewer';
|
12
|
-
import {Icon} from '../../../components/Icon';
|
13
|
-
import {Vdisk} from './Vdisk';
|
7
|
+
import DataTable, {type Column} from '@gravity-ui/react-data-table';
|
14
8
|
|
9
|
+
import type {ValueOf} from '../../../types/common';
|
10
|
+
import type {
|
11
|
+
PreparedStructurePDisk,
|
12
|
+
PreparedStructureVDisk,
|
13
|
+
} from '../../../store/reducers/node/types';
|
14
|
+
import {EVDiskState} from '../../../types/api/vdisk';
|
15
15
|
import {bytesToGB, pad9} from '../../../utils/utils';
|
16
16
|
import {formatStorageValuesToGb} from '../../../utils/dataFormatters/dataFormatters';
|
17
17
|
import {getPDiskType} from '../../../utils/pdisk';
|
18
|
-
|
19
18
|
import {DEFAULT_TABLE_SETTINGS} from '../../../utils/constants';
|
19
|
+
import EntityStatus from '../../../components/EntityStatus/EntityStatus';
|
20
|
+
import InfoViewer, {type InfoViewerItem} from '../../../components/InfoViewer/InfoViewer';
|
21
|
+
import {ProgressViewer} from '../../../components/ProgressViewer/ProgressViewer';
|
22
|
+
import {Icon} from '../../../components/Icon';
|
23
|
+
|
24
|
+
import {Vdisk} from './Vdisk';
|
20
25
|
import {valueIsDefined} from './NodeStructure';
|
21
26
|
import {PDiskTitleBadge} from './PDiskTitleBadge';
|
22
27
|
|
23
28
|
const b = cn('kv-node-structure');
|
24
29
|
|
25
30
|
interface PDiskProps {
|
26
|
-
data:
|
31
|
+
data: PreparedStructurePDisk;
|
27
32
|
unfolded?: boolean;
|
28
33
|
id: string;
|
29
34
|
selectedVdiskId?: string;
|
@@ -37,8 +42,7 @@ enum VDiskTableColumnsIds {
|
|
37
42
|
Info = 'Info',
|
38
43
|
}
|
39
44
|
|
40
|
-
type
|
41
|
-
type VDiskTableColumnsIdsValues = typeof VDiskTableColumnsIds[VDiskTableColumnsIdsKeys];
|
45
|
+
type VDiskTableColumnsIdsValues = ValueOf<typeof VDiskTableColumnsIds>;
|
42
46
|
|
43
47
|
const vDiskTableColumnsNames: Record<VDiskTableColumnsIdsValues, string> = {
|
44
48
|
VDiskSlotId: 'Slot id',
|
@@ -47,39 +51,35 @@ const vDiskTableColumnsNames: Record<VDiskTableColumnsIdsValues, string> = {
|
|
47
51
|
Info: '',
|
48
52
|
};
|
49
53
|
|
50
|
-
interface RowType {
|
51
|
-
id: string;
|
52
|
-
[VDiskTableColumnsIds.slotId]: number;
|
53
|
-
[VDiskTableColumnsIds.VDiskState]: string;
|
54
|
-
AllocatedSize: string;
|
55
|
-
AvailableSize: string;
|
56
|
-
}
|
57
|
-
|
58
54
|
function getColumns({
|
59
55
|
pDiskId,
|
60
56
|
selectedVdiskId,
|
61
57
|
nodeHref,
|
62
58
|
}: {
|
63
|
-
pDiskId: number;
|
59
|
+
pDiskId: number | undefined;
|
64
60
|
selectedVdiskId?: string;
|
65
61
|
nodeHref?: string | null;
|
66
62
|
}) {
|
67
|
-
const columns: Column<
|
63
|
+
const columns: Column<PreparedStructureVDisk>[] = [
|
68
64
|
{
|
69
|
-
name: VDiskTableColumnsIds.slotId
|
65
|
+
name: VDiskTableColumnsIds.slotId,
|
70
66
|
header: vDiskTableColumnsNames[VDiskTableColumnsIds.slotId],
|
71
67
|
width: 100,
|
72
|
-
render: ({
|
68
|
+
render: ({row}) => {
|
73
69
|
let vdiskInternalViewerLink = '';
|
74
70
|
|
75
|
-
if (nodeHref &&
|
71
|
+
if (nodeHref && pDiskId !== undefined && row.VDiskSlotId !== undefined) {
|
76
72
|
vdiskInternalViewerLink +=
|
77
|
-
nodeHref +
|
73
|
+
nodeHref +
|
74
|
+
'actors/vdisks/vdisk' +
|
75
|
+
pad9(pDiskId) +
|
76
|
+
'_' +
|
77
|
+
pad9(row.VDiskSlotId);
|
78
78
|
}
|
79
79
|
|
80
80
|
return (
|
81
81
|
<div className={b('vdisk-id', {selected: row.id === selectedVdiskId})}>
|
82
|
-
<span>{
|
82
|
+
<span>{row.VDiskSlotId}</span>
|
83
83
|
{vdiskInternalViewerLink && (
|
84
84
|
<Button
|
85
85
|
size="s"
|
@@ -96,17 +96,19 @@ function getColumns({
|
|
96
96
|
align: DataTable.LEFT,
|
97
97
|
},
|
98
98
|
{
|
99
|
-
name: VDiskTableColumnsIds.VDiskState
|
99
|
+
name: VDiskTableColumnsIds.VDiskState,
|
100
100
|
header: vDiskTableColumnsNames[VDiskTableColumnsIds.VDiskState],
|
101
101
|
width: 70,
|
102
|
-
render: ({
|
103
|
-
return
|
102
|
+
render: ({row}) => {
|
103
|
+
return (
|
104
|
+
<EntityStatus status={row.VDiskState === EVDiskState.OK ? 'green' : 'red'} />
|
105
|
+
);
|
104
106
|
},
|
105
|
-
sortAccessor: (row) => (row
|
107
|
+
sortAccessor: (row) => (row.VDiskState === EVDiskState.OK ? 1 : 0),
|
106
108
|
align: DataTable.CENTER,
|
107
109
|
},
|
108
110
|
{
|
109
|
-
name: VDiskTableColumnsIds.Size
|
111
|
+
name: VDiskTableColumnsIds.Size,
|
110
112
|
header: vDiskTableColumnsNames[VDiskTableColumnsIds.Size],
|
111
113
|
width: 100,
|
112
114
|
render: ({row}) => {
|
@@ -123,7 +125,7 @@ function getColumns({
|
|
123
125
|
align: DataTable.CENTER,
|
124
126
|
},
|
125
127
|
{
|
126
|
-
name: VDiskTableColumnsIds.Info
|
128
|
+
name: VDiskTableColumnsIds.Info,
|
127
129
|
header: vDiskTableColumnsNames[VDiskTableColumnsIds.Info],
|
128
130
|
width: 70,
|
129
131
|
render: ({row}) => {
|
@@ -150,10 +152,31 @@ function getColumns({
|
|
150
152
|
return columns;
|
151
153
|
}
|
152
154
|
|
153
|
-
export function PDisk(
|
154
|
-
|
155
|
+
export function PDisk({
|
156
|
+
id,
|
157
|
+
data,
|
158
|
+
selectedVdiskId,
|
159
|
+
nodeHref,
|
160
|
+
unfolded: unfoldedFromProps,
|
161
|
+
}: PDiskProps) {
|
162
|
+
const [unfolded, setUnfolded] = useState(unfoldedFromProps ?? false);
|
163
|
+
|
164
|
+
const {
|
165
|
+
TotalSize = 0,
|
166
|
+
AvailableSize = 0,
|
167
|
+
Device,
|
168
|
+
Guid,
|
169
|
+
PDiskId,
|
170
|
+
Path,
|
171
|
+
Realtime,
|
172
|
+
State,
|
173
|
+
Category,
|
174
|
+
SerialNumber,
|
175
|
+
vDisks,
|
176
|
+
} = data;
|
155
177
|
|
156
|
-
const
|
178
|
+
const total = Number(TotalSize);
|
179
|
+
const available = Number(AvailableSize);
|
157
180
|
|
158
181
|
const onOpenPDiskDetails = () => {
|
159
182
|
setUnfolded(true);
|
@@ -163,15 +186,12 @@ export function PDisk(props: PDiskProps) {
|
|
163
186
|
};
|
164
187
|
|
165
188
|
const renderVDisks = () => {
|
166
|
-
const {selectedVdiskId, data, nodeHref} = props;
|
167
|
-
const {vDisks} = data;
|
168
|
-
|
169
189
|
return (
|
170
190
|
<DataTable
|
171
191
|
theme="yandex-cloud"
|
172
192
|
data={vDisks}
|
173
|
-
columns={getColumns({nodeHref, pDiskId:
|
174
|
-
settings={{...DEFAULT_TABLE_SETTINGS, dynamicRender: false}
|
193
|
+
columns={getColumns({nodeHref, pDiskId: PDiskId, selectedVdiskId})}
|
194
|
+
settings={{...DEFAULT_TABLE_SETTINGS, dynamicRender: false}}
|
175
195
|
rowClassName={(row) => {
|
176
196
|
return row.id === selectedVdiskId ? b('selected-vdisk') : '';
|
177
197
|
}}
|
@@ -180,30 +200,16 @@ export function PDisk(props: PDiskProps) {
|
|
180
200
|
};
|
181
201
|
|
182
202
|
const renderPDiskDetails = () => {
|
183
|
-
if (
|
203
|
+
if (isEmpty(data)) {
|
184
204
|
return <div>No information about PDisk</div>;
|
185
205
|
}
|
186
|
-
const {nodeHref} = props;
|
187
|
-
const {
|
188
|
-
TotalSize,
|
189
|
-
AvailableSize,
|
190
|
-
Device,
|
191
|
-
Guid,
|
192
|
-
PDiskId,
|
193
|
-
Path,
|
194
|
-
Realtime,
|
195
|
-
State,
|
196
|
-
Category,
|
197
|
-
SerialNumber,
|
198
|
-
} = data;
|
199
|
-
|
200
206
|
let pDiskInternalViewerLink = '';
|
201
207
|
|
202
208
|
if (nodeHref) {
|
203
209
|
pDiskInternalViewerLink += nodeHref + 'actors/pdisks/pdisk' + pad9(PDiskId);
|
204
210
|
}
|
205
211
|
|
206
|
-
const pdiskInfo:
|
212
|
+
const pdiskInfo: InfoViewerItem[] = [
|
207
213
|
{
|
208
214
|
label: 'PDisk Id',
|
209
215
|
value: (
|
@@ -236,19 +242,19 @@ export function PDisk(props: PDiskProps) {
|
|
236
242
|
}
|
237
243
|
pdiskInfo.push({
|
238
244
|
label: 'Allocated Size',
|
239
|
-
value: bytesToGB(
|
245
|
+
value: bytesToGB(total - available),
|
240
246
|
});
|
241
247
|
pdiskInfo.push({
|
242
248
|
label: 'Available Size',
|
243
|
-
value: bytesToGB(
|
249
|
+
value: bytesToGB(available),
|
244
250
|
});
|
245
|
-
if (
|
251
|
+
if (total >= 0 && available >= 0) {
|
246
252
|
pdiskInfo.push({
|
247
253
|
label: 'Size',
|
248
254
|
value: (
|
249
255
|
<ProgressViewer
|
250
|
-
value={
|
251
|
-
capacity={
|
256
|
+
value={total - available}
|
257
|
+
capacity={total}
|
252
258
|
formatValues={formatStorageValuesToGb}
|
253
259
|
colorizeProgress={true}
|
254
260
|
className={b('size')}
|
@@ -286,24 +292,24 @@ export function PDisk(props: PDiskProps) {
|
|
286
292
|
};
|
287
293
|
|
288
294
|
return (
|
289
|
-
<div className={b('pdisk')} id={
|
295
|
+
<div className={b('pdisk')} id={id}>
|
290
296
|
<div className={b('pdisk-header')}>
|
291
297
|
<div className={b('pdisk-title-wrapper')}>
|
292
|
-
<EntityStatus status={
|
298
|
+
<EntityStatus status={Device} />
|
293
299
|
<PDiskTitleBadge
|
294
300
|
label="PDiskID"
|
295
|
-
value={
|
301
|
+
value={PDiskId}
|
296
302
|
className={b('pdisk-title-id')}
|
297
303
|
/>
|
298
304
|
<PDiskTitleBadge value={getPDiskType(data)} className={b('pdisk-title-type')} />
|
299
305
|
<ProgressViewer
|
300
|
-
value={
|
301
|
-
capacity={
|
306
|
+
value={total - available}
|
307
|
+
capacity={total}
|
302
308
|
formatValues={formatStorageValuesToGb}
|
303
309
|
colorizeProgress={true}
|
304
310
|
className={b('pdisk-title-size')}
|
305
311
|
/>
|
306
|
-
<PDiskTitleBadge label="VDisks" value={
|
312
|
+
<PDiskTitleBadge label="VDisks" value={vDisks.length} />
|
307
313
|
</div>
|
308
314
|
<Button
|
309
315
|
onClick={unfolded ? onClosePDiskDetails : onOpenPDiskDetails}
|
@@ -1,43 +1,19 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import cn from 'bem-cn-lite';
|
3
3
|
|
4
|
-
import {
|
4
|
+
import type {TVDiskStateInfo} from '../../../types/api/vdisk';
|
5
5
|
import {
|
6
6
|
formatStorageValuesToGb,
|
7
7
|
stringifyVdiskId,
|
8
8
|
} from '../../../utils/dataFormatters/dataFormatters';
|
9
9
|
import {bytesToGB, bytesToSpeed} from '../../../utils/utils';
|
10
10
|
import EntityStatus from '../../../components/EntityStatus/EntityStatus';
|
11
|
-
import {valueIsDefined} from './NodeStructure';
|
12
11
|
import InfoViewer from '../../../components/InfoViewer/InfoViewer';
|
12
|
+
import {ProgressViewer} from '../../../components/ProgressViewer/ProgressViewer';
|
13
13
|
|
14
|
-
|
14
|
+
import {valueIsDefined} from './NodeStructure';
|
15
15
|
|
16
|
-
|
17
|
-
AllocatedSize?: string;
|
18
|
-
DiskSpace?: string;
|
19
|
-
FrontQueues?: string;
|
20
|
-
Guid?: string;
|
21
|
-
Replicated?: boolean;
|
22
|
-
VDiskState?: string;
|
23
|
-
VDiskId?: {
|
24
|
-
GroupId: number;
|
25
|
-
GroupGeneration: number;
|
26
|
-
Ring: number;
|
27
|
-
Domain: number;
|
28
|
-
VDisk: number;
|
29
|
-
};
|
30
|
-
VDiskSlotId?: number;
|
31
|
-
Kind?: string;
|
32
|
-
SatisfactionRank?: {FreshRank: {Flag: string}; LevelRank: {Flag: string}};
|
33
|
-
AvailableSize?: string;
|
34
|
-
HasUnreadableBlobs?: boolean;
|
35
|
-
IncarnationGuid?: string;
|
36
|
-
InstanceGuid?: string;
|
37
|
-
StoragePoolName?: string;
|
38
|
-
ReadThroughput?: string;
|
39
|
-
WriteThroughput?: string;
|
40
|
-
}
|
16
|
+
const b = cn('kv-node-structure');
|
41
17
|
|
42
18
|
export function Vdisk({
|
43
19
|
AllocatedSize,
|
@@ -57,7 +33,7 @@ export function Vdisk({
|
|
57
33
|
StoragePoolName,
|
58
34
|
ReadThroughput,
|
59
35
|
WriteThroughput,
|
60
|
-
}:
|
36
|
+
}: TVDiskStateInfo) {
|
61
37
|
const vdiskInfo = [];
|
62
38
|
|
63
39
|
if (valueIsDefined(VDiskSlotId)) {
|
@@ -81,16 +57,16 @@ export function Vdisk({
|
|
81
57
|
value: <EntityStatus status={DiskSpace} />,
|
82
58
|
});
|
83
59
|
}
|
84
|
-
if (valueIsDefined(SatisfactionRank?.FreshRank
|
60
|
+
if (valueIsDefined(SatisfactionRank?.FreshRank?.Flag)) {
|
85
61
|
vdiskInfo.push({
|
86
62
|
label: 'Fresh Rank Satisfaction',
|
87
|
-
value: <EntityStatus status={SatisfactionRank?.FreshRank
|
63
|
+
value: <EntityStatus status={SatisfactionRank?.FreshRank?.Flag} />,
|
88
64
|
});
|
89
65
|
}
|
90
|
-
if (valueIsDefined(SatisfactionRank?.LevelRank
|
66
|
+
if (valueIsDefined(SatisfactionRank?.LevelRank?.Flag)) {
|
91
67
|
vdiskInfo.push({
|
92
68
|
label: 'Level Rank Satisfaction',
|
93
|
-
value: <EntityStatus status={SatisfactionRank?.LevelRank
|
69
|
+
value: <EntityStatus status={SatisfactionRank?.LevelRank?.Flag} />,
|
94
70
|
});
|
95
71
|
}
|
96
72
|
vdiskInfo.push({label: 'Replicated', value: Replicated ? 'Yes' : 'No'});
|
@@ -26,7 +26,11 @@ import {
|
|
26
26
|
useNodesRequestParams,
|
27
27
|
useTableSort,
|
28
28
|
} from '../../utils/hooks';
|
29
|
-
import {
|
29
|
+
import {
|
30
|
+
isSortableNodesProperty,
|
31
|
+
isUnavailableNode,
|
32
|
+
NodesUptimeFilterValues,
|
33
|
+
} from '../../utils/nodes';
|
30
34
|
|
31
35
|
import {
|
32
36
|
getNodes,
|
@@ -153,10 +157,14 @@ export const Nodes = ({path, type, additionalNodesProps = {}}: NodesProps) => {
|
|
153
157
|
};
|
154
158
|
|
155
159
|
const renderTable = () => {
|
156
|
-
const
|
160
|
+
const rawColumns = getNodesColumns({
|
157
161
|
getNodeRef: additionalNodesProps.getNodeRef,
|
158
162
|
});
|
159
163
|
|
164
|
+
const columns = rawColumns.map((column) => {
|
165
|
+
return {...column, sortable: isSortableNodesProperty(column.name)};
|
166
|
+
});
|
167
|
+
|
160
168
|
if (nodes && nodes.length === 0) {
|
161
169
|
if (
|
162
170
|
problemFilter !== ProblemFilterValues.ALL ||
|