Replaced Usage bar in tenant details to display tiers information (#1836)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
65
portal-ui/src/screens/Console/Common/UsageBar/UsageBar.tsx
Normal file
65
portal-ui/src/screens/Console/Common/UsageBar/UsageBar.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2022 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 from "react";
|
||||
|
||||
export interface ISizeBarItem {
|
||||
value: number;
|
||||
itemName: string;
|
||||
color: string;
|
||||
}
|
||||
|
||||
export interface IUsageBar {
|
||||
totalValue: number;
|
||||
sizeItems: ISizeBarItem[];
|
||||
bgColor?: string;
|
||||
}
|
||||
|
||||
const UsageBar = ({
|
||||
totalValue,
|
||||
sizeItems,
|
||||
bgColor = "#ededed",
|
||||
}: IUsageBar) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: "100%",
|
||||
height: 12,
|
||||
backgroundColor: bgColor,
|
||||
borderRadius: 30,
|
||||
display: "flex",
|
||||
transitionDuration: "0.3s",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
{sizeItems.map((sizeElement) => {
|
||||
const itemPercentage = (sizeElement.value * 100) / totalValue;
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: `${itemPercentage}%`,
|
||||
height: "100%",
|
||||
backgroundColor: sizeElement.color,
|
||||
transitionDuration: "0.3s",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default UsageBar;
|
||||
@@ -1,19 +1,23 @@
|
||||
import React from "react";
|
||||
import React, { Fragment } from "react";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import { LinearProgress, Stack } from "@mui/material";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { LinearProgress, Stack } from "@mui/material";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import ErrorBlock from "../../../shared/ErrorBlock";
|
||||
import {
|
||||
CapacityValues,
|
||||
ITenant,
|
||||
ValueUnit,
|
||||
} from "../../Tenants/ListTenants/types";
|
||||
import { CircleIcon } from "../../../../icons";
|
||||
import LabelValuePair from "./LabelValuePair";
|
||||
import { ValueUnit } from "../../Tenants/ListTenants/types";
|
||||
import { niceBytes } from "../../../../common/utils";
|
||||
import { niceBytes, niceBytesInt } from "../../../../common/utils";
|
||||
import Loader from "../Loader/Loader";
|
||||
import TenantCapacity from "../../Tenants/ListTenants/TenantCapacity";
|
||||
import ErrorBlock from "../../../shared/ErrorBlock";
|
||||
import LabelValuePair from "./LabelValuePair";
|
||||
|
||||
interface ISummaryUsageBar {
|
||||
maxValue: number | undefined;
|
||||
currValue: number | undefined;
|
||||
tenant: ITenant;
|
||||
label: string;
|
||||
error: string;
|
||||
loading: boolean;
|
||||
@@ -57,31 +61,66 @@ export const BorderLinearProgress = withStyles((theme) => ({
|
||||
|
||||
const SummaryUsageBar = ({
|
||||
classes,
|
||||
maxValue,
|
||||
currValue,
|
||||
tenant,
|
||||
healthStatus,
|
||||
loading,
|
||||
error,
|
||||
}: ISummaryUsageBar) => {
|
||||
var capacity: ValueUnit = { value: "n/a", unit: "" };
|
||||
var used: ValueUnit = { value: "n/a", unit: "" };
|
||||
console.log("TENANT", tenant)
|
||||
let raw: ValueUnit = { value: "n/a", unit: "" };
|
||||
let capacity: ValueUnit = { value: "n/a", unit: "" };
|
||||
let used: ValueUnit = { value: "n/a", unit: "" };
|
||||
let localUse: ValueUnit = { value: "n/a", unit: "" };
|
||||
let tieredUse: ValueUnit = { value: "n/a", unit: "" };
|
||||
|
||||
if (maxValue) {
|
||||
const b = niceBytes(`${maxValue}`, true);
|
||||
if (tenant.status?.usage?.raw) {
|
||||
const b = niceBytes(`${tenant.status.usage.raw}`, true);
|
||||
const parts = b.split(" ");
|
||||
raw.value = parts[0];
|
||||
raw.unit = parts[1];
|
||||
}
|
||||
if (tenant.status?.usage?.capacity) {
|
||||
const b = niceBytes(`${tenant.status.usage.capacity}`, true);
|
||||
const parts = b.split(" ");
|
||||
capacity.value = parts[0];
|
||||
capacity.unit = parts[1];
|
||||
}
|
||||
if (currValue) {
|
||||
const b = niceBytes(`${currValue}`, true);
|
||||
if (tenant.status?.usage?.capacity_usage) {
|
||||
const b = niceBytesInt(tenant.status.usage.capacity_usage, true);
|
||||
const parts = b.split(" ");
|
||||
used.value = parts[0];
|
||||
used.unit = parts[1];
|
||||
}
|
||||
|
||||
let percentagelValue = 0;
|
||||
if (currValue && maxValue) {
|
||||
percentagelValue = (currValue * 100) / maxValue;
|
||||
let spaceVariants: CapacityValues[] = [];
|
||||
if (!tenant.tiers || tenant.tiers.length === 0) {
|
||||
spaceVariants = [
|
||||
{ value: tenant.status?.usage?.capacity_usage || 0, variant: "STANDARD" },
|
||||
];
|
||||
} else {
|
||||
spaceVariants = tenant.tiers.map((itemTenant) => {
|
||||
return { value: itemTenant.size, variant: itemTenant.name };
|
||||
});
|
||||
let internalUsage = tenant.tiers
|
||||
.filter((itemTenant) => {
|
||||
return itemTenant.type === "internal";
|
||||
})
|
||||
.reduce((sum, itemTenant) => sum + itemTenant.size, 0);
|
||||
let tieredUsage = tenant.tiers
|
||||
.filter((itemTenant) => {
|
||||
return itemTenant.type !== "internal";
|
||||
})
|
||||
.reduce((sum, itemTenant) => sum + itemTenant.size, 0);
|
||||
|
||||
const t = niceBytesInt(tieredUsage, true);
|
||||
const parts = t.split(" ");
|
||||
tieredUse.value = parts[0];
|
||||
tieredUse.unit = parts[1];
|
||||
|
||||
const is = niceBytesInt(internalUsage, true);
|
||||
const partsInternal = is.split(" ");
|
||||
localUse.value = partsInternal[0];
|
||||
localUse.unit = partsInternal[1];
|
||||
}
|
||||
|
||||
const renderComponent = () => {
|
||||
@@ -90,26 +129,41 @@ const SummaryUsageBar = ({
|
||||
<ErrorBlock errorMessage={error} withBreak={false} />
|
||||
) : (
|
||||
<Grid item xs={12}>
|
||||
<BorderLinearProgress
|
||||
variant="determinate"
|
||||
value={percentagelValue}
|
||||
<TenantCapacity
|
||||
totalCapacity={tenant.status?.usage?.raw || 0}
|
||||
usedSpaceVariants={spaceVariants}
|
||||
statusClass={""}
|
||||
render={"bar"}
|
||||
/>
|
||||
<Stack
|
||||
direction={{ xs: "column", sm: "row" }}
|
||||
spacing={{ xs: 1, sm: 2, md: 4 }}
|
||||
alignItems={"stretch"}
|
||||
margin={"15px 0 15px 0"}
|
||||
margin={"0 0 15px 0"}
|
||||
>
|
||||
<LabelValuePair
|
||||
label={"Storage Capacity:"}
|
||||
orientation={"row"}
|
||||
value={`${capacity.value} ${capacity.unit}`}
|
||||
/>
|
||||
<LabelValuePair
|
||||
label={"Used:"}
|
||||
orientation={"row"}
|
||||
value={`${used.value} ${used.unit}`}
|
||||
/>
|
||||
{(!tenant.tiers || tenant.tiers.length === 0) && (
|
||||
<Fragment>
|
||||
<LabelValuePair
|
||||
label={"Internal:"}
|
||||
orientation={"row"}
|
||||
value={`${used.value} ${used.unit}`}
|
||||
/>
|
||||
</Fragment>
|
||||
)}
|
||||
{tenant.tiers && tenant.tiers.length > 0 && (
|
||||
<Fragment>
|
||||
<LabelValuePair
|
||||
label={"Internal:"}
|
||||
orientation={"row"}
|
||||
value={`${localUse.value} ${localUse.unit}`}
|
||||
/>
|
||||
<LabelValuePair
|
||||
label={"Tiered:"}
|
||||
orientation={"row"}
|
||||
value={`${tieredUse.value} ${tieredUse.unit}`}
|
||||
/>
|
||||
</Fragment>
|
||||
)}
|
||||
{healthStatus && (
|
||||
<LabelValuePair
|
||||
orientation={"row"}
|
||||
|
||||
@@ -21,7 +21,10 @@ import { LinearProgress } from "@mui/material";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { ITenant, ITenantsResponse } from "./types";
|
||||
import {
|
||||
ITenant,
|
||||
ITenantsResponse,
|
||||
} from "./types";
|
||||
import { niceBytes } from "../../../../common/utils";
|
||||
import { NewServiceAccount } from "../../Common/CredentialsPrompt/types";
|
||||
import {
|
||||
|
||||
@@ -19,17 +19,20 @@ import { Cell, Pie, PieChart } from "recharts";
|
||||
import { CapacityValue, CapacityValues } from "./types";
|
||||
import { niceBytesInt } from "../../../../common/utils";
|
||||
import { CircleIcon } from "../../../../icons";
|
||||
import UsageBar, { ISizeBarItem } from "../../Common/UsageBar/UsageBar";
|
||||
|
||||
interface ITenantCapacity {
|
||||
totalCapacity: number;
|
||||
usedSpaceVariants: CapacityValues[];
|
||||
statusClass: string;
|
||||
render?: "pie" | "bar";
|
||||
}
|
||||
|
||||
const TenantCapacity = ({
|
||||
totalCapacity,
|
||||
usedSpaceVariants,
|
||||
statusClass,
|
||||
render = "pie",
|
||||
}: ITenantCapacity) => {
|
||||
const colors = [
|
||||
"#8dacd3",
|
||||
@@ -44,6 +47,8 @@ const TenantCapacity = ({
|
||||
"#2781B0",
|
||||
];
|
||||
|
||||
const BGColor = "#ededed";
|
||||
|
||||
const totalUsedSpace = usedSpaceVariants.reduce((acc, currValue) => {
|
||||
return acc + currValue.value;
|
||||
}, 0);
|
||||
@@ -88,15 +93,39 @@ const TenantCapacity = ({
|
||||
}
|
||||
|
||||
const plotValues: CapacityValue[] = [
|
||||
{ value: emptySpace, color: "transparent", label: "Empty Space" },
|
||||
{
|
||||
value: standardTier.value,
|
||||
color: standardTierColor,
|
||||
label: "Used Space by Tenant",
|
||||
},
|
||||
...tiersList,
|
||||
{
|
||||
value: emptySpace,
|
||||
color: render === "bar" ? BGColor : "transparent",
|
||||
label: "Empty Space",
|
||||
},
|
||||
];
|
||||
|
||||
if (render === "bar") {
|
||||
const plotValuesForUsageBar: ISizeBarItem[] = plotValues.map((plotVal) => {
|
||||
return {
|
||||
value: plotVal.value,
|
||||
color: plotVal.color,
|
||||
itemName: plotVal.label,
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<div style={{ width: "100%", marginBottom: 15 }}>
|
||||
<UsageBar
|
||||
totalValue={totalCapacity}
|
||||
sizeItems={plotValuesForUsageBar}
|
||||
bgColor={BGColor}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ position: "relative", width: 110, height: 110 }}>
|
||||
<div
|
||||
@@ -134,7 +163,7 @@ const TenantCapacity = ({
|
||||
dataKey="value"
|
||||
outerRadius={50}
|
||||
innerRadius={40}
|
||||
fill="#ededed"
|
||||
fill={BGColor}
|
||||
isAnimationActive={false}
|
||||
stroke={"none"}
|
||||
/>
|
||||
|
||||
@@ -148,7 +148,7 @@ export interface ITenant {
|
||||
image: string;
|
||||
pool_count: number;
|
||||
currentState: string;
|
||||
instance_count: 4;
|
||||
instance_count: number;
|
||||
creation_date: string;
|
||||
volume_size: number;
|
||||
volume_count: number;
|
||||
@@ -270,3 +270,7 @@ export interface IEditPoolItem {
|
||||
export interface IEditPoolRequest {
|
||||
pools: IEditPoolItem[];
|
||||
}
|
||||
|
||||
export interface IPlotBarValues {
|
||||
[key: string]: CapacityValue;
|
||||
}
|
||||
|
||||
@@ -123,10 +123,13 @@ const healthStatusToClass = (health_status: string = "red", classes: any) => {
|
||||
};
|
||||
|
||||
const StorageSummary = ({ tenant, classes }: Partial<ITenantsSummary>) => {
|
||||
if (!tenant) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<SummaryUsageBar
|
||||
currValue={tenant?.status?.usage?.raw_usage}
|
||||
maxValue={tenant?.status?.usage?.raw}
|
||||
tenant={tenant}
|
||||
label={"Storage"}
|
||||
error={""}
|
||||
loading={false}
|
||||
|
||||
Reference in New Issue
Block a user