ydb-embedded-ui 4.27.1 → 4.29.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 +14 -0
- package/dist/assets/illustrations/dark/error.svg +32 -0
- package/dist/assets/illustrations/light/error.svg +32 -0
- package/dist/components/EmptyState/EmptyState.scss +5 -2
- package/dist/components/EmptyState/EmptyState.tsx +11 -3
- package/dist/components/ErrorBoundary/ErrorBoundary.scss +40 -0
- package/dist/components/ErrorBoundary/ErrorBoundary.tsx +62 -0
- package/dist/components/ErrorBoundary/i18n/en.json +7 -0
- package/dist/components/ErrorBoundary/i18n/index.ts +11 -0
- package/dist/components/ErrorBoundary/i18n/ru.json +7 -0
- package/dist/components/Errors/403/AccessDenied.tsx +4 -3
- package/dist/components/Illustration/Illustration.tsx +3 -1
- package/dist/components/ProblemFilter/ProblemFilter.tsx +1 -1
- package/dist/components/UptimeFIlter/UptimeFilter.tsx +1 -1
- package/dist/components/VirtualTable/VirtualTable.scss +1 -1
- package/dist/containers/App/App.js +5 -2
- package/dist/containers/Cluster/Cluster.tsx +11 -12
- package/dist/containers/Nodes/Nodes.tsx +4 -4
- package/dist/containers/Nodes/NodesWrapper.tsx +21 -0
- package/dist/containers/Nodes/VirtualNodes.tsx +4 -14
- package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.scss +1 -0
- package/dist/containers/Storage/EmptyFilter/EmptyFilter.tsx +1 -0
- package/dist/containers/Storage/PDisk/PDisk.tsx +5 -7
- package/dist/containers/Storage/Storage.tsx +30 -67
- package/dist/containers/Storage/StorageControls/StorageControls.tsx +104 -0
- package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +18 -62
- package/dist/containers/Storage/StorageGroups/StorageGroupsEmptyDataMessage.tsx +30 -0
- package/dist/containers/Storage/StorageGroups/VirtualStorageGroups.tsx +94 -0
- package/dist/containers/Storage/StorageGroups/getGroups.ts +21 -0
- package/dist/containers/Storage/StorageGroups/getStorageGroupsColumns.tsx +73 -50
- package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +23 -138
- package/dist/containers/Storage/StorageNodes/StorageNodesEmptyDataMessage.tsx +44 -0
- package/dist/containers/Storage/StorageNodes/VirtualStorageNodes.tsx +105 -0
- package/dist/containers/Storage/StorageNodes/getNodes.ts +26 -0
- package/dist/containers/Storage/StorageNodes/getStorageNodesColumns.tsx +125 -0
- package/dist/containers/Storage/StorageNodes/shared.ts +9 -0
- package/dist/containers/Storage/StorageTypeFilter/StorageTypeFilter.tsx +1 -1
- package/dist/containers/Storage/StorageVisibleEntitiesFilter/StorageVisibleEntitiesFilter.tsx +1 -1
- package/dist/containers/Storage/StorageWrapper.tsx +23 -0
- package/dist/containers/Storage/UsageFilter/UsageFilter.tsx +3 -4
- package/dist/containers/Storage/VirtualStorage.tsx +112 -0
- package/dist/containers/Storage/i18n/en.json +7 -0
- package/dist/containers/Storage/i18n/index.ts +11 -0
- package/dist/containers/Storage/i18n/ru.json +7 -0
- package/dist/containers/Storage/shared.ts +3 -0
- package/dist/containers/Tenants/Tenants.tsx +2 -2
- package/dist/containers/UserSettings/i18n/en.json +2 -2
- package/dist/containers/UserSettings/i18n/ru.json +2 -2
- package/dist/containers/UserSettings/settings.ts +4 -4
- package/dist/index.tsx +8 -5
- package/dist/store/reducers/storage/selectors.ts +0 -20
- package/dist/utils/registerError.ts +18 -0
- package/package.json +7 -6
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [4.29.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.28.0...v4.29.0) (2024-01-12)
|
4
|
+
|
5
|
+
|
6
|
+
### Features
|
7
|
+
|
8
|
+
* add ErrorBoundary ([#549](https://github.com/ydb-platform/ydb-embedded-ui/issues/549)) ([f5ad224](https://github.com/ydb-platform/ydb-embedded-ui/commit/f5ad224b342e0fa25b1bafa3f5e2202ce165ef80))
|
9
|
+
|
10
|
+
## [4.28.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.27.1...v4.28.0) (2024-01-10)
|
11
|
+
|
12
|
+
|
13
|
+
### Features
|
14
|
+
|
15
|
+
* **Storage:** use VirtualTable ([#628](https://github.com/ydb-platform/ydb-embedded-ui/issues/628)) ([67fd9b0](https://github.com/ydb-platform/ydb-embedded-ui/commit/67fd9b03653dd28be650094c987451b09fcce858))
|
16
|
+
|
3
17
|
## [4.27.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.27.0...v4.27.1) (2024-01-10)
|
4
18
|
|
5
19
|
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="230" height="230" fill="none">
|
2
|
+
<path fill="#BECFE0" fill-opacity=".8" fill-rule="evenodd" d="M169.001 51.666c5.523 0 10 4.477 10 10v21.017l18.197-10.506c4.783-2.762 10.899-1.123 13.66 3.66 2.761 4.783 1.123 10.899-3.66 13.66l-18.197 10.507 18.198 10.506c4.783 2.762 6.421 8.878 3.66 13.661-2.762 4.782-8.877 6.421-13.66 3.66l-18.198-10.506v21.008c0 5.523-4.477 10-10 10-5.522 0-10-4.477-10-10v-21.009l-18.199 10.507c-4.782 2.761-10.898 1.122-13.66-3.66-2.761-4.783-1.122-10.899 3.66-13.661l18.199-10.506-18.198-10.507c-4.783-2.761-6.421-8.877-3.66-13.66 2.762-4.783 8.877-6.422 13.66-3.66l18.198 10.507V61.666c0-5.523 4.478-10 10-10Z" clip-rule="evenodd"/>
|
3
|
+
<path fill="#E7E7E7" fill-rule="evenodd" d="M171.523 95.922a11.003 11.003 0 0 1 1.099 8.347l-13.208 49.291c-1.572 5.868-7.604 9.351-13.472 7.778l-25.356-6.794a44.998 44.998 0 0 1-.53 1.929l25.368 6.797c6.935 1.858 14.064-2.257 15.922-9.192l13.207-49.291c.893-3.33.426-6.879-1.298-9.865L155.598 64.34a12.999 12.999 0 0 0-7.894-6.057l-29.972-8.031c-6.935-1.858-14.063 2.257-15.922 9.192l-11.328 42.277c.64.192 1.276.398 1.905.618l11.355-42.377c1.573-5.868 7.604-9.35 13.472-7.778l29.973 8.03a11 11 0 0 1 6.679 5.126l17.657 30.582Z" clip-rule="evenodd"/>
|
4
|
+
<path fill="#FF5958" fill-opacity=".8" d="M35.388 155.273c-6.29-23.472 7.64-47.599 31.113-53.889 23.472-6.289 47.599 7.641 53.889 31.113 6.289 23.473-7.641 47.599-31.113 53.889-23.473 6.289-47.6-7.64-53.889-31.113Z"/>
|
5
|
+
<path stroke="#E7E7E7" stroke-width="2" d="M60.636 117.734c53.586-33.459-26.868-81.505-36.557-61.318-11.802 24.59 99.395 51.098 128.865-26.3"/>
|
6
|
+
<mask id="b" width="89" height="89" x="33" y="99" maskUnits="userSpaceOnUse" style="mask-type:alpha">
|
7
|
+
<path fill="#FF5958" fill-opacity=".9" d="M35.388 155.273c-6.29-23.472 7.64-47.599 31.113-53.889 23.472-6.289 47.599 7.641 53.889 31.113 6.289 23.473-7.641 47.599-31.113 53.889-23.473 6.289-47.6-7.64-53.889-31.113Z"/>
|
8
|
+
</mask>
|
9
|
+
<g filter="url(#a)" mask="url(#b)">
|
10
|
+
<path stroke="#E7E7E7" stroke-linecap="round" stroke-linejoin="round" stroke-opacity=".6" stroke-width="2" d="M172.389 95.422a12.004 12.004 0 0 1 1.199 9.106l-13.208 49.291c-1.715 6.401-8.295 10.2-14.697 8.485L91.591 147.81c-6.401-1.715-10.2-8.295-8.485-14.697l19.67-73.41c1.716-6.402 8.296-10.2 14.697-8.485l29.972 8.03a11.998 11.998 0 0 1 7.287 5.592l17.657 30.582Z"/>
|
11
|
+
</g>
|
12
|
+
<g filter="url(#c)">
|
13
|
+
<path fill="#fff" fill-opacity=".72" fill-rule="evenodd" d="M80.866 130.432a6.359 6.359 0 1 1-12.284 3.29 6.359 6.359 0 0 1 12.284-3.29Zm4.817-1.291c1.621 6.052-1.97 12.273-8.022 13.894-6.052 1.622-12.273-1.97-13.895-8.022-1.621-6.052 1.97-12.272 8.022-13.894 6.052-1.622 12.273 1.97 13.895 8.022Zm-21.346 32.565c-.154-.577-.009-2.61 2.877-5.555 2.665-2.721 6.917-5.33 12.158-6.734 5.24-1.404 10.227-1.271 13.896-.247 3.971 1.108 5.114 2.796 5.268 3.372a3.116 3.116 0 0 1-2.204 3.817l-28.178 7.55a3.116 3.116 0 0 1-3.817-2.203ZM78.081 144.6c-12.054 3.23-20.238 12.134-18.56 18.396a8.103 8.103 0 0 0 9.924 5.73l28.178-7.55a8.104 8.104 0 0 0 5.73-9.925c-1.678-6.261-13.218-9.881-25.272-6.651Z" clip-rule="evenodd"/>
|
14
|
+
</g>
|
15
|
+
<defs>
|
16
|
+
<filter id="a" width="113.303" height="133.91" x="71.693" y="39.806" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse">
|
17
|
+
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
18
|
+
<feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
19
|
+
<feGaussianBlur result="effect1_foregroundBlur_1301_35376" stdDeviation="5"/>
|
20
|
+
</filter>
|
21
|
+
<filter id="c" width="73.289" height="73.288" x="41.018" y="106.391" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse">
|
22
|
+
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
23
|
+
<feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
24
|
+
<feColorMatrix in="SourceAlpha" result="hardAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
|
25
|
+
<feOffset/>
|
26
|
+
<feGaussianBlur stdDeviation="1.917"/>
|
27
|
+
<feComposite in2="hardAlpha" k2="-1" k3="1" operator="arithmetic"/>
|
28
|
+
<feColorMatrix values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.8 0"/>
|
29
|
+
<feBlend in2="shape" result="effect1_innerShadow_1301_35376"/>
|
30
|
+
</filter>
|
31
|
+
</defs>
|
32
|
+
</svg>
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="230" height="230" fill="none">
|
2
|
+
<path fill="#BECFE0" fill-opacity=".9" fill-rule="evenodd" d="M169.001 51.666c5.523 0 10 4.477 10 10v21.017l18.197-10.506c4.783-2.762 10.899-1.123 13.66 3.66 2.761 4.783 1.123 10.899-3.66 13.66l-18.197 10.507 18.198 10.506c4.783 2.762 6.421 8.878 3.66 13.661-2.762 4.782-8.877 6.421-13.66 3.66l-18.198-10.506v21.008c0 5.523-4.477 10-10 10-5.522 0-10-4.477-10-10v-21.009l-18.199 10.507c-4.782 2.761-10.898 1.122-13.66-3.66-2.761-4.783-1.122-10.899 3.66-13.661l18.199-10.506-18.198-10.507c-4.783-2.761-6.421-8.877-3.66-13.66 2.762-4.783 8.877-6.422 13.66-3.66l18.198 10.507V61.666c0-5.523 4.478-10 10-10Z" clip-rule="evenodd"/>
|
3
|
+
<path fill="#262626" fill-rule="evenodd" d="M171.523 95.922a11.003 11.003 0 0 1 1.099 8.347l-13.208 49.291c-1.572 5.868-7.604 9.351-13.472 7.778l-25.356-6.794a44.998 44.998 0 0 1-.53 1.929l25.368 6.797c6.935 1.858 14.064-2.257 15.922-9.192l13.207-49.291c.893-3.33.426-6.879-1.298-9.865L155.598 64.34a12.999 12.999 0 0 0-7.894-6.057l-29.972-8.031c-6.935-1.858-14.063 2.257-15.922 9.192l-11.328 42.277c.64.192 1.276.398 1.905.618l11.355-42.377c1.573-5.868 7.604-9.35 13.472-7.778l29.973 8.03a11 11 0 0 1 6.679 5.126l17.657 30.582Z" clip-rule="evenodd"/>
|
4
|
+
<path fill="#FF5958" fill-opacity=".9" d="M35.388 155.273c-6.29-23.472 7.64-47.599 31.113-53.889 23.472-6.289 47.599 7.641 53.889 31.113 6.289 23.473-7.641 47.599-31.113 53.889-23.473 6.289-47.6-7.64-53.889-31.113Z"/>
|
5
|
+
<path stroke="#262626" stroke-width="2" d="M60.636 117.734c53.586-33.459-26.868-81.505-36.557-61.318-11.802 24.59 99.395 51.098 128.865-26.3"/>
|
6
|
+
<mask id="b" width="89" height="89" x="33" y="99" maskUnits="userSpaceOnUse" style="mask-type:alpha">
|
7
|
+
<path fill="#FF5958" fill-opacity=".9" d="M35.388 155.273c-6.29-23.472 7.64-47.599 31.113-53.889 23.472-6.289 47.599 7.641 53.889 31.113 6.289 23.473-7.641 47.599-31.113 53.889-23.473 6.289-47.6-7.64-53.889-31.113Z"/>
|
8
|
+
</mask>
|
9
|
+
<g filter="url(#a)" mask="url(#b)">
|
10
|
+
<path stroke="#262626" stroke-linecap="round" stroke-linejoin="round" stroke-opacity=".6" stroke-width="2" d="M172.389 95.422a12.004 12.004 0 0 1 1.199 9.106l-13.208 49.291c-1.715 6.401-8.295 10.2-14.697 8.485L91.591 147.81c-6.401-1.715-10.2-8.295-8.485-14.697l19.67-73.41c1.716-6.402 8.296-10.2 14.697-8.485l29.972 8.03a11.998 11.998 0 0 1 7.287 5.592l17.657 30.582Z"/>
|
11
|
+
</g>
|
12
|
+
<g filter="url(#c)">
|
13
|
+
<path fill="#fff" fill-opacity=".72" fill-rule="evenodd" d="M80.866 130.432a6.359 6.359 0 1 1-12.284 3.29 6.359 6.359 0 0 1 12.284-3.29Zm4.817-1.291c1.621 6.052-1.97 12.273-8.022 13.894-6.052 1.622-12.273-1.97-13.895-8.022-1.621-6.052 1.97-12.272 8.022-13.894 6.052-1.622 12.273 1.97 13.895 8.022Zm-21.346 32.565c-.154-.577-.009-2.61 2.877-5.555 2.665-2.721 6.917-5.33 12.158-6.734 5.24-1.404 10.227-1.271 13.896-.247 3.971 1.108 5.114 2.796 5.268 3.372a3.116 3.116 0 0 1-2.204 3.817l-28.178 7.55a3.116 3.116 0 0 1-3.817-2.203ZM78.081 144.6c-12.054 3.23-20.238 12.134-18.56 18.396a8.103 8.103 0 0 0 9.924 5.73l28.178-7.55a8.104 8.104 0 0 0 5.73-9.925c-1.678-6.261-13.218-9.881-25.272-6.651Z" clip-rule="evenodd"/>
|
14
|
+
</g>
|
15
|
+
<defs>
|
16
|
+
<filter id="a" width="113.303" height="133.91" x="71.693" y="39.806" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse">
|
17
|
+
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
18
|
+
<feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
19
|
+
<feGaussianBlur result="effect1_foregroundBlur_1301_31085" stdDeviation="5"/>
|
20
|
+
</filter>
|
21
|
+
<filter id="c" width="73.289" height="73.288" x="41.018" y="106.391" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse">
|
22
|
+
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
23
|
+
<feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
24
|
+
<feColorMatrix in="SourceAlpha" result="hardAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
|
25
|
+
<feOffset/>
|
26
|
+
<feGaussianBlur stdDeviation="1.917"/>
|
27
|
+
<feComposite in2="hardAlpha" k2="-1" k3="1" operator="arithmetic"/>
|
28
|
+
<feColorMatrix values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.8 0"/>
|
29
|
+
<feBlend in2="shape" result="effect1_innerShadow_1301_31085"/>
|
30
|
+
</filter>
|
31
|
+
</defs>
|
32
|
+
</svg>
|
@@ -13,18 +13,26 @@ const sizes = {
|
|
13
13
|
l: 350,
|
14
14
|
};
|
15
15
|
|
16
|
-
interface EmptyStateProps {
|
16
|
+
export interface EmptyStateProps {
|
17
17
|
title: string;
|
18
18
|
image?: ReactNode;
|
19
19
|
description?: ReactNode;
|
20
20
|
actions?: ReactNode[];
|
21
21
|
size?: keyof typeof sizes;
|
22
|
+
position?: 'left' | 'center';
|
22
23
|
}
|
23
24
|
|
24
|
-
export const EmptyState = ({
|
25
|
+
export const EmptyState = ({
|
26
|
+
image,
|
27
|
+
title,
|
28
|
+
description,
|
29
|
+
actions,
|
30
|
+
size = 'm',
|
31
|
+
position = 'center',
|
32
|
+
}: EmptyStateProps) => {
|
25
33
|
return (
|
26
34
|
<div className={block({size})}>
|
27
|
-
<div className={block('wrapper', {size})}>
|
35
|
+
<div className={block('wrapper', {size, position})}>
|
28
36
|
<div className={block('image')}>
|
29
37
|
{image ? (
|
30
38
|
image
|
@@ -0,0 +1,40 @@
|
|
1
|
+
@import '../../styles/mixins.scss';
|
2
|
+
|
3
|
+
.ydb-error-boundary {
|
4
|
+
display: flex;
|
5
|
+
flex-direction: row;
|
6
|
+
align-items: flex-start;
|
7
|
+
|
8
|
+
padding: 20px;
|
9
|
+
|
10
|
+
@include body-2-typography();
|
11
|
+
|
12
|
+
&__illustration {
|
13
|
+
width: 230px;
|
14
|
+
height: 230px;
|
15
|
+
margin-right: 20px;
|
16
|
+
}
|
17
|
+
&__error-title {
|
18
|
+
margin-top: 44px;
|
19
|
+
@include lead-typography();
|
20
|
+
}
|
21
|
+
&__error-description {
|
22
|
+
margin-top: 12px;
|
23
|
+
}
|
24
|
+
&__show-details {
|
25
|
+
margin-top: 8px;
|
26
|
+
}
|
27
|
+
&__error-details {
|
28
|
+
padding: 13px 18px;
|
29
|
+
|
30
|
+
border: 1px solid var(--g-color-line-generic);
|
31
|
+
background-color: var(--g-color-base-generic-ultralight);
|
32
|
+
}
|
33
|
+
&__actions {
|
34
|
+
display: flex;
|
35
|
+
flex-direction: row;
|
36
|
+
gap: 10px;
|
37
|
+
|
38
|
+
margin-top: 20px;
|
39
|
+
}
|
40
|
+
}
|
@@ -0,0 +1,62 @@
|
|
1
|
+
import type {ReactNode} from 'react';
|
2
|
+
import {ErrorBoundary as ErrorBoundaryBase} from 'react-error-boundary';
|
3
|
+
import cn from 'bem-cn-lite';
|
4
|
+
|
5
|
+
import {Button, Disclosure} from '@gravity-ui/uikit';
|
6
|
+
|
7
|
+
import {registerError} from '../../utils/registerError';
|
8
|
+
import {Illustration} from '../Illustration';
|
9
|
+
import i18n from './i18n';
|
10
|
+
import './ErrorBoundary.scss';
|
11
|
+
|
12
|
+
const b = cn('ydb-error-boundary');
|
13
|
+
|
14
|
+
interface ErrorBoundaryProps {
|
15
|
+
children?: ReactNode;
|
16
|
+
useRetry?: boolean;
|
17
|
+
onReportProblem?: (error?: Error) => void;
|
18
|
+
}
|
19
|
+
|
20
|
+
export const ErrorBoundary = ({children, useRetry = true, onReportProblem}: ErrorBoundaryProps) => {
|
21
|
+
return (
|
22
|
+
<ErrorBoundaryBase
|
23
|
+
onError={(error, info) => {
|
24
|
+
registerError(error, info.componentStack, 'error-boundary');
|
25
|
+
}}
|
26
|
+
fallbackRender={({error, resetErrorBoundary}) => {
|
27
|
+
return (
|
28
|
+
<div className={b(null)}>
|
29
|
+
<Illustration name="error" className={b('illustration')} />
|
30
|
+
<div className={b('content')}>
|
31
|
+
<h2 className={b('error-title')}>{i18n('error-title')}</h2>
|
32
|
+
<div className={b('error-description')}>
|
33
|
+
{i18n('error-description')}
|
34
|
+
</div>
|
35
|
+
<Disclosure
|
36
|
+
summary={i18n('show-details')}
|
37
|
+
className={b('show-details')}
|
38
|
+
size="m"
|
39
|
+
>
|
40
|
+
<pre className={b('error-details')}>{error.stack}</pre>
|
41
|
+
</Disclosure>
|
42
|
+
<div className={b('actions')}>
|
43
|
+
{useRetry && (
|
44
|
+
<Button view="outlined" onClick={resetErrorBoundary}>
|
45
|
+
{i18n('button-reset')}
|
46
|
+
</Button>
|
47
|
+
)}
|
48
|
+
{onReportProblem && (
|
49
|
+
<Button view="outlined" onClick={() => onReportProblem(error)}>
|
50
|
+
{i18n('report-problem')}
|
51
|
+
</Button>
|
52
|
+
)}
|
53
|
+
</div>
|
54
|
+
</div>
|
55
|
+
</div>
|
56
|
+
);
|
57
|
+
}}
|
58
|
+
>
|
59
|
+
{children}
|
60
|
+
</ErrorBoundaryBase>
|
61
|
+
);
|
62
|
+
};
|
@@ -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-error-boundary';
|
7
|
+
|
8
|
+
i18n.registerKeyset(Lang.En, COMPONENT, en);
|
9
|
+
i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
|
10
|
+
|
11
|
+
export default i18n.keyset(COMPONENT);
|
@@ -1,19 +1,20 @@
|
|
1
|
-
import {EmptyState} from '../../EmptyState';
|
1
|
+
import {EmptyState, type EmptyStateProps} from '../../EmptyState';
|
2
2
|
import {Illustration} from '../../Illustration';
|
3
3
|
|
4
4
|
import i18n from '../i18n';
|
5
5
|
|
6
|
-
interface AccessDeniedProps {
|
6
|
+
interface AccessDeniedProps extends Omit<EmptyStateProps, 'image' | 'title' | 'description'> {
|
7
7
|
title?: string;
|
8
8
|
description?: string;
|
9
9
|
}
|
10
10
|
|
11
|
-
export const AccessDenied = ({title, description}: AccessDeniedProps) => {
|
11
|
+
export const AccessDenied = ({title, description, ...restProps}: AccessDeniedProps) => {
|
12
12
|
return (
|
13
13
|
<EmptyState
|
14
14
|
image={<Illustration name="403" />}
|
15
15
|
title={title || i18n('403.title')}
|
16
16
|
description={description || i18n('403.description')}
|
17
|
+
{...restProps}
|
17
18
|
/>
|
18
19
|
);
|
19
20
|
};
|
@@ -13,10 +13,12 @@ const store: IllustrationStore = {
|
|
13
13
|
light: {
|
14
14
|
403: () => import('../../assets/illustrations/light/403.svg'),
|
15
15
|
thumbsUp: () => import('../../assets/illustrations/light/thumbsUp.svg'),
|
16
|
+
error: () => import('../../assets/illustrations/light/error.svg'),
|
16
17
|
},
|
17
18
|
dark: {
|
18
19
|
403: () => import('../../assets/illustrations/dark/403.svg'),
|
19
|
-
thumbsUp: () => import('../../assets/illustrations/
|
20
|
+
thumbsUp: () => import('../../assets/illustrations/dark/thumbsUp.svg'),
|
21
|
+
error: () => import('../../assets/illustrations/dark/error.svg'),
|
20
22
|
},
|
21
23
|
};
|
22
24
|
|
@@ -4,7 +4,7 @@ import {NodesUptimeFilterValues, NodesUptimeFilterTitles} from '../../utils/node
|
|
4
4
|
|
5
5
|
interface UptimeFilterProps {
|
6
6
|
value: NodesUptimeFilterValues;
|
7
|
-
onChange: (value:
|
7
|
+
onChange: (value: NodesUptimeFilterValues) => void;
|
8
8
|
className?: string;
|
9
9
|
}
|
10
10
|
|
@@ -7,6 +7,7 @@ import AsideNavigation from '../AsideNavigation/AsideNavigation';
|
|
7
7
|
|
8
8
|
import {getUser} from '../../store/reducers/authentication/authentication';
|
9
9
|
import {registerLanguages} from '../../utils/monaco';
|
10
|
+
import {ErrorBoundary} from '../../components/ErrorBoundary/ErrorBoundary';
|
10
11
|
|
11
12
|
import './App.scss';
|
12
13
|
|
@@ -38,8 +39,10 @@ class App extends React.Component {
|
|
38
39
|
const {singleClusterMode, clusterName} = this.props;
|
39
40
|
return (
|
40
41
|
<AsideNavigation>
|
41
|
-
<
|
42
|
-
|
42
|
+
<ErrorBoundary>
|
43
|
+
<Content singleClusterMode={singleClusterMode} clusterName={clusterName} />
|
44
|
+
<div id="fullscreen-root"></div>
|
45
|
+
</ErrorBoundary>
|
43
46
|
</AsideNavigation>
|
44
47
|
);
|
45
48
|
}
|
@@ -18,14 +18,12 @@ import {setHeaderBreadcrumbs} from '../../store/reducers/header/header';
|
|
18
18
|
import {getClusterInfo} from '../../store/reducers/cluster/cluster';
|
19
19
|
import {getClusterNodes} from '../../store/reducers/clusterNodes/clusterNodes';
|
20
20
|
import {parseNodesToVersionsValues, parseVersionsToVersionToColorMap} from '../../utils/versions';
|
21
|
-
import {useAutofetcher,
|
22
|
-
import {USE_BACKEND_PARAMS_FOR_TABLES_KEY} from '../../utils/constants';
|
21
|
+
import {useAutofetcher, useTypedSelector} from '../../utils/hooks';
|
23
22
|
|
24
23
|
import {InternalLink} from '../../components/InternalLink';
|
25
24
|
import {Tenants} from '../Tenants/Tenants';
|
26
|
-
import {
|
27
|
-
import {
|
28
|
-
import {Storage} from '../Storage/Storage';
|
25
|
+
import {StorageWrapper} from '../Storage/StorageWrapper';
|
26
|
+
import {NodesWrapper} from '../Nodes/NodesWrapper';
|
29
27
|
import {Versions} from '../Versions/Versions';
|
30
28
|
|
31
29
|
import {ClusterInfo} from './ClusterInfo/ClusterInfo';
|
@@ -55,8 +53,6 @@ function Cluster({
|
|
55
53
|
const match = useRouteMatch<{activeTab: string}>(routes.cluster);
|
56
54
|
const {activeTab = clusterTabsIds.tenants} = match?.params || {};
|
57
55
|
|
58
|
-
const [useVirtualNodes] = useSetting<boolean>(USE_BACKEND_PARAMS_FOR_TABLES_KEY);
|
59
|
-
|
60
56
|
const location = useLocation();
|
61
57
|
const queryParams = qs.parse(location.search, {
|
62
58
|
ignoreQueryPrefix: true,
|
@@ -111,17 +107,20 @@ function Cluster({
|
|
111
107
|
return <Tenants additionalTenantsProps={additionalTenantsProps} />;
|
112
108
|
}
|
113
109
|
case clusterTabsIds.nodes: {
|
114
|
-
return
|
115
|
-
<
|
110
|
+
return (
|
111
|
+
<NodesWrapper
|
116
112
|
parentContainer={container.current}
|
117
113
|
additionalNodesProps={additionalNodesProps}
|
118
114
|
/>
|
119
|
-
) : (
|
120
|
-
<Nodes additionalNodesProps={additionalNodesProps} />
|
121
115
|
);
|
122
116
|
}
|
123
117
|
case clusterTabsIds.storage: {
|
124
|
-
return
|
118
|
+
return (
|
119
|
+
<StorageWrapper
|
120
|
+
parentContainer={container.current}
|
121
|
+
additionalNodesProps={additionalNodesProps}
|
122
|
+
/>
|
123
|
+
);
|
125
124
|
}
|
126
125
|
case clusterTabsIds.versions: {
|
127
126
|
return <Versions versionToColor={versionToColor} />;
|
@@ -106,12 +106,12 @@ export const Nodes = ({path, additionalNodesProps = {}}: NodesProps) => {
|
|
106
106
|
dispatch(setSearchValue(value));
|
107
107
|
};
|
108
108
|
|
109
|
-
const handleProblemFilterChange = (value:
|
110
|
-
dispatch(changeFilter(value
|
109
|
+
const handleProblemFilterChange = (value: ProblemFilterValue) => {
|
110
|
+
dispatch(changeFilter(value));
|
111
111
|
};
|
112
112
|
|
113
|
-
const handleUptimeFilterChange = (value:
|
114
|
-
dispatch(setNodesUptimeFilter(value
|
113
|
+
const handleUptimeFilterChange = (value: NodesUptimeFilterValues) => {
|
114
|
+
dispatch(setNodesUptimeFilter(value));
|
115
115
|
};
|
116
116
|
|
117
117
|
const renderControls = () => {
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import type {AdditionalNodesProps} from '../../types/additionalProps';
|
2
|
+
import {USE_BACKEND_PARAMS_FOR_TABLES_KEY} from '../../utils/constants';
|
3
|
+
import {useSetting} from '../../utils/hooks';
|
4
|
+
|
5
|
+
import {VirtualNodes} from './VirtualNodes';
|
6
|
+
import {Nodes} from './Nodes';
|
7
|
+
|
8
|
+
interface NodesWrapperProps {
|
9
|
+
parentContainer?: Element | null;
|
10
|
+
additionalNodesProps?: AdditionalNodesProps;
|
11
|
+
}
|
12
|
+
|
13
|
+
export const NodesWrapper = ({parentContainer, ...props}: NodesWrapperProps) => {
|
14
|
+
const [useVirtualTable] = useSetting<boolean>(USE_BACKEND_PARAMS_FOR_TABLES_KEY);
|
15
|
+
|
16
|
+
if (useVirtualTable) {
|
17
|
+
return <VirtualNodes parentContainer={parentContainer} {...props} />;
|
18
|
+
}
|
19
|
+
|
20
|
+
return <Nodes {...props} />;
|
21
|
+
};
|
@@ -72,27 +72,17 @@ export const VirtualNodes = ({parentContainer, additionalNodesProps}: NodesProps
|
|
72
72
|
return b('node', {unavailable: isUnavailableNode(row)});
|
73
73
|
};
|
74
74
|
|
75
|
-
const handleSearchQueryChange = (value: string) => {
|
76
|
-
setSearchValue(value);
|
77
|
-
};
|
78
|
-
const handleProblemFilterChange = (value: string) => {
|
79
|
-
setProblemFilter(value as ProblemFilterValue);
|
80
|
-
};
|
81
|
-
const handleUptimeFilterChange = (value: string) => {
|
82
|
-
setUptimeFilter(value as NodesUptimeFilterValues);
|
83
|
-
};
|
84
|
-
|
85
75
|
const renderControls: RenderControls = ({totalEntities, foundEntities, inited}) => {
|
86
76
|
return (
|
87
77
|
<>
|
88
78
|
<Search
|
89
|
-
onChange={
|
79
|
+
onChange={setSearchValue}
|
90
80
|
placeholder="Host name"
|
91
81
|
className={b('search')}
|
92
82
|
value={searchValue}
|
93
83
|
/>
|
94
|
-
<ProblemFilter value={problemFilter} onChange={
|
95
|
-
<UptimeFilter value={uptimeFilter} onChange={
|
84
|
+
<ProblemFilter value={problemFilter} onChange={setProblemFilter} />
|
85
|
+
<UptimeFilter value={uptimeFilter} onChange={setUptimeFilter} />
|
96
86
|
<EntitiesCount
|
97
87
|
total={totalEntities}
|
98
88
|
current={foundEntities}
|
@@ -116,7 +106,7 @@ export const VirtualNodes = ({parentContainer, additionalNodesProps}: NodesProps
|
|
116
106
|
|
117
107
|
const renderErrorMessage: RenderErrorMessage = (error) => {
|
118
108
|
if (error && error.status === 403) {
|
119
|
-
return <AccessDenied />;
|
109
|
+
return <AccessDenied position="left" />;
|
120
110
|
}
|
121
111
|
|
122
112
|
return <ResponseError error={error} />;
|
@@ -1,14 +1,13 @@
|
|
1
1
|
import React, {useEffect, useState, useRef, useMemo} from 'react';
|
2
2
|
import cn from 'bem-cn-lite';
|
3
3
|
|
4
|
+
import type {TVDiskStateInfo} from '../../../types/api/vdisk';
|
4
5
|
import {InternalLink} from '../../../components/InternalLink';
|
5
6
|
import {Stack} from '../../../components/Stack/Stack';
|
6
7
|
|
7
8
|
import routes, {createHref} from '../../../routes';
|
8
|
-
import {selectVDisksForPDisk} from '../../../store/reducers/storage/selectors';
|
9
9
|
import {TPDiskStateInfo, TPDiskState} from '../../../types/api/pdisk';
|
10
10
|
import {stringifyVdiskId} from '../../../utils/dataFormatters/dataFormatters';
|
11
|
-
import {useTypedSelector} from '../../../utils/hooks';
|
12
11
|
import {getPDiskType} from '../../../utils/pdisk';
|
13
12
|
import {isFullVDiskData} from '../../../utils/storage';
|
14
13
|
|
@@ -44,6 +43,7 @@ const stateSeverity = {
|
|
44
43
|
interface PDiskProps {
|
45
44
|
nodeId: number;
|
46
45
|
data?: TPDiskStateInfo;
|
46
|
+
vDisks?: TVDiskStateInfo[];
|
47
47
|
}
|
48
48
|
|
49
49
|
const isSeverityKey = (key?: TPDiskState): key is keyof typeof stateSeverity =>
|
@@ -53,12 +53,10 @@ const getStateSeverity = (pDiskState?: TPDiskState) => {
|
|
53
53
|
return isSeverityKey(pDiskState) ? stateSeverity[pDiskState] : NOT_AVAILABLE_SEVERITY;
|
54
54
|
};
|
55
55
|
|
56
|
-
export const PDisk = ({nodeId, data: rawData = {}}: PDiskProps) => {
|
56
|
+
export const PDisk = ({nodeId, data: rawData = {}, vDisks}: PDiskProps) => {
|
57
57
|
// NodeId in data is required for the popup
|
58
58
|
const data = useMemo(() => ({...rawData, NodeId: nodeId}), [rawData, nodeId]);
|
59
59
|
|
60
|
-
const vdisks = useTypedSelector((state) => selectVDisksForPDisk(state, nodeId, data.PDiskId));
|
61
|
-
|
62
60
|
const [severity, setSeverity] = useState(getStateSeverity(data.State));
|
63
61
|
const [isPopupVisible, setIsPopupVisible] = useState(false);
|
64
62
|
|
@@ -100,13 +98,13 @@ export const PDisk = ({nodeId, data: rawData = {}}: PDiskProps) => {
|
|
100
98
|
};
|
101
99
|
|
102
100
|
const renderVDisks = () => {
|
103
|
-
if (!
|
101
|
+
if (!vDisks?.length) {
|
104
102
|
return null;
|
105
103
|
}
|
106
104
|
|
107
105
|
return (
|
108
106
|
<div className={b('vdisks')}>
|
109
|
-
{
|
107
|
+
{vDisks.map((vdisk) => {
|
110
108
|
const donors = vdisk.Donors;
|
111
109
|
|
112
110
|
return (
|