From c22e450b370fb52c4e346fc11d61b88886577b52 Mon Sep 17 00:00:00 2001 From: scorebreaker Date: Tue, 30 Mar 2021 12:05:58 +0300 Subject: [PATCH 1/2] style: implement Overview design --- src/assets/icon-copy.svg | 29 +++ src/assets/icon-download-log.svg | 16 ++ src/assets/icon-expand.svg | 16 ++ src/assets/icon-notification-active.svg | 16 ++ src/assets/icon-notification.svg | 14 ++ src/assets/icon-ready.svg | 22 ++ src/assets/icon-syncing.svg | 22 ++ .../components/data-display/LabeledRow.tsx | 72 ++++-- src/common/utils/svgIcons.ts | 18 +- src/dashboard/Dashboard.tsx | 2 +- src/dashboard/overview/Overview.tsx | 83 +++++-- src/dashboard/overview/OverviewItem.tsx | 228 +++++++++--------- src/dashboard/overview/ServiceDetails.tsx | 159 +++++++++--- .../overview/ServiceDetailsContent.tsx | 7 +- src/stories/OverviewItem.stories.tsx | 19 ++ src/themes.ts | 3 + 16 files changed, 534 insertions(+), 192 deletions(-) create mode 100644 src/assets/icon-copy.svg create mode 100644 src/assets/icon-download-log.svg create mode 100644 src/assets/icon-expand.svg create mode 100644 src/assets/icon-notification-active.svg create mode 100644 src/assets/icon-notification.svg create mode 100644 src/assets/icon-ready.svg create mode 100644 src/assets/icon-syncing.svg create mode 100644 src/stories/OverviewItem.stories.tsx diff --git a/src/assets/icon-copy.svg b/src/assets/icon-copy.svg new file mode 100644 index 0000000..3cc2679 --- /dev/null +++ b/src/assets/icon-copy.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icon-download-log.svg b/src/assets/icon-download-log.svg new file mode 100644 index 0000000..f4d5de7 --- /dev/null +++ b/src/assets/icon-download-log.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/assets/icon-expand.svg b/src/assets/icon-expand.svg new file mode 100644 index 0000000..04b730d --- /dev/null +++ b/src/assets/icon-expand.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/assets/icon-notification-active.svg b/src/assets/icon-notification-active.svg new file mode 100644 index 0000000..b37b9e5 --- /dev/null +++ b/src/assets/icon-notification-active.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/assets/icon-notification.svg b/src/assets/icon-notification.svg new file mode 100644 index 0000000..7873231 --- /dev/null +++ b/src/assets/icon-notification.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/assets/icon-ready.svg b/src/assets/icon-ready.svg new file mode 100644 index 0000000..0188eef --- /dev/null +++ b/src/assets/icon-ready.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icon-syncing.svg b/src/assets/icon-syncing.svg new file mode 100644 index 0000000..ed516ac --- /dev/null +++ b/src/assets/icon-syncing.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/common/components/data-display/LabeledRow.tsx b/src/common/components/data-display/LabeledRow.tsx index d8fc9d2..265e74b 100644 --- a/src/common/components/data-display/LabeledRow.tsx +++ b/src/common/components/data-display/LabeledRow.tsx @@ -1,8 +1,8 @@ -import { Divider, Grid, makeStyles } from "@material-ui/core"; -import FileCopyOutlinedIcon from "@material-ui/icons/FileCopyOutlined"; +import { Grid, makeStyles } from "@material-ui/core"; import React, { ReactElement } from "react"; import { copyToClipboard } from "../../utils/appUtil"; -import IconButton from "../input/buttons/IconButton"; +import { copyIcon } from "../../../common/utils/svgIcons"; +import ButtonBase from "@material-ui/core/ButtonBase"; type LabeledRowProps = { label: string; @@ -10,15 +10,39 @@ type LabeledRowProps = { paddingSpacing?: number; showCopyIcon?: boolean; reserveSpaceForCopyIcon?: boolean; + statusIcon?: string; }; const useStyles = makeStyles((theme) => ({ cell: (props: LabeledRowProps) => ({ padding: theme.spacing(props.paddingSpacing ?? 2), - textAlign: "center", wordWrap: "break-word", whiteSpace: "pre-wrap", + fontSize: "16px", }), + textLabel: { + color: "#979797", + }, + textValue: { + color: "#f2f2f2", + }, + copyIcon: { + paddingRight: "5px", + }, + copyContainer: { + cursor: "pointer", + color: "#f15a24", + fontSize: "14px", + display: "flex", + justifyContent: "flex-end", + }, + statusContainer: { + display: "flex", + alignItems: "center", + }, + statusIcon: { + marginRight: "10px", + }, })); const LabeledRow = (props: LabeledRowProps): ReactElement => { @@ -26,22 +50,42 @@ const LabeledRow = (props: LabeledRowProps): ReactElement => { const classes = useStyles(props); return ( - - + + {label} - - - {value} + + + {props.statusIcon ? ( +
+ status + {value} +
+ ) : ( +
{value}
+ )}
{reserveSpaceForCopyIcon && ( {showCopyIcon && ( - } - tooltipTitle="Copy to clipboard" - onClick={() => copyToClipboard(value)} - /> +
+ copyToClipboard(value)}> + copy + Copy + +
)}
)} diff --git a/src/common/utils/svgIcons.ts b/src/common/utils/svgIcons.ts index 49a0514..c3a2d2c 100644 --- a/src/common/utils/svgIcons.ts +++ b/src/common/utils/svgIcons.ts @@ -1,3 +1,19 @@ import openDexLogo from "../../assets/OpenDEXLogo.svg"; +import expandIcon from "../../assets/icon-expand.svg"; +import readyIcon from "../../assets/icon-ready.svg"; +import syncingIcon from "../../assets/icon-syncing.svg"; +import copyIcon from "../../assets/icon-copy.svg"; +import notificationIcon from "../../assets/icon-notification.svg"; +import notificationActiveIcon from "../../assets/icon-notification-active.svg"; +import downloadIcon from "../../assets/icon-download-log.svg"; -export { openDexLogo }; +export { + openDexLogo, + expandIcon, + readyIcon, + syncingIcon, + copyIcon, + notificationIcon, + notificationActiveIcon, + downloadIcon, +}; diff --git a/src/dashboard/Dashboard.tsx b/src/dashboard/Dashboard.tsx index d89aba1..d79e9f1 100644 --- a/src/dashboard/Dashboard.tsx +++ b/src/dashboard/Dashboard.tsx @@ -44,7 +44,7 @@ const useStyles = makeStyles((theme: Theme) => content: { marginLeft: drawerWidth, backgroundColor: theme.palette.background.default, - padding: theme.spacing(3), + padding: theme.spacing(4), height: "100vh", display: "flex", flexDirection: "column", diff --git a/src/dashboard/overview/Overview.tsx b/src/dashboard/overview/Overview.tsx index d28e2ca..bcdb8d4 100644 --- a/src/dashboard/overview/Overview.tsx +++ b/src/dashboard/overview/Overview.tsx @@ -1,4 +1,4 @@ -import { createStyles, withStyles, WithStyles } from "@material-ui/core"; +import { createStyles, withStyles, WithStyles, Icon } from "@material-ui/core"; import Grid from "@material-ui/core/Grid"; import { inject, observer } from "mobx-react"; import React, { ReactElement } from "react"; @@ -11,6 +11,7 @@ import DashboardContent, { DashboardContentState, } from "../DashboardContent"; import OverviewItem from "./OverviewItem"; +import { notificationIcon } from "../../common/utils/svgIcons"; type PropsType = DashboardContentProps & WithStyles; @@ -23,6 +24,20 @@ const styles = () => { wrapper: { overflowY: "auto", }, + headingContainer: { + display: "flex", + alignItems: "center", + }, + heading: { + fontSize: "30px", + fontWeight: 500, + }, + notificationIconContainer: { + marginLeft: "auto", + }, + notificationIcon: { + cursor: "pointer", + }, }); }; @@ -58,32 +73,54 @@ class Overview extends DashboardContent { return status.status !== "Disabled"; }; + handleSelectNotifications = () => { + console.log("handleSelectNotifications"); + }; + render(): ReactElement { const { classes } = this.props; return ( - - {this.state.initialLoadCompleted ? ( - this.state.statuses && - this.state.statuses - .filter(this.statusFilter) - .sort( - (a, b) => - this.sortingOrderByService(a.service) - - this.sortingOrderByService(b.service) - ) - .map((status) => ( - - )) - ) : ( - - )} - +
+
+

Overview

+ this.handleSelectNotifications()} + className={classes.notificationIconContainer} + > + notifications + +
+ + + {this.state.initialLoadCompleted ? ( + this.state.statuses && + this.state.statuses + .filter(this.statusFilter) + .sort( + (a, b) => + this.sortingOrderByService(a.service) - + this.sortingOrderByService(b.service) + ) + .map((status) => ( + + + + )) + ) : ( + + )} + +
); } } diff --git a/src/dashboard/overview/OverviewItem.tsx b/src/dashboard/overview/OverviewItem.tsx index 356cd96..3e1160b 100644 --- a/src/dashboard/overview/OverviewItem.tsx +++ b/src/dashboard/overview/OverviewItem.tsx @@ -1,27 +1,18 @@ -import { - createStyles, - Divider, - Icon, - makeStyles, - Theme, -} from "@material-ui/core"; +import { Icon, makeStyles, Theme } from "@material-ui/core"; import Card from "@material-ui/core/Card"; import CardContent from "@material-ui/core/CardContent"; import Grid from "@material-ui/core/Grid"; import Typography from "@material-ui/core/Typography"; -import GetAppOutlinedIcon from "@material-ui/icons/GetAppOutlined"; import React, { ReactElement, useState } from "react"; -import { Subject } from "rxjs"; -import api from "../../api"; -import Snackbar from "../../common/components/data-display/feedback/Snackbar"; -import LabeledRow from "../../common/components/data-display/LabeledRow"; -import IconButton from "../../common/components/input/buttons/IconButton"; -import TextButton from "../../common/components/input/buttons/TextButton"; -import { formatDateTimeForFilename } from "../../common/utils/dateUtil"; import { isServiceReady } from "../../common/utils/serviceUtil"; import { SERVICES_WITH_ADDITIONAL_INFO } from "../../constants"; import { Status } from "../../models/Status"; import ServiceDetails from "./ServiceDetails"; +import { + expandIcon, + readyIcon, + syncingIcon, +} from "../../common/utils/svgIcons"; export type OverviewItemProps = { status: Status; @@ -29,58 +20,70 @@ export type OverviewItemProps = { opendexdNotReady?: boolean; }; -const useStyles = makeStyles((theme: Theme) => - createStyles({ - cardHeader: { - padding: theme.spacing(3), - }, - cardContent: { - padding: 0, - "&:last-child": { - paddingBottom: 0, - }, - }, - statusDot: { - height: 10, - width: 10, - borderRadius: "50%", - display: "inline-block", - marginRight: 10, - }, - active: { - backgroundColor: theme.palette.success.light, - }, - inactive: { - backgroundColor: theme.palette.error.light, - }, - }) -); +const getCardHeaderBackgroundImage = (props: OverviewItemProps) => { + if (props.status.status.includes("Ready")) { + return "linear-gradient(to right, #1f995a, #00e64d)"; + } else { + return "linear-gradient(to left, #fea900, #f15a24 0%)"; + } +}; -const downloadLogs = (serviceName: string, handleError: () => void): void => { - api.logs$(serviceName).subscribe({ - next: (resp: string) => { - const blob = new Blob([resp]); - const url = URL.createObjectURL(blob); - const anchor = Object.assign(document.createElement("a"), { - href: url, - download: `${serviceName}_${formatDateTimeForFilename(new Date())}.log`, - style: { display: "none" }, - }); - anchor.click(); +const useStyles = makeStyles((theme: Theme) => ({ + cardHeader: (props: OverviewItemProps) => ({ + padding: "12px 16px 12px 24px", + backgroundImage: getCardHeaderBackgroundImage(props), + justifyContent: "space-between", + alignItems: "center", + }), + cardHeading: { + fontSize: "20px", + color: "#000000", + }, + cardContainer: { + padding: 0, + "&:last-child": { + paddingBottom: 0, }, - error: handleError, - }); -}; + }, + cardContent: { + fontSize: "16px", + display: "flex", + padding: "35px 25px", + }, + cardContentStatusText: { + color: "#979797", + }, + cardContentStatusValueText: { + color: "#f2f2f2", + }, + statusDot: { + height: 10, + width: 10, + borderRadius: "50%", + display: "inline-block", + marginRight: 10, + }, + active: { + backgroundColor: theme.palette.success.light, + }, + inactive: { + backgroundColor: theme.palette.error.light, + }, + expandIcon: { + cursor: "pointer", + }, + expandIconContainer: { + verticalAlign: "middle", + }, + statusIcon: { + padding: "0 10px", + }, +})); const OverviewItem = (props: OverviewItemProps): ReactElement => { const { status, opendexdLocked, opendexdNotReady } = props; const [detailsOpen, setDetailsOpen] = useState(false); - const errorMsgOpenSubject = new Subject(); - const classes = useStyles(); - - const statusDotClass = `${classes.statusDot} ${ - isServiceReady(status) ? classes.active : classes.inactive - }`; + const classes = useStyles(props); const isDetailsIconVisible = (status: Status): boolean => { return ( @@ -91,82 +94,67 @@ const OverviewItem = (props: OverviewItemProps): ReactElement => { ); }; - const isDownloadLogsEnabled = (status: Status): boolean => { - return ( - !status.status.includes("light mode") && status.status !== "Disabled" - ); + const getStatusIcon = (status: Status) => { + if (status.status.includes("Ready")) { + return readyIcon; + } else { + return syncingIcon; + } }; return ( - - - - - {isDetailsIconVisible(status) && ( - setDetailsOpen(true)} - icon={open_in_full} - tooltipTitle="Details" - /> - )} - - - - +
+ + + + {props.status.service} - - {isDownloadLogsEnabled(status) && ( - - downloadLogs(status.service, () => - errorMsgOpenSubject?.next(true) - ) - } - size="small" - startIcon={} - tooltipTitle="Download logs" - /> + + + {isDetailsIconVisible(status) && ( + setDetailsOpen(true)} + className={classes.expandIconContainer} + > + expand + )} - - - + + +
+

Status:

+ status +

+ {props.status.status} +

+
- {detailsOpen && ( setDetailsOpen(false)} + titleBackground={getCardHeaderBackgroundImage(props)} /> )} - - - +
); }; diff --git a/src/dashboard/overview/ServiceDetails.tsx b/src/dashboard/overview/ServiceDetails.tsx index 5ec1075..8b35c93 100644 --- a/src/dashboard/overview/ServiceDetails.tsx +++ b/src/dashboard/overview/ServiceDetails.tsx @@ -1,49 +1,146 @@ -import { createStyles, makeStyles, Theme } from "@material-ui/core"; +import { makeStyles, Theme } from "@material-ui/core"; import React, { ReactElement } from "react"; -import Dialog from "../../common/components/layout/dialog/Dialog"; +import { Subject } from "rxjs"; import { drawerWidth } from "../../common/components/navigation/Menu"; import { Status } from "../../models/Status"; import ServiceDetailsContent from "./ServiceDetailsContent"; +import { formatDateTimeForFilename } from "../../common/utils/dateUtil"; +import api from "../../api"; +import DialogTitle from "@material-ui/core/DialogTitle"; +import Dialog from "@material-ui/core/Dialog"; +import DialogContent from "@material-ui/core/DialogContent"; +import { downloadIcon, expandIcon } from "../../common/utils/svgIcons"; +import ButtonBase from "@material-ui/core/ButtonBase"; +import Snackbar from "../../common/components/data-display/feedback/Snackbar"; export type ServiceDetailsProps = { status: Status; + statusIcon: string; handleClose: () => void; + titleBackground: string; }; -const useStyles = makeStyles((theme: Theme) => - createStyles({ - dialog: { - position: "absolute", - left: drawerWidth, - top: 0, - margin: theme.spacing(3), - width: "100%", - maxWidth: `calc(100% - ${drawerWidth + theme.spacing(3) * 2}px)`, - backgroundColor: theme.palette.background.default, - }, - }) -); +const useStyles = makeStyles((theme: Theme) => ({ + dialog: { + position: "absolute", + left: drawerWidth, + top: 80, + margin: theme.spacing(3), + width: "100%", + maxWidth: `calc(100% - ${drawerWidth + theme.spacing(3) * 2}px)`, + backgroundColor: theme.palette.background.default, + borderRadius: 0, + }, + dialogTitle: { + fontSize: "18px", + color: "#000000", + }, + downloadIconContainer: { + paddingRight: "30px", + fontSize: "14px", + color: "#000000", + textDecoration: "underline", + }, + dialogTitleContainer: (props: ServiceDetailsProps) => ({ + backgroundImage: props.titleBackground, + padding: "8px", + }), + dialogTitleContent: { + display: "flex", + alignItems: "baseline", + padding: "5px 15px", + }, + logsAndCloseContainer: { + display: "flex", + marginLeft: "auto", + alignItems: "center", + }, + dialogContent: { + padding: 0, + }, +})); const ServiceDetails = (props: ServiceDetailsProps): ReactElement => { - const { status, handleClose } = props; - const classes = useStyles(); + const { status, handleClose, statusIcon } = props; + const classes = useStyles(props); + const errorMsgOpenSubject = new Subject(); - const title = `General ${status.service} info`; + const isDownloadLogsEnabled = (status: Status): boolean => { + return ( + !status.status.includes("light mode") && status.status !== "Disabled" + ); + }; + + const downloadLogs = (serviceName: string, handleError: () => void): void => { + api.logs$(serviceName).subscribe({ + next: (resp: string) => { + const blob = new Blob([resp]); + const url = URL.createObjectURL(blob); + const anchor = Object.assign(document.createElement("a"), { + href: url, + download: `${serviceName}_${formatDateTimeForFilename( + new Date() + )}.log`, + style: { display: "none" }, + }); + anchor.click(); + }, + error: handleError, + }); + }; return ( - - } - /> +
+ + +
+ {`General ${status.service} info`} + +
+ {isDownloadLogsEnabled(status) && ( +
+ + downloadLogs(status.service, () => + errorMsgOpenSubject?.next(true) + ) + } + > + download logs + Download Logs + +
+ )} + + expand + +
+
+
+ + + +
+ + +
); }; diff --git a/src/dashboard/overview/ServiceDetailsContent.tsx b/src/dashboard/overview/ServiceDetailsContent.tsx index 61197f5..54216eb 100644 --- a/src/dashboard/overview/ServiceDetailsContent.tsx +++ b/src/dashboard/overview/ServiceDetailsContent.tsx @@ -18,6 +18,7 @@ import LabeledRow from "../../common/components/data-display/LabeledRow"; export type ServiceDetailsContentProps = { status: Status; closeDetails: () => void; + statusIcon: string; }; type InfoRow = { @@ -29,7 +30,8 @@ type InfoRow = { const useStyles = makeStyles((theme: Theme) => createStyles({ content: { - padding: 0, + padding: "20px", + backgroundColor: "#161616", }, textRow: { padding: theme.spacing(3), @@ -125,7 +127,7 @@ const createLndRows = (lndInfo: LndInfo): InfoRow[] => [ const ServiceDetailsContent = ( props: ServiceDetailsContentProps ): ReactElement => { - const { status, closeDetails } = props; + const { status, closeDetails, statusIcon } = props; const classes = useStyles(); const [rows, setRows] = useState([]); const [initialLoadComplete, setInitialLoadComplete] = useState(false); @@ -151,6 +153,7 @@ const ServiceDetailsContent = ( label={row.label} value={row.value} showCopyIcon={row.copyIcon} + statusIcon={row.label === "Status" ? statusIcon : ""} reserveSpaceForCopyIcon /> )) diff --git a/src/stories/OverviewItem.stories.tsx b/src/stories/OverviewItem.stories.tsx new file mode 100644 index 0000000..63d84d9 --- /dev/null +++ b/src/stories/OverviewItem.stories.tsx @@ -0,0 +1,19 @@ +import React from "react"; +import { storiesOf } from "@storybook/react"; +import OverviewItem from "../dashboard/overview/OverviewItem"; + +export type Status = { + service: string; + status: string; +}; + +storiesOf("Overview", module).add("OverviewItem", () => ( + +)); diff --git a/src/themes.ts b/src/themes.ts index fbd7c13..020dab7 100644 --- a/src/themes.ts +++ b/src/themes.ts @@ -13,6 +13,9 @@ export const darkTheme = createMuiTheme({ paper: "#151515", }, }, + typography: { + fontFamily: ["ApercuPro", "Arial", "sans-serif"].join(","), + }, }); export const tradeTheme = createMuiTheme({ From 55df1a8db4b93b269823b976e929e4e599ab2b04 Mon Sep 17 00:00:00 2001 From: scorebreaker Date: Mon, 12 Apr 2021 02:41:58 +0300 Subject: [PATCH 2/2] 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 --- src/assets/icon-collapse.svg | 16 +++ .../components/data-display/LabeledRow.tsx | 6 +- .../data-display/text/PageTitle.tsx | 47 ++++++++ src/common/utils/svgIcons.ts | 2 + src/dashboard/overview/Overview.tsx | 19 +-- src/dashboard/overview/OverviewItem.tsx | 113 +++++++++++++----- src/dashboard/overview/ServiceDetails.tsx | 62 +--------- 7 files changed, 160 insertions(+), 105 deletions(-) create mode 100644 src/assets/icon-collapse.svg create mode 100644 src/common/components/data-display/text/PageTitle.tsx diff --git a/src/assets/icon-collapse.svg b/src/assets/icon-collapse.svg new file mode 100644 index 0000000..4dff74e --- /dev/null +++ b/src/assets/icon-collapse.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/common/components/data-display/LabeledRow.tsx b/src/common/components/data-display/LabeledRow.tsx index 265e74b..8b8f2a9 100644 --- a/src/common/components/data-display/LabeledRow.tsx +++ b/src/common/components/data-display/LabeledRow.tsx @@ -7,15 +7,15 @@ import ButtonBase from "@material-ui/core/ButtonBase"; type LabeledRowProps = { label: string; value: string | number; - paddingSpacing?: number; showCopyIcon?: boolean; + padding?: string; reserveSpaceForCopyIcon?: boolean; statusIcon?: string; }; -const useStyles = makeStyles((theme) => ({ +const useStyles = makeStyles(() => ({ cell: (props: LabeledRowProps) => ({ - padding: theme.spacing(props.paddingSpacing ?? 2), + padding: props.padding ? props.padding : "15px 40px", wordWrap: "break-word", whiteSpace: "pre-wrap", fontSize: "16px", diff --git a/src/common/components/data-display/text/PageTitle.tsx b/src/common/components/data-display/text/PageTitle.tsx new file mode 100644 index 0000000..3ab9e67 --- /dev/null +++ b/src/common/components/data-display/text/PageTitle.tsx @@ -0,0 +1,47 @@ +import React, { ReactElement } from "react"; +import { Icon } from "@material-ui/core"; +import { makeStyles } from "@material-ui/core"; +import { notificationIcon } from "../../../utils/svgIcons"; + +type PageTitleProps = { + title: string; +}; + +const useStyles = makeStyles(() => ({ + headingContainer: { + display: "flex", + alignItems: "center", + }, + heading: { + fontSize: "30px", + fontWeight: 500, + }, + notificationIconContainer: { + marginLeft: "auto", + }, + notificationIcon: { + cursor: "pointer", + }, +})); + +const PageTitle = (props: PageTitleProps): ReactElement => { + const { title } = props; + const classes = useStyles(); + + return ( +
+

{title}

+ {false && ( + + notifications + + )} +
+ ); +}; + +export default PageTitle; diff --git a/src/common/utils/svgIcons.ts b/src/common/utils/svgIcons.ts index c3a2d2c..9f6aaeb 100644 --- a/src/common/utils/svgIcons.ts +++ b/src/common/utils/svgIcons.ts @@ -6,6 +6,7 @@ import copyIcon from "../../assets/icon-copy.svg"; import notificationIcon from "../../assets/icon-notification.svg"; import notificationActiveIcon from "../../assets/icon-notification-active.svg"; import downloadIcon from "../../assets/icon-download-log.svg"; +import collapseIcon from "../../assets/icon-collapse.svg"; export { openDexLogo, @@ -16,4 +17,5 @@ export { notificationIcon, notificationActiveIcon, downloadIcon, + collapseIcon, }; diff --git a/src/dashboard/overview/Overview.tsx b/src/dashboard/overview/Overview.tsx index bcdb8d4..d6d020c 100644 --- a/src/dashboard/overview/Overview.tsx +++ b/src/dashboard/overview/Overview.tsx @@ -1,4 +1,4 @@ -import { createStyles, withStyles, WithStyles, Icon } from "@material-ui/core"; +import { createStyles, withStyles, WithStyles } from "@material-ui/core"; import Grid from "@material-ui/core/Grid"; import { inject, observer } from "mobx-react"; import React, { ReactElement } from "react"; @@ -11,7 +11,7 @@ import DashboardContent, { DashboardContentState, } from "../DashboardContent"; import OverviewItem from "./OverviewItem"; -import { notificationIcon } from "../../common/utils/svgIcons"; +import PageTitle from "../../common/components/data-display/text/PageTitle"; type PropsType = DashboardContentProps & WithStyles; @@ -82,20 +82,7 @@ class Overview extends DashboardContent { return (
-
-

Overview

- this.handleSelectNotifications()} - className={classes.notificationIconContainer} - > - notifications - -
- + {this.state.initialLoadCompleted ? ( this.state.statuses && diff --git a/src/dashboard/overview/OverviewItem.tsx b/src/dashboard/overview/OverviewItem.tsx index 3e1160b..c57a821 100644 --- a/src/dashboard/overview/OverviewItem.tsx +++ b/src/dashboard/overview/OverviewItem.tsx @@ -1,4 +1,4 @@ -import { Icon, makeStyles, Theme } from "@material-ui/core"; +import { Icon, makeStyles } from "@material-ui/core"; import Card from "@material-ui/core/Card"; import CardContent from "@material-ui/core/CardContent"; import Grid from "@material-ui/core/Grid"; @@ -12,7 +12,13 @@ import { expandIcon, readyIcon, syncingIcon, + downloadIcon, } from "../../common/utils/svgIcons"; +import ButtonBase from "@material-ui/core/ButtonBase"; +import api from "../../api"; +import { formatDateTimeForFilename } from "../../common/utils/dateUtil"; +import { Subject } from "rxjs"; +import Snackbar from "../../common/components/data-display/feedback/Snackbar"; export type OverviewItemProps = { status: Status; @@ -21,14 +27,14 @@ export type OverviewItemProps = { }; const getCardHeaderBackgroundImage = (props: OverviewItemProps) => { - if (props.status.status.includes("Ready")) { + if (isServiceReady(props.status)) { return "linear-gradient(to right, #1f995a, #00e64d)"; } else { return "linear-gradient(to left, #fea900, #f15a24 0%)"; } }; -const useStyles = makeStyles((theme: Theme) => ({ +const useStyles = makeStyles(() => ({ cardHeader: (props: OverviewItemProps) => ({ padding: "12px 16px 12px 24px", backgroundImage: getCardHeaderBackgroundImage(props), @@ -56,19 +62,6 @@ const useStyles = makeStyles((theme: Theme) => ({ cardContentStatusValueText: { color: "#f2f2f2", }, - statusDot: { - height: 10, - width: 10, - borderRadius: "50%", - display: "inline-block", - marginRight: 10, - }, - active: { - backgroundColor: theme.palette.success.light, - }, - inactive: { - backgroundColor: theme.palette.error.light, - }, expandIcon: { cursor: "pointer", }, @@ -78,12 +71,28 @@ const useStyles = makeStyles((theme: Theme) => ({ statusIcon: { padding: "0 10px", }, + downloadIconContainer: { + fontSize: "14px", + color: "#000000", + textDecoration: "underline", + }, + detailsIconContainer: { + display: "flex", + justifyContent: "flex-end", + }, + titleAndLogsContainer: { + width: "66.6%", + display: "flex", + justifyContent: "space-between", + alignItems: "center", + }, })); const OverviewItem = (props: OverviewItemProps): ReactElement => { const { status, opendexdLocked, opendexdNotReady } = props; const [detailsOpen, setDetailsOpen] = useState(false); const classes = useStyles(props); + const errorMsgOpenSubject = new Subject(); const isDetailsIconVisible = (status: Status): boolean => { return ( @@ -95,28 +104,72 @@ const OverviewItem = (props: OverviewItemProps): ReactElement => { }; const getStatusIcon = (status: Status) => { - if (status.status.includes("Ready")) { + if (isServiceReady(status)) { return readyIcon; } else { return syncingIcon; } }; + const isDownloadLogsEnabled = (status: Status): boolean => { + return ( + !status.status.includes("light mode") && status.status !== "Disabled" + ); + }; + + const downloadLogs = (serviceName: string, handleError: () => void): void => { + api.logs$(serviceName).subscribe({ + next: (resp: string) => { + const blob = new Blob([resp]); + const url = URL.createObjectURL(blob); + const anchor = Object.assign(document.createElement("a"), { + href: url, + download: `${serviceName}_${formatDateTimeForFilename( + new Date() + )}.log`, + style: { display: "none" }, + }); + anchor.click(); + }, + error: handleError, + }); + }; + return (
- - - {props.status.service} - - +
+ + + {props.status.service} + + - + + {isDownloadLogsEnabled(status) && ( +
+ + downloadLogs(status.service, () => + errorMsgOpenSubject?.next(true) + ) + } + > + download logs + Download Logs + +
+ )} +
+
+ + {isDetailsIconVisible(status) && ( setDetailsOpen(true)} @@ -154,6 +207,12 @@ const OverviewItem = (props: OverviewItemProps): ReactElement => { titleBackground={getCardHeaderBackgroundImage(props)} /> )} + +
); }; diff --git a/src/dashboard/overview/ServiceDetails.tsx b/src/dashboard/overview/ServiceDetails.tsx index 8b35c93..6fd34bb 100644 --- a/src/dashboard/overview/ServiceDetails.tsx +++ b/src/dashboard/overview/ServiceDetails.tsx @@ -1,17 +1,13 @@ import { makeStyles, Theme } from "@material-ui/core"; import React, { ReactElement } from "react"; -import { Subject } from "rxjs"; import { drawerWidth } from "../../common/components/navigation/Menu"; import { Status } from "../../models/Status"; import ServiceDetailsContent from "./ServiceDetailsContent"; -import { formatDateTimeForFilename } from "../../common/utils/dateUtil"; -import api from "../../api"; import DialogTitle from "@material-ui/core/DialogTitle"; import Dialog from "@material-ui/core/Dialog"; import DialogContent from "@material-ui/core/DialogContent"; -import { downloadIcon, expandIcon } from "../../common/utils/svgIcons"; +import { collapseIcon } from "../../common/utils/svgIcons"; import ButtonBase from "@material-ui/core/ButtonBase"; -import Snackbar from "../../common/components/data-display/feedback/Snackbar"; export type ServiceDetailsProps = { status: Status; @@ -35,19 +31,13 @@ const useStyles = makeStyles((theme: Theme) => ({ fontSize: "18px", color: "#000000", }, - downloadIconContainer: { - paddingRight: "30px", - fontSize: "14px", - color: "#000000", - textDecoration: "underline", - }, dialogTitleContainer: (props: ServiceDetailsProps) => ({ backgroundImage: props.titleBackground, padding: "8px", }), dialogTitleContent: { display: "flex", - alignItems: "baseline", + alignItems: "center", padding: "5px 15px", }, logsAndCloseContainer: { @@ -63,31 +53,6 @@ const useStyles = makeStyles((theme: Theme) => ({ const ServiceDetails = (props: ServiceDetailsProps): ReactElement => { const { status, handleClose, statusIcon } = props; const classes = useStyles(props); - const errorMsgOpenSubject = new Subject(); - - const isDownloadLogsEnabled = (status: Status): boolean => { - return ( - !status.status.includes("light mode") && status.status !== "Disabled" - ); - }; - - const downloadLogs = (serviceName: string, handleError: () => void): void => { - api.logs$(serviceName).subscribe({ - next: (resp: string) => { - const blob = new Blob([resp]); - const url = URL.createObjectURL(blob); - const anchor = Object.assign(document.createElement("a"), { - href: url, - download: `${serviceName}_${formatDateTimeForFilename( - new Date() - )}.log`, - style: { display: "none" }, - }); - anchor.click(); - }, - error: handleError, - }); - }; return (
@@ -105,23 +70,8 @@ const ServiceDetails = (props: ServiceDetailsProps): ReactElement => { >{`General ${status.service} info`}
- {isDownloadLogsEnabled(status) && ( -
- - downloadLogs(status.service, () => - errorMsgOpenSubject?.next(true) - ) - } - > - download logs - Download Logs - -
- )} - expand + collapse
@@ -134,12 +84,6 @@ const ServiceDetails = (props: ServiceDetailsProps): ReactElement => { />
- - ); };