Tenant Details (#162)

This commit is contained in:
Daniel Valdivia
2020-06-08 13:37:14 -07:00
committed by GitHub
parent fb59e8c353
commit f4d08a7502
7 changed files with 179 additions and 194 deletions

File diff suppressed because one or more lines are too long

View File

@@ -307,7 +307,7 @@ const Console = ({
},
{
component: TenantDetails,
path: "/clusters/:clusterName",
path: "/tenants/:tenantName",
},
];
const allowedRoutes = routes.filter((route: any) => allowedPages[route.path]);

View File

@@ -54,6 +54,11 @@ const styles = (theme: Theme) =>
...modalBasic,
});
interface Opts {
label: string;
value: string;
}
const AddTenant = ({
open,
closeModalAndRefresh,
@@ -75,7 +80,7 @@ const AddTenant = ({
const [enableMCS, setEnableMCS] = useState<boolean>(false);
const [enableSSL, setEnableSSL] = useState<boolean>(false);
const [sizeFactor, setSizeFactor] = useState<string>("Gi");
const [storageClasses, setStorageClassesList] = useState<string[]>([]);
const [storageClasses, setStorageClassesList] = useState<Opts[]>([]);
useEffect(() => {
fetchStorageClassList();
@@ -136,18 +141,18 @@ const AddTenant = ({
if (res !== null) {
classes = res;
}
setStorageClassesList(classes);
setStorageClassesList(
classes.map((s: string) => ({
label: s,
value: s,
}))
);
})
.catch((err: any) => {
console.log(err);
});
};
const storageClassesList = storageClasses.map((s: string) => ({
label: s,
value: s,
}));
return (
<ModalWrapper
title="Create Tenant"
@@ -279,7 +284,7 @@ const AddTenant = ({
}}
label="Storage Class"
value={volumeConfiguration.storage_class}
options={storageClassesList}
options={storageClasses}
/>
</Grid>
<Grid item xs={12}>

View File

@@ -76,7 +76,7 @@ const ZonesMultiSelector = ({
onChange,
classes,
}: IZonesMultiSelector) => {
const defaultZone: IZone = { name: "", servers: 0 };
const defaultZone: IZone = { name: "", servers: 0, capacity: "", volumes: 0 };
const [currentElements, setCurrentElements] = useState<IZone[]>([
{ ...defaultZone },

View File

@@ -17,6 +17,9 @@
export interface IZone {
name: string;
servers: number;
// computed
capacity: string;
volumes: number;
}
export interface IVolumeConfiguration {
@@ -32,6 +35,8 @@ export interface ITenant {
creation_date: Date;
volume_size: number;
volume_count: number;
volumes_per_server: number;
zones: IZone[];
// computed
capacity: string;
}

View File

@@ -5,13 +5,19 @@ import { modalBasic } from "../../Common/FormComponents/common/styleLibrary";
import InputBoxWrapper from "../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
import SelectWrapper from "../../Common/FormComponents/SelectWrapper/SelectWrapper";
import Grid from "@material-ui/core/Grid";
import { factorForDropdown, getTotalSize } from "../../../../common/utils";
import {
factorForDropdown,
getTotalSize,
niceBytes,
} from "../../../../common/utils";
import { Button, LinearProgress } from "@material-ui/core";
interface IAddZoneProps {
classes: any;
open: boolean;
onCloseZoneAndReload: (shouldReload: boolean) => void;
volumesPerInstance: number;
volumeSize: number;
}
const styles = (theme: Theme) =>
@@ -60,17 +66,14 @@ const AddZoneModal = ({
classes,
open,
onCloseZoneAndReload,
volumesPerInstance,
volumeSize,
}: IAddZoneProps) => {
const [addSending, setAddSending] = useState<boolean>(false);
const [zoneName, setZoneName] = useState<string>("");
const [numberOfInstances, setNumberOfInstances] = useState<number>(0);
const [volumesPerInstance, setVolumesPerInstance] = useState<number>(0);
const [sizeFactor, setSizeFactor] = useState<string>("GiB");
const [volumeConfiguration, setVolumeConfig] = useState<string>("");
const [storageClass, setStorageClass] = useState<string>("");
const instanceCapacity: number =
parseFloat(volumeConfiguration) * volumesPerInstance;
const instanceCapacity: number = volumeSize * volumesPerInstance;
const totalCapacity: number = instanceCapacity * numberOfInstances;
return (
@@ -112,66 +115,17 @@ const AddZoneModal = ({
/>
</Grid>
<Grid item xs={12}>
<InputBoxWrapper
id="volumes_per_instance"
name="volumes_per_instance"
type="number"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setVolumesPerInstance(parseInt(e.target.value));
}}
label="Volumes per Instance"
value={volumesPerInstance.toString(10)}
/>
</Grid>
<Grid item xs={12}>
<div className={classes.multiContainer}>
<div>
<InputBoxWrapper
id="volume_size"
name="volume_size"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setVolumeConfig(e.target.value);
}}
label="Size"
value={volumeConfiguration}
/>
</div>
<div className={classes.sizeFactorContainer}>
<SelectWrapper
label=""
id="size_factor"
name="size_factor"
value={sizeFactor}
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
setSizeFactor(e.target.value as string);
}}
options={factorForDropdown()}
/>
</div>
</div>
<Grid item xs={12}>
<InputBoxWrapper
id="storage_class"
name="storage_class"
type="string"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setStorageClass(e.target.value);
}}
label="Volumes per Server"
value={storageClass}
/>
</Grid>
<Grid item xs={12} className={classes.bottomContainer}>
<div className={classes.factorElements}>
<div>
<div className={classes.sizeNumber}>
{getTotalSize(instanceCapacity.toString(10), sizeFactor)}
{niceBytes(instanceCapacity.toString(10))}
</div>
<div className={classes.sizeDescription}>Instance Capacity</div>
</div>
<div>
<div className={classes.sizeNumber}>
{getTotalSize(totalCapacity.toString(10), sizeFactor)}
{niceBytes(totalCapacity.toString(10))}
</div>
<div className={classes.sizeDescription}>Total Capacity</div>
</div>

View File

@@ -30,6 +30,9 @@ import { niceBytes } from "../../../../common/utils";
import AddZoneModal from "./AddZoneModal";
import AddBucket from "../../Buckets/ListBuckets/AddBucket";
import ReplicationSetup from "./ReplicationSetup";
import api from "../../../../common/api";
import { BucketInfo } from "../../Buckets/types";
import { ITenant, IZone } from "../ListTenants/types";
interface ITenantDetailsProps {
classes: any;
@@ -106,12 +109,16 @@ const TenantDetails = ({ classes, match }: ITenantDetailsProps) => {
const [capacity, setCapacity] = useState<number>(0);
const [externalIDP, setExternalIDP] = useState<boolean>(false);
const [externalKMS, setExternalKMS] = useState<boolean>(false);
const [zones, setZones] = useState<number>(0);
const [zoneCount, setZoneCount] = useState<number>(0);
const [zones, setZones] = useState<IZone[]>([]);
const [instances, setInstances] = useState<number>(0);
const [drives, setDrives] = useState<number>(0);
const [volumes, setVolumes] = useState<number>(0);
const [addZoneOpen, setAddZone] = useState<boolean>(false);
const [addBucketOpen, setAddBucketOpen] = useState<boolean>(false);
const [addReplicationOpen, setAddReplicationOpen] = useState<boolean>(false);
const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<string>("");
const [tenant, setTenant] = useState<ITenant | null>(null);
const onCloseZoneAndRefresh = (reload: boolean) => {
setAddZone(false);
@@ -133,12 +140,50 @@ const TenantDetails = ({ classes, match }: ITenantDetailsProps) => {
}
};
const loadInfo = () => {
const tenantName = match.params["tenantName"];
setLoading(true);
api
.invoke("GET", `/api/v1/mkube/tenants/${tenantName}`)
.then((res: ITenant) => {
const total = res.volume_count * res.volume_size;
setCapacity(total);
setZoneCount(res.zone_count);
setVolumes(res.volume_count);
setInstances(res.instance_count);
const resZones = !res.zones ? [] : res.zones;
for (let zone of resZones) {
zone.volumes = res.volumes_per_server;
const cap = res.volumes_per_server * res.volume_size * zone.servers;
zone.capacity = niceBytes(cap + "");
}
setZones(resZones);
setTenant(res);
setError("");
setLoading(false);
})
.catch((err) => {
setError(err);
setLoading(false);
});
};
useEffect(() => {
loadInfo();
}, []);
return (
<React.Fragment>
{addZoneOpen && (
{addZoneOpen && tenant !== null && (
<AddZoneModal
open={addZoneOpen}
onCloseZoneAndReload={onCloseZoneAndRefresh}
volumeSize={tenant.volume_size}
volumesPerInstance={tenant.volumes_per_server}
/>
)}
{addBucketOpen && (
@@ -156,7 +201,7 @@ const TenantDetails = ({ classes, match }: ITenantDetailsProps) => {
<Grid container>
<Grid item xs={12}>
<Typography variant="h6">
Tenant > {match.params["clusterName"]}
Tenant > {match.params["tenantName"]}
</Typography>
</Grid>
<Grid item xs={12}>
@@ -168,7 +213,7 @@ const TenantDetails = ({ classes, match }: ITenantDetailsProps) => {
<div>Capacity:</div>
<div>{niceBytes(capacity.toString(10))}</div>
<div>Zones:</div>
<div>{zones}</div>
<div>{zoneCount}</div>
<div>External IDP:</div>
<div>
{externalIDP ? "Yes" : "No"}&nbsp;&nbsp;
@@ -184,19 +229,9 @@ const TenantDetails = ({ classes, match }: ITenantDetailsProps) => {
<div>Instances:</div>
<div>{instances}</div>
<div>External KMS:</div>
<div>
{externalKMS ? "Yes" : "No"}&nbsp;&nbsp;
<Button
variant="contained"
color="primary"
size="small"
onClick={() => {}}
>
Edit
</Button>
</div>
<div>Drives:</div>
<div>{drives}</div>
<div>{externalKMS ? "Yes" : "No"}&nbsp;&nbsp;</div>
<div>Volumes:</div>
<div>{volumes}</div>
</div>
</Paper>
<div className={classes.masterActions}>
@@ -210,16 +245,6 @@ const TenantDetails = ({ classes, match }: ITenantDetailsProps) => {
Warp
</Button>
</div>
<div>
<Button
variant="contained"
color="primary"
fullWidth
onClick={() => {}}
>
See as deployment
</Button>
</div>
</div>
</Grid>
<Grid item xs={12}>
@@ -303,17 +328,13 @@ const TenantDetails = ({ classes, match }: ITenantDetailsProps) => {
},
]}
columns={[
{
label: "Status",
elementKey: "status",
},
{ label: "Name", elementKey: "name" },
{ label: "Capacity", elementKey: "capacity" },
{ label: "# of Instances", elementKey: "instances" },
{ label: "# of Drives", elementKey: "drives" },
{ label: "# of Instances", elementKey: "servers" },
{ label: "# of Drives", elementKey: "volumes" },
]}
isLoading={false}
records={[]}
records={zones}
entityName="Zones"
idField="name"
paginatorConfig={{