ydb-embedded-ui 4.19.2 → 4.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 ||
|