Updated styles in Prometheus dashboard (#1078)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
@@ -22,7 +22,6 @@
|
||||
"@types/react-router": "^5.1.3",
|
||||
"@types/react-router-dom": "^5.1.2",
|
||||
"@types/react-virtualized": "^9.21.10",
|
||||
"@types/recharts": "^1.8.19",
|
||||
"@types/superagent": "^4.1.12",
|
||||
"@types/webpack-env": "^1.14.1",
|
||||
"@types/websocket": "^1.0.0",
|
||||
@@ -49,7 +48,7 @@
|
||||
"react-scripts": "4.0.3",
|
||||
"react-virtualized": "^9.22.2",
|
||||
"react-window-infinite-loader": "^1.0.5",
|
||||
"recharts": "^2.0.3",
|
||||
"recharts": "^2.1.1",
|
||||
"redux": "^4.0.5",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"superagent": "^6.1.0",
|
||||
|
||||
@@ -34,6 +34,7 @@ interface IDateTimePicker {
|
||||
tooltip?: string;
|
||||
id: string;
|
||||
disabled?: boolean;
|
||||
noInputIcon?: boolean;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
@@ -93,18 +94,27 @@ const DateTimePickerWrapper = ({
|
||||
required,
|
||||
id,
|
||||
disabled = false,
|
||||
noInputIcon = false,
|
||||
}: IDateTimePicker) => {
|
||||
let adornment = {};
|
||||
|
||||
if (!noInputIcon) {
|
||||
adornment = {
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<ScheduleIcon />
|
||||
</InputAdornment>
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
const inputItem = (
|
||||
<MuiPickersUtilsProvider utils={MomentUtils}>
|
||||
<DateTimePicker
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<ScheduleIcon />
|
||||
</InputAdornment>
|
||||
),
|
||||
...adornment,
|
||||
className: forSearchBlock ? classes.dateSelectorOverride : "",
|
||||
}}
|
||||
label=""
|
||||
|
||||
@@ -148,9 +148,17 @@ export const containerForHeader = (bottomSpacing: any) => ({
|
||||
});
|
||||
|
||||
export const actionsTray = {
|
||||
filterTitle: {
|
||||
color: "#848484",
|
||||
fontSize: 13,
|
||||
alignSelf: "center" as const,
|
||||
whiteSpace: "nowrap" as const,
|
||||
"&:not(:first-of-type)": {
|
||||
marginLeft: 10,
|
||||
},
|
||||
},
|
||||
label: {
|
||||
color: "#393939",
|
||||
fontWeight: 600,
|
||||
color: "#07193E",
|
||||
fontSize: 13,
|
||||
alignSelf: "center" as const,
|
||||
whiteSpace: "nowrap" as const,
|
||||
@@ -160,6 +168,7 @@ export const actionsTray = {
|
||||
},
|
||||
timeContainers: {
|
||||
height: 40,
|
||||
maxWidth: 1185,
|
||||
},
|
||||
actionsTray: {
|
||||
display: "flex" as const,
|
||||
@@ -399,29 +408,29 @@ export const logsCommon = {
|
||||
|
||||
export const widgetCommon = {
|
||||
singleValueContainer: {
|
||||
position: "relative" as const,
|
||||
flexGrow: 1,
|
||||
height: 200,
|
||||
minWidth: 280,
|
||||
maxWidth: 1185,
|
||||
border: "#eef1f4 2px solid",
|
||||
borderRadius: 10,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
border: "#EAEAEA 1px solid",
|
||||
borderRadius: 5,
|
||||
backgroundColor: "#fff",
|
||||
padding: 16,
|
||||
},
|
||||
titleContainer: {
|
||||
color: "#393939",
|
||||
fontWeight: 600,
|
||||
height: 15,
|
||||
textAlign: "center" as const,
|
||||
fontSize: 10,
|
||||
color: "#404143",
|
||||
fontSize: 14,
|
||||
textTransform: "uppercase" as const,
|
||||
fontWeight: 800,
|
||||
borderBottom: "#eef1f4 1px solid",
|
||||
paddingBottom: 14,
|
||||
marginBottom: 5,
|
||||
},
|
||||
contentContainer: {
|
||||
flexGrow: 2,
|
||||
justifyContent: "center" as const,
|
||||
alignItems: "center" as const,
|
||||
display: "flex" as const,
|
||||
position: "absolute" as const,
|
||||
width: "100%",
|
||||
height: "calc(100% - 15px)",
|
||||
height: 140,
|
||||
},
|
||||
contentContainerWithLabel: {
|
||||
height: "calc(100% - 25px)",
|
||||
@@ -445,7 +454,6 @@ export const widgetCommon = {
|
||||
width: 8,
|
||||
height: 8,
|
||||
minWidth: 8,
|
||||
borderRadius: "100%",
|
||||
marginRight: 5,
|
||||
},
|
||||
legendLabel: {
|
||||
|
||||
@@ -18,7 +18,6 @@ import React, { Fragment, useEffect, useState } from "react";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import { Button, LinearProgress } from "@material-ui/core";
|
||||
import CssBaseline from "@material-ui/core/CssBaseline";
|
||||
import Container from "@material-ui/core/Container";
|
||||
import Snackbar from "@material-ui/core/Snackbar";
|
||||
import history from "../../history";
|
||||
import { Redirect, Route, Router, Switch, useLocation } from "react-router-dom";
|
||||
|
||||
@@ -20,10 +20,8 @@ import Grid from "@material-ui/core/Grid";
|
||||
import { IDriveInfo, Usage } from "../types";
|
||||
import { calculateBytes } from "../../../../common/utils";
|
||||
import { TabPanel } from "../../../shared/tabs";
|
||||
import ReportedUsageIcon from "../../../../icons/ReportedUsageIcon";
|
||||
import ServerInfoCard from "./ServerInfoCard";
|
||||
import DriveInfoCard from "./DriveInfoCard";
|
||||
import { BucketsIcon, TotalObjectsIcon } from "../../../../icons";
|
||||
import CommonCard from "../CommonCard";
|
||||
import TabSelector from "../../Common/TabSelector/TabSelector";
|
||||
import GeneralUsePaginator from "../../Common/GeneralUsePaginator/GeneralUsePaginator";
|
||||
@@ -133,23 +131,19 @@ const BasicDashboard = ({ classes, usage }: IDashboardProps) => {
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.generalStatusCards}>
|
||||
<CommonCard
|
||||
avatar={<BucketsIcon />}
|
||||
title={"All Buckets"}
|
||||
metricValue={usage ? prettyNumber(usage.buckets) : 0}
|
||||
/>
|
||||
<CommonCard
|
||||
avatar={<ReportedUsageIcon />}
|
||||
title={"Usage"}
|
||||
metricValue={usageToRepresent.total}
|
||||
metricUnit={usageToRepresent.unit}
|
||||
/>
|
||||
<CommonCard
|
||||
avatar={<TotalObjectsIcon />}
|
||||
title={"Total Objects"}
|
||||
metricValue={usage ? prettyNumber(usage.objects) : 0}
|
||||
/>
|
||||
<CommonCard
|
||||
avatar={<TotalObjectsIcon />}
|
||||
title={"Servers"}
|
||||
metricValue={usage ? prettyNumber(serverArray.length) : 0}
|
||||
subMessage={{ message: "Total" }}
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
makeStyles,
|
||||
} from "@material-ui/core/styles";
|
||||
import React, { Fragment } from "react";
|
||||
import { widgetCommon } from "../Common/FormComponents/common/styleLibrary";
|
||||
|
||||
export interface ISubInterface {
|
||||
message: string;
|
||||
@@ -30,7 +31,6 @@ export interface ISubInterface {
|
||||
}
|
||||
|
||||
interface ICommonCard {
|
||||
avatar: any;
|
||||
title: string;
|
||||
metricValue: any;
|
||||
metricUnit?: string;
|
||||
@@ -42,12 +42,10 @@ interface ICommonCard {
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...widgetCommon,
|
||||
cardRoot: {
|
||||
border: "#eef1f4 2px solid",
|
||||
borderRadius: 10,
|
||||
...widgetCommon.singleValueContainer,
|
||||
maxWidth: 280,
|
||||
width: "100%",
|
||||
margin: 10,
|
||||
},
|
||||
cardsContainer: {
|
||||
maxHeight: 440,
|
||||
@@ -94,15 +92,9 @@ const styles = (theme: Theme) =>
|
||||
});
|
||||
|
||||
const cardSubStyles = makeStyles({
|
||||
root: { backgroundColor: "#fff" },
|
||||
root: { backgroundColor: "#fff", padding: 0 },
|
||||
title: {
|
||||
color: "#404144",
|
||||
fontSize: 14,
|
||||
textTransform: "uppercase",
|
||||
fontWeight: "bold",
|
||||
borderBottom: "#eef1f4 1px solid",
|
||||
paddingBottom: 14,
|
||||
marginBottom: 5,
|
||||
...widgetCommon.titleContainer
|
||||
},
|
||||
content: {
|
||||
maxWidth: "100%",
|
||||
@@ -110,7 +102,6 @@ const cardSubStyles = makeStyles({
|
||||
});
|
||||
|
||||
const CommonCard = ({
|
||||
avatar,
|
||||
title,
|
||||
metricValue,
|
||||
metricUnit,
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// 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 CommonCard from "../CommonCard";
|
||||
|
||||
interface IMergedWidgets {
|
||||
title: string;
|
||||
leftComponent: any;
|
||||
rightComponent: any;
|
||||
}
|
||||
|
||||
const MergedWidgets = ({
|
||||
title,
|
||||
leftComponent,
|
||||
rightComponent,
|
||||
}: IMergedWidgets) => {
|
||||
return (
|
||||
<Fragment>
|
||||
<CommonCard
|
||||
title={title}
|
||||
metricValue={leftComponent}
|
||||
rightComponent={rightComponent}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default MergedWidgets;
|
||||
@@ -14,21 +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 React, { useCallback, useEffect, useState } from "react";
|
||||
import React, { Fragment, useCallback, useEffect, useState } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import ReactGridLayout from "react-grid-layout";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import ScheduleIcon from "@material-ui/icons/Schedule";
|
||||
import WatchLaterIcon from "@material-ui/icons/WatchLater";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import { Button } from "@material-ui/core";
|
||||
import { actionsTray } from "../../Common/FormComponents/common/styleLibrary";
|
||||
import { AutoSizer } from "react-virtualized";
|
||||
import { IDashboardPanel, widgetType } from "./types";
|
||||
import {
|
||||
getDashboardDistribution,
|
||||
getWidgetsWithValue,
|
||||
panelsConfiguration,
|
||||
saveDashboardDistribution,
|
||||
} from "./utils";
|
||||
import { getWidgetsWithValue, panelsConfiguration } from "./utils";
|
||||
import { TabPanel } from "../../../shared/tabs";
|
||||
import { ErrorResponseHandler } from "../../../../common/types";
|
||||
import { setErrorSnackMessage } from "../../../../actions";
|
||||
@@ -40,8 +35,9 @@ import SingleRepWidget from "./Widgets/SingleRepWidget";
|
||||
import DateTimePickerWrapper from "../../Common/FormComponents/DateTimePickerWrapper/DateTimePickerWrapper";
|
||||
import api from "../../../../common/api";
|
||||
import SyncIcon from "../../../../icons/SyncIcon";
|
||||
import Tabs from "@material-ui/core/Tabs";
|
||||
import Tab from "@material-ui/core/Tab";
|
||||
import TabSelector from "../../Common/TabSelector/TabSelector";
|
||||
import SimpleWidget from "./Widgets/SimpleWidget";
|
||||
import MergedWidgets from "./MergedWidgets";
|
||||
|
||||
interface IPrDashboard {
|
||||
classes: any;
|
||||
@@ -53,8 +49,11 @@ const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...actionsTray,
|
||||
widgetsContainer: {
|
||||
height: "calc(100vh - 250px)",
|
||||
paddingBottom: 235,
|
||||
position: "relative",
|
||||
display: "flex",
|
||||
flexGrow: 1,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
},
|
||||
syncButton: {
|
||||
"&.MuiButton-root .MuiButton-iconSizeMedium > *:first-child": {
|
||||
@@ -65,6 +64,24 @@ const styles = (theme: Theme) =>
|
||||
...actionsTray.actionsTray,
|
||||
padding: "0 10px",
|
||||
},
|
||||
dashboardRow: {
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "flex-start",
|
||||
flexWrap: "wrap",
|
||||
maxWidth: 1180,
|
||||
},
|
||||
widgetPanelDelimiter: {
|
||||
margin: 10,
|
||||
},
|
||||
schedulerIcon: {
|
||||
opacity: 0.4,
|
||||
fontSize: 10,
|
||||
"& svg": {
|
||||
width: 18,
|
||||
height: 18,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const PrDashboard = ({
|
||||
@@ -79,23 +96,8 @@ const PrDashboard = ({
|
||||
useState<IDashboardPanel[]>(panelsConfiguration);
|
||||
const [curTab, setCurTab] = useState<number>(0);
|
||||
|
||||
const minHeight = 600;
|
||||
const colsInGrid = 8;
|
||||
const xSpacing = 10;
|
||||
const ySpacing = 10;
|
||||
|
||||
const dashboardDistr = getDashboardDistribution(panelInformation.length);
|
||||
|
||||
const autoSizerStyleProp = {
|
||||
width: "100%",
|
||||
height: "auto",
|
||||
paddingBottom: 45,
|
||||
};
|
||||
|
||||
const panels = useCallback(
|
||||
(width: number, filterPanels?: number[] | null) => {
|
||||
const singlePanelWidth = width / colsInGrid + xSpacing / 2;
|
||||
|
||||
(tabName: string, filterPanels?: number[][] | null) => {
|
||||
const componentToUse = (value: IDashboardPanel, index: number) => {
|
||||
switch (value.type) {
|
||||
case widgetType.singleValue:
|
||||
@@ -109,6 +111,18 @@ const PrDashboard = ({
|
||||
apiPrefix={apiPrefix}
|
||||
/>
|
||||
);
|
||||
case widgetType.simpleWidget:
|
||||
return (
|
||||
<SimpleWidget
|
||||
title={value.title}
|
||||
panelItem={value}
|
||||
timeStart={timeStart}
|
||||
timeEnd={timeEnd}
|
||||
propLoading={loading}
|
||||
apiPrefix={apiPrefix}
|
||||
iconWidget={value.widgetIcon}
|
||||
/>
|
||||
);
|
||||
case widgetType.pieChart:
|
||||
return (
|
||||
<PieChartWidget
|
||||
@@ -121,6 +135,7 @@ const PrDashboard = ({
|
||||
/>
|
||||
);
|
||||
case widgetType.linearGraph:
|
||||
case widgetType.areaGraph:
|
||||
return (
|
||||
<LinearGraphWidget
|
||||
title={value.title}
|
||||
@@ -131,12 +146,8 @@ const PrDashboard = ({
|
||||
hideYAxis={value.disableYAxis}
|
||||
xAxisFormatter={value.xAxisFormatter}
|
||||
yAxisFormatter={value.yAxisFormatter}
|
||||
panelWidth={
|
||||
dashboardDistr[index]
|
||||
? singlePanelWidth * dashboardDistr[index].w
|
||||
: singlePanelWidth
|
||||
}
|
||||
apiPrefix={apiPrefix}
|
||||
areaWidget={value.type === widgetType.areaGraph}
|
||||
/>
|
||||
);
|
||||
case widgetType.barChart:
|
||||
@@ -169,21 +180,66 @@ const PrDashboard = ({
|
||||
}
|
||||
};
|
||||
|
||||
return panelInformation
|
||||
.filter((val) => {
|
||||
if (filterPanels) {
|
||||
return filterPanels.indexOf(val.id) > -1;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
})
|
||||
.map((val, index) => {
|
||||
return (
|
||||
<div key={val.layoutIdentifier}>{componentToUse(val, index)}</div>
|
||||
);
|
||||
});
|
||||
return filterPanels?.map((panelLine, indexLine) => {
|
||||
const totalPanelsContained = panelLine.length;
|
||||
|
||||
const perc = 100 / totalPanelsContained;
|
||||
|
||||
return (
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
key={`line-${tabName}-${indexLine}`}
|
||||
className={classes.dashboardRow}
|
||||
>
|
||||
{panelLine.map((panelInline, indexPanel) => {
|
||||
const panelInfo = panelInformation.find(
|
||||
(panel) => panel.id === panelInline
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={`widget-${panelInline}-${indexPanel}`}
|
||||
className={classes.widgetPanelDelimiter}
|
||||
style={{ width: `calc(${perc}% - 20px)` }}
|
||||
>
|
||||
{panelInfo ? (
|
||||
<Fragment>
|
||||
{panelInfo.mergedPanels ? (
|
||||
<Fragment>
|
||||
<MergedWidgets
|
||||
title={panelInfo.title}
|
||||
leftComponent={componentToUse(
|
||||
panelInfo.mergedPanels[0],
|
||||
0
|
||||
)}
|
||||
rightComponent={componentToUse(
|
||||
panelInfo.mergedPanels[1],
|
||||
1
|
||||
)}
|
||||
/>
|
||||
</Fragment>
|
||||
) : (
|
||||
componentToUse(panelInfo, indexPanel)
|
||||
)}
|
||||
</Fragment>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
);
|
||||
});
|
||||
},
|
||||
[panelInformation, dashboardDistr, timeEnd, timeStart, loading, apiPrefix]
|
||||
[
|
||||
timeStart,
|
||||
timeEnd,
|
||||
loading,
|
||||
apiPrefix,
|
||||
classes.dashboardRow,
|
||||
classes.widgetPanelDelimiter,
|
||||
panelInformation,
|
||||
]
|
||||
);
|
||||
|
||||
const fetchUsage = useCallback(() => {
|
||||
@@ -235,145 +291,91 @@ const PrDashboard = ({
|
||||
}
|
||||
}, [loading, fetchUsage]);
|
||||
|
||||
const a11yProps = (index: any) => {
|
||||
return {
|
||||
id: `simple-tab-${index}`,
|
||||
"aria-controls": `simple-tabpanel-${index}`,
|
||||
};
|
||||
};
|
||||
|
||||
const summaryPanels = [
|
||||
1, 64, 65, 68, 52, 44, 61, 80, 81, 66, 62, 53, 63, 50, 69, 70, 9, 78,
|
||||
[80, 81, 1],
|
||||
[68, 52],
|
||||
[63, 70],
|
||||
[66, 50, 44, 500],
|
||||
[501, 502, 61, 62],
|
||||
];
|
||||
const resourcesPanels = [76, 77, 11, 8, 82, 74];
|
||||
const requestsPanels = [60, 71, 17, 73];
|
||||
const resourcesPanels = [
|
||||
[76, 77],
|
||||
[11, 8],
|
||||
[82, 74],
|
||||
];
|
||||
const requestsPanels = [[60], [71, 17], [73]];
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Fragment>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
className={`${classes.actionsTray} ${classes.timeContainers}`}
|
||||
>
|
||||
<span className={classes.label}>Start Time</span>
|
||||
<span className={classes.filterTitle}>Filter:</span>
|
||||
<span className={`${classes.filterTitle} ${classes.schedulerIcon}`}>
|
||||
<ScheduleIcon />
|
||||
</span>
|
||||
<span className={classes.label}>Start Time:</span>
|
||||
<DateTimePickerWrapper
|
||||
value={timeStart}
|
||||
onChange={setTimeStart}
|
||||
forSearchBlock
|
||||
id="stTime"
|
||||
noInputIcon
|
||||
/>
|
||||
<span className={classes.label}>End Time</span>
|
||||
<span className={`${classes.filterTitle} ${classes.schedulerIcon}`}>
|
||||
<WatchLaterIcon />
|
||||
</span>
|
||||
<span className={classes.label}>End Time:</span>
|
||||
<DateTimePickerWrapper
|
||||
value={timeEnd}
|
||||
onChange={setTimeEnd}
|
||||
forSearchBlock
|
||||
id="endTime"
|
||||
noInputIcon
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={triggerLoad}
|
||||
startIcon={<SyncIcon />}
|
||||
endIcon={<SyncIcon />}
|
||||
className={classes.syncButton}
|
||||
>
|
||||
Sync
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Tabs
|
||||
indicatorColor="primary"
|
||||
textColor="primary"
|
||||
aria-label="cluster-tabs"
|
||||
variant="scrollable"
|
||||
scrollButtons="auto"
|
||||
value={curTab}
|
||||
onChange={(e: React.ChangeEvent<{}>, newValue: number) => {
|
||||
<TabSelector
|
||||
selectedTab={curTab}
|
||||
onChange={(newValue: number) => {
|
||||
setCurTab(newValue);
|
||||
}}
|
||||
>
|
||||
<Tab label="Summary" {...a11yProps(0)} />
|
||||
<Tab label="Traffic" {...a11yProps(1)} />
|
||||
<Tab label="Resources" {...a11yProps(2)} />
|
||||
</Tabs>
|
||||
tabOptions={[
|
||||
{ label: "Summary" },
|
||||
{ label: "Traffic" },
|
||||
{ label: "Resources" },
|
||||
]}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.widgetsContainer}>
|
||||
<TabPanel index={0} value={curTab}>
|
||||
<AutoSizer style={autoSizerStyleProp}>
|
||||
{({ width, height }: any) => {
|
||||
let hpanel = height < minHeight ? minHeight : height;
|
||||
if (hpanel > 380) {
|
||||
hpanel = 480;
|
||||
}
|
||||
const totalWidth = width > 1920 ? 1920 : width;
|
||||
return (
|
||||
<ReactGridLayout
|
||||
width={totalWidth}
|
||||
cols={colsInGrid}
|
||||
containerPadding={[xSpacing, ySpacing]}
|
||||
onLayoutChange={saveDashboardDistribution}
|
||||
layout={dashboardDistr}
|
||||
rowHeight={hpanel / 6}
|
||||
style={{ margin: "0 auto", width: totalWidth }}
|
||||
>
|
||||
{panels(width, summaryPanels)}
|
||||
</ReactGridLayout>
|
||||
);
|
||||
}}
|
||||
</AutoSizer>
|
||||
{panels("Summary", summaryPanels)}
|
||||
</TabPanel>
|
||||
<TabPanel index={1} value={curTab}>
|
||||
<AutoSizer style={autoSizerStyleProp}>
|
||||
{({ width, height }: any) => {
|
||||
let hpanel = height < minHeight ? minHeight : height;
|
||||
if (hpanel > 380) {
|
||||
hpanel = 480;
|
||||
}
|
||||
const totalWidth = width > 1920 ? 1920 : width;
|
||||
return (
|
||||
<ReactGridLayout
|
||||
width={totalWidth}
|
||||
cols={colsInGrid}
|
||||
containerPadding={[xSpacing, ySpacing]}
|
||||
onLayoutChange={saveDashboardDistribution}
|
||||
layout={dashboardDistr}
|
||||
rowHeight={hpanel / 6}
|
||||
style={{ margin: "0 auto", width: totalWidth }}
|
||||
>
|
||||
{panels(width, requestsPanels)}
|
||||
</ReactGridLayout>
|
||||
);
|
||||
}}
|
||||
</AutoSizer>
|
||||
{panels("Traffic", requestsPanels)}
|
||||
</TabPanel>
|
||||
<TabPanel index={2} value={curTab}>
|
||||
<AutoSizer style={autoSizerStyleProp}>
|
||||
{({ width, height }: any) => {
|
||||
let hpanel = height < minHeight ? minHeight : height;
|
||||
if (hpanel > 380) {
|
||||
hpanel = 480;
|
||||
}
|
||||
const totalWidth = width > 1920 ? 1920 : width;
|
||||
return (
|
||||
<ReactGridLayout
|
||||
width={totalWidth}
|
||||
cols={colsInGrid}
|
||||
containerPadding={[xSpacing, ySpacing]}
|
||||
onLayoutChange={saveDashboardDistribution}
|
||||
layout={dashboardDistr}
|
||||
rowHeight={hpanel / 6}
|
||||
style={{ margin: "0 auto", width: totalWidth }}
|
||||
>
|
||||
{panels(width, resourcesPanels)}
|
||||
</ReactGridLayout>
|
||||
);
|
||||
}}
|
||||
</AutoSizer>
|
||||
{panels("Resources", resourcesPanels)}
|
||||
</TabPanel>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
/*
|
||||
<
|
||||
*/
|
||||
|
||||
const connector = connect(null, {
|
||||
displayErrorMessage: setErrorSnackMessage,
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// 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, { useEffect, useState } from "react";
|
||||
import React, { useEffect, useState, Fragment } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import {
|
||||
Bar,
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
Tooltip,
|
||||
XAxis,
|
||||
YAxis,
|
||||
Cell,
|
||||
} from "recharts";
|
||||
import { MaterialUiPickersDate } from "@material-ui/pickers/typings/date";
|
||||
import { CircularProgress } from "@material-ui/core";
|
||||
@@ -58,14 +59,15 @@ const styles = (theme: Theme) =>
|
||||
},
|
||||
});
|
||||
|
||||
const CustomizedAxisTick = ({ x, y, payload }: any) => {
|
||||
const CustomizedAxisTick = ({ y, payload }: any) => {
|
||||
return (
|
||||
<text
|
||||
width={50}
|
||||
fontSize={"63%"}
|
||||
textAnchor="end"
|
||||
textAnchor="start"
|
||||
fill="#333"
|
||||
transform={`translate(${x},${y})`}
|
||||
transform={`translate(5,${y})`}
|
||||
fontWeight={700}
|
||||
dy={3}
|
||||
>
|
||||
{payload.value}
|
||||
@@ -131,6 +133,19 @@ const BarChartWidget = ({
|
||||
? (result.widgetConfiguration as IBarChartConfiguration[])
|
||||
: [];
|
||||
|
||||
let greatestIndex = 0;
|
||||
let currentValue = 0;
|
||||
|
||||
if (barChartConfiguration.length === 1) {
|
||||
const dataGraph = barChartConfiguration[0];
|
||||
data.forEach((item: any, index: number) => {
|
||||
if (item[dataGraph.dataKey] > currentValue) {
|
||||
currentValue = item[dataGraph.dataKey];
|
||||
greatestIndex = index;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classes.singleValueContainer}>
|
||||
<div className={classes.titleContainer}>{title}</div>
|
||||
@@ -163,7 +178,23 @@ const BarChartWidget = ({
|
||||
dataKey={bar.dataKey}
|
||||
fill={bar.color}
|
||||
background={bar.background}
|
||||
/>
|
||||
barSize={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)" }}
|
||||
|
||||
@@ -49,7 +49,7 @@ interface ILinearGraphWidget {
|
||||
hideYAxis?: boolean;
|
||||
yAxisFormatter?: (item: string) => string;
|
||||
xAxisFormatter?: (item: string) => string;
|
||||
panelWidth?: number;
|
||||
areaWidget?: boolean;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
@@ -57,24 +57,29 @@ const styles = (theme: Theme) =>
|
||||
...widgetCommon,
|
||||
containerElements: {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
height: "calc(100% - 18px)",
|
||||
flexDirection: "row",
|
||||
height: "100%",
|
||||
flexGrow: 1,
|
||||
},
|
||||
chartCont: {
|
||||
position: "relative",
|
||||
flexGrow: 1,
|
||||
minHeight: "65%",
|
||||
height: 1,
|
||||
height: 140,
|
||||
width: "100%",
|
||||
},
|
||||
legendChart: {
|
||||
display: "flex",
|
||||
flexWrap: "wrap",
|
||||
flexDirection: "column",
|
||||
flex: "0 1 auto",
|
||||
maxHeight: "35%",
|
||||
height: 130,
|
||||
margin: 0,
|
||||
overflowY: "auto",
|
||||
position: "relative",
|
||||
textAlign: "center",
|
||||
width: "100%",
|
||||
justifyContent: "flex-start",
|
||||
color: "#404143",
|
||||
fontWeight: "bold",
|
||||
fontSize: 12,
|
||||
},
|
||||
loadingAlign: {
|
||||
margin: "auto",
|
||||
@@ -91,9 +96,9 @@ const LinearGraphWidget = ({
|
||||
panelItem,
|
||||
apiPrefix,
|
||||
hideYAxis = false,
|
||||
areaWidget = false,
|
||||
yAxisFormatter = (item: string) => item,
|
||||
xAxisFormatter = (item: string) => item,
|
||||
panelWidth = 0,
|
||||
}: ILinearGraphWidget) => {
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const [data, setData] = useState<object[]>([]);
|
||||
@@ -153,26 +158,21 @@ const LinearGraphWidget = ({
|
||||
}
|
||||
}, [loading, panelItem, timeEnd, timeStart, displayErrorMessage, apiPrefix]);
|
||||
|
||||
let intervalCount = 5;
|
||||
|
||||
if (panelWidth !== 0) {
|
||||
if (panelWidth > 400) {
|
||||
intervalCount = 5;
|
||||
} else if (panelWidth > 350) {
|
||||
intervalCount = 10;
|
||||
} else if (panelWidth > 300) {
|
||||
intervalCount = 15;
|
||||
} else if (panelWidth > 250) {
|
||||
intervalCount = 20;
|
||||
} else {
|
||||
intervalCount = 30;
|
||||
}
|
||||
}
|
||||
let intervalCount = Math.floor(data.length / 5);
|
||||
|
||||
const linearConfiguration = result
|
||||
? (result?.widgetConfiguration as ILinearGraphConfiguration[])
|
||||
: [];
|
||||
|
||||
const CustomizedDot = (prop: any) => {
|
||||
const { cx, cy, index } = prop;
|
||||
|
||||
if (index % 3 !== 0) {
|
||||
return null;
|
||||
}
|
||||
return <circle cx={cx} cy={cy} r={3} strokeWidth={0} fill="#07264A" />;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={classes.singleValueContainer}>
|
||||
<div className={classes.titleContainer}>{title}</div>
|
||||
@@ -191,24 +191,52 @@ const LinearGraphWidget = ({
|
||||
bottom: 0,
|
||||
}}
|
||||
>
|
||||
{areaWidget && (
|
||||
<defs>
|
||||
<linearGradient id="colorUv" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop
|
||||
offset="0%"
|
||||
stopColor="#ABC8F2"
|
||||
stopOpacity={0.9}
|
||||
/>
|
||||
<stop
|
||||
offset="95%"
|
||||
stopColor="#ABC8F2"
|
||||
stopOpacity={0}
|
||||
/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
)}
|
||||
<CartesianGrid
|
||||
strokeDasharray="3 3"
|
||||
strokeDasharray={areaWidget ? "0 0" : "3 3"}
|
||||
strokeWidth={1}
|
||||
strokeOpacity={0.5}
|
||||
stroke={"#07264A30"}
|
||||
vertical={!areaWidget}
|
||||
/>
|
||||
<XAxis
|
||||
dataKey="name"
|
||||
tickFormatter={(value: any) => xAxisFormatter(value)}
|
||||
interval={intervalCount}
|
||||
tick={{ fontSize: "70%" }}
|
||||
tick={{
|
||||
fontSize: "70%",
|
||||
fontWeight: "bold",
|
||||
color: "#404143",
|
||||
}}
|
||||
tickCount={10}
|
||||
stroke={"#082045"}
|
||||
/>
|
||||
<YAxis
|
||||
type={"number"}
|
||||
domain={[0, dataMax * 1.1]}
|
||||
hide={hideYAxis}
|
||||
tickFormatter={(value: any) => yAxisFormatter(value)}
|
||||
tick={{ fontSize: "70%" }}
|
||||
tick={{
|
||||
fontSize: "70%",
|
||||
fontWeight: "bold",
|
||||
color: "#404143",
|
||||
}}
|
||||
stroke={"#082045"}
|
||||
/>
|
||||
{linearConfiguration.map((section, index) => {
|
||||
return (
|
||||
@@ -217,8 +245,10 @@ const LinearGraphWidget = ({
|
||||
type="monotone"
|
||||
dataKey={section.dataKey}
|
||||
stroke={section.lineColor}
|
||||
fill={section.fillColor}
|
||||
fillOpacity={0.3}
|
||||
fill={areaWidget ? "url(#colorUv)" : section.fillColor}
|
||||
fillOpacity={areaWidget ? 0.3 : 0}
|
||||
strokeWidth={areaWidget ? 0 : 2}
|
||||
dot={areaWidget ? <CustomizedDot /> : false}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
@@ -236,24 +266,26 @@ const LinearGraphWidget = ({
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
<div className={classes.legendChart}>
|
||||
{linearConfiguration.map((section, index) => {
|
||||
return (
|
||||
<div
|
||||
className={classes.singleLegendContainer}
|
||||
key={`legend-${section.keyLabel}-${index.toString()}`}
|
||||
>
|
||||
{!areaWidget && (
|
||||
<div className={classes.legendChart}>
|
||||
{linearConfiguration.map((section, index) => {
|
||||
return (
|
||||
<div
|
||||
className={classes.colorContainer}
|
||||
style={{ backgroundColor: section.lineColor }}
|
||||
/>
|
||||
<div className={classes.legendLabel}>
|
||||
{section.keyLabel}
|
||||
className={classes.singleLegendContainer}
|
||||
key={`legend-${section.keyLabel}-${index.toString()}`}
|
||||
>
|
||||
<div
|
||||
className={classes.colorContainer}
|
||||
style={{ backgroundColor: section.lineColor }}
|
||||
/>
|
||||
<div className={classes.legendLabel}>
|
||||
{section.keyLabel}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</React.Fragment>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -24,7 +24,7 @@ import { IPieChartConfiguration } from "./types";
|
||||
import { widgetCommon } from "../../../Common/FormComponents/common/styleLibrary";
|
||||
import { setErrorSnackMessage } from "../../../../../actions";
|
||||
import { IDashboardPanel } from "../types";
|
||||
import { widgetDetailsToPanel } from "../utils";
|
||||
import { splitSizeMetric, widgetDetailsToPanel } from "../utils";
|
||||
import { ErrorResponseHandler } from "../../../../../common/types";
|
||||
import get from "lodash/get";
|
||||
import api from "../../../../../common/api";
|
||||
@@ -49,6 +49,20 @@ const styles = (theme: Theme) =>
|
||||
textAlign: "center",
|
||||
margin: "auto",
|
||||
},
|
||||
pieChartLabel: {
|
||||
fontSize: 60,
|
||||
color: "#07193E",
|
||||
fontWeight: "bold",
|
||||
width: "100%",
|
||||
"& .unitText": {
|
||||
color: "#767676",
|
||||
fontSize: 12,
|
||||
},
|
||||
},
|
||||
chartContainer: {
|
||||
width: "100%",
|
||||
height: 140,
|
||||
},
|
||||
});
|
||||
|
||||
const PieChartWidget = ({
|
||||
@@ -125,104 +139,97 @@ const PieChartWidget = ({
|
||||
)}
|
||||
{!loading && (
|
||||
<div className={classes.contentContainer}>
|
||||
<ResponsiveContainer>
|
||||
<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 (
|
||||
<span className={classes.pieChartLabel}>
|
||||
{middleLabel && splitSizeMetric(middleLabel)}
|
||||
</span>
|
||||
<div className={classes.chartContainer}>
|
||||
<ResponsiveContainer>
|
||||
<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>
|
||||
)}
|
||||
{middleLabel && (
|
||||
<text
|
||||
x={"50%"}
|
||||
y={"50%"}
|
||||
textAnchor="middle"
|
||||
dominantBaseline="middle"
|
||||
fontWeight={600}
|
||||
fontSize={14}
|
||||
>
|
||||
{middleLabel}
|
||||
</text>
|
||||
)}
|
||||
</PieChart>
|
||||
</ResponsiveContainer>
|
||||
))}
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -14,14 +14,27 @@
|
||||
// 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 React, { Fragment, useEffect, useState } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import { MaterialUiPickersDate } from "@material-ui/pickers/typings/date";
|
||||
import { CircularProgress } from "@material-ui/core";
|
||||
import api from "../../../../../common/api";
|
||||
import { widgetDetailsToPanel } from "../utils";
|
||||
import { IDashboardPanel } from "../types";
|
||||
import { setErrorSnackMessage } from "../../../../../actions";
|
||||
import { ErrorResponseHandler } from "../../../../../common/types";
|
||||
|
||||
interface ISimpleWidget {
|
||||
classes: any;
|
||||
iconWidget: any;
|
||||
label: string;
|
||||
value: string;
|
||||
title: string;
|
||||
panelItem: IDashboardPanel;
|
||||
timeStart: MaterialUiPickersDate;
|
||||
timeEnd: MaterialUiPickersDate;
|
||||
propLoading: boolean;
|
||||
displayErrorMessage: any;
|
||||
apiPrefix: string;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
@@ -47,14 +60,80 @@ const styles = (theme: Theme) =>
|
||||
},
|
||||
});
|
||||
|
||||
const SimpleWidget = ({ classes, iconWidget, label, value }: ISimpleWidget) => {
|
||||
const SimpleWidget = ({
|
||||
classes,
|
||||
iconWidget,
|
||||
title,
|
||||
panelItem,
|
||||
timeStart,
|
||||
timeEnd,
|
||||
propLoading,
|
||||
displayErrorMessage,
|
||||
apiPrefix,
|
||||
}: ISimpleWidget) => {
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const [data, setData] = useState<string>("");
|
||||
|
||||
useEffect(() => {
|
||||
if (propLoading) {
|
||||
setLoading(true);
|
||||
}
|
||||
}, [propLoading]);
|
||||
|
||||
useEffect(() => {
|
||||
if (loading) {
|
||||
let stepCalc = 0;
|
||||
if (timeStart !== null && timeEnd !== null) {
|
||||
const secondsInPeriod = timeEnd.unix() - timeStart.unix();
|
||||
const periods = Math.floor(secondsInPeriod / 60);
|
||||
|
||||
stepCalc = periods < 1 ? 15 : periods;
|
||||
}
|
||||
|
||||
api
|
||||
.invoke(
|
||||
"GET",
|
||||
`/api/v1/${apiPrefix}/info/widgets/${
|
||||
panelItem.id
|
||||
}/?step=${stepCalc}&${
|
||||
timeStart !== null ? `&start=${timeStart.unix()}` : ""
|
||||
}${timeStart !== null && timeEnd !== null ? "&" : ""}${
|
||||
timeEnd !== null ? `end=${timeEnd.unix()}` : ""
|
||||
}`
|
||||
)
|
||||
.then((res: any) => {
|
||||
const widgetsWithValue = widgetDetailsToPanel(res, panelItem);
|
||||
setData(widgetsWithValue.data);
|
||||
setLoading(false);
|
||||
})
|
||||
.catch((err: ErrorResponseHandler) => {
|
||||
displayErrorMessage(err);
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
}, [loading, panelItem, timeEnd, timeStart, displayErrorMessage, apiPrefix]);
|
||||
|
||||
return (
|
||||
<span className={classes.mainWidgetContainer}>
|
||||
<span className={classes.icon}>{iconWidget ? iconWidget : null}</span>
|
||||
<span className={classes.widgetLabel}>{label}: </span>
|
||||
<span className={classes.widgetValue}>{value}</span>
|
||||
</span>
|
||||
<Fragment>
|
||||
{loading && (
|
||||
<div className={classes.loadingAlign}>
|
||||
<CircularProgress />
|
||||
</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>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(SimpleWidget);
|
||||
const connector = connect(null, {
|
||||
displayErrorMessage: setErrorSnackMessage,
|
||||
});
|
||||
|
||||
|
||||
export default withStyles(styles)(connector(SimpleWidget));
|
||||
|
||||
@@ -107,6 +107,8 @@ const SingleRepWidget = ({
|
||||
});
|
||||
}
|
||||
}, [loading, panelItem, timeEnd, timeStart, displayErrorMessage, apiPrefix]);
|
||||
const gradientID= `colorGradient-${title.split(" ").join('-')}`;
|
||||
|
||||
return (
|
||||
<div className={classes.singleValueContainer}>
|
||||
<div className={classes.titleContainer}>{title}</div>
|
||||
@@ -119,6 +121,12 @@ const SingleRepWidget = ({
|
||||
<div className={classes.contentContainer}>
|
||||
<ResponsiveContainer>
|
||||
<AreaChart data={data}>
|
||||
<defs>
|
||||
<linearGradient id={gradientID} x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="5%" stopColor={fillColor} stopOpacity={1} />
|
||||
<stop offset="95%" stopColor={fillColor} stopOpacity={0} />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<YAxis
|
||||
domain={[0, (dataMax: number) => dataMax * 2]}
|
||||
hide={true}
|
||||
@@ -127,17 +135,17 @@ const SingleRepWidget = ({
|
||||
type="monotone"
|
||||
dataKey={"value"}
|
||||
stroke={color}
|
||||
fill={fillColor}
|
||||
fill={`url(#${gradientID})`}
|
||||
fillOpacity={1}
|
||||
/>
|
||||
<text
|
||||
x={"50%"}
|
||||
y={"50%"}
|
||||
textAnchor="middle"
|
||||
dominantBaseline="middle"
|
||||
fontWeight={600}
|
||||
fontSize={18}
|
||||
fill={color}
|
||||
x={"0%"}
|
||||
y={"80%"}
|
||||
textAnchor="start"
|
||||
dominantBaseline="auto"
|
||||
fontWeight={700}
|
||||
fontSize={70}
|
||||
fill={"#07193E"}
|
||||
>
|
||||
{result ? result.innerLabel : ""}
|
||||
</text>
|
||||
|
||||
@@ -14,11 +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 React, { useEffect, useState } from "react";
|
||||
import React, { Fragment, useEffect, useState } from "react";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import { widgetCommon } from "../../../Common/FormComponents/common/styleLibrary";
|
||||
import api from "../../../../../common/api";
|
||||
import { widgetDetailsToPanel } from "../utils";
|
||||
import { splitSizeMetric, widgetDetailsToPanel } from "../utils";
|
||||
import { MaterialUiPickersDate } from "@material-ui/pickers/typings/date";
|
||||
import { IDashboardPanel } from "../types";
|
||||
import { connect } from "react-redux";
|
||||
@@ -49,10 +49,30 @@ const styles = (theme: Theme) =>
|
||||
},
|
||||
loadingAlign: {
|
||||
width: "100%",
|
||||
paddingTop: "15px",
|
||||
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 SingleValueWidget = ({
|
||||
@@ -107,14 +127,18 @@ const SingleValueWidget = ({
|
||||
}
|
||||
}, [loading, panelItem, timeEnd, timeStart, displayErrorMessage, apiPrefix]);
|
||||
return (
|
||||
<div className={classes.singleValueContainer}>
|
||||
<div className={classes.titleContainer}>{title}</div>
|
||||
<div className={classes.containerAlignment}>
|
||||
{loading && (
|
||||
<div className={classes.loadingAlign}>
|
||||
<CircularProgress />
|
||||
</div>
|
||||
)}
|
||||
{!loading && <div className={classes.contentContainer}>{data}</div>}
|
||||
{!loading && (
|
||||
<Fragment>
|
||||
<div className={classes.metric}>{splitSizeMetric(data)}</div>
|
||||
<div className={classes.titleElement}>{title}</div>
|
||||
</Fragment>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -25,6 +25,7 @@ export interface IBarChartConfiguration {
|
||||
dataKey: string;
|
||||
color: string;
|
||||
background?: object;
|
||||
greatestColor?: string;
|
||||
}
|
||||
|
||||
export interface IPieChartConfiguration {
|
||||
|
||||
@@ -25,18 +25,21 @@ import {
|
||||
export enum widgetType {
|
||||
singleValue = "singleValue",
|
||||
linearGraph = "linearGraph",
|
||||
areaGraph = "areaGraph",
|
||||
barChart = "barChart",
|
||||
pieChart = "pieChart",
|
||||
singleRep = "singleRep",
|
||||
simpleWidget = "simpleWidget",
|
||||
}
|
||||
|
||||
export interface IDashboardPanel {
|
||||
id: number;
|
||||
mergedPanels?: IDashboardPanel[];
|
||||
title: string;
|
||||
data: string | object[] | IDataSRep[];
|
||||
data?: string | object[] | IDataSRep[];
|
||||
dataOuter?: string | object[];
|
||||
type: widgetType;
|
||||
layoutIdentifier: string;
|
||||
type?: widgetType;
|
||||
widgetIcon?: any;
|
||||
widgetConfiguration?:
|
||||
| ILinearGraphConfiguration[]
|
||||
| IBarChartConfiguration[]
|
||||
|
||||
@@ -14,311 +14,32 @@
|
||||
// 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 get from "lodash/get";
|
||||
import { Layout } from "react-grid-layout";
|
||||
import { IDashboardPanel, widgetType } from "./types";
|
||||
import {
|
||||
getTimeFromTimestamp,
|
||||
niceBytes,
|
||||
niceDays,
|
||||
textToRGBColor,
|
||||
units,
|
||||
} from "../../../../common/utils";
|
||||
import HealIcon from "../../../../icons/HealIcon";
|
||||
import DiagnosticsIcon from "../../../../icons/DiagnosticsIcon";
|
||||
import HistoryIcon from "../../../../icons/HistoryIcon";
|
||||
|
||||
const dLocalStorageV = "dashboardConfig";
|
||||
|
||||
export const defaultWidgetsLayout: Layout[] = [
|
||||
{
|
||||
w: 1,
|
||||
h: 2,
|
||||
x: 0,
|
||||
y: 0,
|
||||
i: "panel-0",
|
||||
minW: 1,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 1,
|
||||
h: 1,
|
||||
x: 1,
|
||||
y: 2,
|
||||
i: "panel-1",
|
||||
minW: 1,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 1,
|
||||
h: 1,
|
||||
x: 1,
|
||||
y: 3,
|
||||
i: "panel-2",
|
||||
minW: 1,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 1,
|
||||
h: 2,
|
||||
x: 2,
|
||||
y: 0,
|
||||
i: "panel-3",
|
||||
minW: 1,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 4,
|
||||
h: 2,
|
||||
x: 4,
|
||||
y: 2,
|
||||
i: "panel-4",
|
||||
minW: 2,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 4,
|
||||
h: 2,
|
||||
x: 4,
|
||||
y: 0,
|
||||
i: "panel-5",
|
||||
minW: 2,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 1,
|
||||
h: 1,
|
||||
x: 0,
|
||||
y: 2,
|
||||
i: "panel-6",
|
||||
minW: 1,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 1,
|
||||
h: 1,
|
||||
x: 0,
|
||||
y: 3,
|
||||
i: "panel-7",
|
||||
minW: 1,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 1,
|
||||
h: 1,
|
||||
x: 2,
|
||||
y: 2,
|
||||
i: "panel-8",
|
||||
minW: 1,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 1,
|
||||
h: 1,
|
||||
x: 2,
|
||||
y: 3,
|
||||
i: "panel-9",
|
||||
minW: 1,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 4,
|
||||
h: 3,
|
||||
x: 0,
|
||||
y: 4,
|
||||
i: "panel-10",
|
||||
minW: 2,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 1,
|
||||
h: 1,
|
||||
x: 3,
|
||||
y: 0,
|
||||
i: "panel-11",
|
||||
minW: 1,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 1,
|
||||
h: 1,
|
||||
x: 3,
|
||||
y: 1,
|
||||
i: "panel-12",
|
||||
minW: 1,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 4,
|
||||
h: 3,
|
||||
x: 0,
|
||||
y: 10,
|
||||
i: "panel-13",
|
||||
minW: 2,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 4,
|
||||
h: 3,
|
||||
x: 0,
|
||||
y: 4,
|
||||
i: "panel-14",
|
||||
minW: 2,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 4,
|
||||
h: 3,
|
||||
x: 4,
|
||||
y: 4,
|
||||
i: "panel-15",
|
||||
minW: 2,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 8,
|
||||
h: 3,
|
||||
x: 0,
|
||||
y: 7,
|
||||
i: "panel-16",
|
||||
minW: 2,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 8,
|
||||
h: 3,
|
||||
x: 0,
|
||||
y: 19,
|
||||
i: "panel-19",
|
||||
minW: 2,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 1,
|
||||
h: 1,
|
||||
x: 3,
|
||||
y: 2,
|
||||
i: "panel-20",
|
||||
minW: 1,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 1,
|
||||
h: 1,
|
||||
x: 3,
|
||||
y: 3,
|
||||
i: "panel-21",
|
||||
minW: 1,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 4,
|
||||
h: 3,
|
||||
x: 4,
|
||||
y: 4,
|
||||
i: "panel-22",
|
||||
minW: 2,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 4,
|
||||
h: 3,
|
||||
x: 4,
|
||||
y: 10,
|
||||
i: "panel-23",
|
||||
minW: 2,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 4,
|
||||
h: 3,
|
||||
x: 0,
|
||||
y: 13,
|
||||
i: "panel-24",
|
||||
minW: 2,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 4,
|
||||
h: 3,
|
||||
x: 4,
|
||||
y: 13,
|
||||
i: "panel-25",
|
||||
minW: 2,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 4,
|
||||
h: 3,
|
||||
x: 0,
|
||||
y: 16,
|
||||
i: "panel-26",
|
||||
minW: 2,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 4,
|
||||
h: 3,
|
||||
x: 4,
|
||||
y: 16,
|
||||
i: "panel-27",
|
||||
minW: 2,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 1,
|
||||
h: 1,
|
||||
x: 1,
|
||||
y: 0,
|
||||
i: "panel-28",
|
||||
minW: 1,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
{
|
||||
w: 1,
|
||||
h: 1,
|
||||
x: 1,
|
||||
y: 1,
|
||||
i: "panel-29",
|
||||
minW: 1,
|
||||
moved: false,
|
||||
static: false,
|
||||
},
|
||||
];
|
||||
|
||||
const colorsMain = [
|
||||
"#6992B7",
|
||||
"#E2AD17",
|
||||
"#22B573",
|
||||
"#F7655E",
|
||||
"#0071BC",
|
||||
"#C4D4E9",
|
||||
"#DCD1EE",
|
||||
"#D1EEE7",
|
||||
"#EEDED1",
|
||||
"#AAF38F",
|
||||
"#F9E6C5",
|
||||
"#A6E8C4",
|
||||
"#C83B51",
|
||||
"#F4CECE",
|
||||
"#ADD5E0",
|
||||
"#D6D6D6",
|
||||
];
|
||||
|
||||
const niceDaysFromNS = (seconds: string) => {
|
||||
@@ -334,24 +55,10 @@ export const panelsConfiguration: IDashboardPanel[] = [
|
||||
id: 1,
|
||||
title: "Uptime",
|
||||
data: "N/A",
|
||||
type: widgetType.singleValue,
|
||||
layoutIdentifier: "panel-0",
|
||||
type: widgetType.simpleWidget,
|
||||
widgetIcon: <HistoryIcon />,
|
||||
labelDisplayFunction: niceDays,
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
title: "Total Online Disks",
|
||||
data: "N/A",
|
||||
type: widgetType.singleValue,
|
||||
layoutIdentifier: "panel-1",
|
||||
},
|
||||
{
|
||||
id: 78,
|
||||
title: "Total Offline Disks",
|
||||
data: "N/A",
|
||||
type: widgetType.singleValue,
|
||||
layoutIdentifier: "panel-2",
|
||||
},
|
||||
{
|
||||
id: 50,
|
||||
title: "Current Usable Capacity",
|
||||
@@ -360,21 +67,20 @@ export const panelsConfiguration: IDashboardPanel[] = [
|
||||
widgetConfiguration: {
|
||||
outerChart: {
|
||||
colorList: ["#9c9c9c"],
|
||||
innerRadius: 51,
|
||||
outerRadius: 54,
|
||||
startAngle: -15,
|
||||
endAngle: 195,
|
||||
innerRadius: 0,
|
||||
outerRadius: 0,
|
||||
startAngle: 0,
|
||||
endAngle: 0,
|
||||
},
|
||||
innerChart: {
|
||||
colorList: colorsMain,
|
||||
innerRadius: 35,
|
||||
innerRadius: 20,
|
||||
outerRadius: 50,
|
||||
startAngle: -15,
|
||||
endAngle: 195,
|
||||
startAngle: 90,
|
||||
endAngle: -200,
|
||||
},
|
||||
},
|
||||
type: widgetType.pieChart,
|
||||
layoutIdentifier: "panel-3",
|
||||
innerLabel: "N/A",
|
||||
labelDisplayFunction: niceBytes,
|
||||
},
|
||||
@@ -390,8 +96,7 @@ export const panelsConfiguration: IDashboardPanel[] = [
|
||||
fillColor: "#000",
|
||||
},
|
||||
],
|
||||
type: widgetType.linearGraph,
|
||||
layoutIdentifier: "panel-4",
|
||||
type: widgetType.areaGraph,
|
||||
yAxisFormatter: niceBytes,
|
||||
xAxisFormatter: getTimeFromTimestamp,
|
||||
},
|
||||
@@ -404,8 +109,9 @@ export const panelsConfiguration: IDashboardPanel[] = [
|
||||
dataKey: "a",
|
||||
color: colorsMain[0],
|
||||
background: {
|
||||
fill: "rgba(0,0,0,0.1)",
|
||||
fill: "#EEF1F4",
|
||||
},
|
||||
greatestColor: "#081C42",
|
||||
},
|
||||
],
|
||||
customStructure: [
|
||||
@@ -436,21 +142,6 @@ export const panelsConfiguration: IDashboardPanel[] = [
|
||||
},
|
||||
],
|
||||
type: widgetType.barChart,
|
||||
layoutIdentifier: "panel-5",
|
||||
},
|
||||
{
|
||||
id: 53,
|
||||
title: "Total Online Servers",
|
||||
data: "N/A",
|
||||
type: widgetType.singleValue,
|
||||
layoutIdentifier: "panel-6",
|
||||
},
|
||||
{
|
||||
id: 69,
|
||||
title: "Total Offline Servers",
|
||||
data: "N/A",
|
||||
type: widgetType.singleValue,
|
||||
layoutIdentifier: "panel-7",
|
||||
},
|
||||
{
|
||||
id: 66,
|
||||
@@ -460,7 +151,6 @@ export const panelsConfiguration: IDashboardPanel[] = [
|
||||
type: widgetType.singleRep,
|
||||
color: "#0071BC",
|
||||
fillColor: "#ADD5E0",
|
||||
layoutIdentifier: "panel-8",
|
||||
},
|
||||
{
|
||||
id: 44,
|
||||
@@ -470,7 +160,6 @@ export const panelsConfiguration: IDashboardPanel[] = [
|
||||
type: widgetType.singleRep,
|
||||
color: "#0071BC",
|
||||
fillColor: "#ADD5E0",
|
||||
layoutIdentifier: "panel-9",
|
||||
},
|
||||
{
|
||||
id: 63,
|
||||
@@ -485,7 +174,7 @@ export const panelsConfiguration: IDashboardPanel[] = [
|
||||
},
|
||||
],
|
||||
type: widgetType.linearGraph,
|
||||
layoutIdentifier: "panel-10",
|
||||
|
||||
xAxisFormatter: getTimeFromTimestamp,
|
||||
yAxisFormatter: niceBytes,
|
||||
},
|
||||
@@ -495,7 +184,6 @@ export const panelsConfiguration: IDashboardPanel[] = [
|
||||
data: [],
|
||||
innerLabel: "N/A",
|
||||
type: widgetType.singleRep,
|
||||
layoutIdentifier: "panel-11",
|
||||
color: "#22B573",
|
||||
fillColor: "#A6E8C4",
|
||||
},
|
||||
@@ -505,7 +193,6 @@ export const panelsConfiguration: IDashboardPanel[] = [
|
||||
data: [],
|
||||
innerLabel: "N/A",
|
||||
type: widgetType.singleRep,
|
||||
layoutIdentifier: "panel-12",
|
||||
color: "#F7655E",
|
||||
fillColor: "#F4CECE",
|
||||
},
|
||||
@@ -522,7 +209,7 @@ export const panelsConfiguration: IDashboardPanel[] = [
|
||||
},
|
||||
],
|
||||
type: widgetType.linearGraph,
|
||||
layoutIdentifier: "panel-13",
|
||||
|
||||
yAxisFormatter: roundNumber,
|
||||
xAxisFormatter: getTimeFromTimestamp,
|
||||
},
|
||||
@@ -539,7 +226,7 @@ export const panelsConfiguration: IDashboardPanel[] = [
|
||||
},
|
||||
],
|
||||
type: widgetType.linearGraph,
|
||||
layoutIdentifier: "panel-14",
|
||||
|
||||
xAxisFormatter: getTimeFromTimestamp,
|
||||
},
|
||||
{
|
||||
@@ -555,7 +242,7 @@ export const panelsConfiguration: IDashboardPanel[] = [
|
||||
},
|
||||
],
|
||||
type: widgetType.linearGraph,
|
||||
layoutIdentifier: "panel-15",
|
||||
|
||||
xAxisFormatter: getTimeFromTimestamp,
|
||||
yAxisFormatter: niceBytes,
|
||||
},
|
||||
@@ -572,7 +259,7 @@ export const panelsConfiguration: IDashboardPanel[] = [
|
||||
},
|
||||
],
|
||||
type: widgetType.linearGraph,
|
||||
layoutIdentifier: "panel-16",
|
||||
|
||||
yAxisFormatter: niceBytes,
|
||||
xAxisFormatter: getTimeFromTimestamp,
|
||||
},
|
||||
@@ -589,7 +276,7 @@ export const panelsConfiguration: IDashboardPanel[] = [
|
||||
},
|
||||
],
|
||||
type: widgetType.linearGraph,
|
||||
layoutIdentifier: "panel-19",
|
||||
|
||||
yAxisFormatter: niceBytes,
|
||||
xAxisFormatter: getTimeFromTimestamp,
|
||||
},
|
||||
@@ -597,16 +284,16 @@ export const panelsConfiguration: IDashboardPanel[] = [
|
||||
id: 80,
|
||||
title: "Time Since Last Heal Activity",
|
||||
data: "N/A",
|
||||
type: widgetType.singleValue,
|
||||
layoutIdentifier: "panel-20",
|
||||
type: widgetType.simpleWidget,
|
||||
widgetIcon: <HealIcon />,
|
||||
labelDisplayFunction: niceDaysFromNS,
|
||||
},
|
||||
{
|
||||
id: 81,
|
||||
title: "Time Since Last Scan Activity",
|
||||
data: "N/A",
|
||||
type: widgetType.singleValue,
|
||||
layoutIdentifier: "panel-21",
|
||||
type: widgetType.simpleWidget,
|
||||
widgetIcon: <DiagnosticsIcon />,
|
||||
labelDisplayFunction: niceDaysFromNS,
|
||||
},
|
||||
{
|
||||
@@ -622,7 +309,7 @@ export const panelsConfiguration: IDashboardPanel[] = [
|
||||
},
|
||||
],
|
||||
type: widgetType.linearGraph,
|
||||
layoutIdentifier: "panel-22",
|
||||
|
||||
xAxisFormatter: getTimeFromTimestamp,
|
||||
},
|
||||
{
|
||||
@@ -638,7 +325,7 @@ export const panelsConfiguration: IDashboardPanel[] = [
|
||||
},
|
||||
],
|
||||
type: widgetType.linearGraph,
|
||||
layoutIdentifier: "panel-23",
|
||||
|
||||
xAxisFormatter: getTimeFromTimestamp,
|
||||
yAxisFormatter: niceBytes,
|
||||
},
|
||||
@@ -655,7 +342,7 @@ export const panelsConfiguration: IDashboardPanel[] = [
|
||||
},
|
||||
],
|
||||
type: widgetType.linearGraph,
|
||||
layoutIdentifier: "panel-24",
|
||||
|
||||
xAxisFormatter: getTimeFromTimestamp,
|
||||
yAxisFormatter: niceBytes,
|
||||
},
|
||||
@@ -672,7 +359,7 @@ export const panelsConfiguration: IDashboardPanel[] = [
|
||||
},
|
||||
],
|
||||
type: widgetType.linearGraph,
|
||||
layoutIdentifier: "panel-25",
|
||||
|
||||
disableYAxis: true,
|
||||
xAxisFormatter: getTimeFromTimestamp,
|
||||
},
|
||||
@@ -689,7 +376,6 @@ export const panelsConfiguration: IDashboardPanel[] = [
|
||||
},
|
||||
],
|
||||
type: widgetType.linearGraph,
|
||||
layoutIdentifier: "panel-26",
|
||||
yAxisFormatter: roundNumber,
|
||||
xAxisFormatter: getTimeFromTimestamp,
|
||||
},
|
||||
@@ -706,25 +392,66 @@ export const panelsConfiguration: IDashboardPanel[] = [
|
||||
},
|
||||
],
|
||||
type: widgetType.linearGraph,
|
||||
layoutIdentifier: "panel-27",
|
||||
yAxisFormatter: roundNumber,
|
||||
xAxisFormatter: getTimeFromTimestamp,
|
||||
},
|
||||
{
|
||||
id: 65,
|
||||
title: "Total S3 Traffic Inbound",
|
||||
data: "N/A",
|
||||
type: widgetType.singleValue,
|
||||
layoutIdentifier: "panel-28",
|
||||
labelDisplayFunction: niceBytes,
|
||||
id: 500,
|
||||
mergedPanels: [
|
||||
{
|
||||
id: 53,
|
||||
title: "Online Servers",
|
||||
data: "N/A",
|
||||
type: widgetType.singleValue,
|
||||
},
|
||||
{
|
||||
id: 69,
|
||||
title: "Offline Servers",
|
||||
data: "N/A",
|
||||
type: widgetType.singleValue,
|
||||
},
|
||||
],
|
||||
title: "Servers",
|
||||
},
|
||||
{
|
||||
id: 64,
|
||||
title: "Total S3 Traffic Outbound",
|
||||
data: "N/A",
|
||||
type: widgetType.singleValue,
|
||||
layoutIdentifier: "panel-29",
|
||||
labelDisplayFunction: niceBytes,
|
||||
id: 501,
|
||||
mergedPanels: [
|
||||
{
|
||||
id: 9,
|
||||
title: "Online Disks",
|
||||
data: "N/A",
|
||||
type: widgetType.singleValue,
|
||||
},
|
||||
{
|
||||
id: 78,
|
||||
title: "Offline Disks",
|
||||
data: "N/A",
|
||||
type: widgetType.singleValue,
|
||||
},
|
||||
],
|
||||
title: "Disks",
|
||||
},
|
||||
{
|
||||
id: 502,
|
||||
mergedPanels: [
|
||||
{
|
||||
id: 65,
|
||||
title: "Inbound Traffic",
|
||||
data: "N/A",
|
||||
type: widgetType.singleValue,
|
||||
|
||||
labelDisplayFunction: niceBytes,
|
||||
},
|
||||
{
|
||||
id: 64,
|
||||
title: "Outbound Traffic",
|
||||
data: "N/A",
|
||||
type: widgetType.singleValue,
|
||||
|
||||
labelDisplayFunction: niceBytes,
|
||||
},
|
||||
],
|
||||
title: "Total S3 Traffic",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -804,6 +531,7 @@ export const widgetDetailsToPanel = (
|
||||
|
||||
switch (panelItem.type) {
|
||||
case widgetType.singleValue:
|
||||
case widgetType.simpleWidget:
|
||||
if (typeOfPayload === "stat" || typeOfPayload === "singlestat") {
|
||||
// We sort values & get the last value
|
||||
let elements = get(payloadData, "targets[0].result[0].values", []);
|
||||
@@ -873,6 +601,7 @@ export const widgetDetailsToPanel = (
|
||||
}
|
||||
break;
|
||||
case widgetType.linearGraph:
|
||||
case widgetType.areaGraph:
|
||||
if (typeOfPayload === "graph") {
|
||||
let targets = get(payloadData, "targets", []);
|
||||
if (targets === null) {
|
||||
@@ -1064,30 +793,21 @@ export const widgetDetailsToPanel = (
|
||||
return panelItem;
|
||||
};
|
||||
|
||||
export const saveDashboardDistribution = (configuration: Layout[]) => {
|
||||
localStorage.setItem(dLocalStorageV, btoa(JSON.stringify(configuration)));
|
||||
};
|
||||
|
||||
export const getDashboardDistribution = (currentItems: number) => {
|
||||
const storedConfiguration = localStorage.getItem(dLocalStorageV);
|
||||
|
||||
if (!storedConfiguration) {
|
||||
return defaultWidgetsLayout;
|
||||
}
|
||||
|
||||
const parsedConfig = JSON.parse(atob(storedConfiguration));
|
||||
|
||||
if (
|
||||
parsedConfig.length === 0 ||
|
||||
(parsedConfig.length > 0 && !parsedConfig[0].minW)
|
||||
) {
|
||||
return defaultWidgetsLayout;
|
||||
}
|
||||
|
||||
// Stored Widgets length is not the same as the currentItems, then we return the new configuration
|
||||
if (currentItems !== 0 && parsedConfig.length !== currentItems) {
|
||||
return defaultWidgetsLayout;
|
||||
}
|
||||
|
||||
return parsedConfig;
|
||||
export const splitSizeMetric = (val: string) => {
|
||||
const splittedText = val.split(" ");
|
||||
// Value is not a size metric, we return as common string
|
||||
if (splittedText.length !== 2) {
|
||||
return <Fragment>{val}</Fragment>;
|
||||
}
|
||||
|
||||
if (!units.includes(splittedText[1])) {
|
||||
return <Fragment>{val}</Fragment>;
|
||||
}
|
||||
|
||||
return (
|
||||
<span className="commonValue">
|
||||
{splittedText[0]}
|
||||
<span className="unitText">{splittedText[1]}</span>
|
||||
</span>
|
||||
);
|
||||
};
|
||||
@@ -1831,13 +1831,6 @@
|
||||
dependencies:
|
||||
"@types/d3-time" "*"
|
||||
|
||||
"@types/d3-shape@^1":
|
||||
version "1.3.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-1.3.5.tgz#c0164c1be1429473016f855871d487f806c4e968"
|
||||
integrity sha512-aPEax03owTAKynoK8ZkmkZEDZvvT4Y5pWgii4Jp4oQt0gH45j6siDl9gNDVC5kl64XHN2goN9jbYoHK88tFAcA==
|
||||
dependencies:
|
||||
"@types/d3-path" "^1"
|
||||
|
||||
"@types/d3-shape@^2.0.0":
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-2.1.0.tgz#cc7bbc9fc2c25f092bd457887a3224a21a55ca55"
|
||||
@@ -2070,14 +2063,6 @@
|
||||
"@types/prop-types" "*"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/recharts@^1.8.19":
|
||||
version "1.8.19"
|
||||
resolved "https://registry.yarnpkg.com/@types/recharts/-/recharts-1.8.19.tgz#047f72cf4c25df545aa1085fe3a085e58a2483c1"
|
||||
integrity sha512-Fd2cYnBlWz/ga8rLmjwsZNBAc4CzXZiuTYPPqMIgrtQ02yI/OTm8WPM6ZyUuYlSdyangtsvFmHWzZ7W4tuknDA==
|
||||
dependencies:
|
||||
"@types/d3-shape" "^1"
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/resize-observer-browser@^0.1.5":
|
||||
version "0.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/resize-observer-browser/-/resize-observer-browser-0.1.5.tgz#36d897708172ac2380cd486da7a3daf1161c1e23"
|
||||
@@ -9970,10 +9955,10 @@ recharts-scale@^0.4.4:
|
||||
dependencies:
|
||||
decimal.js-light "^2.4.1"
|
||||
|
||||
recharts@^2.0.3:
|
||||
version "2.0.9"
|
||||
resolved "https://registry.yarnpkg.com/recharts/-/recharts-2.0.9.tgz#048068eb01383291104548388712026948275f70"
|
||||
integrity sha512-JNsXE80PuF3hugUCE7JqDOMSvu5xQLxtjOaqFKKZI2pCJ1PVJzhwDv4TWk0nO4AvADbeWzYEHbg8C5Hcrh42UA==
|
||||
recharts@^2.1.1:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/recharts/-/recharts-2.1.2.tgz#ceeb01e53fb46da0d946a1e0f82d783ddf5b9d06"
|
||||
integrity sha512-rwFQT6T4imhLzD1kYtg9ql8YOesbFRdSwZi95KWgi5udbBdLGRCR4SgaPO8kf0URHcC23mdRbLLTMYCnXng7zQ==
|
||||
dependencies:
|
||||
"@types/d3-scale" "^3.0.0"
|
||||
"@types/d3-shape" "^2.0.0"
|
||||
|
||||
Reference in New Issue
Block a user