Connect List,Add Tenants (#148)
This commit is contained in:
@@ -35,8 +35,8 @@ var (
|
||||
buckets = "/buckets"
|
||||
bucketsDetail = "/buckets/:bucketName"
|
||||
serviceAccounts = "/service-accounts"
|
||||
clusters = "/clusters"
|
||||
clustersDetail = "/clusters/:clusterName"
|
||||
tenants = "/tenants"
|
||||
tenantsDetail = "/tenants/:tenantName"
|
||||
heal = "/heal"
|
||||
)
|
||||
|
||||
@@ -192,8 +192,8 @@ var serviceAccountsActionSet = ConfigurationActionSet{
|
||||
actions: iampolicy.NewActionSet(),
|
||||
}
|
||||
|
||||
// clustersActionSet temporally no actions needed for clusters sections to work
|
||||
var clustersActionSet = ConfigurationActionSet{
|
||||
// tenantsActionSet temporally no actions needed for tenants sections to work
|
||||
var tenantsActionSet = ConfigurationActionSet{
|
||||
actionTypes: iampolicy.NewActionSet(),
|
||||
actions: iampolicy.NewActionSet(),
|
||||
}
|
||||
@@ -228,8 +228,8 @@ var endpointRules = map[string]ConfigurationActionSet{
|
||||
|
||||
// operatorRules contains the mapping between endpoints and ActionSets for operator only mode
|
||||
var operatorRules = map[string]ConfigurationActionSet{
|
||||
clusters: clustersActionSet,
|
||||
clustersDetail: clustersActionSet,
|
||||
tenants: tenantsActionSet,
|
||||
tenantsDetail: tenantsActionSet,
|
||||
}
|
||||
|
||||
// operatorOnly ENV variable
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -25,6 +25,7 @@ export const units = [
|
||||
"ZiB",
|
||||
"YiB",
|
||||
];
|
||||
export const k8sUnits = ["Ki", "Mi", "Gi", "Ti", "Pi", "Ei"];
|
||||
export const niceBytes = (x: string) => {
|
||||
let l = 0,
|
||||
n = parseInt(x, 10) || 0;
|
||||
@@ -65,6 +66,13 @@ export const factorForDropdown = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// units to be used in a dropdown
|
||||
export const k8sfactorForDropdown = () => {
|
||||
return k8sUnits.map((unit) => {
|
||||
return { label: unit, value: unit };
|
||||
});
|
||||
};
|
||||
|
||||
//getBytes, converts from a value and a unit from units array to bytes
|
||||
export const getBytes = (value: string, unit: string) => {
|
||||
const vl: number = parseFloat(value);
|
||||
|
||||
@@ -64,10 +64,10 @@ import Trace from "./Trace/Trace";
|
||||
import Logs from "./Logs/Logs";
|
||||
import Heal from "./Heal/Heal";
|
||||
import Watch from "./Watch/Watch";
|
||||
import ListClusters from "./Clusters/ListClusters/ListClusters";
|
||||
import ListTenants from "./Tenants/ListTenants/ListTenants";
|
||||
import { ISessionResponse } from "./types";
|
||||
import { saveSessionResponse } from "./actions";
|
||||
import ClusterDetails from "./Clusters/ClusterDetails/ClusterDetails";
|
||||
import TenantDetails from "./Tenants/TenantDetails/TenantDetails";
|
||||
|
||||
function Copyright() {
|
||||
return (
|
||||
@@ -301,11 +301,11 @@ const Console = ({
|
||||
path: "/webhook/audit",
|
||||
},
|
||||
{
|
||||
component: ListClusters,
|
||||
path: "/clusters",
|
||||
component: ListTenants,
|
||||
path: "/tenants",
|
||||
},
|
||||
{
|
||||
component: ClusterDetails,
|
||||
component: TenantDetails,
|
||||
path: "/clusters/:clusterName",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -246,8 +246,8 @@ class Menu extends React.Component<MenuProps> {
|
||||
group: "Operator",
|
||||
type: "item",
|
||||
component: NavLink,
|
||||
to: "/clusters",
|
||||
name: "Clusters",
|
||||
to: "/tenants",
|
||||
name: "Tenants",
|
||||
icon: <StorageIcon />,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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, { useState, useEffect } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import ModalWrapper from "../../Common/ModalWrapper/ModalWrapper";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
@@ -26,11 +26,11 @@ import { modalBasic } from "../../Common/FormComponents/common/styleLibrary";
|
||||
import { IVolumeConfiguration, IZone } from "./types";
|
||||
import CheckboxWrapper from "../../Common/FormComponents/CheckboxWrapper/CheckboxWrapper";
|
||||
import SelectWrapper from "../../Common/FormComponents/SelectWrapper/SelectWrapper";
|
||||
import { factorForDropdown, units } from "../../../../common/utils";
|
||||
import { k8sfactorForDropdown } from "../../../../common/utils";
|
||||
import ZonesMultiSelector from "./ZonesMultiSelector";
|
||||
import { storageClasses } from "../utils";
|
||||
|
||||
interface IAddClusterProps {
|
||||
interface IAddTenantProps {
|
||||
open: boolean;
|
||||
closeModalAndRefresh: (reloadData: boolean) => any;
|
||||
classes: any;
|
||||
@@ -55,14 +55,14 @@ const styles = (theme: Theme) =>
|
||||
...modalBasic,
|
||||
});
|
||||
|
||||
const AddCluster = ({
|
||||
const AddTenant = ({
|
||||
open,
|
||||
closeModalAndRefresh,
|
||||
classes,
|
||||
}: IAddClusterProps) => {
|
||||
}: IAddTenantProps) => {
|
||||
const [addSending, setAddSending] = useState<boolean>(false);
|
||||
const [addError, setAddError] = useState<string>("");
|
||||
const [clusterName, setClusterName] = useState<string>("");
|
||||
const [tenantName, setTenantName] = useState<string>("");
|
||||
const [imageName, setImageName] = useState<string>("");
|
||||
const [serviceName, setServiceName] = useState<string>("");
|
||||
const [zones, setZones] = useState<IZone[]>([]);
|
||||
@@ -75,13 +75,30 @@ const AddCluster = ({
|
||||
const [secretKey, setSecretKey] = useState<string>("");
|
||||
const [enableMCS, setEnableMCS] = useState<boolean>(false);
|
||||
const [enableSSL, setEnableSSL] = useState<boolean>(false);
|
||||
const [sizeFactor, setSizeFactor] = useState<string>("GiB");
|
||||
const [sizeFactor, setSizeFactor] = useState<string>("Gi");
|
||||
|
||||
useEffect(() => {
|
||||
if (addSending) {
|
||||
let cleanZones: IZone[] = [];
|
||||
for (let zone of zones) {
|
||||
if (zone.name !== "") {
|
||||
cleanZones.push(zone);
|
||||
}
|
||||
}
|
||||
|
||||
api
|
||||
.invoke("POST", `/api/v1/clusters`, {
|
||||
name: clusterName,
|
||||
.invoke("POST", `/api/v1/tenants`, {
|
||||
name: tenantName,
|
||||
service_name: tenantName,
|
||||
enable_ssl: enableSSL,
|
||||
enable_mcs: enableMCS,
|
||||
access_key: accessKey,
|
||||
secret_key: secretKey,
|
||||
volumes_per_server: volumesPerServer,
|
||||
volume_configuration: {
|
||||
size: `${volumeConfiguration.size}${sizeFactor}`,
|
||||
},
|
||||
zones: cleanZones,
|
||||
})
|
||||
.then(() => {
|
||||
setAddSending(false);
|
||||
@@ -107,7 +124,7 @@ const AddCluster = ({
|
||||
|
||||
return (
|
||||
<ModalWrapper
|
||||
title="Create Cluster"
|
||||
title="Create Tenant"
|
||||
modalOpen={open}
|
||||
onClose={() => {
|
||||
setAddError("");
|
||||
@@ -139,13 +156,13 @@ const AddCluster = ({
|
||||
)}
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="cluster-name"
|
||||
name="cluster-name"
|
||||
id="tenant-name"
|
||||
name="tenant-name"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setClusterName(e.target.value);
|
||||
setTenantName(e.target.value);
|
||||
}}
|
||||
label="Cluster Name"
|
||||
value={clusterName}
|
||||
label="Tenant Name"
|
||||
value={tenantName}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
@@ -155,7 +172,7 @@ const AddCluster = ({
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setImageName(e.target.value);
|
||||
}}
|
||||
label="Image"
|
||||
label="MinIO Image"
|
||||
value={imageName}
|
||||
/>
|
||||
</Grid>
|
||||
@@ -175,7 +192,9 @@ const AddCluster = ({
|
||||
<ZonesMultiSelector
|
||||
label="Zones"
|
||||
name="zones_selector"
|
||||
onChange={() => {}}
|
||||
onChange={(elements: IZone[]) => {
|
||||
setZones(elements);
|
||||
}}
|
||||
elements={zones}
|
||||
/>
|
||||
</div>
|
||||
@@ -220,7 +239,7 @@ const AddCluster = ({
|
||||
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
|
||||
setSizeFactor(e.target.value as string);
|
||||
}}
|
||||
options={factorForDropdown()}
|
||||
options={k8sfactorForDropdown()}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -322,4 +341,4 @@ const AddCluster = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(AddCluster);
|
||||
export default withStyles(styles)(AddTenant);
|
||||
@@ -28,10 +28,10 @@ import Typography from "@material-ui/core/Typography";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import api from "../../../../common/api";
|
||||
|
||||
interface IDeleteCluster {
|
||||
interface IDeleteTenant {
|
||||
classes: any;
|
||||
deleteOpen: boolean;
|
||||
selectedCluster: string;
|
||||
selectedTenant: string;
|
||||
closeDeleteModalAndRefresh: (refreshList: boolean) => any;
|
||||
}
|
||||
|
||||
@@ -42,27 +42,29 @@ const styles = (theme: Theme) =>
|
||||
},
|
||||
});
|
||||
|
||||
const DeleteCluster = ({
|
||||
const DeleteTenant = ({
|
||||
classes,
|
||||
deleteOpen,
|
||||
selectedCluster,
|
||||
selectedTenant,
|
||||
closeDeleteModalAndRefresh,
|
||||
}: IDeleteCluster) => {
|
||||
}: IDeleteTenant) => {
|
||||
const [deleteLoading, setDeleteLoading] = useState(false);
|
||||
const [deleteError, setDeleteError] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
api
|
||||
.invoke("DELETE", `/api/v1/clusters/${selectedCluster}`)
|
||||
.then(() => {
|
||||
setDeleteLoading(false);
|
||||
setDeleteError("");
|
||||
closeDeleteModalAndRefresh(true);
|
||||
})
|
||||
.catch((err) => {
|
||||
setDeleteLoading(false);
|
||||
setDeleteError(err);
|
||||
});
|
||||
if (deleteLoading) {
|
||||
api
|
||||
.invoke("DELETE", `/api/v1/clusters/${selectedTenant}`)
|
||||
.then(() => {
|
||||
setDeleteLoading(false);
|
||||
setDeleteError("");
|
||||
closeDeleteModalAndRefresh(true);
|
||||
})
|
||||
.catch((err) => {
|
||||
setDeleteLoading(false);
|
||||
setDeleteError(err);
|
||||
});
|
||||
}
|
||||
}, [deleteLoading]);
|
||||
|
||||
const removeRecord = () => {
|
||||
@@ -79,11 +81,11 @@ const DeleteCluster = ({
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">Delete Cluster</DialogTitle>
|
||||
<DialogTitle id="alert-dialog-title">Delete Tenant</DialogTitle>
|
||||
<DialogContent>
|
||||
{deleteLoading && <LinearProgress />}
|
||||
<DialogContentText id="alert-dialog-description">
|
||||
Are you sure you want to delete cluster <b>{selectedCluster}</b>?
|
||||
Are you sure you want to delete tenant <b>{selectedTenant}</b>?
|
||||
{deleteError !== "" && (
|
||||
<React.Fragment>
|
||||
<br />
|
||||
@@ -117,4 +119,4 @@ const DeleteCluster = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(DeleteCluster);
|
||||
export default withStyles(styles)(DeleteTenant);
|
||||
@@ -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, { useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
@@ -24,12 +24,14 @@ import { Button } from "@material-ui/core";
|
||||
import { CreateIcon } from "../../../../icons";
|
||||
import TableWrapper from "../../Common/TableWrapper/TableWrapper";
|
||||
import { MinTablePaginationActions } from "../../../../common/MinTablePaginationActions";
|
||||
import AddCluster from "./AddCluster";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import DeleteCluster from "./DeleteCluster";
|
||||
import { Link } from "react-router-dom";
|
||||
import api from "../../../../common/api";
|
||||
import { ITenant, ITenantsResponse } from "./types";
|
||||
import { niceBytes } from "../../../../common/utils";
|
||||
import DeleteTenant from "./DeleteTenant";
|
||||
import AddTenant from "./AddTenant";
|
||||
|
||||
interface IClustersList {
|
||||
interface ITenantsList {
|
||||
classes: any;
|
||||
}
|
||||
|
||||
@@ -77,19 +79,20 @@ const styles = (theme: Theme) =>
|
||||
},
|
||||
});
|
||||
|
||||
const ListClusters = ({ classes }: IClustersList) => {
|
||||
const [createClusterOpen, setCreateClusterOpen] = useState<boolean>(false);
|
||||
const ListTenants = ({ classes }: ITenantsList) => {
|
||||
const [createTenantOpen, setCreateTenantOpen] = useState<boolean>(false);
|
||||
const [deleteOpen, setDeleteOpen] = useState<boolean>(false);
|
||||
const [selectedCluster, setSelectedCluster] = useState<any>(null);
|
||||
const [selectedTenant, setSelectedTenant] = useState<any>(null);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [filterClusters, setFilterClusters] = useState<string>("");
|
||||
const [filterTenants, setFilterTenants] = useState<string>("");
|
||||
const [records, setRecords] = useState<any[]>([]);
|
||||
const [offset, setOffset] = useState<number>(0);
|
||||
const [rowsPerPage, setRowsPerPage] = useState<number>(0);
|
||||
const [rowsPerPage, setRowsPerPage] = useState<number>(10);
|
||||
const [page, setPage] = useState<number>(0);
|
||||
const [error, setError] = useState<string>("");
|
||||
|
||||
const closeAddModalAndRefresh = (reloadData: boolean) => {
|
||||
setCreateClusterOpen(false);
|
||||
setCreateTenantOpen(false);
|
||||
|
||||
if (reloadData) {
|
||||
setIsLoading(true);
|
||||
@@ -104,8 +107,8 @@ const ListClusters = ({ classes }: IClustersList) => {
|
||||
}
|
||||
};
|
||||
|
||||
const confirmDeleteCluster = (cluster: string) => {
|
||||
setSelectedCluster(cluster);
|
||||
const confirmDeleteTenant = (tenant: string) => {
|
||||
setSelectedTenant(tenant);
|
||||
setDeleteOpen(true);
|
||||
};
|
||||
|
||||
@@ -122,17 +125,17 @@ const ListClusters = ({ classes }: IClustersList) => {
|
||||
};
|
||||
|
||||
const tableActions = [
|
||||
{ type: "view", to: `/clusters`, sendOnlyId: true },
|
||||
{ type: "delete", onClick: confirmDeleteCluster, sendOnlyId: true },
|
||||
{ type: "view", to: `/tenants`, sendOnlyId: true },
|
||||
{ type: "delete", onClick: confirmDeleteTenant, sendOnlyId: true },
|
||||
];
|
||||
|
||||
const filteredRecords = records
|
||||
.slice(offset, offset + rowsPerPage)
|
||||
.filter((b: any) => {
|
||||
if (filterClusters === "") {
|
||||
if (filterTenants === "") {
|
||||
return true;
|
||||
} else {
|
||||
if (b.name.indexOf(filterClusters) >= 0) {
|
||||
if (b.name.indexOf(filterTenants) >= 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -140,36 +143,84 @@ const ListClusters = ({ classes }: IClustersList) => {
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (isLoading) {
|
||||
const fetchRecords = () => {
|
||||
const offset = page * rowsPerPage;
|
||||
api
|
||||
.invoke(
|
||||
"GET",
|
||||
`/api/v1/tenants?offset=${offset}&limit=${rowsPerPage}`
|
||||
)
|
||||
.then((res: ITenantsResponse) => {
|
||||
if (res === null) {
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
let resTenants: ITenant[] = [];
|
||||
if (res.tenants !== null) {
|
||||
resTenants = res.tenants;
|
||||
}
|
||||
|
||||
for (let i = 0; i < resTenants.length; i++) {
|
||||
const total =
|
||||
resTenants[i].volume_count * resTenants[i].volume_size;
|
||||
resTenants[i].capacity = niceBytes(total + "");
|
||||
}
|
||||
|
||||
setRecords(resTenants);
|
||||
setError("");
|
||||
setIsLoading(false);
|
||||
|
||||
// if we get 0 results, and page > 0 , go down 1 page
|
||||
if ((!res.tenants || res.tenants.length === 0) && page > 0) {
|
||||
const newPage = page - 1;
|
||||
setPage(newPage);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
setError(err);
|
||||
setIsLoading(false);
|
||||
});
|
||||
};
|
||||
fetchRecords();
|
||||
}
|
||||
}, [isLoading, page, rowsPerPage]);
|
||||
|
||||
useEffect(() => {
|
||||
setIsLoading(true);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{createClusterOpen && (
|
||||
<AddCluster
|
||||
open={createClusterOpen}
|
||||
{createTenantOpen && (
|
||||
<AddTenant
|
||||
open={createTenantOpen}
|
||||
closeModalAndRefresh={closeAddModalAndRefresh}
|
||||
/>
|
||||
)}
|
||||
{deleteOpen && (
|
||||
<DeleteCluster
|
||||
<DeleteTenant
|
||||
deleteOpen={deleteOpen}
|
||||
selectedCluster={selectedCluster}
|
||||
selectedTenant={selectedTenant}
|
||||
closeDeleteModalAndRefresh={closeDeleteModalAndRefresh}
|
||||
/>
|
||||
)}
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="h6">Clusters</Typography>
|
||||
<Typography variant="h6">Tenants</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.actionsTray}>
|
||||
<TextField
|
||||
placeholder="Search Clusters"
|
||||
placeholder="Search Tenants"
|
||||
className={classes.searchField}
|
||||
id="search-resource"
|
||||
label=""
|
||||
onChange={(val) => {
|
||||
setFilterClusters(val.target.value);
|
||||
setFilterTenants(val.target.value);
|
||||
}}
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
@@ -185,10 +236,10 @@ const ListClusters = ({ classes }: IClustersList) => {
|
||||
color="primary"
|
||||
startIcon={<CreateIcon />}
|
||||
onClick={() => {
|
||||
setCreateClusterOpen(true);
|
||||
setCreateTenantOpen(true);
|
||||
}}
|
||||
>
|
||||
Create Cluster
|
||||
Create Tenant
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
@@ -200,11 +251,12 @@ const ListClusters = ({ classes }: IClustersList) => {
|
||||
columns={[
|
||||
{ label: "Name", elementKey: "name" },
|
||||
{ label: "Capacity", elementKey: "capacity" },
|
||||
{ label: "# of Zones", elementKey: "zones_counter" },
|
||||
{ label: "# of Zones", elementKey: "zone_count" },
|
||||
{ label: "State", elementKey: "currentState" },
|
||||
]}
|
||||
isLoading={isLoading}
|
||||
records={filteredRecords}
|
||||
entityName="Clusters"
|
||||
entityName="Tenants"
|
||||
idField="name"
|
||||
paginatorConfig={{
|
||||
rowsPerPageOptions: [5, 10, 25],
|
||||
@@ -227,4 +279,4 @@ const ListClusters = ({ classes }: IClustersList) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(ListClusters);
|
||||
export default withStyles(styles)(ListTenants);
|
||||
@@ -23,3 +23,19 @@ export interface IVolumeConfiguration {
|
||||
size: string;
|
||||
storage_class: string;
|
||||
}
|
||||
|
||||
export interface ITenant {
|
||||
name: string;
|
||||
zone_count: number;
|
||||
currentState: string;
|
||||
instance_count: 4;
|
||||
creation_date: Date;
|
||||
volume_size: number;
|
||||
volume_count: number;
|
||||
// computed
|
||||
capacity: string;
|
||||
}
|
||||
|
||||
export interface ITenantsResponse {
|
||||
tenants: ITenant[];
|
||||
}
|
||||
@@ -31,7 +31,7 @@ import AddZoneModal from "./AddZoneModal";
|
||||
import AddBucket from "../../Buckets/ListBuckets/AddBucket";
|
||||
import ReplicationSetup from "./ReplicationSetup";
|
||||
|
||||
interface IClusterDetailsProps {
|
||||
interface ITenantDetailsProps {
|
||||
classes: any;
|
||||
match: any;
|
||||
}
|
||||
@@ -101,7 +101,7 @@ const mainPagination = {
|
||||
ActionsComponent: MinTablePaginationActions,
|
||||
};
|
||||
|
||||
const ClusterDetails = ({ classes, match }: IClusterDetailsProps) => {
|
||||
const TenantDetails = ({ classes, match }: ITenantDetailsProps) => {
|
||||
const [selectedTab, setSelectedTab] = useState<number>(0);
|
||||
const [capacity, setCapacity] = useState<number>(0);
|
||||
const [externalIDP, setExternalIDP] = useState<boolean>(false);
|
||||
@@ -156,7 +156,7 @@ const ClusterDetails = ({ classes, match }: IClusterDetailsProps) => {
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="h6">
|
||||
Cluster > {match.params["clusterName"]}
|
||||
Tenant > {match.params["clusterName"]}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
@@ -233,7 +233,7 @@ const ClusterDetails = ({ classes, match }: IClusterDetailsProps) => {
|
||||
onChange={(_, newValue: number) => {
|
||||
setSelectedTab(newValue);
|
||||
}}
|
||||
aria-label="cluster-tabs"
|
||||
aria-label="tenant-tabs"
|
||||
>
|
||||
<Tab label="Zones" />
|
||||
<Tab label="Buckets" />
|
||||
@@ -425,4 +425,4 @@ const ClusterDetails = ({ classes, match }: IClusterDetailsProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(ClusterDetails);
|
||||
export default withStyles(styles)(TenantDetails);
|
||||
@@ -164,7 +164,7 @@ func FileServerMiddleware(next http.Handler) http.Handler {
|
||||
switch {
|
||||
case strings.HasPrefix(r.URL.Path, "/ws"):
|
||||
serveWS(w, r)
|
||||
case strings.HasPrefix(r.URL.Path, "/api/v1/clusters"):
|
||||
case strings.HasPrefix(r.URL.Path, "/api/v1/tenants"):
|
||||
client := &http.Client{}
|
||||
serverMkube(client, w, r)
|
||||
case strings.HasPrefix(r.URL.Path, "/api"):
|
||||
|
||||
Reference in New Issue
Block a user