ydb-embedded-ui 2.1.0 → 2.2.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 +28 -0
- package/dist/assets/icons/update-arrow.svg +6 -0
- package/dist/components/EntityStatus/EntityStatus.js +16 -14
- package/dist/components/EntityStatus/EntityStatus.scss +14 -5
- package/dist/components/ShortyString/ShortyString.tsx +21 -8
- package/dist/components/ShortyString/i18n/en.json +10 -0
- package/dist/components/ShortyString/i18n/index.ts +11 -0
- package/dist/components/ShortyString/i18n/ru.json +10 -0
- package/dist/containers/Cluster/Cluster.tsx +3 -3
- package/dist/containers/Nodes/Nodes.js +5 -6
- package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.scss +2 -2
- package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.tsx +15 -7
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.scss +11 -4
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.tsx +18 -21
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuePreview/IssuePreview.tsx +8 -7
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesList/IssuesList.tsx +14 -21
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueViewer.scss +21 -15
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssuesViewer.js +52 -86
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Preview/Preview.tsx +17 -23
- package/dist/containers/Tenant/Diagnostics/Healthcheck/i18n/en.json +5 -9
- package/dist/containers/Tenant/Diagnostics/Healthcheck/i18n/ru.json +5 -9
- package/dist/containers/Tenant/Tenant.tsx +2 -2
- package/dist/containers/Tenants/Tenants.js +6 -7
- package/package.json +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.2.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.1.0...v2.2.0) (2022-10-14)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **Healthcheck:** rework issues list in modal ([e7cb0df](https://github.com/ydb-platform/ydb-embedded-ui/commit/e7cb0df58e22c8c9cd25aae83b78be4808e9ba81))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **EntityStatus:** enable component to left trim links ([fbc6c51](https://github.com/ydb-platform/ydb-embedded-ui/commit/fbc6c51f9fbea3c1a7f5f70cb542971a41f4d8b3))
|
|
14
|
+
* fix pre-commit prettier linting and add json linting ([#189](https://github.com/ydb-platform/ydb-embedded-ui/issues/189)) ([047415d](https://github.com/ydb-platform/ydb-embedded-ui/commit/047415d2d69ecf4a2d99f0092b9e6735bd8efbc0))
|
|
15
|
+
* **Healthcheck:** delete unneeded i18n translations ([0c6de90](https://github.com/ydb-platform/ydb-embedded-ui/commit/0c6de9031607e4cde1387387393a9cfc9e1e2b8f))
|
|
16
|
+
* **Healthcheck:** enable update button in modal to fetch data ([de0b06e](https://github.com/ydb-platform/ydb-embedded-ui/commit/de0b06e7f2d3536df1b3896cbf86a947b2e7a291))
|
|
17
|
+
* **Healthcheck:** fix layout shift on scrollbar appearance ([ccdde6e](https://github.com/ydb-platform/ydb-embedded-ui/commit/ccdde6e065abbdb1c22a2c3bdd17e63f706d0f77))
|
|
18
|
+
* **Healthcheck:** fix styles for long issues trees ([32f1a8d](https://github.com/ydb-platform/ydb-embedded-ui/commit/32f1a8db58d9f84073327b92dcd80a5b4626a526))
|
|
19
|
+
* **Healthcheck:** fix variable typo ([0f0e056](https://github.com/ydb-platform/ydb-embedded-ui/commit/0f0e056576b9ec18fc3ce574d3742d55e5da6e35))
|
|
20
|
+
* **Healthcheck:** full check status in a preview ([bc0b51e](https://github.com/ydb-platform/ydb-embedded-ui/commit/bc0b51eedd4ff3b4ae1650946832f463a6703c12))
|
|
21
|
+
* **Healthcheck:** make modal show only one first level issue ([cdc95a7](https://github.com/ydb-platform/ydb-embedded-ui/commit/cdc95a7412c1266d990df7e2807630a8f4c88780))
|
|
22
|
+
* **Healthcheck:** redesign healthcheck header ([867f57a](https://github.com/ydb-platform/ydb-embedded-ui/commit/867f57aed84b7b72c22a816c6ac02387490ff495))
|
|
23
|
+
* **Healthcheck:** replace update button with icon ([709a994](https://github.com/ydb-platform/ydb-embedded-ui/commit/709a994544f068db1b0fe09009ecb4d8db46fc38))
|
|
24
|
+
* **Healthcheck:** update styles to be closer to the design ([aa1083d](https://github.com/ydb-platform/ydb-embedded-ui/commit/aa1083d299e24590336eeb3d913a9c53fd77bad6))
|
|
25
|
+
* **Nodes:** case insensitive search ([11d2c98](https://github.com/ydb-platform/ydb-embedded-ui/commit/11d2c985e0c30bb74ed07e22273d8b3459b54c89))
|
|
26
|
+
* **QueryEditor:** smarter error message trim ([8632948](https://github.com/ydb-platform/ydb-embedded-ui/commit/863294828090dc8eb2595884283d0996156c3785))
|
|
27
|
+
* **Tenants:** case insensitive search ([0ad93f5](https://github.com/ydb-platform/ydb-embedded-ui/commit/0ad93f57dcbba7d9746be54a4ba7b76ab4d45108))
|
|
28
|
+
* **Tenants:** fix filtering by ControlPlane name ([4941c82](https://github.com/ydb-platform/ydb-embedded-ui/commit/4941c821cdbb7c5d0da26a3b0d5c00d8979401c0))
|
|
29
|
+
* **Tenants:** left trim db names in db list ([81bf0fa](https://github.com/ydb-platform/ydb-embedded-ui/commit/81bf0fafe901d3601dc04fdf71939e914493ff1c))
|
|
30
|
+
|
|
3
31
|
## [2.1.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.0.0...v2.1.0) (2022-10-04)
|
|
4
32
|
|
|
5
33
|
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M21 12C21 16.9706 16.9706 21 12 21C9.5 21 6.5 19 5 17" stroke='currentColor' stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
3
|
+
<path d="M5 21L5 17L9 17" stroke='currentColor' stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
4
|
+
<path d="M3 12C3 7.02944 7.02944 3 12 3C14.5 3 17.5 5 19 7" stroke='currentColor' stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
5
|
+
<path d="M19 3L19 7L15 7" stroke='currentColor' stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
6
|
+
</svg>
|
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import cn from 'bem-cn-lite';
|
|
4
4
|
import {Link} from 'react-router-dom';
|
|
5
|
-
import {ClipboardButton, Link as
|
|
5
|
+
import {ClipboardButton, Link as UIKitLink, Button, Icon} from '@gravity-ui/uikit';
|
|
6
6
|
|
|
7
7
|
import circleInfoIcon from '../../assets/icons/circle-info.svg';
|
|
8
8
|
import circleExclamationIcon from '../../assets/icons/circle-exclamation.svg';
|
|
@@ -35,6 +35,7 @@ class EntityStatus extends React.Component {
|
|
|
35
35
|
externalLink: PropTypes.bool,
|
|
36
36
|
className: PropTypes.string,
|
|
37
37
|
mode: PropTypes.oneOf(['color', 'icons']),
|
|
38
|
+
withLeftTrim: PropTypes.bool,
|
|
38
39
|
};
|
|
39
40
|
|
|
40
41
|
static defaultProps = {
|
|
@@ -45,6 +46,7 @@ class EntityStatus extends React.Component {
|
|
|
45
46
|
showStatus: true,
|
|
46
47
|
externalLink: false,
|
|
47
48
|
mode: 'color',
|
|
49
|
+
withLeftTrim: false,
|
|
48
50
|
};
|
|
49
51
|
renderIcon() {
|
|
50
52
|
const {status, size, showStatus, mode} = this.props;
|
|
@@ -56,12 +58,7 @@ class EntityStatus extends React.Component {
|
|
|
56
58
|
const modifiers = {state: status.toLowerCase(), size};
|
|
57
59
|
|
|
58
60
|
if (mode === 'icons' && icons[status]) {
|
|
59
|
-
return (
|
|
60
|
-
<Icon
|
|
61
|
-
className={b('status-icon', modifiers)}
|
|
62
|
-
data={icons[status]}
|
|
63
|
-
/>
|
|
64
|
-
);
|
|
61
|
+
return <Icon className={b('status-icon', modifiers)} data={icons[status]} />;
|
|
65
62
|
}
|
|
66
63
|
|
|
67
64
|
return <div className={b('status-color', modifiers)} />;
|
|
@@ -70,21 +67,25 @@ class EntityStatus extends React.Component {
|
|
|
70
67
|
const {iconPath} = this.props;
|
|
71
68
|
|
|
72
69
|
return (
|
|
73
|
-
<
|
|
70
|
+
<UIKitLink target="_blank" href={iconPath}>
|
|
74
71
|
{this.renderIcon()}
|
|
75
|
-
</
|
|
72
|
+
</UIKitLink>
|
|
76
73
|
);
|
|
77
74
|
}
|
|
78
75
|
renderLink() {
|
|
79
76
|
const {externalLink, name, path, onNameMouseEnter, onNameMouseLeave} = this.props;
|
|
80
77
|
|
|
81
78
|
if (externalLink) {
|
|
82
|
-
return
|
|
79
|
+
return (
|
|
80
|
+
<UIKitLink className={b('name')} href={path}>
|
|
81
|
+
{name}
|
|
82
|
+
</UIKitLink>
|
|
83
|
+
);
|
|
83
84
|
}
|
|
84
85
|
|
|
85
86
|
return path ? (
|
|
86
87
|
<Link
|
|
87
|
-
|
|
88
|
+
className={b('name')}
|
|
88
89
|
to={path}
|
|
89
90
|
onMouseEnter={onNameMouseEnter}
|
|
90
91
|
onMouseLeave={onNameMouseLeave}
|
|
@@ -95,7 +96,6 @@ class EntityStatus extends React.Component {
|
|
|
95
96
|
name && (
|
|
96
97
|
<span
|
|
97
98
|
className={b('name')}
|
|
98
|
-
title={name}
|
|
99
99
|
onMouseEnter={onNameMouseEnter}
|
|
100
100
|
onMouseLeave={onNameMouseLeave}
|
|
101
101
|
>
|
|
@@ -108,14 +108,16 @@ class EntityStatus extends React.Component {
|
|
|
108
108
|
const {name, label, iconPath, hasClipboardButton, className} = this.props;
|
|
109
109
|
|
|
110
110
|
return (
|
|
111
|
-
<div className={b(null, className)}>
|
|
111
|
+
<div className={b(null, className)} title={name}>
|
|
112
112
|
{iconPath ? this.renderStatusLink() : this.renderIcon()}
|
|
113
113
|
{label && (
|
|
114
114
|
<span title={label} className={b('label')}>
|
|
115
115
|
{label}
|
|
116
116
|
</span>
|
|
117
117
|
)}
|
|
118
|
-
{this.
|
|
118
|
+
<span className={b('link', {'with-left-trim': this.props.withLeftTrim})}>
|
|
119
|
+
{this.renderLink()}
|
|
120
|
+
</span>
|
|
119
121
|
{hasClipboardButton && (
|
|
120
122
|
<Button
|
|
121
123
|
component="span"
|
|
@@ -31,11 +31,7 @@
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
a {
|
|
34
|
-
overflow: hidden;
|
|
35
|
-
|
|
36
|
-
white-space: nowrap;
|
|
37
34
|
text-decoration: none;
|
|
38
|
-
text-overflow: ellipsis;
|
|
39
35
|
|
|
40
36
|
color: var(--yc-color-text-link);
|
|
41
37
|
}
|
|
@@ -53,12 +49,25 @@
|
|
|
53
49
|
color: var(--yc-color-text-complementary);
|
|
54
50
|
}
|
|
55
51
|
|
|
56
|
-
&
|
|
52
|
+
&__link {
|
|
53
|
+
overflow: hidden;
|
|
54
|
+
|
|
57
55
|
white-space: nowrap;
|
|
56
|
+
text-overflow: ellipsis;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
&__link_with-left-trim {
|
|
60
|
+
direction: rtl;
|
|
61
|
+
|
|
62
|
+
.entity-status__name {
|
|
63
|
+
unicode-bidi: plaintext;
|
|
64
|
+
}
|
|
58
65
|
}
|
|
59
66
|
|
|
60
67
|
&__status-color,
|
|
61
68
|
&__status-icon {
|
|
69
|
+
flex-shrink: 0;
|
|
70
|
+
|
|
62
71
|
margin-right: 8px;
|
|
63
72
|
|
|
64
73
|
border-radius: 3px;
|
|
@@ -3,6 +3,7 @@ import cn from 'bem-cn-lite';
|
|
|
3
3
|
|
|
4
4
|
import {Link} from '@gravity-ui/uikit';
|
|
5
5
|
|
|
6
|
+
import i18n from './i18n';
|
|
6
7
|
import './ShortyString.scss';
|
|
7
8
|
|
|
8
9
|
const block = cn('kv-shorty-string');
|
|
@@ -10,6 +11,8 @@ const block = cn('kv-shorty-string');
|
|
|
10
11
|
type Props = {
|
|
11
12
|
value?: string;
|
|
12
13
|
limit?: number;
|
|
14
|
+
/** in strict mode the text always trims at the limit, otherwise it is allowed to overflow a little */
|
|
15
|
+
strict?: boolean;
|
|
13
16
|
displayLength?: boolean;
|
|
14
17
|
render?: (value: string) => React.ReactNode;
|
|
15
18
|
onToggle?: () => void;
|
|
@@ -20,19 +23,29 @@ type Props = {
|
|
|
20
23
|
export default function ShortyString({
|
|
21
24
|
value = '',
|
|
22
25
|
limit = 200,
|
|
26
|
+
strict = false,
|
|
23
27
|
displayLength = true,
|
|
24
28
|
render = (v: string) => v,
|
|
25
29
|
onToggle,
|
|
26
|
-
expandLabel = '
|
|
27
|
-
collapseLabel = '
|
|
30
|
+
expandLabel = i18n('default_expand_label'),
|
|
31
|
+
collapseLabel = i18n('default_collapse_label'),
|
|
28
32
|
}: Props) {
|
|
29
33
|
const [expanded, setExpanded] = React.useState(false);
|
|
30
|
-
const hasToggle = value.length > limit;
|
|
31
|
-
const length =
|
|
32
|
-
displayLength && !expanded ? `(${value.length} symbols)` : undefined;
|
|
33
34
|
|
|
34
|
-
const
|
|
35
|
-
const
|
|
35
|
+
const toggleLabelAction = expanded ? collapseLabel : expandLabel;
|
|
36
|
+
const toggleLabelSymbolsCount = displayLength && !expanded
|
|
37
|
+
? i18n('chars_count', {count: value.length})
|
|
38
|
+
: '';
|
|
39
|
+
const toggleLabel = toggleLabelAction + toggleLabelSymbolsCount;
|
|
40
|
+
|
|
41
|
+
// showing toogle button with a label that is longer than the hidden part is pointless,
|
|
42
|
+
// hence compare to limit + length in the not-strict mode
|
|
43
|
+
const hasToggle = value.length > limit + (strict ? 0 : toggleLabel.length);
|
|
44
|
+
|
|
45
|
+
const text = expanded || !hasToggle
|
|
46
|
+
? value
|
|
47
|
+
: value.slice(0, limit - 4) + '\u00a0...';
|
|
48
|
+
|
|
36
49
|
return (
|
|
37
50
|
<div className={block()}>
|
|
38
51
|
{render(text)}
|
|
@@ -45,7 +58,7 @@ export default function ShortyString({
|
|
|
45
58
|
onToggle?.();
|
|
46
59
|
}}
|
|
47
60
|
>
|
|
48
|
-
{
|
|
61
|
+
{toggleLabel}
|
|
49
62
|
</Link>
|
|
50
63
|
) : null}
|
|
51
64
|
</div>
|
|
@@ -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-shorty-string';
|
|
7
|
+
|
|
8
|
+
i18n.registerKeyset(Lang.En, COMPONENT, en);
|
|
9
|
+
i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
|
|
10
|
+
|
|
11
|
+
export default i18n.keyset(COMPONENT);
|
|
@@ -14,9 +14,9 @@ import ClusterInfo from '../../components/ClusterInfo/ClusterInfo';
|
|
|
14
14
|
const b = cn('cluster');
|
|
15
15
|
|
|
16
16
|
interface ClusterProps {
|
|
17
|
-
additionalClusterInfo
|
|
18
|
-
additionalTenantsInfo
|
|
19
|
-
additionalNodesInfo
|
|
17
|
+
additionalClusterInfo?: any;
|
|
18
|
+
additionalTenantsInfo?: any;
|
|
19
|
+
additionalNodesInfo?: any;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
function Cluster(props: ClusterProps) {
|
|
@@ -114,11 +114,10 @@ class Nodes extends React.Component {
|
|
|
114
114
|
});
|
|
115
115
|
|
|
116
116
|
let preparedNodes = searchQuery
|
|
117
|
-
? nodes.filter((node) =>
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
)
|
|
117
|
+
? nodes.filter((node) => {
|
|
118
|
+
const re = new RegExp(searchQuery, 'i');
|
|
119
|
+
return node.Host ? re.test(node.Host) || re.test(String(node.NodeId)) : true;
|
|
120
|
+
})
|
|
122
121
|
: nodes;
|
|
123
122
|
preparedNodes = preparedNodes.map((node) => ({
|
|
124
123
|
...node,
|
|
@@ -143,7 +142,7 @@ class Nodes extends React.Component {
|
|
|
143
142
|
columnId: 'NodeId',
|
|
144
143
|
order: DataTable.ASCENDING,
|
|
145
144
|
}}
|
|
146
|
-
emptyDataMessage=
|
|
145
|
+
emptyDataMessage="No such nodes"
|
|
147
146
|
/>
|
|
148
147
|
</div>
|
|
149
148
|
</div>
|
|
@@ -26,11 +26,12 @@ const b = cn('kv-detailed-overview');
|
|
|
26
26
|
function DetailedOverview(props: DetailedOverviewProps) {
|
|
27
27
|
const [isModalVisible, setIsModalVisible] = useState(false);
|
|
28
28
|
|
|
29
|
-
const
|
|
30
|
-
currentSchemaPath,
|
|
31
|
-
} = useSelector((state: any) => state.schema);
|
|
29
|
+
const [expandedIssueId, setExpandedIssueId] = useState<string>();
|
|
32
30
|
|
|
33
|
-
const
|
|
31
|
+
const {currentSchemaPath} = useSelector((state: any) => state.schema);
|
|
32
|
+
|
|
33
|
+
const openModalHandler = (id: string) => {
|
|
34
|
+
setExpandedIssueId(id);
|
|
34
35
|
setIsModalVisible(true);
|
|
35
36
|
};
|
|
36
37
|
|
|
@@ -41,12 +42,16 @@ function DetailedOverview(props: DetailedOverviewProps) {
|
|
|
41
42
|
const renderModal = () => {
|
|
42
43
|
return (
|
|
43
44
|
<Modal open={isModalVisible} onClose={closeModalHandler} className={b('modal')}>
|
|
44
|
-
<Healthcheck
|
|
45
|
+
<Healthcheck
|
|
46
|
+
tenant={props.tenantName}
|
|
47
|
+
fetchData={false}
|
|
48
|
+
expandedIssueId={expandedIssueId}
|
|
49
|
+
/>
|
|
45
50
|
<Button
|
|
46
51
|
className={b('close-modal-button')}
|
|
47
52
|
onClick={closeModalHandler}
|
|
48
53
|
view="flat-secondary"
|
|
49
|
-
title=
|
|
54
|
+
title="Close"
|
|
50
55
|
>
|
|
51
56
|
<Icon name="close" viewBox={'0 0 16 16 '} height={20} width={20} />
|
|
52
57
|
</Button>
|
|
@@ -62,7 +67,10 @@ function DetailedOverview(props: DetailedOverviewProps) {
|
|
|
62
67
|
{isTenant ? (
|
|
63
68
|
<>
|
|
64
69
|
<div className={b('section')}>
|
|
65
|
-
<TenantOverview
|
|
70
|
+
<TenantOverview
|
|
71
|
+
tenantName={tenantName}
|
|
72
|
+
additionalTenantInfo={additionalTenantInfo}
|
|
73
|
+
/>
|
|
66
74
|
</div>
|
|
67
75
|
<div className={b('section')}>
|
|
68
76
|
<Healthcheck
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
@use '../DetailedOverview/DetailedOverview.scss' as detailedOverview;
|
|
2
2
|
@import '../../../../styles/mixins.scss';
|
|
3
|
+
@import '@gravity-ui/uikit/styles/mixins.scss';
|
|
3
4
|
|
|
4
5
|
.healthcheck {
|
|
6
|
+
// Since most of the inner containers have fixed width, we can set fixed width here as well
|
|
7
|
+
// Thus we will get rid of unneeded layout shift when scrollbar appear
|
|
8
|
+
min-width: 885px;
|
|
9
|
+
|
|
5
10
|
&__issues-list {
|
|
6
11
|
padding: 25px 20px 20px;
|
|
7
12
|
}
|
|
@@ -27,19 +32,21 @@
|
|
|
27
32
|
padding: 15px 0;
|
|
28
33
|
}
|
|
29
34
|
|
|
30
|
-
&
|
|
35
|
+
&__issues-list-header {
|
|
31
36
|
display: flex;
|
|
32
37
|
align-items: center;
|
|
33
38
|
|
|
34
39
|
margin-bottom: 20px;
|
|
35
40
|
}
|
|
36
41
|
|
|
37
|
-
&
|
|
42
|
+
&__issues-list-header-title {
|
|
38
43
|
margin: 0 10px 0 0;
|
|
44
|
+
|
|
45
|
+
@include text-header-1();
|
|
39
46
|
}
|
|
40
47
|
|
|
41
|
-
&
|
|
42
|
-
margin-left:
|
|
48
|
+
&__issues-list-header-update {
|
|
49
|
+
margin-left: 10px;
|
|
43
50
|
}
|
|
44
51
|
|
|
45
52
|
&__status-wrapper {
|
|
@@ -17,18 +17,14 @@ interface HealthcheckProps {
|
|
|
17
17
|
tenant: string;
|
|
18
18
|
preview?: boolean;
|
|
19
19
|
fetchData?: boolean;
|
|
20
|
-
|
|
20
|
+
expandedIssueId?: string;
|
|
21
|
+
showMoreHandler?: (id: string) => void;
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
const b = cn('healthcheck');
|
|
24
25
|
|
|
25
26
|
export const Healthcheck = (props: HealthcheckProps) => {
|
|
26
|
-
const {
|
|
27
|
-
tenant,
|
|
28
|
-
preview,
|
|
29
|
-
fetchData = true,
|
|
30
|
-
showMoreHandler,
|
|
31
|
-
} = props;
|
|
27
|
+
const {tenant, preview, fetchData = true, showMoreHandler, expandedIssueId} = props;
|
|
32
28
|
|
|
33
29
|
const dispatch = useDispatch();
|
|
34
30
|
|
|
@@ -36,12 +32,18 @@ export const Healthcheck = (props: HealthcheckProps) => {
|
|
|
36
32
|
const {autorefresh} = useSelector((state: any) => state.schema);
|
|
37
33
|
|
|
38
34
|
const fetchHealthcheck = useCallback(() => {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
35
|
+
dispatch(getHealthcheckInfo(tenant));
|
|
36
|
+
}, [dispatch, tenant]);
|
|
37
|
+
|
|
38
|
+
useAutofetcher(
|
|
39
|
+
() => {
|
|
40
|
+
if (fetchData) {
|
|
41
|
+
fetchHealthcheck();
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
[fetchData, fetchHealthcheck],
|
|
45
|
+
autorefresh,
|
|
46
|
+
);
|
|
45
47
|
|
|
46
48
|
const renderContent = () => {
|
|
47
49
|
if (error) {
|
|
@@ -67,20 +69,15 @@ export const Healthcheck = (props: HealthcheckProps) => {
|
|
|
67
69
|
) : (
|
|
68
70
|
<IssuesList
|
|
69
71
|
data={data}
|
|
72
|
+
expandedIssueId={expandedIssueId}
|
|
70
73
|
loading={loading}
|
|
71
74
|
onUpdate={fetchHealthcheck}
|
|
72
75
|
/>
|
|
73
76
|
);
|
|
74
77
|
}
|
|
75
78
|
|
|
76
|
-
return (
|
|
77
|
-
<div className="error">{i18n('no-data')}</div>
|
|
78
|
-
);
|
|
79
|
+
return <div className="error">{i18n('no-data')}</div>;
|
|
79
80
|
};
|
|
80
81
|
|
|
81
|
-
return (
|
|
82
|
-
<div className={b()}>
|
|
83
|
-
{renderContent()}
|
|
84
|
-
</div>
|
|
85
|
-
);
|
|
82
|
+
return <div className={b()}>{renderContent()}</div>;
|
|
86
83
|
};
|
|
@@ -11,14 +11,11 @@ const b = cn('healthcheck');
|
|
|
11
11
|
|
|
12
12
|
interface IssuePreviewProps {
|
|
13
13
|
data?: IssueLog;
|
|
14
|
-
onShowMore?:
|
|
14
|
+
onShowMore?: (id: string) => void;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export const IssuePreview = (props: IssuePreviewProps) => {
|
|
18
|
-
const {
|
|
19
|
-
data,
|
|
20
|
-
onShowMore,
|
|
21
|
-
} = props;
|
|
18
|
+
const {data, onShowMore} = props;
|
|
22
19
|
|
|
23
20
|
if (!data) {
|
|
24
21
|
return null;
|
|
@@ -27,8 +24,12 @@ export const IssuePreview = (props: IssuePreviewProps) => {
|
|
|
27
24
|
return (
|
|
28
25
|
<div className={b('issue-preview')}>
|
|
29
26
|
<EntityStatus mode="icons" status={data.status} name={data.type} />
|
|
30
|
-
<Text as="div" color="secondary" variant="body-2">
|
|
31
|
-
|
|
27
|
+
<Text as="div" color="secondary" variant="body-2">
|
|
28
|
+
{data.message}
|
|
29
|
+
</Text>
|
|
30
|
+
<Link onClick={() => onShowMore && onShowMore(data.id)}>
|
|
31
|
+
{i18n('label.show-details')}
|
|
32
|
+
</Link>
|
|
32
33
|
</div>
|
|
33
34
|
);
|
|
34
35
|
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import cn from 'bem-cn-lite';
|
|
2
2
|
|
|
3
|
-
import {Button} from '@gravity-ui/uikit';
|
|
3
|
+
import {Button, Icon} from '@gravity-ui/uikit';
|
|
4
|
+
|
|
5
|
+
import updateArrow from '../../../../../assets/icons/update-arrow.svg';
|
|
4
6
|
|
|
5
7
|
import type {IHealthCheck} from '../../../../../types/store/healthcheck';
|
|
6
8
|
|
|
@@ -13,32 +15,24 @@ const b = cn('healthcheck');
|
|
|
13
15
|
interface IssuesListProps {
|
|
14
16
|
data?: IHealthCheck;
|
|
15
17
|
loading?: boolean;
|
|
18
|
+
expandedIssueId?: string;
|
|
16
19
|
onUpdate: VoidFunction;
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
export const IssuesList = (props: IssuesListProps) => {
|
|
20
|
-
const {
|
|
21
|
-
data,
|
|
22
|
-
loading,
|
|
23
|
-
onUpdate,
|
|
24
|
-
} = props;
|
|
23
|
+
const {data, loading, onUpdate, expandedIssueId} = props;
|
|
25
24
|
|
|
26
25
|
if (!data) {
|
|
27
26
|
return null;
|
|
28
27
|
}
|
|
29
28
|
|
|
30
|
-
const
|
|
31
|
-
const {self_check_result: selfCheckResult} = data;
|
|
32
|
-
const modifier = selfCheckResult.toLowerCase();
|
|
33
|
-
|
|
29
|
+
const renderHealthcheckHeader = () => {
|
|
34
30
|
return (
|
|
35
|
-
<div className={b('
|
|
36
|
-
<h3 className={b('
|
|
37
|
-
<div className={b('
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
<Button size="s" onClick={onUpdate} loading={loading}>
|
|
41
|
-
{i18n('label.update')}
|
|
31
|
+
<div className={b('issues-list-header')}>
|
|
32
|
+
<h3 className={b('issues-list-header-title')}>{i18n('title.healthcheck')}</h3>
|
|
33
|
+
<div className={b('issues-list-header-update')}>
|
|
34
|
+
<Button size="s" onClick={onUpdate} loading={loading} view="flat-secondary">
|
|
35
|
+
<Icon data={updateArrow} height={20} width={20} />
|
|
42
36
|
</Button>
|
|
43
37
|
</div>
|
|
44
38
|
</div>
|
|
@@ -54,15 +48,14 @@ export const IssuesList = (props: IssuesListProps) => {
|
|
|
54
48
|
|
|
55
49
|
return (
|
|
56
50
|
<div className={b('issues')}>
|
|
57
|
-
<
|
|
58
|
-
<IssuesViewer issues={issueLog} />
|
|
51
|
+
<IssuesViewer issues={issueLog} expandedIssueId={expandedIssueId} />
|
|
59
52
|
</div>
|
|
60
53
|
);
|
|
61
|
-
}
|
|
54
|
+
};
|
|
62
55
|
|
|
63
56
|
return (
|
|
64
57
|
<div className={b('issues-list')}>
|
|
65
|
-
{
|
|
58
|
+
{renderHealthcheckHeader()}
|
|
66
59
|
{renderHealthcheckIssues()}
|
|
67
60
|
</div>
|
|
68
61
|
);
|
|
@@ -2,30 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
.issue {
|
|
4
4
|
display: flex;
|
|
5
|
+
justify-content: space-between;
|
|
5
6
|
align-items: center;
|
|
6
7
|
|
|
7
8
|
height: 40px;
|
|
8
9
|
|
|
9
10
|
cursor: pointer;
|
|
10
11
|
|
|
11
|
-
&_active {
|
|
12
|
-
border-radius: 4px;
|
|
13
|
-
background: var(--yc-color-base-info);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
12
|
&__field {
|
|
17
|
-
|
|
13
|
+
display: flex;
|
|
14
|
+
overflow: hidden;
|
|
18
15
|
|
|
19
16
|
&_status {
|
|
20
17
|
display: flex;
|
|
21
18
|
|
|
22
|
-
min-width: 470px;
|
|
23
|
-
|
|
24
19
|
white-space: nowrap;
|
|
25
20
|
}
|
|
26
|
-
&_type {
|
|
27
|
-
min-width: 160px;
|
|
28
|
-
}
|
|
29
21
|
&_additional {
|
|
30
22
|
width: max-content;
|
|
31
23
|
|
|
@@ -39,6 +31,7 @@
|
|
|
39
31
|
}
|
|
40
32
|
&_message {
|
|
41
33
|
overflow: hidden;
|
|
34
|
+
flex-shrink: 0;
|
|
42
35
|
|
|
43
36
|
width: 300px;
|
|
44
37
|
|
|
@@ -96,8 +89,10 @@
|
|
|
96
89
|
.issue-viewer {
|
|
97
90
|
display: flex;
|
|
98
91
|
|
|
92
|
+
width: 820px;
|
|
93
|
+
|
|
99
94
|
&__tree {
|
|
100
|
-
|
|
95
|
+
width: 100%;
|
|
101
96
|
}
|
|
102
97
|
|
|
103
98
|
&__checkbox {
|
|
@@ -106,11 +101,10 @@
|
|
|
106
101
|
|
|
107
102
|
&__info-panel {
|
|
108
103
|
position: sticky;
|
|
109
|
-
top: 20px;
|
|
110
104
|
|
|
111
|
-
width: 500px;
|
|
112
105
|
height: 100%;
|
|
113
|
-
|
|
106
|
+
margin: 11px 0;
|
|
107
|
+
padding: 8px 20px;
|
|
114
108
|
|
|
115
109
|
border-radius: 4px;
|
|
116
110
|
background: var(--yc-color-base-generic);
|
|
@@ -152,6 +146,8 @@
|
|
|
152
146
|
}
|
|
153
147
|
|
|
154
148
|
.ydb-tree-view {
|
|
149
|
+
$calculated-margin: calc(24px * var(--ydb-tree-view-level));
|
|
150
|
+
|
|
155
151
|
&__item {
|
|
156
152
|
height: 40px;
|
|
157
153
|
}
|
|
@@ -160,5 +156,15 @@
|
|
|
160
156
|
width: 40px;
|
|
161
157
|
height: 40px;
|
|
162
158
|
}
|
|
159
|
+
|
|
160
|
+
// Without !important this class does not have enough weight compared to styles set in TreeView
|
|
161
|
+
.ydb-tree-view__item {
|
|
162
|
+
margin-left: $calculated-margin !important;
|
|
163
|
+
padding-left: 0 !important;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.issue-viewer__info-panel {
|
|
167
|
+
margin-left: $calculated-margin;
|
|
168
|
+
}
|
|
163
169
|
}
|
|
164
170
|
}
|
|
@@ -13,62 +13,26 @@ import EntityStatus from '../../../../../components/EntityStatus/EntityStatus';
|
|
|
13
13
|
|
|
14
14
|
import './IssueViewer.scss';
|
|
15
15
|
|
|
16
|
-
// const indicatorBlock = cn('indicator');
|
|
17
|
-
|
|
18
|
-
// const IssueStatus = ({status, name}) => {
|
|
19
|
-
// const modifier = status && status.toLowerCase();
|
|
20
|
-
|
|
21
|
-
// return (
|
|
22
|
-
// <React.Fragment>
|
|
23
|
-
// <div className={indicatorBlock({[modifier]: true})} />
|
|
24
|
-
// {name}
|
|
25
|
-
// </React.Fragment>
|
|
26
|
-
// );
|
|
27
|
-
// };
|
|
28
|
-
|
|
29
16
|
const issueBlock = cn('issue');
|
|
30
17
|
|
|
31
|
-
const IssueRow = ({data,
|
|
32
|
-
|
|
33
|
-
const {id, status, message, type, reasonsItems, ...rest} = data;
|
|
34
|
-
|
|
35
|
-
useEffect(() => {
|
|
36
|
-
if (active) {
|
|
37
|
-
setInfoForActive(rest);
|
|
38
|
-
}
|
|
39
|
-
}, [active, setInfoForActive]);
|
|
18
|
+
const IssueRow = ({data, onClick}) => {
|
|
19
|
+
const {status, message, type} = data;
|
|
40
20
|
|
|
41
21
|
return (
|
|
42
|
-
<div className={issueBlock(
|
|
22
|
+
<div className={issueBlock()} onClick={onClick}>
|
|
43
23
|
<div className={issueBlock('field', {status: true})}>
|
|
44
|
-
<EntityStatus status={status} name={
|
|
45
|
-
{/* <IssueStatus status={status} name={id} /> */}
|
|
46
|
-
</div>
|
|
47
|
-
<div
|
|
48
|
-
className={issueBlock('field', {message: true})}
|
|
49
|
-
style={{marginLeft: -treeLevel * 24 + 'px'}}
|
|
50
|
-
>
|
|
51
|
-
{message}
|
|
24
|
+
<EntityStatus mode="icons" status={status} name={type} />
|
|
52
25
|
</div>
|
|
53
|
-
<div className={issueBlock('field', {
|
|
26
|
+
<div className={issueBlock('field', {message: true})}>{message}</div>
|
|
54
27
|
</div>
|
|
55
28
|
);
|
|
56
29
|
};
|
|
57
30
|
|
|
58
31
|
const issueViewerBlock = cn('issue-viewer');
|
|
59
32
|
|
|
60
|
-
const IssuesViewer = ({issues}) => {
|
|
33
|
+
const IssuesViewer = ({issues, expandedIssueId}) => {
|
|
61
34
|
const [data, setData] = useState([]);
|
|
62
35
|
const [collapsedIssues, setCollapsedIssues] = useState({});
|
|
63
|
-
const [activeItem, setActiveItem] = useState();
|
|
64
|
-
const [infoData, setInfoData] = useState();
|
|
65
|
-
|
|
66
|
-
useEffect(() => {
|
|
67
|
-
if (!activeItem && data.length) {
|
|
68
|
-
const {id} = data[0];
|
|
69
|
-
setActiveItem(id);
|
|
70
|
-
}
|
|
71
|
-
}, [data]);
|
|
72
36
|
|
|
73
37
|
useEffect(() => {
|
|
74
38
|
const newData = getInvertedConsequencesTree({data: issues});
|
|
@@ -77,67 +41,69 @@ const IssuesViewer = ({issues}) => {
|
|
|
77
41
|
}, [issues]);
|
|
78
42
|
|
|
79
43
|
const renderTree = useCallback(
|
|
80
|
-
(data, childrenKey
|
|
44
|
+
(data, childrenKey) => {
|
|
81
45
|
return _.map(data, (item) => {
|
|
82
46
|
const {id} = item;
|
|
83
|
-
|
|
84
|
-
|
|
47
|
+
|
|
48
|
+
// eslint-disable-next-line no-unused-vars
|
|
49
|
+
const {status, message, type, reasonsItems, reason, level, ...rest} = item;
|
|
50
|
+
|
|
51
|
+
if (level === 1 && expandedIssueId && id !== expandedIssueId) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const isCollapsed =
|
|
56
|
+
typeof collapsedIssues[id] === 'undefined' || collapsedIssues[id];
|
|
57
|
+
|
|
58
|
+
const toggleCollapsed = () => {
|
|
59
|
+
setCollapsedIssues((collapsedIssues) => ({
|
|
60
|
+
...collapsedIssues,
|
|
61
|
+
[id]: !isCollapsed,
|
|
62
|
+
}));
|
|
63
|
+
};
|
|
85
64
|
|
|
86
65
|
return (
|
|
87
66
|
<TreeView
|
|
88
67
|
key={id}
|
|
89
|
-
name={
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
/>
|
|
96
|
-
}
|
|
97
|
-
collapsed={
|
|
98
|
-
typeof collapsedIssues[id] === 'undefined' || collapsedIssues[id]
|
|
99
|
-
}
|
|
100
|
-
hasArrow={hasArrow}
|
|
101
|
-
onClick={() => setActiveItem(id)}
|
|
102
|
-
onArrowClick={() => {
|
|
103
|
-
const newValue =
|
|
104
|
-
typeof collapsedIssues[id] === 'undefined'
|
|
105
|
-
? false
|
|
106
|
-
: !collapsedIssues[id];
|
|
107
|
-
const newCollapsedIssues = {...collapsedIssues, [id]: newValue};
|
|
108
|
-
setCollapsedIssues(newCollapsedIssues);
|
|
109
|
-
}}
|
|
68
|
+
name={<IssueRow data={item} />}
|
|
69
|
+
collapsed={isCollapsed}
|
|
70
|
+
hasArrow={true}
|
|
71
|
+
onClick={toggleCollapsed}
|
|
72
|
+
onArrowClick={toggleCollapsed}
|
|
73
|
+
level={level - 1}
|
|
110
74
|
>
|
|
111
|
-
{
|
|
75
|
+
{renderInfoPanel(rest)}
|
|
76
|
+
{renderTree(item[childrenKey], childrenKey)}
|
|
112
77
|
</TreeView>
|
|
113
78
|
);
|
|
114
79
|
});
|
|
115
80
|
},
|
|
116
|
-
[data, collapsedIssues
|
|
81
|
+
[data, collapsedIssues],
|
|
117
82
|
);
|
|
118
83
|
|
|
119
|
-
const renderInfoPanel = useCallback(
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
<
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
84
|
+
const renderInfoPanel = useCallback(
|
|
85
|
+
(info) => {
|
|
86
|
+
if (!info) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<div className={issueViewerBlock('info-panel')}>
|
|
92
|
+
<JSONTree
|
|
93
|
+
data={info}
|
|
94
|
+
search={false}
|
|
95
|
+
isExpanded={() => true}
|
|
96
|
+
className={issueViewerBlock('inspector')}
|
|
97
|
+
/>
|
|
98
|
+
</div>
|
|
99
|
+
);
|
|
100
|
+
},
|
|
101
|
+
[data],
|
|
102
|
+
);
|
|
136
103
|
|
|
137
104
|
return (
|
|
138
105
|
<div className={issueViewerBlock()}>
|
|
139
106
|
<div className={issueViewerBlock('tree')}>{renderTree(data, 'reasonsItems')}</div>
|
|
140
|
-
{renderInfoPanel()}
|
|
141
107
|
</div>
|
|
142
108
|
);
|
|
143
109
|
};
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {useMemo} from 'react';
|
|
2
2
|
import cn from 'bem-cn-lite';
|
|
3
3
|
|
|
4
|
-
import {Button} from '@gravity-ui/uikit';
|
|
4
|
+
import {Button, Icon} from '@gravity-ui/uikit';
|
|
5
|
+
|
|
6
|
+
import updateArrow from '../../../../../assets/icons/update-arrow.svg';
|
|
5
7
|
|
|
6
8
|
import {SelfCheckResult} from '../../../../../types/api/healthcheck';
|
|
7
9
|
import type {IHealthCheck} from '../../../../../types/store/healthcheck';
|
|
@@ -15,23 +17,21 @@ const b = cn('healthcheck');
|
|
|
15
17
|
interface PreviewProps {
|
|
16
18
|
data?: IHealthCheck;
|
|
17
19
|
loading?: boolean;
|
|
18
|
-
onShowMore?: VoidFunction;
|
|
19
20
|
onUpdate: VoidFunction;
|
|
21
|
+
onShowMore?: (id: string) => void;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
export const Preview = (props: PreviewProps) => {
|
|
23
|
-
const {
|
|
24
|
-
data,
|
|
25
|
-
loading,
|
|
26
|
-
onShowMore,
|
|
27
|
-
onUpdate,
|
|
28
|
-
} = props;
|
|
25
|
+
const {data, loading, onShowMore, onUpdate} = props;
|
|
29
26
|
|
|
30
27
|
const selfCheckResult = data?.self_check_result || SelfCheckResult.UNSPECIFIED;
|
|
31
28
|
const isStatusOK = selfCheckResult === SelfCheckResult.GOOD;
|
|
32
29
|
|
|
33
30
|
const issuesLog = data?.issue_log;
|
|
34
|
-
const firstLevelIssues = useMemo(
|
|
31
|
+
const firstLevelIssues = useMemo(
|
|
32
|
+
() => issuesLog?.filter(({level}) => level === 1),
|
|
33
|
+
[issuesLog],
|
|
34
|
+
);
|
|
35
35
|
|
|
36
36
|
if (!data) {
|
|
37
37
|
return null;
|
|
@@ -44,10 +44,10 @@ export const Preview = (props: PreviewProps) => {
|
|
|
44
44
|
<div className={b('status-wrapper')}>
|
|
45
45
|
<div className={b('preview-title')}>{i18n('title.healthcheck')}</div>
|
|
46
46
|
<div className={b('self-check-status-indicator', {[modifier]: true})}>
|
|
47
|
-
{
|
|
47
|
+
{selfCheckResult}
|
|
48
48
|
</div>
|
|
49
|
-
<Button size="s" onClick={onUpdate} loading={loading}>
|
|
50
|
-
{
|
|
49
|
+
<Button size="s" onClick={onUpdate} loading={loading} view="flat-secondary">
|
|
50
|
+
<Icon data={updateArrow} width={20} height={20} />
|
|
51
51
|
</Button>
|
|
52
52
|
</div>
|
|
53
53
|
);
|
|
@@ -56,17 +56,11 @@ export const Preview = (props: PreviewProps) => {
|
|
|
56
56
|
const renderFirstLevelIssues = () => {
|
|
57
57
|
return (
|
|
58
58
|
<div className={b('preview-content')}>
|
|
59
|
-
{
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
key={issue.id}
|
|
65
|
-
data={issue}
|
|
66
|
-
onShowMore={onShowMore}
|
|
67
|
-
/>
|
|
68
|
-
))
|
|
69
|
-
}
|
|
59
|
+
{isStatusOK
|
|
60
|
+
? i18n('status_message.ok')
|
|
61
|
+
: firstLevelIssues?.map((issue) => (
|
|
62
|
+
<IssuePreview key={issue.id} data={issue} onShowMore={onShowMore} />
|
|
63
|
+
))}
|
|
70
64
|
</div>
|
|
71
65
|
);
|
|
72
66
|
};
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
"status_massage.ok": "No issues have been found on this database",
|
|
8
|
-
"ok": "Ok",
|
|
9
|
-
"error": "Error",
|
|
10
|
-
"no-data": "no healthcheck data"
|
|
2
|
+
"title.healthcheck": "Healthcheck",
|
|
3
|
+
"label.update": "Update",
|
|
4
|
+
"label.show-details": "Show details",
|
|
5
|
+
"status_message.ok": "No issues have been found on this database",
|
|
6
|
+
"no-data": "no healthcheck data"
|
|
11
7
|
}
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
"status_massage.ok": "В базе данных нет проблем",
|
|
8
|
-
"ok": "Ok",
|
|
9
|
-
"error": "Ошибка",
|
|
10
|
-
"no-data": "нет данных healthcheck"
|
|
2
|
+
"title.healthcheck": "Healthcheck",
|
|
3
|
+
"label.update": "Обновить",
|
|
4
|
+
"label.show-details": "Посмотреть подробности",
|
|
5
|
+
"status_message.ok": "В базе данных нет проблем",
|
|
6
|
+
"no-data": "нет данных healthcheck"
|
|
11
7
|
}
|
|
@@ -107,7 +107,7 @@ class Tenants extends React.Component {
|
|
|
107
107
|
|
|
108
108
|
getControlPlaneValue = (item) => {
|
|
109
109
|
const parts = _.get(item, 'Name', []).split('/');
|
|
110
|
-
const defaultValue = parts.length ? parts.
|
|
110
|
+
const defaultValue = parts.length ? parts[parts.length - 1] : '—';
|
|
111
111
|
|
|
112
112
|
return _.get(item, 'ControlPlane.name', defaultValue);
|
|
113
113
|
};
|
|
@@ -124,12 +124,10 @@ class Tenants extends React.Component {
|
|
|
124
124
|
savedTenantInitialTab,
|
|
125
125
|
} = this.props;
|
|
126
126
|
|
|
127
|
-
const filteredTenantsBySearch = tenants.filter(
|
|
128
|
-
(
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
filter,
|
|
132
|
-
);
|
|
127
|
+
const filteredTenantsBySearch = tenants.filter((item) => {
|
|
128
|
+
const re = new RegExp(searchQuery, 'i');
|
|
129
|
+
return re.test(item.Name) || re.test(this.getControlPlaneValue(item));
|
|
130
|
+
});
|
|
133
131
|
const filteredTenants = Tenants.filterTenants(filteredTenantsBySearch, filter);
|
|
134
132
|
|
|
135
133
|
const initialTenantGeneralTab = savedTenantInitialTab || TENANT_GENERAL_TABS[0].id;
|
|
@@ -151,6 +149,7 @@ class Tenants extends React.Component {
|
|
|
151
149
|
externalLink={isExternalLink}
|
|
152
150
|
className={b('name')}
|
|
153
151
|
name={value || 'unknown database'}
|
|
152
|
+
withLeftTrim={true}
|
|
154
153
|
status={row.Overall}
|
|
155
154
|
hasClipboardButton
|
|
156
155
|
path={createHref(routes.tenant, undefined, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ydb-embedded-ui",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"files": [
|
|
5
5
|
"dist"
|
|
6
6
|
],
|
|
@@ -57,6 +57,9 @@
|
|
|
57
57
|
],
|
|
58
58
|
"*.{js,jsx,ts,tsx}": [
|
|
59
59
|
"eslint --fix --quiet"
|
|
60
|
+
],
|
|
61
|
+
"*.{json}": [
|
|
62
|
+
"prettier --write"
|
|
60
63
|
]
|
|
61
64
|
},
|
|
62
65
|
"jest": {
|