diff --git a/portal-ui/package.json b/portal-ui/package.json index 620315329..0bade166b 100644 --- a/portal-ui/package.json +++ b/portal-ui/package.json @@ -80,7 +80,7 @@ }, "proxy": "http://localhost:9090/", "devDependencies": { - "prettier": "2.3.1", - "typescript": "^4.3.2" + "prettier": "2.3.2", + "typescript": "^4.4.3" } } diff --git a/portal-ui/src/common/utils.ts b/portal-ui/src/common/utils.ts index 004f65b5f..3adeeeea3 100644 --- a/portal-ui/src/common/utils.ts +++ b/portal-ui/src/common/utils.ts @@ -508,7 +508,7 @@ export const calculateBytes = ( const bytes = parseInt(x, 10); if (bytes === 0) { - return { total: 0, unit: k8sCalcUnits[0] }; + return { total: 0, unit: units[0] }; } // Gi : GiB @@ -525,7 +525,7 @@ export const calculateBytes = ( // Get Unit parsed const unitParsed = parseFloat(roundedUnit.toFixed(fractionDigits)); - const finalUnit = k8sCalcUnits[i]; + const finalUnit = units[i]; return { total: unitParsed, unit: finalUnit }; }; diff --git a/portal-ui/src/screens/Console/Common/FormComponents/common/styleLibrary.ts b/portal-ui/src/screens/Console/Common/FormComponents/common/styleLibrary.ts index 3568c3134..49b8cd18c 100644 --- a/portal-ui/src/screens/Console/Common/FormComponents/common/styleLibrary.ts +++ b/portal-ui/src/screens/Console/Common/FormComponents/common/styleLibrary.ts @@ -730,3 +730,107 @@ export const inlineCheckboxes = { justifyContent: "flex-start", }, }; + +const commonStateIcon = { + marginRight: 10, + lineHeight: 1, + display: "inline-flex", + marginTop: 6 , +}; + +export const commonDashboardInfocard = { + cardIconContainer: { + display: "flex" as const, + position: "relative" as const, + alignItems: "center" as const, + }, + stateContainer: { + display: "flex" as const, + flexWrap: "wrap" as const, + justifyContent: "flex-start" as const, + }, + infoValue: { + fontWeight: 500, + color: "#07193E", + fontSize: 16, + margin: "8px 40px 5px 0", + display: "inline-flex" as const, + "& strong": { + marginRight: 4, + }, + "& .MuiSvgIcon-root": { + width: 20, + height: 20, + }, + alignItems: "center" as const, + }, + redState: { + color: "#F55B5B", + ...commonStateIcon, + }, + greenState: { + color: "#9FF281", + ...commonStateIcon, + }, + yellowState: { + color: "#F7A25A", + ...commonStateIcon, + }, + greyState: { + color: "grey", + ...commonStateIcon, + }, + healthStatusIcon: { + position: "absolute" as const, + fontSize: 8, + left: 18, + height: 10, + bottom: 2, + marginRight: 10, + "& .MuiSvgIcon-root": { + width: 5, + height: 5, + }, + }, + innerState: { + fontSize: 8, + display: "flex" as const, + alignItems: "center" as const, + marginTop: -3, + "& .MuiSvgIcon-root": { + marginTop: 5, + width: 10, + height: 10, + }, + }, + cardContainer: { + border: "#EEF1F4 2px solid", + borderRadius: 10, + boxShadow: "0 0 15px #00000029", + maxWidth: 1185, + marginBottom: 30, + }, + cardHeader: { + "& .MuiCardHeader-title": { + fontWeight: "bolder" as const, + }, + }, + cardNumber: { + color: "#848484", + fontSize: 16, + fontWeight: 400, + marginBottom: 10, + }, + referenceTitle: { + display: "flex", + alignItems: "center" as const, + lineHeight: 1, + fontWeight: "bold" as const, + textTransform: "capitalize" as const, + "& .MuiSvgIcon-root": { + width: 10, + height: 10, + marginTop: -5, + }, + }, +}; diff --git a/portal-ui/src/screens/Console/Common/GeneralUsePaginator/GeneralUsePaginator.tsx b/portal-ui/src/screens/Console/Common/GeneralUsePaginator/GeneralUsePaginator.tsx new file mode 100644 index 000000000..62d8ae387 --- /dev/null +++ b/portal-ui/src/screens/Console/Common/GeneralUsePaginator/GeneralUsePaginator.tsx @@ -0,0 +1,141 @@ +// This file is part of MinIO Console Server +// Copyright (c) 2021 MinIO, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +import React, { Fragment } from "react"; +import { + createStyles, + Theme, + withStyles, + makeStyles, +} from "@material-ui/core/styles"; +import Grid from "@material-ui/core/Grid"; +import Pagination from "@material-ui/lab/Pagination"; + +interface IGeneralUsePaginator { + classes: any; + page: number; + itemsPerPage?: number; + entity: string; + totalItems: number; + onChange: (newPage: number) => void; +} + +const styles = (theme: Theme) => + createStyles({ + paginatorContainer: { + margin: "10px 0 18px", + flexWrap: "wrap", + }, + paginatorInformation: { + color: "#848484", + fontSize: 12, + fontStyle: "italic", + whiteSpace: "nowrap", + }, + paginatorEntity: { + color: "#767676", + fontSize: 12, + fontWeight: "bold", + }, + paginationElement: { + display: "flex", + flexDirection: "row", + alignItems: "center", + justifyContent: "flex-end", + color: "#848484", + fontSize: 12, + }, + }); + +const paginatorStyling = makeStyles({ + ul: { + "& .MuiPaginationItem-root": { + color: "#07193E", + fontSize: 14, + "&.Mui-selected": { + backgroundColor: "transparent", + fontWeight: "bold", + "&::after": { + backgroundColor: "#07193E", + width: "100%", + height: 3, + content: '" "', + position: "absolute", + bottom: -3, + }, + }, + }, + }, +}); + +const GeneralUsePaginator = ({ + classes, + page = 1, + itemsPerPage = 5, + entity, + totalItems, + onChange, +}: IGeneralUsePaginator) => { + const paginatorStyles = paginatorStyling(); + + const currentInitialItem = page * itemsPerPage - itemsPerPage + 1; + const currentEndItem = currentInitialItem + itemsPerPage - 1; + const displayCurrentEndItem = + currentEndItem > totalItems ? totalItems : currentEndItem; + const totalPages = Math.ceil(totalItems / itemsPerPage); + + return ( + + + + {entity} +
+ + Showing{" "} + {totalPages > 1 ? ( + + {currentInitialItem} - {displayCurrentEndItem} out of{" "} + + ) : null} + {totalItems} Total {entity} + +
+ + {totalPages > 1 && ( + + Go to:{" "} + { + onChange(newPage); + }} + classes={{ ul: paginatorStyles.ul }} + /> + + )} + +
+
+ ); +}; + +export default withStyles(styles)(GeneralUsePaginator); diff --git a/portal-ui/src/screens/Console/Common/TabSelector/TabSelector.tsx b/portal-ui/src/screens/Console/Common/TabSelector/TabSelector.tsx new file mode 100644 index 000000000..086b288e2 --- /dev/null +++ b/portal-ui/src/screens/Console/Common/TabSelector/TabSelector.tsx @@ -0,0 +1,138 @@ +// This file is part of MinIO Console Server +// Copyright (c) 2021 MinIO, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +import React, { Fragment } from "react"; +import { + createStyles, + Theme, + withStyles, + makeStyles, +} from "@material-ui/core/styles"; +import Tabs from "@material-ui/core/Tabs"; +import Tab from "@material-ui/core/Tab"; +import { ITabOption } from "./types"; + +interface ITabSelector { + selectedTab: number; + onChange: (newValue: number) => void; + tabOptions: ITabOption[]; + classes: any; +} + +const styles = (theme: Theme) => + createStyles({ + cardsContainer: { + maxHeight: 440, + overflowY: "auto", + overflowX: "hidden", + }, + generalStatusCards: { + display: "flex", + flexDirection: "row", + flexWrap: "wrap", + }, + generalStatusTitle: { + color: "#767676", + fontSize: 16, + fontWeight: "bold", + margin: "15px 10px 0 10px", + }, + }); + +const tabSubStyles = makeStyles({ + root: { + backgroundColor: "transparent", + paddingTop: 0, + paddingBottom: 0, + }, + wrapper: { fontSize: 22, textTransform: "uppercase", color: "#D0D0D0" }, + selected: { "& .MuiTab-wrapper": { color: "#07193E", fontWeight: "bold" } }, + indicator: { + background: + "transparent linear-gradient(90deg, #072B4E 0%, #081C42 100%) 0% 0% no-repeat padding-box;", + height: 4, + }, + scroller: { + maxWidth: 1185, + position: "relative", + "&::after": { + content: '" "', + backgroundColor: "#EEF1F4", + height: 4, + width: "100%", + display: "block", + }, + }, +}); + +const TabSelector = ({ + selectedTab, + onChange, + tabOptions, + classes, +}: ITabSelector) => { + const subStyles = tabSubStyles(); + + return ( + + , newValue: number) => { + onChange(newValue); + }} + classes={{ + indicator: subStyles.indicator, + scroller: subStyles.scroller, + }} + > + {tabOptions.map((option, index) => { + let tabOptions: ITabOption = { + label: option.label, + }; + + if (option.value) { + tabOptions = { ...tabOptions, value: option.value }; + } + + if (option.disabled) { + tabOptions = { ...tabOptions, disabled: option.disabled }; + } + + return ( + + ); + })} + + + ); +}; + +export default withStyles(styles)(TabSelector); diff --git a/portal-ui/src/screens/Console/Common/TabSelector/types.ts b/portal-ui/src/screens/Console/Common/TabSelector/types.ts new file mode 100644 index 000000000..7717fa924 --- /dev/null +++ b/portal-ui/src/screens/Console/Common/TabSelector/types.ts @@ -0,0 +1,21 @@ +// This file is part of MinIO Console Server +// Copyright (c) 2021 MinIO, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +export interface ITabOption { + label: string; + value?: string; + disabled?: boolean; +} diff --git a/portal-ui/src/screens/Console/Dashboard/BasicDashboard/BasicDashboard.tsx b/portal-ui/src/screens/Console/Dashboard/BasicDashboard/BasicDashboard.tsx index 8f8f6703d..bba14a1e3 100644 --- a/portal-ui/src/screens/Console/Dashboard/BasicDashboard/BasicDashboard.tsx +++ b/portal-ui/src/screens/Console/Dashboard/BasicDashboard/BasicDashboard.tsx @@ -14,44 +14,42 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -import React, { Fragment } from "react"; +import React, { Fragment, useState } from "react"; import { createStyles, Theme, withStyles } from "@material-ui/core/styles"; import Grid from "@material-ui/core/Grid"; -import Typography from "@material-ui/core/Typography"; -import { Usage } from "../types"; -import { niceBytes } from "../../../../common/utils"; +import { IDriveInfo, Usage } from "../types"; +import { calculateBytes } from "../../../../common/utils"; +import { TabPanel } from "../../../shared/tabs"; import ReportedUsageIcon from "../../../../icons/ReportedUsageIcon"; import ServerInfoCard from "./ServerInfoCard"; import DriveInfoCard from "./DriveInfoCard"; -import { - BucketsIcon, - ServersIcon, - StorageIcon, - TotalObjectsIcon, - VersionIcon, -} from "../../../../icons"; -import { Card, CardHeader } from "@material-ui/core"; +import { BucketsIcon, TotalObjectsIcon } from "../../../../icons"; +import CommonCard from "../CommonCard"; +import TabSelector from "../../Common/TabSelector/TabSelector"; +import GeneralUsePaginator from "../../Common/GeneralUsePaginator/GeneralUsePaginator"; const styles = (theme: Theme) => createStyles({ - dashboardBG: { - width: 390, - height: 255, - zIndex: -1, - position: "fixed", - backgroundSize: "fill", - backgroundImage: "url(/images/BG_IllustrationDarker.svg)", - backgroundPosition: "right bottom", - right: 0, - bottom: 0, - backgroundRepeat: "no-repeat", - }, - cardsContainer: { maxHeight: 440, overflowY: "auto", overflowX: "hidden", }, + generalStatusCards: { + display: "flex", + flexDirection: "row", + flexWrap: "wrap", + }, + generalStatusTitle: { + color: "#767676", + fontSize: 16, + fontWeight: "bold", + margin: "15px 10px 0 10px", + }, + paginatorContainer: { + maxWidth: 1185, + width: "100%", + }, }); interface IDashboardProps { @@ -59,24 +57,21 @@ interface IDashboardProps { usage: Usage | null; } +const itemsPerPage = 5; + const BasicDashboard = ({ classes, usage }: IDashboardProps) => { + const [curTab, setCurTab] = useState(0); + const [serversPageNumber, setServersPageNumber] = useState(1); + const [drivesPageNumber, setDrivesPageNumber] = useState(1); + const prettyUsage = (usage: string | undefined) => { if (usage === undefined) { - return "0"; + return { total: "0", unit: "Mi" }; } - const niceBytesUsage = niceBytes(usage).split(" "); + const calculatedBytes = calculateBytes(usage); - if (niceBytesUsage.length !== 2) { - return niceBytesUsage.join(" "); - } - - return ( - - {niceBytesUsage[0]} - {niceBytesUsage[1]} - - ); + return calculatedBytes; }; const prettyNumber = (usage: number | undefined) => { @@ -105,95 +100,101 @@ const BasicDashboard = ({ classes, usage }: IDashboardProps) => { const serverArray = makeServerArray(usage); + const usageToRepresent = prettyUsage(usage ? usage.usage.toString() : "0"); + + let allDrivesArray: IDriveInfo[] = []; + + serverArray.forEach((server) => { + const drivesInput = server.drives.map((drive) => { + return drive; + }); + + allDrivesArray = [...allDrivesArray, ...drivesInput]; + }); + + const splitedServers = serverArray.slice( + serversPageNumber * itemsPerPage - itemsPerPage, + serversPageNumber * itemsPerPage + ); + + const splitedDrives = allDrivesArray.slice( + drivesPageNumber * itemsPerPage - itemsPerPage, + drivesPageNumber * itemsPerPage + ); + return (
- - - - - } - title="Number of Buckets" - subheader={usage ? prettyNumber(usage.buckets) : 0} - /> - - - - - } - title="Usage" - subheader={usage ? prettyUsage(usage.usage + "") : 0} - /> - - - - - } - title="Total Objects" - subheader={usage ? prettyNumber(usage.objects) : 0} - /> - - - - - - {usage - ? usage.servers.length !== 0 && ( - } - title="MinIO Version" - subheader={usage ? usage.servers[0].version : 0} - /> - ) - : 0} - - - - - - - - - - - - Drives Status - - - - {serverArray.map((server, index) => - server.drives.map((drive) => ( - - - - )) - )} - - + + General Status - - - - - - - Servers Status - - - - {serverArray.map((server, index) => ( - - + + } + title={"All Buckets"} + metricValue={usage ? prettyNumber(usage.buckets) : 0} + /> + } + title={"Usage"} + metricValue={usageToRepresent.total} + metricUnit={usageToRepresent.unit} + /> + } + title={"Total Objects"} + metricValue={usage ? prettyNumber(usage.objects) : 0} + /> + } + title={"Servers"} + metricValue={usage ? prettyNumber(serverArray.length) : 0} + subMessage={{ message: "Total" }} + /> + + + { + setCurTab(newValue); + }} + tabOptions={[{ label: "Servers" }, { label: "Drives" }]} + /> + + + +
+ +
+ {splitedServers.map((server, index) => ( + + ))} -
+ + +
+ +
+ {splitedDrives.map((drive, index) => ( + + + + ))} +
diff --git a/portal-ui/src/screens/Console/Dashboard/BasicDashboard/DriveInfoCard.tsx b/portal-ui/src/screens/Console/Dashboard/BasicDashboard/DriveInfoCard.tsx index a84d71cbe..55524d38e 100644 --- a/portal-ui/src/screens/Console/Dashboard/BasicDashboard/DriveInfoCard.tsx +++ b/portal-ui/src/screens/Console/Dashboard/BasicDashboard/DriveInfoCard.tsx @@ -20,65 +20,12 @@ import Grid from "@material-ui/core/Grid"; import { IDriveInfo } from "../types"; import { niceBytes } from "../../../../common/utils"; import { Card, CardHeader } from "@material-ui/core"; -import { CircleIcon, StorageIcon } from "../../../../icons"; +import { CircleIcon } from "../../../../icons"; +import { commonDashboardInfocard } from "../../Common/FormComponents/common/styleLibrary"; const styles = (theme: Theme) => createStyles({ - cardIconContainer: { - display: "flex", - position: "relative", - alignItems: "center", - }, - stateContainer: { - display: "flex", - flexWrap: "wrap", - justifyContent: "space-between", - }, - infoValue: { - fontWeight: 500, - color: "#777777", - fontSize: 14, - margin: "5px 4px", - display: "inline-flex", - "& strong": { - marginRight: 4, - }, - }, - redState: { - color: theme.palette.error.main, - }, - greenState: { - color: theme.palette.success.main, - }, - yellowState: { - color: theme.palette.warning.main, - }, - greyState: { - color: "grey", - }, - healthStatusIcon: { - position: "absolute", - fontSize: 10, - left: 18, - height: 10, - bottom: 2, - "& .MuiSvgIcon-root": { - width: 10, - height: 10, - }, - }, - innerState: { - fontSize: 10, - marginLeft: 5, - display: "flex", - alignItems: "center", - marginTop: -3, - }, - cardHeader: { - "& .MuiCardHeader-title": { - fontWeight: "bolder", - }, - }, + ...commonDashboardInfocard, }); interface ICardProps { @@ -100,22 +47,19 @@ const DriveInfoCard = ({ classes, drive }: ICardProps) => { return ( - + - -
- {drive.state && ( - - - - )} -
+ title={ +
+ {drive.state && ( + + + + )} + {drive.endpoint || ""}
} - title={drive.endpoint || ""} subheader={ diff --git a/portal-ui/src/screens/Console/Dashboard/BasicDashboard/ServerInfoCard.tsx b/portal-ui/src/screens/Console/Dashboard/BasicDashboard/ServerInfoCard.tsx index 63b9c613d..47dd0d082 100644 --- a/portal-ui/src/screens/Console/Dashboard/BasicDashboard/ServerInfoCard.tsx +++ b/portal-ui/src/screens/Console/Dashboard/BasicDashboard/ServerInfoCard.tsx @@ -16,83 +16,28 @@ import React from "react"; import { createStyles, Theme, withStyles } from "@material-ui/core/styles"; -import ComputerIcon from "@material-ui/icons/Computer"; import Grid from "@material-ui/core/Grid"; import { ServerInfo } from "../types"; import { niceDays } from "../../../../common/utils"; import { Card, CardHeader } from "@material-ui/core"; -import { CircleIcon } from "../../../../icons"; +import { CircleIcon, VersionIcon } from "../../../../icons"; import get from "lodash/get"; +import { commonDashboardInfocard } from "../../Common/FormComponents/common/styleLibrary"; + + const styles = (theme: Theme) => createStyles({ - cardIconContainer: { - display: "flex", - position: "relative", - alignItems: "center", - }, - stateContainer: { - display: "flex", - flexWrap: "wrap", - justifyContent: "space-between", - }, - infoValue: { - fontWeight: 500, - color: "#777777", - fontSize: 14, - margin: "5px 4px", - display: "inline-flex", - "& strong": { - marginRight: 4, - }, - "& .MuiSvgIcon-root": { - width: 16, - height: 16, - }, - }, - redState: { - color: theme.palette.error.main, - }, - greenState: { - color: theme.palette.success.main, - }, - yellowState: { - color: theme.palette.warning.main, - }, - greyState: { - color: "grey", - }, - healthStatusIcon: { - position: "absolute", - fontSize: 10, - left: 18, - height: 10, - bottom: 2, - "& .MuiSvgIcon-root": { - width: 10, - height: 10, - }, - }, - innerState: { - fontSize: 10, - marginLeft: 5, - display: "flex", - alignItems: "center", - marginTop: -3, - }, - cardHeader: { - "& .MuiCardHeader-title": { - fontWeight: "bolder", - }, - }, + ...commonDashboardInfocard, }); interface ICardProps { classes: any; server: ServerInfo; + index: number; } -const ServerInfoCard = ({ classes, server }: ICardProps) => { +const ServerInfoCard = ({ classes, server, index }: ICardProps) => { const serverStatusToClass = (health_status: string) => { switch (health_status) { case "offline": @@ -122,26 +67,25 @@ const ServerInfoCard = ({ classes, server }: ICardProps) => { : 0; return ( - + - -
+ title={ +
+
Server {index}
+
{server.state && ( )} + {server.endpoint || ""}
} - title={server.endpoint || ""} subheader={ - Drives: {activeDisks}/{totalDrives}{" "} { > + Drives: {activeDisks}/{totalDrives}{" "} - Network: {activeNetwork}/{networkTotal}{" "} { > + Network: {activeNetwork}/{networkTotal}{" "} - Uptime:{" "} - {server.uptime ? niceDays(server.uptime) : "N/A"} + Uptime: {server.uptime ? niceDays(server.uptime) : "N/A"} + + + + Version {server.version ? server.version : "N/A"} } diff --git a/portal-ui/src/screens/Console/Dashboard/CommonCard.tsx b/portal-ui/src/screens/Console/Dashboard/CommonCard.tsx new file mode 100644 index 000000000..4b3c2c18a --- /dev/null +++ b/portal-ui/src/screens/Console/Dashboard/CommonCard.tsx @@ -0,0 +1,190 @@ +// This file is part of MinIO Console Server +// Copyright (c) 2021 MinIO, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +import { Card, CardHeader } from "@material-ui/core"; +import { Link } from "react-router-dom"; +import { + createStyles, + Theme, + withStyles, + makeStyles, +} from "@material-ui/core/styles"; +import React, { Fragment } from "react"; + +export interface ISubInterface { + message: string; + fontWeight?: "normal" | "bold"; +} + +interface ICommonCard { + avatar: any; + title: string; + metricValue: any; + metricUnit?: string; + subMessage?: ISubInterface; + moreLink?: string; + rightComponent?: any; + classes: any; +} + +const styles = (theme: Theme) => + createStyles({ + cardRoot: { + border: "#eef1f4 2px solid", + borderRadius: 10, + maxWidth: 280, + width: "100%", + margin: 10, + }, + cardsContainer: { + maxHeight: 440, + overflowY: "auto", + overflowX: "hidden", + }, + metricText: { + fontSize: 70, + lineHeight: 1.1, + color: "#07193E", + fontWeight: "bold", + }, + unitText: { + fontSize: 10, + color: "#767676", + fontWeight: "normal", + }, + subHearderContainer: { + display: "flex", + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center", + }, + subMessage: { + fontSize: 10, + color: "#767676", + "&.bold": { + fontWeight: "bold", + }, + }, + headerContainer: { + display: "flex", + justifyContent: "space-between", + }, + viewAll: { + fontSize: 10, + color: "#C83B51", + textTransform: "capitalize", + + "& a, & a:hover, & a:visited, & a:active": { + color: "#C83B51", + }, + }, + }); + +const cardSubStyles = makeStyles({ + root: { backgroundColor: "#fff" }, + title: { + color: "#404144", + fontSize: 14, + textTransform: "uppercase", + fontWeight: "bold", + borderBottom: "#eef1f4 1px solid", + paddingBottom: 14, + marginBottom: 5, + }, + content: { + maxWidth: "100%", + }, +}); + +const CommonCard = ({ + avatar, + title, + metricValue, + metricUnit, + subMessage, + moreLink, + rightComponent, + classes, +}: ICommonCard) => { + const subStyles = cardSubStyles(); + const SubHeader = () => { + return ( + +
+
+
+ + {metricValue} + {metricUnit} + +
+ {subMessage && ( +
+ {subMessage.message} +
+ )} +
+
{rightComponent}
+
+
+ ); + }; + + const Header = () => { + return ( + +
+ {title} + {moreLink && ( + + + View All + + + )} +
+
+ ); + }; + + return ( + + + {metricValue !== "" && ( + } + subheader={ + + + + } + classes={{ + root: subStyles.root, + title: subStyles.title, + content: subStyles.content, + }} + /> + )} + + + ); +}; + +export default withStyles(styles)(CommonCard); diff --git a/portal-ui/src/screens/Console/Dashboard/Prometheus/Widgets/SimpleWidget.tsx b/portal-ui/src/screens/Console/Dashboard/Prometheus/Widgets/SimpleWidget.tsx new file mode 100644 index 000000000..c36ad27fd --- /dev/null +++ b/portal-ui/src/screens/Console/Dashboard/Prometheus/Widgets/SimpleWidget.tsx @@ -0,0 +1,60 @@ +// This file is part of MinIO Console Server +// Copyright (c) 2021 MinIO, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +import React from "react"; +import { createStyles, Theme, withStyles } from "@material-ui/core/styles"; + +interface ISimpleWidget { + classes: any; + iconWidget: any; + label: string; + value: string; +} + +const styles = (theme: Theme) => + createStyles({ + mainWidgetContainer: { + display: "inline-flex", + color: "#072A4D", + alignItems: "center", + }, + icon: { + color: "#072A4D", + fill: "#072A4D", + marginRight: 5, + marginLeft: 12, + }, + widgetLabel: { + fontWeight: "bold", + textTransform: "uppercase", + marginRight: 10, + }, + widgetValue: { + marginRight: 25, + } + }); + +const SimpleWidget = ({ classes, iconWidget, label, value }: ISimpleWidget) => { + return ( + + {iconWidget ? iconWidget : null} + {label}: + {value} + + ); +}; + +export default withStyles(styles)(SimpleWidget); diff --git a/portal-ui/src/screens/Console/Tenants/TenantDetails/hop/Hop.tsx b/portal-ui/src/screens/Console/Tenants/TenantDetails/hop/Hop.tsx index 197d0ba0a..4d602b14c 100644 --- a/portal-ui/src/screens/Console/Tenants/TenantDetails/hop/Hop.tsx +++ b/portal-ui/src/screens/Console/Tenants/TenantDetails/hop/Hop.tsx @@ -106,7 +106,7 @@ const Hop = ({ classes, match }: IHopSimple) => { const next = `${loc}${add}cp=y`; consoleFrame.current.contentDocument.location.replace(next); } else { - consoleFrame.current.contentDocument.location.reload(true); + consoleFrame.current.contentDocument.location.reload(); } } }} diff --git a/portal-ui/yarn.lock b/portal-ui/yarn.lock index e874d8028..f4ed30cb5 100644 --- a/portal-ui/yarn.lock +++ b/portal-ui/yarn.lock @@ -9306,10 +9306,10 @@ prepend-http@^1.0.0: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= -prettier@2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.1.tgz#76903c3f8c4449bc9ac597acefa24dc5ad4cbea6" - integrity sha512-p+vNbgpLjif/+D+DwAZAbndtRrR0md0MwfmOVN9N+2RgyACMT+7tfaRnT+WDPkqnuVwleyuBIG2XBxKDme3hPA== +prettier@2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.2.tgz#ef280a05ec253712e486233db5c6f23441e7342d" + integrity sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ== pretty-bytes@^5.3.0: version "5.6.0" @@ -11499,10 +11499,10 @@ typeface-roboto@^0.0.75: resolved "https://registry.yarnpkg.com/typeface-roboto/-/typeface-roboto-0.0.75.tgz#98d5ba35ec234bbc7172374c8297277099cc712b" integrity sha512-VrR/IiH00Z1tFP4vDGfwZ1esNqTiDMchBEXYY9kilT6wRGgFoCAlgkEUMHb1E3mB0FsfZhv756IF0+R+SFPfdg== -typescript@^4.3.2: - version "4.3.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.2.tgz#399ab18aac45802d6f2498de5054fcbbe716a805" - integrity sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw== +typescript@^4.4.3: + version "4.4.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.3.tgz#bdc5407caa2b109efd4f82fe130656f977a29324" + integrity sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA== unbox-primitive@^1.0.1: version "1.0.1"