Tenant Details Thunk (#2072)

Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
This commit is contained in:
Daniel Valdivia
2022-06-02 09:18:16 -07:00
committed by GitHub
parent 41155b3f97
commit 6c5f6934e7
4 changed files with 117 additions and 70 deletions

View File

@@ -26,6 +26,9 @@ import { niceBytes, niceBytesInt } from "../../../../common/utils";
import InformationItem from "./InformationItem";
import TenantCapacity from "./TenantCapacity";
import { DrivesIcon } from "../../../../icons";
import { setTenantName } from "../tenantsSlice";
import { getTenantAsync } from "../thunks/tenantDetailsAsync";
import { useDispatch } from "react-redux";
const styles = (theme: Theme) =>
createStyles({
@@ -104,6 +107,7 @@ interface ITenantListItem {
}
const TenantListItem = ({ tenant, classes }: ITenantListItem) => {
const dispatch = useDispatch();
const healthStatusToClass = (health_status: string) => {
switch (health_status) {
case "red":
@@ -174,6 +178,13 @@ const TenantListItem = ({ tenant, classes }: ITenantListItem) => {
}
const openTenantDetails = () => {
dispatch(
setTenantName({
name: tenant.name,
namespace: tenant.namespace,
})
);
dispatch(getTenantAsync());
history.push(`/namespaces/${tenant.namespace}/tenants/${tenant.name}`);
};

View File

@@ -22,16 +22,12 @@ import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import get from "lodash/get";
import Grid from "@mui/material/Grid";
import { ITenant } from "../ListTenants/types";
import {
containerForHeader,
pageContentStyles,
tenantDetailsStyles,
} from "../../Common/FormComponents/common/styleLibrary";
import { AppState } from "../../../../store";
import { ErrorResponseHandler } from "../../../../common/types";
import api from "../../../../common/api";
import PageHeader from "../../Common/PageHeader/PageHeader";
import { CircleIcon, MinIOTierIconXs, TrashIcon } from "../../../../icons";
import { niceBytes } from "../../../../common/utils";
@@ -46,15 +42,10 @@ import BoxIconButton from "../../Common/BoxIconButton/BoxIconButton";
import withSuspense from "../../Common/Components/withSuspense";
import { IAM_PAGES } from "../../../../common/SecureComponent/permissions";
import { tenantIsOnline } from "../ListTenants/utils";
import {
setErrorSnackMessage,
setSnackBarMessage,
} from "../../../../systemSlice";
import {
setTenantDetailsLoad,
setTenantInfo,
setTenantName,
} from "../tenantsSlice";
import { setSnackBarMessage } from "../../../../systemSlice";
import { setTenantDetailsLoad, setTenantName } from "../tenantsSlice";
import { getTenantAsync } from "../thunks/tenantDetailsAsync";
import { LinearProgress } from "@mui/material";
const TenantYAML = withSuspense(React.lazy(() => import("./TenantYAML")));
const TenantSummary = withSuspense(React.lazy(() => import("./TenantSummary")));
@@ -188,23 +179,21 @@ const TenantDetails = ({ classes, match, history }: ITenantDetailsProps) => {
const tenantNamespace = match.params["tenantNamespace"];
const [deleteOpen, setDeleteOpen] = useState<boolean>(false);
// if the current tenant selected is not the one in the redux, reload it
useEffect(() => {
if (!loadingTenant) {
if (
tenantName !== selectedTenant ||
tenantNamespace !== selectedNamespace
) {
dispatch(
setTenantName({
name: tenantName,
namespace: tenantNamespace,
})
);
dispatch(setTenantDetailsLoad(true));
}
if (
selectedNamespace !== tenantNamespace ||
selectedTenant !== tenantName
) {
dispatch(
setTenantName({
name: tenantName,
namespace: tenantNamespace,
})
);
dispatch(getTenantAsync());
}
}, [
loadingTenant,
selectedTenant,
selectedNamespace,
dispatch,
@@ -212,48 +201,6 @@ const TenantDetails = ({ classes, match, history }: ITenantDetailsProps) => {
tenantNamespace,
]);
useEffect(() => {
if (loadingTenant) {
api
.invoke(
"GET",
`/api/v1/namespaces/${tenantNamespace}/tenants/${tenantName}`
)
.then((res: ITenant) => {
// add computed fields
const resPools = !res.pools ? [] : res.pools;
let totalInstances = 0;
let totalVolumes = 0;
let poolNamedIndex = 0;
for (let pool of resPools) {
const cap =
pool.volumes_per_server *
pool.servers *
pool.volume_configuration.size;
pool.label = `pool-${poolNamedIndex}`;
if (pool.name === undefined || pool.name === "") {
pool.name = pool.label;
}
pool.capacity = niceBytes(cap + "");
pool.volumes = pool.servers * pool.volumes_per_server;
totalInstances += pool.servers;
totalVolumes += pool.volumes;
poolNamedIndex += 1;
}
res.total_instances = totalInstances;
res.total_volumes = totalVolumes;
dispatch(setTenantInfo(res));
dispatch(setTenantDetailsLoad(false));
})
.catch((err: ErrorResponseHandler) => {
dispatch(setErrorSnackMessage(err));
dispatch(setTenantDetailsLoad(false));
});
}
}, [loadingTenant, tenantNamespace, tenantName, dispatch]);
const path = get(match, "path", "/");
const splitSections = path.split("/");
@@ -332,6 +279,11 @@ const TenantDetails = ({ classes, match, history }: ITenantDetailsProps) => {
/>
<PageLayout className={classes.pageContainer}>
{loadingTenant && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
<Grid item xs={12}>
<ScreenTitle
icon={
@@ -417,7 +369,7 @@ const TenantDetails = ({ classes, match, history }: ITenantDetailsProps) => {
variant="outlined"
aria-label="Refresh List"
onClick={() => {
dispatch(setTenantDetailsLoad(true));
dispatch(getTenantAsync());
}}
>
<span>Refresh</span> <RefreshIcon />

View File

@@ -25,6 +25,7 @@ import get from "lodash/get";
import { has } from "lodash";
import { Opts } from "./ListTenants/utils";
import { ITenant } from "./ListTenants/types";
import { getTenantAsync } from "./thunks/tenantDetailsAsync";
export interface FileValue {
fileName: string;
@@ -247,6 +248,19 @@ export const tenantSlice = createSlice({
state.tenantDetails.poolDetailsOpen = action.payload;
},
},
extraReducers: (builder) => {
builder
.addCase(getTenantAsync.pending, (state) => {
state.tenantDetails.loadingTenant = true;
})
.addCase(getTenantAsync.rejected, (state) => {
state.tenantDetails.loadingTenant = false;
})
.addCase(getTenantAsync.fulfilled, (state, action) => {
state.tenantDetails.loadingTenant = false;
state.tenantDetails.tenantInfo = action.payload;
});
},
});
// Action creators are generated for each case reducer function

View File

@@ -0,0 +1,70 @@
// This file is part of MinIO Console Server
// Copyright (c) 2022 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import { createAsyncThunk } from "@reduxjs/toolkit";
import { AppState } from "../../../../store";
import { niceBytes } from "../../../../common/utils";
import { ITenant } from "../ListTenants/types";
import api from "../../../../common/api";
import { ErrorResponseHandler } from "../../../../common/types";
import { setErrorSnackMessage } from "../../../../systemSlice";
export const getTenantAsync = createAsyncThunk(
"tenantDetails/getTenantAsync",
async (_, { getState, rejectWithValue, dispatch }) => {
const state = getState() as AppState;
const currentNamespace = state.tenants.tenantDetails.currentNamespace;
const currentTenant = state.tenants.tenantDetails.currentTenant;
return api
.invoke(
"GET",
`/api/v1/namespaces/${currentNamespace}/tenants/${currentTenant}`
)
.then((res: ITenant) => {
// add computed fields
const resPools = !res.pools ? [] : res.pools;
let totalInstances = 0;
let totalVolumes = 0;
let poolNamedIndex = 0;
for (let pool of resPools) {
const cap =
pool.volumes_per_server *
pool.servers *
pool.volume_configuration.size;
pool.label = `pool-${poolNamedIndex}`;
if (pool.name === undefined || pool.name === "") {
pool.name = pool.label;
}
pool.capacity = niceBytes(cap + "");
pool.volumes = pool.servers * pool.volumes_per_server;
totalInstances += pool.servers;
totalVolumes += pool.volumes;
poolNamedIndex += 1;
}
res.total_instances = totalInstances;
res.total_volumes = totalVolumes;
return res;
})
.catch((err: ErrorResponseHandler) => {
dispatch(setErrorSnackMessage(err));
return rejectWithValue(err);
});
}
);