Skip to content

Commit e315ca4

Browse files
authored
feat(Diagnostics): update Healthcheck design (#509)
1 parent 428b624 commit e315ca4

File tree

12 files changed

+165
-130
lines changed

12 files changed

+165
-130
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.diagnostic-card {
2+
min-width: 200px;
3+
max-width: 350px;
4+
padding: 16px;
5+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import {ReactNode} from 'react';
2+
import cn from 'bem-cn-lite';
3+
4+
import {Card} from '@gravity-ui/uikit';
5+
6+
import './DiagnosticCard.scss';
7+
8+
const b = cn('diagnostic-card');
9+
10+
interface DiagnosticCardProps {
11+
children?: ReactNode;
12+
className?: string;
13+
}
14+
15+
export function DiagnosticCard({children, className}: DiagnosticCardProps) {
16+
return <Card className={b(null, className)}>{children}</Card>;
17+
}

src/components/EntityStatus/EntityStatus.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,13 @@ class EntityStatus extends React.Component {
107107
);
108108
}
109109
render() {
110-
const {name, label, iconPath, hasClipboardButton, className} = this.props;
110+
const {name, label, iconPath, hasClipboardButton, className, size, status} = this.props;
111111

112112
return (
113113
<div className={b(null, className)} title={name}>
114114
{iconPath ? this.renderStatusLink() : this.renderIcon()}
115115
{label && (
116-
<span title={label} className={b('label')}>
116+
<span title={label} className={b('label', {size, state: status.toLowerCase()})}>
117117
{label}
118118
</span>
119119
)}

src/components/EntityStatus/EntityStatus.scss

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,15 @@
4747
line-height: var(--yc-text-body-2-line-height);
4848

4949
color: var(--yc-color-text-complementary);
50+
51+
&_size_m {
52+
font-size: var(--yc-text-body-2-font-size);
53+
line-height: var(--yc-text-body-2-line-height);
54+
}
55+
56+
&_size_l {
57+
font-size: var(--yc-text-header-2-font-size);
58+
}
5059
}
5160

5261
&__link {
@@ -89,6 +98,11 @@
8998
width: 18px;
9099
height: 18px;
91100
}
101+
102+
&_size_l {
103+
width: 27px;
104+
height: 27px;
105+
}
92106
}
93107

94108
&__status-color {
@@ -115,6 +129,7 @@
115129
}
116130
}
117131

