Skip to content

Commit 10b4bf5

Browse files
committed
feat(Healthcheck): display first level issues in overview
1 parent 2728a3b commit 10b4bf5

File tree

11 files changed

+133
-30
lines changed

11 files changed

+133
-30
lines changed

src/components/EntityStatus/EntityStatus.js

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,22 @@ import React from 'react';
22
import PropTypes from 'prop-types';
33
import cn from 'bem-cn-lite';
44
import {Link} from 'react-router-dom';
5-
import {ClipboardButton, Link as ExternalLink, Button} from '@gravity-ui/uikit';
5+
import {ClipboardButton, Link as ExternalLink, Button, Icon} from '@gravity-ui/uikit';
6+
7+
import circleInfoIcon from '../../assets/icons/circle-info.svg';
8+
import circleExclamationIcon from '../../assets/icons/circle-exclamation.svg';
9+
import triangleExclamationIcon from '../../assets/icons/triangle-exclamation.svg';
10+
import circleTimesIcon from '../../assets/icons/circle-xmark.svg';
611

712
import './EntityStatus.scss';
813

14+
const icons = {
15+
BLUE: circleInfoIcon,
16+
YELLOW: circleExclamationIcon,
17+
ORANGE: triangleExclamationIcon,
18+
RED: circleTimesIcon,
19+
};
20+
921
const b = cn('entity-status');
1022

