UX Basic Dashboard (#1799)

This commit is contained in:
Prakash Senthil Vel
2022-04-06 05:48:35 +00:00
committed by GitHub
parent f30450c3c1
commit 4647671f07
7 changed files with 370 additions and 286 deletions

View File

@@ -959,7 +959,7 @@ const commonStateIcon = {
marginTop: 6,
};
export const commonDashboardInfocard = {
export const commonDashboardInfocard: any = {
cardIconContainer: {
display: "flex" as const,
position: "relative" as const,

View File

@@ -32,21 +32,14 @@ import ServersList from "./ServersList";
import CounterCard from "./CounterCard";
import ReportedUsage from "./ReportedUsage";
const BoxItem = ({
children,
background = "#ffffff",
}: {
children: any;
background?: string;
}) => {
const BoxItem = ({ children }: { children: any }) => {
return (
<Box
sx={{
border: "1px solid #f1f1f1",
background: background,
padding: "25px",
maxWidth: {
sm: "100%",
xs: "250px",
},
}}
>
@@ -204,22 +197,14 @@ const BasicDashboard = ({ usage }: IDashboardProps) => {
gap: "40px",
}}
>
<BoxItem
background={
"linear-gradient(-15deg, #2781b0 0%, #ffffff 30%) 0% 0% no-repeat padding-box"
}
>
<BoxItem>
<CounterCard
label={"Buckets"}
icon={<BucketsIcon />}
counterValue={usage ? representationNumber(usage.buckets) : 0}
/>
</BoxItem>
<BoxItem
background={
"linear-gradient(-15deg, #4CCB92 0%, #ffffff 30%) 0% 0% no-repeat padding-box"
}
>
<BoxItem>
<CounterCard
label={"Objects"}
icon={<TotalObjectsIcon />}
@@ -259,9 +244,7 @@ const BasicDashboard = ({ usage }: IDashboardProps) => {
gap: "auto",
}}
>
<BoxItem>
<ServersList data={serverList} />
</BoxItem>
<ServersList data={serverList} />
</Box>
</Box>
</Box>

View File

@@ -32,19 +32,20 @@ const CounterCard = ({
fontFamily: "Lato,sans-serif",
color: "#07193E",
maxWidth: "300px",
minHeight: "200px",
minHeight: "143px",
display: "flex",
marginLeft: "auto",
marginRight: "auto",
cursor: "default",
position: "relative",
width: "100%",
//marginLeft: "25px",
}}
>
<Box
sx={{
flex: 1,
height: "200px",
minHeight: "200px",
display: "flex",
width: "100%",
padding: {
@@ -59,7 +60,7 @@ const CounterCard = ({
flex: 1,
display: "flex",
flexFlow: "column",
marginTop: "32px",
marginTop: "22px",
zIndex: 10,
overflow: "hidden",
}}
@@ -78,10 +79,10 @@ const CounterCard = ({
sx={{
fontSize: {
xl: "55px",
lg: "40px",
lg: "50px",
md: "36px",
sm: "22px",
xs: "14px",
sm: "35px",
xs: "35px",
},
fontWeight: 600,
overflow: "hidden",
@@ -90,6 +91,10 @@ const CounterCard = ({
md: 187,
xs: 200,
},
flexFlow: {
md: "row",
xs: "column",
},
}}
>
{counterValue}

View File

@@ -19,9 +19,10 @@ import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import { IDriveInfo } from "../types";
import { niceBytes } from "../../../../common/utils";
import { niceBytes, niceBytesInt } from "../../../../common/utils";
import { Box } from "@mui/material";
import { CircleIcon, DrivesIcon } from "../../../../icons";
import { Cell, Pie, PieChart } from "recharts";
import { CircleIcon } from "../../../../icons";
import { commonDashboardInfocard } from "../../Common/FormComponents/common/styleLibrary";
import { STATUS_COLORS } from "./Utils";
@@ -46,7 +47,15 @@ const driveStatusColor = (health_status: string) => {
}
};
const DriveInfoItem = ({ classes, drive }: ICardProps) => {
const DriveInfoItem = ({ drive }: ICardProps) => {
const plotValues = [
{ value: drive.totalSpace, color: "#D6D6D6", label: "Free Space" },
{
value: drive.usedSpace,
color: "#073052",
label: "Used Space",
},
];
return (
<Box
sx={{
@@ -54,21 +63,10 @@ const DriveInfoItem = ({ classes, drive }: ICardProps) => {
flex: 1,
alignItems: "center",
paddingBottom: "10px",
borderBottom: {
xs: "1px solid #eaeaea",
},
padding: "20px",
border: "1px solid #eaeaea",
}}
>
<Box
sx={{
"& .min-icon": {
fill: "#848484",
},
}}
>
<DrivesIcon />
</Box>
<Box
sx={{
display: "flex",
@@ -97,15 +95,17 @@ const DriveInfoItem = ({ classes, drive }: ICardProps) => {
textOverflow: "ellipsis",
whiteSpace: "normal",
wordBreak: "break-all",
marginRight: "8px",
fontWeight: 600,
fontSize: {
md: "14px",
md: "16px",
xs: "10px",
},
},
}}
>
{drive.state && <CircleIcon />}
<div className="drive-endpoint">{drive.endpoint || ""}</div>
{drive.state && <CircleIcon />}
</Box>
<Box
@@ -113,7 +113,6 @@ const DriveInfoItem = ({ classes, drive }: ICardProps) => {
flex: 1,
display: "flex",
alignItems: "center",
justifyContent: "space-between",
paddingLeft: "20px",
marginTop: "10px",
flexFlow: {
@@ -121,50 +120,105 @@ const DriveInfoItem = ({ classes, drive }: ICardProps) => {
xs: "column",
},
"& .info-label": {
color: "#8399AB",
color: "#5E5E5E",
fontSize: "12px",
textAlign: "center",
},
"& .info-value": {
color: "#073052",
fontSize: "14px",
fontSize: "18px",
color: "#07193E",
display: "flex",
fontWeight: 500,
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
},
}}
>
<Box
sx={{
display: "flex",
flexFlow: "column",
}}
>
<label className="info-label">Capacity:</label>
<div className="info-value">
{niceBytes(drive.totalSpace ? drive.totalSpace.toString() : "0")}
<Box sx={{ flex: 1 }}>
<div style={{ position: "relative", width: 110, height: 110 }}>
<span
style={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
fontWeight: "bold",
color: "#000",
fontSize: 12,
}}
>
{niceBytesInt(drive.usedSpace)}
</span>
<div>
<PieChart width={110} height={110}>
<Pie
data={plotValues}
cx={"50%"}
cy={"50%"}
dataKey="value"
outerRadius={50}
innerRadius={40}
startAngle={-70}
endAngle={360}
animationDuration={1}
>
{plotValues.map((entry, index) => (
<Cell key={`cellCapacity-${index}`} fill={entry.color} />
))}
</Pie>
</PieChart>
</div>
</div>
</Box>
<Box
sx={{
display: "flex",
flexFlow: "column",
gap: "5%",
alignItems: "center",
flex: 2,
flexGrow: 1,
}}
>
<label className="info-label">Used:</label>
<div className="info-value">
{niceBytes(drive.usedSpace ? drive.usedSpace.toString() : "0")}
</div>
</Box>
<Box
sx={{
display: "flex",
flexFlow: "column",
}}
>
<label className="info-label">Available:</label>
<div className="info-value">
{niceBytes(
drive.availableSpace ? drive.availableSpace.toString() : "0"
)}
</div>
<Box
sx={{
display: "flex",
flexFlow: "column",
}}
>
<div className="info-value">
{niceBytes(
drive.totalSpace ? drive.totalSpace.toString() : "0"
)}
</div>
<label className="info-label">Capacity</label>
</Box>
<Box
sx={{
display: "flex",
flexFlow: "column",
}}
>
<div className="info-value">
{niceBytes(drive.usedSpace ? drive.usedSpace.toString() : "0")}
</div>
<label className="info-label">Used</label>
</Box>
<Box
sx={{
display: "flex",
flexFlow: "column",
}}
>
<div className="info-value">
{niceBytes(
drive.availableSpace ? drive.availableSpace.toString() : "0"
)}
</div>
<label className="info-label">Available</label>
</Box>
</Box>
</Box>
</Box>

View File

@@ -20,13 +20,7 @@ import withStyles from "@mui/styles/withStyles";
import { ServerInfo } from "../types";
import { niceDays } from "../../../../common/utils";
import { Box } from "@mui/material";
import {
CircleIcon,
DrivesIcon,
UptimeIcon,
VersionIcon,
WarpIcon,
} from "../../../../icons";
import { CircleIcon } from "../../../../icons";
import get from "lodash/get";
import { commonDashboardInfocard } from "../../Common/FormComponents/common/styleLibrary";
import {
@@ -51,77 +45,82 @@ const ServerStatItem = ({
value = "",
statusColor = "",
hasStatus = false,
icon = null,
}: {
label?: string;
value?: any;
hasStatus?: boolean;
statusColor: string | undefined;
icon?: any;
}) => {
return (
<Box
sx={{
alignItems: "center",
alignItems: "baseline",
padding: "5px",
display: "flex",
gap: "10px",
gap: "5px",
}}
>
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "center",
flexFlow: "column",
maxWidth: "40px",
"&:first-of-type(svg)": {
fill: "#848484",
},
}}
>
{icon}
{hasStatus ? (
<Box
sx={{
marginRight: "0px",
justifyContent: "center",
alignItems: "center",
textAlign: "center",
"& svg.min-icon": {
fill: statusColor,
width: "10px",
height: "10px",
},
}}
>
<CircleIcon />
</Box>
) : (
<Box sx={{ width: "12px", height: "12px" }} />
)}
</Box>
<Box
sx={{
display: "flex",
alignItems: "flex-start",
justifyContent: "flex-start",
flexFlow: "column",
"& .stat-text": { color: "#5E5E5E", fontSize: "14px" },
"& .stat-text": { color: "#5E5E5E", fontSize: "12px" },
"& .stat-value": {
fontSize: "18px",
color: "#07193E",
display: "flex",
fontWeight: 500,
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
},
}}
>
<div className="stat-value">
{value}{" "}
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "center",
flexFlow: "column",
marginLeft: "5px",
maxWidth: "40px",
"&:first-of-type(svg)": {
fill: "#848484",
},
}}
>
{hasStatus ? (
<Box
sx={{
marginRight: "0px",
justifyContent: "center",
alignItems: "center",
textAlign: "center",
"& svg.min-icon": {
fill: statusColor,
width: "10px",
height: "10px",
},
}}
>
<CircleIcon />
</Box>
) : (
<Box sx={{ width: "12px", height: "12px" }} />
)}
</Box>
</div>
<div className="stat-text">{label}</div>
<div className="stat-value">{value}</div>
</Box>
</Box>
);
};
const ServerInfoItem = ({ classes = {}, server, index }: ICardProps) => {
const ServerInfoItem = ({ server }: ICardProps) => {
const networkKeys = Object.keys(get(server, "network", {}));
const networkTotal = networkKeys.length;
const totalDrives = server.drives ? server.drives.length : 0;
@@ -144,36 +143,6 @@ const ServerInfoItem = ({ classes = {}, server, index }: ICardProps) => {
flex: 1,
}}
>
<Box
sx={{
display: "flex",
alignItems: "center",
marginBottom: "15px",
}}
>
{server?.state && (
<Box
sx={{
marginRight: "8px",
"& .min-icon": {
fill: serverStatusColor(server.state),
height: "14px",
width: "14px",
},
}}
>
<CircleIcon />
</Box>
)}
<Box
sx={{
fontWeight: 600,
textTransform: "none",
}}
>
{server.endpoint || ""}
</Box>
</Box>
<Box
sx={{
display: "flex",
@@ -190,32 +159,70 @@ const ServerInfoItem = ({ classes = {}, server, index }: ICardProps) => {
},
}}
>
<ServerStatItem
statusColor={getDriveStatusColor(activeDisks, totalDrives)}
label={"Drives"}
icon={<DrivesIcon />}
hasStatus={true}
value={`${activeDisks}/${totalDrives}`}
/>
<ServerStatItem
statusColor={getNetworkStatusColor(activeNetwork, networkTotal)}
label={"Network"}
icon={<WarpIcon />}
hasStatus={true}
value={`${activeNetwork}/${networkTotal}`}
/>
<Box
sx={{
display: "flex",
alignItems: "center",
}}
>
<Box
sx={{
fontWeight: 600,
textTransform: "none",
}}
>
{server.endpoint || ""}
</Box>
{server?.state && (
<Box
sx={{
marginLeft: "8px",
"& .min-icon": {
fill: serverStatusColor(server.state),
height: "14px",
width: "14px",
},
}}
>
<CircleIcon />
</Box>
)}
</Box>
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "center",
flex: "1.5",
gap: {
md: "5%",
xs: "5%",
},
}}
>
<ServerStatItem
statusColor={getDriveStatusColor(activeDisks, totalDrives)}
label={"Drives"}
hasStatus={true}
value={`${activeDisks}/${totalDrives}`}
/>
<ServerStatItem
statusColor={getNetworkStatusColor(activeNetwork, networkTotal)}
label={"Network"}
hasStatus={true}
value={`${activeNetwork}/${networkTotal}`}
/>
<ServerStatItem
statusColor={"green"}
label={"Up time"}
value={server?.uptime ? niceDays(server.uptime) : "N/A"}
/>
</Box>
<ServerStatItem
statusColor={"green"}
label={"Up time"}
icon={<UptimeIcon />}
value={server?.uptime ? niceDays(server.uptime) : "N/A"}
/>
<ServerStatItem
statusColor={"green"}
label={"Version"}
icon={<VersionIcon />}
label={""}
value={
<Box
sx={{
@@ -223,11 +230,17 @@ const ServerInfoItem = ({ classes = {}, server, index }: ICardProps) => {
color: "#000000",
paddingLeft: "10px",
paddingRight: "10px",
borderRadius: "16px",
borderRadius: "2px",
fontSize: "12px",
marginTop: "5px",
"& .label": {
fontWeight: 600,
marginRight: "3px",
},
}}
>
<span className="label">Version:</span>
{server.version ? server.version : "N/A"}
</Box>
}

View File

@@ -19,12 +19,14 @@ import ListSubheader from "@mui/material/ListSubheader";
import List from "@mui/material/List";
import ListItemButton from "@mui/material/ListItemButton";
import Collapse from "@mui/material/Collapse";
import ExpandLess from "@mui/icons-material/ExpandLess";
import ExpandMore from "@mui/icons-material/ExpandMore";
import { ServerInfo } from "../types";
import ServerInfoItem from "./ServerInfoItem";
import { Box } from "@mui/material";
import DriveInfoItem from "./DriveInfoItem";
import {
MenuCollapsedIcon,
MenuExpandedIcon,
} from "../../../../icons/SidebarMenus";
const ServersList = ({ data }: { data: ServerInfo[] }) => {
const [expanded, setExpanded] = React.useState<string>(
@@ -36,112 +38,129 @@ const ServersList = ({ data }: { data: ServerInfo[] }) => {
};
return (
<List
sx={{ width: "100%", flex: 1 }}
component="nav"
aria-labelledby="nested-list-subheader"
subheader={
<ListSubheader
component="div"
sx={{
borderBottom: "1px solid #F8F8F8",
}}
>
Servers ({data.length})
</ListSubheader>
}
>
{data.map((serverInfo, index) => {
const key = `${serverInfo.endpoint}-${index}`;
const isExpanded = expanded === key;
return (
<React.Fragment key={key}>
<ListItemButton
disableRipple
onClick={() => {
if (!isExpanded) {
handleClick(key);
} else {
handleClick("");
}
}}
className={isExpanded ? "expanded" : ""}
sx={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
borderBottom: "1px solid #eaeaea",
"&:hover": {
background: "#F8F8F8",
},
"&.expanded": {
borderBottom: "none",
},
}}
>
<ServerInfoItem server={serverInfo} index={index} />
<Box
<Box>
<Box
sx={{
marginBottom: "10px",
}}
>
Servers ({data.length})
</Box>
<List
sx={{ width: "100%", flex: 1, padding: "0" }}
component="nav"
aria-labelledby="nested-list-subheader"
>
{data.map((serverInfo, index) => {
const key = `${serverInfo.endpoint}-${index}`;
const isExpanded = expanded === key;
return (
<React.Fragment key={key}>
<ListItemButton
disableRipple
onClick={() => {
if (!isExpanded) {
handleClick(key);
} else {
handleClick("");
}
}}
className={isExpanded ? "expanded" : ""}
sx={{
height: "25px",
width: "25px",
marginLeft: "25px",
background: "#FBFAFA",
borderRadius: "2px",
display: "flex",
alignItems: "center",
justifyContent: "space-between",
border: "1px solid #f1f1f1",
padding: "3px 10px 3px 10px",
"&:hover": {
background: "#fafafa",
},
display: {
md: "block",
xs: "none",
background: "#bebbbb0d",
},
}}
>
{isExpanded ? <ExpandLess /> : <ExpandMore />}
</Box>
</ListItemButton>
{isExpanded ? (
<React.Fragment key={`${serverInfo.endpoint}-${index}`}>
<ListSubheader
key={`${index}-drive-details`}
component="div"
<ServerInfoItem server={serverInfo} index={index} />
<Box
sx={{
borderBottom: "1px solid #F8F8F8",
}}
>
Drives ({serverInfo.drives.length})
</ListSubheader>
<Collapse
in={isExpanded}
timeout="auto"
unmountOnExit
sx={{
width: "100%",
flex: 1,
display: "flex",
padding: { md: "20px 50px", xs: "15px 15px" },
"& .MuiCollapse-wrapperInner": {
display: "flex",
flexFlow: "column",
gap: "15px",
height: "25px",
width: "25px",
background: "#FBFAFA",
borderRadius: "2px",
"&:hover": {
background: "#fafafa",
},
display: {
md: "block",
xs: "none",
},
"& .collapse-icon": {
fill: "#494949",
"& g rect": {
fill: "#ffffff",
},
},
"& .expand-icon": {
fill: "#494949",
"& rect": {
fill: "#ffffff",
},
},
}}
>
{serverInfo.drives.map((driveInfo, index) => {
return (
<DriveInfoItem
drive={driveInfo}
key={`${driveInfo.endpoint}-${index}`}
/>
);
})}
</Collapse>
</React.Fragment>
) : null}
</React.Fragment>
);
})}
</List>
{isExpanded ? (
<MenuCollapsedIcon className="collapse-icon" />
) : (
<MenuExpandedIcon className="expand-icon" />
)}
</Box>
</ListItemButton>
{isExpanded ? (
<Box
key={`${serverInfo.endpoint}-${index}`}
sx={{
border: "1px solid #f1f1f1",
borderTop: "0",
}}
>
<ListSubheader
key={`${index}-drive-details`}
component="div"
sx={{ paddingLeft: "30px" }}
>
Drives ({serverInfo.drives.length})
</ListSubheader>
<Collapse
in={isExpanded}
timeout="auto"
unmountOnExit
sx={{
width: "100%",
flex: 1,
display: "flex",
padding: { md: "15px 30px", xs: "10px 10px" },
"& .MuiCollapse-wrapperInner": {
display: "flex",
flexFlow: "column",
gap: "15px",
},
}}
>
{serverInfo.drives.map((driveInfo, index) => {
return (
<DriveInfoItem
drive={driveInfo}
key={`${driveInfo.endpoint}-${index}`}
/>
);
})}
</Collapse>
</Box>
) : null}
</React.Fragment>
);
})}
</List>
</Box>
);
};

View File

@@ -34,8 +34,8 @@ export const StatusCountCard = ({
sx={{
fontFamily: "Lato,sans-serif",
color: "#07193E",
maxWidth: "300px",
minHeight: "200px",
maxWidth: "260px",
minHeight: "143px",
display: "flex",
marginLeft: "auto",
marginRight: "auto",
@@ -45,7 +45,6 @@ export const StatusCountCard = ({
<Box
sx={{
flex: 1,
height: "200px",
display: "flex",
padding: {
sm: "0 8px 0 8px",
@@ -58,14 +57,13 @@ export const StatusCountCard = ({
flex: 1,
display: "flex",
flexFlow: "column",
marginTop: "32px",
marginTop: "22px",
}}
>
<Box
sx={{
fontSize: "16px",
fontWeight: 600,
marginBottom: "24px",
}}
>
{label}
@@ -76,25 +74,38 @@ export const StatusCountCard = ({
display: "flex",
alignItems: "center",
justifyContent: "space-between",
paddingBottom: {
md: "0px",
xs: "10px",
},
fontSize: {
xl: "55px",
lg: "50px",
md: "45px",
xs: "35px",
},
flexFlow: "row",
fontWeight: 600,
"& .stat-text": { color: "#696969", fontSize: "12px" },
"& .stat-text": {
color: "#696969",
fontSize: "12px",
marginTop: "25px",
},
"& .stat-value": {
textAlign: "center",
height: "50px",
},
"& .min-icon": {
marginRight: "8px",
marginTop: "25px",
height: "10px",
width: "10px",
},
}}
>
<Box>
<Box className="stat-value">{onlineCount}</Box>
<Box
sx={{
display: "flex",
@@ -106,10 +117,10 @@ export const StatusCountCard = ({
>
<CircleIcon /> <div className="stat-text">Online</div>
</Box>
<Box className="stat-value">{onlineCount}</Box>
</Box>
<Box>
<Box className="stat-value">{offlineCount}</Box>
<Box
sx={{
display: "flex",
@@ -121,7 +132,6 @@ export const StatusCountCard = ({
>
<CircleIcon /> <div className="stat-text">Offline</div>
</Box>
<Box className="stat-value">{offlineCount}</Box>
</Box>
</Box>
</Box>