132+
&__label,
118133
&__status-icon {
119134
&_state_blue {
120135
color: var(--yc-color-infographics-info-heavy);

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

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,9 @@ const b = cn('kv-detailed-overview');
2525
function DetailedOverview(props: DetailedOverviewProps) {
2626
const [isModalVisible, setIsModalVisible] = useState(false);
2727

28-
const [expandedIssueId, setExpandedIssueId] = useState<string>();
29-
3028
const {currentSchemaPath} = useSelector((state: any) => state.schema);
3129

32-
const openModalHandler = (id: string) => {
33-
setExpandedIssueId(id);
30+
const openModalHandler = () => {
3431
setIsModalVisible(true);
3532
};
3633

@@ -41,11 +38,7 @@ function DetailedOverview(props: DetailedOverviewProps) {
4138
const renderModal = () => {
4239
return (
4340
<Modal open={isModalVisible} onClose={closeModalHandler} className={b('modal')}>
44-
<Healthcheck
45-
tenant={props.tenantName}
46-
fetchData={false}
47-
expandedIssueId={expandedIssueId}
48-
/>
41+
<Healthcheck tenant={props.tenantName} fetchData={false} />
4942
<Button
5043
className={b('close-modal-button')}
5144
onClick={closeModalHandler}

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

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import {Button, Icon} from '@gravity-ui/uikit';
44

55
import updateArrow from '../../../../../assets/icons/update-arrow.svg';
66

7+
import type {IResponseError} from '../../../../../types/api/error';
78
import type {IIssuesTree} from '../../../../../types/store/healthcheck';
9+
import {ResponseError} from '../../../../../components/Errors/ResponseError';
810

911
import IssueTree from '../IssuesViewer/IssueTree';
1012

@@ -13,17 +15,14 @@ import i18n from '../i18n';
1315
const b = cn('healthcheck');
1416

1517
interface DetailsProps {
16-
issueTree?: IIssuesTree;
18+
issueTrees?: IIssuesTree[];
1719
loading?: boolean;
1820
onUpdate: VoidFunction;
21+
error?: IResponseError;
1922
}
2023

2124
export const Details = (props: DetailsProps) => {
22-
const {loading, onUpdate, issueTree} = props;
23-
24-
if (!issueTree) {
25-
return null;
26-
}
25+
const {loading, onUpdate, issueTrees, error} = props;
2726

2827
const renderHealthcheckHeader = () => {
2928
return (
@@ -38,18 +37,28 @@ export const Details = (props: DetailsProps) => {
3837
);
3938
};
4039

41-
const renderHealthcheckIssues = () => {
40+
const renderContent = () => {
41+
if (error) {
42+
return <ResponseError error={error} defaultMessage={i18n('no-data')} />;
43+
}
44+
45+
if (!issueTrees || !issueTrees.length) {
46+
return i18n('status_message.ok');
47+
}
48+
4249
return (
43-
<div className={b('issues-wrapper')}>
44-
<IssueTree issueTree={issueTree} />
45-
</div>
50+
<>
51+
{issueTrees.map((issueTree) => (
52+
<IssueTree key={issueTree.id} issueTree={issueTree} />
53+
))}
54+
</>
4655
);
4756
};
4857

4958
return (
5059
<div className={b('details')}>
5160
{renderHealthcheckHeader()}
52-
{renderHealthcheckIssues()}
61+
<div className={b('details-content-wrapper')}>{renderContent()}</div>
5362
</div>
5463
);
5564
};

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
@import '@gravity-ui/uikit/styles/mixins.scss';
44

55
.healthcheck {
6+
display: flex;
7+
68
&_expanded {
79
// Since most of the inner containers have fixed width, we can set fixed width here as well
810
// Thus we will get rid of unneeded layout shift when scrollbar appear
@@ -17,7 +19,7 @@
1719
margin-bottom: 15px;
1820
}
1921

20-
&__issues-wrapper {
22+
&__details-content-wrapper {
2123
overflow-x: hidden;
2224
overflow-y: auto;
2325

@@ -67,6 +69,17 @@
6769
line-height: 24px;
6870
}
6971

72+
&__issues-statistics {
73+
display: flex;
74+
flex-wrap: wrap;
75+
align-items: center;
76+
77+
margin: 10px 0;
78+
79+
column-gap: 26px;
80+
row-gap: 16px;
81+
}
82+
7083
&__self-check-status-indicator {
7184
padding: 0 8px;
7285

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

Lines changed: 26 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,40 +8,36 @@ import {SelfCheckResult} from '../../../../types/api/healthcheck';
88
import {useTypedSelector, useAutofetcher} from '../../../../utils/hooks';
99
import {
1010
getHealthcheckInfo,
11-
selectIssuesTreeById,
12-
selectIssuesTreesRoots,
11+
selectIssuesStatistics,
12+
selectIssuesTrees,
1313
setDataWasNotLoaded,
1414
} from '../../../../store/reducers/healthcheckInfo';
15+
import {DiagnosticCard} from '../../../../components/DiagnosticCard/DiagnosticCard';
1516

1617
import {Details} from './Details';
1718
import {Preview} from './Preview';
1819

19-
import i18n from './i18n';
2020
import './Healthcheck.scss';
2121

2222
interface HealthcheckProps {
2323
tenant: string;
2424
preview?: boolean;
2525
fetchData?: boolean;
26-
expandedIssueId?: string;
27-
showMoreHandler?: (id: string) => void;
26+
showMoreHandler?: VoidFunction;
2827
}
2928

3029
const b = cn('healthcheck');
3130

3231
export const Healthcheck = (props: HealthcheckProps) => {
33-
const {tenant, preview, fetchData = true, showMoreHandler, expandedIssueId} = props;
32+
const {tenant, preview, fetchData = true, showMoreHandler} = props;
3433

3534
const dispatch = useDispatch();
3635

3736
const {data, loading, wasLoaded, error} = useTypedSelector((state) => state.healthcheckInfo);
3837
const selfCheckResult = data?.self_check_result || SelfCheckResult.UNSPECIFIED;
3938

40-
const issuesTreesRoots = useTypedSelector(selectIssuesTreesRoots);
41-
const expandedIssueTree = useTypedSelector((state) =>
42-
selectIssuesTreeById(state, expandedIssueId),
43-
);
44-
39+
const issuesStatistics = useTypedSelector(selectIssuesStatistics);
40+
const issueTrees = useTypedSelector(selectIssuesTrees);
4541
const {autorefresh} = useTypedSelector((state) => state.schema);
4642

4743
const fetchHealthcheck = useCallback(
@@ -66,37 +62,30 @@ export const Healthcheck = (props: HealthcheckProps) => {
6662
);
6763

6864
const renderContent = () => {
69-
if (error) {
70-
return error.statusText;
71-
}
72-
7365
if (loading && !wasLoaded) {
7466
return (
75-
<div className={b('loader')}>
67+
<DiagnosticCard className={b('loader')}>
7668
<Loader size="m" />
77-
</div>
69+
</DiagnosticCard>
7870
);
7971
}
80-
81-
if (data && data['self_check_result']) {
82-
return preview ? (
83-
<Preview
84-
issuesTrees={issuesTreesRoots}
85-
selfCheckResult={selfCheckResult}
86-
loading={loading}
87-
onShowMore={showMoreHandler}
88-
onUpdate={fetchHealthcheck}
89-
/>
90-
) : (
91-
<Details
92-
issueTree={expandedIssueTree}
93-
loading={loading}
94-
onUpdate={fetchHealthcheck}
95-
/>
96-
);
97-
}
98-
99-
return <div className="error">{i18n('no-data')}</div>;
72+
return preview ? (
73+
<Preview
74+
issuesStatistics={issuesStatistics}
75+
selfCheckResult={selfCheckResult}
76+
loading={loading}
77+
onShowMore={showMoreHandler}
78+
onUpdate={fetchHealthcheck}
79+
error={error}
80+
/>
81+
) : (
82+
<Details
83+
loading={loading}
84+
onUpdate={fetchHealthcheck}
85+
issueTrees={issueTrees}
86+
error={error}
87+
/>
88+
);
10089
};
10190

10291
return <div className={b({expanded: !preview})}>{renderContent()}</div>;

0 commit comments

Comments
 (0)