MDS Console improvements (#3102)

- Removed mui badge component
- Updated icons screen
- Migrated Wizard Component
- Improved modals styles
- Updated KMS Status page

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
Alex
2023-10-24 14:09:22 -06:00
committed by GitHub
parent ec77a03d7c
commit 701039454a
11 changed files with 195 additions and 699 deletions

View File

@@ -27,10 +27,10 @@ import {
Switch,
Tooltip,
WarnIcon,
Wizard,
} from "mds";
import get from "lodash/get";
import ModalWrapper from "../../Common/ModalWrapper/ModalWrapper";
import GenericWizard from "../../Common/GenericWizard/GenericWizard";
import QueryMultiSelector from "../../Common/FormComponents/QueryMultiSelector/QueryMultiSelector";
import { ITiersDropDown } from "../types";
import { setModalErrorSnackMessage } from "../../../../systemSlice";
@@ -196,20 +196,23 @@ const AddBulkReplicationModal = ({
}}
title="Set Lifecycle to multiple buckets"
>
<GenericWizard
<Wizard
loadingStep={addLoading || loadingTiers}
wizardSteps={[
{
label: "Lifecycle Configuration",
componentRender: (
<Fragment>
<Grid item xs={12}>
<ReadBox label="Local Buckets to replicate">
{buckets.join(", ")}
</ReadBox>
</Grid>
<h4>Remote Endpoint Configuration</h4>
<FormLayout withBorders={false} containerPadding={false}>
<Grid item xs={12}>
<ReadBox
label="Local Buckets to replicate"
sx={{ maxWidth: "440px", width: "100%" }}
>
{buckets.join(", ")}
</ReadBox>
</Grid>
<h4>Remote Endpoint Configuration</h4>
<fieldset className={"inputItem"}>
<legend>Lifecycle Configuration</legend>
<RadioGroup

View File

@@ -19,17 +19,16 @@ import {
Box,
CheckCircleIcon,
FormLayout,
Grid,
InputBox,
ReadBox,
Select,
Switch,
Tooltip,
WarnIcon,
Wizard,
} from "mds";
import get from "lodash/get";
import ModalWrapper from "../../Common/ModalWrapper/ModalWrapper";
import GenericWizard from "../../Common/GenericWizard/GenericWizard";
import { getBytes, k8sScalarUnitsExcluding } from "../../../../common/utils";
import InputUnitMenu from "../../Common/FormComponents/InputUnitMenu/InputUnitMenu";
import { setModalErrorSnackMessage } from "../../../../systemSlice";
@@ -302,28 +301,26 @@ const AddBulkReplicationModal = ({
}}
title="Set Multiple Bucket Replication"
>
<GenericWizard
<Wizard
loadingStep={addLoading || externalLoading}
wizardSteps={[
{
label: "Remote Configuration",
componentRender: (
<Fragment>
<Grid item xs={12}>
<FormLayout containerPadding={false} withBorders={false}>
<ReadBox
sx={{ width: "100%" }}
label="Local Buckets to replicate"
sx={{ maxWidth: "440px", width: "100%" }}
>
{bucketsToAlter.join(", ")}
</ReadBox>
</Grid>
<h4>Remote Endpoint Configuration</h4>
<span style={{ fontSize: 14 }}>
Please avoid the use of root credentials for this feature
</span>
<br />
<br />
<FormLayout containerPadding={false} withBorders={false}>
<h4>Remote Endpoint Configuration</h4>
<span style={{ fontSize: 14 }}>
Please avoid the use of root credentials for this feature
<br />
<br />
</span>
<InputBox
id="accessKey"
name="accessKey"

View File

@@ -39,9 +39,9 @@ import {
RefreshIcon,
ScreenTitle,
ShareIcon,
Badge,
} from "mds";
import { api } from "api";
import { Badge } from "@mui/material"; // TODO: Remove this
import { errorToHandler } from "api/errors";
import { BucketQuota } from "api/consoleApi";
import { useSelector } from "react-redux";
@@ -1029,14 +1029,7 @@ const ListObjects = () => {
id={"rewind-objects-list"}
label={"Rewind"}
icon={
<Badge
badgeContent=" "
color="secondary"
variant="dot"
invisible={!rewindEnabled}
className={""}
sx={{ height: 16 }}
>
<Badge color="alert" dotOnly invisible={!rewindEnabled}>
<HistoryIcon
style={{
minWidth: 16,

View File

@@ -216,6 +216,7 @@ const QueryMultiSelector = ({
fontWeight: 600,
},
}}
className={"inputItem"}
>
<InputLabel>
{label}

View File

@@ -104,33 +104,6 @@ export const tooltipHelper = {
},
};
export const containerForHeader = {
container: {
position: "relative" as const,
padding: "20px 35px 0",
"& h6": {
color: "#777777",
fontSize: 30,
},
"& p": {
"& span:not(*[class*='smallUnit'])": {
fontSize: 16,
},
},
},
sectionTitle: {
margin: 0,
marginBottom: ".8rem",
fontSize: "1.3rem",
},
boxy: {
border: "#E5E5E5 1px solid",
borderRadius: 2,
padding: 40,
backgroundColor: "#fff",
},
};
export const actionsTray = {
label: {
color: "#07193E",

View File

@@ -1,256 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { Fragment, useState } from "react";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import { IWizardMain } from "./types";
import WizardPage from "./WizardPage";
import { Grid, List } from "@mui/material";
import ListItem from "@mui/material/ListItem";
import ListItemText from "@mui/material/ListItemText";
const styles = (theme: Theme) =>
createStyles({
wizFromContainer: {},
wizFromModal: {
position: "relative",
},
modalWizardSteps: {
padding: 5,
borderBottom: "#eaeaea 1px solid",
"& ul": {
padding: 0,
marginTop: 0,
display: "flex",
justifyContent: "space-evenly",
"& li": {
listStyle: "lower-roman",
"&::marker": {
paddingLeft: 15,
},
},
},
},
buttonList: {
backgroundColor: "transparent",
border: "none",
cursor: "pointer",
"&:not(:disabled):hover": {
textDecoration: "underline",
},
"&:selected, &:active, &:focus, &:focus:active": {
border: "none",
outline: 0,
boxShadow: "none",
},
},
paddedContentGrid: {
marginTop: 8,
padding: "0 10px",
minHeight: 400,
},
stepsLabel: {
fontSize: 20,
color: "#393939",
fontWeight: 600,
margin: "15px 12px",
"&.stepsModalTitle": {
textAlign: "center",
width: "100%",
marginTop: 0,
marginBottom: 10,
},
},
stepsMasterContainer: {
position: "sticky",
top: 0,
backgroundColor: "#FFFFFF",
width: "100%",
maxHeight: 90,
},
verticalSteps: {
borderRight: "1px solid #E5E5E5",
background: "#F8F8F8",
},
stepsContainer: {
paddingTop: 0,
"& .MuiButtonBase-root.Mui-selected": {
background: "#E5E5E5",
},
},
stepItem: {
minHeight: 60,
borderBottom: "1px solid #E5E5E5",
"&:hover": {
background: "rgba(247,247,247,0.7)",
},
},
});
const GenericWizard = ({
classes,
wizardSteps,
loadingStep,
forModal,
}: IWizardMain) => {
const [currentStep, setCurrentStep] = useState<number>(0);
const pageChange = (toElement: string | number) => {
const lastPage = wizardSteps.length - 1;
if (toElement === "++") {
let nextPage = currentStep + 1;
if (nextPage > lastPage) {
nextPage = lastPage;
}
setCurrentStep(nextPage);
}
if (toElement === "--") {
let prevPage = currentStep - 1;
if (prevPage < 0) {
prevPage = 0;
}
setCurrentStep(prevPage);
}
if (typeof toElement === "number") {
let pg = toElement;
if (toElement < 0) {
pg = 0;
}
if (toElement > lastPage) {
pg = lastPage;
}
setCurrentStep(pg);
}
};
if (wizardSteps.length === 0) {
return null;
}
const stepsList = () => {
return (
<Fragment>
<List
component="nav"
dense={true}
classes={{
root: classes.stepsContainer,
}}
>
{wizardSteps.map((step, index) => {
return (
<ListItem
id={
"wizard-step-" + step.label.toLowerCase().replaceAll(" ", "-")
}
button
disableRipple
onClick={() => pageChange(index)}
key={`wizard-${index.toString()}`}
selected={currentStep === index}
classes={{
root: classes.stepItem,
}}
>
<ListItemText primary={step.label} />
</ListItem>
);
})}
</List>
</Fragment>
);
};
const stepsListModal = () => {
return (
<ul>
{wizardSteps.map((step, index) => {
return (
<li key={`wizard-${index.toString()}`}>
<button
onClick={() => pageChange(index)}
disabled={index > currentStep}
className={classes.buttonList}
>
{step.label}
</button>
</li>
);
})}
</ul>
);
};
return (
<Grid
container
className={forModal ? classes.wizFromModal : classes.wizFromContainer}
>
{forModal ? (
<Fragment>
<div className={classes.stepsMasterContainer}>
<div className={`${classes.stepsLabel} stepsModalTitle`}>Steps</div>
<div className={classes.modalWizardSteps}>{stepsListModal()}</div>
</div>
</Fragment>
) : (
<Fragment>
<Grid
item
xs={12}
sm={2}
md={2}
lg={2}
xl={2}
className={classes.verticalSteps}
>
{stepsList()}
</Grid>
</Fragment>
)}
<Grid
item
xs={12}
sm={forModal ? 12 : 10}
md={forModal ? 12 : 10}
lg={forModal ? 12 : 10}
xl={forModal ? 12 : 10}
className={forModal ? "" : classes.paddedContentGrid}
>
<WizardPage
page={wizardSteps[currentStep]}
pageChange={pageChange}
loadingStep={loadingStep}
forModal={forModal}
/>
</Grid>
</Grid>
);
};
export default withStyles(styles)(GenericWizard);

View File

@@ -1,129 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React from "react";
import { Theme } from "@mui/material/styles";
import { Button, ProgressBar } from "mds";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import { IWizardButton, IWizardPage } from "./types";
const styles = (theme: Theme) =>
createStyles({
wizardStepContainer: {
display: "flex",
flexDirection: "column",
flex: 1,
},
wizardComponent: {
overflowY: "auto",
marginBottom: 10,
height: "calc(100vh - 100px - 80px)",
minHeight: 400,
flex: 1,
width: "100%",
},
wizardModal: {
overflowY: "auto",
marginBottom: 10,
height: "calc(100vh - 515px)",
},
buttonsContainer: {
display: "flex",
flexDirection: "row",
justifyContent: "flex-start" as const,
padding: "10px 0",
borderTop: "#EAEAEA 1px solid",
"& button": {
marginLeft: 10,
},
"&.forModal": {
paddingBottom: 0,
},
},
buttonInnerContainer: {
width: "100%",
display: "flex",
justifyContent: "flex-end",
marginRight: 15,
},
});
const WizardPage = ({
classes,
page,
pageChange,
loadingStep,
forModal,
}: IWizardPage) => {
const buttonAction = (btn: IWizardButton) => {
switch (btn.type) {
case "next":
pageChange("++");
break;
case "back":
pageChange("--");
break;
case "to":
pageChange(btn.toPage || 0);
break;
case "custom":
default:
}
if (btn.action) {
btn.action(pageChange);
}
};
return (
<div className={classes.wizardStepContainer}>
<div className={forModal ? classes.wizardModal : classes.wizardComponent}>
{page.componentRender}
</div>
{loadingStep && (
<div>
<ProgressBar />
</div>
)}
<div
className={`${classes.buttonsContainer} ${forModal ? "forModal" : ""}`}
>
<div className={classes.buttonInnerContainer}>
{page.buttons.map((btn) => {
if (btn.componentRender) {
return btn.componentRender;
}
return (
<Button
id={"wizard-button-" + btn.label}
variant="regular"
onClick={() => {
buttonAction(btn);
}}
disabled={!btn.enabled}
key={`button-${page.label}-${btn.label}`}
label={btn.label}
/>
);
})}
</div>
</div>
</div>
);
};
export default withStyles(styles)(WizardPage);

View File

@@ -1,47 +0,0 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
export interface IWizardButton {
label?: string;
type?: string;
action?: (nextFunction: (to: string | number) => void) => void;
enabled?: boolean;
toPage?: number;
componentRender?: React.ReactNode;
}
export interface IWizardElement {
label: string;
componentRender: any;
buttons: IWizardButton[];
advancedOnly?: boolean;
loadingStep?: boolean;
}
export interface IWizardMain {
classes: any;
loadingStep?: boolean;
wizardSteps: IWizardElement[];
forModal?: boolean;
}
export interface IWizardPage {
classes: any;
page: IWizardElement;
pageChange: (to: string | number) => void;
loadingStep?: boolean;
forModal?: boolean;
}

View File

@@ -15,75 +15,56 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useState } from "react";
import { containerForHeader } from "./FormComponents/common/styleLibrary";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import clsx from "clsx";
import {
FormControl,
FormControlLabel,
FormLabel,
Grid,
Radio,
RadioGroup,
} from "@mui/material";
import * as cicons from "mds";
import * as micons from "mds";
import { Loader } from "mds";
import { Box, Grid, Loader, RadioGroup } from "mds";
interface IIconsScreenSimple {
classes: any;
}
const styles = (theme: Theme) =>
createStyles({
...containerForHeader,
root: {
fontSize: 12,
wordWrap: "break-word",
"& .min-loader": {
width: 45,
height: 45,
},
},
red: {
"& .min-icon": {
color: "red",
},
},
});
const IconsScreen = ({ classes }: IIconsScreenSimple) => {
const IconsScreen = () => {
const [color, setColor] = useState<string>("default");
return (
<div className={classes.container}>
<Box
sx={{
position: "relative" as const,
padding: "20px 35px 0",
"& h6": {
color: "#777777",
fontSize: 30,
},
"& p": {
"& span:not(*[class*='smallUnit'])": {
fontSize: 16,
},
},
}}
>
<Grid container>
<FormControl>
<FormLabel id="demo-radio-buttons-group-label">Color</FormLabel>
<RadioGroup
row
aria-labelledby="demo-radio-buttons-group-label"
defaultValue="default"
name="radio-buttons-group"
onChange={(c) => {
setColor(c.target.value);
}}
>
<FormControlLabel value="def" control={<Radio />} label="Default" />
<FormControlLabel value="red" control={<Radio />} label="Color" />
</RadioGroup>
</FormControl>
<RadioGroup
selectorOptions={[
{ value: "def", label: "Default" },
{ value: "red", label: "Color" },
]}
currentValue={color}
id={"color-selector"}
name={"color-selector"}
onChange={(c) => {
setColor(c.target.value);
}}
/>
</Grid>
<h1>Logos</h1>
<Grid
container
spacing={4}
textAlign={"center"}
className={clsx(classes.root, {
[classes.red]: color === "red",
})}
sx={{
fontSize: 12,
wordWrap: "break-word",
"& .min-loader": {
width: 45,
height: 45,
},
"& .min-icon": {
color: color === "red" ? "red" : "black",
},
}}
>
<Grid item xs={3}>
<cicons.ThemedLogo />
@@ -94,11 +75,17 @@ const IconsScreen = ({ classes }: IIconsScreenSimple) => {
<h1>Loaders</h1>
<Grid
container
spacing={4}
textAlign={"center"}
className={clsx(classes.root, {
[classes.red]: color === "red",
})}
sx={{
fontSize: 12,
wordWrap: "break-word",
"& .min-loader": {
width: 45,
height: 45,
},
"& .min-icon": {
color: color === "red" ? "red" : "black",
},
}}
>
<Grid item xs={3}>
<Loader />
@@ -109,11 +96,17 @@ const IconsScreen = ({ classes }: IIconsScreenSimple) => {
<h1>Icons</h1>
<Grid
container
spacing={4}
textAlign={"center"}
className={clsx(classes.root, {
[classes.red]: color === "red",
})}
sx={{
fontSize: 12,
wordWrap: "break-word",
"& .min-loader": {
width: 45,
height: 45,
},
"& .min-icon": {
color: color === "red" ? "red" : "black",
},
}}
>
<Grid item xs={3} sm={2} md={1}>
<cicons.AccountIcon />
@@ -1160,11 +1153,17 @@ const IconsScreen = ({ classes }: IIconsScreenSimple) => {
<h1>Menu Icons</h1>
<Grid
container
spacing={4}
textAlign={"center"}
className={clsx(classes.root, {
[classes.red]: color === "red",
})}
sx={{
fontSize: 12,
wordWrap: "break-word",
"& .min-loader": {
width: 45,
height: 45,
},
"& .min-icon": {
color: color === "red" ? "red" : "black",
},
}}
>
<Grid item xs={3} sm={2} md={1}>
<micons.AccessMenuIcon />
@@ -1298,8 +1297,8 @@ const IconsScreen = ({ classes }: IIconsScreenSimple) => {
UsersMenuIcon
</Grid>
</Grid>
</div>
</Box>
);
};
export default withStyles(styles)(IconsScreen);
export default IconsScreen;

View File

@@ -1,33 +0,0 @@
import React from "react";
import { Stack } from "@mui/material";
type LabelValuePairProps = {
label?: any;
value?: any;
orientation?: any;
stkProps?: any;
lblProps?: any;
valProps?: any;
};
const LabelValuePair = ({
label = null,
value = "-",
orientation = "column",
stkProps = {},
lblProps = {},
valProps = {},
}: LabelValuePairProps) => {
return (
<Stack direction={{ xs: "column", sm: orientation }} {...stkProps}>
<label style={{ marginRight: 5, fontWeight: 600 }} {...lblProps}>
{label}
</label>
<label style={{ marginRight: 5, fontWeight: 500 }} {...valProps}>
{value}
</label>
</Stack>
);
};
export default LabelValuePair;

View File

@@ -15,25 +15,17 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { Fragment, useEffect, useState } from "react";
import { Box, Grid } from "@mui/material";
import { SectionTitle } from "mds";
import api from "../../../common/api";
import { ErrorResponseHandler } from "../../../common/types";
import { hasPermission } from "../../../common/SecureComponent";
import {
CONSOLE_UI_RESOURCE,
IAM_SCOPES,
} from "../../../common/SecureComponent/permissions";
import { setErrorSnackMessage, setHelpName } from "../../../systemSlice";
import { useAppDispatch } from "../../../store";
import Tabs from "@mui/material/Tabs";
import Tab from "@mui/material/Tab";
import { TabPanel } from "../../shared/tabs";
import LabelValuePair from "../Common/UsageBarWrapper/LabelValuePair";
import LabelWithIcon from "../Buckets/BucketDetails/SummaryItems/LabelWithIcon";
Box,
breakPoints,
DisabledIcon,
EnabledIcon,
Grid,
PageLayout,
SectionTitle,
Tabs,
ValuePair,
} from "mds";
import {
Bar,
BarChart,
@@ -45,14 +37,22 @@ import {
XAxis,
YAxis,
} from "recharts";
import { DisabledIcon, EnabledIcon, PageLayout } from "mds";
import api from "../../../common/api";
import { ErrorResponseHandler } from "../../../common/types";
import { hasPermission } from "../../../common/SecureComponent";
import {
CONSOLE_UI_RESOURCE,
IAM_SCOPES,
} from "../../../common/SecureComponent/permissions";
import { setErrorSnackMessage, setHelpName } from "../../../systemSlice";
import { useAppDispatch } from "../../../store";
import LabelWithIcon from "../Buckets/BucketDetails/SummaryItems/LabelWithIcon";
import PageHeaderWrapper from "../Common/PageHeaderWrapper/PageHeaderWrapper";
import HelpMenu from "../HelpMenu";
const Status = () => {
const dispatch = useAppDispatch();
const [curTab, setCurTab] = useState<number>(0);
const [curTab, setCurTab] = useState<string>("simple-tab-0");
const [status, setStatus] = useState<any | null>(null);
const [loadingStatus, setLoadingStatus] = useState<boolean>(true);
@@ -184,33 +184,41 @@ const Status = () => {
<SectionTitle>Status</SectionTitle>
<br />
{status && (
<Grid container spacing={1}>
<Grid container>
<Grid item xs={12}>
<Box
sx={{
display: "grid",
gridTemplateColumns: { xs: "1fr", sm: "2fr 1fr" },
gridAutoFlow: { xs: "dense", sm: "row" },
gap: 2,
gridTemplateColumns: "2fr 1fr",
gridAutoFlow: "row",
[`@media (max-width: ${breakPoints.sm}px)`]: {
gridTemplateColumns: "1fr",
gridAutoFlow: "dense",
},
}}
>
<Box
sx={{
display: "grid",
gridTemplateColumns: { xs: "1fr", sm: "2fr 1fr" },
gridAutoFlow: { xs: "dense", sm: "row" },
gap: 2,
gridTemplateColumns: "2fr 1fr",
gridAutoFlow: "row",
[`@media (max-width: ${breakPoints.sm}px)`]: {
gridTemplateColumns: "1fr",
gridAutoFlow: "dense",
},
}}
>
<LabelValuePair label={"Name:"} value={status.name} />
<ValuePair label={"Name:"} value={status.name} />
{version && (
<LabelValuePair label={"Version:"} value={version.version} />
<ValuePair label={"Version:"} value={version.version} />
)}
<LabelValuePair
<ValuePair
label={"Default Key ID:"}
value={status.defaultKeyID}
/>
<LabelValuePair
<ValuePair
label={"Key Management Service Endpoints:"}
value={
<Fragment>
@@ -243,17 +251,21 @@ const Status = () => {
<SectionTitle>Supported API endpoints</SectionTitle>
<br />
{apis && (
<Grid container spacing={1}>
<Grid container>
<Grid item xs={12}>
<LabelValuePair
<ValuePair
label={""}
value={
<Box
sx={{
display: "grid",
gridTemplateColumns: { xs: "1fr", sm: "2fr 1fr" },
gridAutoFlow: { xs: "dense", sm: "row" },
gap: 2,
gridTemplateColumns: "2fr 1fr",
gridAutoFlow: "row",
[`@media (max-width: ${breakPoints.sm}px)`]: {
gridTemplateColumns: "1fr",
gridAutoFlow: "dense",
},
}}
>
{apis.results.map((e: any, i: number) => (
@@ -364,73 +376,56 @@ const Status = () => {
<PageLayout>
<Tabs
value={curTab}
onChange={(e: React.ChangeEvent<{}>, newValue: number) => {
setCurTab(newValue);
}}
indicatorColor="primary"
textColor="primary"
aria-label="cluster-tabs"
variant="scrollable"
scrollButtons="auto"
>
<Tab
label="Status"
id="simple-tab-0"
aria-controls="simple-tabpanel-0"
/>
<Tab
label="APIs"
id="simple-tab-1"
aria-controls="simple-tabpanel-1"
/>
<Tab
label="Metrics"
id="simple-tab-2"
aria-controls="simple-tabpanel-2"
onClick={() => {}}
/>
</Tabs>
<TabPanel index={0} value={curTab}>
<Box
sx={{
border: "1px solid #eaeaea",
borderRadius: "2px",
display: "flex",
flexFlow: "column",
padding: "43px",
}}
>
{statusPanel}
</Box>
</TabPanel>
<TabPanel index={1} value={curTab}>
<Box
sx={{
border: "1px solid #eaeaea",
borderRadius: "2px",
display: "flex",
flexFlow: "column",
padding: "43px",
}}
>
{apisPanel}
</Box>
</TabPanel>
<TabPanel index={2} value={curTab}>
<Box
sx={{
border: "1px solid #eaeaea",
borderRadius: "2px",
display: "flex",
flexFlow: "column",
padding: "43px",
}}
>
{metricsPanel}
</Box>
</TabPanel>
currentTabOrPath={curTab}
onTabClick={(newValue) => setCurTab(newValue)}
options={[
{
tabConfig: { label: "Status", id: "simple-tab-0" },
content: (
<Box
withBorders
sx={{
display: "flex",
flexFlow: "column",
padding: "43px",
}}
>
{statusPanel}
</Box>
),
},
{
tabConfig: { label: "APIs", id: "simple-tab-1" },
content: (
<Box
withBorders
sx={{
display: "flex",
flexFlow: "column",
padding: "43px",
}}
>
{apisPanel}
</Box>
),
},
{
tabConfig: { label: "Metrics", id: "simple-tab-2" },
content: (
<Box
withBorders
sx={{
display: "flex",
flexFlow: "column",
padding: "43px",
}}
>
{metricsPanel}
</Box>
),
},
]}
/>
</PageLayout>
</Fragment>
);