Skip to content

Commit 4e4c4bf

Browse files
committed
style: use isServiceReady to determine ready status, move Download Logs back outside Overview item, use collapse icon instead of expand, created PageTitle component to be reusable with all views
1 parent c22e450 commit 4e4c4bf

File tree

7 files changed

+160
-105
lines changed

7 files changed

+160
-105
lines changed

src/assets/icon-collapse.svg

Lines changed: 16 additions & 0 deletions
Loading

src/common/components/data-display/LabeledRow.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ import ButtonBase from "@material-ui/core/ButtonBase";
77
type LabeledRowProps = {
88
label: string;
99
value: string | number;
10-
paddingSpacing?: number;
1110
showCopyIcon?: boolean;
11+
padding?: string;
1212
reserveSpaceForCopyIcon?: boolean;
1313
statusIcon?: string;
1414
};
1515

16-
const useStyles = makeStyles((theme) => ({
16+
const useStyles = makeStyles(() => ({
1717
cell: (props: LabeledRowProps) => ({
18-
padding: theme.spacing(props.paddingSpacing ?? 2),
18+
padding: props.padding ? props.padding : "15px 40px",
1919
wordWrap: "break-word",
2020
whiteSpace: "pre-wrap",
2121
fontSize: "16px",
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import React, { ReactElement } from "react";
2+
import { Icon } from "@material-ui/core";
3+
import { makeStyles } from "@material-ui/core";
4+
import { notificationIcon } from "../../../utils/svgIcons";
5+
6+
type PageTitleProps = {
7+
title: string;
8+
};
9+
10+
const useStyles = makeStyles(() => ({
11+
headingContainer: {
12+
display: "flex",
13+
alignItems: "center",
14+
},
15+
heading: {
16+
fontSize: "30px",
17+
fontWeight: 500,
18+
},
19+
notificationIconContainer: {
20+
marginLeft: "auto",
21+
},
22+
notificationIcon: {
23+
cursor: "pointer",
24+
},
25+
}));
26+
27+
const PageTitle = (props: PageTitleProps): ReactElement => {
28+
const { title } = props;
29+
const classes = useStyles();
30+
31+
return (
32+
<div className={classes.headingContainer}>
33+
<h1 className={classes.heading}>{title}</h1>
34+
{false && (
35+
<Icon className={classes.notificationIconContainer}>
36+
<img
37+
src={notificationIcon}
38+
alt="notifications"
39+
className={classes.notificationIcon}
40+
/>
41+
</Icon>
42+
)}
43+
</div>
44+
);
45+
};
46+
47+
export default PageTitle;

src/common/utils/svgIcons.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import copyIcon from "../../assets/icon-copy.svg";
66
import notificationIcon from "../../assets/icon-notification.svg";
77
import notificationActiveIcon from "../../assets/icon-notification-active.svg";
88
import downloadIcon from "../../assets/icon-download-log.svg";
9+
import collapseIcon from "../../assets/icon-collapse.svg";
910

1011
export {
1112
openDexLogo,
@@ -16,4 +17,5 @@ export {
1617
notificationIcon,
1718
notificationActiveIcon,
1819
downloadIcon,
20+
collapseIcon
1921
};

src/dashboard/overview/Overview.tsx

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createStyles, withStyles, WithStyles, Icon } from "@material-ui/core";
1+
import { createStyles, withStyles, WithStyles } from "@material-ui/core";
22
import Grid from "@material-ui/core/Grid";
33
import { inject, observer } from "mobx-react";
44
import React, { ReactElement } from "react";
@@ -11,7 +11,7 @@ import DashboardContent, {
1111
DashboardContentState,
1212
} from "../DashboardContent";
1313
import OverviewItem from "./OverviewItem";
14-
import { notificationIcon } from "../../common/utils/svgIcons";
14+
import PageTitle from "../../common/components/data-display/text/PageTitle";
1515

1616
type PropsType = DashboardContentProps & WithStyles<typeof styles>;
1717

@@ -82,20 +82,7 @@ class Overview extends DashboardContent<PropsType, StateType> {
8282

8383
return (
8484
<div>
85-
<div className={classes.headingContainer}>
86-
<h1 className={classes.heading}>Overview</h1>
87-
<Icon
88-
onClick={() => this.handleSelectNotifications()}
89-
className={classes.notificationIconContainer}
90-
>
91-
<img
92-
src={notificationIcon}
93-
alt="notifications"
94-
className={classes.notificationIcon}
95-
/>
96-
</Icon>
97-
</div>
98-
85+
<PageTitle title="Overview" />
9986
<Grid container spacing={2} className={classes.wrapper}>
10087
{this.state.initialLoadCompleted ? (
10188
this.state.statuses &&

src/dashboard/overview/OverviewItem.tsx

Lines changed: 86 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Icon, makeStyles, Theme } from "@material-ui/core";
1+
import { Icon, makeStyles } from "@material-ui/core";
22
import Card from "@material-ui/core/Card";
33
import CardContent from "@material-ui/core/CardContent";
44
import Grid from "@material-ui/core/Grid";
@@ -12,7 +12,13 @@ import {
1212
expandIcon,
1313
readyIcon,
1414
syncingIcon,
15+
downloadIcon,
1516
} from "../../common/utils/svgIcons";
17+
import ButtonBase from "@material-ui/core/ButtonBase";
18+
import api from "../../api";
19+
import { formatDateTimeForFilename } from "../../common/utils/dateUtil";
20+
import { Subject } from "rxjs";
21+
import Snackbar from "../../common/components/data-display/feedback/Snackbar";
1622

1723
export type OverviewItemProps = {
1824
status: Status;
@@ -21,14 +27,14 @@ export type OverviewItemProps = {
2127
};
2228

2329
const getCardHeaderBackgroundImage = (props: OverviewItemProps) => {
24-
if (props.status.status.includes("Ready")) {
30+
if (isServiceReady(props.status)) {
2531
return "linear-gradient(to right, #1f995a, #00e64d)";
2632
} else {
2733
return "linear-gradient(to left, #fea900, #f15a24 0%)";
2834
}
2935
};
3036

31-
const useStyles = makeStyles((theme: Theme) => ({
37+
const useStyles = makeStyles(() => ({
3238
cardHeader: (props: OverviewItemProps) => ({
3339
padding: "12px 16px 12px 24px",
3440
backgroundImage: getCardHeaderBackgroundImage(props),
@@ -56,19 +62,6 @@ const useStyles = makeStyles((theme: Theme) => ({
5662
cardContentStatusValueText: {
5763
color: "#f2f2f2",
5864
},
59-
statusDot: {
60-
height: 10,
61-
width: 10,
62-
borderRadius: "50%",
63-
display: "inline-block",
64-
marginRight: 10,
65-
},
66-
active: {
67-
backgroundColor: theme.palette.success.light,
68-
},
69-
inactive: {
70-
backgroundColor: theme.palette.error.light,
71-
},
7265
expandIcon: {
7366
cursor: "pointer",
7467
},
@@ -78,12 +71,28 @@ const useStyles = makeStyles((theme: Theme) => ({
7871
statusIcon: {
7972
padding: "0 10px",
8073
},
74+
downloadIconContainer: {
75+
fontSize: "14px",
76+
color: "#000000",
77+
textDecoration: "underline",
78+
},
79+
detailsIconContainer: {
80+
display: "flex",
81+
justifyContent: "flex-end",
82+
},
83+
titleAndLogsContainer: {
84+
width: "66.6%",
85+
display: "flex",
86+
justifyContent: "space-between",
87+
alignItems: "center",
88+
},
8189
}));
8290

8391
const OverviewItem = (props: OverviewItemProps): ReactElement => {
8492
const { status, opendexdLocked, opendexdNotReady } = props;
8593
const [detailsOpen, setDetailsOpen] = useState(false);
8694
const classes = useStyles(props);
95+
const errorMsgOpenSubject = new Subject<boolean>();
8796

8897
const isDetailsIconVisible = (status: Status): boolean => {
8998
return (
@@ -95,28 +104,72 @@ const OverviewItem = (props: OverviewItemProps): ReactElement => {
95104
};
96105

97106
const getStatusIcon = (status: Status) => {
98-
if (status.status.includes("Ready")) {
107+
if (isServiceReady(status)) {
99108
return readyIcon;
100109
} else {
101110
return syncingIcon;
102111
}
103112
};
104113

114+
const isDownloadLogsEnabled = (status: Status): boolean => {
115+
return (
116+
!status.status.includes("light mode") && status.status !== "Disabled"
117+
);
118+
};
119+
120+
const downloadLogs = (serviceName: string, handleError: () => void): void => {
121+
api.logs$(serviceName).subscribe({
122+
next: (resp: string) => {
123+
const blob = new Blob([resp]);
124+
const url = URL.createObjectURL(blob);
125+
const anchor = Object.assign(document.createElement("a"), {
126+
href: url,
127+
download: `${serviceName}_${formatDateTimeForFilename(
128+
new Date()
129+
)}.log`,
130+
style: { display: "none" },
131+
});
132+
anchor.click();
133+
},
134+
error: handleError,
135+
});
136+
};
137+
105138
return (
106139
<div>
107140
<Card square={true}>
108141
<Grid container className={classes.cardHeader}>
109-
<Grid>
110-
<Typography
111-
component="span"
112-
variant="body1"
113-
className={classes.cardHeading}
114-
>
115-
{props.status.service}
116-
</Typography>
117-
</Grid>
142+
<div className={classes.titleAndLogsContainer}>
143+
<Grid>
144+
<Typography
145+
component="span"
146+
variant="body1"
147+
className={classes.cardHeading}
148+
>
149+
{props.status.service}
150+
</Typography>
151+
</Grid>
118152

119-
<Grid>
153+
<Grid>
154+
{isDownloadLogsEnabled(status) && (
155+
<div>
156+
<ButtonBase
157+
className={classes.downloadIconContainer}
158+
onClick={() =>
159+
downloadLogs(status.service, () =>
160+
errorMsgOpenSubject?.next(true)
161+
)
162+
}
163+
>
164+
<img src={downloadIcon} alt="download logs" />
165+
Download Logs
166+
</ButtonBase>
167+
</div>
168+
)}
169+
</Grid>
170+
</div>
171+
172+
<Grid className={classes.detailsIconContainer}>
120173
{isDetailsIconVisible(status) && (
121174
<Icon
122175
onClick={() => setDetailsOpen(true)}
@@ -154,6 +207,12 @@ const OverviewItem = (props: OverviewItemProps): ReactElement => {
154207
titleBackground={getCardHeaderBackgroundImage(props)}
155208
/>
156209
)}
210+
211+
<Snackbar
212+
message={`Could not download the logs for ${status.service}`}
213+
openSubject={errorMsgOpenSubject}
214+
type="error"
215+
></Snackbar>
157216
</div>
158217
);
159218
};

0 commit comments

Comments
 (0)