New tenants list (#1160)
* New Tenants Listing * Removed all warnings and duplciate comments
This commit is contained in:
2
go.sum
2
go.sum
@@ -911,8 +911,6 @@ github.com/minio/kes v0.11.0/go.mod h1:mTF1Bv8YVEtQqF/B7Felp4tLee44Pp+dgI0rhCvgN
|
||||
github.com/minio/madmin-go v1.0.12/go.mod h1:BK+z4XRx7Y1v8SFWXsuLNqQqnq5BO/axJ8IDJfgyvfs=
|
||||
github.com/minio/madmin-go v1.1.10 h1:pfMgXkzdwADnNfVdNMJbwok2fjb2sJ7Q76kDt89RGzE=
|
||||
github.com/minio/madmin-go v1.1.10/go.mod h1:Iu0OnrMWNBYx1lqJTW+BFjBMx0Hi0wjw8VmqhiOs2Jo=
|
||||
github.com/minio/mc v0.0.0-20211026035615-633978474384 h1:kegqQrdBZ6Vzpa6WI+dop2j7ysRIXNa1ZOC08vSDgNE=
|
||||
github.com/minio/mc v0.0.0-20211026035615-633978474384/go.mod h1:vxztwXLB9Gyl/h3Yh08Mpz1CB/0FO5Es0iQRpzxvS5I=
|
||||
github.com/minio/mc v0.0.0-20211027024940-7866f97ef502 h1:7ip9qTspUniv+WDENgOcfUr95IccxG5aDkBM4Z96kQg=
|
||||
github.com/minio/mc v0.0.0-20211027024940-7866f97ef502/go.mod h1:vxztwXLB9Gyl/h3Yh08Mpz1CB/0FO5Es0iQRpzxvS5I=
|
||||
github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw=
|
||||
|
||||
@@ -34,6 +34,18 @@ import (
|
||||
// swagger:model tenantList
|
||||
type TenantList struct {
|
||||
|
||||
// capacity
|
||||
Capacity int64 `json:"capacity,omitempty"`
|
||||
|
||||
// capacity raw
|
||||
CapacityRaw int64 `json:"capacity_raw,omitempty"`
|
||||
|
||||
// capacity raw usage
|
||||
CapacityRawUsage int64 `json:"capacity_raw_usage,omitempty"`
|
||||
|
||||
// capacity usage
|
||||
CapacityUsage int64 `json:"capacity_usage,omitempty"`
|
||||
|
||||
// creation date
|
||||
CreationDate string `json:"creation_date,omitempty"`
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ package models
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
@@ -46,17 +47,69 @@ type TenantStatus struct {
|
||||
// health status
|
||||
HealthStatus string `json:"health_status,omitempty"`
|
||||
|
||||
// usage
|
||||
Usage *TenantStatusUsage `json:"usage,omitempty"`
|
||||
|
||||
// write quorum
|
||||
WriteQuorum int32 `json:"write_quorum,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates this tenant status
|
||||
func (m *TenantStatus) Validate(formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.validateUsage(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this tenant status based on context it is used
|
||||
func (m *TenantStatus) validateUsage(formats strfmt.Registry) error {
|
||||
if swag.IsZero(m.Usage) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
if m.Usage != nil {
|
||||
if err := m.Usage.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("usage")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this tenant status based on the context it is used
|
||||
func (m *TenantStatus) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.contextValidateUsage(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *TenantStatus) contextValidateUsage(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if m.Usage != nil {
|
||||
if err := m.Usage.ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("usage")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -77,3 +130,49 @@ func (m *TenantStatus) UnmarshalBinary(b []byte) error {
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
|
||||
// TenantStatusUsage tenant status usage
|
||||
//
|
||||
// swagger:model TenantStatusUsage
|
||||
type TenantStatusUsage struct {
|
||||
|
||||
// capacity
|
||||
Capacity int64 `json:"capacity,omitempty"`
|
||||
|
||||
// capacity usage
|
||||
CapacityUsage int64 `json:"capacity_usage,omitempty"`
|
||||
|
||||
// raw
|
||||
Raw int64 `json:"raw,omitempty"`
|
||||
|
||||
// raw usage
|
||||
RawUsage int64 `json:"raw_usage,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates this tenant status usage
|
||||
func (m *TenantStatusUsage) Validate(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this tenant status usage based on context it is used
|
||||
func (m *TenantStatusUsage) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *TenantStatusUsage) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *TenantStatusUsage) UnmarshalBinary(b []byte) error {
|
||||
var res TenantStatusUsage
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -379,7 +379,7 @@ func init() {
|
||||
"tags": [
|
||||
"UserAPI"
|
||||
],
|
||||
"summary": "Logout from Console.",
|
||||
"summary": "Logout from Operator.",
|
||||
"operationId": "Logout",
|
||||
"responses": {
|
||||
"200": {
|
||||
@@ -2895,6 +2895,22 @@ func init() {
|
||||
"tenantList": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"capacity": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"capacity_raw": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"capacity_raw_usage": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"capacity_usage": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"creation_date": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -3007,6 +3023,27 @@ func init() {
|
||||
"health_status": {
|
||||
"type": "string"
|
||||
},
|
||||
"usage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"capacity": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"capacity_usage": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"raw": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"raw_usage": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
}
|
||||
},
|
||||
"write_quorum": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
@@ -3526,7 +3563,7 @@ func init() {
|
||||
"tags": [
|
||||
"UserAPI"
|
||||
],
|
||||
"summary": "Logout from Console.",
|
||||
"summary": "Logout from Operator.",
|
||||
"operationId": "Logout",
|
||||
"responses": {
|
||||
"200": {
|
||||
@@ -5203,6 +5240,27 @@ func init() {
|
||||
}
|
||||
}
|
||||
},
|
||||
"TenantStatusUsage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"capacity": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"capacity_usage": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"raw": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"raw_usage": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
}
|
||||
},
|
||||
"UpdateTenantSecurityRequestCustomCertificates": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -6599,6 +6657,22 @@ func init() {
|
||||
"tenantList": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"capacity": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"capacity_raw": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"capacity_raw_usage": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"capacity_usage": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"creation_date": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -6711,6 +6785,27 @@ func init() {
|
||||
"health_status": {
|
||||
"type": "string"
|
||||
},
|
||||
"usage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"capacity": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"capacity_usage": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"raw": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"raw_usage": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
}
|
||||
},
|
||||
"write_quorum": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
|
||||
@@ -50,7 +50,7 @@ func NewLogout(ctx *middleware.Context, handler LogoutHandler) *Logout {
|
||||
|
||||
/* Logout swagger:route POST /logout UserAPI logout
|
||||
|
||||
Logout from Console.
|
||||
Logout from Operator.
|
||||
|
||||
*/
|
||||
type Logout struct {
|
||||
|
||||
@@ -526,6 +526,12 @@ func getTenantDetailsResponse(session *models.Principal, params operator_api.Ten
|
||||
DrivesOffline: minTenant.Status.DrivesOffline,
|
||||
DrivesOnline: minTenant.Status.DrivesOnline,
|
||||
WriteQuorum: minTenant.Status.WriteQuorum,
|
||||
Usage: &models.TenantStatusUsage{
|
||||
Raw: minTenant.Status.Usage.RawCapacity,
|
||||
RawUsage: minTenant.Status.Usage.RawUsage,
|
||||
Capacity: minTenant.Status.Usage.Capacity,
|
||||
CapacityUsage: minTenant.Status.Usage.Usage,
|
||||
},
|
||||
}
|
||||
|
||||
// get tenant service
|
||||
@@ -824,16 +830,20 @@ func listTenants(ctx context.Context, operatorClient OperatorClientI, namespace
|
||||
}
|
||||
|
||||
tenants = append(tenants, &models.TenantList{
|
||||
CreationDate: tenant.ObjectMeta.CreationTimestamp.Format(time.RFC3339),
|
||||
DeletionDate: deletion,
|
||||
Name: tenant.ObjectMeta.Name,
|
||||
PoolCount: int64(len(tenant.Spec.Pools)),
|
||||
InstanceCount: instanceCount,
|
||||
VolumeCount: volumeCount,
|
||||
CurrentState: tenant.Status.CurrentState,
|
||||
Namespace: tenant.ObjectMeta.Namespace,
|
||||
TotalSize: totalSize,
|
||||
HealthStatus: string(tenant.Status.HealthStatus),
|
||||
CreationDate: tenant.ObjectMeta.CreationTimestamp.Format(time.RFC3339),
|
||||
DeletionDate: deletion,
|
||||
Name: tenant.ObjectMeta.Name,
|
||||
PoolCount: int64(len(tenant.Spec.Pools)),
|
||||
InstanceCount: instanceCount,
|
||||
VolumeCount: volumeCount,
|
||||
CurrentState: tenant.Status.CurrentState,
|
||||
Namespace: tenant.ObjectMeta.Namespace,
|
||||
TotalSize: totalSize,
|
||||
HealthStatus: string(tenant.Status.HealthStatus),
|
||||
CapacityRaw: tenant.Status.Usage.RawCapacity,
|
||||
CapacityRawUsage: tenant.Status.Usage.RawUsage,
|
||||
Capacity: tenant.Status.Usage.Capacity,
|
||||
CapacityUsage: tenant.Status.Usage.Usage,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -67,6 +67,13 @@ const GlobalCss = withStyles({
|
||||
borderRadius: 0,
|
||||
},
|
||||
},
|
||||
hr: {
|
||||
borderTop: 0,
|
||||
borderLeft: 0,
|
||||
borderRight: 0,
|
||||
borderColor: "#999999",
|
||||
backgroundColor: "transparent" as const,
|
||||
},
|
||||
},
|
||||
})(() => null);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from "react";
|
||||
import React, { Fragment } from "react";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
@@ -15,6 +15,7 @@ interface IProgressBar {
|
||||
error: string;
|
||||
loading: boolean;
|
||||
classes: any;
|
||||
labels?: boolean;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
@@ -36,7 +37,7 @@ const styles = (theme: Theme) =>
|
||||
},
|
||||
});
|
||||
|
||||
const BorderLinearProgress = withStyles((theme) => ({
|
||||
export const BorderLinearProgress = withStyles((theme) => ({
|
||||
root: {
|
||||
height: 10,
|
||||
borderRadius: 5,
|
||||
@@ -61,6 +62,7 @@ const UsageBarWrapper = ({
|
||||
renderFunction,
|
||||
loading,
|
||||
error,
|
||||
labels = true,
|
||||
}: IProgressBar) => {
|
||||
const porcentualValue = (currValue * 100) / maxValue;
|
||||
|
||||
@@ -71,13 +73,25 @@ const UsageBarWrapper = ({
|
||||
) : (
|
||||
<React.Fragment>
|
||||
<Grid item xs={12} className={classes.allValue}>
|
||||
{label}{" "}
|
||||
{renderFunction ? renderFunction(maxValue.toString()) : maxValue}
|
||||
{labels && (
|
||||
<Fragment>
|
||||
{label}{" "}
|
||||
{renderFunction
|
||||
? renderFunction(maxValue.toString())
|
||||
: maxValue}
|
||||
</Fragment>
|
||||
)}
|
||||
</Grid>
|
||||
<BorderLinearProgress variant="determinate" value={porcentualValue} />
|
||||
<Grid item xs={12} className={classes.currentUsage}>
|
||||
Used:{" "}
|
||||
{renderFunction ? renderFunction(currValue.toString()) : currValue}
|
||||
{labels && (
|
||||
<Fragment>
|
||||
Used:{" "}
|
||||
{renderFunction
|
||||
? renderFunction(currValue.toString())
|
||||
: currValue}
|
||||
</Fragment>
|
||||
)}
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
);
|
||||
|
||||
@@ -44,7 +44,6 @@ import Account from "./Account/Account";
|
||||
import Users from "./Users/Users";
|
||||
import Groups from "./Groups/Groups";
|
||||
import ConfigurationMain from "./Configurations/ConfigurationMain";
|
||||
import TenantsMain from "./Tenants/TenantsMain";
|
||||
import TenantDetails from "./Tenants/TenantDetails/TenantDetails";
|
||||
import License from "./License/License";
|
||||
import Trace from "./Trace/Trace";
|
||||
@@ -63,6 +62,7 @@ import NotificationTypeSelector from "./NotificationEndpoints/NotificationTypeSe
|
||||
import ListTiersConfiguration from "./Configurations/TiersConfiguration/ListTiersConfiguration";
|
||||
import TierTypeSelector from "./Configurations/TiersConfiguration/TierTypeSelector";
|
||||
import AddTierConfiguration from "./Configurations/TiersConfiguration/AddTierConfiguration";
|
||||
import ListTenants from "./Tenants/ListTenants/ListTenants";
|
||||
|
||||
const drawerWidth = 245;
|
||||
|
||||
@@ -321,7 +321,7 @@ const Console = ({
|
||||
},
|
||||
},
|
||||
{
|
||||
component: TenantsMain,
|
||||
component: ListTenants,
|
||||
path: "/tenants",
|
||||
},
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@ import { connect } from "react-redux";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import InputAdornment from "@mui/material/InputAdornment";
|
||||
import { IconButton } from "@mui/material";
|
||||
import { Box, Button, IconButton } from "@mui/material";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
@@ -28,18 +28,19 @@ import { niceBytes } from "../../../../common/utils";
|
||||
import { NewServiceAccount } from "../../Common/CredentialsPrompt/types";
|
||||
import {
|
||||
actionsTray,
|
||||
containerForHeader,
|
||||
searchField,
|
||||
} from "../../Common/FormComponents/common/styleLibrary";
|
||||
import { setErrorSnackMessage } from "../../../../actions";
|
||||
import { CircleIcon, CreateIcon } from "../../../../icons";
|
||||
import { AddIcon } from "../../../../icons";
|
||||
import { ErrorResponseHandler } from "../../../../common/types";
|
||||
import api from "../../../../common/api";
|
||||
import TableWrapper from "../../Common/TableWrapper/TableWrapper";
|
||||
import DeleteTenant from "./DeleteTenant";
|
||||
import CredentialsPrompt from "../../Common/CredentialsPrompt/CredentialsPrompt";
|
||||
import history from "../../../../history";
|
||||
import RefreshIcon from "../../../../icons/RefreshIcon";
|
||||
import SearchIcon from "../../../../icons/SearchIcon";
|
||||
import PageHeader from "../../Common/PageHeader/PageHeader";
|
||||
import TenantListItem from "./TenantListItem";
|
||||
|
||||
interface ITenantsList {
|
||||
classes: any;
|
||||
@@ -50,48 +51,61 @@ const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...actionsTray,
|
||||
...searchField,
|
||||
|
||||
redState: {
|
||||
color: theme.palette.error.main,
|
||||
"& .MuiSvgIcon-root": {
|
||||
width: 16,
|
||||
height: 16,
|
||||
float: "left",
|
||||
marginRight: 4,
|
||||
},
|
||||
...containerForHeader(theme.spacing(4)),
|
||||
addTenant: {
|
||||
marginRight: 8,
|
||||
},
|
||||
yellowState: {
|
||||
color: theme.palette.warning.main,
|
||||
"& .MuiSvgIcon-root": {
|
||||
width: 16,
|
||||
height: 16,
|
||||
float: "left",
|
||||
marginRight: 4,
|
||||
},
|
||||
theaderSearchLabel: {
|
||||
color: theme.palette.grey["400"],
|
||||
fontSize: 14,
|
||||
fontWeight: "bold",
|
||||
},
|
||||
greenState: {
|
||||
color: theme.palette.success.main,
|
||||
"& .MuiSvgIcon-root": {
|
||||
width: 16,
|
||||
height: 16,
|
||||
float: "left",
|
||||
marginRight: 4,
|
||||
},
|
||||
addBucket: {
|
||||
marginRight: 8,
|
||||
},
|
||||
greyState: {
|
||||
color: "grey",
|
||||
"& .MuiSvgIcon-root": {
|
||||
width: 16,
|
||||
height: 16,
|
||||
float: "left",
|
||||
marginRight: 4,
|
||||
theaderSearch: {
|
||||
borderColor: theme.palette.grey["200"],
|
||||
"& .MuiInputBase-input": {
|
||||
paddingTop: 10,
|
||||
paddingBottom: 10,
|
||||
},
|
||||
"& .MuiInputBase-root": {
|
||||
"& .MuiInputAdornment-root": {
|
||||
"& .MuiSvgIcon-root": {
|
||||
color: theme.palette.grey["400"],
|
||||
height: 14,
|
||||
},
|
||||
},
|
||||
},
|
||||
actionHeaderItems: {
|
||||
"@media (min-width: 320px)": {
|
||||
marginTop: 8,
|
||||
},
|
||||
},
|
||||
marginRight: 10,
|
||||
marginLeft: 10,
|
||||
},
|
||||
mainActions: {
|
||||
textAlign: "right",
|
||||
},
|
||||
healthStatusIcon: {
|
||||
position: "relative",
|
||||
fontSize: 10,
|
||||
right: -30,
|
||||
height: 10,
|
||||
top: -50,
|
||||
},
|
||||
tenantItem: {
|
||||
border: "1px solid #dedede",
|
||||
marginBottom: 20,
|
||||
paddingLeft: 40,
|
||||
paddingRight: 40,
|
||||
paddingTop: 30,
|
||||
paddingBottom: 30,
|
||||
},
|
||||
});
|
||||
|
||||
const ListTenants = ({ classes, setErrorSnackMessage }: ITenantsList) => {
|
||||
const [deleteOpen, setDeleteOpen] = useState<boolean>(false);
|
||||
const [selectedTenant, setSelectedTenant] = useState<any>(null);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [filterTenants, setFilterTenants] = useState<string>("");
|
||||
const [records, setRecords] = useState<any[]>([]);
|
||||
@@ -99,34 +113,11 @@ const ListTenants = ({ classes, setErrorSnackMessage }: ITenantsList) => {
|
||||
const [createdAccount, setCreatedAccount] =
|
||||
useState<NewServiceAccount | null>(null);
|
||||
|
||||
const closeDeleteModalAndRefresh = (reloadData: boolean) => {
|
||||
setDeleteOpen(false);
|
||||
|
||||
if (reloadData) {
|
||||
setIsLoading(true);
|
||||
}
|
||||
};
|
||||
|
||||
const confirmDeleteTenant = (tenant: ITenant) => {
|
||||
setSelectedTenant(tenant);
|
||||
setDeleteOpen(true);
|
||||
};
|
||||
|
||||
const redirectToTenantDetails = (tenant: ITenant) => {
|
||||
history.push(`/namespaces/${tenant.namespace}/tenants/${tenant.name}`);
|
||||
return;
|
||||
};
|
||||
|
||||
const closeCredentialsModal = () => {
|
||||
setShowNewCredentials(false);
|
||||
setCreatedAccount(null);
|
||||
};
|
||||
|
||||
const tableActions = [
|
||||
{ type: "view", onClick: redirectToTenantDetails },
|
||||
{ type: "delete", onClick: confirmDeleteTenant },
|
||||
];
|
||||
|
||||
const filteredRecords = records.filter((b: any) => {
|
||||
if (filterTenants === "") {
|
||||
return true;
|
||||
@@ -155,7 +146,9 @@ const ListTenants = ({ classes, setErrorSnackMessage }: ITenantsList) => {
|
||||
}
|
||||
|
||||
for (let i = 0; i < resTenants.length; i++) {
|
||||
resTenants[i].capacity = niceBytes(resTenants[i].total_size + "");
|
||||
resTenants[i].total_capacity = niceBytes(
|
||||
resTenants[i].total_size + ""
|
||||
);
|
||||
}
|
||||
|
||||
setRecords(resTenants);
|
||||
@@ -174,28 +167,8 @@ const ListTenants = ({ classes, setErrorSnackMessage }: ITenantsList) => {
|
||||
setIsLoading(true);
|
||||
}, []);
|
||||
|
||||
const healthStatusToClass = (health_status: string) => {
|
||||
switch (health_status) {
|
||||
case "red":
|
||||
return classes.redState;
|
||||
case "yellow":
|
||||
return classes.yellowState;
|
||||
case "green":
|
||||
return classes.greenState;
|
||||
default:
|
||||
return classes.greyState;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{deleteOpen && (
|
||||
<DeleteTenant
|
||||
deleteOpen={deleteOpen}
|
||||
selectedTenant={selectedTenant}
|
||||
closeDeleteModalAndRefresh={closeDeleteModalAndRefresh}
|
||||
/>
|
||||
)}
|
||||
{showNewCredentials && (
|
||||
<CredentialsPrompt
|
||||
newServiceAccount={createdAccount}
|
||||
@@ -206,78 +179,101 @@ const ListTenants = ({ classes, setErrorSnackMessage }: ITenantsList) => {
|
||||
entity="Tenant"
|
||||
/>
|
||||
)}
|
||||
<PageHeader
|
||||
label="Tenants"
|
||||
actions={
|
||||
<Fragment>
|
||||
<Grid
|
||||
container
|
||||
direction="row"
|
||||
justifyContent="flex-end"
|
||||
alignItems="center"
|
||||
className={classes.actionHeaderItems}
|
||||
>
|
||||
<Box display={{ xs: "none", sm: "none", md: "block" }}>
|
||||
<Grid item>
|
||||
<div className={classes.theaderSearchLabel}>
|
||||
Filter Tenants:
|
||||
</div>
|
||||
</Grid>
|
||||
</Box>
|
||||
<Box display={{ xs: "block", sm: "block", md: "none" }}>
|
||||
<TextField
|
||||
className={classes.theaderSearch}
|
||||
variant={"outlined"}
|
||||
id="search-resource"
|
||||
placeholder={"Filter Tenants"}
|
||||
onChange={(val) => {
|
||||
setFilterTenants(val.target.value);
|
||||
}}
|
||||
inputProps={{
|
||||
disableUnderline: true,
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
<SearchIcon />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<Box display={{ xs: "none", sm: "none", md: "block" }}>
|
||||
<TextField
|
||||
className={classes.theaderSearch}
|
||||
variant={"outlined"}
|
||||
id="search-resource"
|
||||
onChange={(val) => {
|
||||
setFilterTenants(val.target.value);
|
||||
}}
|
||||
inputProps={{
|
||||
disableUnderline: true,
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
<SearchIcon />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Grid item>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
endIcon={<AddIcon />}
|
||||
onClick={() => {
|
||||
history.push("/tenants/add");
|
||||
}}
|
||||
className={classes.addTenant}
|
||||
>
|
||||
Create Tenant
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Fragment>
|
||||
}
|
||||
/>
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.actionsTray}>
|
||||
<TextField
|
||||
placeholder="Search Tenants"
|
||||
className={classes.searchField}
|
||||
id="search-resource"
|
||||
label=""
|
||||
onChange={(val) => {
|
||||
setFilterTenants(val.target.value);
|
||||
}}
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<SearchIcon />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
variant="standard"
|
||||
/>
|
||||
<IconButton
|
||||
color="primary"
|
||||
aria-label="Refresh Tenant List"
|
||||
component="span"
|
||||
onClick={() => {
|
||||
setIsLoading(true);
|
||||
}}
|
||||
size="large"
|
||||
>
|
||||
<RefreshIcon />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
color="primary"
|
||||
aria-label="Create Tenant"
|
||||
component="span"
|
||||
onClick={() => {
|
||||
history.push("/tenants/add");
|
||||
}}
|
||||
size="large"
|
||||
>
|
||||
<CreateIcon />
|
||||
</IconButton>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TableWrapper
|
||||
itemActions={tableActions}
|
||||
columns={[
|
||||
{
|
||||
label: "Name",
|
||||
elementKey: "name",
|
||||
renderFullObject: true,
|
||||
renderFunction: (t) => {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className={healthStatusToClass(t.health_status)}>
|
||||
<CircleIcon />
|
||||
</div>
|
||||
<div>{t.name}</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
},
|
||||
},
|
||||
{ label: "Namespace", elementKey: "namespace" },
|
||||
{ label: "Capacity", elementKey: "capacity" },
|
||||
{ label: "# of Pools", elementKey: "pool_count" },
|
||||
{ label: "State", elementKey: "currentState" },
|
||||
]}
|
||||
isLoading={isLoading}
|
||||
records={filteredRecords}
|
||||
entityName="Tenants"
|
||||
idField="name"
|
||||
/>
|
||||
<Grid item xs={12} className={classes.container}>
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.mainActions}>
|
||||
<IconButton
|
||||
color="primary"
|
||||
aria-label="Refresh Tenant List"
|
||||
component="span"
|
||||
onClick={() => {
|
||||
setIsLoading(true);
|
||||
}}
|
||||
size="large"
|
||||
>
|
||||
<RefreshIcon />
|
||||
</IconButton>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
{filteredRecords.map((t) => {
|
||||
return <TenantListItem tenant={t} />;
|
||||
})}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Fragment>
|
||||
|
||||
@@ -0,0 +1,270 @@
|
||||
// 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 { Button } from "@mui/material";
|
||||
import { ITenant } from "./types";
|
||||
import { connect } from "react-redux";
|
||||
import { setErrorSnackMessage } from "../../../../actions";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { ArrowRightIcon, CircleIcon } from "../../../../icons";
|
||||
import history from "../../../../history";
|
||||
import TenantsIcon from "../../../../icons/TenantsIcon";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { niceBytes } from "../../../../common/utils";
|
||||
import UsageBarWrapper from "../../Common/UsageBarWrapper/UsageBarWrapper";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
redState: {
|
||||
color: theme.palette.error.main,
|
||||
"& .MuiSvgIcon-root": {
|
||||
width: 16,
|
||||
height: 16,
|
||||
float: "left",
|
||||
marginRight: 4,
|
||||
},
|
||||
},
|
||||
yellowState: {
|
||||
color: theme.palette.warning.main,
|
||||
"& .MuiSvgIcon-root": {
|
||||
width: 16,
|
||||
height: 16,
|
||||
float: "left",
|
||||
marginRight: 4,
|
||||
},
|
||||
},
|
||||
greenState: {
|
||||
color: theme.palette.success.main,
|
||||
"& .MuiSvgIcon-root": {
|
||||
width: 16,
|
||||
height: 16,
|
||||
float: "left",
|
||||
marginRight: 4,
|
||||
},
|
||||
},
|
||||
greyState: {
|
||||
color: "grey",
|
||||
"& .MuiSvgIcon-root": {
|
||||
width: 16,
|
||||
height: 16,
|
||||
float: "left",
|
||||
marginRight: 4,
|
||||
},
|
||||
},
|
||||
tenantIcon: { width: 40, height: 40, position: "relative" },
|
||||
healthStatusIcon: {
|
||||
position: "absolute",
|
||||
fontSize: 10,
|
||||
top: 0,
|
||||
right: -20,
|
||||
height: 10,
|
||||
},
|
||||
tenantItem: {
|
||||
border: "1px solid #dedede",
|
||||
marginBottom: 20,
|
||||
paddingLeft: 40,
|
||||
paddingRight: 40,
|
||||
paddingTop: 30,
|
||||
paddingBottom: 30,
|
||||
},
|
||||
title: {
|
||||
fontSize: 22,
|
||||
fontWeight: "bold",
|
||||
},
|
||||
titleSubKey: {
|
||||
fontSize: 14,
|
||||
paddingRight: 8,
|
||||
},
|
||||
titleSubValue: {
|
||||
fontSize: 14,
|
||||
fontWeight: "bold",
|
||||
paddingRight: 16,
|
||||
},
|
||||
boxyTitle: {
|
||||
fontWeight: "bold",
|
||||
},
|
||||
boxyValue: {
|
||||
fontSize: 24,
|
||||
fontWeight: "bold",
|
||||
},
|
||||
boxyUnit: {
|
||||
fontSize: 12,
|
||||
color: "#5E5E5E",
|
||||
},
|
||||
});
|
||||
|
||||
interface ITenantListItem {
|
||||
tenant: ITenant;
|
||||
classes: any;
|
||||
}
|
||||
|
||||
interface ValueUnit {
|
||||
value: string;
|
||||
unit: string;
|
||||
}
|
||||
|
||||
const TenantListItem = ({ tenant, classes }: ITenantListItem) => {
|
||||
const healthStatusToClass = (health_status: string) => {
|
||||
switch (health_status) {
|
||||
case "red":
|
||||
return classes.redState;
|
||||
case "yellow":
|
||||
return classes.yellowState;
|
||||
case "green":
|
||||
return classes.greenState;
|
||||
default:
|
||||
return classes.greyState;
|
||||
}
|
||||
};
|
||||
|
||||
var raw: ValueUnit = { value: "n/a", unit: "" };
|
||||
var capacity: ValueUnit = { value: "n/a", unit: "" };
|
||||
var used: ValueUnit = { value: "n/a", unit: "" };
|
||||
|
||||
if (tenant.capacity_raw) {
|
||||
const b = niceBytes(`${tenant.capacity_raw}`, true);
|
||||
const parts = b.split(" ");
|
||||
raw.value = parts[0];
|
||||
raw.unit = parts[1];
|
||||
}
|
||||
if (tenant.capacity) {
|
||||
const b = niceBytes(`${tenant.capacity}`, true);
|
||||
const parts = b.split(" ");
|
||||
capacity.value = parts[0];
|
||||
capacity.unit = parts[1];
|
||||
}
|
||||
if (tenant.capacity_usage) {
|
||||
const usageProportion =
|
||||
(tenant.capacity! * tenant.capacity_raw_usage!) / tenant.capacity_raw!;
|
||||
const b = niceBytes(`${usageProportion}`, true);
|
||||
const parts = b.split(" ");
|
||||
used.value = parts[0];
|
||||
used.unit = parts[1];
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<div className={classes.tenantItem}>
|
||||
<Grid container>
|
||||
<Grid item xs={10}>
|
||||
<div className={classes.title}>{tenant.name}</div>
|
||||
<div>
|
||||
<span className={classes.titleSubKey}>Namespace:</span>
|
||||
<span className={classes.titleSubValue}>{tenant.namespace}</span>
|
||||
<span className={classes.titleSubKey}>Pools:</span>
|
||||
<span className={classes.titleSubValue}>{tenant.pool_count}</span>
|
||||
<span className={classes.titleSubKey}>State:</span>
|
||||
<span className={classes.titleSubValue}>
|
||||
{tenant.currentState}
|
||||
</span>
|
||||
</div>
|
||||
</Grid>
|
||||
<Grid item xs={2} textAlign={"end"}>
|
||||
<Button
|
||||
endIcon={<ArrowRightIcon />}
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
history.push(
|
||||
`/namespaces/${tenant.namespace}/tenants/${tenant.name}`
|
||||
);
|
||||
}}
|
||||
>
|
||||
View
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<hr />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Grid container alignItems={"center"}>
|
||||
<Grid item xs={7}>
|
||||
<Grid container>
|
||||
<Grid item xs={3} style={{ textAlign: "center" }}>
|
||||
<div className={classes.tenantIcon}>
|
||||
<div className={classes.healthStatusIcon}>
|
||||
<span
|
||||
className={healthStatusToClass(tenant.health_status)}
|
||||
>
|
||||
<CircleIcon />
|
||||
</span>
|
||||
</div>
|
||||
<TenantsIcon style={{ fontSize: 40 }} />
|
||||
</div>
|
||||
</Grid>
|
||||
<Grid item xs={3}>
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.boxyTitle}>
|
||||
Raw Capacity
|
||||
</Grid>
|
||||
<Grid item className={classes.boxyValue}>
|
||||
{raw.value}
|
||||
<span className={classes.boxyUnit}>{raw.unit}</span>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={3}>
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.boxyTitle}>
|
||||
Capacity
|
||||
</Grid>
|
||||
<Grid item className={classes.boxyValue}>
|
||||
{capacity.value}
|
||||
<span className={classes.boxyUnit}>
|
||||
{capacity.unit}
|
||||
</span>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={3}>
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.boxyTitle}>
|
||||
Usage
|
||||
</Grid>
|
||||
<Grid item className={classes.boxyValue}>
|
||||
{used.value}
|
||||
<span className={classes.boxyUnit}>{used.unit}</span>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={5}>
|
||||
<UsageBarWrapper
|
||||
currValue={tenant.capacity_raw_usage ?? 0}
|
||||
maxValue={tenant.capacity_raw ?? 1}
|
||||
label={""}
|
||||
renderFunction={niceBytes}
|
||||
error={""}
|
||||
loading={false}
|
||||
labels={false}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const connector = connect(null, {
|
||||
setErrorSnackMessage,
|
||||
});
|
||||
|
||||
export default withStyles(styles)(connector(TenantListItem));
|
||||
@@ -68,12 +68,19 @@ export interface IEndpoints {
|
||||
console: string;
|
||||
}
|
||||
|
||||
export interface ITenantStatusUsage {
|
||||
raw: number;
|
||||
raw_usage: number;
|
||||
capacity: number;
|
||||
capacity_usage: number;
|
||||
}
|
||||
export interface ITenantStatus {
|
||||
write_quorum: string;
|
||||
drives_online: string;
|
||||
drives_offline: string;
|
||||
drives_healing: string;
|
||||
health_status: string;
|
||||
usage?: ITenantStatusUsage;
|
||||
}
|
||||
|
||||
export interface ITenant {
|
||||
@@ -100,8 +107,12 @@ export interface ITenant {
|
||||
idpOidcEnabled: boolean;
|
||||
health_status: string;
|
||||
status?: ITenantStatus;
|
||||
capacity_raw?: number;
|
||||
capacity_raw_usage?: number;
|
||||
capacity?: number;
|
||||
capacity_usage?: number;
|
||||
// computed
|
||||
capacity: string;
|
||||
total_capacity: string;
|
||||
subnet_license: LicenseInfo;
|
||||
total_instances?: number;
|
||||
total_volumes?: number;
|
||||
|
||||
@@ -28,12 +28,10 @@ import Grid from "@mui/material/Grid";
|
||||
import { Button, CircularProgress } from "@mui/material";
|
||||
import Paper from "@mui/material/Paper";
|
||||
import { niceBytes } from "../../../../common/utils";
|
||||
import api from "../../../../common/api";
|
||||
import { ITenant } from "../ListTenants/types";
|
||||
import UsageBarWrapper from "../../Common/UsageBarWrapper/UsageBarWrapper";
|
||||
import UpdateTenantModal from "./UpdateTenantModal";
|
||||
import { AppState } from "../../../../store";
|
||||
import { ErrorResponseHandler } from "../../../../common/types";
|
||||
import history from "./../../../../history";
|
||||
import { CircleIcon } from "../../../../icons";
|
||||
|
||||
@@ -52,11 +50,6 @@ interface ITenantsSummary {
|
||||
loadingTenant: boolean;
|
||||
}
|
||||
|
||||
interface ITenantUsage {
|
||||
used: string;
|
||||
disk_used: string;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...tenantDetailsStyles,
|
||||
@@ -136,9 +129,6 @@ const TenantSummary = ({
|
||||
const [poolCount, setPoolCount] = useState<number>(0);
|
||||
const [instances, setInstances] = useState<number>(0);
|
||||
const [volumes, setVolumes] = useState<number>(0);
|
||||
const [loadingUsage, setLoadingUsage] = useState<boolean>(true);
|
||||
const [usageError, setUsageError] = useState<string>("");
|
||||
const [usage, setUsage] = useState<number>(0);
|
||||
const [updateMinioVersion, setUpdateMinioVersion] = useState<boolean>(false);
|
||||
|
||||
const tenantName = match.params["tenantName"];
|
||||
@@ -154,27 +144,6 @@ const TenantSummary = ({
|
||||
: classes.greyState;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (loadingUsage) {
|
||||
api
|
||||
.invoke(
|
||||
"GET",
|
||||
`/api/v1/namespaces/${tenantNamespace}/tenants/${tenantName}/usage`
|
||||
)
|
||||
.then((result: ITenantUsage) => {
|
||||
const usage = get(result, "disk_used", "0");
|
||||
setUsage(parseInt(usage));
|
||||
setUsageError("");
|
||||
setLoadingUsage(false);
|
||||
})
|
||||
.catch((err: ErrorResponseHandler) => {
|
||||
setUsageError(err.errorMessage);
|
||||
setUsage(0);
|
||||
setLoadingUsage(false);
|
||||
});
|
||||
}
|
||||
}, [tenantName, tenantNamespace, loadingUsage]);
|
||||
|
||||
useEffect(() => {
|
||||
if (tenant) {
|
||||
setCapacity(tenant.total_size || 0);
|
||||
@@ -302,12 +271,12 @@ const TenantSummary = ({
|
||||
) : (
|
||||
<Fragment>
|
||||
<UsageBarWrapper
|
||||
currValue={usage}
|
||||
maxValue={tenant ? tenant.total_size : 0}
|
||||
currValue={tenant?.status?.usage?.raw_usage ?? 0}
|
||||
maxValue={tenant?.status?.usage?.raw ?? 1}
|
||||
label={"Storage"}
|
||||
renderFunction={niceBytes}
|
||||
error={usageError}
|
||||
loading={loadingUsage}
|
||||
error={""}
|
||||
loading={false}
|
||||
/>
|
||||
<h4>
|
||||
{tenant && tenant.status && (
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
import React, { Fragment } from "react";
|
||||
import PageHeader from "../Common/PageHeader/PageHeader";
|
||||
import { Grid } from "@mui/material";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { containerForHeader } from "../Common/FormComponents/common/styleLibrary";
|
||||
import ListTenants from "./ListTenants/ListTenants";
|
||||
|
||||
interface IConfigurationMain {
|
||||
classes: any;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
headerLabel: {
|
||||
fontSize: 22,
|
||||
fontWeight: 600,
|
||||
color: "#000",
|
||||
marginTop: 4,
|
||||
},
|
||||
...containerForHeader(theme.spacing(4)),
|
||||
});
|
||||
|
||||
const TenantsMain = ({ classes }: IConfigurationMain) => {
|
||||
return (
|
||||
<Fragment>
|
||||
<PageHeader label="Tenants" />
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.container}>
|
||||
<ListTenants />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(TenantsMain);
|
||||
@@ -14,11 +14,6 @@ const theme = createTheme({
|
||||
dark: "#ba000d",
|
||||
contrastText: "#000",
|
||||
},
|
||||
error: {
|
||||
light: "#e03a48",
|
||||
main: "#dc1f2e",
|
||||
contrastText: "#fff",
|
||||
},
|
||||
grey: {
|
||||
100: "#f0f0f0",
|
||||
200: "#e6e6e6",
|
||||
@@ -33,6 +28,17 @@ const theme = createTheme({
|
||||
background: {
|
||||
default: "#fff",
|
||||
},
|
||||
success: {
|
||||
main: "#4ccb92",
|
||||
},
|
||||
warning: {
|
||||
main: "#FFBD62",
|
||||
},
|
||||
error: {
|
||||
light: "#e03a48",
|
||||
main: "#C83B51",
|
||||
contrastText: "#fff",
|
||||
},
|
||||
},
|
||||
typography: {
|
||||
fontFamily: ["Lato", "sans-serif"].join(","),
|
||||
|
||||
@@ -30,7 +30,7 @@ const newTheme = createTheme(
|
||||
default: "#F4F4F4",
|
||||
},
|
||||
success: {
|
||||
main: "#32c787",
|
||||
main: "#4ccb92",
|
||||
},
|
||||
warning: {
|
||||
main: "#ffb300",
|
||||
|
||||
@@ -108,7 +108,7 @@ paths:
|
||||
|
||||
/logout:
|
||||
post:
|
||||
summary: Logout from Operator.
|
||||
summary: Logout from Console.
|
||||
operationId: Logout
|
||||
responses:
|
||||
200:
|
||||
|
||||
@@ -108,7 +108,7 @@ paths:
|
||||
|
||||
/logout:
|
||||
post:
|
||||
summary: Logout from Console.
|
||||
summary: Logout from Operator.
|
||||
operationId: Logout
|
||||
responses:
|
||||
200:
|
||||
@@ -1040,6 +1040,21 @@ definitions:
|
||||
format: int32
|
||||
health_status:
|
||||
type: string
|
||||
usage:
|
||||
type: object
|
||||
properties:
|
||||
raw:
|
||||
type: integer
|
||||
format: int64
|
||||
raw_usage:
|
||||
type: integer
|
||||
format: int64
|
||||
capacity:
|
||||
type: integer
|
||||
format: int64
|
||||
capacity_usage:
|
||||
type: integer
|
||||
format: int64
|
||||
tenantSecurityResponse:
|
||||
type: object
|
||||
properties:
|
||||
@@ -1173,6 +1188,18 @@ definitions:
|
||||
type: string
|
||||
health_status:
|
||||
type: string
|
||||
capacity_raw:
|
||||
type: integer
|
||||
format: int64
|
||||
capacity_raw_usage:
|
||||
type: integer
|
||||
format: int64
|
||||
capacity:
|
||||
type: integer
|
||||
format: int64
|
||||
capacity_usage:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
listTenantsResponse:
|
||||
type: object
|
||||
|
||||
Reference in New Issue
Block a user