Migrated Metrics pages and components to mds (#3042)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
// This object contains variables that will be used across form components.
|
||||
|
||||
import { breakPoints } from "mds";
|
||||
import get from "lodash/get";
|
||||
|
||||
const inputLabelBase = {
|
||||
fontWeight: 600,
|
||||
@@ -416,16 +417,16 @@ export const typesSelection = {
|
||||
},
|
||||
};
|
||||
|
||||
export const widgetCommon = {
|
||||
singleValueContainer: {
|
||||
export const widgetCommon = (theme: any) => ({
|
||||
"& .singleValueContainer": {
|
||||
height: 200,
|
||||
border: "#eaeaea 1px solid",
|
||||
backgroundColor: "#fff",
|
||||
borderRadius: "3px",
|
||||
border: `${get(theme, "borderColor", "#eaeaea")} 1px solid`,
|
||||
borderRadius: 2,
|
||||
backgroundColor: get(theme, "bgColor", "#fff"),
|
||||
padding: 16,
|
||||
},
|
||||
titleContainer: {
|
||||
color: "#404143",
|
||||
"& .titleContainer": {
|
||||
color: get(theme, "mutedText", "#87888d"),
|
||||
fontSize: 16,
|
||||
fontWeight: 600,
|
||||
paddingBottom: 14,
|
||||
@@ -433,38 +434,38 @@ export const widgetCommon = {
|
||||
display: "flex" as const,
|
||||
justifyContent: "space-between" as const,
|
||||
},
|
||||
contentContainer: {
|
||||
"& .contentContainer": {
|
||||
justifyContent: "center" as const,
|
||||
alignItems: "center" as const,
|
||||
display: "flex" as const,
|
||||
width: "100%",
|
||||
height: 140,
|
||||
},
|
||||
singleLegendContainer: {
|
||||
"& .singleLegendContainer": {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
padding: "0 10px",
|
||||
maxWidth: "100%",
|
||||
},
|
||||
colorContainer: {
|
||||
"& .colorContainer": {
|
||||
width: 8,
|
||||
height: 8,
|
||||
minWidth: 8,
|
||||
marginRight: 5,
|
||||
},
|
||||
legendLabel: {
|
||||
"& .legendLabel": {
|
||||
fontSize: "80%",
|
||||
color: "#393939",
|
||||
color: get(theme, "mutedText", "#87888d"),
|
||||
whiteSpace: "nowrap" as const,
|
||||
overflow: "hidden" as const,
|
||||
textOverflow: "ellipsis" as const,
|
||||
},
|
||||
zoomChartCont: {
|
||||
"& .zoomChartCont": {
|
||||
position: "relative" as const,
|
||||
height: 340,
|
||||
width: "100%",
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
export const tooltipCommon = {
|
||||
customTooltip: {
|
||||
@@ -646,44 +647,6 @@ export const inputFieldStyles = {
|
||||
},
|
||||
};
|
||||
|
||||
const commonStateIcon = {
|
||||
marginRight: 10,
|
||||
lineHeight: 1,
|
||||
display: "inline-flex",
|
||||
marginTop: 6,
|
||||
};
|
||||
|
||||
export const commonDashboardInfocard: any = {
|
||||
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,
|
||||
"& .min-icon": {
|
||||
width: 5,
|
||||
height: 5,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const tableStyles: any = {
|
||||
tableBlock: {
|
||||
display: "flex",
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment } from "react";
|
||||
import makeStyles from "@mui/styles/makeStyles";
|
||||
import Tabs from "@mui/material/Tabs";
|
||||
import Tab from "@mui/material/Tab";
|
||||
import { ITabOption } from "./types";
|
||||
|
||||
interface ITabSelector {
|
||||
selectedTab: number;
|
||||
onChange: (newValue: number) => void;
|
||||
tabOptions: ITabOption[];
|
||||
}
|
||||
|
||||
const tabSubStyles = makeStyles({
|
||||
tabRoot: {
|
||||
height: "40px",
|
||||
borderBottom: "1px solid #eaeaea",
|
||||
},
|
||||
root: {
|
||||
width: "120px",
|
||||
backgroundColor: "transparent",
|
||||
paddingTop: 0,
|
||||
paddingBottom: 0,
|
||||
fontSize: "14px",
|
||||
fontWeight: 600,
|
||||
color: "#07193E",
|
||||
height: "40px",
|
||||
},
|
||||
selected: {
|
||||
"&.MuiTab-selected": {
|
||||
backgroundColor: "#F6F7F7 !important",
|
||||
},
|
||||
"&.MuiTab-wrapper": {
|
||||
color: "#07193E",
|
||||
fontWeight: 600,
|
||||
},
|
||||
},
|
||||
indicator: {
|
||||
background:
|
||||
"transparent linear-gradient(90deg, #072B4E 0%, #081C42 100%) 0% 0% no-repeat padding-box;",
|
||||
height: 2,
|
||||
},
|
||||
scroller: {
|
||||
maxWidth: 1185,
|
||||
position: "relative",
|
||||
"&::after": {
|
||||
content: '" "',
|
||||
backgroundColor: "#EEF1F4",
|
||||
height: 2,
|
||||
width: "100%",
|
||||
display: "block",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const TabSelector = ({ selectedTab, onChange, tabOptions }: ITabSelector) => {
|
||||
const subStyles = tabSubStyles();
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Tabs
|
||||
indicatorColor="primary"
|
||||
textColor="primary"
|
||||
aria-label="cluster-tabs"
|
||||
variant="scrollable"
|
||||
scrollButtons="auto"
|
||||
value={selectedTab}
|
||||
onChange={(e: React.ChangeEvent<{}>, newValue: number) => {
|
||||
onChange(newValue);
|
||||
}}
|
||||
classes={{
|
||||
root: subStyles.tabRoot,
|
||||
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 (
|
||||
<Tab
|
||||
{...tabOptions}
|
||||
classes={{
|
||||
root: subStyles.root,
|
||||
selected: subStyles.selected,
|
||||
}}
|
||||
id={`simple-tab-${index}`}
|
||||
aria-controls={`simple-tabpanel-${index}`}
|
||||
key={`tab-${index}-${option.label}`}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Tabs>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default TabSelector;
|
||||
@@ -1,21 +0,0 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
export interface ITabOption {
|
||||
label: string;
|
||||
value?: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
@@ -15,9 +15,10 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import { Box, Grid } from "@mui/material";
|
||||
import {
|
||||
ArrowRightIcon,
|
||||
Box,
|
||||
breakPoints,
|
||||
BucketsIcon,
|
||||
Button,
|
||||
DiagnosticsMenuIcon,
|
||||
@@ -46,15 +47,14 @@ import { AdminInfoResponse, ServerDrives } from "api/consoleApi";
|
||||
const BoxItem = ({ children }: { children: any }) => {
|
||||
return (
|
||||
<Box
|
||||
withBorders
|
||||
sx={{
|
||||
border: "1px solid #f1f1f1",
|
||||
padding: {
|
||||
md: "15px",
|
||||
xs: "5px",
|
||||
},
|
||||
padding: 15,
|
||||
height: "136px",
|
||||
maxWidth: {
|
||||
sm: "100%",
|
||||
maxWidth: "100%",
|
||||
[`@media (max-width: ${breakPoints.sm}px)`]: {
|
||||
padding: 5,
|
||||
maxWidth: "initial",
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -124,8 +124,8 @@ const BasicDashboard = ({ usage }: IDashboardProps) => {
|
||||
display: "grid",
|
||||
gridTemplateRows: "1fr",
|
||||
gridTemplateColumns: "1fr",
|
||||
gap: "27px",
|
||||
marginBottom: "40px",
|
||||
gap: 27,
|
||||
marginBottom: 40,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
@@ -139,13 +139,13 @@ const BasicDashboard = ({ usage }: IDashboardProps) => {
|
||||
sx={{
|
||||
display: "grid",
|
||||
gridTemplateRows: "136px",
|
||||
gridTemplateColumns: {
|
||||
sm: "1fr 1fr 1fr",
|
||||
xs: "1fr",
|
||||
gridTemplateColumns: "1fr 1fr 1fr",
|
||||
gap: 20,
|
||||
[`@media (max-width: ${breakPoints.sm}px)`]: {
|
||||
gridTemplateColumns: "1fr",
|
||||
},
|
||||
gap: {
|
||||
md: "20px",
|
||||
xs: "20px",
|
||||
[`@media (max-width: ${breakPoints.md}px)`]: {
|
||||
marginBottom: 0,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -214,12 +214,12 @@ const BasicDashboard = ({ usage }: IDashboardProps) => {
|
||||
</BoxItem>
|
||||
|
||||
<Box
|
||||
withBorders
|
||||
sx={{
|
||||
gridRowStart: "1",
|
||||
gridRowEnd: "3",
|
||||
gridColumnStart: "3",
|
||||
border: "1px solid #f1f1f1",
|
||||
padding: "15px",
|
||||
padding: 15,
|
||||
display: "grid",
|
||||
justifyContent: "stretch",
|
||||
}}
|
||||
@@ -243,9 +243,9 @@ const BasicDashboard = ({ usage }: IDashboardProps) => {
|
||||
<Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: {
|
||||
md: "inline",
|
||||
xs: "none",
|
||||
display: "inline",
|
||||
[`@media (max-width: ${breakPoints.sm}px)`]: {
|
||||
display: "none",
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -262,9 +262,9 @@ const BasicDashboard = ({ usage }: IDashboardProps) => {
|
||||
<Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: {
|
||||
md: "inline",
|
||||
xs: "none",
|
||||
display: "inline",
|
||||
[`@media (max-width: ${breakPoints.sm}px)`]: {
|
||||
display: "none",
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -283,29 +283,32 @@ const BasicDashboard = ({ usage }: IDashboardProps) => {
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
<Grid container spacing={1}>
|
||||
<Grid item xs={4}>
|
||||
<TimeStatItem
|
||||
icon={<StorageIcon />}
|
||||
label={"Backend type"}
|
||||
value={usage?.backend?.backendType ?? "Unknown"}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
<TimeStatItem
|
||||
icon={<FormatDrivesIcon />}
|
||||
label={"Standard storage class parity"}
|
||||
value={usage?.backend?.standardSCParity?.toString() ?? "n/a"}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
<TimeStatItem
|
||||
icon={<FormatDrivesIcon />}
|
||||
label={"Reduced redundancy storage class parity"}
|
||||
value={usage?.backend?.rrSCParity?.toString() ?? "n/a"}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Box
|
||||
sx={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: "1fr 1fr 1fr",
|
||||
gap: "14px",
|
||||
[`@media (max-width: ${breakPoints.lg}px)`]: {
|
||||
gridTemplateColumns: "1fr",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<TimeStatItem
|
||||
icon={<StorageIcon />}
|
||||
label={"Backend type"}
|
||||
value={usage?.backend?.backendType ?? "Unknown"}
|
||||
/>
|
||||
<TimeStatItem
|
||||
icon={<FormatDrivesIcon />}
|
||||
label={"Standard storage class parity"}
|
||||
value={usage?.backend?.standardSCParity?.toString() ?? "n/a"}
|
||||
/>
|
||||
<TimeStatItem
|
||||
icon={<FormatDrivesIcon />}
|
||||
label={"Reduced redundancy storage class parity"}
|
||||
value={usage?.backend?.rrSCParity?.toString() ?? "n/a"}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
@@ -338,11 +341,8 @@ const BasicDashboard = ({ usage }: IDashboardProps) => {
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
paddingTop: "20px",
|
||||
fontSize: "14px",
|
||||
"& a": {
|
||||
color: (theme) => theme.colors.link,
|
||||
},
|
||||
paddingTop: 20,
|
||||
fontSize: 14,
|
||||
}}
|
||||
>
|
||||
<a
|
||||
|
||||
@@ -14,46 +14,46 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { Box, Tooltip } from "@mui/material";
|
||||
import React from "react";
|
||||
import get from "lodash/get";
|
||||
import styled from "styled-components";
|
||||
import { Box, breakPoints, Tooltip } from "mds";
|
||||
|
||||
const CounterCardMain = styled.div(({ theme }) => ({
|
||||
fontFamily: "Inter,sans-serif",
|
||||
color: get(theme, "signalColors.main", "#07193E"),
|
||||
maxWidth: "300px",
|
||||
display: "flex",
|
||||
marginLeft: "auto",
|
||||
marginRight: "auto",
|
||||
cursor: "default",
|
||||
position: "relative",
|
||||
width: "100%",
|
||||
}));
|
||||
|
||||
const CounterCard = ({
|
||||
counterValue,
|
||||
label = "",
|
||||
icon = null,
|
||||
actions = null,
|
||||
loading = false,
|
||||
}: {
|
||||
counterValue: string | number;
|
||||
label?: any;
|
||||
icon?: any;
|
||||
actions?: any;
|
||||
loading?: boolean;
|
||||
}) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
fontFamily: "Inter,sans-serif",
|
||||
color: "#07193E",
|
||||
maxWidth: "300px",
|
||||
display: "flex",
|
||||
marginLeft: "auto",
|
||||
marginRight: "auto",
|
||||
cursor: "default",
|
||||
position: "relative",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<CounterCardMain>
|
||||
<Box
|
||||
sx={{
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
width: "100%",
|
||||
padding: {
|
||||
sm: "0 8px 0 8px",
|
||||
xs: "0 10px 0 10px",
|
||||
},
|
||||
padding: "0 8px 0 8px",
|
||||
position: "absolute",
|
||||
[`@media (max-width: ${breakPoints.md}px)`]: {
|
||||
padding: "0 10px 0 10px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
@@ -75,36 +75,28 @@ const CounterCard = ({
|
||||
{label}
|
||||
</Box>
|
||||
|
||||
<Tooltip title={counterValue} placement="bottom" enterDelay={500}>
|
||||
<Tooltip tooltip={counterValue} placement="bottom">
|
||||
<Box
|
||||
sx={{
|
||||
fontSize:
|
||||
counterValue.toString().length >= 5
|
||||
? {
|
||||
xl: "50px",
|
||||
lg: "45px",
|
||||
md: "28px",
|
||||
sm: "28px",
|
||||
xs: "20px",
|
||||
}
|
||||
: {
|
||||
xl: "55px",
|
||||
lg: "50px",
|
||||
md: "36px",
|
||||
sm: "35px",
|
||||
xs: "35px",
|
||||
},
|
||||
|
||||
fontWeight: 600,
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
maxWidth: {
|
||||
md: 187,
|
||||
xs: 200,
|
||||
maxWidth: 187,
|
||||
flexFlow: "row",
|
||||
fontSize: counterValue.toString().length >= 5 ? 50 : 55,
|
||||
[`@media (max-width: ${breakPoints.sm}px)`]: {
|
||||
flexFlow: "column",
|
||||
maxWidth: 200,
|
||||
fontSize: counterValue.toString().length >= 5 ? 20 : 35,
|
||||
},
|
||||
flexFlow: {
|
||||
md: "row",
|
||||
xs: "column",
|
||||
[`@media (max-width: ${breakPoints.md}px)`]: {
|
||||
fontSize: counterValue.toString().length >= 5 ? 28 : 35,
|
||||
},
|
||||
[`@media (max-width: ${breakPoints.lg}px)`]: {
|
||||
fontSize: counterValue.toString().length >= 5 ? 28 : 36,
|
||||
},
|
||||
[`@media (max-width: ${breakPoints.xl}px)`]: {
|
||||
fontSize: counterValue.toString().length >= 5 ? 45 : 50,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -137,7 +129,7 @@ const CounterCard = ({
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</CounterCardMain>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -15,28 +15,14 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import {
|
||||
capacityColors,
|
||||
niceBytes,
|
||||
niceBytesInt,
|
||||
} from "../../../../common/utils";
|
||||
import { Box } from "@mui/material";
|
||||
import { Cell, Pie, PieChart } from "recharts";
|
||||
import { CircleIcon } from "mds";
|
||||
import { commonDashboardInfocard } from "../../Common/FormComponents/common/styleLibrary";
|
||||
import { STATUS_COLORS } from "./Utils";
|
||||
import get from "lodash/get";
|
||||
import styled from "styled-components";
|
||||
import { niceBytes } from "../../../../common/utils";
|
||||
import { Box, breakPoints, CircleIcon, SizeChart } from "mds";
|
||||
import { ServerDrives } from "api/consoleApi";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...commonDashboardInfocard,
|
||||
});
|
||||
import { STATUS_COLORS } from "./Utils";
|
||||
|
||||
interface ICardProps {
|
||||
classes?: any;
|
||||
drive: ServerDrives;
|
||||
}
|
||||
|
||||
@@ -51,29 +37,45 @@ const driveStatusColor = (health_status: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
const DataContainerMain = styled.div(({ theme }) => ({
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
paddingLeft: "20px",
|
||||
marginTop: "10px",
|
||||
flexFlow: "row",
|
||||
"& .info-label": {
|
||||
color: get(theme, "mutedText", "#87888d"),
|
||||
fontSize: "12px",
|
||||
textAlign: "center",
|
||||
},
|
||||
"& .info-value": {
|
||||
fontSize: "18px",
|
||||
color: get(theme, "signalColors.main", "#07193E"),
|
||||
display: "flex",
|
||||
fontWeight: 500,
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
},
|
||||
[`@media (max-width: ${breakPoints.sm}px)`]: {
|
||||
flexFlow: "column",
|
||||
},
|
||||
}));
|
||||
|
||||
const DriveInfoItem = ({ drive }: ICardProps) => {
|
||||
const totalSpace = drive.totalSpace || 0;
|
||||
const usedSpace = drive.usedSpace || 0;
|
||||
|
||||
const freeSpace = totalSpace - usedSpace;
|
||||
|
||||
const plotValues = [
|
||||
{ value: freeSpace, color: "#D6D6D6", label: "Free Space" },
|
||||
{
|
||||
value: drive.usedSpace,
|
||||
color: capacityColors(usedSpace, totalSpace),
|
||||
label: "Used Space",
|
||||
},
|
||||
];
|
||||
return (
|
||||
<Box
|
||||
withBorders
|
||||
sx={{
|
||||
display: "flex",
|
||||
flex: 1,
|
||||
alignItems: "center",
|
||||
paddingBottom: "10px",
|
||||
padding: "20px",
|
||||
border: "1px solid #eaeaea",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
@@ -106,9 +108,9 @@ const DriveInfoItem = ({ drive }: ICardProps) => {
|
||||
wordBreak: "break-all",
|
||||
marginRight: "8px",
|
||||
fontWeight: 600,
|
||||
fontSize: {
|
||||
md: "16px",
|
||||
xs: "10px",
|
||||
fontSize: 16,
|
||||
[`@media (max-width: ${breakPoints.sm}px)`]: {
|
||||
fontSize: 10,
|
||||
},
|
||||
},
|
||||
}}
|
||||
@@ -117,68 +119,15 @@ const DriveInfoItem = ({ drive }: ICardProps) => {
|
||||
{drive.state && <CircleIcon />}
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
paddingLeft: "20px",
|
||||
marginTop: "10px",
|
||||
flexFlow: {
|
||||
sm: "row",
|
||||
xs: "column",
|
||||
},
|
||||
"& .info-label": {
|
||||
color: "#5E5E5E",
|
||||
fontSize: "12px",
|
||||
textAlign: "center",
|
||||
},
|
||||
"& .info-value": {
|
||||
fontSize: "18px",
|
||||
color: "#07193E",
|
||||
display: "flex",
|
||||
fontWeight: 500,
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<DataContainerMain>
|
||||
<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,
|
||||
}}
|
||||
>
|
||||
{drive.usedSpace ? 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>
|
||||
<SizeChart
|
||||
label={true}
|
||||
usedBytes={usedSpace}
|
||||
totalBytes={totalSpace}
|
||||
width={"120"}
|
||||
height={"120"}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
@@ -229,10 +178,10 @@ const DriveInfoItem = ({ drive }: ICardProps) => {
|
||||
<label className="info-label">Available</label>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</DataContainerMain>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(DriveInfoItem);
|
||||
export default DriveInfoItem;
|
||||
|
||||
@@ -14,10 +14,46 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { Box, Tooltip } from "@mui/material";
|
||||
import React from "react";
|
||||
import get from "lodash/get";
|
||||
import styled from "styled-components";
|
||||
import { Box, Tooltip } from "mds";
|
||||
import { Cell, Pie, PieChart } from "recharts";
|
||||
|
||||
const ReportedUsageMain = styled.div(({ theme }) => ({
|
||||
maxHeight: "110px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
fontSize: "19px",
|
||||
|
||||
padding: "10px",
|
||||
"& .unit-value": {
|
||||
fontSize: "50px",
|
||||
color: get(theme, "signalColors.main", "#07193E"),
|
||||
},
|
||||
"& .unit-type": {
|
||||
fontSize: "18px",
|
||||
color: get(theme, "mutedText", "#87888d"),
|
||||
marginTop: "20px",
|
||||
marginLeft: "5px",
|
||||
},
|
||||
|
||||
"& .usage-label": {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
fontSize: "16px",
|
||||
fontWeight: 600,
|
||||
marginRight: "20px",
|
||||
marginTop: "-10px",
|
||||
"& .min-icon": {
|
||||
marginLeft: "10px",
|
||||
height: 16,
|
||||
width: 16,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
const ReportedUsage = ({
|
||||
usageValue,
|
||||
total,
|
||||
@@ -37,47 +73,13 @@ const ReportedUsage = ({
|
||||
];
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
maxHeight: "110px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
fontSize: "19px",
|
||||
|
||||
padding: "10px",
|
||||
"& .unit-value": {
|
||||
fontSize: "50px",
|
||||
color: "#07193E",
|
||||
},
|
||||
"& .unit-type": {
|
||||
fontSize: "18px",
|
||||
color: "#5E5E5E",
|
||||
marginTop: "20px",
|
||||
marginLeft: "5px",
|
||||
},
|
||||
|
||||
"& .usage-label": {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
fontSize: "16px",
|
||||
fontWeight: 600,
|
||||
marginRight: "20px",
|
||||
marginTop: "-10px",
|
||||
"& .min-icon": {
|
||||
marginLeft: "10px",
|
||||
height: 16,
|
||||
width: 16,
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ReportedUsageMain>
|
||||
<Box>
|
||||
<div className="usage-label">
|
||||
<span>Reported Usage</span>
|
||||
</div>
|
||||
|
||||
<Tooltip title={`${usageValue} Bytes`}>
|
||||
<Tooltip tooltip={`${usageValue} Bytes`}>
|
||||
<label
|
||||
className={"unit-value"}
|
||||
style={{
|
||||
@@ -122,7 +124,7 @@ const ReportedUsage = ({
|
||||
</div>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</ReportedUsageMain>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -14,14 +14,10 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import React from "react";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { niceDays } from "../../../../common/utils";
|
||||
import { Box } from "@mui/material";
|
||||
import { CircleIcon } from "mds";
|
||||
import styled from "styled-components";
|
||||
import get from "lodash/get";
|
||||
import { commonDashboardInfocard } from "../../Common/FormComponents/common/styleLibrary";
|
||||
import { Box, breakPoints, CircleIcon } from "mds";
|
||||
import { niceDays } from "../../../../common/utils";
|
||||
import {
|
||||
getDriveStatusColor,
|
||||
getNetworkStatusColor,
|
||||
@@ -29,84 +25,121 @@ import {
|
||||
} from "./Utils";
|
||||
import { ServerProperties } from "api/consoleApi";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...commonDashboardInfocard,
|
||||
});
|
||||
|
||||
interface ICardProps {
|
||||
classes?: any;
|
||||
server: ServerProperties;
|
||||
index: number;
|
||||
}
|
||||
|
||||
const ServerStatItemMain = styled.div(({ theme }) => ({
|
||||
alignItems: "baseline",
|
||||
padding: "5px",
|
||||
display: "flex",
|
||||
gap: "5px",
|
||||
"& .StatBox": {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
flexFlow: "column",
|
||||
"& .stat-text": {
|
||||
color: get(theme, "mutedText", "#87888d"),
|
||||
fontSize: "12px",
|
||||
},
|
||||
"& .stat-value": {
|
||||
fontSize: "18px",
|
||||
color: get(theme, "signalColors.main", "#07193E"),
|
||||
display: "flex",
|
||||
fontWeight: 500,
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
"& .stat-container": {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
flexFlow: "column",
|
||||
marginLeft: "5px",
|
||||
maxWidth: "40px",
|
||||
"&:first-of-type(svg)": {
|
||||
fill: get(theme, "mutedText", "#87888d"),
|
||||
},
|
||||
"& .stat-indicator": {
|
||||
marginRight: "0px",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
textAlign: "center",
|
||||
"& svg.min-icon": {
|
||||
width: "10px",
|
||||
height: "10px",
|
||||
},
|
||||
"&.good": {
|
||||
"& svg.min-icon": {
|
||||
fill: get(theme, "signalColors.good", "#4CCB92"),
|
||||
},
|
||||
},
|
||||
"&.warn": {
|
||||
"& svg.min-icon": {
|
||||
fill: get(theme, "signalColors.warning", "#FFBD62"),
|
||||
},
|
||||
},
|
||||
"&.bad": {
|
||||
"& svg.min-icon": {
|
||||
fill: get(theme, "signalColors.danger", "#C51B3F"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
const ServerInfoItemMain = styled.div(({ theme }) => ({
|
||||
display: "flex",
|
||||
alignItems: "flex-start",
|
||||
flexFlow: "column",
|
||||
flex: 1,
|
||||
"& .server-state": {
|
||||
marginLeft: "8px",
|
||||
"& .min-icon": {
|
||||
height: "14px",
|
||||
width: "14px",
|
||||
},
|
||||
"&.good": {
|
||||
"& svg.min-icon": {
|
||||
fill: get(theme, "signalColors.good", "#4CCB92"),
|
||||
},
|
||||
},
|
||||
"&.warn": {
|
||||
"& svg.min-icon": {
|
||||
fill: get(theme, "signalColors.warning", "#FFBD62"),
|
||||
},
|
||||
},
|
||||
"&.bad": {
|
||||
"& svg.min-icon": {
|
||||
fill: get(theme, "signalColors.danger", "#C51B3F"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
const ServerStatItem = ({
|
||||
label = "",
|
||||
value = "",
|
||||
statusColor = "",
|
||||
statusColor = "warn",
|
||||
hasStatus = false,
|
||||
}: {
|
||||
label?: string;
|
||||
value?: any;
|
||||
hasStatus?: boolean;
|
||||
statusColor: string | undefined;
|
||||
statusColor?: "good" | "warn" | "bad";
|
||||
}) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
alignItems: "baseline",
|
||||
padding: "5px",
|
||||
display: "flex",
|
||||
gap: "5px",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
flexFlow: "column",
|
||||
"& .stat-text": { color: "#5E5E5E", fontSize: "12px" },
|
||||
"& .stat-value": {
|
||||
fontSize: "18px",
|
||||
color: "#07193E",
|
||||
display: "flex",
|
||||
fontWeight: 500,
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ServerStatItemMain>
|
||||
<Box className={"StatBox"}>
|
||||
<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",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box className={"stat-container"}>
|
||||
{hasStatus ? (
|
||||
<Box
|
||||
sx={{
|
||||
marginRight: "0px",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
textAlign: "center",
|
||||
"& svg.min-icon": {
|
||||
fill: statusColor,
|
||||
width: "10px",
|
||||
height: "10px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box className={`stat-indicator ${statusColor}`}>
|
||||
<CircleIcon />
|
||||
</Box>
|
||||
) : (
|
||||
@@ -116,7 +149,7 @@ const ServerStatItem = ({
|
||||
</div>
|
||||
<div className="stat-text">{label}</div>
|
||||
</Box>
|
||||
</Box>
|
||||
</ServerStatItemMain>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -135,14 +168,7 @@ const ServerInfoItem = ({ server }: ICardProps) => {
|
||||
? server.drives.filter((element) => element.state === "ok").length
|
||||
: 0;
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "flex-start",
|
||||
flexFlow: "column",
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
<ServerInfoItemMain>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
@@ -152,10 +178,9 @@ const ServerInfoItem = ({ server }: ICardProps) => {
|
||||
justifyContent: "space-between",
|
||||
width: "100%",
|
||||
paddingLeft: "20px",
|
||||
|
||||
flexFlow: {
|
||||
sm: "row",
|
||||
xs: "column",
|
||||
flexFlow: "row",
|
||||
[`@media (max-width: ${breakPoints.md}px)`]: {
|
||||
flexFlow: "column",
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -174,16 +199,7 @@ const ServerInfoItem = ({ server }: ICardProps) => {
|
||||
{server.endpoint || ""}
|
||||
</Box>
|
||||
{server?.state && (
|
||||
<Box
|
||||
sx={{
|
||||
marginLeft: "8px",
|
||||
"& .min-icon": {
|
||||
fill: serverStatusColor(server.state),
|
||||
height: "14px",
|
||||
width: "14px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box className={`server-state ${serverStatusColor(server.state)}`}>
|
||||
<CircleIcon />
|
||||
</Box>
|
||||
)}
|
||||
@@ -195,10 +211,7 @@ const ServerInfoItem = ({ server }: ICardProps) => {
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
flex: "1.5",
|
||||
gap: {
|
||||
md: "5%",
|
||||
xs: "5%",
|
||||
},
|
||||
gap: "5%",
|
||||
}}
|
||||
>
|
||||
<ServerStatItem
|
||||
@@ -213,15 +226,14 @@ const ServerInfoItem = ({ server }: ICardProps) => {
|
||||
hasStatus={true}
|
||||
value={`${activeNetwork}/${networkTotal}`}
|
||||
/>
|
||||
|
||||
<ServerStatItem
|
||||
statusColor={"green"}
|
||||
statusColor={"good"}
|
||||
label={"Up time"}
|
||||
value={server?.uptime ? niceDays(`${server.uptime}`) : "N/A"}
|
||||
/>
|
||||
</Box>
|
||||
<ServerStatItem
|
||||
statusColor={"green"}
|
||||
statusColor={"good"}
|
||||
label={""}
|
||||
value={
|
||||
<Box
|
||||
@@ -246,7 +258,7 @@ const ServerInfoItem = ({ server }: ICardProps) => {
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</ServerInfoItemMain>
|
||||
);
|
||||
};
|
||||
export default withStyles(styles)(ServerInfoItem);
|
||||
export default ServerInfoItem;
|
||||
|
||||
@@ -15,14 +15,9 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
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 { Accordion, Box, breakPoints } from "mds";
|
||||
import ServerInfoItem from "./ServerInfoItem";
|
||||
import { Box } from "@mui/material";
|
||||
import DriveInfoItem from "./DriveInfoItem";
|
||||
import { MenuCollapsedIcon, MenuExpandedIcon } from "mds";
|
||||
import { ServerProperties } from "api/consoleApi";
|
||||
|
||||
const ServersList = ({ data }: { data: ServerProperties[] }) => {
|
||||
@@ -38,128 +33,63 @@ const ServersList = ({ data }: { data: ServerProperties[] }) => {
|
||||
<Box>
|
||||
<Box
|
||||
sx={{
|
||||
marginBottom: "10px",
|
||||
fontSize: 18,
|
||||
lineHeight: 2,
|
||||
fontWeight: 700,
|
||||
}}
|
||||
>
|
||||
Servers ({data.length})
|
||||
</Box>
|
||||
<List
|
||||
sx={{ width: "100%", flex: 1, padding: "0" }}
|
||||
component="nav"
|
||||
aria-labelledby="nested-list-subheader"
|
||||
>
|
||||
<Box>
|
||||
{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" : ""}
|
||||
<Accordion
|
||||
key={key}
|
||||
expanded={isExpanded}
|
||||
onTitleClick={() => {
|
||||
if (!isExpanded) {
|
||||
handleClick(key);
|
||||
} else {
|
||||
handleClick("");
|
||||
}
|
||||
}}
|
||||
id={"key"}
|
||||
title={<ServerInfoItem server={serverInfo} index={index} />}
|
||||
sx={{ marginBottom: 15 }}
|
||||
>
|
||||
<Box
|
||||
useBackground
|
||||
sx={{ padding: "10px 30px", fontWeight: "bold" }}
|
||||
>
|
||||
Drives ({serverInfo.drives?.length})
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
borderTop: index === 0 ? "1px solid #f1f1f1" : "",
|
||||
borderBottom: "1px solid #f1f1f1",
|
||||
borderLeft: "1px solid #f1f1f1",
|
||||
borderRight: "1px solid #f1f1f1",
|
||||
padding: "3px 10px 3px 10px",
|
||||
|
||||
"&:hover": {
|
||||
background: "#bebbbb0d",
|
||||
flexDirection: "column",
|
||||
padding: "15px 30px",
|
||||
gap: 15,
|
||||
[`@media (max-width: ${breakPoints.sm}px)`]: {
|
||||
padding: "10px 10px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ServerInfoItem server={serverInfo} index={index} />
|
||||
<Box
|
||||
sx={{
|
||||
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",
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
{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>
|
||||
{serverInfo.drives?.map((driveInfo, index) => {
|
||||
return (
|
||||
<DriveInfoItem
|
||||
drive={driveInfo}
|
||||
key={`${driveInfo.endpoint}-${index}`}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
</Accordion>
|
||||
);
|
||||
})}
|
||||
</List>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
export const STATUS_COLORS = {
|
||||
RED: "#C83B51",
|
||||
GREEN: "#4CCB92",
|
||||
YELLOW: "#E7A219",
|
||||
YELLOW: "#FFBD62",
|
||||
};
|
||||
|
||||
export const getDriveStatusColor = (
|
||||
@@ -25,24 +25,24 @@ export const getDriveStatusColor = (
|
||||
totalDrives: number,
|
||||
) => {
|
||||
if (activeDisks <= totalDrives / 2) {
|
||||
return STATUS_COLORS.RED;
|
||||
return "bad";
|
||||
}
|
||||
if (totalDrives !== 2 && activeDisks === totalDrives / 2 + 1) {
|
||||
return STATUS_COLORS.YELLOW;
|
||||
return "warn";
|
||||
}
|
||||
if (activeDisks === totalDrives) {
|
||||
return STATUS_COLORS.GREEN;
|
||||
return "good";
|
||||
}
|
||||
};
|
||||
|
||||
export const serverStatusColor = (health_status: string) => {
|
||||
switch (health_status) {
|
||||
case "offline":
|
||||
return STATUS_COLORS.RED;
|
||||
return "bad";
|
||||
case "online":
|
||||
return STATUS_COLORS.GREEN;
|
||||
return "good";
|
||||
default:
|
||||
return STATUS_COLORS.YELLOW;
|
||||
return "warn";
|
||||
}
|
||||
};
|
||||
export const getNetworkStatusColor = (
|
||||
@@ -50,12 +50,12 @@ export const getNetworkStatusColor = (
|
||||
networkTotal: number,
|
||||
) => {
|
||||
if (activeNetwork <= networkTotal / 2) {
|
||||
return STATUS_COLORS.RED;
|
||||
return "bad";
|
||||
}
|
||||
if (activeNetwork === networkTotal / 2 + 1) {
|
||||
return STATUS_COLORS.YELLOW;
|
||||
return "warn";
|
||||
}
|
||||
if (activeNetwork === networkTotal) {
|
||||
return STATUS_COLORS.GREEN;
|
||||
return "good";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -14,13 +14,11 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { Card, CardHeader } from "@mui/material";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import makeStyles from "@mui/styles/makeStyles";
|
||||
import React, { Fragment } from "react";
|
||||
import styled from "styled-components";
|
||||
import get from "lodash/get";
|
||||
import { Box } from "mds";
|
||||
import { Link } from "react-router-dom";
|
||||
import { widgetCommon } from "../Common/FormComponents/common/styleLibrary";
|
||||
|
||||
export interface ISubInterface {
|
||||
@@ -36,69 +34,48 @@ interface ICommonCard {
|
||||
moreLink?: string;
|
||||
rightComponent?: any;
|
||||
extraMargin?: boolean;
|
||||
classes: any;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...widgetCommon,
|
||||
cardRoot: {
|
||||
...widgetCommon.singleValueContainer,
|
||||
"&.MuiPaper-root": {
|
||||
borderRadius: 10,
|
||||
},
|
||||
},
|
||||
metricText: {
|
||||
fontSize: 70,
|
||||
lineHeight: 1.1,
|
||||
color: "#07193E",
|
||||
const CommonCardItem = styled.div(({ theme }) => ({
|
||||
...widgetCommon(theme),
|
||||
"& .metricText": {
|
||||
fontSize: 70,
|
||||
lineHeight: 1.1,
|
||||
color: get(theme, "signalColors.main", "#07193E"),
|
||||
fontWeight: "bold",
|
||||
},
|
||||
"& .unitText": {
|
||||
fontSize: 10,
|
||||
color: get(theme, "mutedText", "#87888d"),
|
||||
fontWeight: "normal",
|
||||
},
|
||||
"& .subHeaderContainer": {
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
},
|
||||
"& .subMessage": {
|
||||
fontSize: 10,
|
||||
color: get(theme, "mutedText", "#87888d"),
|
||||
"&.bold": {
|
||||
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",
|
||||
},
|
||||
},
|
||||
extraMargin: {
|
||||
margin: "10px 20px 10px 0",
|
||||
},
|
||||
});
|
||||
|
||||
const cardSubStyles = makeStyles({
|
||||
root: { backgroundColor: "#fff", padding: 0 },
|
||||
title: {
|
||||
...widgetCommon.titleContainer,
|
||||
},
|
||||
content: {
|
||||
maxWidth: "100%",
|
||||
"& .headerContainer": {
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
},
|
||||
});
|
||||
"& .viewAll": {
|
||||
fontSize: 10,
|
||||
color: get(theme, "signalColors.danger", "#C83B51"),
|
||||
textTransform: "capitalize",
|
||||
|
||||
"& a, & a:hover, & a:visited, & a:active": {
|
||||
color: get(theme, "signalColors.danger", "#C83B51"),
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
const CommonCard = ({
|
||||
title,
|
||||
@@ -108,31 +85,29 @@ const CommonCard = ({
|
||||
moreLink,
|
||||
rightComponent,
|
||||
extraMargin = false,
|
||||
classes,
|
||||
}: ICommonCard) => {
|
||||
const subStyles = cardSubStyles();
|
||||
const SubHeader = () => {
|
||||
return (
|
||||
<Fragment>
|
||||
<div className={classes.subHearderContainer}>
|
||||
<div className={classes.leftSide}>
|
||||
<div className={"subHeaderContainer"}>
|
||||
<div className={"leftSide"}>
|
||||
<div>
|
||||
<span className={classes.metricText}>
|
||||
<span className={"metricText"}>
|
||||
{metricValue}
|
||||
<span className={classes.unitText}>{metricUnit}</span>
|
||||
<span className={"unitText"}>{metricUnit}</span>
|
||||
</span>
|
||||
</div>
|
||||
{subMessage && (
|
||||
<div
|
||||
className={`${classes.subMessage} ${
|
||||
subMessage.fontWeight ? subMessage.fontWeight : ""
|
||||
}`}
|
||||
<Box
|
||||
sx={{
|
||||
fontWeight: subMessage.fontWeight || "normal",
|
||||
}}
|
||||
>
|
||||
{subMessage.message}
|
||||
</div>
|
||||
</Box>
|
||||
)}
|
||||
</div>
|
||||
<div className={classes.rightSide}>{rightComponent}</div>
|
||||
<div className={"rightSide"}>{rightComponent}</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
@@ -141,11 +116,11 @@ const CommonCard = ({
|
||||
const Header = () => {
|
||||
return (
|
||||
<Fragment>
|
||||
<div className={classes.headerContainer}>
|
||||
<span className={classes.title}>{title}</span>
|
||||
<div className={"headerContainer"}>
|
||||
<span className={"titleContainer"}>{title}</span>
|
||||
{moreLink && (
|
||||
<Fragment>
|
||||
<span className={classes.viewAll}>
|
||||
<span className={"viewAll"}>
|
||||
<Link to={moreLink}>View All</Link>
|
||||
</span>
|
||||
</Fragment>
|
||||
@@ -157,29 +132,23 @@ const CommonCard = ({
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Card
|
||||
className={`${classes.cardRoot} ${
|
||||
extraMargin ? classes.extraMargin : ""
|
||||
}`}
|
||||
<Box
|
||||
withBorders
|
||||
sx={{
|
||||
height: 200,
|
||||
padding: 16,
|
||||
margin: extraMargin ? "10px 20px 10px 0" : "",
|
||||
}}
|
||||
>
|
||||
{metricValue !== "" && (
|
||||
<CardHeader
|
||||
title={<Header />}
|
||||
subheader={
|
||||
<Fragment>
|
||||
<SubHeader />
|
||||
</Fragment>
|
||||
}
|
||||
classes={{
|
||||
root: subStyles.root,
|
||||
title: subStyles.title,
|
||||
content: subStyles.content,
|
||||
}}
|
||||
/>
|
||||
<CommonCardItem>
|
||||
<Header />
|
||||
<SubHeader />
|
||||
</CommonCardItem>
|
||||
)}
|
||||
</Card>
|
||||
</Box>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(CommonCard);
|
||||
export default CommonCard;
|
||||
|
||||
@@ -15,32 +15,17 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment, useEffect, useState } from "react";
|
||||
import PrDashboard from "./Prometheus/PrDashboard";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { containerForHeader } from "../Common/FormComponents/common/styleLibrary";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
|
||||
import { Grid, ProgressBar } from "mds";
|
||||
import { useSelector } from "react-redux";
|
||||
import { AppState, useAppDispatch } from "../../../store";
|
||||
import { getUsageAsync } from "./dashboardThunks";
|
||||
import { useSelector } from "react-redux";
|
||||
import PageHeaderWrapper from "../Common/PageHeaderWrapper/PageHeaderWrapper";
|
||||
import { selFeatures } from "../consoleSlice";
|
||||
import HelpMenu from "../HelpMenu";
|
||||
import { setHelpName } from "../../../systemSlice";
|
||||
import { ProgressBar } from "mds";
|
||||
import PrDashboard from "./Prometheus/PrDashboard";
|
||||
import PageHeaderWrapper from "../Common/PageHeaderWrapper/PageHeaderWrapper";
|
||||
import HelpMenu from "../HelpMenu";
|
||||
|
||||
interface IDashboardSimple {
|
||||
classes: any;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...containerForHeader,
|
||||
});
|
||||
|
||||
const Dashboard = ({ classes }: IDashboardSimple) => {
|
||||
const Dashboard = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
|
||||
@@ -73,7 +58,7 @@ const Dashboard = ({ classes }: IDashboardSimple) => {
|
||||
)}
|
||||
{loading ? (
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.container}>
|
||||
<Grid item xs={12}>
|
||||
<ProgressBar />
|
||||
</Grid>
|
||||
</Grid>
|
||||
@@ -84,4 +69,4 @@ const Dashboard = ({ classes }: IDashboardSimple) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(Dashboard);
|
||||
export default Dashboard;
|
||||
|
||||
@@ -15,24 +15,25 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import { Box } from "@mui/material";
|
||||
import { Box, breakPoints } from "mds";
|
||||
|
||||
const DashboardItemBox = ({ children }: { children: any }) => {
|
||||
return (
|
||||
<Box
|
||||
withBorders
|
||||
sx={{
|
||||
border: "1px solid #f1f1f1",
|
||||
borderRadius: "3px",
|
||||
padding: {
|
||||
md: "15px",
|
||||
xs: "5px",
|
||||
padding: 15,
|
||||
height: 136,
|
||||
maxWidth: "100%",
|
||||
[`@media (max-width: ${breakPoints.sm}px)`]: {
|
||||
padding: 5,
|
||||
height: "auto",
|
||||
},
|
||||
height: {
|
||||
md: "136px",
|
||||
xs: "auto",
|
||||
},
|
||||
maxWidth: {
|
||||
sm: "100%",
|
||||
[`@media (max-width: ${breakPoints.md}px)`]: {
|
||||
display: "flex",
|
||||
flexFlow: "column",
|
||||
maxWidth: "initial",
|
||||
},
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -16,21 +16,22 @@
|
||||
|
||||
import React, { Fragment, useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { Box } from "@mui/material";
|
||||
import { actionsTray } from "../../Common/FormComponents/common/styleLibrary";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Grid,
|
||||
HelpBox,
|
||||
PageLayout,
|
||||
ProgressBar,
|
||||
PrometheusErrorIcon,
|
||||
SyncIcon,
|
||||
TabItemProps,
|
||||
Tabs,
|
||||
} from "mds";
|
||||
import { IDashboardPanel } from "./types";
|
||||
import { panelsConfiguration } from "./utils";
|
||||
import { TabPanel } from "../../../shared/tabs";
|
||||
|
||||
import TabSelector from "../../Common/TabSelector/TabSelector";
|
||||
import { componentToUse } from "./widgetUtils";
|
||||
import ZoomWidget from "./ZoomWidget";
|
||||
import { AppState, useAppDispatch } from "../../../../store";
|
||||
import DateRangeSelector from "../../Common/FormComponents/DateRangeSelector/DateRangeSelector";
|
||||
import {
|
||||
DLayoutColumnProps,
|
||||
DLayoutRowProps,
|
||||
@@ -40,33 +41,20 @@ import {
|
||||
summaryPanelsLayout,
|
||||
trafficPanelsLayout,
|
||||
} from "./Widgets/LayoutUtil";
|
||||
import MergedWidgetsRenderer from "./Widgets/MergedWidgetsRenderer";
|
||||
import BasicDashboard from "../BasicDashboard/BasicDashboard";
|
||||
import {
|
||||
Button,
|
||||
HelpBox,
|
||||
PageLayout,
|
||||
ProgressBar,
|
||||
PrometheusErrorIcon,
|
||||
SyncIcon,
|
||||
} from "mds";
|
||||
import { ITabOption } from "../../Common/TabSelector/types";
|
||||
import { getUsageAsync } from "../dashboardThunks";
|
||||
import { reloadWidgets } from "../dashboardSlice";
|
||||
import { selFeatures } from "../../consoleSlice";
|
||||
import { AdminInfoResponse } from "api/consoleApi";
|
||||
import ZoomWidget from "./ZoomWidget";
|
||||
import DateRangeSelector from "../../Common/FormComponents/DateRangeSelector/DateRangeSelector";
|
||||
import MergedWidgetsRenderer from "./Widgets/MergedWidgetsRenderer";
|
||||
import BasicDashboard from "../BasicDashboard/BasicDashboard";
|
||||
|
||||
interface IPrDashboard {
|
||||
classes?: any;
|
||||
apiPrefix?: string;
|
||||
usage: AdminInfoResponse | null;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...actionsTray,
|
||||
});
|
||||
|
||||
const PrDashboard = ({ apiPrefix = "admin", usage }: IPrDashboard) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const loadingUsage = useSelector(
|
||||
@@ -90,7 +78,9 @@ const PrDashboard = ({ apiPrefix = "admin", usage }: IPrDashboard) => {
|
||||
const [timeStart, setTimeStart] = useState<any>(null);
|
||||
const [timeEnd, setTimeEnd] = useState<any>(null);
|
||||
const panelInformation = panelsConfiguration;
|
||||
const [curTab, setCurTab] = useState<number>(0);
|
||||
const [curTab, setCurTab] = useState<string>(
|
||||
usage?.advancedMetricsStatus === "not configured" ? "info" : "usage",
|
||||
);
|
||||
|
||||
const getPanelDetails = (id: number) => {
|
||||
return panelInformation.find((panel) => panel.id === id);
|
||||
@@ -168,110 +158,79 @@ const PrDashboard = ({ apiPrefix = "admin", usage }: IPrDashboard) => {
|
||||
return renderPanelItems(resourcesPanelsLayoutAdvanced);
|
||||
};
|
||||
|
||||
let tabs: ITabOption[];
|
||||
if (usage?.advancedMetricsStatus !== "not configured") {
|
||||
tabs = [
|
||||
{ label: "Usage" },
|
||||
{ label: "Traffic" },
|
||||
{ label: "Resources" },
|
||||
{ label: "Info" },
|
||||
];
|
||||
} else {
|
||||
tabs = [
|
||||
{ label: "Info" },
|
||||
{ label: "Usage", disabled: true },
|
||||
{ label: "Traffic", disabled: true },
|
||||
{ label: "Resources", disabled: true },
|
||||
];
|
||||
}
|
||||
const prometheusOptionsDisabled =
|
||||
usage?.advancedMetricsStatus === "not configured";
|
||||
|
||||
return (
|
||||
<PageLayout
|
||||
sx={{
|
||||
padding: hideMenu ? 0 : "2rem",
|
||||
}}
|
||||
>
|
||||
{zoomOpen && (
|
||||
<ZoomWidget
|
||||
modalOpen={zoomOpen}
|
||||
timeStart={timeStart}
|
||||
timeEnd={timeEnd}
|
||||
widgetRender={0}
|
||||
value={zoomWidget}
|
||||
apiPrefix={apiPrefix}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Grid item xs={12}>
|
||||
<TabSelector
|
||||
selectedTab={curTab}
|
||||
onChange={(newValue: number) => {
|
||||
setCurTab(newValue);
|
||||
}}
|
||||
tabOptions={tabs}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
sx={{
|
||||
paddingTop: "20px",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
marginBottom: "20px",
|
||||
}}
|
||||
>
|
||||
{curTab ===
|
||||
(usage?.advancedMetricsStatus === "not configured" ? 0 : 3) ? (
|
||||
<Grid container>
|
||||
const searchBox = (
|
||||
<Box sx={{ marginBottom: 20 }}>
|
||||
{curTab === "info" ? (
|
||||
<Grid container>
|
||||
<Grid item>
|
||||
<Box
|
||||
sx={{
|
||||
fontSize: 18,
|
||||
lineHeight: 2,
|
||||
fontWeight: 700,
|
||||
}}
|
||||
>
|
||||
Server Information
|
||||
</Box>
|
||||
</Grid>
|
||||
<Grid item xs>
|
||||
<Grid container direction="row-reverse">
|
||||
<Grid item>
|
||||
<Box
|
||||
sx={{
|
||||
color: "#000",
|
||||
fontSize: 18,
|
||||
lineHeight: 2,
|
||||
fontWeight: 700,
|
||||
marginLeft: "21px",
|
||||
display: "flex",
|
||||
<Button
|
||||
id={"sync"}
|
||||
type="button"
|
||||
variant="callAction"
|
||||
onClick={() => {
|
||||
dispatch(getUsageAsync());
|
||||
}}
|
||||
>
|
||||
Server Information
|
||||
</Box>
|
||||
</Grid>
|
||||
<Grid item xs>
|
||||
<Grid container direction="row-reverse">
|
||||
<Grid item>
|
||||
<Button
|
||||
id={"sync"}
|
||||
type="button"
|
||||
variant="callAction"
|
||||
onClick={() => {
|
||||
dispatch(getUsageAsync());
|
||||
}}
|
||||
disabled={loadingUsage}
|
||||
icon={<SyncIcon />}
|
||||
label={"Sync"}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
disabled={loadingUsage}
|
||||
icon={<SyncIcon />}
|
||||
label={"Sync"}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
) : (
|
||||
<DateRangeSelector
|
||||
timeStart={timeStart}
|
||||
setTimeStart={setTimeStart}
|
||||
timeEnd={timeEnd}
|
||||
setTimeEnd={setTimeEnd}
|
||||
triggerSync={triggerLoad}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
<TabPanel
|
||||
index={usage?.advancedMetricsStatus === "not configured" ? 3 : 0}
|
||||
value={curTab}
|
||||
>
|
||||
</Grid>
|
||||
</Grid>
|
||||
) : (
|
||||
<DateRangeSelector
|
||||
timeStart={timeStart}
|
||||
setTimeStart={setTimeStart}
|
||||
timeEnd={timeEnd}
|
||||
setTimeEnd={setTimeEnd}
|
||||
triggerSync={triggerLoad}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
|
||||
const infoTab: TabItemProps = {
|
||||
tabConfig: { label: "Info", id: "info", disabled: false },
|
||||
content: (
|
||||
<Fragment>
|
||||
{(!usage || loadingUsage) && <ProgressBar />}
|
||||
{usage && !loadingUsage && (
|
||||
<Fragment>
|
||||
{searchBox}
|
||||
<BasicDashboard usage={usage} />
|
||||
</Fragment>
|
||||
)}
|
||||
</Fragment>
|
||||
),
|
||||
};
|
||||
|
||||
const prometheusTabs: TabItemProps[] = [
|
||||
{
|
||||
tabConfig: {
|
||||
label: "Usage",
|
||||
id: "usage",
|
||||
disabled: prometheusOptionsDisabled,
|
||||
},
|
||||
content: (
|
||||
<Fragment>
|
||||
{searchBox}
|
||||
<RowPanelLayout>
|
||||
{usage?.advancedMetricsStatus === "unavailable" && (
|
||||
<HelpBox
|
||||
@@ -291,8 +250,18 @@ const PrDashboard = ({ apiPrefix = "admin", usage }: IPrDashboard) => {
|
||||
)}
|
||||
{panelInformation.length ? renderSummaryPanels() : null}
|
||||
</RowPanelLayout>
|
||||
</TabPanel>
|
||||
<TabPanel index={1} value={curTab}>
|
||||
</Fragment>
|
||||
),
|
||||
},
|
||||
{
|
||||
tabConfig: {
|
||||
label: "Traffic",
|
||||
id: "traffic",
|
||||
disabled: prometheusOptionsDisabled,
|
||||
},
|
||||
content: (
|
||||
<Fragment>
|
||||
{searchBox}
|
||||
<RowPanelLayout>
|
||||
{usage?.advancedMetricsStatus === "unavailable" && (
|
||||
<HelpBox
|
||||
@@ -312,8 +281,18 @@ const PrDashboard = ({ apiPrefix = "admin", usage }: IPrDashboard) => {
|
||||
)}
|
||||
{panelInformation.length ? renderTrafficPanels() : null}
|
||||
</RowPanelLayout>
|
||||
</TabPanel>
|
||||
<TabPanel index={2} value={curTab}>
|
||||
</Fragment>
|
||||
),
|
||||
},
|
||||
{
|
||||
tabConfig: {
|
||||
label: "Resources",
|
||||
id: "resources",
|
||||
disabled: prometheusOptionsDisabled,
|
||||
},
|
||||
content: (
|
||||
<Fragment>
|
||||
{searchBox}
|
||||
<RowPanelLayout>
|
||||
{usage?.advancedMetricsStatus === "unavailable" && (
|
||||
<HelpBox
|
||||
@@ -337,17 +316,46 @@ const PrDashboard = ({ apiPrefix = "admin", usage }: IPrDashboard) => {
|
||||
</h2>
|
||||
{panelInformation.length ? renderAdvancedResourcesPanels() : null}
|
||||
</RowPanelLayout>
|
||||
</TabPanel>
|
||||
<TabPanel
|
||||
index={usage?.advancedMetricsStatus === "not configured" ? 0 : 3}
|
||||
value={curTab}
|
||||
>
|
||||
{(!usage || loadingUsage) && <ProgressBar />}
|
||||
{usage && !loadingUsage && <BasicDashboard usage={usage} />}
|
||||
</TabPanel>
|
||||
</Grid>
|
||||
</Fragment>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
let tabsOptions: TabItemProps[];
|
||||
|
||||
if (!prometheusOptionsDisabled) {
|
||||
tabsOptions = [...prometheusTabs, infoTab];
|
||||
} else {
|
||||
tabsOptions = [infoTab, ...prometheusTabs];
|
||||
}
|
||||
|
||||
return (
|
||||
<PageLayout
|
||||
sx={{
|
||||
padding: hideMenu ? 0 : "2rem",
|
||||
}}
|
||||
>
|
||||
{zoomOpen && (
|
||||
<ZoomWidget
|
||||
modalOpen={zoomOpen}
|
||||
timeStart={timeStart}
|
||||
timeEnd={timeEnd}
|
||||
widgetRender={0}
|
||||
value={zoomWidget}
|
||||
apiPrefix={apiPrefix}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Tabs
|
||||
horizontal
|
||||
options={tabsOptions}
|
||||
currentTabOrPath={curTab}
|
||||
onTabClick={(newValue) => {
|
||||
setCurTab(newValue);
|
||||
}}
|
||||
/>
|
||||
</PageLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(PrDashboard);
|
||||
export default PrDashboard;
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment, useEffect, useRef, useState } from "react";
|
||||
|
||||
import styled from "styled-components";
|
||||
import { Box, breakPoints, Grid, Loader } from "mds";
|
||||
import { useSelector } from "react-redux";
|
||||
import {
|
||||
Bar,
|
||||
BarChart,
|
||||
@@ -25,46 +27,36 @@ import {
|
||||
XAxis,
|
||||
YAxis,
|
||||
} from "recharts";
|
||||
import { Grid, useMediaQuery } from "@mui/material";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { IBarChartConfiguration } from "./types";
|
||||
import { widgetCommon } from "../../../Common/FormComponents/common/styleLibrary";
|
||||
import BarChartTooltip from "./tooltips/BarChartTooltip";
|
||||
import { IDashboardPanel } from "../types";
|
||||
import { widgetDetailsToPanel } from "../utils";
|
||||
import { ErrorResponseHandler } from "../../../../../common/types";
|
||||
import api from "../../../../../common/api";
|
||||
import { useTheme } from "@mui/styles";
|
||||
import { Loader } from "mds";
|
||||
import ExpandGraphLink from "./ExpandGraphLink";
|
||||
import { setErrorSnackMessage } from "../../../../../systemSlice";
|
||||
import { AppState, useAppDispatch } from "../../../../../store";
|
||||
import ExpandGraphLink from "./ExpandGraphLink";
|
||||
import DownloadWidgetDataButton from "../../DownloadWidgetDataButton";
|
||||
import { useSelector } from "react-redux";
|
||||
import BarChartTooltip from "./tooltips/BarChartTooltip";
|
||||
import api from "../../../../../common/api";
|
||||
|
||||
interface IBarChartWidget {
|
||||
classes: any;
|
||||
title: string;
|
||||
panelItem: IDashboardPanel;
|
||||
timeStart: any;
|
||||
timeEnd: any;
|
||||
propLoading: boolean;
|
||||
apiPrefix: string;
|
||||
zoomActivated?: boolean;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...widgetCommon,
|
||||
loadingAlign: {
|
||||
width: "100%",
|
||||
paddingTop: "15px",
|
||||
textAlign: "center",
|
||||
margin: "auto",
|
||||
},
|
||||
});
|
||||
const BarChartMain = styled.div(({ theme }) => ({
|
||||
...widgetCommon(theme),
|
||||
loadingAlign: {
|
||||
width: "100%",
|
||||
paddingTop: "15px",
|
||||
textAlign: "center",
|
||||
margin: "auto",
|
||||
},
|
||||
}));
|
||||
|
||||
const CustomizedAxisTick = ({ y, payload }: any) => {
|
||||
return (
|
||||
@@ -83,12 +75,10 @@ const CustomizedAxisTick = ({ y, payload }: any) => {
|
||||
};
|
||||
|
||||
const BarChartWidget = ({
|
||||
classes,
|
||||
title,
|
||||
panelItem,
|
||||
timeStart,
|
||||
timeEnd,
|
||||
propLoading,
|
||||
apiPrefix,
|
||||
zoomActivated = false,
|
||||
}: IBarChartWidget) => {
|
||||
@@ -97,10 +87,15 @@ const BarChartWidget = ({
|
||||
const [data, setData] = useState<any>([]);
|
||||
const [result, setResult] = useState<IDashboardPanel | null>(null);
|
||||
const [hover, setHover] = useState<boolean>(false);
|
||||
const [biggerThanMd, setBiggerThanMd] = useState<boolean>(
|
||||
window.innerWidth >= breakPoints.md,
|
||||
);
|
||||
|
||||
const componentRef = useRef<HTMLElement>();
|
||||
const widgetVersion = useSelector(
|
||||
(state: AppState) => state.dashboard.widgetLoadVersion,
|
||||
);
|
||||
|
||||
const onHover = () => {
|
||||
setHover(true);
|
||||
};
|
||||
@@ -112,6 +107,23 @@ const BarChartWidget = ({
|
||||
setLoading(true);
|
||||
}, [widgetVersion]);
|
||||
|
||||
useEffect(() => {
|
||||
const handleWindowResize = () => {
|
||||
let extMD = false;
|
||||
if (window.innerWidth >= breakPoints.md) {
|
||||
console.log("Bigger");
|
||||
extMD = true;
|
||||
}
|
||||
setBiggerThanMd(extMD);
|
||||
};
|
||||
|
||||
window.addEventListener("resize", handleWindowResize);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("resize", handleWindowResize);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (loading) {
|
||||
let stepCalc = 0;
|
||||
@@ -164,103 +176,112 @@ const BarChartWidget = ({
|
||||
});
|
||||
}
|
||||
|
||||
const theme = useTheme();
|
||||
const biggerThanMd = useMediaQuery(theme.breakpoints.up("md"));
|
||||
|
||||
return (
|
||||
<div
|
||||
className={zoomActivated ? "" : classes.singleValueContainer}
|
||||
onMouseOver={onHover}
|
||||
onMouseLeave={onStopHover}
|
||||
>
|
||||
{!zoomActivated && (
|
||||
<Grid container>
|
||||
<Grid item xs={10} alignItems={"start"} justifyItems={"start"}>
|
||||
<div className={classes.titleContainer}>{title}</div>
|
||||
</Grid>
|
||||
<Grid item xs={1} display={"flex"} justifyContent={"flex-end"}>
|
||||
{hover && <ExpandGraphLink panelItem={panelItem} />}
|
||||
</Grid>
|
||||
<Grid item xs={1} display={"flex"} justifyContent={"flex-end"}>
|
||||
<DownloadWidgetDataButton
|
||||
title={title}
|
||||
componentRef={componentRef}
|
||||
data={data}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
{loading && (
|
||||
<div className={classes.loadingAlign}>
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
{!loading && (
|
||||
<div
|
||||
ref={componentRef as React.RefObject<HTMLDivElement>}
|
||||
className={
|
||||
zoomActivated ? classes.zoomChartCont : classes.contentContainer
|
||||
}
|
||||
>
|
||||
<ResponsiveContainer width="99%">
|
||||
<BarChart
|
||||
data={data as object[]}
|
||||
layout={"vertical"}
|
||||
barCategoryGap={1}
|
||||
<BarChartMain>
|
||||
<Box
|
||||
className={zoomActivated ? "" : "singleValueContainer"}
|
||||
onMouseOver={onHover}
|
||||
onMouseLeave={onStopHover}
|
||||
>
|
||||
{!zoomActivated && (
|
||||
<Grid container>
|
||||
<Grid
|
||||
item
|
||||
xs={10}
|
||||
sx={{ alignItems: "start", justifyItems: "start" }}
|
||||
>
|
||||
<XAxis type="number" hide />
|
||||
<YAxis
|
||||
dataKey="name"
|
||||
type="category"
|
||||
interval={0}
|
||||
tick={<CustomizedAxisTick />}
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
width={150}
|
||||
hide={!biggerThanMd}
|
||||
style={{
|
||||
fontSize: "12px",
|
||||
fontWeight: 100,
|
||||
}}
|
||||
<div className={"titleContainer"}>{title}</div>
|
||||
</Grid>
|
||||
<Grid
|
||||
item
|
||||
xs={1}
|
||||
sx={{ display: "flex", justifyContent: "flex-end" }}
|
||||
>
|
||||
{hover && <ExpandGraphLink panelItem={panelItem} />}
|
||||
</Grid>
|
||||
<Grid
|
||||
item
|
||||
xs={1}
|
||||
sx={{ display: "flex", justifyContent: "flex-end" }}
|
||||
>
|
||||
<DownloadWidgetDataButton
|
||||
title={title}
|
||||
componentRef={componentRef}
|
||||
data={data}
|
||||
/>
|
||||
{barChartConfiguration.map((bar) => (
|
||||
<Bar
|
||||
key={`bar-${bar.dataKey}`}
|
||||
dataKey={bar.dataKey}
|
||||
fill={bar.color}
|
||||
background={bar.background}
|
||||
barSize={zoomActivated ? 25 : 12}
|
||||
>
|
||||
{barChartConfiguration.length === 1 ? (
|
||||
<Fragment>
|
||||
{data.map((_: any, index: number) => (
|
||||
<Cell
|
||||
key={`chart-bar-${index.toString()}`}
|
||||
fill={
|
||||
index === greatestIndex
|
||||
? bar.greatestColor
|
||||
: bar.color
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</Fragment>
|
||||
) : null}
|
||||
</Bar>
|
||||
))}
|
||||
<Tooltip
|
||||
cursor={{ fill: "rgba(255, 255, 255, 0.3)" }}
|
||||
content={
|
||||
<BarChartTooltip
|
||||
barChartConfiguration={barChartConfiguration}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
{loading && (
|
||||
<Box className={"loadingAlign"}>
|
||||
<Loader />
|
||||
</Box>
|
||||
)}
|
||||
{!loading && (
|
||||
<div
|
||||
ref={componentRef as React.RefObject<HTMLDivElement>}
|
||||
className={zoomActivated ? "zoomChartCont" : "contentContainer"}
|
||||
>
|
||||
<ResponsiveContainer width="99%">
|
||||
<BarChart
|
||||
data={data as object[]}
|
||||
layout={"vertical"}
|
||||
barCategoryGap={1}
|
||||
>
|
||||
<XAxis type="number" hide />
|
||||
<YAxis
|
||||
dataKey="name"
|
||||
type="category"
|
||||
interval={0}
|
||||
tick={<CustomizedAxisTick />}
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
width={150}
|
||||
hide={!biggerThanMd}
|
||||
style={{
|
||||
fontSize: "12px",
|
||||
fontWeight: 100,
|
||||
}}
|
||||
/>
|
||||
{barChartConfiguration.map((bar) => (
|
||||
<Bar
|
||||
key={`bar-${bar.dataKey}`}
|
||||
dataKey={bar.dataKey}
|
||||
fill={bar.color}
|
||||
background={bar.background}
|
||||
barSize={zoomActivated ? 25 : 12}
|
||||
>
|
||||
{barChartConfiguration.length === 1 ? (
|
||||
<Fragment>
|
||||
{data.map((_: any, index: number) => (
|
||||
<Cell
|
||||
key={`chart-bar-${index.toString()}`}
|
||||
fill={
|
||||
index === greatestIndex
|
||||
? bar.greatestColor
|
||||
: bar.color
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</Fragment>
|
||||
) : null}
|
||||
</Bar>
|
||||
))}
|
||||
<Tooltip
|
||||
cursor={{ fill: "rgba(255, 255, 255, 0.3)" }}
|
||||
content={
|
||||
<BarChartTooltip
|
||||
barChartConfiguration={barChartConfiguration}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
)}
|
||||
</Box>
|
||||
</BarChartMain>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(BarChartWidget);
|
||||
export default BarChartWidget;
|
||||
|
||||
@@ -15,34 +15,81 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { IDashboardPanel } from "../types";
|
||||
import { Box } from "@mui/material";
|
||||
import styled from "styled-components";
|
||||
import get from "lodash/get";
|
||||
import { Box, breakPoints, Loader, ReportedUsageIcon } from "mds";
|
||||
import { Cell, Pie, PieChart } from "recharts";
|
||||
import { useSelector } from "react-redux";
|
||||
import api from "../../../../../common/api";
|
||||
import { IDashboardPanel } from "../types";
|
||||
import { widgetDetailsToPanel } from "../utils";
|
||||
import { ErrorResponseHandler } from "../../../../../common/types";
|
||||
|
||||
import {
|
||||
calculateBytes,
|
||||
capacityColors,
|
||||
niceBytesInt,
|
||||
} from "../../../../../common/utils";
|
||||
import { Cell, Pie, PieChart } from "recharts";
|
||||
import { Loader, ReportedUsageIcon } from "mds";
|
||||
import { setErrorSnackMessage } from "../../../../../systemSlice";
|
||||
import { AppState, useAppDispatch } from "../../../../../store";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
const CapacityItemMain = styled.div(({ theme }) => ({
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flexFlow: "row",
|
||||
"& .usableLabel": {
|
||||
color: get(theme, "mutedText", "#87888d"),
|
||||
fontSize: "10px",
|
||||
display: "flex",
|
||||
flexFlow: "column",
|
||||
alignItems: "center",
|
||||
textAlign: "center",
|
||||
},
|
||||
"& .usedLabel": {
|
||||
color: get(theme, "mutedText", "#87888d"),
|
||||
fontWeight: "bold",
|
||||
fontSize: "14px",
|
||||
},
|
||||
"& .totalUsed": {
|
||||
display: "flex",
|
||||
"& .value": {
|
||||
fontSize: "50px",
|
||||
fontFamily: "Inter",
|
||||
fontWeight: 600,
|
||||
alignSelf: "flex-end",
|
||||
lineHeight: 1,
|
||||
},
|
||||
"& .unit": {
|
||||
color: get(theme, "mutedText", "#87888d"),
|
||||
fontWeight: "bold",
|
||||
fontSize: "14px",
|
||||
marginLeft: "12px",
|
||||
alignSelf: "flex-end",
|
||||
},
|
||||
},
|
||||
"& .ofUsed": {
|
||||
marginTop: "5px",
|
||||
"& .value": {
|
||||
color: get(theme, "mutedText", "#87888d"),
|
||||
fontWeight: "bold",
|
||||
fontSize: "14px",
|
||||
textAlign: "right",
|
||||
},
|
||||
},
|
||||
[`@media (max-width: ${breakPoints.sm}px)`]: {
|
||||
flexFlow: "column",
|
||||
},
|
||||
}));
|
||||
|
||||
const CapacityItem = ({
|
||||
value,
|
||||
timeStart,
|
||||
timeEnd,
|
||||
propLoading,
|
||||
apiPrefix,
|
||||
}: {
|
||||
value: IDashboardPanel;
|
||||
timeStart: any;
|
||||
timeEnd: any;
|
||||
propLoading: boolean;
|
||||
apiPrefix: string;
|
||||
}) => {
|
||||
const dispatch = useAppDispatch();
|
||||
@@ -134,23 +181,13 @@ const CapacityItem = ({
|
||||
},
|
||||
];
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flexFlow: {
|
||||
sm: "row",
|
||||
xs: "column",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<CapacityItemMain>
|
||||
<Box
|
||||
sx={{
|
||||
fontSize: "16px",
|
||||
fontWeight: 600,
|
||||
alignSelf: {
|
||||
xs: "flex-start",
|
||||
[`@media (max-width: ${breakPoints.sm}px)`]: {
|
||||
alignSelf: "flex-start",
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -161,9 +198,9 @@ const CapacityItem = ({
|
||||
position: "relative",
|
||||
width: 110,
|
||||
height: 110,
|
||||
marginLeft: {
|
||||
sm: "auto",
|
||||
xs: "",
|
||||
marginLeft: "auto",
|
||||
[`@media (max-width: ${breakPoints.sm}px)`]: {
|
||||
marginLeft: "",
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -177,24 +214,12 @@ const CapacityItem = ({
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
fontWeight: "bold",
|
||||
color: "#000",
|
||||
fontSize: 12,
|
||||
}}
|
||||
>
|
||||
{`${totalUsableFreeRatio}%`}
|
||||
<br />
|
||||
<Box
|
||||
sx={{
|
||||
color: "#8F9090",
|
||||
fontSize: "10px",
|
||||
display: "flex",
|
||||
flexFlow: "column",
|
||||
alignItems: "center",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
Free
|
||||
</Box>
|
||||
<Box className={"usableLabel"}>Free</Box>
|
||||
</Box>
|
||||
<PieChart width={110} height={110}>
|
||||
<Pie
|
||||
@@ -218,55 +243,19 @@ const CapacityItem = ({
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
marginLeft: {
|
||||
sm: "auto",
|
||||
xs: "",
|
||||
marginLeft: "auto",
|
||||
[`@media (max-width: ${breakPoints.sm}px)`]: {
|
||||
marginLeft: "",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box>
|
||||
<Box
|
||||
sx={{
|
||||
color: "#5E5E5E",
|
||||
fontWeight: "bold",
|
||||
fontSize: "14px",
|
||||
}}
|
||||
>
|
||||
Used:
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
"& .value": {
|
||||
fontSize: "50px",
|
||||
fontFamily: "Inter",
|
||||
fontWeight: 600,
|
||||
alignSelf: "flex-end",
|
||||
lineHeight: 1,
|
||||
},
|
||||
"& .unit": {
|
||||
color: "#5E5E5E",
|
||||
fontWeight: "bold",
|
||||
fontSize: "14px",
|
||||
marginLeft: "12px",
|
||||
alignSelf: "flex-end",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box className={"usedLabel"}>Used:</Box>
|
||||
<Box className={"totalUsed"}>
|
||||
<div className="value">{usedConvert.total}</div>
|
||||
<div className="unit">{usedConvert.unit}</div>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: "5px",
|
||||
"& .value": {
|
||||
color: "#5E5E5E",
|
||||
fontWeight: "bold",
|
||||
fontSize: "14px",
|
||||
textAlign: "right",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box className={"ofUsed"}>
|
||||
<div className="value">Of: {niceBytesInt(totalUsable)}</div>
|
||||
</Box>
|
||||
</Box>
|
||||
@@ -288,7 +277,7 @@ const CapacityItem = ({
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</CapacityItemMain>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -15,7 +15,24 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import { Box } from "@mui/material";
|
||||
import styled from "styled-components";
|
||||
import get from "lodash/get";
|
||||
import { Box, breakPoints } from "mds";
|
||||
|
||||
const DualSTCardContent = styled.div(({ theme }) => ({
|
||||
fontFamily: "Inter,sans-serif",
|
||||
color: get(theme, "signalColors.main", "#07193E"),
|
||||
maxWidth: "321px",
|
||||
display: "flex",
|
||||
marginLeft: "auto",
|
||||
marginRight: "auto",
|
||||
cursor: "default",
|
||||
"& .stat-text": {
|
||||
color: get(theme, "mutedText", "#87888d"),
|
||||
fontSize: "12px",
|
||||
marginTop: "8px",
|
||||
},
|
||||
}));
|
||||
|
||||
const DualStatCard = ({
|
||||
statItemLeft = null,
|
||||
@@ -34,9 +51,9 @@ const DualStatCard = ({
|
||||
sx={{
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
padding: {
|
||||
sm: "0 8px 0 8px",
|
||||
xs: "0 10px 0 10px",
|
||||
padding: "0 8px 0 8px",
|
||||
[`@media (max-width: ${breakPoints.sm}px)`]: {
|
||||
padding: "0 10px 0 10px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -60,26 +77,12 @@ const DualStatCard = ({
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "5px",
|
||||
gap: 5,
|
||||
justifyContent: "space-between",
|
||||
paddingBottom: {
|
||||
md: "0px",
|
||||
xs: "10px",
|
||||
},
|
||||
fontSize: {
|
||||
xl: "55px",
|
||||
lg: "50px",
|
||||
md: "45px",
|
||||
xs: "35px",
|
||||
},
|
||||
paddingBottom: 0,
|
||||
fontSize: 55,
|
||||
flexFlow: "row",
|
||||
fontWeight: 600,
|
||||
|
||||
"& .stat-text": {
|
||||
color: "#696969",
|
||||
fontSize: "12px",
|
||||
marginTop: "8px",
|
||||
},
|
||||
"& .stat-value": {
|
||||
textAlign: "center",
|
||||
height: "50px",
|
||||
@@ -90,6 +93,15 @@ const DualStatCard = ({
|
||||
height: "10px",
|
||||
width: "10px",
|
||||
},
|
||||
[`@media (max-width: ${breakPoints.sm}px)`]: {
|
||||
fontSize: 35,
|
||||
},
|
||||
[`@media (max-width: ${breakPoints.lg}px)`]: {
|
||||
fontSize: 45,
|
||||
},
|
||||
[`@media (max-width: ${breakPoints.xl}px)`]: {
|
||||
fontSize: 50,
|
||||
},
|
||||
}}
|
||||
>
|
||||
{statItemLeft}
|
||||
@@ -114,21 +126,7 @@ const DualStatCard = ({
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
fontFamily: "Inter,sans-serif",
|
||||
color: "#07193E",
|
||||
maxWidth: "321px",
|
||||
display: "flex",
|
||||
marginLeft: "auto",
|
||||
marginRight: "auto",
|
||||
cursor: "default",
|
||||
}}
|
||||
>
|
||||
{getContent()}
|
||||
</Box>
|
||||
);
|
||||
return <DualSTCardContent>{getContent()}</DualSTCardContent>;
|
||||
};
|
||||
|
||||
export default DualStatCard;
|
||||
|
||||
@@ -15,23 +15,45 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import get from "lodash/get";
|
||||
import { CircleIcon, DrivesIcon, ServersIcon, Box } from "mds";
|
||||
import EntityStateStatItem from "./EntityStateStatItem";
|
||||
import { Box } from "@mui/material";
|
||||
import { CircleIcon, DrivesIcon, ServersIcon } from "mds";
|
||||
import DualStatCard from "./DualStatCard";
|
||||
import { IDashboardPanel } from "../types";
|
||||
|
||||
const StateIndicator = styled.div(({ theme }) => ({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
marginTop: "5px",
|
||||
gap: 8,
|
||||
"&.online": {
|
||||
"& .min-icon": {
|
||||
margin: 0,
|
||||
fill: get(theme, "signalColors.good", "#4CCB92"),
|
||||
},
|
||||
},
|
||||
"&.offline": {
|
||||
"& .min-icon": {
|
||||
margin: 0,
|
||||
fill: get(theme, "signalColors.danger", "#C51B3F"),
|
||||
},
|
||||
},
|
||||
"& .indicatorText": {
|
||||
color: get(theme, "mutedText", "#C51B3F"),
|
||||
fontSize: 12,
|
||||
},
|
||||
}));
|
||||
|
||||
const EntityStateItemRenderer = ({
|
||||
info,
|
||||
timeStart,
|
||||
timeEnd,
|
||||
loading,
|
||||
apiPrefix,
|
||||
}: {
|
||||
info: IDashboardPanel;
|
||||
timeStart: any;
|
||||
timeEnd: any;
|
||||
loading: boolean;
|
||||
apiPrefix: string;
|
||||
}) => {
|
||||
const { mergedPanels = [], id } = info;
|
||||
@@ -42,22 +64,12 @@ const EntityStateItemRenderer = ({
|
||||
panelItem={leftPanel}
|
||||
timeStart={timeStart}
|
||||
timeEnd={timeEnd}
|
||||
propLoading={loading}
|
||||
apiPrefix={apiPrefix}
|
||||
statLabel={
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
marginTop: "5px",
|
||||
"& .min-icon": {
|
||||
fill: "#4CCB92",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<StateIndicator className={"online"}>
|
||||
<CircleIcon />
|
||||
<div className="stat-text">Online</div>
|
||||
</Box>
|
||||
<Box className="indicatorText">Online</Box>
|
||||
</StateIndicator>
|
||||
}
|
||||
/>
|
||||
);
|
||||
@@ -66,22 +78,12 @@ const EntityStateItemRenderer = ({
|
||||
panelItem={rightPanel}
|
||||
timeStart={timeStart}
|
||||
timeEnd={timeEnd}
|
||||
propLoading={loading}
|
||||
apiPrefix={apiPrefix}
|
||||
statLabel={
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
marginTop: "5px",
|
||||
"& .min-icon": {
|
||||
fill: "#C83B51",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<StateIndicator className={"offline"}>
|
||||
<CircleIcon />
|
||||
<div className="stat-text">Offline</div>
|
||||
</Box>
|
||||
<Box className="indicatorText">Offline</Box>
|
||||
</StateIndicator>
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -15,29 +15,25 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Box } from "@mui/material";
|
||||
import api from "../../../../../common/api";
|
||||
import { Loader, Box } from "mds";
|
||||
import { useSelector } from "react-redux";
|
||||
import { widgetDetailsToPanel } from "../utils";
|
||||
import { ErrorResponseHandler } from "../../../../../common/types";
|
||||
import { IDashboardPanel } from "../types";
|
||||
import { Loader } from "mds";
|
||||
|
||||
import { setErrorSnackMessage } from "../../../../../systemSlice";
|
||||
import { AppState, useAppDispatch } from "../../../../../store";
|
||||
import { useSelector } from "react-redux";
|
||||
import api from "../../../../../common/api";
|
||||
|
||||
const EntityStateStatItem = ({
|
||||
panelItem,
|
||||
timeStart,
|
||||
timeEnd,
|
||||
propLoading,
|
||||
apiPrefix,
|
||||
statLabel,
|
||||
}: {
|
||||
panelItem: IDashboardPanel;
|
||||
timeStart: any;
|
||||
timeEnd: any;
|
||||
propLoading: boolean;
|
||||
apiPrefix: string;
|
||||
statLabel: any;
|
||||
}) => {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import { Box } from "@mui/material";
|
||||
import { Box, breakPoints } from "mds";
|
||||
import TimeStatItem from "../../TimeStatItem";
|
||||
|
||||
export type SimpleWidgetRenderProps = {
|
||||
@@ -50,9 +50,9 @@ const HealActivityRenderer = ({
|
||||
<Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: {
|
||||
md: "inline",
|
||||
xs: "none",
|
||||
display: "inline",
|
||||
[`@media (max-width: ${breakPoints.sm}px)`]: {
|
||||
display: "none",
|
||||
},
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -14,15 +14,16 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { Box } from "@mui/material";
|
||||
import { SxProps, Theme } from "@mui/material/styles";
|
||||
import { Box } from "mds";
|
||||
import { CSSObject } from "styled-components";
|
||||
import { breakPoints } from "mds";
|
||||
|
||||
export type DLayoutColumnProps = {
|
||||
componentId: number;
|
||||
sx?: SxProps<Theme>;
|
||||
sx?: CSSObject;
|
||||
};
|
||||
export type DLayoutRowProps = {
|
||||
sx?: SxProps<Theme>;
|
||||
sx?: CSSObject;
|
||||
columns: DLayoutColumnProps[];
|
||||
};
|
||||
|
||||
@@ -31,12 +32,14 @@ export const summaryPanelsLayout: DLayoutRowProps[] = [
|
||||
sx: {
|
||||
minWidth: 0,
|
||||
display: "grid",
|
||||
gridTemplateColumns: {
|
||||
md: "1fr 1fr 1fr 1fr",
|
||||
sm: "1fr 1fr",
|
||||
xs: "1fr",
|
||||
},
|
||||
gap: "30px",
|
||||
gridTemplateColumns: "1fr 1fr 1fr 1fr",
|
||||
[`@media (max-width: ${breakPoints.sm}px)`]: {
|
||||
gridTemplateColumns: "1fr",
|
||||
},
|
||||
[`@media (max-width: ${breakPoints.md}px)`]: {
|
||||
gridTemplateColumns: "1fr 1fr",
|
||||
},
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
@@ -57,11 +60,11 @@ export const summaryPanelsLayout: DLayoutRowProps[] = [
|
||||
sx: {
|
||||
display: "grid",
|
||||
minWidth: 0, // important to avoid css grid blow out.
|
||||
gridTemplateColumns: {
|
||||
md: "1fr 1fr",
|
||||
xs: "1fr",
|
||||
},
|
||||
gap: "30px",
|
||||
gridTemplateColumns: "1fr 1fr",
|
||||
[`@media (max-width: ${breakPoints.md}px)`]: {
|
||||
gridTemplateColumns: "1fr",
|
||||
},
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
@@ -76,11 +79,11 @@ export const summaryPanelsLayout: DLayoutRowProps[] = [
|
||||
sx: {
|
||||
display: "grid",
|
||||
minWidth: 0,
|
||||
gridTemplateColumns: {
|
||||
md: "1fr 1fr 1fr",
|
||||
xs: "1fr",
|
||||
},
|
||||
gap: "30px",
|
||||
gridTemplateColumns: "1fr 1fr 1fr",
|
||||
[`@media (max-width: ${breakPoints.md}px)`]: {
|
||||
gridTemplateColumns: "1fr",
|
||||
},
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
@@ -98,11 +101,11 @@ export const summaryPanelsLayout: DLayoutRowProps[] = [
|
||||
sx: {
|
||||
display: "grid",
|
||||
minWidth: 0,
|
||||
gridTemplateColumns: {
|
||||
sm: "1fr 1fr",
|
||||
xs: "1fr",
|
||||
},
|
||||
gap: "30px",
|
||||
gridTemplateColumns: "1fr 1fr",
|
||||
[`@media (max-width: ${breakPoints.md}px)`]: {
|
||||
gridTemplateColumns: "1fr",
|
||||
},
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
@@ -117,11 +120,11 @@ export const summaryPanelsLayout: DLayoutRowProps[] = [
|
||||
sx: {
|
||||
display: "grid",
|
||||
minWidth: 0,
|
||||
gridTemplateColumns: {
|
||||
sm: "1fr 1fr",
|
||||
xs: "1fr",
|
||||
},
|
||||
gap: "30px",
|
||||
gridTemplateColumns: "1fr 1fr",
|
||||
[`@media (max-width: ${breakPoints.md}px)`]: {
|
||||
gridTemplateColumns: "1fr",
|
||||
},
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
@@ -151,11 +154,11 @@ export const trafficPanelsLayout: DLayoutRowProps[] = [
|
||||
sx: {
|
||||
display: "grid",
|
||||
minWidth: 0,
|
||||
gridTemplateColumns: {
|
||||
sm: "1fr 1fr",
|
||||
xs: "1fr",
|
||||
},
|
||||
gap: "30px",
|
||||
gridTemplateColumns: "1fr 1fr",
|
||||
[`@media (max-width: ${breakPoints.md}px)`]: {
|
||||
gridTemplateColumns: "1fr",
|
||||
},
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment, useEffect, useRef, useState } from "react";
|
||||
import styled from "styled-components";
|
||||
import get from "lodash/get";
|
||||
import { useSelector } from "react-redux";
|
||||
import {
|
||||
Area,
|
||||
AreaChart,
|
||||
@@ -24,32 +27,24 @@ import {
|
||||
XAxis,
|
||||
YAxis,
|
||||
} from "recharts";
|
||||
import { Box, Grid, useMediaQuery } from "@mui/material";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { Box, breakPoints, Grid, Loader } from "mds";
|
||||
import { ILinearGraphConfiguration } from "./types";
|
||||
import { widgetCommon } from "../../../Common/FormComponents/common/styleLibrary";
|
||||
import { IDashboardPanel } from "../types";
|
||||
import { widgetDetailsToPanel } from "../utils";
|
||||
import { ErrorResponseHandler } from "../../../../../common/types";
|
||||
import api from "../../../../../common/api";
|
||||
import LineChartTooltip from "./tooltips/LineChartTooltip";
|
||||
import { useTheme } from "@mui/styles";
|
||||
import { Loader } from "mds";
|
||||
import ExpandGraphLink from "./ExpandGraphLink";
|
||||
import { setErrorSnackMessage } from "../../../../../systemSlice";
|
||||
import { AppState, useAppDispatch } from "../../../../../store";
|
||||
import api from "../../../../../common/api";
|
||||
import LineChartTooltip from "./tooltips/LineChartTooltip";
|
||||
import ExpandGraphLink from "./ExpandGraphLink";
|
||||
import DownloadWidgetDataButton from "../../DownloadWidgetDataButton";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
interface ILinearGraphWidget {
|
||||
classes: any;
|
||||
title: string;
|
||||
panelItem: IDashboardPanel;
|
||||
timeStart: any;
|
||||
timeEnd: any;
|
||||
propLoading: boolean;
|
||||
apiPrefix: string;
|
||||
hideYAxis?: boolean;
|
||||
yAxisFormatter?: (item: string) => string;
|
||||
@@ -58,43 +53,43 @@ interface ILinearGraphWidget {
|
||||
zoomActivated?: boolean;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...widgetCommon,
|
||||
chartCont: {
|
||||
position: "relative",
|
||||
height: 140,
|
||||
width: "100%",
|
||||
const LinearGraphMain = styled.div(({ theme }) => ({
|
||||
...widgetCommon(theme),
|
||||
"& .chartCont": {
|
||||
position: "relative",
|
||||
height: 140,
|
||||
width: "100%",
|
||||
},
|
||||
"& .legendChart": {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
flex: "0 1 auto",
|
||||
maxHeight: 130,
|
||||
margin: 0,
|
||||
overflowY: "auto",
|
||||
position: "relative",
|
||||
textAlign: "center",
|
||||
width: "100%",
|
||||
justifyContent: "flex-start",
|
||||
color: get(theme, "mutedText", "#87888d"),
|
||||
fontWeight: "bold",
|
||||
fontSize: 12,
|
||||
[`@media (max-width: ${breakPoints.md}px)`]: {
|
||||
display: "none",
|
||||
},
|
||||
legendChart: {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
flex: "0 1 auto",
|
||||
maxHeight: 130,
|
||||
margin: 0,
|
||||
overflowY: "auto",
|
||||
position: "relative",
|
||||
textAlign: "center",
|
||||
width: "100%",
|
||||
justifyContent: "flex-start",
|
||||
color: "#404143",
|
||||
fontWeight: "bold",
|
||||
fontSize: 12,
|
||||
},
|
||||
loadingAlign: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
textAlign: "center",
|
||||
margin: "15px auto",
|
||||
},
|
||||
});
|
||||
},
|
||||
"& .loadingAlign": {
|
||||
width: 40,
|
||||
height: 40,
|
||||
textAlign: "center",
|
||||
margin: "15px auto",
|
||||
},
|
||||
}));
|
||||
|
||||
const LinearGraphWidget = ({
|
||||
classes,
|
||||
title,
|
||||
timeStart,
|
||||
timeEnd,
|
||||
propLoading,
|
||||
panelItem,
|
||||
apiPrefix,
|
||||
hideYAxis = false,
|
||||
@@ -114,7 +109,7 @@ const LinearGraphWidget = ({
|
||||
(state: AppState) => state.dashboard.widgetLoadVersion,
|
||||
);
|
||||
|
||||
const componentRef = useRef<HTMLElement>();
|
||||
const componentRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
@@ -208,9 +203,6 @@ const LinearGraphWidget = ({
|
||||
return <circle cx={cx} cy={cy} r={3} strokeWidth={0} fill="#07264A" />;
|
||||
};
|
||||
|
||||
const theme = useTheme();
|
||||
const biggerThanMd = useMediaQuery(theme.breakpoints.up("md"));
|
||||
|
||||
let dspLongDate = false;
|
||||
|
||||
if (zoomActivated) {
|
||||
@@ -218,185 +210,205 @@ const LinearGraphWidget = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<Box
|
||||
className={zoomActivated ? "" : classes.singleValueContainer}
|
||||
onMouseOver={onHover}
|
||||
onMouseLeave={onStopHover}
|
||||
>
|
||||
{!zoomActivated && (
|
||||
<Grid container alignItems={"left"}>
|
||||
<Grid item xs={10} alignItems={"start"}>
|
||||
<div className={classes.titleContainer}>{title}</div>
|
||||
</Grid>
|
||||
<Grid
|
||||
item
|
||||
xs={1}
|
||||
display={"flex"}
|
||||
justifyContent={"flex-end"}
|
||||
alignContent={"flex-end"}
|
||||
>
|
||||
{hover && <ExpandGraphLink panelItem={panelItem} />}
|
||||
</Grid>
|
||||
<Grid item xs={1} display={"flex"} justifyContent={"flex-end"}>
|
||||
<DownloadWidgetDataButton
|
||||
title={title}
|
||||
componentRef={componentRef}
|
||||
data={csvData}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
<LinearGraphMain>
|
||||
<Box
|
||||
sx={
|
||||
zoomActivated
|
||||
? { flexDirection: "column" }
|
||||
: {
|
||||
height: "100%",
|
||||
display: "grid",
|
||||
gridTemplateColumns: {
|
||||
md: "1fr 1fr",
|
||||
sm: "1fr",
|
||||
},
|
||||
}
|
||||
}
|
||||
style={areaWidget ? { gridTemplateColumns: "1fr" } : {}}
|
||||
ref={componentRef}
|
||||
className={zoomActivated ? "" : "singleValueContainer"}
|
||||
onMouseOver={onHover}
|
||||
onMouseLeave={onStopHover}
|
||||
>
|
||||
{loading && <Loader className={classes.loadingAlign} />}
|
||||
{!loading && (
|
||||
<React.Fragment>
|
||||
<div
|
||||
className={
|
||||
zoomActivated ? classes.zoomChartCont : classes.chartCont
|
||||
}
|
||||
{!zoomActivated && (
|
||||
<Grid container>
|
||||
<Grid item xs={10} sx={{ alignItems: "start" }}>
|
||||
<Box className={"titleContainer"}>{title}</Box>
|
||||
</Grid>
|
||||
<Grid
|
||||
item
|
||||
xs={1}
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "flex-end",
|
||||
alignContent: "flex-end",
|
||||
}}
|
||||
>
|
||||
<ResponsiveContainer width="99%">
|
||||
<AreaChart
|
||||
data={data}
|
||||
margin={{
|
||||
top: 5,
|
||||
right: 20,
|
||||
left: hideYAxis ? 20 : 5,
|
||||
bottom: 0,
|
||||
}}
|
||||
>
|
||||
{areaWidget && (
|
||||
<defs>
|
||||
<linearGradient id="colorUv" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stopColor="#2781B0" stopOpacity={1} />
|
||||
<stop
|
||||
offset="100%"
|
||||
stopColor="#ffffff"
|
||||
stopOpacity={0}
|
||||
/>
|
||||
|
||||
<stop
|
||||
offset="95%"
|
||||
stopColor="#ffffff"
|
||||
stopOpacity={0.8}
|
||||
/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
)}
|
||||
<CartesianGrid
|
||||
strokeDasharray={areaWidget ? "2 2" : "5 5"}
|
||||
strokeWidth={1}
|
||||
strokeOpacity={1}
|
||||
stroke={"#eee0e0"}
|
||||
vertical={!areaWidget}
|
||||
/>
|
||||
<XAxis
|
||||
dataKey="name"
|
||||
tickFormatter={(value: any) =>
|
||||
xAxisFormatter(value, dspLongDate, true)
|
||||
}
|
||||
interval={intervalCount}
|
||||
tick={{
|
||||
fontSize: "68%",
|
||||
fontWeight: "normal",
|
||||
color: "#404143",
|
||||
}}
|
||||
tickCount={10}
|
||||
stroke={"#082045"}
|
||||
/>
|
||||
<YAxis
|
||||
type={"number"}
|
||||
domain={[0, dataMax * 1.1]}
|
||||
hide={hideYAxis}
|
||||
tickFormatter={(value: any) => yAxisFormatter(value)}
|
||||
tick={{
|
||||
fontSize: "68%",
|
||||
fontWeight: "normal",
|
||||
color: "#404143",
|
||||
}}
|
||||
stroke={"#082045"}
|
||||
/>
|
||||
{linearConfiguration.map((section, index) => {
|
||||
return (
|
||||
<Area
|
||||
key={`area-${section.dataKey}-${index.toString()}`}
|
||||
type="monotone"
|
||||
dataKey={section.dataKey}
|
||||
isAnimationActive={false}
|
||||
stroke={!areaWidget ? section.lineColor : "#D7E5F8"}
|
||||
fill={areaWidget ? "url(#colorUv)" : section.fillColor}
|
||||
fillOpacity={areaWidget ? 0.65 : 0}
|
||||
strokeWidth={!areaWidget ? 3 : 0}
|
||||
strokeLinecap={"round"}
|
||||
dot={areaWidget ? <CustomizedDot /> : false}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<Tooltip
|
||||
content={
|
||||
<LineChartTooltip
|
||||
linearConfiguration={linearConfiguration}
|
||||
yAxisFormatter={yAxisFormatter}
|
||||
/>
|
||||
}
|
||||
wrapperStyle={{
|
||||
zIndex: 5000,
|
||||
}}
|
||||
/>
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
{!areaWidget && (
|
||||
{hover && <ExpandGraphLink panelItem={panelItem} />}
|
||||
</Grid>
|
||||
<Grid
|
||||
item
|
||||
xs={1}
|
||||
sx={{ display: "flex", justifyContent: "flex-end" }}
|
||||
>
|
||||
{componentRef !== null && (
|
||||
<DownloadWidgetDataButton
|
||||
title={title}
|
||||
componentRef={componentRef}
|
||||
data={csvData}
|
||||
/>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
<div ref={componentRef}>
|
||||
<Box
|
||||
sx={
|
||||
zoomActivated
|
||||
? { flexDirection: "column" }
|
||||
: {
|
||||
height: "100%",
|
||||
display: "grid",
|
||||
gridTemplateColumns: "1fr 1fr",
|
||||
[`@media (max-width: ${breakPoints.md}px)`]: {
|
||||
gridTemplateColumns: "1fr",
|
||||
},
|
||||
}
|
||||
}
|
||||
style={areaWidget ? { gridTemplateColumns: "1fr" } : {}}
|
||||
>
|
||||
{loading && <Loader className={"loadingAlign"} />}
|
||||
{!loading && (
|
||||
<Fragment>
|
||||
{zoomActivated && (
|
||||
<Fragment>
|
||||
<strong>Series</strong>
|
||||
<br />
|
||||
<br />
|
||||
</Fragment>
|
||||
)}
|
||||
{biggerThanMd && (
|
||||
<div className={classes.legendChart}>
|
||||
{linearConfiguration.map((section, index) => {
|
||||
return (
|
||||
<div
|
||||
className={classes.singleLegendContainer}
|
||||
key={`legend-${section.keyLabel}-${index.toString()}`}
|
||||
>
|
||||
<div
|
||||
className={classes.colorContainer}
|
||||
style={{ backgroundColor: section.lineColor }}
|
||||
<Box className={zoomActivated ? "zoomChartCont" : "chartCont"}>
|
||||
<ResponsiveContainer width="99%">
|
||||
<AreaChart
|
||||
data={data}
|
||||
margin={{
|
||||
top: 5,
|
||||
right: 20,
|
||||
left: hideYAxis ? 20 : 5,
|
||||
bottom: 0,
|
||||
}}
|
||||
>
|
||||
{areaWidget && (
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="colorUv"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="0"
|
||||
y2="1"
|
||||
>
|
||||
<stop
|
||||
offset="0%"
|
||||
stopColor="#2781B0"
|
||||
stopOpacity={1}
|
||||
/>
|
||||
<stop
|
||||
offset="100%"
|
||||
stopColor="#ffffff"
|
||||
stopOpacity={0}
|
||||
/>
|
||||
|
||||
<stop
|
||||
offset="95%"
|
||||
stopColor="#ffffff"
|
||||
stopOpacity={0.8}
|
||||
/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
)}
|
||||
<CartesianGrid
|
||||
strokeDasharray={areaWidget ? "2 2" : "5 5"}
|
||||
strokeWidth={1}
|
||||
strokeOpacity={1}
|
||||
stroke={"#eee0e0"}
|
||||
vertical={!areaWidget}
|
||||
/>
|
||||
<XAxis
|
||||
dataKey="name"
|
||||
tickFormatter={(value: any) =>
|
||||
xAxisFormatter(value, dspLongDate, true)
|
||||
}
|
||||
interval={intervalCount}
|
||||
tick={{
|
||||
fontSize: "68%",
|
||||
fontWeight: "normal",
|
||||
color: "#404143",
|
||||
}}
|
||||
tickCount={10}
|
||||
stroke={"#082045"}
|
||||
/>
|
||||
<YAxis
|
||||
type={"number"}
|
||||
domain={[0, dataMax * 1.1]}
|
||||
hide={hideYAxis}
|
||||
tickFormatter={(value: any) => yAxisFormatter(value)}
|
||||
tick={{
|
||||
fontSize: "68%",
|
||||
fontWeight: "normal",
|
||||
color: "#404143",
|
||||
}}
|
||||
stroke={"#082045"}
|
||||
/>
|
||||
{linearConfiguration.map((section, index) => {
|
||||
return (
|
||||
<Area
|
||||
key={`area-${section.dataKey}-${index.toString()}`}
|
||||
type="monotone"
|
||||
dataKey={section.dataKey}
|
||||
isAnimationActive={false}
|
||||
stroke={!areaWidget ? section.lineColor : "#D7E5F8"}
|
||||
fill={
|
||||
areaWidget ? "url(#colorUv)" : section.fillColor
|
||||
}
|
||||
fillOpacity={areaWidget ? 0.65 : 0}
|
||||
strokeWidth={!areaWidget ? 3 : 0}
|
||||
strokeLinecap={"round"}
|
||||
dot={areaWidget ? <CustomizedDot /> : false}
|
||||
/>
|
||||
<div className={classes.legendLabel}>
|
||||
{section.keyLabel}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<Tooltip
|
||||
content={
|
||||
<LineChartTooltip
|
||||
linearConfiguration={linearConfiguration}
|
||||
yAxisFormatter={yAxisFormatter}
|
||||
/>
|
||||
}
|
||||
wrapperStyle={{
|
||||
zIndex: 5000,
|
||||
}}
|
||||
/>
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
</Box>
|
||||
{!areaWidget && (
|
||||
<Fragment>
|
||||
{zoomActivated && (
|
||||
<Fragment>
|
||||
<strong>Series</strong>
|
||||
<br />
|
||||
<br />
|
||||
</Fragment>
|
||||
)}
|
||||
|
||||
<Box className={"legendChart"}>
|
||||
{linearConfiguration.map((section, index) => {
|
||||
return (
|
||||
<Box
|
||||
className={"singleLegendContainer"}
|
||||
key={`legend-${
|
||||
section.keyLabel
|
||||
}-${index.toString()}`}
|
||||
>
|
||||
<Box
|
||||
className={"colorContainer"}
|
||||
style={{ backgroundColor: section.lineColor }}
|
||||
/>
|
||||
<Box className={"legendLabel"}>
|
||||
{section.keyLabel}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
</Fragment>
|
||||
)}
|
||||
</Fragment>
|
||||
)}
|
||||
</React.Fragment>
|
||||
)}
|
||||
</Box>
|
||||
</div>
|
||||
</Box>
|
||||
</Box>
|
||||
</LinearGraphMain>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(LinearGraphWidget);
|
||||
export default LinearGraphWidget;
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
import React from "react";
|
||||
import { componentToUse } from "../widgetUtils";
|
||||
import MergedWidgets from "../MergedWidgets";
|
||||
import { IDashboardPanel } from "../types";
|
||||
import MergedWidgets from "../MergedWidgets";
|
||||
import EntityStateItemRenderer from "./EntityStateItemRenderer";
|
||||
import NetworkItem from "./NetworkItem";
|
||||
import DashboardItemBox from "../../DashboardItemBox";
|
||||
@@ -46,7 +46,6 @@ const MergedWidgetsRenderer = ({
|
||||
info={info}
|
||||
timeStart={timeStart}
|
||||
timeEnd={timeEnd}
|
||||
loading={loading}
|
||||
apiPrefix={apiPrefix}
|
||||
/>
|
||||
</DashboardItemBox>
|
||||
@@ -61,7 +60,6 @@ const MergedWidgetsRenderer = ({
|
||||
timeEnd={timeEnd}
|
||||
timeStart={timeStart}
|
||||
value={info}
|
||||
propLoading={loading}
|
||||
/>
|
||||
</DashboardItemBox>
|
||||
);
|
||||
|
||||
@@ -15,8 +15,35 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import { Box } from "@mui/material";
|
||||
import { Loader, NetworkGetIcon } from "mds";
|
||||
import styled from "styled-components";
|
||||
import get from "lodash/get";
|
||||
import { Loader, NetworkGetIcon, Box } from "mds";
|
||||
|
||||
const NetworkGetBase = styled.div(({ theme }) => ({
|
||||
"& .putLabel": {
|
||||
display: "flex",
|
||||
gap: 10,
|
||||
alignItems: "center",
|
||||
marginTop: "10px",
|
||||
|
||||
"& .min-icon": {
|
||||
height: 15,
|
||||
width: 15,
|
||||
fill: get(theme, "signalColors.good", "#4CCB92"),
|
||||
},
|
||||
|
||||
"& .getText": {
|
||||
fontSize: "18px",
|
||||
color: get(theme, "mutedText", "#87888d"),
|
||||
fontWeight: "bold",
|
||||
},
|
||||
"& .valueText": {
|
||||
fontSize: 50,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: 600,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
const NetworkGetItem = ({
|
||||
value,
|
||||
@@ -28,44 +55,17 @@ const NetworkGetItem = ({
|
||||
id?: number;
|
||||
}) => {
|
||||
return (
|
||||
<Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
marginTop: "10px",
|
||||
gap: "10px",
|
||||
"& .min-icon": {
|
||||
height: "15px",
|
||||
width: "15px",
|
||||
fill: "#4ccb92",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
fontSize: "18px",
|
||||
color: "#696969",
|
||||
}}
|
||||
>
|
||||
GET
|
||||
</Box>
|
||||
<NetworkGetBase>
|
||||
<Box className={"putLabel"}>
|
||||
<Box className={"getText"}>GET</Box>
|
||||
{loading ? (
|
||||
<Loader style={{ width: "15px", height: "15px" }} />
|
||||
) : (
|
||||
<NetworkGetIcon />
|
||||
)}
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
fontSize: "50px",
|
||||
fontFamily: "Inter",
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
{value}
|
||||
</Box>
|
||||
</Box>
|
||||
<Box className={"valueText"}>{value}</Box>
|
||||
</NetworkGetBase>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -15,24 +15,45 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import get from "lodash/get";
|
||||
import { Box, breakPoints, SpeedtestIcon } from "mds";
|
||||
import { IDashboardPanel } from "../types";
|
||||
import { Box } from "@mui/material";
|
||||
import { SpeedtestIcon } from "mds";
|
||||
import SingleValueWidget from "./SingleValueWidget";
|
||||
import NetworkGetItem from "./NetworkGetItem";
|
||||
import NetworkPutItem from "./NetworkPutItem";
|
||||
|
||||
const NetworkItemBase = styled.div(({ theme }) => ({
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flexFlow: "row",
|
||||
gap: "15px",
|
||||
"& .unitText": {
|
||||
fontSize: "14px",
|
||||
color: get(theme, "mutedText", "#87888d"),
|
||||
marginLeft: "5px",
|
||||
},
|
||||
"& .unit": {
|
||||
color: get(theme, "mutedText", "#87888d"),
|
||||
fontSize: "18px",
|
||||
marginLeft: "12px",
|
||||
marginTop: "10px",
|
||||
},
|
||||
[`@media (max-width: ${breakPoints.sm}px)`]: {
|
||||
flexFlow: "column",
|
||||
},
|
||||
}));
|
||||
|
||||
const NetworkItem = ({
|
||||
value,
|
||||
timeStart,
|
||||
timeEnd,
|
||||
propLoading,
|
||||
apiPrefix,
|
||||
}: {
|
||||
value: IDashboardPanel;
|
||||
timeStart: any;
|
||||
timeEnd: any;
|
||||
propLoading: boolean;
|
||||
apiPrefix: string;
|
||||
}) => {
|
||||
const { mergedPanels = [] } = value;
|
||||
@@ -44,7 +65,6 @@ const NetworkItem = ({
|
||||
panelItem={leftPanel}
|
||||
timeStart={timeStart}
|
||||
timeEnd={timeEnd}
|
||||
propLoading={propLoading}
|
||||
apiPrefix={apiPrefix}
|
||||
renderFn={({ valueToRender, loading, title, id }) => {
|
||||
return (
|
||||
@@ -64,7 +84,6 @@ const NetworkItem = ({
|
||||
panelItem={rightPanel}
|
||||
timeStart={timeStart}
|
||||
timeEnd={timeEnd}
|
||||
propLoading={propLoading}
|
||||
apiPrefix={apiPrefix}
|
||||
renderFn={({ valueToRender, loading, title, id }) => {
|
||||
return (
|
||||
@@ -80,23 +99,7 @@ const NetworkItem = ({
|
||||
);
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flexFlow: {
|
||||
sm: "row",
|
||||
xs: "column",
|
||||
},
|
||||
gap: "15px",
|
||||
"& .unitText": {
|
||||
fontSize: "14px",
|
||||
color: "#5E5E5E",
|
||||
marginLeft: "5px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<NetworkItemBase>
|
||||
<Box
|
||||
sx={{
|
||||
fontSize: "16px",
|
||||
@@ -110,9 +113,9 @@ const NetworkItem = ({
|
||||
position: "relative",
|
||||
width: 110,
|
||||
height: 110,
|
||||
marginLeft: {
|
||||
sm: "auto",
|
||||
xs: "",
|
||||
marginLeft: "auto",
|
||||
[`@media (max-width: ${breakPoints.sm}px)`]: {
|
||||
marginLeft: "0",
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -126,7 +129,6 @@ const NetworkItem = ({
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
fontWeight: "bold",
|
||||
color: "#000",
|
||||
fontSize: 12,
|
||||
}}
|
||||
>
|
||||
@@ -137,9 +139,9 @@ const NetworkItem = ({
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
marginLeft: {
|
||||
sm: "auto",
|
||||
xs: "",
|
||||
marginLeft: "auto",
|
||||
[`@media (max-width: ${breakPoints.sm}px)`]: {
|
||||
marginLeft: "0",
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -148,12 +150,6 @@ const NetworkItem = ({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
"& .value": { fontSize: "50px", fontFamily: "Inter" },
|
||||
"& .unit": {
|
||||
color: "#5E5E5E",
|
||||
fontSize: "18px",
|
||||
marginLeft: "12px",
|
||||
marginTop: "10px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{rightCmp}
|
||||
@@ -173,7 +169,7 @@ const NetworkItem = ({
|
||||
>
|
||||
<SpeedtestIcon />
|
||||
</Box>
|
||||
</Box>
|
||||
</NetworkItemBase>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -15,8 +15,35 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import { Box } from "@mui/material";
|
||||
import { Loader, NetworkPutIcon } from "mds";
|
||||
import styled from "styled-components";
|
||||
import get from "lodash/get";
|
||||
import { Box, Loader, NetworkPutIcon } from "mds";
|
||||
|
||||
const NetworkPutBase = styled.div(({ theme }) => ({
|
||||
"& .putLabel": {
|
||||
display: "flex",
|
||||
gap: 10,
|
||||
alignItems: "center",
|
||||
marginTop: "10px",
|
||||
|
||||
"& .min-icon": {
|
||||
height: 15,
|
||||
width: 15,
|
||||
fill: get(theme, "signalColors.info", "#2781B0"),
|
||||
},
|
||||
|
||||
"& .putText": {
|
||||
fontSize: "18px",
|
||||
color: get(theme, "mutedText", "#87888d"),
|
||||
fontWeight: "bold",
|
||||
},
|
||||
"& .valueText": {
|
||||
fontSize: 50,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: 600,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
const NetworkPutItem = ({
|
||||
value,
|
||||
@@ -28,46 +55,17 @@ const NetworkPutItem = ({
|
||||
id?: number;
|
||||
}) => {
|
||||
return (
|
||||
<Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
gap: "10px",
|
||||
alignItems: "center",
|
||||
marginTop: "10px",
|
||||
|
||||
"& .min-icon": {
|
||||
height: "15px",
|
||||
width: "15px",
|
||||
fill: "#2781b0",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
fontSize: "18px",
|
||||
color: "#696969",
|
||||
fontWeight: "normal",
|
||||
}}
|
||||
>
|
||||
PUT
|
||||
</Box>
|
||||
<NetworkPutBase>
|
||||
<Box className={"putLabel"}>
|
||||
<Box className={"putText"}>PUT</Box>
|
||||
{loading ? (
|
||||
<Loader style={{ width: "15px", height: "15px" }} />
|
||||
) : (
|
||||
<NetworkPutIcon />
|
||||
)}
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
fontSize: "50px",
|
||||
fontFamily: "Inter",
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
{value}
|
||||
</Box>
|
||||
</Box>
|
||||
<Box className={"valueText"}>{value}</Box>
|
||||
</NetworkPutBase>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -15,8 +15,21 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import { Box, Tooltip } from "@mui/material";
|
||||
import { Loader } from "mds";
|
||||
import styled from "styled-components";
|
||||
import get from "lodash/get";
|
||||
import { Box, breakPoints, Loader, Tooltip } from "mds";
|
||||
|
||||
const StatCardMain = styled.div(({ theme }) => ({
|
||||
fontFamily: "Inter,sans-serif",
|
||||
color: get(theme, "signalColors.main", "#07193E"),
|
||||
maxWidth: "300px",
|
||||
display: "flex",
|
||||
marginLeft: "auto",
|
||||
marginRight: "auto",
|
||||
cursor: "default",
|
||||
position: "relative",
|
||||
width: "100%",
|
||||
}));
|
||||
|
||||
const NumericStatCard = ({
|
||||
value,
|
||||
@@ -36,9 +49,9 @@ const NumericStatCard = ({
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
width: "100%",
|
||||
padding: {
|
||||
sm: "0 8px 0 8px",
|
||||
xs: "0 10px 0 10px",
|
||||
padding: "0 8px 0 8px",
|
||||
[`@media (max-width: ${breakPoints.sm}px)`]: {
|
||||
padding: "0 10px 0 10px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -61,26 +74,28 @@ const NumericStatCard = ({
|
||||
{label}
|
||||
</Box>
|
||||
|
||||
<Tooltip title={value} placement="bottom" enterDelay={500}>
|
||||
<Tooltip tooltip={value} placement="bottom">
|
||||
<Box
|
||||
sx={{
|
||||
fontSize: {
|
||||
xl: "55px",
|
||||
lg: "50px",
|
||||
md: "36px",
|
||||
sm: "35px",
|
||||
xs: "35px",
|
||||
},
|
||||
fontWeight: 600,
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
maxWidth: {
|
||||
md: 187,
|
||||
xs: 200,
|
||||
maxWidth: 187,
|
||||
flexFlow: "row",
|
||||
fontSize: 55,
|
||||
[`@media (max-width: ${breakPoints.sm}px)`]: {
|
||||
fontSize: 35,
|
||||
maxWidth: 200,
|
||||
flexFlow: "column",
|
||||
},
|
||||
flexFlow: {
|
||||
md: "row",
|
||||
xs: "column",
|
||||
[`@media (max-width: ${breakPoints.md}px)`]: {
|
||||
fontSize: 35,
|
||||
},
|
||||
[`@media (max-width: ${breakPoints.lg}px)`]: {
|
||||
fontSize: 36,
|
||||
},
|
||||
[`@media (max-width: ${breakPoints.xl}px)`]: {
|
||||
fontSize: 50,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -113,23 +128,7 @@ const NumericStatCard = ({
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
fontFamily: "Inter,sans-serif",
|
||||
color: "#07193E",
|
||||
maxWidth: "300px",
|
||||
display: "flex",
|
||||
marginLeft: "auto",
|
||||
marginRight: "auto",
|
||||
cursor: "default",
|
||||
position: "relative",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
{getContent()}
|
||||
</Box>
|
||||
);
|
||||
return <StatCardMain>{getContent()}</StatCardMain>;
|
||||
};
|
||||
|
||||
export default NumericStatCard;
|
||||
|
||||
@@ -15,68 +15,57 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import get from "lodash/get";
|
||||
import styled from "styled-components";
|
||||
import { Box, Loader } from "mds";
|
||||
import { Cell, Pie, PieChart, ResponsiveContainer } from "recharts";
|
||||
import { useSelector } from "react-redux";
|
||||
import api from "../../../../../common/api";
|
||||
import { IPieChartConfiguration } from "./types";
|
||||
import { widgetCommon } from "../../../Common/FormComponents/common/styleLibrary";
|
||||
|
||||
import { IDashboardPanel } from "../types";
|
||||
import { splitSizeMetric, widgetDetailsToPanel } from "../utils";
|
||||
import { ErrorResponseHandler } from "../../../../../common/types";
|
||||
import get from "lodash/get";
|
||||
import api from "../../../../../common/api";
|
||||
import { Loader } from "mds";
|
||||
import { setErrorSnackMessage } from "../../../../../systemSlice";
|
||||
import { AppState, useAppDispatch } from "../../../../../store";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
interface IPieChartWidget {
|
||||
classes: any;
|
||||
title: string;
|
||||
panelItem: IDashboardPanel;
|
||||
timeStart: any;
|
||||
timeEnd: any;
|
||||
propLoading: boolean;
|
||||
|
||||
apiPrefix: string;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...widgetCommon,
|
||||
loadingAlign: {
|
||||
width: "100%",
|
||||
paddingTop: "15px",
|
||||
textAlign: "center",
|
||||
margin: "auto",
|
||||
const PieChartMain = styled.div(({ theme }) => ({
|
||||
...widgetCommon(theme),
|
||||
"& .loadingAlign": {
|
||||
width: "100%",
|
||||
paddingTop: "15px",
|
||||
textAlign: "center",
|
||||
margin: "auto",
|
||||
},
|
||||
"& .pieChartLabel": {
|
||||
fontSize: 60,
|
||||
color: get(theme, "signalColors.main", "#07193E"),
|
||||
fontWeight: "bold",
|
||||
width: "100%",
|
||||
"& .unitText": {
|
||||
color: get(theme, "mutedText", "#87888d"),
|
||||
fontSize: 12,
|
||||
},
|
||||
pieChartLabel: {
|
||||
fontSize: 60,
|
||||
color: "#07193E",
|
||||
fontWeight: "bold",
|
||||
width: "100%",
|
||||
"& .unitText": {
|
||||
color: "#767676",
|
||||
fontSize: 12,
|
||||
},
|
||||
},
|
||||
chartContainer: {
|
||||
width: "100%",
|
||||
height: 140,
|
||||
},
|
||||
});
|
||||
},
|
||||
"& .chartContainer": {
|
||||
width: "100%",
|
||||
height: 140,
|
||||
},
|
||||
}));
|
||||
|
||||
const PieChartWidget = ({
|
||||
classes,
|
||||
title,
|
||||
panelItem,
|
||||
timeStart,
|
||||
timeEnd,
|
||||
propLoading,
|
||||
|
||||
apiPrefix,
|
||||
}: IPieChartWidget) => {
|
||||
const dispatch = useAppDispatch();
|
||||
@@ -137,110 +126,112 @@ const PieChartWidget = ({
|
||||
const outerColors = get(pieChartConfiguration, "outerChart.colorList", []);
|
||||
|
||||
return (
|
||||
<div className={classes.singleValueContainer}>
|
||||
<div className={classes.titleContainer}>{title}</div>
|
||||
{loading && (
|
||||
<div className={classes.loadingAlign}>
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
{!loading && (
|
||||
<div className={classes.contentContainer}>
|
||||
<span className={classes.pieChartLabel}>
|
||||
{middleLabel && splitSizeMetric(middleLabel)}
|
||||
</span>
|
||||
<div className={classes.chartContainer}>
|
||||
<ResponsiveContainer width="99%">
|
||||
<PieChart margin={{ top: 5, bottom: 5 }}>
|
||||
{dataOuter && (
|
||||
<Pie
|
||||
data={dataOuter as object[]}
|
||||
cx={"50%"}
|
||||
cy={"50%"}
|
||||
dataKey="value"
|
||||
innerRadius={get(
|
||||
pieChartConfiguration,
|
||||
"outerChart.innerRadius",
|
||||
0,
|
||||
)}
|
||||
outerRadius={get(
|
||||
pieChartConfiguration,
|
||||
"outerChart.outerRadius",
|
||||
"80%",
|
||||
)}
|
||||
startAngle={get(
|
||||
pieChartConfiguration,
|
||||
"outerChart.startAngle",
|
||||
0,
|
||||
)}
|
||||
endAngle={get(
|
||||
pieChartConfiguration,
|
||||
"outerChart.endAngle",
|
||||
360,
|
||||
)}
|
||||
fill="#201763"
|
||||
>
|
||||
{dataOuter.map((entry, index) => (
|
||||
<Cell
|
||||
key={`cellOuter-${index}`}
|
||||
fill={
|
||||
typeof outerColors[index] === "undefined"
|
||||
? "#393939"
|
||||
: outerColors[index]
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</Pie>
|
||||
)}
|
||||
{dataInner && (
|
||||
<Pie
|
||||
data={dataInner as object[]}
|
||||
dataKey="value"
|
||||
cx={"50%"}
|
||||
cy={"50%"}
|
||||
innerRadius={get(
|
||||
pieChartConfiguration,
|
||||
"innerChart.innerRadius",
|
||||
0,
|
||||
)}
|
||||
outerRadius={get(
|
||||
pieChartConfiguration,
|
||||
"innerChart.outerRadius",
|
||||
"80%",
|
||||
)}
|
||||
startAngle={get(
|
||||
pieChartConfiguration,
|
||||
"innerChart.startAngle",
|
||||
0,
|
||||
)}
|
||||
endAngle={get(
|
||||
pieChartConfiguration,
|
||||
"innerChart.endAngle",
|
||||
360,
|
||||
)}
|
||||
fill="#201763"
|
||||
>
|
||||
{dataInner.map((entry, index) => {
|
||||
return (
|
||||
<PieChartMain>
|
||||
<Box className={"singleValueContainer"}>
|
||||
<Box className={"titleContainer"}>{title}</Box>
|
||||
{loading && (
|
||||
<Box className={"loadingAlign"}>
|
||||
<Loader />
|
||||
</Box>
|
||||
)}
|
||||
{!loading && (
|
||||
<Box className={"contentContainer"}>
|
||||
<span className={"pieChartLabel"}>
|
||||
{middleLabel && splitSizeMetric(middleLabel)}
|
||||
</span>
|
||||
<Box className={"chartContainer"}>
|
||||
<ResponsiveContainer width="99%">
|
||||
<PieChart margin={{ top: 5, bottom: 5 }}>
|
||||
{dataOuter && (
|
||||
<Pie
|
||||
data={dataOuter as object[]}
|
||||
cx={"50%"}
|
||||
cy={"50%"}
|
||||
dataKey="value"
|
||||
innerRadius={get(
|
||||
pieChartConfiguration,
|
||||
"outerChart.innerRadius",
|
||||
0,
|
||||
)}
|
||||
outerRadius={get(
|
||||
pieChartConfiguration,
|
||||
"outerChart.outerRadius",
|
||||
"80%",
|
||||
)}
|
||||
startAngle={get(
|
||||
pieChartConfiguration,
|
||||
"outerChart.startAngle",
|
||||
0,
|
||||
)}
|
||||
endAngle={get(
|
||||
pieChartConfiguration,
|
||||
"outerChart.endAngle",
|
||||
360,
|
||||
)}
|
||||
fill="#201763"
|
||||
>
|
||||
{dataOuter.map((entry, index) => (
|
||||
<Cell
|
||||
key={`cell-${index}`}
|
||||
key={`cellOuter-${index}`}
|
||||
fill={
|
||||
typeof innerColors[index] === "undefined"
|
||||
typeof outerColors[index] === "undefined"
|
||||
? "#393939"
|
||||
: innerColors[index]
|
||||
: outerColors[index]
|
||||
}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Pie>
|
||||
)}
|
||||
</PieChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</Pie>
|
||||
)}
|
||||
{dataInner && (
|
||||
<Pie
|
||||
data={dataInner as object[]}
|
||||
dataKey="value"
|
||||
cx={"50%"}
|
||||
cy={"50%"}
|
||||
innerRadius={get(
|
||||
pieChartConfiguration,
|
||||
"innerChart.innerRadius",
|
||||
0,
|
||||
)}
|
||||
outerRadius={get(
|
||||
pieChartConfiguration,
|
||||
"innerChart.outerRadius",
|
||||
"80%",
|
||||
)}
|
||||
startAngle={get(
|
||||
pieChartConfiguration,
|
||||
"innerChart.startAngle",
|
||||
0,
|
||||
)}
|
||||
endAngle={get(
|
||||
pieChartConfiguration,
|
||||
"innerChart.endAngle",
|
||||
360,
|
||||
)}
|
||||
fill="#201763"
|
||||
>
|
||||
{dataInner.map((entry, index) => {
|
||||
return (
|
||||
<Cell
|
||||
key={`cell-${index}`}
|
||||
fill={
|
||||
typeof innerColors[index] === "undefined"
|
||||
? "#393939"
|
||||
: innerColors[index]
|
||||
}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Pie>
|
||||
)}
|
||||
</PieChart>
|
||||
</ResponsiveContainer>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</PieChartMain>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(PieChartWidget);
|
||||
export default PieChartWidget;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import { Box } from "@mui/material";
|
||||
import { Box, breakPoints } from "mds";
|
||||
import TimeStatItem from "../../TimeStatItem";
|
||||
import { SimpleWidgetRenderProps } from "./HealActivityRenderer";
|
||||
|
||||
@@ -44,9 +44,9 @@ const ScanActivityRenderer = ({
|
||||
<Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: {
|
||||
md: "inline",
|
||||
xs: "none",
|
||||
display: "inline",
|
||||
[`@media (max-width: ${breakPoints.sm}px)`]: {
|
||||
display: "none",
|
||||
},
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -15,63 +15,53 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment, useEffect, useState } from "react";
|
||||
import { connect, useSelector } from "react-redux";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import styled from "styled-components";
|
||||
import get from "lodash/get";
|
||||
import { useSelector } from "react-redux";
|
||||
import { Loader } from "mds";
|
||||
import api from "../../../../../common/api";
|
||||
import { widgetDetailsToPanel } from "../utils";
|
||||
import { IDashboardPanel } from "../types";
|
||||
|
||||
import { ErrorResponseHandler } from "../../../../../common/types";
|
||||
import { Loader } from "mds";
|
||||
import { setErrorSnackMessage } from "../../../../../systemSlice";
|
||||
import { AppState, useAppDispatch } from "../../../../../store";
|
||||
|
||||
interface ISimpleWidget {
|
||||
classes: any;
|
||||
iconWidget: any;
|
||||
title: string;
|
||||
panelItem: IDashboardPanel;
|
||||
timeStart: any;
|
||||
timeEnd: any;
|
||||
propLoading: boolean;
|
||||
|
||||
apiPrefix: string;
|
||||
renderFn?: undefined | null | ((arg: Record<string, any>) => any);
|
||||
}
|
||||
|
||||
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 SimpleWidgetMain = styled.span(({ theme }) => ({
|
||||
display: "inline-flex",
|
||||
color: get(theme, "signalColors.main", "#07193E"),
|
||||
alignItems: "center",
|
||||
"& .icon": {
|
||||
color: get(theme, "signalColors.main", "#07193E"),
|
||||
fill: get(theme, "signalColors.main", "#07193E"),
|
||||
marginRight: 5,
|
||||
marginLeft: 12,
|
||||
},
|
||||
"& .widgetLabel": {
|
||||
fontWeight: "bold",
|
||||
textTransform: "uppercase",
|
||||
marginRight: 10,
|
||||
},
|
||||
"& .widgetValue": {
|
||||
marginRight: 25,
|
||||
},
|
||||
}));
|
||||
|
||||
const SimpleWidget = ({
|
||||
classes,
|
||||
iconWidget,
|
||||
title,
|
||||
panelItem,
|
||||
timeStart,
|
||||
timeEnd,
|
||||
propLoading,
|
||||
apiPrefix,
|
||||
renderFn,
|
||||
}: ISimpleWidget) => {
|
||||
@@ -132,23 +122,19 @@ const SimpleWidget = ({
|
||||
return (
|
||||
<Fragment>
|
||||
{loading && (
|
||||
<div className={classes.loadingAlign}>
|
||||
<div className={"loadingAlign"}>
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
{!loading && (
|
||||
<span className={classes.mainWidgetContainer}>
|
||||
<span className={classes.icon}>{iconWidget ? iconWidget : null}</span>
|
||||
<span className={classes.widgetLabel}>{title}: </span>
|
||||
<span className={classes.widgetValue}>{data}</span>
|
||||
</span>
|
||||
<SimpleWidgetMain>
|
||||
<span className={"icon"}>{iconWidget ? iconWidget : null}</span>
|
||||
<span className={"widgetLabel"}>{title}: </span>
|
||||
<span className={"widgetValue"}>{data}</span>
|
||||
</SimpleWidgetMain>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const connector = connect(null, {
|
||||
setErrorSnackMessage: setErrorSnackMessage,
|
||||
});
|
||||
|
||||
export default withStyles(styles)(connector(SimpleWidget));
|
||||
export default SimpleWidget;
|
||||
|
||||
@@ -15,73 +15,65 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment, useEffect, useState } from "react";
|
||||
import { connect, useSelector } from "react-redux";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import api from "../../../../../common/api";
|
||||
import { Loader } from "mds";
|
||||
import { useSelector } from "react-redux";
|
||||
import { Box, Loader } from "mds";
|
||||
import styled from "styled-components";
|
||||
import get from "lodash/get";
|
||||
import { widgetCommon } from "../../../Common/FormComponents/common/styleLibrary";
|
||||
import { splitSizeMetric, widgetDetailsToPanel } from "../utils";
|
||||
import { IDashboardPanel } from "../types";
|
||||
import { ErrorResponseHandler } from "../../../../../common/types";
|
||||
import { setErrorSnackMessage } from "../../../../../systemSlice";
|
||||
import { AppState, useAppDispatch } from "../../../../../store";
|
||||
import api from "../../../../../common/api";
|
||||
|
||||
interface ISingleValueWidget {
|
||||
title: string;
|
||||
panelItem: IDashboardPanel;
|
||||
timeStart: any;
|
||||
timeEnd: any;
|
||||
propLoading: boolean;
|
||||
|
||||
classes: any;
|
||||
apiPrefix: string;
|
||||
renderFn?: (arg: Record<string, any>) => any;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...widgetCommon,
|
||||
loadingAlign: {
|
||||
width: "100%",
|
||||
textAlign: "center",
|
||||
margin: "auto",
|
||||
},
|
||||
metric: {
|
||||
fontSize: 60,
|
||||
lineHeight: 1,
|
||||
color: "#07193E",
|
||||
fontWeight: 700,
|
||||
},
|
||||
titleElement: {
|
||||
fontSize: 10,
|
||||
color: "#767676",
|
||||
fontWeight: 700,
|
||||
},
|
||||
containerAlignment: {
|
||||
display: "flex",
|
||||
height: 140,
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
"& .unitText": {
|
||||
color: "#767676",
|
||||
fontSize: 12,
|
||||
},
|
||||
},
|
||||
});
|
||||
const SingleValueWidgetMain = styled.div(({ theme }) => ({
|
||||
display: "flex",
|
||||
height: 140,
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
"& .unitText": {
|
||||
color: get(theme, "mutedText", "#87888d"),
|
||||
fontSize: 12,
|
||||
},
|
||||
"& .loadingAlign": {
|
||||
width: "100%",
|
||||
textAlign: "center",
|
||||
margin: "auto",
|
||||
},
|
||||
"& .metric": {
|
||||
fontSize: 60,
|
||||
lineHeight: 1,
|
||||
color: get(theme, "signalColors.main", "#07193E"),
|
||||
fontWeight: 700,
|
||||
},
|
||||
"& .titleElement": {
|
||||
fontSize: 10,
|
||||
color: get(theme, "mutedText", "#87888d"),
|
||||
fontWeight: 700,
|
||||
},
|
||||
...widgetCommon(theme),
|
||||
}));
|
||||
|
||||
const SingleValueWidget = ({
|
||||
title,
|
||||
panelItem,
|
||||
timeStart,
|
||||
timeEnd,
|
||||
propLoading,
|
||||
classes,
|
||||
apiPrefix,
|
||||
renderFn,
|
||||
}: ISingleValueWidget) => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [data, setData] = useState<string>("");
|
||||
const widgetVersion = useSelector(
|
||||
@@ -132,24 +124,20 @@ const SingleValueWidget = ({
|
||||
return renderFn({ valueToRender, loading, title, id: panelItem.id });
|
||||
}
|
||||
return (
|
||||
<div className={classes.containerAlignment}>
|
||||
<SingleValueWidgetMain>
|
||||
{loading && (
|
||||
<div className={classes.loadingAlign}>
|
||||
<Box className={"loadingAlign"}>
|
||||
<Loader />
|
||||
</div>
|
||||
</Box>
|
||||
)}
|
||||
{!loading && (
|
||||
<Fragment>
|
||||
<div className={classes.metric}>{splitSizeMetric(data)}</div>
|
||||
<div className={classes.titleElement}>{title}</div>
|
||||
<Box className={"metric"}>{splitSizeMetric(data)}</Box>
|
||||
<Box className={"titleElement"}>{title}</Box>
|
||||
</Fragment>
|
||||
)}
|
||||
</div>
|
||||
</SingleValueWidgetMain>
|
||||
);
|
||||
};
|
||||
|
||||
const connector = connect(null, {
|
||||
setErrorSnackMessage: setErrorSnackMessage,
|
||||
});
|
||||
|
||||
export default withStyles(styles)(connector(SingleValueWidget));
|
||||
export default SingleValueWidget;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import { Box } from "@mui/material";
|
||||
import { Box } from "mds";
|
||||
import TimeStatItem from "../../TimeStatItem";
|
||||
|
||||
export type SimpleWidgetRenderProps = {
|
||||
@@ -34,8 +34,8 @@ const UptimeActivityRenderer = ({
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
height: "47px",
|
||||
borderRadius: "2px",
|
||||
height: 47,
|
||||
borderRadius: 2,
|
||||
|
||||
"& .dashboard-time-stat-item": {
|
||||
height: "100%",
|
||||
|
||||
@@ -46,7 +46,6 @@ export const componentToUse = (
|
||||
panelItem={value}
|
||||
timeStart={timeStart}
|
||||
timeEnd={timeEnd}
|
||||
propLoading={loading}
|
||||
apiPrefix={apiPrefix}
|
||||
/>
|
||||
);
|
||||
@@ -86,7 +85,6 @@ export const componentToUse = (
|
||||
panelItem={value}
|
||||
timeStart={timeStart}
|
||||
timeEnd={timeEnd}
|
||||
propLoading={loading}
|
||||
apiPrefix={apiPrefix}
|
||||
iconWidget={value.widgetIcon}
|
||||
renderFn={renderFn}
|
||||
@@ -100,7 +98,6 @@ export const componentToUse = (
|
||||
value={value}
|
||||
timeStart={timeStart}
|
||||
timeEnd={timeEnd}
|
||||
propLoading={loading}
|
||||
apiPrefix={apiPrefix}
|
||||
/>
|
||||
</DashboardItemBox>
|
||||
@@ -112,7 +109,6 @@ export const componentToUse = (
|
||||
panelItem={value}
|
||||
timeStart={timeStart}
|
||||
timeEnd={timeEnd}
|
||||
propLoading={loading}
|
||||
apiPrefix={apiPrefix}
|
||||
/>
|
||||
);
|
||||
@@ -124,7 +120,6 @@ export const componentToUse = (
|
||||
panelItem={value}
|
||||
timeStart={timeStart}
|
||||
timeEnd={timeEnd}
|
||||
propLoading={loading}
|
||||
hideYAxis={value.disableYAxis}
|
||||
xAxisFormatter={value.xAxisFormatter}
|
||||
yAxisFormatter={value.yAxisFormatter}
|
||||
@@ -140,7 +135,6 @@ export const componentToUse = (
|
||||
panelItem={value}
|
||||
timeStart={timeStart}
|
||||
timeEnd={timeEnd}
|
||||
propLoading={loading}
|
||||
apiPrefix={apiPrefix}
|
||||
zoomActivated={zoomActivated}
|
||||
/>
|
||||
|
||||
@@ -15,8 +15,39 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import { Box } from "@mui/material";
|
||||
import { Loader, SuccessIcon } from "mds";
|
||||
import styled from "styled-components";
|
||||
import get from "lodash/get";
|
||||
import { Box, Loader, SuccessIcon } from "mds";
|
||||
|
||||
const TimeStatBase = styled.div(({ theme }) => ({
|
||||
display: "grid",
|
||||
alignItems: "center",
|
||||
gap: 8,
|
||||
height: 33,
|
||||
paddingLeft: 15,
|
||||
gridTemplateColumns: "20px 1.5fr .5fr 20px",
|
||||
background: get(theme, "boxBackground", "#FBFAFA"), // #EBF9EE
|
||||
"& .min-icon": {
|
||||
height: "12px",
|
||||
width: "12px",
|
||||
fill: get(theme, "signalColors.good", "#4CCB92"),
|
||||
},
|
||||
"& .ok-icon": {
|
||||
height: "8px",
|
||||
width: "8px",
|
||||
fill: get(theme, "signalColors.good", "#4CCB92"),
|
||||
color: get(theme, "signalColors.good", "#4CCB92"),
|
||||
},
|
||||
"& .timeStatLabel": {
|
||||
fontSize: "12px",
|
||||
color: get(theme, "signalColors.good", "#4CCB92"),
|
||||
fontWeight: 600,
|
||||
},
|
||||
"& .timeStatValue": {
|
||||
fontSize: "12px",
|
||||
color: get(theme, "signalColors.good", "#4CCB92"),
|
||||
},
|
||||
}));
|
||||
|
||||
const TimeStatItem = ({
|
||||
icon,
|
||||
@@ -30,46 +61,12 @@ const TimeStatItem = ({
|
||||
loading?: boolean;
|
||||
}) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "grid",
|
||||
alignItems: "center",
|
||||
gap: "8px",
|
||||
height: "33px",
|
||||
paddingLeft: "15px",
|
||||
gridTemplateColumns: {
|
||||
xs: "20px 1.5fr .5fr 20px",
|
||||
},
|
||||
background: "#EBF9EE",
|
||||
|
||||
"& .min-icon": {
|
||||
height: "12px",
|
||||
width: "12px",
|
||||
fill: "#4CCB92",
|
||||
},
|
||||
|
||||
"& .ok-icon": {
|
||||
height: "8px",
|
||||
width: "8px",
|
||||
fill: "#4CCB92",
|
||||
color: "#4CCB92",
|
||||
},
|
||||
}}
|
||||
className="dashboard-time-stat-item"
|
||||
>
|
||||
<TimeStatBase className="dashboard-time-stat-item">
|
||||
{loading ? <Loader style={{ width: 10, height: 10 }} /> : icon}
|
||||
<Box
|
||||
sx={{
|
||||
fontSize: "12px",
|
||||
color: "#4CCB92",
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</Box>
|
||||
<Box sx={{ fontSize: "12px", color: "#4CCB92" }}>{value}</Box>
|
||||
<Box className={"timeStatLabel"}>{label}</Box>
|
||||
<Box className={"timeStatValue"}>{value}</Box>
|
||||
{value !== "n/a" ? <SuccessIcon className="ok-icon" /> : null}
|
||||
</Box>
|
||||
</TimeStatBase>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -15,21 +15,11 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment, useState } from "react";
|
||||
import SearchBox from "../Common/SearchBox";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import { searchField } from "../Common/FormComponents/common/styleLibrary";
|
||||
import { DisabledIcon, EnabledIcon, Box, Grid } from "mds";
|
||||
import SearchBox from "../Common/SearchBox";
|
||||
import { STATUS_COLORS } from "../Dashboard/BasicDashboard/Utils";
|
||||
import makeStyles from "@mui/styles/makeStyles";
|
||||
import { IAMStatement } from "./types";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => ({
|
||||
searchField: {
|
||||
...searchField.searchField,
|
||||
maxWidth: 380,
|
||||
},
|
||||
}));
|
||||
|
||||
const rowGridStyle = {
|
||||
display: "grid",
|
||||
gridTemplateColumns: "70px 1fr",
|
||||
@@ -57,8 +47,6 @@ const PolicyView = ({
|
||||
}: {
|
||||
policyStatements: IAMStatement[];
|
||||
}) => {
|
||||
const classes = useStyles();
|
||||
|
||||
const [filter, setFilter] = useState<string>("");
|
||||
|
||||
return (
|
||||
@@ -77,8 +65,10 @@ const PolicyView = ({
|
||||
<SearchBox
|
||||
placeholder={"Search"}
|
||||
onChange={setFilter}
|
||||
overrideClass={classes.searchField}
|
||||
value={filter}
|
||||
sx={{
|
||||
maxWidth: 380,
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
Reference in New Issue
Block a user