1123
class EntityStatus extends React.Component {
@@ -22,6 +34,7 @@ class EntityStatus extends React.Component {
2234
showStatus: PropTypes.bool,
2335
externalLink: PropTypes.bool,
2436
className: PropTypes.string,
37+
mode: PropTypes.oneOf(['color', 'icons']),
2538
};
2639

2740
static defaultProps = {
@@ -31,15 +44,27 @@ class EntityStatus extends React.Component {
3144
label: '',
3245
showStatus: true,
3346
externalLink: false,
47+
mode: 'color',
3448
};
3549
renderIcon() {
36-
const {status, size, showStatus} = this.props;
50+
const {status, size, showStatus, mode} = this.props;
3751

3852
if (!showStatus) {
3953
return null;
4054
}
4155

42-
return <div className={b('status-icon', {state: status.toLowerCase(), size})} />;
56+
const modifiers = {state: status.toLowerCase(), size};
57+
58+
if (mode === 'icons' && icons[status]) {
59+
return (
60+
<Icon
61+
className={b('status-icon', modifiers)}
62+
data={icons[status]}
63+
/>
64+
);
65+
}
66+
67+
return <div className={b('status-color', modifiers)} />;
4368
}
4469
renderStatusLink() {
4570
const {iconPath} = this.props;

src/components/EntityStatus/EntityStatus.scss

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,26 +57,32 @@
5757
white-space: nowrap;
5858
}
5959

60+
&__status-color,
6061
&__status-icon {
6162
margin-right: 8px;
6263

6364
border-radius: 3px;
6465
&_size_xs {
6566
aspect-ratio: 1;
6667

68+
width: 12px;
6769
height: 12px;
6870
}
6971
&_size_s {
7072
aspect-ratio: 1;
7173

74+
width: 16px;
7275
height: 16px;
7376
}
7477
&_size_m {
7578
aspect-ratio: 1;
7679

80+
width: 18px;
7781
height: 18px;
7882
}
83+
}
7984

85+
&__status-color {
8086
&_state_running,
8187
&_state_green {
8288
background-color: var(--yc-color-infographics-positive-heavy);
@@ -96,7 +102,22 @@
96102
background: var(--yc-color-text-complementary);
97103
}
98104
&_state_orange {
99-
background: var(--yc-color-text-warning-heavy);
105+
background: var(--yc-color-base-warning-orange);
106+
}
107+
}
108+
109+
&__status-icon {
110+
&_state_blue {
111+
color: var(--yc-color-infographics-info-heavy);
112+
}
113+
&_state_yellow {
114+
color: var(--yc-color-infographics-warning-heavy);
115+
}
116+
&_state_orange {
117+
color: var(--yc-color-base-warning-orange);
118+
}
119+
&_state_red {
120+
color: var(--yc-color-infographics-danger-heavy);
100121
}
101122
}
102123

src/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ function DetailedOverview(props: DetailedOverviewProps) {
4141
const renderModal = () => {
4242
return (
4343
<Modal open={isModalVisible} onClose={closeModalHandler} className={b('modal')}>
44-
<Healthcheck tenant={props.tenantName} />
44+
<Healthcheck tenant={props.tenantName} fetchData={false} />
4545
<Button
4646
className={b('close-modal-button')}
4747
onClick={closeModalHandler}

src/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
padding: 25px 20px 20px;
77
}
88

9+
&__issue-preview {
10+
margin-bottom: 15px;
11+
}
12+
913
&__issues {
1014
overflow-x: hidden;
1115
overflow-y: auto;

src/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import './Healthcheck.scss';
1616
interface HealthcheckProps {
1717
tenant: string;
1818
preview?: boolean;
19+
fetchData?: boolean;
1920
showMoreHandler?: VoidFunction;
2021
}
2122

@@ -25,6 +26,7 @@ export const Healthcheck = (props: HealthcheckProps) => {
2526
const {
2627
tenant,
2728
preview,
29+
fetchData = true,
2830
showMoreHandler,
2931
} = props;
3032

@@ -34,8 +36,10 @@ export const Healthcheck = (props: HealthcheckProps) => {
3436
const {autorefresh} = useSelector((state: any) => state.schema);
3537

3638
const fetchHealthcheck = useCallback(() => {
37-
dispatch(getHealthcheckInfo(tenant));
38-
}, [dispatch, tenant]);
39+
if (fetchData) {
40+
dispatch(getHealthcheckInfo(tenant));
41+
}
42+
}, [dispatch, fetchData, tenant]);
3943

4044
useAutofetcher(fetchHealthcheck, [fetchHealthcheck], autorefresh);
4145

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import cn from 'bem-cn-lite';
2+
3+
import {Link, Text} from '@gravity-ui/uikit';
4+
5+
import EntityStatus from '../../../../../components/EntityStatus/EntityStatus';
6+
import {IssueLog} from '../../../../../types/api/healthcheck';
7+
8+
import i18n from '../i18n';
9+
10+
const b = cn('healthcheck');
11+
12+
interface IssuePreviewProps {
13+
data?: IssueLog;
14+
onShowMore?: VoidFunction;
15+
}
16+
17+
export const IssuePreview = (props: IssuePreviewProps) => {
18+
const {
19+
data,
20+
onShowMore,
21+
} = props;
22+
23+
if (!data) {
24+
return null;
25+
}
26+
27+
return (
28+
<div className={b('issue-preview')}>
29+
<EntityStatus mode="icons" status={data.status} name={data.type} />
30+
<Text as="div" color="secondary" variant="body-2">{data.message}</Text>
31+
<Link onClick={onShowMore}>{i18n('label.show-details')}</Link>
32+
</div>
33+
);
34+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './IssuePreview';
Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
import {useMemo} from 'react';
12
import cn from 'bem-cn-lite';
23

34
import {Button} from '@gravity-ui/uikit';
45

56
import {SelfCheckResult} from '../../../../../types/api/healthcheck';
67
import type {IHealthCheck} from '../../../../../types/store/healthcheck';
78

9+
import {IssuePreview} from '../IssuePreview';
10+
811
import i18n from '../i18n';
912

1013
const b = cn('healthcheck');
@@ -24,41 +27,54 @@ export const Preview = (props: PreviewProps) => {
2427
onUpdate,
2528
} = props;
2629

30+
const selfCheckResult = data?.self_check_result || SelfCheckResult.UNSPECIFIED;
31+
const isStatusOK = selfCheckResult === SelfCheckResult.GOOD;
32+
33+
const issuesLog = data?.issue_log;
34+
const firstLevelIssues = useMemo(() => issuesLog?.filter(({level}) => level === 1), [issuesLog]);
35+
2736
if (!data) {
2837
return null;
2938
}
3039

31-
const {self_check_result: selfCheckResult} = data;
32-
const modifier = selfCheckResult.toLowerCase();
40+
const renderStatus = () => {
41+
const modifier = selfCheckResult.toLowerCase();
3342

34-
const statusOk = selfCheckResult === SelfCheckResult.GOOD;
35-
const text = statusOk
36-
? i18n('status_message.ok')
37-
: i18n('status_message.error');
38-
39-
return (
40-
<div className={b('preview')}>
43+
return (
4144
<div className={b('status-wrapper')}>
4245
<div className={b('preview-title')}>{i18n('title.healthcheck')}</div>
4346
<div className={b('self-check-status-indicator', {[modifier]: true})}>
44-
{statusOk ? i18n('ok') : i18n('error')}
47+
{isStatusOK ? i18n('ok') : i18n('error')}
4548
</div>
4649
<Button size="s" onClick={onUpdate} loading={loading}>
4750
{i18n('label.update')}
4851
</Button>
4952
</div>
53+
);
54+
};
55+
56+
const renderFirstLevelIssues = () => {
57+
return (
5058
<div className={b('preview-content')}>
51-
{text}
52-
{!statusOk && (
53-
<Button
54-
view="flat-info"
55-
onClick={onShowMore}
56-
size="s"
57-
>
58-
{i18n('label.show-details')}
59-
</Button>
60-
)}
59+
{
60+
isStatusOK ?
61+
i18n('status_massage.ok') :
62+
firstLevelIssues?.map((issue) => (
63+
<IssuePreview
64+
key={issue.id}
65+
data={issue}
66+
onShowMore={onShowMore}
67+
/>
68+
))
69+
}
6170
</div>
71+
);
72+
};
73+
74+
return (
75+
<div className={b('preview')}>
76+
{renderStatus()}
77+
{renderFirstLevelIssues()}
6278
</div>
6379
);
6480
};

src/containers/Tenant/Diagnostics/Healthcheck/i18n/en.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
"label.update": "Update",
66
"label.show-details": "Show details",
77
"status_massage.ok": "No issues have been found on this database",
8-
"status_message.error": "Several issues have been found on this database",
98
"ok": "Ok",
109
"error": "Error",
1110
"no-data": "no healthcheck data"

src/containers/Tenant/Diagnostics/Healthcheck/i18n/ru.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
"label.update": "Обновить",
66
"label.show-details": "Посмотреть подробности",
77
"status_massage.ok": "В базе данных нет проблем",
8-
"status_message.error": "В базе данных есть несколько проблем",
98
"ok": "Ok",
109
"error": "Ошибка",
1110
"no-data": "нет данных healthcheck"

0 commit comments

Comments
 (0)