Add Pool Slice and Tenants Slice simplification (#2074)
Add Pool Slice and Tenants Slice simplification Flatten Slice AddPool Thunk Return HMR support for Redux Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
This commit is contained in:
@@ -63,33 +63,17 @@ const KeyPairView = ({ classes, records, recordName }: IKeyPairView) => {
|
||||
};
|
||||
|
||||
const mapState = (state: AppState) => ({
|
||||
loadingTenant: state.tenants.tenantDetails.loadingTenant,
|
||||
selectedTenant: state.tenants.tenantDetails.currentTenant,
|
||||
tenant: state.tenants.tenantDetails.tenantInfo,
|
||||
logEnabled: get(state.tenants.tenantDetails.tenantInfo, "logEnabled", false),
|
||||
monitoringEnabled: get(
|
||||
state.tenants.tenantDetails.tenantInfo,
|
||||
"monitoringEnabled",
|
||||
false
|
||||
),
|
||||
encryptionEnabled: get(
|
||||
state.tenants.tenantDetails.tenantInfo,
|
||||
"encryptionEnabled",
|
||||
false
|
||||
),
|
||||
minioTLS: get(state.tenants.tenantDetails.tenantInfo, "minioTLS", false),
|
||||
consoleTLS: get(state.tenants.tenantDetails.tenantInfo, "consoleTLS", false),
|
||||
consoleEnabled: get(
|
||||
state.tenants.tenantDetails.tenantInfo,
|
||||
"consoleEnabled",
|
||||
false
|
||||
),
|
||||
adEnabled: get(state.tenants.tenantDetails.tenantInfo, "idpAdEnabled", false),
|
||||
oidcEnabled: get(
|
||||
state.tenants.tenantDetails.tenantInfo,
|
||||
"idpOidcEnabled",
|
||||
false
|
||||
),
|
||||
loadingTenant: state.tenants.loadingTenant,
|
||||
selectedTenant: state.tenants.currentTenant,
|
||||
tenant: state.tenants.tenantInfo,
|
||||
logEnabled: get(state.tenants.tenantInfo, "logEnabled", false),
|
||||
monitoringEnabled: get(state.tenants.tenantInfo, "monitoringEnabled", false),
|
||||
encryptionEnabled: get(state.tenants.tenantInfo, "encryptionEnabled", false),
|
||||
minioTLS: get(state.tenants.tenantInfo, "minioTLS", false),
|
||||
consoleTLS: get(state.tenants.tenantInfo, "consoleTLS", false),
|
||||
consoleEnabled: get(state.tenants.tenantInfo, "consoleEnabled", false),
|
||||
adEnabled: get(state.tenants.tenantInfo, "idpAdEnabled", false),
|
||||
oidcEnabled: get(state.tenants.tenantInfo, "idpOidcEnabled", false),
|
||||
});
|
||||
|
||||
const connector = connect(mapState, null);
|
||||
|
||||
@@ -53,7 +53,7 @@ const PodsSummary = ({ classes, match, history }: IPodsSummary) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const loadingTenant = useSelector(
|
||||
(state: AppState) => state.tenants.tenantDetails.loadingTenant
|
||||
(state: AppState) => state.tenants.loadingTenant
|
||||
);
|
||||
|
||||
const [pods, setPods] = useState<IPodListElement[]>([]);
|
||||
|
||||
@@ -14,18 +14,16 @@
|
||||
// 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, useEffect, useState } 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";
|
||||
import {
|
||||
formFieldStyles,
|
||||
modalStyleUtils,
|
||||
} from "../../../../Common/FormComponents/common/styleLibrary";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { generatePoolName, niceBytes } from "../../../../../../common/utils";
|
||||
import { niceBytes } from "../../../../../../common/utils";
|
||||
import { LinearProgress } from "@mui/material";
|
||||
import { IAddPoolRequest } from "../../../ListTenants/types";
|
||||
import PageHeader from "../../../../Common/PageHeader/PageHeader";
|
||||
import PageLayout from "../../../../Common/Layout/PageLayout";
|
||||
import GenericWizard from "../../../../Common/GenericWizard/GenericWizard";
|
||||
@@ -39,20 +37,12 @@ import { AppState } from "../../../../../../store";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import PoolConfiguration from "./PoolConfiguration";
|
||||
import PoolPodPlacement from "./PoolPodPlacement";
|
||||
import { ErrorResponseHandler } from "../../../../../../common/types";
|
||||
import { getDefaultAffinity, getNodeSelector } from "../../utils";
|
||||
import api from "../../../../../../common/api";
|
||||
import BackLink from "../../../../../../common/BackLink";
|
||||
import { setErrorSnackMessage } from "../../../../../../systemSlice";
|
||||
import { resetPoolForm, setTenantDetailsLoad } from "../../../tenantsSlice";
|
||||
import { resetPoolForm } from "./addPoolSlice";
|
||||
import AddPoolCreateButton from "./AddPoolCreateButton";
|
||||
import makeStyles from "@mui/styles/makeStyles";
|
||||
|
||||
interface IAddPoolProps {
|
||||
classes: any;
|
||||
open: boolean;
|
||||
match: any;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
bottomContainer: {
|
||||
display: "flex",
|
||||
@@ -77,136 +67,20 @@ const styles = (theme: Theme) =>
|
||||
},
|
||||
...formFieldStyles,
|
||||
...modalStyleUtils,
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
const requiredPages = ["setup", "affinity", "configure"];
|
||||
|
||||
const AddPool = ({ classes, open, match }: IAddPoolProps) => {
|
||||
const AddPool = () => {
|
||||
const dispatch = useDispatch();
|
||||
const classes = useStyles();
|
||||
|
||||
const tenant = useSelector(
|
||||
(state: AppState) => state.tenants.tenantDetails.tenantInfo
|
||||
);
|
||||
const selectedStorageClass = useSelector(
|
||||
(state: AppState) => state.tenants.addPool.fields.setup.storageClass
|
||||
);
|
||||
const validPages = useSelector(
|
||||
(state: AppState) => state.tenants.addPool.validPages
|
||||
);
|
||||
const numberOfNodes = useSelector(
|
||||
(state: AppState) => state.tenants.addPool.fields.setup.numberOfNodes
|
||||
);
|
||||
const volumeSize = useSelector(
|
||||
(state: AppState) => state.tenants.addPool.fields.setup.volumeSize
|
||||
);
|
||||
const volumesPerServer = useSelector(
|
||||
(state: AppState) => state.tenants.addPool.fields.setup.volumesPerServer
|
||||
);
|
||||
const affinityType = useSelector(
|
||||
(state: AppState) => state.tenants.addPool.fields.affinity.podAffinity
|
||||
);
|
||||
const nodeSelectorLabels = useSelector(
|
||||
(state: AppState) =>
|
||||
state.tenants.addPool.fields.affinity.nodeSelectorLabels
|
||||
);
|
||||
const withPodAntiAffinity = useSelector(
|
||||
(state: AppState) =>
|
||||
state.tenants.addPool.fields.affinity.withPodAntiAffinity
|
||||
);
|
||||
const tolerations = useSelector(
|
||||
(state: AppState) => state.tenants.addPool.fields.tolerations
|
||||
);
|
||||
const securityContextEnabled = useSelector(
|
||||
(state: AppState) =>
|
||||
state.tenants.addPool.fields.configuration.securityContextEnabled
|
||||
);
|
||||
const securityContext = useSelector(
|
||||
(state: AppState) =>
|
||||
state.tenants.addPool.fields.configuration.securityContext
|
||||
);
|
||||
|
||||
const [addSending, setAddSending] = useState<boolean>(false);
|
||||
const tenant = useSelector((state: AppState) => state.tenants.tenantInfo);
|
||||
const sending = useSelector((state: AppState) => state.addPool.sending);
|
||||
|
||||
const poolsURL = `/namespaces/${tenant?.namespace || ""}/tenants/${
|
||||
tenant?.name || ""
|
||||
}/pools`;
|
||||
|
||||
useEffect(() => {
|
||||
if (addSending && tenant) {
|
||||
const poolName = generatePoolName(tenant.pools);
|
||||
|
||||
let affinityObject = {};
|
||||
|
||||
switch (affinityType) {
|
||||
case "default":
|
||||
affinityObject = {
|
||||
affinity: getDefaultAffinity(tenant.name, poolName),
|
||||
};
|
||||
break;
|
||||
case "nodeSelector":
|
||||
affinityObject = {
|
||||
affinity: getNodeSelector(
|
||||
nodeSelectorLabels,
|
||||
withPodAntiAffinity,
|
||||
tenant.name,
|
||||
poolName
|
||||
),
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
const tolerationValues = tolerations.filter(
|
||||
(toleration) => toleration.key.trim() !== ""
|
||||
);
|
||||
|
||||
const data: IAddPoolRequest = {
|
||||
name: poolName,
|
||||
servers: numberOfNodes,
|
||||
volumes_per_server: volumesPerServer,
|
||||
volume_configuration: {
|
||||
size: volumeSize * 1073741824,
|
||||
storage_class_name: selectedStorageClass,
|
||||
labels: null,
|
||||
},
|
||||
tolerations: tolerationValues,
|
||||
securityContext: securityContextEnabled ? securityContext : null,
|
||||
...affinityObject,
|
||||
};
|
||||
|
||||
api
|
||||
.invoke(
|
||||
"POST",
|
||||
`/api/v1/namespaces/${tenant.namespace}/tenants/${tenant.name}/pools`,
|
||||
data
|
||||
)
|
||||
.then(() => {
|
||||
setAddSending(false);
|
||||
dispatch(resetPoolForm());
|
||||
dispatch(setTenantDetailsLoad(true));
|
||||
history.push(poolsURL);
|
||||
})
|
||||
.catch((err: ErrorResponseHandler) => {
|
||||
setAddSending(false);
|
||||
dispatch(setErrorSnackMessage(err));
|
||||
});
|
||||
}
|
||||
}, [
|
||||
addSending,
|
||||
poolsURL,
|
||||
affinityType,
|
||||
nodeSelectorLabels,
|
||||
numberOfNodes,
|
||||
securityContext,
|
||||
securityContextEnabled,
|
||||
selectedStorageClass,
|
||||
tenant,
|
||||
tolerations,
|
||||
volumeSize,
|
||||
volumesPerServer,
|
||||
withPodAntiAffinity,
|
||||
dispatch,
|
||||
]);
|
||||
|
||||
const cancelButton = {
|
||||
label: "Cancel",
|
||||
type: "other",
|
||||
@@ -218,15 +92,7 @@ const AddPool = ({ classes, open, match }: IAddPoolProps) => {
|
||||
};
|
||||
|
||||
const createButton = {
|
||||
label: "Create",
|
||||
type: "submit",
|
||||
enabled:
|
||||
!addSending &&
|
||||
selectedStorageClass !== "" &&
|
||||
requiredPages.every((v) => validPages.includes(v)),
|
||||
action: () => {
|
||||
setAddSending(true);
|
||||
},
|
||||
componentRender: <AddPoolCreateButton key={"add-pool-crate"} />,
|
||||
};
|
||||
|
||||
const wizardSteps: IWizardElement[] = [
|
||||
@@ -272,8 +138,7 @@ const AddPool = ({ classes, open, match }: IAddPoolProps) => {
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{addSending && (
|
||||
{sending && (
|
||||
<Grid item xs={12}>
|
||||
<LinearProgress />
|
||||
</Grid>
|
||||
@@ -287,4 +152,4 @@ const AddPool = ({ classes, open, match }: IAddPoolProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(AddPool);
|
||||
export default AddPool;
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
// 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 { Button } from "@mui/material";
|
||||
import React from "react";
|
||||
import { addPoolAsync } from "./addPoolThunks";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { AppState } from "../../../../../../store";
|
||||
|
||||
const AddPoolCreateButton = () => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const selectedStorageClass = useSelector(
|
||||
(state: AppState) => state.addPool.setup.storageClass
|
||||
);
|
||||
const validPages = useSelector((state: AppState) => state.addPool.validPages);
|
||||
|
||||
const sending = useSelector((state: AppState) => state.addPool.sending);
|
||||
const requiredPages = ["setup", "affinity", "configure"];
|
||||
const enabled =
|
||||
!sending &&
|
||||
selectedStorageClass !== "" &&
|
||||
requiredPages.every((v) => validPages.includes(v));
|
||||
return (
|
||||
<Button
|
||||
id={"wizard-button-Create"}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
dispatch(addPoolAsync());
|
||||
}}
|
||||
disabled={!enabled}
|
||||
key={`button-AddTenant-Create`}
|
||||
>
|
||||
Create
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddPoolCreateButton;
|
||||
@@ -33,7 +33,7 @@ import {
|
||||
} from "../../../../../../utils/validationFunctions";
|
||||
import FormSwitchWrapper from "../../../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
|
||||
import InputBoxWrapper from "../../../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import { isPoolPageValid, setPoolField } from "../../../tenantsSlice";
|
||||
import { isPoolPageValid, setPoolField } from "./addPoolSlice";
|
||||
|
||||
interface IConfigureProps {
|
||||
classes: any;
|
||||
@@ -81,12 +81,10 @@ const PoolConfiguration = ({ classes }: IConfigureProps) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const securityContextEnabled = useSelector(
|
||||
(state: AppState) =>
|
||||
state.tenants.addPool.fields.configuration.securityContextEnabled
|
||||
(state: AppState) => state.addPool.configuration.securityContextEnabled
|
||||
);
|
||||
const securityContext = useSelector(
|
||||
(state: AppState) =>
|
||||
state.tenants.addPool.fields.configuration.securityContext
|
||||
(state: AppState) => state.addPool.configuration.securityContext
|
||||
);
|
||||
|
||||
const [validationErrors, setValidationErrors] = useState<any>({});
|
||||
|
||||
@@ -48,7 +48,7 @@ import {
|
||||
setPoolField,
|
||||
setPoolKeyValuePairs,
|
||||
setPoolTolerationInfo,
|
||||
} from "../../../tenantsSlice";
|
||||
} from "./addPoolSlice";
|
||||
|
||||
interface IAffinityProps {
|
||||
classes: any;
|
||||
@@ -119,21 +119,19 @@ const Affinity = ({ classes }: IAffinityProps) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const podAffinity = useSelector(
|
||||
(state: AppState) => state.tenants.addPool.fields.affinity.podAffinity
|
||||
(state: AppState) => state.addPool.affinity.podAffinity
|
||||
);
|
||||
const nodeSelectorLabels = useSelector(
|
||||
(state: AppState) =>
|
||||
state.tenants.addPool.fields.affinity.nodeSelectorLabels
|
||||
(state: AppState) => state.addPool.affinity.nodeSelectorLabels
|
||||
);
|
||||
const withPodAntiAffinity = useSelector(
|
||||
(state: AppState) =>
|
||||
state.tenants.addPool.fields.affinity.withPodAntiAffinity
|
||||
(state: AppState) => state.addPool.affinity.withPodAntiAffinity
|
||||
);
|
||||
const keyValuePairs = useSelector(
|
||||
(state: AppState) => state.tenants.addPool.fields.nodeSelectorPairs
|
||||
(state: AppState) => state.addPool.nodeSelectorPairs
|
||||
);
|
||||
const tolerations = useSelector(
|
||||
(state: AppState) => state.tenants.addPool.fields.tolerations
|
||||
(state: AppState) => state.addPool.tolerations
|
||||
);
|
||||
|
||||
const [validationErrors, setValidationErrors] = useState<any>({});
|
||||
|
||||
@@ -43,7 +43,7 @@ import {
|
||||
isPoolPageValid,
|
||||
setPoolField,
|
||||
setPoolStorageClasses,
|
||||
} from "../../../tenantsSlice";
|
||||
} from "./addPoolSlice";
|
||||
|
||||
interface IPoolResourcesProps {
|
||||
classes: any;
|
||||
@@ -86,23 +86,21 @@ const styles = (theme: Theme) =>
|
||||
const PoolResources = ({ classes }: IPoolResourcesProps) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const tenant = useSelector(
|
||||
(state: AppState) => state.tenants.tenantDetails.tenantInfo
|
||||
);
|
||||
const tenant = useSelector((state: AppState) => state.tenants.tenantInfo);
|
||||
const storageClasses = useSelector(
|
||||
(state: AppState) => state.tenants.addPool.storageClasses
|
||||
(state: AppState) => state.addPool.storageClasses
|
||||
);
|
||||
const numberOfNodes = useSelector((state: AppState) =>
|
||||
state.tenants.addPool.fields.setup.numberOfNodes.toString()
|
||||
state.addPool.setup.numberOfNodes.toString()
|
||||
);
|
||||
const storageClass = useSelector(
|
||||
(state: AppState) => state.tenants.addPool.fields.setup.storageClass
|
||||
(state: AppState) => state.addPool.setup.storageClass
|
||||
);
|
||||
const volumeSize = useSelector((state: AppState) =>
|
||||
state.tenants.addPool.fields.setup.volumeSize.toString()
|
||||
state.addPool.setup.volumeSize.toString()
|
||||
);
|
||||
const volumesPerServer = useSelector((state: AppState) =>
|
||||
state.tenants.addPool.fields.setup.volumesPerServer.toString()
|
||||
state.addPool.setup.volumesPerServer.toString()
|
||||
);
|
||||
|
||||
const [validationErrors, setValidationErrors] = useState<any>({});
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
// 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 { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
import {
|
||||
ITolerationEffect,
|
||||
ITolerationModel,
|
||||
ITolerationOperator,
|
||||
} from "../../../../../../common/types";
|
||||
import {
|
||||
IAddPoolSetup,
|
||||
IPoolConfiguration,
|
||||
ITenantAffinity,
|
||||
LabelKeyPair,
|
||||
} from "../../../types";
|
||||
import { has } from "lodash";
|
||||
import get from "lodash/get";
|
||||
import { Opts } from "../../../ListTenants/utils";
|
||||
import { addPoolAsync } from "./addPoolThunks";
|
||||
|
||||
export interface IAddPool {
|
||||
addPoolLoading: boolean;
|
||||
sending: boolean;
|
||||
validPages: string[];
|
||||
storageClasses: Opts[];
|
||||
limitSize: any;
|
||||
setup: IAddPoolSetup;
|
||||
affinity: ITenantAffinity;
|
||||
configuration: IPoolConfiguration;
|
||||
tolerations: ITolerationModel[];
|
||||
nodeSelectorPairs: LabelKeyPair[];
|
||||
}
|
||||
|
||||
const initialState: IAddPool = {
|
||||
addPoolLoading: false,
|
||||
sending: false,
|
||||
validPages: ["affinity", "configure"],
|
||||
storageClasses: [],
|
||||
limitSize: {},
|
||||
setup: {
|
||||
numberOfNodes: 0,
|
||||
storageClass: "",
|
||||
volumeSize: 0,
|
||||
volumesPerServer: 0,
|
||||
},
|
||||
affinity: {
|
||||
nodeSelectorLabels: "",
|
||||
podAffinity: "default",
|
||||
withPodAntiAffinity: true,
|
||||
},
|
||||
configuration: {
|
||||
securityContextEnabled: false,
|
||||
securityContext: {
|
||||
runAsUser: "1000",
|
||||
runAsGroup: "1000",
|
||||
fsGroup: "1000",
|
||||
runAsNonRoot: true,
|
||||
},
|
||||
},
|
||||
nodeSelectorPairs: [{ key: "", value: "" }],
|
||||
tolerations: [
|
||||
{
|
||||
key: "",
|
||||
tolerationSeconds: { seconds: 0 },
|
||||
value: "",
|
||||
effect: ITolerationEffect.NoSchedule,
|
||||
operator: ITolerationOperator.Equal,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const addPoolSlice = createSlice({
|
||||
name: "addPool",
|
||||
initialState,
|
||||
reducers: {
|
||||
setPoolLoading: (state, action: PayloadAction<boolean>) => {
|
||||
state.addPoolLoading = action.payload;
|
||||
},
|
||||
setPoolField: (
|
||||
state,
|
||||
action: PayloadAction<{
|
||||
page:
|
||||
| "setup"
|
||||
| "affinity"
|
||||
| "configuration"
|
||||
| "tolerations"
|
||||
| "nodeSelectorPairs";
|
||||
field: string;
|
||||
value: any;
|
||||
}>
|
||||
) => {
|
||||
if (has(state, `${action.payload.page}.${action.payload.field}`)) {
|
||||
const originPageNameItems = get(state, `${action.payload.page}`, {});
|
||||
|
||||
let newValue: any = {};
|
||||
newValue[action.payload.field] = action.payload.value;
|
||||
|
||||
state[action.payload.page] = {
|
||||
...originPageNameItems,
|
||||
...newValue,
|
||||
};
|
||||
}
|
||||
},
|
||||
isPoolPageValid: (
|
||||
state,
|
||||
action: PayloadAction<{
|
||||
page: string;
|
||||
status: boolean;
|
||||
}>
|
||||
) => {
|
||||
if (action.payload.status) {
|
||||
if (!state.validPages.includes(action.payload.page)) {
|
||||
state.validPages.push(action.payload.page);
|
||||
}
|
||||
} else {
|
||||
state.validPages = state.validPages.filter(
|
||||
(elm) => elm !== action.payload.page
|
||||
);
|
||||
}
|
||||
},
|
||||
setPoolStorageClasses: (state, action: PayloadAction<Opts[]>) => {
|
||||
state.storageClasses = action.payload;
|
||||
},
|
||||
setPoolTolerationInfo: (
|
||||
state,
|
||||
action: PayloadAction<{
|
||||
index: number;
|
||||
tolerationValue: ITolerationModel;
|
||||
}>
|
||||
) => {
|
||||
state.tolerations[action.payload.index] = action.payload.tolerationValue;
|
||||
},
|
||||
addNewPoolToleration: (state) => {
|
||||
state.tolerations.push({
|
||||
key: "",
|
||||
tolerationSeconds: { seconds: 0 },
|
||||
value: "",
|
||||
effect: ITolerationEffect.NoSchedule,
|
||||
operator: ITolerationOperator.Equal,
|
||||
});
|
||||
},
|
||||
removePoolToleration: (state, action: PayloadAction<number>) => {
|
||||
state.tolerations = state.tolerations.filter(
|
||||
(_, index) => index !== action.payload
|
||||
);
|
||||
},
|
||||
setPoolKeyValuePairs: (state, action: PayloadAction<LabelKeyPair[]>) => {
|
||||
state.nodeSelectorPairs = action.payload;
|
||||
},
|
||||
resetPoolForm: () => initialState,
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
builder
|
||||
.addCase(addPoolAsync.pending, (state) => {
|
||||
state.sending = true;
|
||||
})
|
||||
.addCase(addPoolAsync.rejected, (state) => {
|
||||
state.sending = false;
|
||||
})
|
||||
.addCase(addPoolAsync.fulfilled, (state, action) => {
|
||||
state.sending = false;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export const {
|
||||
setPoolLoading,
|
||||
resetPoolForm,
|
||||
setPoolField,
|
||||
isPoolPageValid,
|
||||
setPoolStorageClasses,
|
||||
setPoolTolerationInfo,
|
||||
addNewPoolToleration,
|
||||
removePoolToleration,
|
||||
setPoolKeyValuePairs,
|
||||
} = addPoolSlice.actions;
|
||||
|
||||
export default addPoolSlice.reducer;
|
||||
@@ -0,0 +1,107 @@
|
||||
// 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 api from "../../../../../../common/api";
|
||||
import { IAddPoolRequest } from "../../../ListTenants/types";
|
||||
import { generatePoolName } from "../../../../../../common/utils";
|
||||
import { ErrorResponseHandler } from "../../../../../../common/types";
|
||||
import { setErrorSnackMessage } from "../../../../../../systemSlice";
|
||||
import { getDefaultAffinity, getNodeSelector } from "../../utils";
|
||||
import { resetPoolForm } from "./addPoolSlice";
|
||||
import { getTenantAsync } from "../../../thunks/tenantDetailsAsync";
|
||||
import history from "../../../../../../history";
|
||||
|
||||
export const addPoolAsync = createAsyncThunk(
|
||||
"addPool/addPoolAsync",
|
||||
async (_, { getState, rejectWithValue, dispatch }) => {
|
||||
const state = getState() as AppState;
|
||||
|
||||
const tenant = state.tenants.tenantInfo;
|
||||
const selectedStorageClass = state.addPool.setup.storageClass;
|
||||
const numberOfNodes = state.addPool.setup.numberOfNodes;
|
||||
const volumeSize = state.addPool.setup.volumeSize;
|
||||
const volumesPerServer = state.addPool.setup.volumesPerServer;
|
||||
const affinityType = state.addPool.affinity.podAffinity;
|
||||
const nodeSelectorLabels = state.addPool.affinity.nodeSelectorLabels;
|
||||
const withPodAntiAffinity = state.addPool.affinity.withPodAntiAffinity;
|
||||
const tolerations = state.addPool.tolerations;
|
||||
const securityContextEnabled =
|
||||
state.addPool.configuration.securityContextEnabled;
|
||||
const securityContext = state.addPool.configuration.securityContext;
|
||||
if (tenant === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const poolName = generatePoolName(tenant.pools);
|
||||
|
||||
let affinityObject = {};
|
||||
|
||||
switch (affinityType) {
|
||||
case "default":
|
||||
affinityObject = {
|
||||
affinity: getDefaultAffinity(tenant.name, poolName),
|
||||
};
|
||||
break;
|
||||
case "nodeSelector":
|
||||
affinityObject = {
|
||||
affinity: getNodeSelector(
|
||||
nodeSelectorLabels,
|
||||
withPodAntiAffinity,
|
||||
tenant.name,
|
||||
poolName
|
||||
),
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
const tolerationValues = tolerations.filter(
|
||||
(toleration) => toleration.key.trim() !== ""
|
||||
);
|
||||
|
||||
const data: IAddPoolRequest = {
|
||||
name: poolName,
|
||||
servers: numberOfNodes,
|
||||
volumes_per_server: volumesPerServer,
|
||||
volume_configuration: {
|
||||
size: volumeSize * 1073741824,
|
||||
storage_class_name: selectedStorageClass,
|
||||
labels: null,
|
||||
},
|
||||
tolerations: tolerationValues,
|
||||
securityContext: securityContextEnabled ? securityContext : null,
|
||||
...affinityObject,
|
||||
};
|
||||
const poolsURL = `/namespaces/${tenant?.namespace || ""}/tenants/${
|
||||
tenant?.name || ""
|
||||
}/pools`;
|
||||
return api
|
||||
.invoke(
|
||||
"POST",
|
||||
`/api/v1/namespaces/${tenant.namespace}/tenants/${tenant.name}/pools`,
|
||||
data
|
||||
)
|
||||
.then(() => {
|
||||
dispatch(resetPoolForm());
|
||||
dispatch(getTenantAsync());
|
||||
history.push(poolsURL);
|
||||
})
|
||||
.catch((err: ErrorResponseHandler) => {
|
||||
dispatch(setErrorSnackMessage(err));
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -66,11 +66,9 @@ const twoColCssGridLayoutConfig = {
|
||||
};
|
||||
|
||||
const PoolDetails = ({ history }: IPoolDetails) => {
|
||||
const tenant = useSelector(
|
||||
(state: AppState) => state.tenants.tenantDetails.tenantInfo
|
||||
);
|
||||
const tenant = useSelector((state: AppState) => state.tenants.tenantInfo);
|
||||
const selectedPool = useSelector(
|
||||
(state: AppState) => state.tenants.tenantDetails.selectedPool
|
||||
(state: AppState) => state.tenants.selectedPool
|
||||
);
|
||||
|
||||
const poolInformation =
|
||||
|
||||
@@ -59,11 +59,9 @@ const PoolsListing = ({
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const loadingTenant = useSelector(
|
||||
(state: AppState) => state.tenants.tenantDetails.loadingTenant
|
||||
);
|
||||
const tenant = useSelector(
|
||||
(state: AppState) => state.tenants.tenantDetails.tenantInfo
|
||||
(state: AppState) => state.tenants.loadingTenant
|
||||
);
|
||||
const tenant = useSelector((state: AppState) => state.tenants.tenantInfo);
|
||||
|
||||
const [pools, setPools] = useState<IPool[]>([]);
|
||||
const [filter, setFilter] = useState<string>("");
|
||||
|
||||
@@ -74,11 +74,9 @@ const EditPool = () => {
|
||||
const dispatch = useDispatch();
|
||||
const classes = useStyles();
|
||||
|
||||
const tenant = useSelector(
|
||||
(state: AppState) => state.tenants.tenantDetails.tenantInfo
|
||||
);
|
||||
const tenant = useSelector((state: AppState) => state.tenants.tenantInfo);
|
||||
const selectedPool = useSelector(
|
||||
(state: AppState) => state.tenants.tenantDetails.selectedPool
|
||||
(state: AppState) => state.tenants.selectedPool
|
||||
);
|
||||
|
||||
const editSending = useSelector(
|
||||
|
||||
@@ -86,9 +86,7 @@ const styles = (theme: Theme) =>
|
||||
const PoolResources = ({ classes }: IPoolResourcesProps) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const tenant = useSelector(
|
||||
(state: AppState) => state.tenants.tenantDetails.tenantInfo
|
||||
);
|
||||
const tenant = useSelector((state: AppState) => state.tenants.tenantInfo);
|
||||
const storageClasses = useSelector(
|
||||
(state: AppState) => state.editPool.storageClasses
|
||||
);
|
||||
|
||||
@@ -31,8 +31,8 @@ export const editPoolAsync = createAsyncThunk(
|
||||
async (_, { getState, rejectWithValue, dispatch }) => {
|
||||
const state = getState() as AppState;
|
||||
|
||||
const tenant = state.tenants.tenantDetails.tenantInfo;
|
||||
const selectedPool = state.tenants.tenantDetails.selectedPool;
|
||||
const tenant = state.tenants.tenantInfo;
|
||||
const selectedPool = state.tenants.selectedPool;
|
||||
const selectedStorageClass = state.editPool.fields.setup.storageClass;
|
||||
const numberOfNodes = state.editPool.fields.setup.numberOfNodes;
|
||||
const volumeSize = state.editPool.fields.setup.volumeSize;
|
||||
|
||||
@@ -52,10 +52,10 @@ const PoolsSummary = ({ classes, history, match }: IPoolsSummary) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const selectedPool = useSelector(
|
||||
(state: AppState) => state.tenants.tenantDetails.selectedPool
|
||||
(state: AppState) => state.tenants.selectedPool
|
||||
);
|
||||
const poolDetailsOpen = useSelector(
|
||||
(state: AppState) => state.tenants.tenantDetails.poolDetailsOpen
|
||||
(state: AppState) => state.tenants.poolDetailsOpen
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -161,17 +161,15 @@ const TenantDetails = ({ classes, match, history }: ITenantDetailsProps) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const loadingTenant = useSelector(
|
||||
(state: AppState) => state.tenants.tenantDetails.loadingTenant
|
||||
(state: AppState) => state.tenants.loadingTenant
|
||||
);
|
||||
const selectedTenant = useSelector(
|
||||
(state: AppState) => state.tenants.tenantDetails.currentTenant
|
||||
(state: AppState) => state.tenants.currentTenant
|
||||
);
|
||||
const selectedNamespace = useSelector(
|
||||
(state: AppState) => state.tenants.tenantDetails.currentNamespace
|
||||
);
|
||||
const tenantInfo = useSelector(
|
||||
(state: AppState) => state.tenants.tenantDetails.tenantInfo
|
||||
(state: AppState) => state.tenants.currentNamespace
|
||||
);
|
||||
const tenantInfo = useSelector((state: AppState) => state.tenants.tenantInfo);
|
||||
|
||||
const [yamlScreenOpen, setYamlScreenOpen] = useState<boolean>(false);
|
||||
|
||||
|
||||
@@ -87,9 +87,7 @@ const styles = (theme: Theme) =>
|
||||
const TenantEncryption = ({ classes }: ITenantEncryption) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const tenant = useSelector(
|
||||
(state: AppState) => state.tenants.tenantDetails.tenantInfo
|
||||
);
|
||||
const tenant = useSelector((state: AppState) => state.tenants.tenantInfo);
|
||||
|
||||
const [encryptionEnabled, setEncryptionEnabled] = useState<boolean>(false);
|
||||
const [encryptionType, setEncryptionType] = useState<string>("vault");
|
||||
|
||||
@@ -98,7 +98,7 @@ const TenantEvents = ({
|
||||
);
|
||||
};
|
||||
const mapState = (state: AppState) => ({
|
||||
loadingTenant: state.tenants.tenantDetails.loadingTenant,
|
||||
loadingTenant: state.tenants.loadingTenant,
|
||||
});
|
||||
const connector = connect(mapState, null);
|
||||
|
||||
|
||||
@@ -594,9 +594,9 @@ const TenantIdentityProvider = ({
|
||||
};
|
||||
|
||||
const mapState = (state: AppState) => ({
|
||||
loadingTenant: state.tenants.tenantDetails.loadingTenant,
|
||||
selectedTenant: state.tenants.tenantDetails.currentTenant,
|
||||
tenant: state.tenants.tenantDetails.tenantInfo,
|
||||
loadingTenant: state.tenants.loadingTenant,
|
||||
selectedTenant: state.tenants.currentTenant,
|
||||
tenant: state.tenants.tenantInfo,
|
||||
});
|
||||
|
||||
const connector = connect(mapState, null);
|
||||
|
||||
@@ -50,11 +50,9 @@ const TenantLicense = ({ classes }: ITenantLicense) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const loadingTenant = useSelector(
|
||||
(state: AppState) => state.tenants.tenantDetails.loadingTenant
|
||||
);
|
||||
const tenant = useSelector(
|
||||
(state: AppState) => state.tenants.tenantDetails.tenantInfo
|
||||
(state: AppState) => state.tenants.loadingTenant
|
||||
);
|
||||
const tenant = useSelector((state: AppState) => state.tenants.tenantInfo);
|
||||
|
||||
const [licenseInfo, setLicenseInfo] = useState<SubnetInfo>();
|
||||
const [loadingLicenseInfo, setLoadingLicenseInfo] = useState<boolean>(true);
|
||||
|
||||
@@ -489,9 +489,9 @@ const TenantLogging = ({
|
||||
};
|
||||
|
||||
const mapState = (state: AppState) => ({
|
||||
loadingTenant: state.tenants.tenantDetails.loadingTenant,
|
||||
selectedTenant: state.tenants.tenantDetails.currentTenant,
|
||||
tenant: state.tenants.tenantDetails.tenantInfo,
|
||||
loadingTenant: state.tenants.loadingTenant,
|
||||
selectedTenant: state.tenants.currentTenant,
|
||||
tenant: state.tenants.tenantInfo,
|
||||
});
|
||||
|
||||
const connector = connect(mapState, null);
|
||||
|
||||
@@ -531,9 +531,9 @@ const TenantSecurity = ({
|
||||
};
|
||||
|
||||
const mapState = (state: AppState) => ({
|
||||
loadingTenant: state.tenants.tenantDetails.loadingTenant,
|
||||
selectedTenant: state.tenants.tenantDetails.currentTenant,
|
||||
tenant: state.tenants.tenantDetails.tenantInfo,
|
||||
loadingTenant: state.tenants.loadingTenant,
|
||||
selectedTenant: state.tenants.currentTenant,
|
||||
tenant: state.tenants.tenantInfo,
|
||||
});
|
||||
|
||||
const connector = connect(mapState, null);
|
||||
|
||||
@@ -184,26 +184,24 @@ const featureItemStyleProps = {
|
||||
const TenantSummary = ({ classes, match }: ITenantsSummary) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const tenant = useSelector(
|
||||
(state: AppState) => state.tenants.tenantDetails.tenantInfo
|
||||
);
|
||||
const tenant = useSelector((state: AppState) => state.tenants.tenantInfo);
|
||||
const logEnabled = useSelector((state: AppState) =>
|
||||
get(state.tenants.tenantDetails.tenantInfo, "logEnabled", false)
|
||||
get(state.tenants.tenantInfo, "logEnabled", false)
|
||||
);
|
||||
const monitoringEnabled = useSelector((state: AppState) =>
|
||||
get(state.tenants.tenantDetails.tenantInfo, "monitoringEnabled", false)
|
||||
get(state.tenants.tenantInfo, "monitoringEnabled", false)
|
||||
);
|
||||
const encryptionEnabled = useSelector((state: AppState) =>
|
||||
get(state.tenants.tenantDetails.tenantInfo, "encryptionEnabled", false)
|
||||
get(state.tenants.tenantInfo, "encryptionEnabled", false)
|
||||
);
|
||||
const minioTLS = useSelector((state: AppState) =>
|
||||
get(state.tenants.tenantDetails.tenantInfo, "minioTLS", false)
|
||||
get(state.tenants.tenantInfo, "minioTLS", false)
|
||||
);
|
||||
const adEnabled = useSelector((state: AppState) =>
|
||||
get(state.tenants.tenantDetails.tenantInfo, "idpAdEnabled", false)
|
||||
get(state.tenants.tenantInfo, "idpAdEnabled", false)
|
||||
);
|
||||
const oidcEnabled = useSelector((state: AppState) =>
|
||||
get(state.tenants.tenantDetails.tenantInfo, "idpOidcEnabled", false)
|
||||
get(state.tenants.tenantInfo, "idpOidcEnabled", false)
|
||||
);
|
||||
|
||||
const [poolCount, setPoolCount] = useState<number>(0);
|
||||
|
||||
@@ -55,7 +55,7 @@ const TenantVolumes = ({ classes, history, match }: ITenantVolumesProps) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const loadingTenant = useSelector(
|
||||
(state: AppState) => state.tenants.tenantDetails.loadingTenant
|
||||
(state: AppState) => state.tenants.loadingTenant
|
||||
);
|
||||
|
||||
const [records, setRecords] = useState<IStoragePVCs[]>([]);
|
||||
|
||||
@@ -406,7 +406,7 @@ const PodDescribe = ({
|
||||
}: IPodEventsProps) => {
|
||||
const dispatch = useDispatch();
|
||||
const loadingTenant = useSelector(
|
||||
(state: AppState) => state.tenants.tenantDetails.loadingTenant
|
||||
(state: AppState) => state.tenants.loadingTenant
|
||||
);
|
||||
|
||||
const [describeInfo, setDescribeInfo] = useState<DescribeResponse>();
|
||||
|
||||
@@ -63,7 +63,7 @@ const PodEvents = ({
|
||||
}: IPodEventsProps) => {
|
||||
const dispatch = useDispatch();
|
||||
const loadingTenant = useSelector(
|
||||
(state: AppState) => state.tenants.tenantDetails.loadingTenant
|
||||
(state: AppState) => state.tenants.loadingTenant
|
||||
);
|
||||
const [events, setEvents] = useState<IEvent[]>([]);
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
|
||||
@@ -92,7 +92,7 @@ const PodLogs = ({
|
||||
}: IPodLogsProps) => {
|
||||
const dispatch = useDispatch();
|
||||
const loadingTenant = useSelector(
|
||||
(state: AppState) => state.tenants.tenantDetails.loadingTenant
|
||||
(state: AppState) => state.tenants.loadingTenant
|
||||
);
|
||||
const [highlight, setHighlight] = useState<string>("");
|
||||
const [logLines, setLogLines] = useState<string[]>([]);
|
||||
|
||||
@@ -215,7 +215,7 @@ const PVCDescribe = ({
|
||||
);
|
||||
};
|
||||
const mapState = (state: AppState) => ({
|
||||
loadingTenant: state.tenants.tenantDetails.loadingTenant,
|
||||
loadingTenant: state.tenants.loadingTenant,
|
||||
});
|
||||
const connector = connect(mapState, {
|
||||
setErrorSnackMessage,
|
||||
|
||||
@@ -15,15 +15,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
import { IAddPoolFields, ITenantState, LabelKeyPair } from "./types";
|
||||
import {
|
||||
ITolerationEffect,
|
||||
ITolerationModel,
|
||||
ITolerationOperator,
|
||||
} from "../../../common/types";
|
||||
import get from "lodash/get";
|
||||
import { has } from "lodash";
|
||||
import { Opts } from "./ListTenants/utils";
|
||||
import { ITenantState } from "./types";
|
||||
import { ITenant } from "./ListTenants/types";
|
||||
import { getTenantAsync } from "./thunks/tenantDetailsAsync";
|
||||
|
||||
@@ -46,53 +38,13 @@ export interface CertificateFile {
|
||||
}
|
||||
|
||||
const initialState: ITenantState = {
|
||||
tenantDetails: {
|
||||
currentTenant: "",
|
||||
currentNamespace: "",
|
||||
loadingTenant: false,
|
||||
tenantInfo: null,
|
||||
currentTab: "summary",
|
||||
selectedPool: null,
|
||||
poolDetailsOpen: false,
|
||||
},
|
||||
addPool: {
|
||||
addPoolLoading: false,
|
||||
validPages: ["affinity", "configure"],
|
||||
storageClasses: [],
|
||||
limitSize: {},
|
||||
fields: {
|
||||
setup: {
|
||||
numberOfNodes: 0,
|
||||
storageClass: "",
|
||||
volumeSize: 0,
|
||||
volumesPerServer: 0,
|
||||
},
|
||||
affinity: {
|
||||
nodeSelectorLabels: "",
|
||||
podAffinity: "default",
|
||||
withPodAntiAffinity: true,
|
||||
},
|
||||
configuration: {
|
||||
securityContextEnabled: false,
|
||||
securityContext: {
|
||||
runAsUser: "1000",
|
||||
runAsGroup: "1000",
|
||||
fsGroup: "1000",
|
||||
runAsNonRoot: true,
|
||||
},
|
||||
},
|
||||
nodeSelectorPairs: [{ key: "", value: "" }],
|
||||
tolerations: [
|
||||
{
|
||||
key: "",
|
||||
tolerationSeconds: { seconds: 0 },
|
||||
value: "",
|
||||
effect: ITolerationEffect.NoSchedule,
|
||||
operator: ITolerationOperator.Equal,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
currentTenant: "",
|
||||
currentNamespace: "",
|
||||
loadingTenant: false,
|
||||
tenantInfo: null,
|
||||
currentTab: "summary",
|
||||
selectedPool: null,
|
||||
poolDetailsOpen: false,
|
||||
};
|
||||
|
||||
export const tenantSlice = createSlice({
|
||||
@@ -100,7 +52,7 @@ export const tenantSlice = createSlice({
|
||||
initialState,
|
||||
reducers: {
|
||||
setTenantDetailsLoad: (state, action: PayloadAction<boolean>) => {
|
||||
state.tenantDetails.loadingTenant = action.payload;
|
||||
state.loadingTenant = action.payload;
|
||||
},
|
||||
setTenantName: (
|
||||
state,
|
||||
@@ -109,156 +61,36 @@ export const tenantSlice = createSlice({
|
||||
namespace: string;
|
||||
}>
|
||||
) => {
|
||||
state.tenantDetails.currentTenant = action.payload.name;
|
||||
state.tenantDetails.currentNamespace = action.payload.namespace;
|
||||
state.currentTenant = action.payload.name;
|
||||
state.currentNamespace = action.payload.namespace;
|
||||
},
|
||||
setTenantInfo: (state, action: PayloadAction<ITenant | null>) => {
|
||||
if (action.payload) {
|
||||
state.tenantDetails.tenantInfo = action.payload;
|
||||
state.tenantInfo = action.payload;
|
||||
}
|
||||
},
|
||||
setTenantTab: (state, action: PayloadAction<string>) => {
|
||||
state.tenantDetails.currentTab = action.payload;
|
||||
state.currentTab = action.payload;
|
||||
},
|
||||
|
||||
setPoolLoading: (state, action: PayloadAction<boolean>) => {
|
||||
state.addPool.addPoolLoading = action.payload;
|
||||
},
|
||||
setPoolField: (
|
||||
state,
|
||||
action: PayloadAction<{
|
||||
page: keyof IAddPoolFields;
|
||||
field: string;
|
||||
value: any;
|
||||
}>
|
||||
) => {
|
||||
if (
|
||||
has(
|
||||
state.addPool.fields,
|
||||
`${action.payload.page}.${action.payload.field}`
|
||||
)
|
||||
) {
|
||||
const originPageNameItems = get(
|
||||
state.addPool.fields,
|
||||
`${action.payload.page}`,
|
||||
{}
|
||||
);
|
||||
|
||||
let newValue: any = {};
|
||||
newValue[action.payload.field] = action.payload.value;
|
||||
|
||||
state.addPool.fields[action.payload.page] = {
|
||||
...originPageNameItems,
|
||||
...newValue,
|
||||
};
|
||||
}
|
||||
},
|
||||
isPoolPageValid: (
|
||||
state,
|
||||
action: PayloadAction<{
|
||||
page: string;
|
||||
status: boolean;
|
||||
}>
|
||||
) => {
|
||||
if (action.payload.status) {
|
||||
if (!state.addPool.validPages.includes(action.payload.page)) {
|
||||
state.addPool.validPages.push(action.payload.page);
|
||||
}
|
||||
} else {
|
||||
state.addPool.validPages = state.addPool.validPages.filter(
|
||||
(elm) => elm !== action.payload.page
|
||||
);
|
||||
}
|
||||
},
|
||||
setPoolStorageClasses: (state, action: PayloadAction<Opts[]>) => {
|
||||
state.addPool.storageClasses = action.payload;
|
||||
},
|
||||
setPoolTolerationInfo: (
|
||||
state,
|
||||
action: PayloadAction<{
|
||||
index: number;
|
||||
tolerationValue: ITolerationModel;
|
||||
}>
|
||||
) => {
|
||||
state.addPool.fields.tolerations[action.payload.index] =
|
||||
action.payload.tolerationValue;
|
||||
},
|
||||
addNewPoolToleration: (state) => {
|
||||
state.addPool.fields.tolerations.push({
|
||||
key: "",
|
||||
tolerationSeconds: { seconds: 0 },
|
||||
value: "",
|
||||
effect: ITolerationEffect.NoSchedule,
|
||||
operator: ITolerationOperator.Equal,
|
||||
});
|
||||
},
|
||||
removePoolToleration: (state, action: PayloadAction<number>) => {
|
||||
state.addPool.fields.tolerations =
|
||||
state.addPool.fields.tolerations.filter(
|
||||
(_, index) => index !== action.payload
|
||||
);
|
||||
},
|
||||
setPoolKeyValuePairs: (state, action: PayloadAction<LabelKeyPair[]>) => {
|
||||
state.addPool.fields.nodeSelectorPairs = action.payload;
|
||||
},
|
||||
resetPoolForm: (state) => {
|
||||
state.addPool = {
|
||||
addPoolLoading: false,
|
||||
validPages: ["affinity", "configure"],
|
||||
storageClasses: [],
|
||||
limitSize: {},
|
||||
fields: {
|
||||
setup: {
|
||||
numberOfNodes: 0,
|
||||
storageClass: "",
|
||||
volumeSize: 0,
|
||||
volumesPerServer: 0,
|
||||
},
|
||||
affinity: {
|
||||
nodeSelectorLabels: "",
|
||||
podAffinity: "default",
|
||||
withPodAntiAffinity: true,
|
||||
},
|
||||
configuration: {
|
||||
securityContextEnabled: false,
|
||||
securityContext: {
|
||||
runAsUser: "1000",
|
||||
runAsGroup: "1000",
|
||||
fsGroup: "1000",
|
||||
runAsNonRoot: true,
|
||||
},
|
||||
},
|
||||
nodeSelectorPairs: [{ key: "", value: "" }],
|
||||
tolerations: [
|
||||
{
|
||||
key: "",
|
||||
tolerationSeconds: { seconds: 0 },
|
||||
value: "",
|
||||
effect: ITolerationEffect.NoSchedule,
|
||||
operator: ITolerationOperator.Equal,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
setSelectedPool: (state, action: PayloadAction<string | null>) => {
|
||||
state.tenantDetails.selectedPool = action.payload;
|
||||
state.selectedPool = action.payload;
|
||||
},
|
||||
setOpenPoolDetails: (state, action: PayloadAction<boolean>) => {
|
||||
state.tenantDetails.poolDetailsOpen = action.payload;
|
||||
state.poolDetailsOpen = action.payload;
|
||||
},
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
builder
|
||||
.addCase(getTenantAsync.pending, (state) => {
|
||||
state.tenantDetails.loadingTenant = true;
|
||||
state.loadingTenant = true;
|
||||
})
|
||||
.addCase(getTenantAsync.rejected, (state) => {
|
||||
state.tenantDetails.loadingTenant = false;
|
||||
state.loadingTenant = false;
|
||||
})
|
||||
.addCase(getTenantAsync.fulfilled, (state, action) => {
|
||||
state.tenantDetails.loadingTenant = false;
|
||||
state.tenantDetails.tenantInfo = action.payload;
|
||||
state.loadingTenant = false;
|
||||
state.tenantInfo = action.payload;
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -269,15 +101,6 @@ export const {
|
||||
setTenantName,
|
||||
setTenantInfo,
|
||||
setTenantTab,
|
||||
setPoolLoading,
|
||||
resetPoolForm,
|
||||
setPoolField,
|
||||
isPoolPageValid,
|
||||
setPoolStorageClasses,
|
||||
setPoolTolerationInfo,
|
||||
addNewPoolToleration,
|
||||
removePoolToleration,
|
||||
setPoolKeyValuePairs,
|
||||
setSelectedPool,
|
||||
setOpenPoolDetails,
|
||||
} = tenantSlice.actions;
|
||||
|
||||
@@ -27,8 +27,8 @@ export const getTenantAsync = createAsyncThunk(
|
||||
async (_, { getState, rejectWithValue, dispatch }) => {
|
||||
const state = getState() as AppState;
|
||||
|
||||
const currentNamespace = state.tenants.tenantDetails.currentNamespace;
|
||||
const currentTenant = state.tenants.tenantDetails.currentTenant;
|
||||
const currentNamespace = state.tenants.currentNamespace;
|
||||
const currentTenant = state.tenants.currentTenant;
|
||||
|
||||
return api
|
||||
.invoke(
|
||||
|
||||
@@ -20,7 +20,6 @@ import {
|
||||
IErasureCodeCalc,
|
||||
IGCPConfig,
|
||||
IGemaltoCredentials,
|
||||
ITolerationModel,
|
||||
} from "../../../common/types";
|
||||
import { IResourcesSize, ITenant } from "./ListTenants/types";
|
||||
import { KeyPair, Opts } from "./ListTenants/utils";
|
||||
@@ -278,7 +277,7 @@ export interface ITenantAffinity {
|
||||
withPodAntiAffinity: boolean;
|
||||
}
|
||||
|
||||
export interface ITenantDetails {
|
||||
export interface ITenantState {
|
||||
currentTenant: string;
|
||||
currentNamespace: string;
|
||||
loadingTenant: boolean;
|
||||
@@ -288,11 +287,6 @@ export interface ITenantDetails {
|
||||
selectedPool: string | null;
|
||||
}
|
||||
|
||||
export interface ITenantState {
|
||||
tenantDetails: ITenantDetails;
|
||||
addPool: IAddPool;
|
||||
}
|
||||
|
||||
export interface ILabelKeyPair {
|
||||
labelKey: string;
|
||||
labelValue: string;
|
||||
@@ -322,22 +316,6 @@ export interface IPoolConfiguration {
|
||||
securityContext: ISecurityContext;
|
||||
}
|
||||
|
||||
export interface IAddPoolFields {
|
||||
setup: IAddPoolSetup;
|
||||
affinity: ITenantAffinity;
|
||||
configuration: IPoolConfiguration;
|
||||
tolerations: ITolerationModel[];
|
||||
nodeSelectorPairs: LabelKeyPair[];
|
||||
}
|
||||
|
||||
export interface IAddPool {
|
||||
addPoolLoading: boolean;
|
||||
validPages: string[];
|
||||
storageClasses: Opts[];
|
||||
limitSize: any;
|
||||
fields: IAddPoolFields;
|
||||
}
|
||||
|
||||
export interface ITenantIdentityProviderResponse {
|
||||
oidc?: {
|
||||
callback_url: string;
|
||||
|
||||
@@ -25,29 +25,39 @@ import bucketDetailsReducer from "./screens/Console/Buckets/BucketDetails/bucket
|
||||
import objectBrowserReducer from "./screens/Console/ObjectBrowser/objectBrowserSlice";
|
||||
import tenantsReducer from "./screens/Console/Tenants/tenantsSlice";
|
||||
import dashboardReducer from "./screens/Console/Dashboard/dashboardSlice";
|
||||
import { configureStore } from "@reduxjs/toolkit";
|
||||
import { combineReducers, configureStore } from "@reduxjs/toolkit";
|
||||
import createTenantReducer from "./screens/Console/Tenants/AddTenant/createTenantSlice";
|
||||
import addPoolReducer from "./screens/Console/Tenants/TenantDetails/Pools/AddPool/addPoolSlice";
|
||||
import editPoolReducer from "./screens/Console/Tenants/TenantDetails/Pools/EditPool/editPoolSlice";
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
system: systemReducer,
|
||||
trace: traceReducer,
|
||||
logs: logReducer,
|
||||
watch: watchReducer,
|
||||
console: consoleReducer,
|
||||
buckets: bucketsReducer,
|
||||
bucketDetails: bucketDetailsReducer,
|
||||
objectBrowser: objectBrowserReducer,
|
||||
healthInfo: healthInfoReducer,
|
||||
dashboard: dashboardReducer,
|
||||
// Operator Reducers
|
||||
tenants: tenantsReducer,
|
||||
createTenant: createTenantReducer,
|
||||
editPool: editPoolReducer,
|
||||
},
|
||||
const rootReducer = combineReducers({
|
||||
system: systemReducer,
|
||||
trace: traceReducer,
|
||||
logs: logReducer,
|
||||
watch: watchReducer,
|
||||
console: consoleReducer,
|
||||
buckets: bucketsReducer,
|
||||
bucketDetails: bucketDetailsReducer,
|
||||
objectBrowser: objectBrowserReducer,
|
||||
healthInfo: healthInfoReducer,
|
||||
dashboard: dashboardReducer,
|
||||
// Operator Reducers
|
||||
tenants: tenantsReducer,
|
||||
createTenant: createTenantReducer,
|
||||
addPool: addPoolReducer,
|
||||
editPool: editPoolReducer,
|
||||
});
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: rootReducer,
|
||||
});
|
||||
|
||||
if (process.env.NODE_ENV !== "production" && module.hot) {
|
||||
module.hot.accept(() => {
|
||||
store.replaceReducer(rootReducer);
|
||||
});
|
||||
}
|
||||
|
||||
export type AppState = ReturnType<typeof store.getState>;
|
||||
|
||||
export type AppDispatch = typeof store.dispatch;
|
||||
|
||||
Reference in New Issue
Block a user